summaryrefslogtreecommitdiff
path: root/drivers/media
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media')
-rw-r--r--drivers/media/IR/Kconfig68
-rw-r--r--drivers/media/IR/Makefile15
-rw-r--r--drivers/media/IR/ir-functions.c356
-rw-r--r--drivers/media/IR/ir-keytable.c552
-rw-r--r--drivers/media/IR/ir-raw-event.c251
-rw-r--r--drivers/media/IR/ir-sysfs.c302
-rw-r--r--drivers/media/IR/keymaps/rc-asus-pc39.c91
-rw-r--r--drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c90
-rw-r--r--drivers/media/IR/keymaps/rc-empty.c44
-rw-r--r--drivers/media/IR/keymaps/rc-tbs-nec.c73
-rw-r--r--drivers/media/IR/keymaps/rc-tt-1500.c82
-rw-r--r--drivers/media/IR/rc-map.c84
-rw-r--r--drivers/media/Kconfig53
-rw-r--r--drivers/media/Makefile2
-rw-r--r--drivers/media/common/saa7146_core.c2
-rw-r--r--drivers/media/common/saa7146_fops.c12
-rw-r--r--drivers/media/common/saa7146_hlp.c8
-rw-r--r--drivers/media/common/saa7146_i2c.c2
-rw-r--r--drivers/media/common/saa7146_vbi.c6
-rw-r--r--drivers/media/common/saa7146_video.c72
-rw-r--r--drivers/media/common/tuners/Kconfig15
-rw-r--r--drivers/media/common/tuners/Makefile1
-rw-r--r--drivers/media/common/tuners/max2165.c10
-rw-r--r--drivers/media/common/tuners/tda18218.c334
-rw-r--r--drivers/media/common/tuners/tda18218.h45
-rw-r--r--drivers/media/common/tuners/tda18218_priv.h106
-rw-r--r--drivers/media/common/tuners/tda18271-common.c61
-rw-r--r--drivers/media/common/tuners/tda18271-fe.c24
-rw-r--r--drivers/media/common/tuners/tda18271.h5
-rw-r--r--drivers/media/common/tuners/tda8290.c130
-rw-r--r--drivers/media/common/tuners/tuner-simple.c4
-rw-r--r--drivers/media/common/tuners/tuner-types.c16
-rw-r--r--drivers/media/common/tuners/xc5000.c61
-rw-r--r--drivers/media/common/tuners/xc5000.h4
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c3
-rw-r--r--drivers/media/dvb/bt8xx/dst.c10
-rw-r--r--drivers/media/dvb/bt8xx/dst_ca.c12
-rw-r--r--drivers/media/dvb/dm1105/Kconfig3
-rw-r--r--drivers/media/dvb/dm1105/dm1105.c45
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c25
-rw-r--r--drivers/media/dvb/dvb-core/dvb_ca_en50221.c20
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c10
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.c18
-rw-r--r--drivers/media/dvb/dvb-core/dvb_frontend.h2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c25
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c18
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig18
-rw-r--r--drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--drivers/media/dvb/dvb-usb/a800.c12
-rw-r--r--drivers/media/dvb/dvb-usb/af9005-remote.c16
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.c79
-rw-r--r--drivers/media/dvb/dvb-usb/af9005.h4
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.c400
-rw-r--r--drivers/media/dvb/dvb-usb/af9015.h735
-rw-r--r--drivers/media/dvb/dvb-usb/anysee.c99
-rw-r--r--drivers/media/dvb/dvb-usb/az6027.c20
-rw-r--r--drivers/media/dvb/dvb-usb/cinergyT2-core.c12
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c132
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h1
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c265
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c642
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-common.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mb.c40
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb-mc.c10
-rw-r--r--drivers/media/dvb/dvb-usb/dibusb.h2
-rw-r--r--drivers/media/dvb/dvb-usb/digitv.c20
-rw-r--r--drivers/media/dvb/dvb-usb/dtt200u.c42
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-i2c.c1
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h9
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-init.c60
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-remote.c214
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb.h100
-rw-r--r--drivers/media/dvb/dvb-usb/dw2102.c81
-rw-r--r--drivers/media/dvb/dvb-usb/friio-fe.c2
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk-fe.c6
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.c37
-rw-r--r--drivers/media/dvb/dvb-usb/gp8psk.h8
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.c1113
-rw-r--r--drivers/media/dvb/dvb-usb/lmedm04.h173
-rw-r--r--drivers/media/dvb/dvb-usb/m920x.c44
-rw-r--r--drivers/media/dvb/dvb-usb/nova-t-usb2.c24
-rw-r--r--drivers/media/dvb/dvb-usb/opera1.c26
-rw-r--r--drivers/media/dvb/dvb-usb/ttusb2.c130
-rw-r--r--drivers/media/dvb/dvb-usb/vp702x.c18
-rw-r--r--drivers/media/dvb/dvb-usb/vp7045.c18
-rw-r--r--drivers/media/dvb/firewire/firedtv-1394.c2
-rw-r--r--drivers/media/dvb/firewire/firedtv-avc.c61
-rw-r--r--drivers/media/dvb/firewire/firedtv-ci.c1
-rw-r--r--drivers/media/dvb/firewire/firedtv-fe.c36
-rw-r--r--drivers/media/dvb/firewire/firedtv-fw.c4
-rw-r--r--drivers/media/dvb/firewire/firedtv-rc.c9
-rw-r--r--drivers/media/dvb/frontends/Kconfig42
-rw-r--r--drivers/media/dvb/frontends/Makefile5
-rw-r--r--drivers/media/dvb/frontends/af9013.c309
-rw-r--r--drivers/media/dvb/frontends/af9013.h3
-rw-r--r--drivers/media/dvb/frontends/af9013_priv.h68
-rw-r--r--drivers/media/dvb/frontends/atbm8830.c8
-rw-r--r--drivers/media/dvb/frontends/au8522_decoder.c104
-rw-r--r--drivers/media/dvb/frontends/au8522_priv.h2
-rw-r--r--drivers/media/dvb/frontends/cx22702.c123
-rw-r--r--drivers/media/dvb/frontends/cx24110.c2
-rw-r--r--drivers/media/dvb/frontends/cx24123.c1
-rw-r--r--drivers/media/dvb/frontends/dib3000mb.c9
-rw-r--r--drivers/media/dvb/frontends/dib3000mb_priv.h4
-rw-r--r--drivers/media/dvb/frontends/dib3000mc.c2
-rw-r--r--drivers/media/dvb/frontends/dib7000m.c10
-rw-r--r--drivers/media/dvb/frontends/dib7000p.c18
-rw-r--r--drivers/media/dvb/frontends/dib7000p.h5
-rw-r--r--drivers/media/dvb/frontends/dibx000_common.c2
-rw-r--r--drivers/media/dvb/frontends/drx397xD.c2
-rw-r--r--drivers/media/dvb/frontends/ds3000.c5
-rw-r--r--drivers/media/dvb/frontends/ix2505v.c323
-rw-r--r--drivers/media/dvb/frontends/ix2505v.h64
-rw-r--r--drivers/media/dvb/frontends/lgdt3304.c380
-rw-r--r--drivers/media/dvb/frontends/lgdt3304.h45
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.c267
-rw-r--r--drivers/media/dvb/frontends/lgdt3305.h10
-rw-r--r--drivers/media/dvb/frontends/lgs8gxx.c63
-rw-r--r--drivers/media/dvb/frontends/mb86a16.c1
-rw-r--r--drivers/media/dvb/frontends/mb86a20s.c639
-rw-r--r--drivers/media/dvb/frontends/mb86a20s.h52
-rw-r--r--drivers/media/dvb/frontends/mt352.c2
-rw-r--r--drivers/media/dvb/frontends/mt352.h2
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c1
-rw-r--r--drivers/media/dvb/frontends/s5h1432.c415
-rw-r--r--drivers/media/dvb/frontends/s5h1432.h91
-rw-r--r--drivers/media/dvb/frontends/s921.c548
-rw-r--r--drivers/media/dvb/frontends/s921.h47
-rw-r--r--drivers/media/dvb/frontends/s921_core.c216
-rw-r--r--drivers/media/dvb/frontends/s921_core.h114
-rw-r--r--drivers/media/dvb/frontends/s921_module.c192
-rw-r--r--drivers/media/dvb/frontends/s921_module.h49
-rw-r--r--drivers/media/dvb/frontends/si21xx.c2
-rw-r--r--drivers/media/dvb/frontends/stb0899_drv.c2
-rw-r--r--drivers/media/dvb/frontends/stb6100.c200
-rw-r--r--drivers/media/dvb/frontends/stb6100.h4
-rw-r--r--drivers/media/dvb/frontends/stv0288.c25
-rw-r--r--drivers/media/dvb/frontends/stv0299.c2
-rw-r--r--drivers/media/dvb/frontends/stv0299.h2
-rw-r--r--drivers/media/dvb/frontends/stv090x.c6
-rw-r--r--drivers/media/dvb/frontends/stv6110x.c5
-rw-r--r--drivers/media/dvb/frontends/tda10048.c43
-rw-r--r--drivers/media/dvb/frontends/tda1004x.c2
-rw-r--r--drivers/media/dvb/frontends/zl10353.c2
-rw-r--r--drivers/media/dvb/mantis/Kconfig16
-rw-r--r--drivers/media/dvb/mantis/hopper_cards.c2
-rw-r--r--drivers/media/dvb/mantis/hopper_vp3028.c6
-rw-r--r--drivers/media/dvb/mantis/mantis_cards.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_common.h4
-rw-r--r--drivers/media/dvb/mantis/mantis_core.c5
-rw-r--r--drivers/media/dvb/mantis/mantis_dvb.c17
-rw-r--r--drivers/media/dvb/mantis/mantis_evm.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_i2c.c1
-rw-r--r--drivers/media/dvb/mantis/mantis_input.c79
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.c13
-rw-r--r--drivers/media/dvb/mantis/mantis_ioc.h2
-rw-r--r--drivers/media/dvb/mantis/mantis_uart.c1
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1033.c2
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1034.c10
-rw-r--r--drivers/media/dvb/mantis/mantis_vp1041.c6
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2033.c4
-rw-r--r--drivers/media/dvb/mantis/mantis_vp2040.c4
-rw-r--r--drivers/media/dvb/mantis/mantis_vp3030.c8
-rw-r--r--drivers/media/dvb/ngene/ngene-cards.c15
-rw-r--r--drivers/media/dvb/ngene/ngene-core.c87
-rw-r--r--drivers/media/dvb/ngene/ngene-dvb.c16
-rw-r--r--drivers/media/dvb/ngene/ngene-i2c.c3
-rw-r--r--drivers/media/dvb/ngene/ngene.h3
-rw-r--r--drivers/media/dvb/pluto2/pluto2.c1
-rw-r--r--drivers/media/dvb/pt1/pt1.c1
-rw-r--r--drivers/media/dvb/siano/Kconfig2
-rw-r--r--drivers/media/dvb/siano/sms-cards.c2
-rw-r--r--drivers/media/dvb/siano/sms-cards.h2
-rw-r--r--drivers/media/dvb/siano/smscoreapi.c42
-rw-r--r--drivers/media/dvb/siano/smsir.c287
-rw-r--r--drivers/media/dvb/siano/smsir.h64
-rw-r--r--drivers/media/dvb/siano/smsusb.c12
-rw-r--r--drivers/media/dvb/ttpci/Kconfig8
-rw-r--r--drivers/media/dvb/ttpci/av7110.c13
-rw-r--r--drivers/media/dvb/ttpci/av7110_av.c9
-rw-r--r--drivers/media/dvb/ttpci/av7110_ca.c5
-rw-r--r--drivers/media/dvb/ttpci/av7110_hw.c2
-rw-r--r--drivers/media/dvb/ttpci/av7110_ir.c1
-rw-r--r--drivers/media/dvb/ttpci/av7110_v4l.c6
-rw-r--r--drivers/media/dvb/ttpci/budget-av.c8
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c57
-rw-r--r--drivers/media/dvb/ttpci/budget-core.c4
-rw-r--r--drivers/media/dvb/ttpci/budget-patch.c2
-rw-r--r--drivers/media/dvb/ttpci/budget.c2
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c1
-rw-r--r--drivers/media/radio/Kconfig30
-rw-r--r--drivers/media/radio/Makefile2
-rw-r--r--drivers/media/radio/radio-aimslab.c40
-rw-r--r--drivers/media/radio/radio-aztech.c6
-rw-r--r--drivers/media/radio/radio-cadet.c15
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c478
-rw-r--r--drivers/media/radio/radio-gemtek.c14
-rw-r--r--drivers/media/radio/radio-maestro.c14
-rw-r--r--drivers/media/radio/radio-maxiradio.c8
-rw-r--r--drivers/media/radio/radio-miropcm20.c6
-rw-r--r--drivers/media/radio/radio-mr800.c76
-rw-r--r--drivers/media/radio/radio-rtrack2.c10
-rw-r--r--drivers/media/radio/radio-sf16fmi.c7
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c11
-rw-r--r--drivers/media/radio/radio-si4713.c15
-rw-r--r--drivers/media/radio/radio-tea5764.c49
-rw-r--r--drivers/media/radio/radio-terratec.c8
-rw-r--r--drivers/media/radio/radio-timb.c5
-rw-r--r--drivers/media/radio/radio-trust.c18
-rw-r--r--drivers/media/radio/radio-typhoon.c19
-rw-r--r--drivers/media/radio/radio-wl1273.c2330
-rw-r--r--drivers/media/radio/radio-zoltrix.c30
-rw-r--r--drivers/media/radio/si470x/radio-si470x-common.c40
-rw-r--r--drivers/media/radio/si470x/radio-si470x-i2c.c3
-rw-r--r--drivers/media/radio/si470x/radio-si470x-usb.c17
-rw-r--r--drivers/media/radio/si470x/radio-si470x.h4
-rw-r--r--drivers/media/radio/si4713-i2c.c88
-rw-r--r--drivers/media/radio/si4713-i2c.h5
-rw-r--r--drivers/media/radio/tef6862.c1
-rw-r--r--drivers/media/rc/Kconfig193
-rw-r--r--drivers/media/rc/Makefile22
-rw-r--r--drivers/media/rc/ene_ir.c1213
-rw-r--r--drivers/media/rc/ene_ir.h259
-rw-r--r--drivers/media/rc/imon.c (renamed from drivers/media/IR/imon.c)825
-rw-r--r--drivers/media/rc/ir-jvc-decoder.c (renamed from drivers/media/IR/ir-jvc-decoder.c)182
-rw-r--r--drivers/media/rc/ir-lirc-codec.c402
-rw-r--r--drivers/media/rc/ir-nec-decoder.c (renamed from drivers/media/IR/ir-nec-decoder.c)200
-rw-r--r--drivers/media/rc/ir-raw.c371
-rw-r--r--drivers/media/rc/ir-rc5-decoder.c (renamed from drivers/media/IR/ir-rc5-decoder.c)181
-rw-r--r--drivers/media/rc/ir-rc5-sz-decoder.c153
-rw-r--r--drivers/media/rc/ir-rc6-decoder.c (renamed from drivers/media/IR/ir-rc6-decoder.c)167
-rw-r--r--drivers/media/rc/ir-sony-decoder.c (renamed from drivers/media/IR/ir-sony-decoder.c)169
-rw-r--r--drivers/media/rc/keymaps/Kconfig (renamed from drivers/media/IR/keymaps/Kconfig)2
-rw-r--r--drivers/media/rc/keymaps/Makefile (renamed from drivers/media/IR/keymaps/Makefile)25
-rw-r--r--drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c (renamed from drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-alink-dtu-m.c68
-rw-r--r--drivers/media/rc/keymaps/rc-anysee.c93
-rw-r--r--drivers/media/rc/keymaps/rc-apac-viewcomp.c (renamed from drivers/media/IR/keymaps/rc-apac-viewcomp.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-asus-pc39.c91
-rw-r--r--drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c (renamed from drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-a16d.c (renamed from drivers/media/IR/keymaps/rc-avermedia-a16d.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-cardbus.c (renamed from drivers/media/IR/keymaps/rc-avermedia-cardbus.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-dvbt.c (renamed from drivers/media/IR/keymaps/rc-avermedia-dvbt.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m135a.c147
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c95
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia-rm-ks.c79
-rw-r--r--drivers/media/rc/keymaps/rc-avermedia.c (renamed from drivers/media/IR/keymaps/rc-avermedia.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-avertv-303.c (renamed from drivers/media/IR/keymaps/rc-avertv-303.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c102
-rw-r--r--drivers/media/rc/keymaps/rc-behold-columbus.c (renamed from drivers/media/IR/keymaps/rc-behold-columbus.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-behold.c (renamed from drivers/media/IR/keymaps/rc-behold.c)78
-rw-r--r--drivers/media/rc/keymaps/rc-budget-ci-old.c (renamed from drivers/media/IR/keymaps/rc-budget-ci-old.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy-1400.c (renamed from drivers/media/IR/keymaps/rc-cinergy-1400.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-cinergy.c (renamed from drivers/media/IR/keymaps/rc-cinergy.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-nec.c124
-rw-r--r--drivers/media/rc/keymaps/rc-dib0700-rc5.c235
-rw-r--r--drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c98
-rw-r--r--drivers/media/rc/keymaps/rc-digittrade.c82
-rw-r--r--drivers/media/rc/keymaps/rc-dm1105-nec.c (renamed from drivers/media/IR/keymaps/rc-dm1105-nec.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c (renamed from drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c (renamed from drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-em-terratec.c (renamed from drivers/media/IR/keymaps/rc-em-terratec.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv-fm53.c (renamed from drivers/media/IR/keymaps/rc-encore-enltv-fm53.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv.c (renamed from drivers/media/IR/keymaps/rc-encore-enltv.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-encore-enltv2.c (renamed from drivers/media/IR/keymaps/rc-encore-enltv2.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-evga-indtube.c (renamed from drivers/media/IR/keymaps/rc-evga-indtube.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-eztv.c (renamed from drivers/media/IR/keymaps/rc-eztv.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-flydvb.c (renamed from drivers/media/IR/keymaps/rc-flydvb.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-flyvideo.c (renamed from drivers/media/IR/keymaps/rc-flyvideo.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-fusionhdtv-mce.c (renamed from drivers/media/IR/keymaps/rc-fusionhdtv-mce.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-gadmei-rm008z.c (renamed from drivers/media/IR/keymaps/rc-gadmei-rm008z.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c (renamed from drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-gotview7135.c (renamed from drivers/media/IR/keymaps/rc-gotview7135.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-hauppauge-new.c (renamed from drivers/media/IR/keymaps/rc-hauppauge-new.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-imon-mce.c (renamed from drivers/media/IR/keymaps/rc-imon-mce.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-imon-pad.c (renamed from drivers/media/IR/keymaps/rc-imon-pad.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-iodata-bctv7e.c (renamed from drivers/media/IR/keymaps/rc-iodata-bctv7e.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-kaiomy.c (renamed from drivers/media/IR/keymaps/rc-kaiomy.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-315u.c (renamed from drivers/media/IR/keymaps/rc-kworld-315u.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c (renamed from drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-leadtek-y04g0051.c99
-rw-r--r--drivers/media/rc/keymaps/rc-lirc.c41
-rw-r--r--drivers/media/rc/keymaps/rc-lme2510.c68
-rw-r--r--drivers/media/rc/keymaps/rc-manli.c (renamed from drivers/media/IR/keymaps/rc-manli.c)11
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-ii.c67
-rw-r--r--drivers/media/rc/keymaps/rc-msi-digivox-iii.c85
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c (renamed from drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-msi-tvanywhere.c (renamed from drivers/media/IR/keymaps/rc-msi-tvanywhere.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-nebula.c (renamed from drivers/media/IR/keymaps/rc-nebula.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c (renamed from drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-norwood.c (renamed from drivers/media/IR/keymaps/rc-norwood.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-npgtech.c (renamed from drivers/media/IR/keymaps/rc-npgtech.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pctv-sedna.c (renamed from drivers/media/IR/keymaps/rc-pctv-sedna.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-color.c (renamed from drivers/media/IR/keymaps/rc-pinnacle-color.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-grey.c (renamed from drivers/media/IR/keymaps/rc-pinnacle-grey.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c (renamed from drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-002t.c77
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-mk12.c (renamed from drivers/media/IR/keymaps/rc-pixelview-mk12.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview-new.c (renamed from drivers/media/IR/keymaps/rc-pixelview-new.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pixelview.c (renamed from drivers/media/IR/keymaps/rc-pixelview.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-powercolor-real-angel.c (renamed from drivers/media/IR/keymaps/rc-powercolor-real-angel.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-proteus-2309.c (renamed from drivers/media/IR/keymaps/rc-proteus-2309.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-purpletv.c (renamed from drivers/media/IR/keymaps/rc-purpletv.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-pv951.c (renamed from drivers/media/IR/keymaps/rc-pv951.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c (renamed from drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c)48
-rw-r--r--drivers/media/rc/keymaps/rc-rc5-tv.c (renamed from drivers/media/IR/keymaps/rc-rc5-tv.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-rc6-mce.c113
-rw-r--r--drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c (renamed from drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-streamzap.c82
-rw-r--r--drivers/media/rc/keymaps/rc-tbs-nec.c75
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c (renamed from drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-terratec-slim.c79
-rw-r--r--drivers/media/rc/keymaps/rc-tevii-nec.c (renamed from drivers/media/IR/keymaps/rc-tevii-nec.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-total-media-in-hand.c85
-rw-r--r--drivers/media/rc/keymaps/rc-trekstor.c80
-rw-r--r--drivers/media/rc/keymaps/rc-tt-1500.c82
-rw-r--r--drivers/media/rc/keymaps/rc-twinhan1027.c87
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-m1f.c92
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-s350.c (renamed from drivers/media/IR/keymaps/rc-videomate-s350.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-videomate-tv-pvr.c (renamed from drivers/media/IR/keymaps/rc-videomate-tv-pvr.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c (renamed from drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c)10
-rw-r--r--drivers/media/rc/keymaps/rc-winfast.c (renamed from drivers/media/IR/keymaps/rc-winfast.c)10
-rw-r--r--drivers/media/rc/lirc_dev.c816
-rw-r--r--drivers/media/rc/mceusb.c1312
-rw-r--r--drivers/media/rc/nuvoton-cir.c1244
-rw-r--r--drivers/media/rc/nuvoton-cir.h407
-rw-r--r--drivers/media/rc/rc-core-priv.h (renamed from drivers/media/IR/ir-core-priv.h)113
-rw-r--r--drivers/media/rc/rc-loopback.c260
-rw-r--r--drivers/media/rc/rc-main.c1135
-rw-r--r--drivers/media/rc/streamzap.c557
-rw-r--r--drivers/media/rc/winbond-cir.c932
-rw-r--r--drivers/media/video/Kconfig369
-rw-r--r--drivers/media/video/Makefile38
-rw-r--r--drivers/media/video/adv7170.c28
-rw-r--r--drivers/media/video/adv7175.c39
-rw-r--r--drivers/media/video/adv7180.c1
-rw-r--r--drivers/media/video/ak881x.c9
-rw-r--r--drivers/media/video/arv.c2
-rw-r--r--drivers/media/video/au0828/Makefile2
-rw-r--r--drivers/media/video/au0828/au0828-cards.c4
-rw-r--r--drivers/media/video/au0828/au0828-vbi.c138
-rw-r--r--drivers/media/video/au0828/au0828-video.c555
-rw-r--r--drivers/media/video/au0828/au0828.h26
-rw-r--r--drivers/media/video/bt819.c28
-rw-r--r--drivers/media/video/bt856.c28
-rw-r--r--drivers/media/video/bt866.c28
-rw-r--r--drivers/media/video/bt8xx/Kconfig4
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c61
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c316
-rw-r--r--drivers/media/video/bt8xx/bttv-i2c.c43
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c317
-rw-r--r--drivers/media/video/bt8xx/bttv-risc.c4
-rw-r--r--drivers/media/video/bt8xx/bttv.h3
-rw-r--r--drivers/media/video/bt8xx/bttvp.h47
-rw-r--r--drivers/media/video/bw-qcam.c759
-rw-r--r--drivers/media/video/bw-qcam.h69
-rw-r--r--drivers/media/video/c-qcam.c634
-rw-r--r--drivers/media/video/cafe_ccic.c202
-rw-r--r--drivers/media/video/cpia.c4032
-rw-r--r--drivers/media/video/cpia.h432
-rw-r--r--drivers/media/video/cpia2/Kconfig2
-rw-r--r--drivers/media/video/cpia2/cpia2.h10
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c116
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c456
-rw-r--r--drivers/media/video/cpia2/cpia2dev.h4
-rw-r--r--drivers/media/video/cpia_pp.c869
-rw-r--r--drivers/media/video/cpia_usb.c643
-rw-r--r--drivers/media/video/cs5345.c27
-rw-r--r--drivers/media/video/cs53l32a.c134
-rw-r--r--drivers/media/video/cx18/Kconfig3
-rw-r--r--drivers/media/video/cx18/cx18-alsa-main.c2
-rw-r--r--drivers/media/video/cx18/cx18-alsa-mixer.c2
-rw-r--r--drivers/media/video/cx18/cx18-alsa-mixer.h2
-rw-r--r--drivers/media/video/cx18/cx18-alsa-pcm.c10
-rw-r--r--drivers/media/video/cx18/cx18-alsa-pcm.h2
-rw-r--r--drivers/media/video/cx18/cx18-alsa.h2
-rw-r--r--drivers/media/video/cx18/cx18-av-audio.c2
-rw-r--r--drivers/media/video/cx18/cx18-av-core.c127
-rw-r--r--drivers/media/video/cx18/cx18-av-core.h2
-rw-r--r--drivers/media/video/cx18/cx18-av-firmware.c2
-rw-r--r--drivers/media/video/cx18/cx18-cards.c66
-rw-r--r--drivers/media/video/cx18/cx18-cards.h2
-rw-r--r--drivers/media/video/cx18/cx18-controls.c13
-rw-r--r--drivers/media/video/cx18/cx18-driver.c45
-rw-r--r--drivers/media/video/cx18/cx18-driver.h37
-rw-r--r--drivers/media/video/cx18/cx18-dvb.c66
-rw-r--r--drivers/media/video/cx18/cx18-fileops.c2
-rw-r--r--drivers/media/video/cx18/cx18-firmware.c2
-rw-r--r--drivers/media/video/cx18/cx18-gpio.c2
-rw-r--r--drivers/media/video/cx18/cx18-gpio.h2
-rw-r--r--drivers/media/video/cx18/cx18-i2c.c30
-rw-r--r--drivers/media/video/cx18/cx18-io.c2
-rw-r--r--drivers/media/video/cx18/cx18-io.h4
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.c13
-rw-r--r--drivers/media/video/cx18/cx18-ioctl.h2
-rw-r--r--drivers/media/video/cx18/cx18-irq.c2
-rw-r--r--drivers/media/video/cx18/cx18-irq.h2
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.c8
-rw-r--r--drivers/media/video/cx18/cx18-mailbox.h2
-rw-r--r--drivers/media/video/cx18/cx18-queue.c2
-rw-r--r--drivers/media/video/cx18/cx18-queue.h2
-rw-r--r--drivers/media/video/cx18/cx18-scb.c2
-rw-r--r--drivers/media/video/cx18/cx18-scb.h2
-rw-r--r--drivers/media/video/cx18/cx18-streams.c49
-rw-r--r--drivers/media/video/cx18/cx18-streams.h8
-rw-r--r--drivers/media/video/cx18/cx23418.h2
-rw-r--r--drivers/media/video/cx231xx/Kconfig20
-rw-r--r--drivers/media/video/cx231xx/Makefile6
-rw-r--r--drivers/media/video/cx231xx/cx231xx-417.c2192
-rw-r--r--drivers/media/video/cx231xx/cx231xx-audio.c256
-rw-r--r--drivers/media/video/cx231xx/cx231xx-avcore.c694
-rw-r--r--drivers/media/video/cx231xx/cx231xx-cards.c499
-rw-r--r--drivers/media/video/cx231xx/cx231xx-conf-reg.h1
-rw-r--r--drivers/media/video/cx231xx/cx231xx-core.c795
-rw-r--r--drivers/media/video/cx231xx/cx231xx-dif.h3178
-rw-r--r--drivers/media/video/cx231xx/cx231xx-dvb.c293
-rw-r--r--drivers/media/video/cx231xx/cx231xx-i2c.c11
-rw-r--r--drivers/media/video/cx231xx/cx231xx-input.c288
-rw-r--r--drivers/media/video/cx231xx/cx231xx-vbi.c109
-rw-r--r--drivers/media/video/cx231xx/cx231xx-vbi.h2
-rw-r--r--drivers/media/video/cx231xx/cx231xx-video.c612
-rw-r--r--drivers/media/video/cx231xx/cx231xx.h282
-rw-r--r--drivers/media/video/cx2341x.c761
-rw-r--r--drivers/media/video/cx23885/Kconfig2
-rw-r--r--drivers/media/video/cx23885/Makefile5
-rw-r--r--drivers/media/video/cx23885/cimax2.c24
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c13
-rw-r--r--drivers/media/video/cx23885/cx23885-av.c35
-rw-r--r--drivers/media/video/cx23885/cx23885-av.h27
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c189
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c138
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c9
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c32
-rw-r--r--drivers/media/video/cx23885/cx23885-input.c363
-rw-r--r--drivers/media/video/cx23885/cx23885-input.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-ioctl.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-ioctl.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-ir.c28
-rw-r--r--drivers/media/video/cx23885/cx23885-ir.h2
-rw-r--r--drivers/media/video/cx23885/cx23885-reg.h1
-rw-r--r--drivers/media/video/cx23885/cx23885-vbi.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c75
-rw-r--r--drivers/media/video/cx23885/cx23885.h21
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.c145
-rw-r--r--drivers/media/video/cx23885/cx23888-ir.h2
-rw-r--r--drivers/media/video/cx25840/Makefile2
-rw-r--r--drivers/media/video/cx25840/cx25840-audio.c198
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c690
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h52
-rw-r--r--drivers/media/video/cx25840/cx25840-ir.c1280
-rw-r--r--drivers/media/video/cx88/Kconfig5
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c55
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c19
-rw-r--r--drivers/media/video/cx88/cx88-cards.c61
-rw-r--r--drivers/media/video/cx88/cx88-core.c32
-rw-r--r--drivers/media/video/cx88/cx88-dsp.c11
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c189
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c25
-rw-r--r--drivers/media/video/cx88/cx88-input.c335
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c14
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c43
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c2
-rw-r--r--drivers/media/video/cx88/cx88-video.c75
-rw-r--r--drivers/media/video/cx88/cx88-vp3054-i2c.c3
-rw-r--r--drivers/media/video/cx88/cx88.h67
-rw-r--r--drivers/media/video/dabusb.c931
-rw-r--r--drivers/media/video/dabusb.h85
-rw-r--r--drivers/media/video/davinci/Kconfig93
-rw-r--r--drivers/media/video/davinci/vpfe_capture.c41
-rw-r--r--drivers/media/video/davinci/vpif.c177
-rw-r--r--drivers/media/video/davinci/vpif.h20
-rw-r--r--drivers/media/video/davinci/vpif_capture.c466
-rw-r--r--drivers/media/video/davinci/vpif_capture.h2
-rw-r--r--drivers/media/video/davinci/vpif_display.c488
-rw-r--r--drivers/media/video/davinci/vpif_display.h2
-rw-r--r--drivers/media/video/davinci/vpss.c2
-rw-r--r--drivers/media/video/em28xx/Kconfig5
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c75
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c188
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c7
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c49
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c156
-rw-r--r--drivers/media/video/em28xx/em28xx-vbi.c1
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c133
-rw-r--r--drivers/media/video/em28xx/em28xx.h22
-rw-r--r--drivers/media/video/et61x251/et61x251.h24
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c3
-rw-r--r--drivers/media/video/fsl-viu.c1659
-rw-r--r--drivers/media/video/gspca/Kconfig36
-rw-r--r--drivers/media/video/gspca/Makefile8
-rw-r--r--drivers/media/video/gspca/benq.c25
-rw-r--r--drivers/media/video/gspca/conex.c26
-rw-r--r--drivers/media/video/gspca/cpia1.c166
-rw-r--r--drivers/media/video/gspca/etoms.c16
-rw-r--r--drivers/media/video/gspca/finepix.c17
-rw-r--r--drivers/media/video/gspca/gl860/gl860-mi2020.c729
-rw-r--r--drivers/media/video/gspca/gl860/gl860-ov9655.c4
-rw-r--r--drivers/media/video/gspca/gl860/gl860.c50
-rw-r--r--drivers/media/video/gspca/gl860/gl860.h13
-rw-r--r--drivers/media/video/gspca/gspca.c765
-rw-r--r--drivers/media/video/gspca/gspca.h40
-rw-r--r--drivers/media/video/gspca/jeilinj.c23
-rw-r--r--drivers/media/video/gspca/jpeg.h4
-rw-r--r--drivers/media/video/gspca/konica.c646
-rw-r--r--drivers/media/video/gspca/m5602/m5602_bridge.h1
-rw-r--r--drivers/media/video/gspca/m5602/m5602_core.c25
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.c48
-rw-r--r--drivers/media/video/gspca/m5602/m5602_mt9m111.h14
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.c70
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov7660.h9
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.c104
-rw-r--r--drivers/media/video/gspca/m5602/m5602_ov9650.h12
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.c136
-rw-r--r--drivers/media/video/gspca/m5602/m5602_po1030.h13
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.c28
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k4aa.h14
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.c1
-rw-r--r--drivers/media/video/gspca/m5602/m5602_s5k83a.h12
-rw-r--r--drivers/media/video/gspca/mars.c342
-rw-r--r--drivers/media/video/gspca/mr97310a.c58
-rw-r--r--drivers/media/video/gspca/ov519.c2060
-rw-r--r--drivers/media/video/gspca/ov534.c69
-rw-r--r--drivers/media/video/gspca/ov534_9.c22
-rw-r--r--drivers/media/video/gspca/pac207.c32
-rw-r--r--drivers/media/video/gspca/pac7302.c69
-rw-r--r--drivers/media/video/gspca/pac7311.c67
-rw-r--r--drivers/media/video/gspca/sn9c2028.c21
-rw-r--r--drivers/media/video/gspca/sn9c20x.c229
-rw-r--r--drivers/media/video/gspca/sonixb.c529
-rw-r--r--drivers/media/video/gspca/sonixj.c1450
-rw-r--r--drivers/media/video/gspca/spca1528.c598
-rw-r--r--drivers/media/video/gspca/spca500.c29
-rw-r--r--drivers/media/video/gspca/spca501.c18
-rw-r--r--drivers/media/video/gspca/spca505.c20
-rw-r--r--drivers/media/video/gspca/spca508.c18
-rw-r--r--drivers/media/video/gspca/spca561.c20
-rw-r--r--drivers/media/video/gspca/sq905.c23
-rw-r--r--drivers/media/video/gspca/sq905c.c18
-rw-r--r--drivers/media/video/gspca/sq930x.c1208
-rw-r--r--drivers/media/video/gspca/stk014.c193
-rw-r--r--drivers/media/video/gspca/stv0680.c19
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.c73
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx.h3
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c19
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h13
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c18
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h3
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_sensor.h4
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.c291
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_st6422.h13
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c2
-rw-r--r--drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h13
-rw-r--r--drivers/media/video/gspca/sunplus.c46
-rw-r--r--drivers/media/video/gspca/t613.c420
-rw-r--r--drivers/media/video/gspca/tv8532.c239
-rw-r--r--drivers/media/video/gspca/vc032x.c665
-rw-r--r--drivers/media/video/gspca/w996Xcf.c351
-rw-r--r--drivers/media/video/gspca/xirlink_cit.c3337
-rw-r--r--drivers/media/video/gspca/zc3xx.c2020
-rw-r--r--drivers/media/video/hdpvr/Makefile4
-rw-r--r--drivers/media/video/hdpvr/hdpvr-control.c5
-rw-r--r--drivers/media/video/hdpvr/hdpvr-core.c52
-rw-r--r--drivers/media/video/hdpvr/hdpvr-i2c.c125
-rw-r--r--drivers/media/video/hdpvr/hdpvr-video.c18
-rw-r--r--drivers/media/video/hdpvr/hdpvr.h18
-rw-r--r--drivers/media/video/hexium_gemini.c19
-rw-r--r--drivers/media/video/hexium_orion.c19
-rw-r--r--drivers/media/video/imx074.c505
-rw-r--r--drivers/media/video/indycam.c27
-rw-r--r--drivers/media/video/ir-kbd-i2c.c153
-rw-r--r--drivers/media/video/ivtv/Kconfig3
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c7
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h4
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.c276
-rw-r--r--drivers/media/video/ivtv/ivtv-controls.h6
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c94
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h30
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c68
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.c128
-rw-r--r--drivers/media/video/ivtv/ivtv-firmware.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-gpio.c77
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c112
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c38
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c15
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c8
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.h1
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c55
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.c115
-rw-r--r--drivers/media/video/ivtv/ivtv-vbi.h5
-rw-r--r--drivers/media/video/ivtv/ivtv-version.h2
-rw-r--r--drivers/media/video/ivtv/ivtvfb.c61
-rw-r--r--drivers/media/video/ks0127.c27
-rw-r--r--drivers/media/video/m52790.c28
-rw-r--r--drivers/media/video/mem2mem_testdev.c31
-rw-r--r--drivers/media/video/meye.c14
-rw-r--r--drivers/media/video/msp3400-driver.c284
-rw-r--r--drivers/media/video/msp3400-driver.h18
-rw-r--r--drivers/media/video/msp3400-kthreads.c16
-rw-r--r--drivers/media/video/mt9m001.c33
-rw-r--r--drivers/media/video/mt9m111.c109
-rw-r--r--drivers/media/video/mt9t031.c29
-rw-r--r--drivers/media/video/mt9t112.c32
-rw-r--r--drivers/media/video/mt9v011.c118
-rw-r--r--drivers/media/video/mt9v011.h36
-rw-r--r--drivers/media/video/mt9v022.c36
-rw-r--r--drivers/media/video/mx1_camera.c17
-rw-r--r--drivers/media/video/mx2_camera.c1525
-rw-r--r--drivers/media/video/mx3_camera.c22
-rw-r--r--drivers/media/video/mxb.c27
-rw-r--r--drivers/media/video/omap/Kconfig4
-rw-r--r--drivers/media/video/omap/Makefile4
-rw-r--r--drivers/media/video/omap/omap_vout.c89
-rw-r--r--drivers/media/video/omap1_camera.c1702
-rw-r--r--drivers/media/video/omap24xxcam.c12
-rw-r--r--drivers/media/video/ov2640.c1205
-rw-r--r--drivers/media/video/ov511.c5995
-rw-r--r--drivers/media/video/ov511.h573
-rw-r--r--drivers/media/video/ov6650.c1221
-rw-r--r--drivers/media/video/ov7670.c228
-rw-r--r--drivers/media/video/ov7670.h20
-rw-r--r--drivers/media/video/ov772x.c43
-rw-r--r--drivers/media/video/ov9640.c47
-rw-r--r--drivers/media/video/ovcamchip/Makefile4
-rw-r--r--drivers/media/video/ovcamchip/ov6x20.c414
-rw-r--r--drivers/media/video/ovcamchip/ov6x30.c373
-rw-r--r--drivers/media/video/ovcamchip/ov76be.c302
-rw-r--r--drivers/media/video/ovcamchip/ov7x10.c334
-rw-r--r--drivers/media/video/ovcamchip/ov7x20.c454
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_core.c395
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_priv.h101
-rw-r--r--drivers/media/video/pms.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c12
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c14
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c1
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.h5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c50
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c62
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ioread.c5
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c15
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c19
-rw-r--r--drivers/media/video/pwc/Kconfig2
-rw-r--r--drivers/media/video/pwc/pwc-ctrl.c27
-rw-r--r--drivers/media/video/pwc/pwc-if.c104
-rw-r--r--drivers/media/video/pwc/pwc-misc.c4
-rw-r--r--drivers/media/video/pwc/pwc-uncompress.c2
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c348
-rw-r--r--drivers/media/video/pwc/pwc.h7
-rw-r--r--drivers/media/video/pxa_camera.c26
-rw-r--r--drivers/media/video/rj54n1cb0c.c43
-rw-r--r--drivers/media/video/s2255drv.c762
-rw-r--r--drivers/media/video/s5p-fimc/Makefile3
-rw-r--r--drivers/media/video/s5p-fimc/fimc-capture.c864
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.c1844
-rw-r--r--drivers/media/video/s5p-fimc/fimc-core.h698
-rw-r--r--drivers/media/video/s5p-fimc/fimc-reg.c668
-rw-r--r--drivers/media/video/s5p-fimc/regs-fimc.h288
-rw-r--r--drivers/media/video/saa5246a.c1123
-rw-r--r--drivers/media/video/saa5249.c650
-rw-r--r--drivers/media/video/saa6588.c43
-rw-r--r--drivers/media/video/saa7110.c27
-rw-r--r--drivers/media/video/saa7115.c246
-rw-r--r--drivers/media/video/saa7127.c35
-rw-r--r--drivers/media/video/saa7134/Kconfig11
-rw-r--r--drivers/media/video/saa7134/Makefile7
-rw-r--r--drivers/media/video/saa7134/saa6752hs.c73
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c14
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c249
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c19
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c86
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c14
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c1
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c462
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c12
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c42
-rw-r--r--drivers/media/video/saa7134/saa7134.h44
-rw-r--r--drivers/media/video/saa7164/Makefile2
-rw-r--r--drivers/media/video/saa7164/saa7164-api.c1010
-rw-r--r--drivers/media/video/saa7164/saa7164-buffer.c273
-rw-r--r--drivers/media/video/saa7164/saa7164-bus.c137
-rw-r--r--drivers/media/video/saa7164/saa7164-cards.c35
-rw-r--r--drivers/media/video/saa7164/saa7164-cmd.c39
-rw-r--r--drivers/media/video/saa7164/saa7164-core.c908
-rw-r--r--drivers/media/video/saa7164/saa7164-dvb.c109
-rw-r--r--drivers/media/video/saa7164/saa7164-encoder.c1510
-rw-r--r--drivers/media/video/saa7164/saa7164-fw.c23
-rw-r--r--drivers/media/video/saa7164/saa7164-i2c.c6
-rw-r--r--drivers/media/video/saa7164/saa7164-reg.h59
-rw-r--r--drivers/media/video/saa7164/saa7164-types.h255
-rw-r--r--drivers/media/video/saa7164/saa7164-vbi.c1384
-rw-r--r--drivers/media/video/saa7164/saa7164.h293
-rw-r--r--drivers/media/video/saa717x.c388
-rw-r--r--drivers/media/video/saa7185.c28
-rw-r--r--drivers/media/video/saa7191.c27
-rw-r--r--drivers/media/video/se401.c1493
-rw-r--r--drivers/media/video/se401.h236
-rw-r--r--drivers/media/video/sh_mobile_ceu_camera.c181
-rw-r--r--drivers/media/video/sh_mobile_csi2.c354
-rw-r--r--drivers/media/video/sh_vou.c83
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c3
-rw-r--r--drivers/media/video/sn9c102/sn9c102_devtable.h76
-rw-r--r--drivers/media/video/sn9c102/sn9c102_pas202bcb.c1
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h2
-rw-r--r--drivers/media/video/soc_camera.c326
-rw-r--r--drivers/media/video/soc_camera_platform.c44
-rw-r--r--drivers/media/video/soc_mediabus.c8
-rw-r--r--drivers/media/video/sr030pc30.c884
-rw-r--r--drivers/media/video/stk-webcam.c152
-rw-r--r--drivers/media/video/stradis.c2213
-rw-r--r--drivers/media/video/stv680.c1565
-rw-r--r--drivers/media/video/stv680.h227
-rw-r--r--drivers/media/video/tcm825x.c8
-rw-r--r--drivers/media/video/tda7432.c27
-rw-r--r--drivers/media/video/tda9840.c27
-rw-r--r--drivers/media/video/tda9875.c396
-rw-r--r--drivers/media/video/tea6415c.c29
-rw-r--r--drivers/media/video/tea6420.c27
-rw-r--r--drivers/media/video/timblogiw.c893
-rw-r--r--drivers/media/video/tlg2300/Kconfig4
-rw-r--r--drivers/media/video/tlg2300/pd-main.c19
-rw-r--r--drivers/media/video/tlg2300/pd-video.c17
-rw-r--r--drivers/media/video/tlv320aic23b.c28
-rw-r--r--drivers/media/video/tuner-core.c40
-rw-r--r--drivers/media/video/tvaudio.c40
-rw-r--r--drivers/media/video/tveeprom.c15
-rw-r--r--drivers/media/video/tvp514x.c252
-rw-r--r--drivers/media/video/tvp5150.c51
-rw-r--r--drivers/media/video/tvp7002.c138
-rw-r--r--drivers/media/video/tw9910.c32
-rw-r--r--drivers/media/video/upd64031a.c27
-rw-r--r--drivers/media/video/upd64083.c27
-rw-r--r--drivers/media/video/usbvideo/Kconfig53
-rw-r--r--drivers/media/video/usbvideo/Makefile5
-rw-r--r--drivers/media/video/usbvideo/ibmcam.c3977
-rw-r--r--drivers/media/video/usbvideo/konicawc.c992
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c1126
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.h112
-rw-r--r--drivers/media/video/usbvideo/ultracam.c685
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c2234
-rw-r--r--drivers/media/video/usbvideo/usbvideo.h395
-rw-r--r--drivers/media/video/usbvideo/vicam.c953
-rw-r--r--drivers/media/video/usbvision/usbvision-cards.c1860
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c1635
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c70
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c633
-rw-r--r--drivers/media/video/usbvision/usbvision.h268
-rw-r--r--drivers/media/video/uvc/uvc_ctrl.c769
-rw-r--r--drivers/media/video/uvc/uvc_driver.c65
-rw-r--r--drivers/media/video/uvc/uvc_isight.c2
-rw-r--r--drivers/media/video/uvc/uvc_queue.c157
-rw-r--r--drivers/media/video/uvc/uvc_status.c4
-rw-r--r--drivers/media/video/uvc/uvc_v4l2.c319
-rw-r--r--drivers/media/video/uvc/uvc_video.c74
-rw-r--r--drivers/media/video/uvc/uvcvideo.h93
-rw-r--r--drivers/media/video/v4l1-compat.c1270
-rw-r--r--drivers/media/video/v4l2-common.c545
-rw-r--r--drivers/media/video/v4l2-compat-ioctl32.c330
-rw-r--r--drivers/media/video/v4l2-ctrls.c1873
-rw-r--r--drivers/media/video/v4l2-dev.c210
-rw-r--r--drivers/media/video/v4l2-device.c20
-rw-r--r--drivers/media/video/v4l2-event.c9
-rw-r--r--drivers/media/video/v4l2-ioctl.c152
-rw-r--r--drivers/media/video/v4l2-mem2mem.c8
-rw-r--r--drivers/media/video/via-camera.c1459
-rw-r--r--drivers/media/video/via-camera.h93
-rw-r--r--drivers/media/video/videobuf-core.c229
-rw-r--r--drivers/media/video/videobuf-dma-contig.c27
-rw-r--r--drivers/media/video/videobuf-dma-sg.c128
-rw-r--r--drivers/media/video/videobuf-dvb.c2
-rw-r--r--drivers/media/video/videobuf-vmalloc.c45
-rw-r--r--drivers/media/video/vino.c7
-rw-r--r--drivers/media/video/vivi.c29
-rw-r--r--drivers/media/video/vp27smpx.c28
-rw-r--r--drivers/media/video/vpx3220.c27
-rw-r--r--drivers/media/video/w9966.c3
-rw-r--r--drivers/media/video/w9968cf.c3620
-rw-r--r--drivers/media/video/w9968cf.h333
-rw-r--r--drivers/media/video/w9968cf_decoder.h86
-rw-r--r--drivers/media/video/w9968cf_vpp.h40
-rw-r--r--drivers/media/video/wm8739.c206
-rw-r--r--drivers/media/video/wm8775.c107
-rw-r--r--drivers/media/video/zc0301/Kconfig15
-rw-r--r--drivers/media/video/zc0301/Makefile3
-rw-r--r--drivers/media/video/zc0301/zc0301.h196
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c2098
-rw-r--r--drivers/media/video/zc0301/zc0301_pas202bcb.c362
-rw-r--r--drivers/media/video/zc0301/zc0301_pb0330.c188
-rw-r--r--drivers/media/video/zc0301/zc0301_sensor.h107
-rw-r--r--drivers/media/video/zoran/videocodec.c5
-rw-r--r--drivers/media/video/zoran/videocodec.h2
-rw-r--r--drivers/media/video/zoran/zoran.h112
-rw-r--r--drivers/media/video/zoran/zoran_card.c29
-rw-r--r--drivers/media/video/zoran/zoran_device.c16
-rw-r--r--drivers/media/video/zoran/zoran_driver.c359
-rw-r--r--drivers/media/video/zoran/zr36050.c2
-rw-r--r--drivers/media/video/zoran/zr36060.c2
-rw-r--r--drivers/media/video/zr364xx.c4
799 files changed, 80958 insertions, 71888 deletions
diff --git a/drivers/media/IR/Kconfig b/drivers/media/IR/Kconfig
deleted file mode 100644
index 195c6cf359f6..000000000000
--- a/drivers/media/IR/Kconfig
+++ /dev/null
@@ -1,68 +0,0 @@
-config IR_CORE
- tristate
- depends on INPUT
- default INPUT
-
-config VIDEO_IR
- tristate
- depends on IR_CORE
- default IR_CORE
-
-source "drivers/media/IR/keymaps/Kconfig"
-
-config IR_NEC_DECODER
- tristate "Enable IR raw decoder for the NEC protocol"
- depends on IR_CORE
- default y
-
- ---help---
- Enable this option if you have IR with NEC protocol, and
- if the IR is decoded in software
-
-config IR_RC5_DECODER
- tristate "Enable IR raw decoder for the RC-5 protocol"
- depends on IR_CORE
- default y
-
- ---help---
- Enable this option if you have IR with RC-5 protocol, and
- if the IR is decoded in software
-
-config IR_RC6_DECODER
- tristate "Enable IR raw decoder for the RC6 protocol"
- depends on IR_CORE
- default y
-
- ---help---
- Enable this option if you have an infrared remote control which
- uses the RC6 protocol, and you need software decoding support.
-
-config IR_JVC_DECODER
- tristate "Enable IR raw decoder for the JVC protocol"
- depends on IR_CORE
- default y
-
- ---help---
- Enable this option if you have an infrared remote control which
- uses the JVC protocol, and you need software decoding support.
-
-config IR_SONY_DECODER
- tristate "Enable IR raw decoder for the Sony protocol"
- depends on IR_CORE
- default y
-
- ---help---
- Enable this option if you have an infrared remote control which
- uses the Sony protocol, and you need software decoding support.
-
-config IR_IMON
- tristate "SoundGraph iMON Receiver and Display"
- depends on USB_ARCH_HAS_HCD
- depends on IR_CORE
- select USB
- ---help---
- Say Y here if you want to use a SoundGraph iMON (aka Antec Veris)
- IR Receiver and/or LCD/VFD/VGA display.
-
- To compile this driver as a module, choose M here: the
- module will be called imon.
diff --git a/drivers/media/IR/Makefile b/drivers/media/IR/Makefile
deleted file mode 100644
index b998fcced2e4..000000000000
--- a/drivers/media/IR/Makefile
+++ /dev/null
@@ -1,15 +0,0 @@
-ir-common-objs := ir-functions.o
-ir-core-objs := ir-keytable.o ir-sysfs.o ir-raw-event.o rc-map.o
-
-obj-y += keymaps/
-
-obj-$(CONFIG_IR_CORE) += ir-core.o
-obj-$(CONFIG_VIDEO_IR) += ir-common.o
-obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
-obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
-obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
-obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
-obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
-
-# stand-alone IR receivers/transmitters
-obj-$(CONFIG_IR_IMON) += imon.o
diff --git a/drivers/media/IR/ir-functions.c b/drivers/media/IR/ir-functions.c
deleted file mode 100644
index db591e421887..000000000000
--- a/drivers/media/IR/ir-functions.c
+++ /dev/null
@@ -1,356 +0,0 @@
-/*
- *
- * some common structs and functions to handle infrared remotes via
- * input layer ...
- *
- * (c) 2003 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/jiffies.h>
-#include <media/ir-common.h>
-#include "ir-core-priv.h"
-
-/* -------------------------------------------------------------------------- */
-
-MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
-MODULE_LICENSE("GPL");
-
-static int repeat = 1;
-module_param(repeat, int, 0444);
-MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
-
-/* -------------------------------------------------------------------------- */
-
-static void ir_input_key_event(struct input_dev *dev, struct ir_input_state *ir)
-{
- if (KEY_RESERVED == ir->keycode) {
- printk(KERN_INFO "%s: unknown key: key=0x%02x down=%d\n",
- dev->name, ir->ir_key, ir->keypressed);
- return;
- }
- IR_dprintk(1,"%s: key event code=%d down=%d\n",
- dev->name,ir->keycode,ir->keypressed);
- input_report_key(dev,ir->keycode,ir->keypressed);
- input_sync(dev);
-}
-
-/* -------------------------------------------------------------------------- */
-
-int ir_input_init(struct input_dev *dev, struct ir_input_state *ir,
- const u64 ir_type)
-{
- ir->ir_type = ir_type;
-
- if (repeat)
- set_bit(EV_REP, dev->evbit);
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_input_init);
-
-
-void ir_input_nokey(struct input_dev *dev, struct ir_input_state *ir)
-{
- if (ir->keypressed) {
- ir->keypressed = 0;
- ir_input_key_event(dev,ir);
- }
-}
-EXPORT_SYMBOL_GPL(ir_input_nokey);
-
-void ir_input_keydown(struct input_dev *dev, struct ir_input_state *ir,
- u32 ir_key)
-{
- u32 keycode = ir_g_keycode_from_table(dev, ir_key);
-
- if (ir->keypressed && ir->keycode != keycode) {
- ir->keypressed = 0;
- ir_input_key_event(dev,ir);
- }
- if (!ir->keypressed) {
- ir->ir_key = ir_key;
- ir->keycode = keycode;
- ir->keypressed = 1;
- ir_input_key_event(dev,ir);
- }
-}
-EXPORT_SYMBOL_GPL(ir_input_keydown);
-
-/* -------------------------------------------------------------------------- */
-/* extract mask bits out of data and pack them into the result */
-u32 ir_extract_bits(u32 data, u32 mask)
-{
- u32 vbit = 1, value = 0;
-
- do {
- if (mask&1) {
- if (data&1)
- value |= vbit;
- vbit<<=1;
- }
- data>>=1;
- } while (mask>>=1);
-
- return value;
-}
-EXPORT_SYMBOL_GPL(ir_extract_bits);
-
-static int inline getbit(u32 *samples, int bit)
-{
- return (samples[bit/32] & (1 << (31-(bit%32)))) ? 1 : 0;
-}
-
-/* sump raw samples for visual debugging ;) */
-int ir_dump_samples(u32 *samples, int count)
-{
- int i, bit, start;
-
- printk(KERN_DEBUG "ir samples: ");
- start = 0;
- for (i = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit)
- start = 1;
- if (0 == start)
- continue;
- printk("%s", bit ? "#" : "_");
- }
- printk("\n");
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_dump_samples);
-
-/* decode raw samples, pulse distance coding used by NEC remotes */
-int ir_decode_pulsedistance(u32 *samples, int count, int low, int high)
-{
- int i,last,bit,len;
- u32 curBit;
- u32 value;
-
- /* find start burst */
- for (i = len = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit) {
- len++;
- } else {
- if (len >= 29)
- break;
- len = 0;
- }
- }
-
- /* start burst to short */
- if (len < 29)
- return 0xffffffff;
-
- /* find start silence */
- for (len = 0; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (bit) {
- break;
- } else {
- len++;
- }
- }
-
- /* silence to short */
- if (len < 7)
- return 0xffffffff;
-
- /* go decoding */
- len = 0;
- last = 1;
- value = 0; curBit = 1;
- for (; i < count * 32; i++) {
- bit = getbit(samples,i);
- if (last) {
- if(bit) {
- continue;
- } else {
- len = 1;
- }
- } else {
- if (bit) {
- if (len > (low + high) /2)
- value |= curBit;
- curBit <<= 1;
- if (curBit == 1)
- break;
- } else {
- len++;
- }
- }
- last = bit;
- }
-
- return value;
-}
-EXPORT_SYMBOL_GPL(ir_decode_pulsedistance);
-
-/* decode raw samples, biphase coding, used by rc5 for example */
-int ir_decode_biphase(u32 *samples, int count, int low, int high)
-{
- int i,last,bit,len,flips;
- u32 value;
-
- /* find start bit (1) */
- for (i = 0; i < 32; i++) {
- bit = getbit(samples,i);
- if (bit)
- break;
- }
-
- /* go decoding */
- len = 0;
- flips = 0;
- value = 1;
- for (; i < count * 32; i++) {
- if (len > high)
- break;
- if (flips > 1)
- break;
- last = bit;
- bit = getbit(samples,i);
- if (last == bit) {
- len++;
- continue;
- }
- if (len < low) {
- len++;
- flips++;
- continue;
- }
- value <<= 1;
- value |= bit;
- flips = 0;
- len = 1;
- }
- return value;
-}
-EXPORT_SYMBOL_GPL(ir_decode_biphase);
-
-/* RC5 decoding stuff, moved from bttv-input.c to share it with
- * saa7134 */
-
-/* decode raw bit pattern to RC5 code */
-u32 ir_rc5_decode(unsigned int code)
-{
- unsigned int org_code = code;
- unsigned int pair;
- unsigned int rc5 = 0;
- int i;
-
- for (i = 0; i < 14; ++i) {
- pair = code & 0x3;
- code >>= 2;
-
- rc5 <<= 1;
- switch (pair) {
- case 0:
- case 2:
- break;
- case 1:
- rc5 |= 1;
- break;
- case 3:
- IR_dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);
- return 0;
- }
- }
- IR_dprintk(1, "ir-common: code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
- "instr=%x\n", rc5, org_code, RC5_START(rc5),
- RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
- return rc5;
-}
-EXPORT_SYMBOL_GPL(ir_rc5_decode);
-
-void ir_rc5_timer_end(unsigned long data)
-{
- struct card_ir *ir = (struct card_ir *)data;
- struct timeval tv;
- unsigned long current_jiffies, timeout;
- u32 gap;
- u32 rc5 = 0;
-
- /* get time */
- current_jiffies = jiffies;
- do_gettimeofday(&tv);
-
- /* avoid overflow with gap >1s */
- if (tv.tv_sec - ir->base_time.tv_sec > 1) {
- gap = 200000;
- } else {
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
- }
-
- /* signal we're ready to start a new code */
- ir->active = 0;
-
- /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
- if (gap < 28000) {
- IR_dprintk(1, "ir-common: spurious timer_end\n");
- return;
- }
-
- if (ir->last_bit < 20) {
- /* ignore spurious codes (caused by light/other remotes) */
- IR_dprintk(1, "ir-common: short code: %x\n", ir->code);
- } else {
- ir->code = (ir->code << ir->shift_by) | 1;
- rc5 = ir_rc5_decode(ir->code);
-
- /* two start bits? */
- if (RC5_START(rc5) != ir->start) {
- IR_dprintk(1, "ir-common: rc5 start bits invalid: %u\n", RC5_START(rc5));
-
- /* right address? */
- } else if (RC5_ADDR(rc5) == ir->addr) {
- u32 toggle = RC5_TOGGLE(rc5);
- u32 instr = RC5_INSTR(rc5);
-
- /* Good code, decide if repeat/repress */
- if (toggle != RC5_TOGGLE(ir->last_rc5) ||
- instr != RC5_INSTR(ir->last_rc5)) {
- IR_dprintk(1, "ir-common: instruction %x, toggle %x\n", instr,
- toggle);
- ir_input_nokey(ir->dev, &ir->ir);
- ir_input_keydown(ir->dev, &ir->ir, instr);
- }
-
- /* Set/reset key-up timer */
- timeout = current_jiffies +
- msecs_to_jiffies(ir->rc5_key_timeout);
- mod_timer(&ir->timer_keyup, timeout);
-
- /* Save code for repeat test */
- ir->last_rc5 = rc5;
- }
- }
-}
-EXPORT_SYMBOL_GPL(ir_rc5_timer_end);
-
-void ir_rc5_timer_keyup(unsigned long data)
-{
- struct card_ir *ir = (struct card_ir *)data;
-
- IR_dprintk(1, "ir-common: key released\n");
- ir_input_nokey(ir->dev, &ir->ir);
-}
-EXPORT_SYMBOL_GPL(ir_rc5_timer_keyup);
diff --git a/drivers/media/IR/ir-keytable.c b/drivers/media/IR/ir-keytable.c
deleted file mode 100644
index 9374a006f43d..000000000000
--- a/drivers/media/IR/ir-keytable.c
+++ /dev/null
@@ -1,552 +0,0 @@
-/* ir-keytable.c - handle IR scancode->keycode tables
- *
- * Copyright (C) 2009 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-
-#include <linux/input.h>
-#include <linux/slab.h>
-#include "ir-core-priv.h"
-
-/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
-#define IR_TAB_MIN_SIZE 256
-#define IR_TAB_MAX_SIZE 8192
-
-/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
-#define IR_KEYPRESS_TIMEOUT 250
-
-/**
- * ir_resize_table() - resizes a scancode table if necessary
- * @rc_tab: the ir_scancode_table to resize
- * @return: zero on success or a negative error code
- *
- * This routine will shrink the ir_scancode_table if it has lots of
- * unused entries and grow it if it is full.
- */
-static int ir_resize_table(struct ir_scancode_table *rc_tab)
-{
- unsigned int oldalloc = rc_tab->alloc;
- unsigned int newalloc = oldalloc;
- struct ir_scancode *oldscan = rc_tab->scan;
- struct ir_scancode *newscan;
-
- if (rc_tab->size == rc_tab->len) {
- /* All entries in use -> grow keytable */
- if (rc_tab->alloc >= IR_TAB_MAX_SIZE)
- return -ENOMEM;
-
- newalloc *= 2;
- IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
- }
-
- if ((rc_tab->len * 3 < rc_tab->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
- /* Less than 1/3 of entries in use -> shrink keytable */
- newalloc /= 2;
- IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
- }
-
- if (newalloc == oldalloc)
- return 0;
-
- newscan = kmalloc(newalloc, GFP_ATOMIC);
- if (!newscan) {
- IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
- return -ENOMEM;
- }
-
- memcpy(newscan, rc_tab->scan, rc_tab->len * sizeof(struct ir_scancode));
- rc_tab->scan = newscan;
- rc_tab->alloc = newalloc;
- rc_tab->size = rc_tab->alloc / sizeof(struct ir_scancode);
- kfree(oldscan);
- return 0;
-}
-
-/**
- * ir_do_setkeycode() - internal function to set a keycode in the
- * scancode->keycode table
- * @dev: the struct input_dev device descriptor
- * @rc_tab: the struct ir_scancode_table to set the keycode in
- * @scancode: the scancode for the ir command
- * @keycode: the keycode for the ir command
- * @resize: whether the keytable may be shrunk
- * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
- *
- * This routine is used internally to manipulate the scancode->keycode table.
- * The caller has to hold @rc_tab->lock.
- */
-static int ir_do_setkeycode(struct input_dev *dev,
- struct ir_scancode_table *rc_tab,
- unsigned scancode, unsigned keycode,
- bool resize)
-{
- unsigned int i;
- int old_keycode = KEY_RESERVED;
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
-
- /*
- * Unfortunately, some hardware-based IR decoders don't provide
- * all bits for the complete IR code. In general, they provide only
- * the command part of the IR code. Yet, as it is possible to replace
- * the provided IR with another one, it is needed to allow loading
- * IR tables from other remotes. So,
- */
- if (ir_dev->props && ir_dev->props->scanmask) {
- scancode &= ir_dev->props->scanmask;
- }
-
- /* First check if we already have a mapping for this ir command */
- for (i = 0; i < rc_tab->len; i++) {
- /* Keytable is sorted from lowest to highest scancode */
- if (rc_tab->scan[i].scancode > scancode)
- break;
- else if (rc_tab->scan[i].scancode < scancode)
- continue;
-
- old_keycode = rc_tab->scan[i].keycode;
- rc_tab->scan[i].keycode = keycode;
-
- /* Did the user wish to remove the mapping? */
- if (keycode == KEY_RESERVED || keycode == KEY_UNKNOWN) {
- IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
- i, scancode);
- rc_tab->len--;
- memmove(&rc_tab->scan[i], &rc_tab->scan[i + 1],
- (rc_tab->len - i) * sizeof(struct ir_scancode));
- }
-
- /* Possibly shrink the keytable, failure is not a problem */
- ir_resize_table(rc_tab);
- break;
- }
-
- if (old_keycode == KEY_RESERVED && keycode != KEY_RESERVED) {
- /* No previous mapping found, we might need to grow the table */
- if (resize && ir_resize_table(rc_tab))
- return -ENOMEM;
-
- IR_dprintk(1, "#%d: New scan 0x%04x with key 0x%04x\n",
- i, scancode, keycode);
-
- /* i is the proper index to insert our new keycode */
- memmove(&rc_tab->scan[i + 1], &rc_tab->scan[i],
- (rc_tab->len - i) * sizeof(struct ir_scancode));
- rc_tab->scan[i].scancode = scancode;
- rc_tab->scan[i].keycode = keycode;
- rc_tab->len++;
- set_bit(keycode, dev->keybit);
- } else {
- IR_dprintk(1, "#%d: Replacing scan 0x%04x with key 0x%04x\n",
- i, scancode, keycode);
- /* A previous mapping was updated... */
- clear_bit(old_keycode, dev->keybit);
- /* ...but another scancode might use the same keycode */
- for (i = 0; i < rc_tab->len; i++) {
- if (rc_tab->scan[i].keycode == old_keycode) {
- set_bit(old_keycode, dev->keybit);
- break;
- }
- }
- }
-
- return 0;
-}
-
-/**
- * ir_setkeycode() - set a keycode in the scancode->keycode table
- * @dev: the struct input_dev device descriptor
- * @scancode: the desired scancode
- * @keycode: result
- * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
- *
- * This routine is used to handle evdev EVIOCSKEY ioctl.
- */
-static int ir_setkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int keycode)
-{
- int rc;
- unsigned long flags;
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
- struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
-
- spin_lock_irqsave(&rc_tab->lock, flags);
- rc = ir_do_setkeycode(dev, rc_tab, scancode, keycode, true);
- spin_unlock_irqrestore(&rc_tab->lock, flags);
- return rc;
-}
-
-/**
- * ir_setkeytable() - sets several entries in the scancode->keycode table
- * @dev: the struct input_dev device descriptor
- * @to: the struct ir_scancode_table to copy entries to
- * @from: the struct ir_scancode_table to copy entries from
- * @return: -EINVAL if all keycodes could not be inserted, otherwise zero.
- *
- * This routine is used to handle table initialization.
- */
-static int ir_setkeytable(struct input_dev *dev,
- struct ir_scancode_table *to,
- const struct ir_scancode_table *from)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
- struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
- unsigned long flags;
- unsigned int i;
- int rc = 0;
-
- spin_lock_irqsave(&rc_tab->lock, flags);
- for (i = 0; i < from->size; i++) {
- rc = ir_do_setkeycode(dev, to, from->scan[i].scancode,
- from->scan[i].keycode, false);
- if (rc)
- break;
- }
- spin_unlock_irqrestore(&rc_tab->lock, flags);
- return rc;
-}
-
-/**
- * ir_getkeycode() - get a keycode from the scancode->keycode table
- * @dev: the struct input_dev device descriptor
- * @scancode: the desired scancode
- * @keycode: used to return the keycode, if found, or KEY_RESERVED
- * @return: always returns zero.
- *
- * This routine is used to handle evdev EVIOCGKEY ioctl.
- */
-static int ir_getkeycode(struct input_dev *dev,
- unsigned int scancode, unsigned int *keycode)
-{
- int start, end, mid;
- unsigned long flags;
- int key = KEY_RESERVED;
- struct ir_input_dev *ir_dev = input_get_drvdata(dev);
- struct ir_scancode_table *rc_tab = &ir_dev->rc_tab;
-
- spin_lock_irqsave(&rc_tab->lock, flags);
- start = 0;
- end = rc_tab->len - 1;
- while (start <= end) {
- mid = (start + end) / 2;
- if (rc_tab->scan[mid].scancode < scancode)
- start = mid + 1;
- else if (rc_tab->scan[mid].scancode > scancode)
- end = mid - 1;
- else {
- key = rc_tab->scan[mid].keycode;
- break;
- }
- }
- spin_unlock_irqrestore(&rc_tab->lock, flags);
-
- if (key == KEY_RESERVED)
- IR_dprintk(1, "unknown key for scancode 0x%04x\n",
- scancode);
-
- *keycode = key;
- return 0;
-}
-
-/**
- * ir_g_keycode_from_table() - gets the keycode that corresponds to a scancode
- * @input_dev: the struct input_dev descriptor of the device
- * @scancode: the scancode that we're seeking
- *
- * This routine is used by the input routines when a key is pressed at the
- * IR. The scancode is received and needs to be converted into a keycode.
- * If the key is not found, it returns KEY_RESERVED. Otherwise, returns the
- * corresponding keycode from the table.
- */
-u32 ir_g_keycode_from_table(struct input_dev *dev, u32 scancode)
-{
- int keycode;
-
- ir_getkeycode(dev, scancode, &keycode);
- if (keycode != KEY_RESERVED)
- IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
- dev->name, scancode, keycode);
- return keycode;
-}
-EXPORT_SYMBOL_GPL(ir_g_keycode_from_table);
-
-/**
- * ir_keyup() - generates input event to cleanup a key press
- * @ir: the struct ir_input_dev descriptor of the device
- *
- * This routine is used to signal that a key has been released on the
- * remote control. It reports a keyup input event via input_report_key().
- */
-static void ir_keyup(struct ir_input_dev *ir)
-{
- if (!ir->keypressed)
- return;
-
- IR_dprintk(1, "keyup key 0x%04x\n", ir->last_keycode);
- input_report_key(ir->input_dev, ir->last_keycode, 0);
- input_sync(ir->input_dev);
- ir->keypressed = false;
-}
-
-/**
- * ir_timer_keyup() - generates a keyup event after a timeout
- * @cookie: a pointer to struct ir_input_dev passed to setup_timer()
- *
- * This routine will generate a keyup event some time after a keydown event
- * is generated when no further activity has been detected.
- */
-static void ir_timer_keyup(unsigned long cookie)
-{
- struct ir_input_dev *ir = (struct ir_input_dev *)cookie;
- unsigned long flags;
-
- /*
- * ir->keyup_jiffies is used to prevent a race condition if a
- * hardware interrupt occurs at this point and the keyup timer
- * event is moved further into the future as a result.
- *
- * The timer will then be reactivated and this function called
- * again in the future. We need to exit gracefully in that case
- * to allow the input subsystem to do its auto-repeat magic or
- * a keyup event might follow immediately after the keydown.
- */
- spin_lock_irqsave(&ir->keylock, flags);
- if (time_is_after_eq_jiffies(ir->keyup_jiffies))
- ir_keyup(ir);
- spin_unlock_irqrestore(&ir->keylock, flags);
-}
-
-/**
- * ir_repeat() - notifies the IR core that a key is still pressed
- * @dev: the struct input_dev descriptor of the device
- *
- * This routine is used by IR decoders when a repeat message which does
- * not include the necessary bits to reproduce the scancode has been
- * received.
- */
-void ir_repeat(struct input_dev *dev)
-{
- unsigned long flags;
- struct ir_input_dev *ir = input_get_drvdata(dev);
-
- spin_lock_irqsave(&ir->keylock, flags);
-
- if (!ir->keypressed)
- goto out;
-
- ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
- mod_timer(&ir->timer_keyup, ir->keyup_jiffies);
-
-out:
- spin_unlock_irqrestore(&ir->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(ir_repeat);
-
-/**
- * ir_keydown() - generates input event for a key press
- * @dev: the struct input_dev descriptor of the device
- * @scancode: the scancode that we're seeking
- * @toggle: the toggle value (protocol dependent, if the protocol doesn't
- * support toggle values, this should be set to zero)
- *
- * This routine is used by the input routines when a key is pressed at the
- * IR. It gets the keycode for a scancode and reports an input event via
- * input_report_key().
- */
-void ir_keydown(struct input_dev *dev, int scancode, u8 toggle)
-{
- unsigned long flags;
- struct ir_input_dev *ir = input_get_drvdata(dev);
-
- u32 keycode = ir_g_keycode_from_table(dev, scancode);
-
- spin_lock_irqsave(&ir->keylock, flags);
-
- /* Repeat event? */
- if (ir->keypressed &&
- ir->last_scancode == scancode &&
- ir->last_toggle == toggle)
- goto set_timer;
-
- /* Release old keypress */
- ir_keyup(ir);
-
- ir->last_scancode = scancode;
- ir->last_toggle = toggle;
- ir->last_keycode = keycode;
-
- if (keycode == KEY_RESERVED)
- goto out;
-
- /* Register a keypress */
- ir->keypressed = true;
- IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
- dev->name, keycode, scancode);
- input_report_key(dev, ir->last_keycode, 1);
- input_sync(dev);
-
-set_timer:
- ir->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
- mod_timer(&ir->timer_keyup, ir->keyup_jiffies);
-out:
- spin_unlock_irqrestore(&ir->keylock, flags);
-}
-EXPORT_SYMBOL_GPL(ir_keydown);
-
-static int ir_open(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-
- return ir_dev->props->open(ir_dev->props->priv);
-}
-
-static void ir_close(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-
- ir_dev->props->close(ir_dev->props->priv);
-}
-
-/**
- * __ir_input_register() - sets the IR keycode table and add the handlers
- * for keymap table get/set
- * @input_dev: the struct input_dev descriptor of the device
- * @rc_tab: the struct ir_scancode_table table of scancode/keymap
- *
- * This routine is used to initialize the input infrastructure
- * to work with an IR.
- * It will register the input/evdev interface for the device and
- * register the syfs code for IR class
- */
-int __ir_input_register(struct input_dev *input_dev,
- const struct ir_scancode_table *rc_tab,
- const struct ir_dev_props *props,
- const char *driver_name)
-{
- struct ir_input_dev *ir_dev;
- int rc;
-
- if (rc_tab->scan == NULL || !rc_tab->size)
- return -EINVAL;
-
- ir_dev = kzalloc(sizeof(*ir_dev), GFP_KERNEL);
- if (!ir_dev)
- return -ENOMEM;
-
- ir_dev->driver_name = kasprintf(GFP_KERNEL, "%s", driver_name);
- if (!ir_dev->driver_name) {
- rc = -ENOMEM;
- goto out_dev;
- }
-
- input_dev->getkeycode = ir_getkeycode;
- input_dev->setkeycode = ir_setkeycode;
- input_set_drvdata(input_dev, ir_dev);
- ir_dev->input_dev = input_dev;
-
- spin_lock_init(&ir_dev->rc_tab.lock);
- spin_lock_init(&ir_dev->keylock);
- setup_timer(&ir_dev->timer_keyup, ir_timer_keyup, (unsigned long)ir_dev);
-
- ir_dev->rc_tab.name = rc_tab->name;
- ir_dev->rc_tab.ir_type = rc_tab->ir_type;
- ir_dev->rc_tab.alloc = roundup_pow_of_two(rc_tab->size *
- sizeof(struct ir_scancode));
- ir_dev->rc_tab.scan = kmalloc(ir_dev->rc_tab.alloc, GFP_KERNEL);
- ir_dev->rc_tab.size = ir_dev->rc_tab.alloc / sizeof(struct ir_scancode);
- if (props) {
- ir_dev->props = props;
- if (props->open)
- input_dev->open = ir_open;
- if (props->close)
- input_dev->close = ir_close;
- }
-
- if (!ir_dev->rc_tab.scan) {
- rc = -ENOMEM;
- goto out_name;
- }
-
- IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
- ir_dev->rc_tab.size, ir_dev->rc_tab.alloc);
-
- set_bit(EV_KEY, input_dev->evbit);
- set_bit(EV_REP, input_dev->evbit);
-
- if (ir_setkeytable(input_dev, &ir_dev->rc_tab, rc_tab)) {
- rc = -ENOMEM;
- goto out_table;
- }
-
- rc = ir_register_class(input_dev);
- if (rc < 0)
- goto out_table;
-
- if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW) {
- rc = ir_raw_event_register(input_dev);
- if (rc < 0)
- goto out_event;
- }
-
- IR_dprintk(1, "Registered input device on %s for %s remote.\n",
- driver_name, rc_tab->name);
-
- return 0;
-
-out_event:
- ir_unregister_class(input_dev);
-out_table:
- kfree(ir_dev->rc_tab.scan);
-out_name:
- kfree(ir_dev->driver_name);
-out_dev:
- kfree(ir_dev);
- return rc;
-}
-EXPORT_SYMBOL_GPL(__ir_input_register);
-
-/**
- * ir_input_unregister() - unregisters IR and frees resources
- * @input_dev: the struct input_dev descriptor of the device
-
- * This routine is used to free memory and de-register interfaces.
- */
-void ir_input_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct ir_scancode_table *rc_tab;
-
- if (!ir_dev)
- return;
-
- IR_dprintk(1, "Freed keycode table\n");
-
- del_timer_sync(&ir_dev->timer_keyup);
- if (ir_dev->props->driver_type == RC_DRIVER_IR_RAW)
- ir_raw_event_unregister(input_dev);
- rc_tab = &ir_dev->rc_tab;
- rc_tab->size = 0;
- kfree(rc_tab->scan);
- rc_tab->scan = NULL;
-
- ir_unregister_class(input_dev);
-
- kfree(ir_dev->driver_name);
- kfree(ir_dev);
-}
-EXPORT_SYMBOL_GPL(ir_input_unregister);
-
-int ir_core_debug; /* ir_debug level (0,1,2) */
-EXPORT_SYMBOL_GPL(ir_core_debug);
-module_param_named(debug, ir_core_debug, int, 0644);
-
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/IR/ir-raw-event.c b/drivers/media/IR/ir-raw-event.c
deleted file mode 100644
index ea68a3f2effa..000000000000
--- a/drivers/media/IR/ir-raw-event.c
+++ /dev/null
@@ -1,251 +0,0 @@
-/* ir-raw-event.c - handle IR Pulse/Space event
- *
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/workqueue.h>
-#include <linux/spinlock.h>
-#include <linux/sched.h>
-#include "ir-core-priv.h"
-
-/* Define the max number of pulse/space transitions to buffer */
-#define MAX_IR_EVENT_SIZE 512
-
-/* Used to handle IR raw handler extensions */
-static LIST_HEAD(ir_raw_handler_list);
-static DEFINE_SPINLOCK(ir_raw_handler_lock);
-
-/**
- * RUN_DECODER() - runs an operation on all IR decoders
- * @ops: IR raw handler operation to be called
- * @arg: arguments to be passed to the callback
- *
- * Calls ir_raw_handler::ops for all registered IR handlers. It prevents
- * new decode addition/removal while running, by locking ir_raw_handler_lock
- * mutex. If an error occurs, it stops the ops. Otherwise, it returns a sum
- * of the return codes.
- */
-#define RUN_DECODER(ops, ...) ({ \
- struct ir_raw_handler *_ir_raw_handler; \
- int _sumrc = 0, _rc; \
- spin_lock(&ir_raw_handler_lock); \
- list_for_each_entry(_ir_raw_handler, &ir_raw_handler_list, list) { \
- if (_ir_raw_handler->ops) { \
- _rc = _ir_raw_handler->ops(__VA_ARGS__); \
- if (_rc < 0) \
- break; \
- _sumrc += _rc; \
- } \
- } \
- spin_unlock(&ir_raw_handler_lock); \
- _sumrc; \
-})
-
-#ifdef MODULE
-/* Used to load the decoders */
-static struct work_struct wq_load;
-#endif
-
-static void ir_raw_event_work(struct work_struct *work)
-{
- struct ir_raw_event ev;
- struct ir_raw_event_ctrl *raw =
- container_of(work, struct ir_raw_event_ctrl, rx_work);
-
- while (kfifo_out(&raw->kfifo, &ev, sizeof(ev)) == sizeof(ev))
- RUN_DECODER(decode, raw->input_dev, ev);
-}
-
-int ir_raw_event_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
- int rc;
-
- ir->raw = kzalloc(sizeof(*ir->raw), GFP_KERNEL);
- if (!ir->raw)
- return -ENOMEM;
-
- ir->raw->input_dev = input_dev;
- INIT_WORK(&ir->raw->rx_work, ir_raw_event_work);
-
- rc = kfifo_alloc(&ir->raw->kfifo, sizeof(s64) * MAX_IR_EVENT_SIZE,
- GFP_KERNEL);
- if (rc < 0) {
- kfree(ir->raw);
- ir->raw = NULL;
- return rc;
- }
-
- rc = RUN_DECODER(raw_register, input_dev);
- if (rc < 0) {
- kfifo_free(&ir->raw->kfifo);
- kfree(ir->raw);
- ir->raw = NULL;
- return rc;
- }
-
- return rc;
-}
-
-void ir_raw_event_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
-
- if (!ir->raw)
- return;
-
- cancel_work_sync(&ir->raw->rx_work);
- RUN_DECODER(raw_unregister, input_dev);
-
- kfifo_free(&ir->raw->kfifo);
- kfree(ir->raw);
- ir->raw = NULL;
-}
-
-/**
- * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
- * @input_dev: the struct input_dev device descriptor
- * @ev: the struct ir_raw_event descriptor of the pulse/space
- *
- * This routine (which may be called from an interrupt context) stores a
- * pulse/space duration for the raw ir decoding state machines. Pulses are
- * signalled as positive values and spaces as negative values. A zero value
- * will reset the decoding state machines.
- */
-int ir_raw_event_store(struct input_dev *input_dev, struct ir_raw_event *ev)
-{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
-
- if (!ir->raw)
- return -EINVAL;
-
- if (kfifo_in(&ir->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
- return -ENOMEM;
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_raw_event_store);
-
-/**
- * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
- * @input_dev: the struct input_dev device descriptor
- * @type: the type of the event that has occurred
- *
- * This routine (which may be called from an interrupt context) is used to
- * store the beginning of an ir pulse or space (or the start/end of ir
- * reception) for the raw ir decoding state machines. This is used by
- * hardware which does not provide durations directly but only interrupts
- * (or similar events) on state change.
- */
-int ir_raw_event_store_edge(struct input_dev *input_dev, enum raw_event_type type)
-{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
- ktime_t now;
- s64 delta; /* ns */
- struct ir_raw_event ev;
- int rc = 0;
-
- if (!ir->raw)
- return -EINVAL;
-
- now = ktime_get();
- delta = ktime_to_ns(ktime_sub(now, ir->raw->last_event));
-
- /* Check for a long duration since last event or if we're
- * being called for the first time, note that delta can't
- * possibly be negative.
- */
- ev.duration = 0;
- if (delta > IR_MAX_DURATION || !ir->raw->last_type)
- type |= IR_START_EVENT;
- else
- ev.duration = delta;
-
- if (type & IR_START_EVENT)
- ir_raw_event_reset(input_dev);
- else if (ir->raw->last_type & IR_SPACE) {
- ev.pulse = false;
- rc = ir_raw_event_store(input_dev, &ev);
- } else if (ir->raw->last_type & IR_PULSE) {
- ev.pulse = true;
- rc = ir_raw_event_store(input_dev, &ev);
- } else
- return 0;
-
- ir->raw->last_event = now;
- ir->raw->last_type = type;
- return rc;
-}
-EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
-
-/**
- * ir_raw_event_handle() - schedules the decoding of stored ir data
- * @input_dev: the struct input_dev device descriptor
- *
- * This routine will signal the workqueue to start decoding stored ir data.
- */
-void ir_raw_event_handle(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir = input_get_drvdata(input_dev);
-
- if (!ir->raw)
- return;
-
- schedule_work(&ir->raw->rx_work);
-}
-EXPORT_SYMBOL_GPL(ir_raw_event_handle);
-
-/*
- * Extension interface - used to register the IR decoders
- */
-
-int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
-{
- spin_lock(&ir_raw_handler_lock);
- list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
- spin_unlock(&ir_raw_handler_lock);
- return 0;
-}
-EXPORT_SYMBOL(ir_raw_handler_register);
-
-void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
-{
- spin_lock(&ir_raw_handler_lock);
- list_del(&ir_raw_handler->list);
- spin_unlock(&ir_raw_handler_lock);
-}
-EXPORT_SYMBOL(ir_raw_handler_unregister);
-
-#ifdef MODULE
-static void init_decoders(struct work_struct *work)
-{
- /* Load the decoder modules */
-
- load_nec_decode();
- load_rc5_decode();
- load_rc6_decode();
- load_jvc_decode();
- load_sony_decode();
-
- /* If needed, we may later add some init code. In this case,
- it is needed to change the CONFIG_MODULE test at ir-core.h
- */
-}
-#endif
-
-void ir_raw_init(void)
-{
-#ifdef MODULE
- INIT_WORK(&wq_load, init_decoders);
- schedule_work(&wq_load);
-#endif
-}
diff --git a/drivers/media/IR/ir-sysfs.c b/drivers/media/IR/ir-sysfs.c
deleted file mode 100644
index d7da63e16c92..000000000000
--- a/drivers/media/IR/ir-sysfs.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* ir-sysfs.c - sysfs interface for RC devices (/sys/class/rc)
- *
- * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/device.h>
-#include "ir-core-priv.h"
-
-#define IRRCV_NUM_DEVICES 256
-
-/* bit array to represent IR sysfs device number */
-static unsigned long ir_core_dev_number;
-
-/* class for /sys/class/rc */
-static char *ir_devnode(struct device *dev, mode_t *mode)
-{
- return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
-}
-
-static struct class ir_input_class = {
- .name = "rc",
- .devnode = ir_devnode,
-};
-
-/**
- * show_protocol() - shows the current IR protocol
- * @d: the device descriptor
- * @mattr: the device attribute struct (unused)
- * @buf: a pointer to the output buffer
- *
- * This routine is a callback routine for input read the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It returns the protocol name, as understood by the driver.
- */
-static ssize_t show_protocol(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- char *s;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- u64 ir_type = ir_dev->rc_tab.ir_type;
-
- IR_dprintk(1, "Current protocol is %lld\n", (long long)ir_type);
-
- /* FIXME: doesn't support multiple protocols at the same time */
- if (ir_type == IR_TYPE_UNKNOWN)
- s = "Unknown";
- else if (ir_type == IR_TYPE_RC5)
- s = "rc-5";
- else if (ir_type == IR_TYPE_NEC)
- s = "nec";
- else if (ir_type == IR_TYPE_RC6)
- s = "rc6";
- else if (ir_type == IR_TYPE_JVC)
- s = "jvc";
- else if (ir_type == IR_TYPE_SONY)
- s = "sony";
- else
- s = "other";
-
- return sprintf(buf, "%s\n", s);
-}
-
-/**
- * store_protocol() - shows the current IR protocol
- * @d: the device descriptor
- * @mattr: the device attribute struct (unused)
- * @buf: a pointer to the input buffer
- * @len: length of the input buffer
- *
- * This routine is a callback routine for changing the IR protocol type.
- * it is trigged by reading /sys/class/rc/rc?/current_protocol.
- * It changes the IR the protocol name, if the IR type is recognized
- * by the driver.
- * If an unknown protocol name is used, returns -EINVAL.
- */
-static ssize_t store_protocol(struct device *d,
- struct device_attribute *mattr,
- const char *data,
- size_t len)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- u64 ir_type = 0;
- int rc = -EINVAL;
- unsigned long flags;
- char *buf;
-
- while ((buf = strsep((char **) &data, " \n")) != NULL) {
- if (!strcasecmp(buf, "rc-5") || !strcasecmp(buf, "rc5"))
- ir_type |= IR_TYPE_RC5;
- if (!strcasecmp(buf, "nec"))
- ir_type |= IR_TYPE_NEC;
- if (!strcasecmp(buf, "jvc"))
- ir_type |= IR_TYPE_JVC;
- if (!strcasecmp(buf, "sony"))
- ir_type |= IR_TYPE_SONY;
- }
-
- if (!ir_type) {
- IR_dprintk(1, "Unknown protocol\n");
- return -EINVAL;
- }
-
- if (ir_dev->props && ir_dev->props->change_protocol)
- rc = ir_dev->props->change_protocol(ir_dev->props->priv,
- ir_type);
-
- if (rc < 0) {
- IR_dprintk(1, "Error setting protocol to %lld\n",
- (long long)ir_type);
- return -EINVAL;
- }
-
- spin_lock_irqsave(&ir_dev->rc_tab.lock, flags);
- ir_dev->rc_tab.ir_type = ir_type;
- spin_unlock_irqrestore(&ir_dev->rc_tab.lock, flags);
-
- IR_dprintk(1, "Current protocol(s) is(are) %lld\n",
- (long long)ir_type);
-
- return len;
-}
-
-static ssize_t show_supported_protocols(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- char *orgbuf = buf;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
-
- /* FIXME: doesn't support multiple protocols at the same time */
- if (ir_dev->props->allowed_protos == IR_TYPE_UNKNOWN)
- buf += sprintf(buf, "unknown ");
- if (ir_dev->props->allowed_protos & IR_TYPE_RC5)
- buf += sprintf(buf, "rc-5 ");
- if (ir_dev->props->allowed_protos & IR_TYPE_NEC)
- buf += sprintf(buf, "nec ");
- if (buf == orgbuf)
- buf += sprintf(buf, "other ");
-
- buf += sprintf(buf - 1, "\n");
-
- return buf - orgbuf;
-}
-
-#define ADD_HOTPLUG_VAR(fmt, val...) \
- do { \
- int err = add_uevent_var(env, fmt, val); \
- if (err) \
- return err; \
- } while (0)
-
-static int ir_dev_uevent(struct device *device, struct kobj_uevent_env *env)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(device);
-
- if (ir_dev->rc_tab.name)
- ADD_HOTPLUG_VAR("NAME=%s", ir_dev->rc_tab.name);
- if (ir_dev->driver_name)
- ADD_HOTPLUG_VAR("DRV_NAME=%s", ir_dev->driver_name);
-
- return 0;
-}
-
-/*
- * Static device attribute struct with the sysfs attributes for IR's
- */
-static DEVICE_ATTR(protocol, S_IRUGO | S_IWUSR,
- show_protocol, store_protocol);
-
-static DEVICE_ATTR(supported_protocols, S_IRUGO | S_IWUSR,
- show_supported_protocols, NULL);
-
-static struct attribute *ir_hw_dev_attrs[] = {
- &dev_attr_protocol.attr,
- &dev_attr_supported_protocols.attr,
- NULL,
-};
-
-static struct attribute_group ir_hw_dev_attr_grp = {
- .attrs = ir_hw_dev_attrs,
-};
-
-static const struct attribute_group *ir_hw_dev_attr_groups[] = {
- &ir_hw_dev_attr_grp,
- NULL
-};
-
-static struct device_type rc_dev_type = {
- .groups = ir_hw_dev_attr_groups,
- .uevent = ir_dev_uevent,
-};
-
-static struct device_type ir_raw_dev_type = {
- .uevent = ir_dev_uevent,
-};
-
-/**
- * ir_register_class() - creates the sysfs for /sys/class/rc/rc?
- * @input_dev: the struct input_dev descriptor of the device
- *
- * This routine is used to register the syfs code for IR class
- */
-int ir_register_class(struct input_dev *input_dev)
-{
- int rc;
- const char *path;
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- int devno = find_first_zero_bit(&ir_core_dev_number,
- IRRCV_NUM_DEVICES);
-
- if (unlikely(devno < 0))
- return devno;
-
- if (ir_dev->props->driver_type == RC_DRIVER_SCANCODE)
- ir_dev->dev.type = &rc_dev_type;
- else
- ir_dev->dev.type = &ir_raw_dev_type;
-
- ir_dev->dev.class = &ir_input_class;
- ir_dev->dev.parent = input_dev->dev.parent;
- dev_set_name(&ir_dev->dev, "rc%d", devno);
- dev_set_drvdata(&ir_dev->dev, ir_dev);
- rc = device_register(&ir_dev->dev);
- if (rc)
- return rc;
-
-
- input_dev->dev.parent = &ir_dev->dev;
- rc = input_register_device(input_dev);
- if (rc < 0) {
- device_del(&ir_dev->dev);
- return rc;
- }
-
- __module_get(THIS_MODULE);
-
- path = kobject_get_path(&ir_dev->dev.kobj, GFP_KERNEL);
- printk(KERN_INFO "%s: %s as %s\n",
- dev_name(&ir_dev->dev),
- input_dev->name ? input_dev->name : "Unspecified device",
- path ? path : "N/A");
- kfree(path);
-
- ir_dev->devno = devno;
- set_bit(devno, &ir_core_dev_number);
-
- return 0;
-};
-
-/**
- * ir_unregister_class() - removes the sysfs for sysfs for
- * /sys/class/rc/rc?
- * @input_dev: the struct input_dev descriptor of the device
- *
- * This routine is used to unregister the syfs code for IR class
- */
-void ir_unregister_class(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-
- clear_bit(ir_dev->devno, &ir_core_dev_number);
- input_unregister_device(input_dev);
- device_del(&ir_dev->dev);
-
- module_put(THIS_MODULE);
-}
-
-/*
- * Init/exit code for the module. Basically, creates/removes /sys/class/rc
- */
-
-static int __init ir_core_init(void)
-{
- int rc = class_register(&ir_input_class);
- if (rc) {
- printk(KERN_ERR "ir_core: unable to register rc class\n");
- return rc;
- }
-
- /* Initialize/load the decoders/keymap code that will be used */
- ir_raw_init();
-
- return 0;
-}
-
-static void __exit ir_core_exit(void)
-{
- class_unregister(&ir_input_class);
-}
-
-module_init(ir_core_init);
-module_exit(ir_core_exit);
diff --git a/drivers/media/IR/keymaps/rc-asus-pc39.c b/drivers/media/IR/keymaps/rc-asus-pc39.c
deleted file mode 100644
index 2aa068cd6c75..000000000000
--- a/drivers/media/IR/keymaps/rc-asus-pc39.c
+++ /dev/null
@@ -1,91 +0,0 @@
-/* asus-pc39.h - Keytable for asus_pc39 Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/*
- * Marc Fargas <telenieko@telenieko.com>
- * this is the remote control that comes with the asus p7131
- * which has a label saying is "Model PC-39"
- */
-
-static struct ir_scancode asus_pc39[] = {
- /* Keys 0 to 9 */
- { 0x15, KEY_0 },
- { 0x29, KEY_1 },
- { 0x2d, KEY_2 },
- { 0x2b, KEY_3 },
- { 0x09, KEY_4 },
- { 0x0d, KEY_5 },
- { 0x0b, KEY_6 },
- { 0x31, KEY_7 },
- { 0x35, KEY_8 },
- { 0x33, KEY_9 },
-
- { 0x3e, KEY_RADIO }, /* radio */
- { 0x03, KEY_MENU }, /* dvd/menu */
- { 0x2a, KEY_VOLUMEUP },
- { 0x19, KEY_VOLUMEDOWN },
- { 0x37, KEY_UP },
- { 0x3b, KEY_DOWN },
- { 0x27, KEY_LEFT },
- { 0x2f, KEY_RIGHT },
- { 0x25, KEY_VIDEO }, /* video */
- { 0x39, KEY_AUDIO }, /* music */
-
- { 0x21, KEY_TV }, /* tv */
- { 0x1d, KEY_EXIT }, /* back */
- { 0x0a, KEY_CHANNELUP }, /* channel / program + */
- { 0x1b, KEY_CHANNELDOWN }, /* channel / program - */
- { 0x1a, KEY_ENTER }, /* enter */
-
- { 0x06, KEY_PAUSE }, /* play/pause */
- { 0x1e, KEY_PREVIOUS }, /* rew */
- { 0x26, KEY_NEXT }, /* forward */
- { 0x0e, KEY_REWIND }, /* backward << */
- { 0x3a, KEY_FASTFORWARD }, /* forward >> */
- { 0x36, KEY_STOP },
- { 0x2e, KEY_RECORD }, /* recording */
- { 0x16, KEY_POWER }, /* the button that reads "close" */
-
- { 0x11, KEY_ZOOM }, /* full screen */
- { 0x13, KEY_MACRO }, /* recall */
- { 0x23, KEY_HOME }, /* home */
- { 0x05, KEY_PVR }, /* picture */
- { 0x3d, KEY_MUTE }, /* mute */
- { 0x01, KEY_DVD }, /* dvd */
-};
-
-static struct rc_keymap asus_pc39_map = {
- .map = {
- .scan = asus_pc39,
- .size = ARRAY_SIZE(asus_pc39),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_ASUS_PC39,
- }
-};
-
-static int __init init_rc_map_asus_pc39(void)
-{
- return ir_register_map(&asus_pc39_map);
-}
-
-static void __exit exit_rc_map_asus_pc39(void)
-{
- ir_unregister_map(&asus_pc39_map);
-}
-
-module_init(init_rc_map_asus_pc39)
-module_exit(exit_rc_map_asus_pc39)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c b/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c
deleted file mode 100644
index 101e7ea85941..000000000000
--- a/drivers/media/IR/keymaps/rc-avermedia-m135a-rm-jx.c
+++ /dev/null
@@ -1,90 +0,0 @@
-/* avermedia-m135a-rm-jx.h - Keytable for avermedia_m135a_rm_jx Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/*
- * Avermedia M135A with IR model RM-JX
- * The same codes exist on both Positivo (BR) and original IR
- * Mauro Carvalho Chehab <mchehab@infradead.org>
- */
-
-static struct ir_scancode avermedia_m135a_rm_jx[] = {
- { 0x0200, KEY_POWER2 },
- { 0x022e, KEY_DOT }, /* '.' */
- { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */
-
- { 0x0205, KEY_1 },
- { 0x0206, KEY_2 },
- { 0x0207, KEY_3 },
- { 0x0209, KEY_4 },
- { 0x020a, KEY_5 },
- { 0x020b, KEY_6 },
- { 0x020d, KEY_7 },
- { 0x020e, KEY_8 },
- { 0x020f, KEY_9 },
- { 0x0211, KEY_0 },
-
- { 0x0213, KEY_RIGHT }, /* -> or L */
- { 0x0212, KEY_LEFT }, /* <- or R */
-
- { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */
- { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */
-
- { 0x0303, KEY_CHANNELUP },
- { 0x0302, KEY_CHANNELDOWN },
- { 0x021f, KEY_VOLUMEUP },
- { 0x021e, KEY_VOLUMEDOWN },
- { 0x020c, KEY_ENTER }, /* Full Screen */
-
- { 0x0214, KEY_MUTE },
- { 0x0208, KEY_AUDIO },
-
- { 0x0203, KEY_TEXT }, /* Teletext */
- { 0x0204, KEY_EPG },
- { 0x022b, KEY_TV2 }, /* TV2 or PIP */
-
- { 0x021d, KEY_RED },
- { 0x021c, KEY_YELLOW },
- { 0x0301, KEY_GREEN },
- { 0x0300, KEY_BLUE },
-
- { 0x021a, KEY_PLAYPAUSE },
- { 0x0219, KEY_RECORD },
- { 0x0218, KEY_PLAY },
- { 0x021b, KEY_STOP },
-};
-
-static struct rc_keymap avermedia_m135a_rm_jx_map = {
- .map = {
- .scan = avermedia_m135a_rm_jx,
- .size = ARRAY_SIZE(avermedia_m135a_rm_jx),
- .ir_type = IR_TYPE_NEC,
- .name = RC_MAP_AVERMEDIA_M135A_RM_JX,
- }
-};
-
-static int __init init_rc_map_avermedia_m135a_rm_jx(void)
-{
- return ir_register_map(&avermedia_m135a_rm_jx_map);
-}
-
-static void __exit exit_rc_map_avermedia_m135a_rm_jx(void)
-{
- ir_unregister_map(&avermedia_m135a_rm_jx_map);
-}
-
-module_init(init_rc_map_avermedia_m135a_rm_jx)
-module_exit(exit_rc_map_avermedia_m135a_rm_jx)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-empty.c b/drivers/media/IR/keymaps/rc-empty.c
deleted file mode 100644
index 3b338d84b476..000000000000
--- a/drivers/media/IR/keymaps/rc-empty.c
+++ /dev/null
@@ -1,44 +0,0 @@
-/* empty.h - Keytable for empty Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/* empty keytable, can be used as placeholder for not-yet created keytables */
-
-static struct ir_scancode empty[] = {
- { 0x2a, KEY_COFFEE },
-};
-
-static struct rc_keymap empty_map = {
- .map = {
- .scan = empty,
- .size = ARRAY_SIZE(empty),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_EMPTY,
- }
-};
-
-static int __init init_rc_map_empty(void)
-{
- return ir_register_map(&empty_map);
-}
-
-static void __exit exit_rc_map_empty(void)
-{
- ir_unregister_map(&empty_map);
-}
-
-module_init(init_rc_map_empty)
-module_exit(exit_rc_map_empty)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-tbs-nec.c b/drivers/media/IR/keymaps/rc-tbs-nec.c
deleted file mode 100644
index 3309631e6f80..000000000000
--- a/drivers/media/IR/keymaps/rc-tbs-nec.c
+++ /dev/null
@@ -1,73 +0,0 @@
-/* tbs-nec.h - Keytable for tbs_nec Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-static struct ir_scancode tbs_nec[] = {
- { 0x04, KEY_POWER2}, /*power*/
- { 0x14, KEY_MUTE}, /*mute*/
- { 0x07, KEY_1},
- { 0x06, KEY_2},
- { 0x05, KEY_3},
- { 0x0b, KEY_4},
- { 0x0a, KEY_5},
- { 0x09, KEY_6},
- { 0x0f, KEY_7},
- { 0x0e, KEY_8},
- { 0x0d, KEY_9},
- { 0x12, KEY_0},
- { 0x16, KEY_CHANNELUP}, /*ch+*/
- { 0x11, KEY_CHANNELDOWN},/*ch-*/
- { 0x13, KEY_VOLUMEUP}, /*vol+*/
- { 0x0c, KEY_VOLUMEDOWN},/*vol-*/
- { 0x03, KEY_RECORD}, /*rec*/
- { 0x18, KEY_PAUSE}, /*pause*/
- { 0x19, KEY_OK}, /*ok*/
- { 0x1a, KEY_CAMERA}, /* snapshot */
- { 0x01, KEY_UP},
- { 0x10, KEY_LEFT},
- { 0x02, KEY_RIGHT},
- { 0x08, KEY_DOWN},
- { 0x15, KEY_FAVORITES},
- { 0x17, KEY_SUBTITLE},
- { 0x1d, KEY_ZOOM},
- { 0x1f, KEY_EXIT},
- { 0x1e, KEY_MENU},
- { 0x1c, KEY_EPG},
- { 0x00, KEY_PREVIOUS},
- { 0x1b, KEY_MODE},
-};
-
-static struct rc_keymap tbs_nec_map = {
- .map = {
- .scan = tbs_nec,
- .size = ARRAY_SIZE(tbs_nec),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_TBS_NEC,
- }
-};
-
-static int __init init_rc_map_tbs_nec(void)
-{
- return ir_register_map(&tbs_nec_map);
-}
-
-static void __exit exit_rc_map_tbs_nec(void)
-{
- ir_unregister_map(&tbs_nec_map);
-}
-
-module_init(init_rc_map_tbs_nec)
-module_exit(exit_rc_map_tbs_nec)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-tt-1500.c b/drivers/media/IR/keymaps/rc-tt-1500.c
deleted file mode 100644
index bc88de011d5d..000000000000
--- a/drivers/media/IR/keymaps/rc-tt-1500.c
+++ /dev/null
@@ -1,82 +0,0 @@
-/* tt-1500.h - Keytable for tt_1500 Remote Controller
- *
- * keymap imported from ir-keymaps.c
- *
- * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- */
-
-#include <media/rc-map.h>
-
-/* for the Technotrend 1500 bundled remotes (grey and black): */
-
-static struct ir_scancode tt_1500[] = {
- { 0x01, KEY_POWER },
- { 0x02, KEY_SHUFFLE }, /* ? double-arrow key */
- { 0x03, KEY_1 },
- { 0x04, KEY_2 },
- { 0x05, KEY_3 },
- { 0x06, KEY_4 },
- { 0x07, KEY_5 },
- { 0x08, KEY_6 },
- { 0x09, KEY_7 },
- { 0x0a, KEY_8 },
- { 0x0b, KEY_9 },
- { 0x0c, KEY_0 },
- { 0x0d, KEY_UP },
- { 0x0e, KEY_LEFT },
- { 0x0f, KEY_OK },
- { 0x10, KEY_RIGHT },
- { 0x11, KEY_DOWN },
- { 0x12, KEY_INFO },
- { 0x13, KEY_EXIT },
- { 0x14, KEY_RED },
- { 0x15, KEY_GREEN },
- { 0x16, KEY_YELLOW },
- { 0x17, KEY_BLUE },
- { 0x18, KEY_MUTE },
- { 0x19, KEY_TEXT },
- { 0x1a, KEY_MODE }, /* ? TV/Radio */
- { 0x21, KEY_OPTION },
- { 0x22, KEY_EPG },
- { 0x23, KEY_CHANNELUP },
- { 0x24, KEY_CHANNELDOWN },
- { 0x25, KEY_VOLUMEUP },
- { 0x26, KEY_VOLUMEDOWN },
- { 0x27, KEY_SETUP },
- { 0x3a, KEY_RECORD }, /* these keys are only in the black remote */
- { 0x3b, KEY_PLAY },
- { 0x3c, KEY_STOP },
- { 0x3d, KEY_REWIND },
- { 0x3e, KEY_PAUSE },
- { 0x3f, KEY_FORWARD },
-};
-
-static struct rc_keymap tt_1500_map = {
- .map = {
- .scan = tt_1500,
- .size = ARRAY_SIZE(tt_1500),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
- .name = RC_MAP_TT_1500,
- }
-};
-
-static int __init init_rc_map_tt_1500(void)
-{
- return ir_register_map(&tt_1500_map);
-}
-
-static void __exit exit_rc_map_tt_1500(void)
-{
- ir_unregister_map(&tt_1500_map);
-}
-
-module_init(init_rc_map_tt_1500)
-module_exit(exit_rc_map_tt_1500)
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/rc-map.c b/drivers/media/IR/rc-map.c
deleted file mode 100644
index 46a8f1524b5b..000000000000
--- a/drivers/media/IR/rc-map.c
+++ /dev/null
@@ -1,84 +0,0 @@
-/* ir-raw-event.c - handle IR Pulse/Space event
- *
- * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
-
-#include <media/ir-core.h>
-#include <linux/spinlock.h>
-#include <linux/delay.h>
-
-/* Used to handle IR raw handler extensions */
-static LIST_HEAD(rc_map_list);
-static DEFINE_SPINLOCK(rc_map_lock);
-
-static struct rc_keymap *seek_rc_map(const char *name)
-{
- struct rc_keymap *map = NULL;
-
- spin_lock(&rc_map_lock);
- list_for_each_entry(map, &rc_map_list, list) {
- if (!strcmp(name, map->map.name)) {
- spin_unlock(&rc_map_lock);
- return map;
- }
- }
- spin_unlock(&rc_map_lock);
-
- return NULL;
-}
-
-struct ir_scancode_table *get_rc_map(const char *name)
-{
-
- struct rc_keymap *map;
-
- map = seek_rc_map(name);
-#ifdef MODULE
- if (!map) {
- int rc = request_module(name);
- if (rc < 0) {
- printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
- return NULL;
- }
- msleep(20); /* Give some time for IR to register */
-
- map = seek_rc_map(name);
- }
-#endif
- if (!map) {
- printk(KERN_ERR "IR keymap %s not found\n", name);
- return NULL;
- }
-
- printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
-
- return &map->map;
-}
-EXPORT_SYMBOL_GPL(get_rc_map);
-
-int ir_register_map(struct rc_keymap *map)
-{
- spin_lock(&rc_map_lock);
- list_add_tail(&map->list, &rc_map_list);
- spin_unlock(&rc_map_lock);
- return 0;
-}
-EXPORT_SYMBOL_GPL(ir_register_map);
-
-void ir_unregister_map(struct rc_keymap *map)
-{
- spin_lock(&rc_map_lock);
- list_del(&map->list);
- spin_unlock(&rc_map_lock);
-}
-EXPORT_SYMBOL_GPL(ir_unregister_map);
-
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index a28541b2b1a2..81b3ba83cc65 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -40,35 +40,6 @@ config VIDEO_V4L2_COMMON
depends on (I2C || I2C=n) && VIDEO_DEV
default (I2C || I2C=n) && VIDEO_DEV
-config VIDEO_ALLOW_V4L1
- bool "Enable Video For Linux API 1 (DEPRECATED)"
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON
- default VIDEO_DEV && VIDEO_V4L2_COMMON
- ---help---
- Enables drivers based on the legacy V4L1 API.
-
- This api were developed to be used at Kernel 2.2 and 2.4, but
- lacks support for several video standards. There are several
- drivers at kernel that still depends on it.
-
- If you are unsure as to whether this is required, answer Y.
-
-config VIDEO_V4L1_COMPAT
- bool "Enable Video For Linux API 1 compatible Layer" if !VIDEO_ALLOW_V4L1
- depends on VIDEO_DEV
- default y
- ---help---
- Enables a compatibility API used by most V4L2 devices to allow
- its usage with legacy applications that supports only V4L1 api.
-
- Documentation for the original API is included in the file
- <Documentation/video4linux/API.html>.
-
- User tools for this are available from
- <ftp://ftp.uk.linux.org/pub/linux/video4linux/>.
-
- If you are unsure as to whether this is required, answer Y.
-
#
# DVB Core
#
@@ -99,7 +70,7 @@ config VIDEO_MEDIA
comment "Multimedia drivers"
source "drivers/media/common/Kconfig"
-source "drivers/media/IR/Kconfig"
+source "drivers/media/rc/Kconfig"
#
# Tuner drivers for DVB and V4L
@@ -121,26 +92,4 @@ source "drivers/media/radio/Kconfig"
source "drivers/media/dvb/Kconfig"
-config DAB
- boolean "DAB adapters"
- ---help---
- Allow selecting support for Digital Audio Broadcasting (DAB)
- Receiver adapters.
-
-if DAB
-config USB_DABUSB
- tristate "DABUSB driver"
- depends on USB
- ---help---
- A Digital Audio Broadcasting (DAB) Receiver for USB and Linux
- brought to you by the DAB-Team
- <http://wwwbode.cs.tum.edu/Par/arch/dab/>. This driver can be taken
- as an example for URB-based bulk, control, and isochronous
- transactions. URB's are explained in
- <Documentation/usb/URB.txt>.
-
- To compile this driver as a module, choose M here: the
- module will be called dabusb.
-endif # DAB
-
endif # MEDIA_SUPPORT
diff --git a/drivers/media/Makefile b/drivers/media/Makefile
index 499b0810d019..b603ea645ede 100644
--- a/drivers/media/Makefile
+++ b/drivers/media/Makefile
@@ -2,7 +2,7 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y += common/ IR/ video/
+obj-y += common/ rc/ video/
obj-$(CONFIG_VIDEO_DEV) += radio/
obj-$(CONFIG_DVB_CORE) += dvb/
diff --git a/drivers/media/common/saa7146_core.c b/drivers/media/common/saa7146_core.c
index 982f000a57ff..9f47e383c57a 100644
--- a/drivers/media/common/saa7146_core.c
+++ b/drivers/media/common/saa7146_core.c
@@ -452,7 +452,7 @@ static int saa7146_init_one(struct pci_dev *pci, const struct pci_device_id *ent
INFO(("found saa7146 @ mem %p (revision %d, irq %d) (0x%04x,0x%04x).\n", dev->mem, dev->revision, pci->irq, pci->subsystem_vendor, pci->subsystem_device));
dev->ext = ext;
- mutex_init(&dev->lock);
+ mutex_init(&dev->v4l2_lock);
spin_lock_init(&dev->int_slock);
spin_lock_init(&dev->slock);
diff --git a/drivers/media/common/saa7146_fops.c b/drivers/media/common/saa7146_fops.c
index 7364b9642d00..1bd3dd762c6b 100644
--- a/drivers/media/common/saa7146_fops.c
+++ b/drivers/media/common/saa7146_fops.c
@@ -15,18 +15,15 @@ int saa7146_res_get(struct saa7146_fh *fh, unsigned int bit)
}
/* is it free? */
- mutex_lock(&dev->lock);
if (vv->resources & bit) {
DEB_D(("locked! vv->resources:0x%02x, we want:0x%02x\n",vv->resources,bit));
/* no, someone else uses it */
- mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
vv->resources |= bit;
DEB_D(("res: get 0x%02x, cur:0x%02x\n",bit,vv->resources));
- mutex_unlock(&dev->lock);
return 1;
}
@@ -37,11 +34,9 @@ void saa7146_res_free(struct saa7146_fh *fh, unsigned int bits)
BUG_ON((fh->resources & bits) != bits);
- mutex_lock(&dev->lock);
fh->resources &= ~bits;
vv->resources &= ~bits;
DEB_D(("res: put 0x%02x, cur:0x%02x\n",bits,vv->resources));
- mutex_unlock(&dev->lock);
}
@@ -56,8 +51,8 @@ void saa7146_dma_free(struct saa7146_dev *dev,struct videobuf_queue *q,
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
@@ -396,7 +391,7 @@ static const struct v4l2_file_operations video_fops =
.write = fops_write,
.poll = fops_poll,
.mmap = fops_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static void vv_callback(struct saa7146_dev *dev, unsigned long status)
@@ -505,6 +500,7 @@ int saa7146_register_device(struct video_device **vid, struct saa7146_dev* dev,
vfd->fops = &video_fops;
vfd->ioctl_ops = &dev->ext_vv_data->ops;
vfd->release = video_device_release;
+ vfd->lock = &dev->v4l2_lock;
vfd->tvnorms = 0;
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
vfd->tvnorms |= dev->ext_vv_data->stds[i].id;
diff --git a/drivers/media/common/saa7146_hlp.c b/drivers/media/common/saa7146_hlp.c
index 05bde9ccb770..1d1d8d200755 100644
--- a/drivers/media/common/saa7146_hlp.c
+++ b/drivers/media/common/saa7146_hlp.c
@@ -558,7 +558,7 @@ static void saa7146_set_window(struct saa7146_dev *dev, int width, int height, e
static void saa7146_set_position(struct saa7146_dev *dev, int w_x, int w_y, int w_height, enum v4l2_field field, u32 pixelformat)
{
struct saa7146_vv *vv = dev->vv_data;
- struct saa7146_format *sfmt = format_by_fourcc(dev, pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev, pixelformat);
int b_depth = vv->ov_fmt->depth;
int b_bpl = vv->ov_fb.fmt.bytesperline;
@@ -702,7 +702,7 @@ static int calculate_video_dma_grab_packed(struct saa7146_dev* dev, struct saa71
struct saa7146_vv *vv = dev->vv_data;
struct saa7146_video_dma vdma1;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
int width = buf->fmt->width;
int height = buf->fmt->height;
@@ -827,7 +827,7 @@ static int calculate_video_dma_grab_planar(struct saa7146_dev* dev, struct saa71
struct saa7146_video_dma vdma2;
struct saa7146_video_dma vdma3;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
int width = buf->fmt->width;
int height = buf->fmt->height;
@@ -994,7 +994,7 @@ static void program_capture_engine(struct saa7146_dev *dev, int planar)
void saa7146_set_capture(struct saa7146_dev *dev, struct saa7146_buf *buf, struct saa7146_buf *next)
{
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
struct saa7146_vv *vv = dev->vv_data;
u32 vdma1_prot_addr;
diff --git a/drivers/media/common/saa7146_i2c.c b/drivers/media/common/saa7146_i2c.c
index 48cb154c7a46..74ee172b5bc9 100644
--- a/drivers/media/common/saa7146_i2c.c
+++ b/drivers/media/common/saa7146_i2c.c
@@ -391,7 +391,6 @@ static int saa7146_i2c_xfer(struct i2c_adapter* adapter, struct i2c_msg *msg, in
/*****************************************************************************/
/* i2c-adapter helper functions */
-#include <linux/i2c-id.h>
/* exported algorithm data */
static struct i2c_algorithm saa7146_algo = {
@@ -414,7 +413,6 @@ int saa7146_i2c_adapter_prepare(struct saa7146_dev *dev, struct i2c_adapter *i2c
i2c_adapter->dev.parent = &dev->pci->dev;
i2c_adapter->algo = &saa7146_algo;
i2c_adapter->algo_data = NULL;
- i2c_adapter->id = I2C_HW_SAA7146;
i2c_adapter->timeout = SAA7146_I2C_TIMEOUT;
i2c_adapter->retries = SAA7146_I2C_RETRIES;
}
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index 74e2b56ecb5b..afe85801d6ca 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -375,7 +375,7 @@ static void vbi_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
static int vbi_open(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
u32 arbtr_ctrl = saa7146_read(dev, PCI_BT_V1);
int ret = 0;
@@ -412,7 +412,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
sizeof(struct saa7146_buf),
- file);
+ file, &dev->v4l2_lock);
init_timer(&fh->vbi_read_timeout);
fh->vbi_read_timeout.function = vbi_read_timeout;
@@ -437,7 +437,7 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
static void vbi_close(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
struct saa7146_vv *vv = dev->vv_data;
DEB_VBI(("dev:%p, fh:%p\n",dev,fh));
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index b8b2c551a1e2..9aafa4e969a8 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -84,7 +84,7 @@ static struct saa7146_format formats[] = {
static int NUM_FORMATS = sizeof(formats)/sizeof(struct saa7146_format);
-struct saa7146_format* format_by_fourcc(struct saa7146_dev *dev, int fourcc)
+struct saa7146_format* saa7146_format_by_fourcc(struct saa7146_dev *dev, int fourcc)
{
int i, j = NUM_FORMATS;
@@ -266,7 +266,7 @@ static int saa7146_pgtable_build(struct saa7146_dev *dev, struct saa7146_buf *bu
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
struct scatterlist *list = dma->sglist;
int length = dma->sglen;
- struct saa7146_format *sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ struct saa7146_format *sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
DEB_EE(("dev:%p, buf:%p, sg_len:%d\n",dev,buf,length));
@@ -408,7 +408,7 @@ static int video_begin(struct saa7146_fh *fh)
}
}
- fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
@@ -460,7 +460,7 @@ static int video_end(struct saa7146_fh *fh, struct file *file)
return -EBUSY;
}
- fmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
/* we need to have a valid format set here */
BUG_ON(NULL == fmt);
@@ -536,7 +536,7 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
return -EPERM;
/* check args */
- fmt = format_by_fourcc(dev, fb->fmt.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev, fb->fmt.pixelformat);
if (NULL == fmt)
return -EINVAL;
@@ -553,8 +553,6 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
}
}
- mutex_lock(&dev->lock);
-
/* ok, accept it */
vv->ov_fb = *fb;
vv->ov_fmt = fmt;
@@ -563,8 +561,6 @@ static int vidioc_s_fbuf(struct file *file, void *fh, struct v4l2_framebuffer *f
vv->ov_fb.fmt.bytesperline = vv->ov_fb.fmt.width * fmt->depth / 8;
DEB_D(("setting bytesperline to %d\n", vv->ov_fb.fmt.bytesperline));
}
-
- mutex_unlock(&dev->lock);
return 0;
}
@@ -649,8 +645,6 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
return -EINVAL;
}
- mutex_lock(&dev->lock);
-
switch (ctrl->type) {
case V4L2_CTRL_TYPE_BOOLEAN:
case V4L2_CTRL_TYPE_MENU:
@@ -693,7 +687,6 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
/* fixme: we can support changing VFLIP and HFLIP here... */
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_HFLIP while active capture.\n"));
- mutex_unlock(&dev->lock);
return -EBUSY;
}
vv->hflip = c->value;
@@ -701,16 +694,13 @@ static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
case V4L2_CID_VFLIP:
if (IS_CAPTURE_ACTIVE(fh) != 0) {
DEB_D(("V4L2_CID_VFLIP while active capture.\n"));
- mutex_unlock(&dev->lock);
return -EBUSY;
}
vv->vflip = c->value;
break;
default:
- mutex_unlock(&dev->lock);
return -EINVAL;
}
- mutex_unlock(&dev->lock);
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
@@ -760,7 +750,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_forma
DEB_EE(("V4L2_BUF_TYPE_VIDEO_CAPTURE: dev:%p, fh:%p\n", dev, fh));
- fmt = format_by_fourcc(dev, f->fmt.pix.pixelformat);
+ fmt = saa7146_format_by_fourcc(dev, f->fmt.pix.pixelformat);
if (NULL == fmt)
return -EINVAL;
@@ -902,22 +892,18 @@ static int vidioc_s_fmt_vid_overlay(struct file *file, void *__fh, struct v4l2_f
err = vidioc_try_fmt_vid_overlay(file, fh, f);
if (0 != err)
return err;
- mutex_lock(&dev->lock);
fh->ov.win = f->fmt.win;
fh->ov.nclips = f->fmt.win.clipcount;
if (fh->ov.nclips > 16)
fh->ov.nclips = 16;
if (copy_from_user(fh->ov.clips, f->fmt.win.clips,
sizeof(struct v4l2_clip) * fh->ov.nclips)) {
- mutex_unlock(&dev->lock);
return -EFAULT;
}
/* fh->ov.fh is used to indicate that we have valid overlay informations, too */
fh->ov.fh = fh;
- mutex_unlock(&dev->lock);
-
/* check if our current overlay is active */
if (IS_OVERLAY_ACTIVE(fh) != 0) {
saa7146_stop_preview(fh);
@@ -976,8 +962,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
}
}
- mutex_lock(&dev->lock);
-
for (i = 0; i < dev->ext_vv_data->num_stds; i++)
if (*id & dev->ext_vv_data->stds[i].id)
break;
@@ -988,8 +972,6 @@ static int vidioc_s_std(struct file *file, void *fh, v4l2_std_id *id)
found = 1;
}
- mutex_unlock(&dev->lock);
-
if (vv->ov_suspend != NULL) {
saa7146_start_preview(vv->ov_suspend);
vv->ov_suspend = NULL;
@@ -1129,35 +1111,6 @@ static int vidioc_g_chip_ident(struct file *file, void *__fh,
core, g_chip_ident, chip);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *mbuf)
-{
- struct saa7146_fh *fh = __fh;
- struct videobuf_queue *q = &fh->video_q;
- int err, i;
-
- /* fixme: number of capture buffers and sizes for v4l apps */
- int gbuffers = 2;
- int gbufsize = 768 * 576 * 4;
-
- DEB_D(("VIDIOCGMBUF \n"));
-
- q = &fh->video_q;
- err = videobuf_mmap_setup(q, gbuffers, gbufsize,
- V4L2_MEMORY_MMAP);
- if (err < 0)
- return err;
-
- gbuffers = err;
- memset(mbuf, 0, sizeof(*mbuf));
- mbuf->frames = gbuffers;
- mbuf->size = gbuffers * gbufsize;
- for (i = 0; i < gbuffers; i++)
- mbuf->offsets[i] = i * gbufsize;
- return 0;
-}
-#endif
-
const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_querycap = vidioc_querycap,
.vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
@@ -1186,9 +1139,6 @@ const struct v4l2_ioctl_ops saa7146_video_ioctl_ops = {
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
.vidioc_g_parm = vidioc_g_parm,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
/*********************************************************************************/
@@ -1264,7 +1214,7 @@ static int buffer_prepare(struct videobuf_queue *q,
buf->fmt = &fh->video_fmt;
buf->vb.field = fh->video_fmt.field;
- sfmt = format_by_fourcc(dev,buf->fmt->pixelformat);
+ sfmt = saa7146_format_by_fourcc(dev,buf->fmt->pixelformat);
release_all_pagetables(dev, buf);
if( 0 != IS_PLANAR(sfmt->trans)) {
@@ -1370,7 +1320,7 @@ static void video_init(struct saa7146_dev *dev, struct saa7146_vv *vv)
static int video_open(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
struct saa7146_format *sfmt;
fh->video_fmt.width = 384;
@@ -1378,7 +1328,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
fh->video_fmt.pixelformat = V4L2_PIX_FMT_BGR24;
fh->video_fmt.bytesperline = 0;
fh->video_fmt.field = V4L2_FIELD_ANY;
- sfmt = format_by_fourcc(dev,fh->video_fmt.pixelformat);
+ sfmt = saa7146_format_by_fourcc(dev,fh->video_fmt.pixelformat);
fh->video_fmt.sizeimage = (fh->video_fmt.width * fh->video_fmt.height * sfmt->depth)/8;
videobuf_queue_sg_init(&fh->video_q, &video_qops,
@@ -1386,7 +1336,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7146_buf),
- file);
+ file, &dev->v4l2_lock);
return 0;
}
@@ -1394,7 +1344,7 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
static void video_close(struct saa7146_dev *dev, struct file *file)
{
- struct saa7146_fh *fh = (struct saa7146_fh *)file->private_data;
+ struct saa7146_fh *fh = file->private_data;
struct saa7146_vv *vv = dev->vv_data;
struct videobuf_queue *q = &fh->video_q;
int err;
diff --git a/drivers/media/common/tuners/Kconfig b/drivers/media/common/tuners/Kconfig
index 409a4261e5b5..6fc79f15dcbc 100644
--- a/drivers/media/common/tuners/Kconfig
+++ b/drivers/media/common/tuners/Kconfig
@@ -31,10 +31,10 @@ config MEDIA_TUNER
select MEDIA_TUNER_TDA9887 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
-menuconfig MEDIA_TUNER_CUSTOMISE
+config MEDIA_TUNER_CUSTOMISE
bool "Customize analog and hybrid tuner modules to build"
depends on MEDIA_TUNER
- default n
+ default y if EXPERT
help
This allows the user to deselect tuner drivers unnecessary
for their hardware from the build. Use this option with care
@@ -44,7 +44,8 @@ menuconfig MEDIA_TUNER_CUSTOMISE
If unsure say N.
-if MEDIA_TUNER_CUSTOMISE
+menu "Customize TV tuners"
+ visible if MEDIA_TUNER_CUSTOMISE
config MEDIA_TUNER_SIMPLE
tristate "Simple tuner support"
@@ -179,4 +180,10 @@ config MEDIA_TUNER_MAX2165
help
A driver for the silicon tuner MAX2165 from Maxim.
-endif # MEDIA_TUNER_CUSTOMISE
+config MEDIA_TUNER_TDA18218
+ tristate "NXP TDA18218 silicon tuner"
+ depends on VIDEO_MEDIA && I2C
+ default m if MEDIA_TUNER_CUSTOMISE
+ help
+ NXP TDA18218 silicon tuner driver.
+endmenu
diff --git a/drivers/media/common/tuners/Makefile b/drivers/media/common/tuners/Makefile
index a5438523f30d..96da03d349ca 100644
--- a/drivers/media/common/tuners/Makefile
+++ b/drivers/media/common/tuners/Makefile
@@ -24,6 +24,7 @@ obj-$(CONFIG_MEDIA_TUNER_MXL5005S) += mxl5005s.o
obj-$(CONFIG_MEDIA_TUNER_MXL5007T) += mxl5007t.o
obj-$(CONFIG_MEDIA_TUNER_MC44S803) += mc44s803.o
obj-$(CONFIG_MEDIA_TUNER_MAX2165) += max2165.o
+obj-$(CONFIG_MEDIA_TUNER_TDA18218) += tda18218.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/common/tuners/max2165.c b/drivers/media/common/tuners/max2165.c
index 937e4b00d7ee..9883617b7862 100644
--- a/drivers/media/common/tuners/max2165.c
+++ b/drivers/media/common/tuners/max2165.c
@@ -52,13 +52,12 @@ static int max2165_write_reg(struct max2165_priv *priv, u8 reg, u8 data)
msg.addr = priv->config->i2c_address;
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
- __func__, reg, data);
+ dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
ret = i2c_transfer(priv->i2c, &msg, 1);
if (ret != 1)
- dprintk(KERN_DEBUG "%s: error reg=0x%x, data=0x%x, ret=%i\n",
+ dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
__func__, reg, data, ret);
return (ret != 1) ? -EIO : 0;
@@ -78,14 +77,13 @@ static int max2165_read_reg(struct max2165_priv *priv, u8 reg, u8 *p_data)
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret != 2) {
- dprintk(KERN_DEBUG "%s: error reg=0x%x, ret=%i\n",
- __func__, reg, ret);
+ dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
return -EIO;
}
*p_data = b1[0];
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
+ dprintk("%s: reg=0x%02X, data=0x%02X\n",
__func__, reg, b1[0]);
return 0;
}
diff --git a/drivers/media/common/tuners/tda18218.c b/drivers/media/common/tuners/tda18218.c
new file mode 100644
index 000000000000..aacfe2387e28
--- /dev/null
+++ b/drivers/media/common/tuners/tda18218.c
@@ -0,0 +1,334 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "tda18218.h"
+#include "tda18218_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+/* write multiple registers */
+static int tda18218_wr_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+ int ret = 0;
+ u8 buf[1+len], quotient, remainder, i, msg_len, msg_len_max;
+ struct i2c_msg msg[1] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .buf = buf,
+ }
+ };
+
+ msg_len_max = priv->cfg->i2c_wr_max - 1;
+ quotient = len / msg_len_max;
+ remainder = len % msg_len_max;
+ msg_len = msg_len_max;
+ for (i = 0; (i <= quotient && remainder); i++) {
+ if (i == quotient) /* set len of the last msg */
+ msg_len = remainder;
+
+ msg[0].len = msg_len + 1;
+ buf[0] = reg + i * msg_len_max;
+ memcpy(&buf[1], &val[i * msg_len_max], msg_len);
+
+ ret = i2c_transfer(priv->i2c, msg, 1);
+ if (ret != 1)
+ break;
+ }
+
+ if (ret == 1) {
+ ret = 0;
+ } else {
+ warn("i2c wr failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* read multiple registers */
+static int tda18218_rd_regs(struct tda18218_priv *priv, u8 reg, u8 *val, u8 len)
+{
+ int ret;
+ u8 buf[reg+len]; /* we must start read always from reg 0x00 */
+ struct i2c_msg msg[2] = {
+ {
+ .addr = priv->cfg->i2c_address,
+ .flags = 0,
+ .len = 1,
+ .buf = "\x00",
+ }, {
+ .addr = priv->cfg->i2c_address,
+ .flags = I2C_M_RD,
+ .len = sizeof(buf),
+ .buf = buf,
+ }
+ };
+
+ ret = i2c_transfer(priv->i2c, msg, 2);
+ if (ret == 2) {
+ memcpy(val, &buf[reg], len);
+ ret = 0;
+ } else {
+ warn("i2c rd failed ret:%d reg:%02x len:%d", ret, reg, len);
+ ret = -EREMOTEIO;
+ }
+
+ return ret;
+}
+
+/* write single register */
+static int tda18218_wr_reg(struct tda18218_priv *priv, u8 reg, u8 val)
+{
+ return tda18218_wr_regs(priv, reg, &val, 1);
+}
+
+/* read single register */
+
+static int tda18218_rd_reg(struct tda18218_priv *priv, u8 reg, u8 *val)
+{
+ return tda18218_rd_regs(priv, reg, val, 1);
+}
+
+static int tda18218_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ int ret;
+ u8 buf[3], i, BP_Filter, LP_Fc;
+ u32 LO_Frac;
+ /* TODO: find out correct AGC algorithm */
+ u8 agc[][2] = {
+ { R20_AGC11, 0x60 },
+ { R23_AGC21, 0x02 },
+ { R20_AGC11, 0xa0 },
+ { R23_AGC21, 0x09 },
+ { R20_AGC11, 0xe0 },
+ { R23_AGC21, 0x0c },
+ { R20_AGC11, 0x40 },
+ { R23_AGC21, 0x01 },
+ { R20_AGC11, 0x80 },
+ { R23_AGC21, 0x08 },
+ { R20_AGC11, 0xc0 },
+ { R23_AGC21, 0x0b },
+ { R24_AGC22, 0x1c },
+ { R24_AGC22, 0x0c },
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* low-pass filter cut-off frequency */
+ switch (params->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ LP_Fc = 0;
+ LO_Frac = params->frequency + 4000000;
+ break;
+ case BANDWIDTH_7_MHZ:
+ LP_Fc = 1;
+ LO_Frac = params->frequency + 3500000;
+ break;
+ case BANDWIDTH_8_MHZ:
+ default:
+ LP_Fc = 2;
+ LO_Frac = params->frequency + 4000000;
+ break;
+ }
+
+ /* band-pass filter */
+ if (LO_Frac < 188000000)
+ BP_Filter = 3;
+ else if (LO_Frac < 253000000)
+ BP_Filter = 4;
+ else if (LO_Frac < 343000000)
+ BP_Filter = 5;
+ else
+ BP_Filter = 6;
+
+ buf[0] = (priv->regs[R1A_IF1] & ~7) | BP_Filter; /* BP_Filter */
+ buf[1] = (priv->regs[R1B_IF2] & ~3) | LP_Fc; /* LP_Fc */
+ buf[2] = priv->regs[R1C_AGC2B];
+ ret = tda18218_wr_regs(priv, R1A_IF1, buf, 3);
+ if (ret)
+ goto error;
+
+ buf[0] = (LO_Frac / 1000) >> 12; /* LO_Frac_0 */
+ buf[1] = (LO_Frac / 1000) >> 4; /* LO_Frac_1 */
+ buf[2] = (LO_Frac / 1000) << 4 |
+ (priv->regs[R0C_MD5] & 0x0f); /* LO_Frac_2 */
+ ret = tda18218_wr_regs(priv, R0A_MD3, buf, 3);
+ if (ret)
+ goto error;
+
+ buf[0] = priv->regs[R0F_MD8] | (1 << 6); /* Freq_prog_Start */
+ ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+ if (ret)
+ goto error;
+
+ buf[0] = priv->regs[R0F_MD8] & ~(1 << 6); /* Freq_prog_Start */
+ ret = tda18218_wr_regs(priv, R0F_MD8, buf, 1);
+ if (ret)
+ goto error;
+
+ /* trigger AGC */
+ for (i = 0; i < ARRAY_SIZE(agc); i++) {
+ ret = tda18218_wr_reg(priv, agc[i][0], agc[i][1]);
+ if (ret)
+ goto error;
+ }
+
+error:
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ return ret;
+}
+
+static int tda18218_sleep(struct dvb_frontend *fe)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* standby */
+ ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ return ret;
+}
+
+static int tda18218_init(struct dvb_frontend *fe)
+{
+ struct tda18218_priv *priv = fe->tuner_priv;
+ int ret;
+
+ /* TODO: calibrations */
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ ret = tda18218_wr_regs(priv, R00_ID, priv->regs, TDA18218_NUM_REGS);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ return ret;
+}
+
+static int tda18218_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops tda18218_tuner_ops = {
+ .info = {
+ .name = "NXP TDA18218",
+
+ .frequency_min = 174000000,
+ .frequency_max = 864000000,
+ .frequency_step = 1000,
+ },
+
+ .release = tda18218_release,
+ .init = tda18218_init,
+ .sleep = tda18218_sleep,
+
+ .set_params = tda18218_set_params,
+};
+
+struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+ struct tda18218_priv *priv = NULL;
+ u8 val;
+ int ret;
+ /* chip default registers values */
+ static u8 def_regs[] = {
+ 0xc0, 0x88, 0x00, 0x8e, 0x03, 0x00, 0x00, 0xd0, 0x00, 0x40,
+ 0x00, 0x00, 0x07, 0xff, 0x84, 0x09, 0x00, 0x13, 0x00, 0x00,
+ 0x01, 0x84, 0x09, 0xf0, 0x19, 0x0a, 0x8e, 0x69, 0x98, 0x01,
+ 0x00, 0x58, 0x10, 0x40, 0x8c, 0x00, 0x0c, 0x48, 0x85, 0xc9,
+ 0xa7, 0x00, 0x00, 0x00, 0x30, 0x81, 0x80, 0x00, 0x39, 0x00,
+ 0x8a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf6, 0xf6
+ };
+
+ priv = kzalloc(sizeof(struct tda18218_priv), GFP_KERNEL);
+ if (priv == NULL)
+ return NULL;
+
+ priv->cfg = cfg;
+ priv->i2c = i2c;
+ fe->tuner_priv = priv;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1); /* open I2C-gate */
+
+ /* check if the tuner is there */
+ ret = tda18218_rd_reg(priv, R00_ID, &val);
+ dbg("%s: ret:%d chip ID:%02x", __func__, ret, val);
+ if (ret || val != def_regs[R00_ID]) {
+ kfree(priv);
+ return NULL;
+ }
+
+ info("NXP TDA18218HN successfully identified.");
+
+ memcpy(&fe->ops.tuner_ops, &tda18218_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ memcpy(priv->regs, def_regs, sizeof(def_regs));
+
+ /* loop-through enabled chip default register values */
+ if (priv->cfg->loop_through) {
+ priv->regs[R17_PD1] = 0xb0;
+ priv->regs[R18_PD2] = 0x59;
+ }
+
+ /* standby */
+ ret = tda18218_wr_reg(priv, R17_PD1, priv->regs[R17_PD1] | (1 << 0));
+ if (ret)
+ dbg("%s: failed ret:%d", __func__, ret);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0); /* close I2C-gate */
+
+ return fe;
+}
+EXPORT_SYMBOL(tda18218_attach);
+
+MODULE_DESCRIPTION("NXP TDA18218HN silicon tuner driver");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/common/tuners/tda18218.h b/drivers/media/common/tuners/tda18218.h
new file mode 100644
index 000000000000..b4180d180029
--- /dev/null
+++ b/drivers/media/common/tuners/tda18218.h
@@ -0,0 +1,45 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA18218_H
+#define TDA18218_H
+
+#include "dvb_frontend.h"
+
+struct tda18218_config {
+ u8 i2c_address;
+ u8 i2c_wr_max;
+ u8 loop_through:1;
+};
+
+#if defined(CONFIG_MEDIA_TUNER_TDA18218) || \
+ (defined(CONFIG_MEDIA_TUNER_TDA18218_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18218_config *cfg);
+#else
+static inline struct dvb_frontend *tda18218_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, struct tda18218_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/drivers/media/common/tuners/tda18218_priv.h b/drivers/media/common/tuners/tda18218_priv.h
new file mode 100644
index 000000000000..904e5365c78c
--- /dev/null
+++ b/drivers/media/common/tuners/tda18218_priv.h
@@ -0,0 +1,106 @@
+/*
+ * NXP TDA18218HN silicon tuner driver
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef TDA18218_PRIV_H
+#define TDA18218_PRIV_H
+
+#define LOG_PREFIX "tda18218"
+
+#undef dbg
+#define dbg(f, arg...) \
+ if (debug) \
+ printk(KERN_DEBUG LOG_PREFIX": " f "\n" , ## arg)
+#undef err
+#define err(f, arg...) printk(KERN_ERR LOG_PREFIX": " f "\n" , ## arg)
+#undef info
+#define info(f, arg...) printk(KERN_INFO LOG_PREFIX": " f "\n" , ## arg)
+#undef warn
+#define warn(f, arg...) printk(KERN_WARNING LOG_PREFIX": " f "\n" , ## arg)
+
+#define R00_ID 0x00 /* ID byte */
+#define R01_R1 0x01 /* Read byte 1 */
+#define R02_R2 0x02 /* Read byte 2 */
+#define R03_R3 0x03 /* Read byte 3 */
+#define R04_R4 0x04 /* Read byte 4 */
+#define R05_R5 0x05 /* Read byte 5 */
+#define R06_R6 0x06 /* Read byte 6 */
+#define R07_MD1 0x07 /* Main divider byte 1 */
+#define R08_PSM1 0x08 /* PSM byte 1 */
+#define R09_MD2 0x09 /* Main divider byte 2 */
+#define R0A_MD3 0x0a /* Main divider byte 1 */
+#define R0B_MD4 0x0b /* Main divider byte 4 */
+#define R0C_MD5 0x0c /* Main divider byte 5 */
+#define R0D_MD6 0x0d /* Main divider byte 6 */
+#define R0E_MD7 0x0e /* Main divider byte 7 */
+#define R0F_MD8 0x0f /* Main divider byte 8 */
+#define R10_CD1 0x10 /* Call divider byte 1 */
+#define R11_CD2 0x11 /* Call divider byte 2 */
+#define R12_CD3 0x12 /* Call divider byte 3 */
+#define R13_CD4 0x13 /* Call divider byte 4 */
+#define R14_CD5 0x14 /* Call divider byte 5 */
+#define R15_CD6 0x15 /* Call divider byte 6 */
+#define R16_CD7 0x16 /* Call divider byte 7 */
+#define R17_PD1 0x17 /* Power-down byte 1 */
+#define R18_PD2 0x18 /* Power-down byte 2 */
+#define R19_XTOUT 0x19 /* XTOUT byte */
+#define R1A_IF1 0x1a /* IF byte 1 */
+#define R1B_IF2 0x1b /* IF byte 2 */
+#define R1C_AGC2B 0x1c /* AGC2b byte */
+#define R1D_PSM2 0x1d /* PSM byte 2 */
+#define R1E_PSM3 0x1e /* PSM byte 3 */
+#define R1F_PSM4 0x1f /* PSM byte 4 */
+#define R20_AGC11 0x20 /* AGC1 byte 1 */
+#define R21_AGC12 0x21 /* AGC1 byte 2 */
+#define R22_AGC13 0x22 /* AGC1 byte 3 */
+#define R23_AGC21 0x23 /* AGC2 byte 1 */
+#define R24_AGC22 0x24 /* AGC2 byte 2 */
+#define R25_AAGC 0x25 /* Analog AGC byte */
+#define R26_RC 0x26 /* RC byte */
+#define R27_RSSI 0x27 /* RSSI byte */
+#define R28_IRCAL1 0x28 /* IR CAL byte 1 */
+#define R29_IRCAL2 0x29 /* IR CAL byte 2 */
+#define R2A_IRCAL3 0x2a /* IR CAL byte 3 */
+#define R2B_IRCAL4 0x2b /* IR CAL byte 4 */
+#define R2C_RFCAL1 0x2c /* RF CAL byte 1 */
+#define R2D_RFCAL2 0x2d /* RF CAL byte 2 */
+#define R2E_RFCAL3 0x2e /* RF CAL byte 3 */
+#define R2F_RFCAL4 0x2f /* RF CAL byte 4 */
+#define R30_RFCAL5 0x30 /* RF CAL byte 5 */
+#define R31_RFCAL6 0x31 /* RF CAL byte 6 */
+#define R32_RFCAL7 0x32 /* RF CAL byte 7 */
+#define R33_RFCAL8 0x33 /* RF CAL byte 8 */
+#define R34_RFCAL9 0x34 /* RF CAL byte 9 */
+#define R35_RFCAL10 0x35 /* RF CAL byte 10 */
+#define R36_RFCALRAM1 0x36 /* RF CAL RAM byte 1 */
+#define R37_RFCALRAM2 0x37 /* RF CAL RAM byte 2 */
+#define R38_MARGIN 0x38 /* Margin byte */
+#define R39_FMAX1 0x39 /* Fmax byte 1 */
+#define R3A_FMAX2 0x3a /* Fmax byte 2 */
+
+#define TDA18218_NUM_REGS 59
+
+struct tda18218_priv {
+ struct tda18218_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u8 regs[TDA18218_NUM_REGS];
+};
+
+#endif
diff --git a/drivers/media/common/tuners/tda18271-common.c b/drivers/media/common/tuners/tda18271-common.c
index e1f678281a58..5466d47db899 100644
--- a/drivers/media/common/tuners/tda18271-common.c
+++ b/drivers/media/common/tuners/tda18271-common.c
@@ -193,25 +193,51 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
unsigned char *regs = priv->tda18271_regs;
unsigned char buf[TDA18271_NUM_REGS + 1];
struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0,
- .buf = buf, .len = len + 1 };
- int i, ret;
+ .buf = buf };
+ int i, ret = 1, max;
BUG_ON((len == 0) || (idx + len > sizeof(buf)));
- buf[0] = idx;
- for (i = 1; i <= len; i++)
- buf[i] = regs[idx - 1 + i];
+
+ switch (priv->small_i2c) {
+ case TDA18271_03_BYTE_CHUNK_INIT:
+ max = 3;
+ break;
+ case TDA18271_08_BYTE_CHUNK_INIT:
+ max = 8;
+ break;
+ case TDA18271_16_BYTE_CHUNK_INIT:
+ max = 16;
+ break;
+ case TDA18271_39_BYTE_CHUNK_INIT:
+ default:
+ max = 39;
+ }
tda18271_i2c_gate_ctrl(fe, 1);
+ while (len) {
+ if (max > len)
+ max = len;
+
+ buf[0] = idx;
+ for (i = 1; i <= max; i++)
+ buf[i] = regs[idx - 1 + i];
- /* write registers */
- ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ msg.len = max + 1;
+ /* write registers */
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
+ if (ret != 1)
+ break;
+
+ idx += max;
+ len -= max;
+ }
tda18271_i2c_gate_ctrl(fe, 0);
if (ret != 1)
tda_err("ERROR: idx = 0x%x, len = %d, "
- "i2c_transfer returned: %d\n", idx, len, ret);
+ "i2c_transfer returned: %d\n", idx, max, ret);
return (ret == 1 ? 0 : ret);
}
@@ -326,24 +352,7 @@ int tda18271_init_regs(struct dvb_frontend *fe)
regs[R_EB22] = 0x48;
regs[R_EB23] = 0xb0;
- switch (priv->small_i2c) {
- case TDA18271_08_BYTE_CHUNK_INIT:
- tda18271_write_regs(fe, 0x00, 0x08);
- tda18271_write_regs(fe, 0x08, 0x08);
- tda18271_write_regs(fe, 0x10, 0x08);
- tda18271_write_regs(fe, 0x18, 0x08);
- tda18271_write_regs(fe, 0x20, 0x07);
- break;
- case TDA18271_16_BYTE_CHUNK_INIT:
- tda18271_write_regs(fe, 0x00, 0x10);
- tda18271_write_regs(fe, 0x10, 0x10);
- tda18271_write_regs(fe, 0x20, 0x07);
- break;
- case TDA18271_39_BYTE_CHUNK_INIT:
- default:
- tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
- break;
- }
+ tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
/* setup agc1 gain */
regs[R_EB17] = 0x00;
diff --git a/drivers/media/common/tuners/tda18271-fe.c b/drivers/media/common/tuners/tda18271-fe.c
index b2e15456d5f3..9ad4454a148d 100644
--- a/drivers/media/common/tuners/tda18271-fe.c
+++ b/drivers/media/common/tuners/tda18271-fe.c
@@ -1156,7 +1156,6 @@ static int tda18271_get_id(struct dvb_frontend *fe)
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
char *name;
- int ret = 0;
mutex_lock(&priv->lock);
tda18271_read_regs(fe);
@@ -1172,17 +1171,16 @@ static int tda18271_get_id(struct dvb_frontend *fe)
priv->id = TDA18271HDC2;
break;
default:
- name = "Unknown device";
- ret = -EINVAL;
- break;
+ tda_info("Unknown device (%i) detected @ %d-%04x, device not supported.\n",
+ regs[R_ID], i2c_adapter_id(priv->i2c_props.adap),
+ priv->i2c_props.addr);
+ return -EINVAL;
}
- tda_info("%s detected @ %d-%04x%s\n", name,
- i2c_adapter_id(priv->i2c_props.adap),
- priv->i2c_props.addr,
- (0 == ret) ? "" : ", device not supported.");
+ tda_info("%s detected @ %d-%04x\n", name,
+ i2c_adapter_id(priv->i2c_props.adap), priv->i2c_props.addr);
- return ret;
+ return 0;
}
static int tda18271_setup_configuration(struct dvb_frontend *fe,
@@ -1249,7 +1247,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
struct tda18271_config *cfg)
{
struct tda18271_priv *priv = NULL;
- int instance;
+ int instance, ret;
mutex_lock(&tda18271_list_mutex);
@@ -1268,10 +1266,12 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
priv->cal_initialized = false;
mutex_init(&priv->lock);
- if (tda_fail(tda18271_get_id(fe)))
+ ret = tda18271_get_id(fe);
+ if (tda_fail(ret))
goto fail;
- if (tda_fail(tda18271_assign_map_layout(fe)))
+ ret = tda18271_assign_map_layout(fe);
+ if (tda_fail(ret))
goto fail;
mutex_lock(&priv->lock);
diff --git a/drivers/media/common/tuners/tda18271.h b/drivers/media/common/tuners/tda18271.h
index d7fcc36dc6e6..3abb221f3d07 100644
--- a/drivers/media/common/tuners/tda18271.h
+++ b/drivers/media/common/tuners/tda18271.h
@@ -80,8 +80,9 @@ enum tda18271_output_options {
enum tda18271_small_i2c {
TDA18271_39_BYTE_CHUNK_INIT = 0,
- TDA18271_16_BYTE_CHUNK_INIT = 1,
- TDA18271_08_BYTE_CHUNK_INIT = 2,
+ TDA18271_16_BYTE_CHUNK_INIT = 16,
+ TDA18271_08_BYTE_CHUNK_INIT = 8,
+ TDA18271_03_BYTE_CHUNK_INIT = 3,
};
struct tda18271_config {
diff --git a/drivers/media/common/tuners/tda8290.c b/drivers/media/common/tuners/tda8290.c
index c9062ceddc71..bc6a67768af1 100644
--- a/drivers/media/common/tuners/tda8290.c
+++ b/drivers/media/common/tuners/tda8290.c
@@ -95,8 +95,7 @@ static int tda8295_i2c_bridge(struct dvb_frontend *fe, int close)
msleep(20);
} else {
msg = disable;
- tuner_i2c_xfer_send(&priv->i2c_props, msg, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &msg[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, msg, 1, &msg[1], 1);
buf[2] = msg[1];
buf[2] &= ~0x04;
@@ -233,19 +232,22 @@ static void tda8290_set_params(struct dvb_frontend *fe,
tuner_i2c_xfer_send(&priv->i2c_props, pll_bw_nom, 2);
}
+
tda8290_i2c_bridge(fe, 1);
if (fe->ops.tuner_ops.set_analog_params)
fe->ops.tuner_ops.set_analog_params(fe, params);
for (i = 0; i < 3; i++) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_pll_stat, 1, &pll_stat, 1);
if (pll_stat & 0x80) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_adc_sat, 1,
+ &adc_sat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_agc_stat, 1,
+ &agc_stat, 1);
tuner_dbg("tda8290 is locked, AGC: %d\n", agc_stat);
break;
} else {
@@ -259,20 +261,22 @@ static void tda8290_set_params(struct dvb_frontend *fe,
agc_stat, adc_sat, pll_stat & 0x80);
tuner_i2c_xfer_send(&priv->i2c_props, gainset_2, 2);
msleep(100);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_agc_stat, 1, &agc_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_pll_stat, 1, &pll_stat, 1);
if ((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 2. Agc: %d, lock: %d\n",
agc_stat, pll_stat & 0x80);
if (priv->cfg.agcf)
priv->cfg.agcf(fe);
msleep(100);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_agc_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &agc_stat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_agc_stat, 1,
+ &agc_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_pll_stat, 1,
+ &pll_stat, 1);
if((agc_stat > 115) || !(pll_stat & 0x80)) {
tuner_dbg("adjust gain, step 3. Agc: %d\n", agc_stat);
tuner_i2c_xfer_send(&priv->i2c_props, adc_head_12, 2);
@@ -284,10 +288,12 @@ static void tda8290_set_params(struct dvb_frontend *fe,
/* l/ l' deadlock? */
if(priv->tda8290_easy_mode & 0x60) {
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_adc_sat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &adc_sat, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &addr_pll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &pll_stat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_adc_sat, 1,
+ &adc_sat, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &addr_pll_stat, 1,
+ &pll_stat, 1);
if ((adc_sat > 20) || !(pll_stat & 0x80)) {
tuner_dbg("trying to resolve SECAM L deadlock\n");
tuner_i2c_xfer_send(&priv->i2c_props, agc_rst_on, 2);
@@ -307,8 +313,7 @@ static void tda8295_power(struct dvb_frontend *fe, int enable)
struct tda8290_priv *priv = fe->analog_demod_priv;
unsigned char buf[] = { 0x30, 0x00 }; /* clb_stdbt */
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
if (enable)
buf[1] = 0x01;
@@ -323,8 +328,7 @@ static void tda8295_set_easy_mode(struct dvb_frontend *fe, int enable)
struct tda8290_priv *priv = fe->analog_demod_priv;
unsigned char buf[] = { 0x01, 0x00 };
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
if (enable)
buf[1] = 0x01; /* rising edge sets regs 0x02 - 0x23 */
@@ -353,8 +357,7 @@ static void tda8295_agc1_out(struct dvb_frontend *fe, int enable)
struct tda8290_priv *priv = fe->analog_demod_priv;
unsigned char buf[] = { 0x02, 0x00 }; /* DIV_FUNC */
- tuner_i2c_xfer_send(&priv->i2c_props, &buf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &buf[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, &buf[0], 1, &buf[1], 1);
if (enable)
buf[1] &= ~0x40;
@@ -370,10 +373,10 @@ static void tda8295_agc2_out(struct dvb_frontend *fe, int enable)
unsigned char set_gpio_cf[] = { 0x44, 0x00 };
unsigned char set_gpio_val[] = { 0x46, 0x00 };
- tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_cf[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_cf[1], 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &set_gpio_val[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &set_gpio_val[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &set_gpio_cf[0], 1, &set_gpio_cf[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &set_gpio_val[0], 1, &set_gpio_val[1], 1);
set_gpio_cf[1] &= 0xf0; /* clear GPIO_0 bits 3-0 */
@@ -392,8 +395,7 @@ static int tda8295_has_signal(struct dvb_frontend *fe)
unsigned char hvpll_stat = 0x26;
unsigned char ret;
- tuner_i2c_xfer_send(&priv->i2c_props, &hvpll_stat, 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &ret, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props, &hvpll_stat, 1, &ret, 1);
return (ret & 0x01) ? 65535 : 0;
}
@@ -413,8 +415,8 @@ static void tda8295_set_params(struct dvb_frontend *fe,
tda8295_power(fe, 1);
tda8295_agc1_out(fe, 1);
- tuner_i2c_xfer_send(&priv->i2c_props, &blanking_mode[0], 1);
- tuner_i2c_xfer_recv(&priv->i2c_props, &blanking_mode[1], 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ &blanking_mode[0], 1, &blanking_mode[1], 1);
tda8295_set_video_std(fe);
@@ -447,8 +449,8 @@ static int tda8290_has_signal(struct dvb_frontend *fe)
unsigned char i2c_get_afc[1] = { 0x1B };
unsigned char afc = 0;
- tuner_i2c_xfer_send(&priv->i2c_props, i2c_get_afc, ARRAY_SIZE(i2c_get_afc));
- tuner_i2c_xfer_recv(&priv->i2c_props, &afc, 1);
+ tuner_i2c_xfer_send_recv(&priv->i2c_props,
+ i2c_get_afc, ARRAY_SIZE(i2c_get_afc), &afc, 1);
return (afc & 0x80)? 65535:0;
}
@@ -654,20 +656,26 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
static int tda8290_probe(struct tuner_i2c_props *i2c_props)
{
#define TDA8290_ID 0x89
- unsigned char tda8290_id[] = { 0x1f, 0x00 };
+ u8 reg = 0x1f, id;
+ struct i2c_msg msg_read[] = {
+ { .addr = 0x4b, .flags = 0, .len = 1, .buf = &reg },
+ { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id },
+ };
/* detect tda8290 */
- tuner_i2c_xfer_send(i2c_props, &tda8290_id[0], 1);
- tuner_i2c_xfer_recv(i2c_props, &tda8290_id[1], 1);
+ if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
+ printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n",
+ __func__, reg);
+ return -ENODEV;
+ }
- if (tda8290_id[1] == TDA8290_ID) {
+ if (id == TDA8290_ID) {
if (debug)
printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
__func__, i2c_adapter_id(i2c_props->adap),
i2c_props->addr);
return 0;
}
-
return -ENODEV;
}
@@ -675,16 +683,23 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props)
{
#define TDA8295_ID 0x8a
#define TDA8295C2_ID 0x8b
- unsigned char tda8295_id[] = { 0x2f, 0x00 };
+ u8 reg = 0x2f, id;
+ struct i2c_msg msg_read[] = {
+ { .addr = 0x4b, .flags = 0, .len = 1, .buf = &reg },
+ { .addr = 0x4b, .flags = I2C_M_RD, .len = 1, .buf = &id },
+ };
- /* detect tda8295 */
- tuner_i2c_xfer_send(i2c_props, &tda8295_id[0], 1);
- tuner_i2c_xfer_recv(i2c_props, &tda8295_id[1], 1);
+ /* detect tda8290 */
+ if (i2c_transfer(i2c_props->adap, msg_read, 2) != 2) {
+ printk(KERN_WARNING "%s: tda8290 couldn't read register 0x%02x\n",
+ __func__, reg);
+ return -ENODEV;
+ }
- if ((tda8295_id[1] & 0xfe) == TDA8295_ID) {
+ if ((id & 0xfe) == TDA8295_ID) {
if (debug)
printk(KERN_DEBUG "%s: %s detected @ %d-%04x\n",
- __func__, (tda8295_id[1] == TDA8295_ID) ?
+ __func__, (id == TDA8295_ID) ?
"tda8295c1" : "tda8295c2",
i2c_adapter_id(i2c_props->adap),
i2c_props->addr);
@@ -740,9 +755,11 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
sizeof(struct analog_demod_ops));
}
- if ((!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) &&
- (tda829x_find_tuner(fe) < 0))
- goto fail;
+ if (!(cfg) || (TDA829X_PROBE_TUNER == cfg->probe_tuner)) {
+ tda8295_power(fe, 1);
+ if (tda829x_find_tuner(fe) < 0)
+ goto fail;
+ }
switch (priv->ver) {
case TDA8290:
@@ -786,6 +803,8 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
return fe;
fail:
+ memset(&fe->ops.analog_ops, 0, sizeof(struct analog_demod_ops));
+
tda829x_release(fe);
return NULL;
}
@@ -809,8 +828,8 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
int i;
/* rule out tda9887, which would return the same byte repeatedly */
- tuner_i2c_xfer_send(&i2c_props, soft_reset, 1);
- tuner_i2c_xfer_recv(&i2c_props, buf, PROBE_BUFFER_SIZE);
+ tuner_i2c_xfer_send_recv(&i2c_props,
+ soft_reset, 1, buf, PROBE_BUFFER_SIZE);
for (i = 1; i < PROBE_BUFFER_SIZE; i++) {
if (buf[i] != buf[0])
break;
@@ -827,13 +846,12 @@ int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
/* fall back to old probing method */
tuner_i2c_xfer_send(&i2c_props, easy_mode_b, 2);
tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
- tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
- tuner_i2c_xfer_recv(&i2c_props, &data, 1);
+ tuner_i2c_xfer_send_recv(&i2c_props, &addr_dto_lsb, 1, &data, 1);
if (data == 0) {
tuner_i2c_xfer_send(&i2c_props, easy_mode_g, 2);
tuner_i2c_xfer_send(&i2c_props, soft_reset, 2);
- tuner_i2c_xfer_send(&i2c_props, &addr_dto_lsb, 1);
- tuner_i2c_xfer_recv(&i2c_props, &data, 1);
+ tuner_i2c_xfer_send_recv(&i2c_props,
+ &addr_dto_lsb, 1, &data, 1);
if (data == 0x7b) {
return 0;
}
diff --git a/drivers/media/common/tuners/tuner-simple.c b/drivers/media/common/tuners/tuner-simple.c
index 8abbcc5fcf95..f8ee29e6059c 100644
--- a/drivers/media/common/tuners/tuner-simple.c
+++ b/drivers/media/common/tuners/tuner-simple.c
@@ -524,6 +524,7 @@ static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
buffer[3] = 0x39;
break;
case TUNER_PHILIPS_FQ1216LME_MK3:
+ case TUNER_PHILIPS_FQ1236_MK5:
tuner_err("This tuner doesn't have FM\n");
/* Set the low band for sanity, since it covers 88-108 MHz */
buffer[3] = 0x01;
@@ -545,14 +546,11 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
struct tuner_simple_priv *priv = fe->tuner_priv;
u8 config, cb;
u16 div;
- struct tunertype *tun;
u8 buffer[4];
int rc, IFPCoff, i;
enum param_type desired_type;
struct tuner_params *t_params;
- tun = priv->tun;
-
/* IFPCoff = Video Intermediate Frequency - Vif:
940 =16*58.75 NTSC/J (Japan)
732 =16*45.75 M/N STD
diff --git a/drivers/media/common/tuners/tuner-types.c b/drivers/media/common/tuners/tuner-types.c
index d9aaaca620c9..58a513bcd747 100644
--- a/drivers/media/common/tuners/tuner-types.c
+++ b/drivers/media/common/tuners/tuner-types.c
@@ -1353,6 +1353,17 @@ static struct tuner_params tuner_sony_btf_pxn01z_params[] = {
},
};
+/* ------------ TUNER_PHILIPS_FQ1236_MK5 - Philips NTSC ------------ */
+
+static struct tuner_params tuner_philips_fq1236_mk5_params[] = {
+ {
+ .type = TUNER_PARAM_TYPE_NTSC,
+ .ranges = tuner_fm1236_mk3_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_fm1236_mk3_ntsc_ranges),
+ .has_tda9887 = 1, /* TDA9885, no FM radio */
+ },
+};
+
/* --------------------------------------------------------------------- */
struct tunertype tuners[] = {
@@ -1826,6 +1837,11 @@ struct tunertype tuners[] = {
.params = tuner_sony_btf_pxn01z_params,
.count = ARRAY_SIZE(tuner_sony_btf_pxn01z_params),
},
+ [TUNER_PHILIPS_FQ1236_MK5] = { /* NTSC, TDA9885, no FM radio */
+ .name = "Philips FQ1236 MK5",
+ .params = tuner_philips_fq1236_mk5_params,
+ .count = ARRAY_SIZE(tuner_philips_fq1236_mk5_params),
+ },
};
EXPORT_SYMBOL(tuners);
diff --git a/drivers/media/common/tuners/xc5000.c b/drivers/media/common/tuners/xc5000.c
index 432003dded7c..76ac5cd84af7 100644
--- a/drivers/media/common/tuners/xc5000.c
+++ b/drivers/media/common/tuners/xc5000.c
@@ -217,6 +217,7 @@ static int xc_send_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
return XC_RESULT_SUCCESS;
}
+#if 0
/* This routine is never used because the only time we read data from the
i2c bus is when we read registers, and we want that to be an atomic i2c
transaction in case we are on a multi-master bus */
@@ -231,6 +232,27 @@ static int xc_read_i2c_data(struct xc5000_priv *priv, u8 *buf, int len)
}
return 0;
}
+#endif
+
+static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
+{
+ u8 buf[2] = { reg >> 8, reg & 0xff };
+ u8 bval[2] = { 0, 0 };
+ struct i2c_msg msg[2] = {
+ { .addr = priv->i2c_props.addr,
+ .flags = 0, .buf = &buf[0], .len = 2 },
+ { .addr = priv->i2c_props.addr,
+ .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
+ };
+
+ if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
+ printk(KERN_WARNING "xc5000: I2C read failed\n");
+ return -EREMOTEIO;
+ }
+
+ *val = (bval[0] << 8) | bval[1];
+ return XC_RESULT_SUCCESS;
+}
static void xc_wait(int wait_ms)
{
@@ -275,20 +297,14 @@ static int xc_write_reg(struct xc5000_priv *priv, u16 regAddr, u16 i2cData)
if (result == XC_RESULT_SUCCESS) {
/* wait for busy flag to clear */
while ((WatchDogTimer > 0) && (result == XC_RESULT_SUCCESS)) {
- buf[0] = 0;
- buf[1] = XREG_BUSY;
-
- result = xc_send_i2c_data(priv, buf, 2);
+ result = xc5000_readreg(priv, XREG_BUSY, (u16 *)buf);
if (result == XC_RESULT_SUCCESS) {
- result = xc_read_i2c_data(priv, buf, 2);
- if (result == XC_RESULT_SUCCESS) {
- if ((buf[0] == 0) && (buf[1] == 0)) {
- /* busy flag cleared */
+ if ((buf[0] == 0) && (buf[1] == 0)) {
+ /* busy flag cleared */
break;
- } else {
- xc_wait(5); /* wait 5 ms */
- WatchDogTimer--;
- }
+ } else {
+ xc_wait(5); /* wait 5 ms */
+ WatchDogTimer--;
}
}
}
@@ -526,25 +542,6 @@ static int xc_tune_channel(struct xc5000_priv *priv, u32 freq_hz, int mode)
return found;
}
-static int xc5000_readreg(struct xc5000_priv *priv, u16 reg, u16 *val)
-{
- u8 buf[2] = { reg >> 8, reg & 0xff };
- u8 bval[2] = { 0, 0 };
- struct i2c_msg msg[2] = {
- { .addr = priv->i2c_props.addr,
- .flags = 0, .buf = &buf[0], .len = 2 },
- { .addr = priv->i2c_props.addr,
- .flags = I2C_M_RD, .buf = &bval[0], .len = 2 },
- };
-
- if (i2c_transfer(priv->i2c_props.adap, msg, 2) != 2) {
- printk(KERN_WARNING "xc5000: I2C read failed\n");
- return -EREMOTEIO;
- }
-
- *val = (bval[0] << 8) | bval[1];
- return XC_RESULT_SUCCESS;
-}
static int xc5000_fwupload(struct dvb_frontend *fe)
{
@@ -1045,7 +1042,7 @@ static const struct dvb_tuner_ops xc5000_tuner_ops = {
struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg)
+ const struct xc5000_config *cfg)
{
struct xc5000_priv *priv = NULL;
int instance;
diff --git a/drivers/media/common/tuners/xc5000.h b/drivers/media/common/tuners/xc5000.h
index e6d7236c9ea1..3756e73649be 100644
--- a/drivers/media/common/tuners/xc5000.h
+++ b/drivers/media/common/tuners/xc5000.h
@@ -53,11 +53,11 @@ struct xc5000_config {
(defined(CONFIG_MEDIA_TUNER_XC5000_MODULE) && defined(MODULE))
extern struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg);
+ const struct xc5000_config *cfg);
#else
static inline struct dvb_frontend *xc5000_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c,
- struct xc5000_config *cfg)
+ const struct xc5000_config *cfg)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index fd1df2352764..965d5eb33752 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -245,9 +245,6 @@ int flexcop_i2c_init(struct flexcop_device *fc)
i2c_set_adapdata(&fc->fc_i2c_adap[1].i2c_adap, &fc->fc_i2c_adap[1]);
i2c_set_adapdata(&fc->fc_i2c_adap[2].i2c_adap, &fc->fc_i2c_adap[2]);
- fc->fc_i2c_adap[0].i2c_adap.class =
- fc->fc_i2c_adap[1].i2c_adap.class =
- fc->fc_i2c_adap[2].i2c_adap.class = I2C_CLASS_TV_DIGITAL;
fc->fc_i2c_adap[0].i2c_adap.algo =
fc->fc_i2c_adap[1].i2c_adap.algo =
fc->fc_i2c_adap[2].i2c_adap.algo = &flexcop_algo;
diff --git a/drivers/media/dvb/bt8xx/dst.c b/drivers/media/dvb/bt8xx/dst.c
index 248a2a9d8416..caa4e18ed1c1 100644
--- a/drivers/media/dvb/bt8xx/dst.c
+++ b/drivers/media/dvb/bt8xx/dst.c
@@ -1763,7 +1763,15 @@ static struct dvb_frontend_ops dst_dvbt_ops = {
.frequency_min = 137000000,
.frequency_max = 858000000,
.frequency_stepsize = 166667,
- .caps = FE_CAN_FEC_AUTO | FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO
+ .caps = FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_AUTO |
+ FE_CAN_QAM_16 |
+ FE_CAN_QAM_32 |
+ FE_CAN_QAM_64 |
+ FE_CAN_QAM_128 |
+ FE_CAN_QAM_256 |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO
},
.release = dst_release,
diff --git a/drivers/media/dvb/bt8xx/dst_ca.c b/drivers/media/dvb/bt8xx/dst_ca.c
index 770243c720d2..48e48e8af55a 100644
--- a/drivers/media/dvb/bt8xx/dst_ca.c
+++ b/drivers/media/dvb/bt8xx/dst_ca.c
@@ -22,7 +22,7 @@
#include <linux/module.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/smp_lock.h>
+#include <linux/mutex.h>
#include <linux/string.h>
#include <linux/dvb/ca.h>
#include "dvbdev.h"
@@ -52,6 +52,7 @@
} while(0)
+static DEFINE_MUTEX(dst_ca_mutex);
static unsigned int verbose = 5;
module_param(verbose, int, 0644);
MODULE_PARM_DESC(verbose, "verbose startup messages, default is 1 (yes)");
@@ -564,8 +565,8 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct
void __user *arg = (void __user *)ioctl_arg;
int result = 0;
- lock_kernel();
- dvbdev = (struct dvb_device *)file->private_data;
+ mutex_lock(&dst_ca_mutex);
+ dvbdev = file->private_data;
state = (struct dst_state *)dvbdev->priv;
p_ca_message = kmalloc(sizeof (struct ca_msg), GFP_KERNEL);
p_ca_slot_info = kmalloc(sizeof (struct ca_slot_info), GFP_KERNEL);
@@ -652,7 +653,7 @@ static long dst_ca_ioctl(struct file *file, unsigned int cmd, unsigned long ioct
kfree (p_ca_slot_info);
kfree (p_ca_caps);
- unlock_kernel();
+ mutex_unlock(&dst_ca_mutex);
return result;
}
@@ -694,7 +695,8 @@ static const struct file_operations dst_ca_fops = {
.open = dst_ca_open,
.release = dst_ca_release,
.read = dst_ca_read,
- .write = dst_ca_write
+ .write = dst_ca_write,
+ .llseek = noop_llseek,
};
static struct dvb_device dvbdev_ca = {
diff --git a/drivers/media/dvb/dm1105/Kconfig b/drivers/media/dvb/dm1105/Kconfig
index 695239227cb7..f3de0a4d63f2 100644
--- a/drivers/media/dvb/dm1105/Kconfig
+++ b/drivers/media/dvb/dm1105/Kconfig
@@ -1,7 +1,6 @@
config DVB_DM1105
tristate "SDMC DM1105 based PCI cards"
depends on DVB_CORE && PCI && I2C
- depends on INPUT
select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_STV0288 if !DVB_FE_CUSTOMISE
@@ -9,7 +8,7 @@ config DVB_DM1105
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_SI21XX if !DVB_FE_CUSTOMISE
select DVB_DS3000 if !DVB_FE_CUSTOMISE
- select VIDEO_IR
+ depends on RC_CORE
help
Support for cards based on the SDMC DM1105 PCI chip like
DvbWorld 2002
diff --git a/drivers/media/dvb/dm1105/dm1105.c b/drivers/media/dvb/dm1105/dm1105.c
index b762e561a6d5..2d8b4044be36 100644
--- a/drivers/media/dvb/dm1105/dm1105.c
+++ b/drivers/media/dvb/dm1105/dm1105.c
@@ -26,9 +26,8 @@
#include <linux/proc_fs.h>
#include <linux/pci.h>
#include <linux/dma-mapping.h>
-#include <linux/input.h>
#include <linux/slab.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "demux.h"
#include "dmxdev.h"
@@ -266,7 +265,7 @@ static void dm1105_card_list(struct pci_dev *pci)
/* infrared remote control */
struct infrared {
- struct input_dev *input_dev;
+ struct rc_dev *dev;
char input_phys[32];
struct work_struct work;
u32 ir_command;
@@ -532,7 +531,7 @@ static void dm1105_emit_key(struct work_struct *work)
data = (ircom >> 8) & 0x7f;
- ir_keydown(ir->input_dev, data, 0);
+ rc_keydown(ir->dev, data, 0);
}
/* work handler */
@@ -593,46 +592,47 @@ static irqreturn_t dm1105_irq(int irq, void *dev_id)
int __devinit dm1105_ir_init(struct dm1105_dev *dm1105)
{
- struct input_dev *input_dev;
- char *ir_codes = NULL;
+ struct rc_dev *dev;
int err = -ENOMEM;
- input_dev = input_allocate_device();
- if (!input_dev)
+ dev = rc_allocate_device();
+ if (!dev)
return -ENOMEM;
- dm1105->ir.input_dev = input_dev;
snprintf(dm1105->ir.input_phys, sizeof(dm1105->ir.input_phys),
"pci-%s/ir0", pci_name(dm1105->pdev));
- input_dev->name = "DVB on-card IR receiver";
- input_dev->phys = dm1105->ir.input_phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ dev->driver_name = MODULE_NAME;
+ dev->map_name = RC_MAP_DM1105_NEC;
+ dev->driver_type = RC_DRIVER_SCANCODE;
+ dev->input_name = "DVB on-card IR receiver";
+ dev->input_phys = dm1105->ir.input_phys;
+ dev->input_id.bustype = BUS_PCI;
+ dev->input_id.version = 1;
if (dm1105->pdev->subsystem_vendor) {
- input_dev->id.vendor = dm1105->pdev->subsystem_vendor;
- input_dev->id.product = dm1105->pdev->subsystem_device;
+ dev->input_id.vendor = dm1105->pdev->subsystem_vendor;
+ dev->input_id.product = dm1105->pdev->subsystem_device;
} else {
- input_dev->id.vendor = dm1105->pdev->vendor;
- input_dev->id.product = dm1105->pdev->device;
+ dev->input_id.vendor = dm1105->pdev->vendor;
+ dev->input_id.product = dm1105->pdev->device;
}
-
- input_dev->dev.parent = &dm1105->pdev->dev;
+ dev->dev.parent = &dm1105->pdev->dev;
INIT_WORK(&dm1105->ir.work, dm1105_emit_key);
- err = ir_input_register(input_dev, ir_codes, NULL, MODULE_NAME);
+ err = rc_register_device(dev);
if (err < 0) {
- input_free_device(input_dev);
+ rc_free_device(dev);
return err;
}
+ dm1105->ir.dev = dev;
return 0;
}
void __devexit dm1105_ir_exit(struct dm1105_dev *dm1105)
{
- ir_input_unregister(dm1105->ir.input_dev);
+ rc_unregister_device(dm1105->ir.dev);
}
static int __devinit dm1105_hw_init(struct dm1105_dev *dev)
@@ -862,7 +862,6 @@ static int __devinit dm1105_probe(struct pci_dev *pdev,
i2c_set_adapdata(&dev->i2c_adap, dev);
strcpy(dev->i2c_adap.name, DRIVER_NAME);
dev->i2c_adap.owner = THIS_MODULE;
- dev->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
dev->i2c_adap.dev.parent = &pdev->dev;
dev->i2c_adap.algo = &dm1105_algo;
dev->i2c_adap.algo_data = dev;
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index 425862ffb285..e4b5c03ae516 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <linux/poll.h>
#include <linux/ioctl.h>
#include <linux/wait.h>
@@ -207,7 +206,7 @@ static int dvb_dvr_release(struct inode *inode, struct file *file)
}
/* TODO */
dvbdev->users--;
- if(dvbdev->users==-1 && dmxdev->exit==1) {
+ if (dvbdev->users == 1 && dmxdev->exit == 1) {
fops_put(file->f_op);
file->f_op = NULL;
mutex_unlock(&dmxdev->mutex);
@@ -573,13 +572,13 @@ static int dvb_dmxdev_start_feed(struct dmxdev *dmxdev,
dmx_output_t otype;
int ret;
int ts_type;
- enum dmx_ts_pes ts_pes;
+ dmx_pes_type_t ts_pes;
struct dmx_ts_feed *tsfeed;
feed->ts = NULL;
otype = para->output;
- ts_pes = (enum dmx_ts_pes)para->pes_type;
+ ts_pes = para->pes_type;
if (ts_pes < DMX_PES_OTHER)
ts_type = TS_DECODER;
@@ -1088,13 +1087,7 @@ static int dvb_demux_do_ioctl(struct file *file,
static long dvb_demux_ioctl(struct file *file, unsigned int cmd,
unsigned long arg)
{
- int ret;
-
- lock_kernel();
- ret = dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
- unlock_kernel();
-
- return ret;
+ return dvb_usercopy(file, cmd, arg, dvb_demux_do_ioctl);
}
static unsigned int dvb_demux_poll(struct file *file, poll_table *wait)
@@ -1150,6 +1143,7 @@ static const struct file_operations dvb_demux_fops = {
.open = dvb_demux_open,
.release = dvb_demux_release,
.poll = dvb_demux_poll,
+ .llseek = default_llseek,
};
static struct dvb_device dvbdev_demux = {
@@ -1186,13 +1180,7 @@ static int dvb_dvr_do_ioctl(struct file *file,
static long dvb_dvr_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- int ret;
-
- lock_kernel();
- ret = dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
- unlock_kernel();
-
- return ret;
+ return dvb_usercopy(file, cmd, arg, dvb_dvr_do_ioctl);
}
static unsigned int dvb_dvr_poll(struct file *file, poll_table *wait)
@@ -1225,6 +1213,7 @@ static const struct file_operations dvb_dvr_fops = {
.open = dvb_dvr_open,
.release = dvb_dvr_release,
.poll = dvb_dvr_poll,
+ .llseek = default_llseek,
};
static struct dvb_device dvbdev_dvr = {
diff --git a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
index ef259a0718ac..7ea517b7e186 100644
--- a/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
+++ b/drivers/media/dvb/dvb-core/dvb_ca_en50221.c
@@ -36,7 +36,6 @@
#include <linux/delay.h>
#include <linux/spinlock.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include "dvb_ca_en50221.h"
@@ -1259,13 +1258,7 @@ static int dvb_ca_en50221_io_do_ioctl(struct file *file,
static long dvb_ca_en50221_io_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- int ret;
-
- lock_kernel();
- ret = dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
- unlock_kernel();
-
- return ret;
+ return dvb_usercopy(file, cmd, arg, dvb_ca_en50221_io_do_ioctl);
}
@@ -1318,8 +1311,11 @@ static ssize_t dvb_ca_en50221_io_write(struct file *file,
fragbuf[0] = connection_id;
fragbuf[1] = ((fragpos + fraglen) < count) ? 0x80 : 0x00;
- if ((status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen)) != 0)
+ status = copy_from_user(fragbuf + 2, buf + fragpos, fraglen);
+ if (status) {
+ status = -EFAULT;
goto exit;
+ }
timeout = jiffies + HZ / 2;
written = 0;
@@ -1494,8 +1490,11 @@ static ssize_t dvb_ca_en50221_io_read(struct file *file, char __user * buf,
hdr[0] = slot;
hdr[1] = connection_id;
- if ((status = copy_to_user(buf, hdr, 2)) != 0)
+ status = copy_to_user(buf, hdr, 2);
+ if (status) {
+ status = -EFAULT;
goto exit;
+ }
status = pktlen;
exit:
@@ -1622,6 +1621,7 @@ static const struct file_operations dvb_ca_fops = {
.open = dvb_ca_en50221_io_open,
.release = dvb_ca_en50221_io_release,
.poll = dvb_ca_en50221_io_poll,
+ .llseek = noop_llseek,
};
static struct dvb_device dvbdev_ca = {
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 977ddba3e235..4a88a3e4db2b 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -1130,13 +1130,9 @@ static int dvbdmx_write(struct dmx_demux *demux, const char __user *buf, size_t
if ((!demux->frontend) || (demux->frontend->source != DMX_MEMORY_FE))
return -EINVAL;
- p = kmalloc(count, GFP_USER);
- if (!p)
- return -ENOMEM;
- if (copy_from_user(p, buf, count)) {
- kfree(p);
- return -EFAULT;
- }
+ p = memdup_user(buf, count);
+ if (IS_ERR(p))
+ return PTR_ERR(p);
if (mutex_lock_interruptible(&dvbdemux->mutex)) {
kfree(p);
return -ERESTARTSYS;
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.c b/drivers/media/dvb/dvb-core/dvb_frontend.c
index 44ae89ecef94..cad6634610ea 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -36,7 +36,6 @@
#include <linux/list.h>
#include <linux/freezer.h>
#include <linux/jiffies.h>
-#include <linux/smp_lock.h>
#include <linux/kthread.h>
#include <asm/processor.h>
@@ -465,7 +464,7 @@ static void dvb_frontend_swzigzag(struct dvb_frontend *fe)
if ((fepriv->state & FESTATE_SEARCHING_FAST) || (fepriv->state & FESTATE_RETUNE)) {
fepriv->delay = fepriv->min_delay;
- /* peform a tune */
+ /* perform a tune */
retval = dvb_frontend_swzigzag_autotune(fe,
fepriv->check_wrapped);
if (retval < 0) {
@@ -702,7 +701,7 @@ static void dvb_frontend_stop(struct dvb_frontend *fe)
kthread_stop(fepriv->thread);
- init_MUTEX (&fepriv->sem);
+ sema_init(&fepriv->sem, 1);
fepriv->state = FESTATE_IDLE;
/* paranoia check in case a signal arrived */
@@ -791,7 +790,7 @@ static int dvb_frontend_start(struct dvb_frontend *fe)
return 0;
}
-static void dvb_frontend_get_frequeny_limits(struct dvb_frontend *fe,
+static void dvb_frontend_get_frequency_limits(struct dvb_frontend *fe,
u32 *freq_min, u32 *freq_max)
{
*freq_min = max(fe->ops.info.frequency_min, fe->ops.tuner_ops.info.frequency_min);
@@ -815,7 +814,7 @@ static int dvb_frontend_check_parameters(struct dvb_frontend *fe,
u32 freq_max;
/* range check: frequency */
- dvb_frontend_get_frequeny_limits(fe, &freq_min, &freq_max);
+ dvb_frontend_get_frequency_limits(fe, &freq_min, &freq_max);
if ((freq_min && parms->frequency < freq_min) ||
(freq_max && parms->frequency > freq_max)) {
printk(KERN_WARNING "DVB: adapter %i frontend %i frequency %u out of range (%u..%u)\n",
@@ -1627,7 +1626,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
case FE_GET_INFO: {
struct dvb_frontend_info* info = parg;
memcpy(info, &fe->ops.info, sizeof(struct dvb_frontend_info));
- dvb_frontend_get_frequeny_limits(fe, &info->frequency_min, &info->frequency_max);
+ dvb_frontend_get_frequency_limits(fe, &info->frequency_min, &info->frequency_max);
/* Force the CAN_INVERSION_AUTO bit on. If the frontend doesn't
* do it, it is done for it. */
@@ -1726,7 +1725,7 @@ static int dvb_frontend_ioctl_legacy(struct file *file,
* (stv0299 for instance) take longer than 8msec to
* respond to a set_voltage command. Those switches
* need custom routines to switch properly. For all
- * other frontends, the following shoule work ok.
+ * other frontends, the following should work ok.
* Dish network legacy switches (as used by Dish500)
* are controlled by sending 9-bit command words
* spaced 8msec apart.
@@ -2034,7 +2033,8 @@ static const struct file_operations dvb_frontend_fops = {
.unlocked_ioctl = dvb_generic_ioctl,
.poll = dvb_frontend_poll,
.open = dvb_frontend_open,
- .release = dvb_frontend_release
+ .release = dvb_frontend_release,
+ .llseek = noop_llseek,
};
int dvb_register_frontend(struct dvb_adapter* dvb,
@@ -2061,7 +2061,7 @@ int dvb_register_frontend(struct dvb_adapter* dvb,
}
fepriv = fe->frontend_priv;
- init_MUTEX (&fepriv->sem);
+ sema_init(&fepriv->sem, 1);
init_waitqueue_head (&fepriv->wait_queue);
init_waitqueue_head (&fepriv->events.wait_queue);
mutex_init(&fepriv->events.mtx);
diff --git a/drivers/media/dvb/dvb-core/dvb_frontend.h b/drivers/media/dvb/dvb-core/dvb_frontend.h
index bf0e6bed28dd..f9f19be77181 100644
--- a/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -260,7 +260,7 @@ struct dvb_frontend_ops {
int (*init)(struct dvb_frontend* fe);
int (*sleep)(struct dvb_frontend* fe);
- int (*write)(struct dvb_frontend* fe, u8* buf, int len);
+ int (*write)(struct dvb_frontend* fe, const u8 buf[], int len);
/* if this is set, it overrides the default swzigzag */
int (*tune)(struct dvb_frontend* fe,
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index f6dac2bb0ac6..51752a9ef7a4 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -59,7 +59,6 @@
#include <linux/netdevice.h>
#include <linux/etherdevice.h>
#include <linux/dvb/net.h>
-#include <linux/smp_lock.h>
#include <linux/uio.h>
#include <asm/uaccess.h>
#include <linux/crc32.h>
@@ -351,6 +350,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
const u8 *ts, *ts_end, *from_where = NULL;
u8 ts_remain = 0, how_much = 0, new_ts = 1;
struct ethhdr *ethh = NULL;
+ bool error = false;
#ifdef ULE_DEBUG
/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
@@ -460,10 +460,16 @@ 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 );
+ error = true;
+ dev_kfree_skb(priv->ule_skb);
+ }
+
+ if (error || priv->ule_sndu_remain) {
dev->stats.rx_errors++;
dev->stats.rx_frame_errors++;
+ error = false;
}
+
reset_ule(priv);
priv->need_pusi = 1;
continue;
@@ -535,6 +541,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
from_where += 2;
}
+ priv->ule_sndu_remain = priv->ule_sndu_len + 2;
/*
* State of current TS:
* ts_remain (remaining bytes in the current TS cell)
@@ -544,6 +551,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
*/
switch (ts_remain) {
case 1:
+ priv->ule_sndu_remain--;
priv->ule_sndu_type = from_where[0] << 8;
priv->ule_sndu_type_1 = 1; /* first byte of ule_type is set. */
ts_remain -= 1; from_where += 1;
@@ -557,6 +565,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
default: /* complete ULE header is present in current TS. */
/* Extract ULE type field. */
if (priv->ule_sndu_type_1) {
+ priv->ule_sndu_type_1 = 0;
priv->ule_sndu_type |= from_where[0];
from_where += 1; /* points to payload start. */
ts_remain -= 1;
@@ -1320,7 +1329,8 @@ static int dvb_net_remove_if(struct dvb_net *dvbnet, unsigned long num)
return -EBUSY;
dvb_net_stop(net);
- flush_scheduled_work();
+ flush_work_sync(&priv->set_multicast_list_wq);
+ flush_work_sync(&priv->restart_net_feed_wq);
printk("dvb_net: removed network interface %s\n", net->name);
unregister_netdev(net);
dvbnet->state[num]=0;
@@ -1435,13 +1445,7 @@ static int dvb_net_do_ioctl(struct file *file,
static long dvb_net_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
- int ret;
-
- lock_kernel();
- ret = dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
- unlock_kernel();
-
- return ret;
+ return dvb_usercopy(file, cmd, arg, dvb_net_do_ioctl);
}
static int dvb_net_close(struct inode *inode, struct file *file)
@@ -1465,6 +1469,7 @@ static const struct file_operations dvb_net_fops = {
.unlocked_ioctl = dvb_net_ioctl,
.open = dvb_generic_open,
.release = dvb_net_close,
+ .llseek = noop_llseek,
};
static struct dvb_device dvbdev_net = {
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index b915c39d782f..f73287775953 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -32,9 +32,9 @@
#include <linux/fs.h>
#include <linux/cdev.h>
#include <linux/mutex.h>
-#include <linux/smp_lock.h>
#include "dvbdev.h"
+static DEFINE_MUTEX(dvbdev_mutex);
static int dvbdev_debug;
module_param(dvbdev_debug, int, 0644);
@@ -68,7 +68,7 @@ static int dvb_device_open(struct inode *inode, struct file *file)
{
struct dvb_device *dvbdev;
- lock_kernel();
+ mutex_lock(&dvbdev_mutex);
down_read(&minor_rwsem);
dvbdev = dvb_minors[iminor(inode)];
@@ -91,12 +91,12 @@ static int dvb_device_open(struct inode *inode, struct file *file)
}
fops_put(old_fops);
up_read(&minor_rwsem);
- unlock_kernel();
+ mutex_unlock(&dvbdev_mutex);
return err;
}
fail:
up_read(&minor_rwsem);
- unlock_kernel();
+ mutex_unlock(&dvbdev_mutex);
return -ENODEV;
}
@@ -105,6 +105,7 @@ static const struct file_operations dvb_device_fops =
{
.owner = THIS_MODULE,
.open = dvb_device_open,
+ .llseek = noop_llseek,
};
static struct cdev dvb_device_cdev;
@@ -158,7 +159,6 @@ long dvb_generic_ioctl(struct file *file,
unsigned int cmd, unsigned long arg)
{
struct dvb_device *dvbdev = file->private_data;
- int ret;
if (!dvbdev)
return -ENODEV;
@@ -166,11 +166,7 @@ long dvb_generic_ioctl(struct file *file,
if (!dvbdev->kernel_ioctl)
return -EINVAL;
- lock_kernel();
- ret = dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
- unlock_kernel();
-
- return ret;
+ return dvb_usercopy(file, cmd, arg, dvbdev->kernel_ioctl);
}
EXPORT_SYMBOL(dvb_generic_ioctl);
@@ -421,8 +417,10 @@ int dvb_usercopy(struct file *file,
}
/* call driver */
+ mutex_lock(&dvbdev_mutex);
if ((err = func(file, cmd, parg)) == -ENOIOCTLCMD)
err = -EINVAL;
+ mutex_unlock(&dvbdev_mutex);
if (err < 0)
goto out;
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index e5f91f16ffa4..3d48ba019342 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -1,6 +1,6 @@
config DVB_USB
tristate "Support for various USB DVB devices"
- depends on DVB_CORE && USB && I2C && INPUT
+ depends on DVB_CORE && USB && I2C && RC_CORE
help
By enabling this you will be able to choose the various supported
USB1.1 and USB2.0 DVB devices.
@@ -76,6 +76,7 @@ config DVB_USB_DIB0700
select DVB_S5H1411 if !DVB_FE_CUSTOMISE
select DVB_LGDT3305 if !DVB_FE_CUSTOMISE
select DVB_TUNER_DIB0070 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_DIB0090 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_MT2060 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MT2266 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_XC2028 if !MEDIA_TUNER_CUSTOMISE
@@ -134,6 +135,7 @@ config DVB_USB_M920X
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_QT1010 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_SIMPLE if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the MSI Mega Sky 580 USB2.0 DVB-T receiver.
Currently, only devices with a product id of
@@ -264,7 +266,7 @@ config DVB_USB_DW2102
select DVB_STB6000 if !DVB_FE_CUSTOMISE
select DVB_CX24116 if !DVB_FE_CUSTOMISE
select DVB_SI21XX if !DVB_FE_CUSTOMISE
- select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_MT312 if !DVB_FE_CUSTOMISE
select DVB_ZL10039 if !DVB_FE_CUSTOMISE
select DVB_DS3000 if !DVB_FE_CUSTOMISE
@@ -312,6 +314,8 @@ config DVB_USB_AF9015
select MEDIA_TUNER_TDA18271 if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
select MEDIA_TUNER_MC44S803 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_TDA18218 if !MEDIA_TUNER_CUSTOMISE
+ select MEDIA_TUNER_MXL5007T if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Afatech AF9015 based DVB-T USB2.0 receiver
@@ -344,3 +348,13 @@ config DVB_USB_AZ6027
select DVB_STB6100 if !DVB_FE_CUSTOMISE
help
Say Y here to support the AZ6027 device
+
+config DVB_USB_LME2510
+ tristate "LME DM04/QQBOX DVB-S USB2.0 support"
+ depends on DVB_USB
+ select DVB_TDA10086 if !DVB_FE_CUSTOMISE
+ select DVB_TDA826X if !DVB_FE_CUSTOMISE
+ select DVB_STV0288 if !DVB_FE_CUSTOMISE
+ select DVB_IX2505V if !DVB_FE_CUSTOMISE
+ help
+ Say Y here to support the LME DM04/QQBOX DVB-S USB2.0 .
diff --git a/drivers/media/dvb/dvb-usb/Makefile b/drivers/media/dvb/dvb-usb/Makefile
index 1a192453b0e7..5b1d12f2d591 100644
--- a/drivers/media/dvb/dvb-usb/Makefile
+++ b/drivers/media/dvb/dvb-usb/Makefile
@@ -88,6 +88,9 @@ obj-$(CONFIG_DVB_USB_EC168) += dvb-usb-ec168.o
dvb-usb-az6027-objs = az6027.o
obj-$(CONFIG_DVB_USB_AZ6027) += dvb-usb-az6027.o
+dvb-usb-lmedm04-objs = lmedm04.o
+obj-$(CONFIG_DVB_USB_LME2510) += dvb-usb-lmedm04.o
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/drivers/media/dvb/dvb-usb/a800.c b/drivers/media/dvb/dvb-usb/a800.c
index b6cbb1dfc5f1..53b93a4b6f8a 100644
--- a/drivers/media/dvb/dvb-usb/a800.c
+++ b/drivers/media/dvb/dvb-usb/a800.c
@@ -37,7 +37,7 @@ static int a800_identify_state(struct usb_device *udev, struct dvb_usb_device_pr
return 0;
}
-static struct dvb_usb_rc_key ir_codes_a800_table[] = {
+static struct rc_map_table rc_map_a800_table[] = {
{ 0x0201, KEY_PROG1 }, /* SOURCE */
{ 0x0200, KEY_POWER }, /* POWER */
{ 0x0205, KEY_1 }, /* 1 */
@@ -146,10 +146,12 @@ static struct dvb_usb_device_properties a800_properties = {
.power_ctrl = a800_power_ctrl,
.identify_state = a800_identify_state,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_a800_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_a800_table),
- .rc_query = a800_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_map_table = rc_map_a800_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_a800_table),
+ .rc_query = a800_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/af9005-remote.c b/drivers/media/dvb/dvb-usb/af9005-remote.c
index b41fa873b04d..c3bc64ed405c 100644
--- a/drivers/media/dvb/dvb-usb/af9005-remote.c
+++ b/drivers/media/dvb/dvb-usb/af9005-remote.c
@@ -33,7 +33,7 @@ MODULE_PARM_DESC(debug,
#define deb_decode(args...) dprintk(dvb_usb_af9005_remote_debug,0x01,args)
-struct dvb_usb_rc_key ir_codes_af9005_table[] = {
+struct rc_map_table rc_map_af9005_table[] = {
{0x01b7, KEY_POWER},
{0x01a7, KEY_VOLUMEUP},
@@ -74,7 +74,7 @@ struct dvb_usb_rc_key ir_codes_af9005_table[] = {
{0x00d5, KEY_GOTO}, /* marked jump on the remote */
};
-int ir_codes_af9005_table_size = ARRAY_SIZE(ir_codes_af9005_table);
+int rc_map_af9005_table_size = ARRAY_SIZE(rc_map_af9005_table);
static int repeatable_keys[] = {
KEY_VOLUMEUP,
@@ -130,10 +130,10 @@ int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
deb_decode("code != inverted code\n");
return 0;
}
- for (i = 0; i < ir_codes_af9005_table_size; i++) {
- if (rc5_custom(&ir_codes_af9005_table[i]) == cust
- && rc5_data(&ir_codes_af9005_table[i]) == dat) {
- *event = ir_codes_af9005_table[i].event;
+ for (i = 0; i < rc_map_af9005_table_size; i++) {
+ if (rc5_custom(&rc_map_af9005_table[i]) == cust
+ && rc5_data(&rc_map_af9005_table[i]) == dat) {
+ *event = rc_map_af9005_table[i].keycode;
*state = REMOTE_KEY_PRESSED;
deb_decode
("key pressed, event %x\n", *event);
@@ -146,8 +146,8 @@ int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len, u32 * event,
return 0;
}
-EXPORT_SYMBOL(ir_codes_af9005_table);
-EXPORT_SYMBOL(ir_codes_af9005_table_size);
+EXPORT_SYMBOL(rc_map_af9005_table);
+EXPORT_SYMBOL(rc_map_af9005_table_size);
EXPORT_SYMBOL(af9005_rc_decode);
MODULE_AUTHOR("Luca Olivetti <luca@ventoso.org>");
diff --git a/drivers/media/dvb/dvb-usb/af9005.c b/drivers/media/dvb/dvb-usb/af9005.c
index cfd6107d5349..51f6439dcfd5 100644
--- a/drivers/media/dvb/dvb-usb/af9005.c
+++ b/drivers/media/dvb/dvb-usb/af9005.c
@@ -54,50 +54,6 @@ struct af9005_device_state {
int led_state;
};
-static int af9005_usb_generic_rw(struct dvb_usb_device *d, u8 *wbuf, u16 wlen,
- u8 *rbuf, u16 rlen, int delay_ms)
-{
- int actlen, ret = -ENOMEM;
-
- if (wbuf == NULL || wlen == 0)
- return -EINVAL;
-
- if ((ret = mutex_lock_interruptible(&d->usb_mutex)))
- return ret;
-
- deb_xfer(">>> ");
- debug_dump(wbuf, wlen, deb_xfer);
-
- ret = usb_bulk_msg(d->udev, usb_sndbulkpipe(d->udev,
- 2), wbuf, wlen,
- &actlen, 2000);
-
- if (ret)
- err("bulk message failed: %d (%d/%d)", ret, wlen, actlen);
- else
- ret = actlen != wlen ? -1 : 0;
-
- /* an answer is expected, and no error before */
- if (!ret && rbuf && rlen) {
- if (delay_ms)
- msleep(delay_ms);
-
- ret = usb_bulk_msg(d->udev, usb_rcvbulkpipe(d->udev,
- 0x01), rbuf,
- rlen, &actlen, 2000);
-
- if (ret)
- err("recv bulk message failed: %d", ret);
- else {
- deb_xfer("<<< ");
- debug_dump(rbuf, actlen, deb_xfer);
- }
- }
-
- mutex_unlock(&d->usb_mutex);
- return ret;
-}
-
static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
int readwrite, int type, u8 * values, int len)
{
@@ -146,7 +102,7 @@ static int af9005_generic_read_write(struct dvb_usb_device *d, u16 reg,
obuf[8] = values[0];
obuf[7] = command;
- ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
+ ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 17, 0);
if (ret)
return ret;
@@ -534,7 +490,7 @@ int af9005_send_command(struct dvb_usb_device *d, u8 command, u8 * wbuf,
buf[6] = wlen;
for (i = 0; i < wlen; i++)
buf[7 + i] = wbuf[i];
- ret = af9005_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
+ ret = dvb_usb_generic_rw(d, buf, wlen + 7, ibuf, rlen + 7, 0);
if (ret)
return ret;
if (ibuf[2] != 0x27) {
@@ -581,7 +537,7 @@ int af9005_read_eeprom(struct dvb_usb_device *d, u8 address, u8 * values,
obuf[6] = len;
obuf[7] = address;
- ret = af9005_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
+ ret = dvb_usb_generic_rw(d, obuf, 16, ibuf, 14, 0);
if (ret)
return ret;
if (ibuf[2] != 0x2b) {
@@ -882,7 +838,7 @@ static int af9005_rc_query(struct dvb_usb_device *d, u32 * event, int *state)
obuf[2] = 0x40; /* read remote */
obuf[3] = 1; /* rest of packet length */
obuf[4] = st->sequence++; /* sequence number */
- ret = af9005_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
+ ret = dvb_usb_generic_rw(d, obuf, 5, ibuf, 256, 0);
if (ret) {
err("rc query failed");
return ret;
@@ -1069,10 +1025,15 @@ static struct dvb_usb_device_properties af9005_properties = {
.i2c_algo = &af9005_i2c_algo,
- .rc_interval = 200,
- .rc_key_map = NULL,
- .rc_key_map_size = 0,
- .rc_query = af9005_rc_query,
+ .rc.legacy = {
+ .rc_interval = 200,
+ .rc_map_table = NULL,
+ .rc_map_size = 0,
+ .rc_query = af9005_rc_query,
+ },
+
+ .generic_bulk_ctrl_endpoint = 2,
+ .generic_bulk_ctrl_endpoint_response = 1,
.num_device_descs = 3,
.devices = {
@@ -1109,14 +1070,14 @@ static int __init af9005_usb_module_init(void)
return result;
}
rc_decode = symbol_request(af9005_rc_decode);
- rc_keys = symbol_request(ir_codes_af9005_table);
- rc_keys_size = symbol_request(ir_codes_af9005_table_size);
+ rc_keys = symbol_request(rc_map_af9005_table);
+ rc_keys_size = symbol_request(rc_map_af9005_table_size);
if (rc_decode == NULL || rc_keys == NULL || rc_keys_size == NULL) {
err("af9005_rc_decode function not found, disabling remote");
- af9005_properties.rc_query = NULL;
+ af9005_properties.rc.legacy.rc_query = NULL;
} else {
- af9005_properties.rc_key_map = rc_keys;
- af9005_properties.rc_key_map_size = *rc_keys_size;
+ af9005_properties.rc.legacy.rc_map_table = rc_keys;
+ af9005_properties.rc.legacy.rc_map_size = *rc_keys_size;
}
return 0;
@@ -1128,9 +1089,9 @@ static void __exit af9005_usb_module_exit(void)
if (rc_decode != NULL)
symbol_put(af9005_rc_decode);
if (rc_keys != NULL)
- symbol_put(ir_codes_af9005_table);
+ symbol_put(rc_map_af9005_table);
if (rc_keys_size != NULL)
- symbol_put(ir_codes_af9005_table_size);
+ symbol_put(rc_map_af9005_table_size);
/* deregister this driver from the USB subsystem */
usb_deregister(&af9005_usb_driver);
}
diff --git a/drivers/media/dvb/dvb-usb/af9005.h b/drivers/media/dvb/dvb-usb/af9005.h
index 088e7083a39b..c71c77bd7f4b 100644
--- a/drivers/media/dvb/dvb-usb/af9005.h
+++ b/drivers/media/dvb/dvb-usb/af9005.h
@@ -3490,7 +3490,7 @@ extern u8 regmask[8];
/* remote control decoder */
extern int af9005_rc_decode(struct dvb_usb_device *d, u8 * data, int len,
u32 * event, int *state);
-extern struct dvb_usb_rc_key ir_codes_af9005_table[];
-extern int ir_codes_af9005_table_size;
+extern struct rc_map_table rc_map_af9005_table[];
+extern int rc_map_af9005_table_size;
#endif
diff --git a/drivers/media/dvb/dvb-usb/af9015.c b/drivers/media/dvb/dvb-usb/af9015.c
index 66c7c3ea7990..8671ca362c81 100644
--- a/drivers/media/dvb/dvb-usb/af9015.c
+++ b/drivers/media/dvb/dvb-usb/af9015.c
@@ -31,6 +31,8 @@
#include "tda18271.h"
#include "mxl5005s.h"
#include "mc44s803.h"
+#include "tda18218.h"
+#include "mxl5007t.h"
static int dvb_usb_af9015_debug;
module_param_named(debug, dvb_usb_af9015_debug, int, 0644);
@@ -205,12 +207,18 @@ static int af9015_write_reg(struct dvb_usb_device *d, u16 addr, u8 val)
return af9015_write_regs(d, addr, &val, 1);
}
-static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+static int af9015_read_regs(struct dvb_usb_device *d, u16 addr, u8 *val, u8 len)
{
- struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, 1, val};
+ struct req_t req = {READ_MEMORY, AF9015_I2C_DEMOD, addr, 0, 0, len,
+ val};
return af9015_ctrl_msg(d, &req);
}
+static int af9015_read_reg(struct dvb_usb_device *d, u16 addr, u8 *val)
+{
+ return af9015_read_regs(d, addr, val, 1);
+}
+
static int af9015_write_reg_i2c(struct dvb_usb_device *d, u8 addr, u16 reg,
u8 val)
{
@@ -241,7 +249,7 @@ static int af9015_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
struct dvb_usb_device *d = i2c_get_adapdata(adap);
int ret = 0, i = 0;
u16 addr;
- u8 mbox, addr_len;
+ u8 uninitialized_var(mbox), addr_len;
struct req_t req;
/* TODO: implement bus lock
@@ -280,7 +288,7 @@ Due to that the only way to select correct tuner is use demodulator I2C-gate.
} else {
addr = msg[i].buf[0];
addr_len = 1;
- mbox = 0;
+ /* mbox is don't care in that case */
}
if (num > i + 1 && (msg[i+1].flags & I2C_M_RD)) {
@@ -494,7 +502,8 @@ static int af9015_copy_firmware(struct dvb_usb_device *d)
/* wait 2nd demodulator ready */
msleep(100);
- ret = af9015_read_reg_i2c(d, 0x3a, 0x98be, &val);
+ ret = af9015_read_reg_i2c(d,
+ af9015_af9013_config[1].demod_address, 0x98be, &val);
if (ret)
goto error;
else
@@ -597,37 +606,6 @@ free:
return ret;
}
-static int af9015_download_ir_table(struct dvb_usb_device *d)
-{
- int i, packets = 0, ret;
- u16 addr = 0x9a56; /* ir-table start address */
- struct req_t req = {WRITE_MEMORY, 0, 0, 0, 0, 1, NULL};
- u8 *data = NULL;
- deb_info("%s:\n", __func__);
-
- data = af9015_config.ir_table;
- packets = af9015_config.ir_table_size;
-
- /* no remote */
- if (!packets)
- goto exit;
-
- /* load remote ir-table */
- for (i = 0; i < packets; i++) {
- req.addr = addr + i;
- req.data = &data[i];
- ret = af9015_ctrl_msg(d, &req);
- if (ret) {
- err("ir-table download failed at packet %d with " \
- "code %d", i, ret);
- return ret;
- }
- }
-
-exit:
- return 0;
-}
-
static int af9015_init(struct dvb_usb_device *d)
{
int ret;
@@ -637,10 +615,6 @@ static int af9015_init(struct dvb_usb_device *d)
if (ret)
goto error;
- ret = af9015_download_ir_table(d);
- if (ret)
- goto error;
-
error:
return ret;
}
@@ -733,125 +707,102 @@ error:
return ret;
}
-struct af9015_setup {
+struct af9015_rc_setup {
unsigned int id;
- struct dvb_usb_rc_key *rc_key_map;
- unsigned int rc_key_map_size;
- u8 *ir_table;
- unsigned int ir_table_size;
+ char *rc_codes;
};
-static const struct af9015_setup *af9015_setup_match(unsigned int id,
- const struct af9015_setup *table)
+static char *af9015_rc_setup_match(unsigned int id,
+ const struct af9015_rc_setup *table)
{
- for (; table->rc_key_map; table++)
+ for (; table->rc_codes; table++)
if (table->id == id)
- return table;
+ return table->rc_codes;
return NULL;
}
-static const struct af9015_setup af9015_setup_modparam[] = {
- { AF9015_REMOTE_A_LINK_DTU_M,
- ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
- af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
- { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
- af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
- { AF9015_REMOTE_MYGICTV_U718,
- ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
- af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
- { AF9015_REMOTE_DIGITTRADE_DVB_T,
- ir_codes_af9015_table_digittrade, ARRAY_SIZE(ir_codes_af9015_table_digittrade),
- af9015_ir_table_digittrade, ARRAY_SIZE(af9015_ir_table_digittrade) },
- { AF9015_REMOTE_AVERMEDIA_KS,
- ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
- af9015_ir_table_avermedia_ks, ARRAY_SIZE(af9015_ir_table_avermedia_ks) },
+static const struct af9015_rc_setup af9015_rc_setup_modparam[] = {
+ { AF9015_REMOTE_A_LINK_DTU_M, RC_MAP_ALINK_DTU_M },
+ { AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3, RC_MAP_MSI_DIGIVOX_II },
+ { AF9015_REMOTE_MYGICTV_U718, RC_MAP_TOTAL_MEDIA_IN_HAND },
+ { AF9015_REMOTE_DIGITTRADE_DVB_T, RC_MAP_DIGITTRADE },
+ { AF9015_REMOTE_AVERMEDIA_KS, RC_MAP_AVERMEDIA_RM_KS },
{ }
};
-/* don't add new entries here anymore, use hashes instead */
-static const struct af9015_setup af9015_setup_usbids[] = {
- { USB_VID_LEADTEK,
- ir_codes_af9015_table_leadtek, ARRAY_SIZE(ir_codes_af9015_table_leadtek),
- af9015_ir_table_leadtek, ARRAY_SIZE(af9015_ir_table_leadtek) },
- { USB_VID_VISIONPLUS,
- ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
- af9015_ir_table_twinhan, ARRAY_SIZE(af9015_ir_table_twinhan) },
- { USB_VID_KWORLD_2, /* TODO: use correct rc keys */
- ir_codes_af9015_table_twinhan, ARRAY_SIZE(ir_codes_af9015_table_twinhan),
- af9015_ir_table_kworld, ARRAY_SIZE(af9015_ir_table_kworld) },
- { USB_VID_AVERMEDIA,
- ir_codes_af9015_table_avermedia, ARRAY_SIZE(ir_codes_af9015_table_avermedia),
- af9015_ir_table_avermedia, ARRAY_SIZE(af9015_ir_table_avermedia) },
- { USB_VID_MSI_2,
- ir_codes_af9015_table_msi_digivox_iii, ARRAY_SIZE(ir_codes_af9015_table_msi_digivox_iii),
- af9015_ir_table_msi_digivox_iii, ARRAY_SIZE(af9015_ir_table_msi_digivox_iii) },
+static const struct af9015_rc_setup af9015_rc_setup_hashes[] = {
+ { 0xb8feb708, RC_MAP_MSI_DIGIVOX_II },
+ { 0xa3703d00, RC_MAP_ALINK_DTU_M },
+ { 0x9b7dc64e, RC_MAP_TOTAL_MEDIA_IN_HAND }, /* MYGICTV U718 */
{ }
};
-static const struct af9015_setup af9015_setup_hashes[] = {
- { 0xb8feb708,
- ir_codes_af9015_table_msi, ARRAY_SIZE(ir_codes_af9015_table_msi),
- af9015_ir_table_msi, ARRAY_SIZE(af9015_ir_table_msi) },
- { 0xa3703d00,
- ir_codes_af9015_table_a_link, ARRAY_SIZE(ir_codes_af9015_table_a_link),
- af9015_ir_table_a_link, ARRAY_SIZE(af9015_ir_table_a_link) },
- { 0x9b7dc64e,
- ir_codes_af9015_table_mygictv, ARRAY_SIZE(ir_codes_af9015_table_mygictv),
- af9015_ir_table_mygictv, ARRAY_SIZE(af9015_ir_table_mygictv) },
+static const struct af9015_rc_setup af9015_rc_setup_usbids[] = {
+ { (USB_VID_TERRATEC << 16) + USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC,
+ RC_MAP_TERRATEC_SLIM },
+ { (USB_VID_VISIONPLUS << 16) + USB_PID_AZUREWAVE_AD_TU700,
+ RC_MAP_AZUREWAVE_AD_TU700 },
+ { (USB_VID_VISIONPLUS << 16) + USB_PID_TINYTWIN,
+ RC_MAP_AZUREWAVE_AD_TU700 },
+ { (USB_VID_MSI_2 << 16) + USB_PID_MSI_DIGI_VOX_MINI_III,
+ RC_MAP_MSI_DIGIVOX_III },
+ { (USB_VID_LEADTEK << 16) + USB_PID_WINFAST_DTV_DONGLE_GOLD,
+ RC_MAP_LEADTEK_Y04G0051 },
+ { (USB_VID_AVERMEDIA << 16) + USB_PID_AVERMEDIA_VOLAR_X,
+ RC_MAP_AVERMEDIA_M135A },
+ { (USB_VID_AFATECH << 16) + USB_PID_TREKSTOR_DVBT,
+ RC_MAP_TREKSTOR },
+ { (USB_VID_KWORLD_2 << 16) + USB_PID_TINYTWIN_2,
+ RC_MAP_DIGITALNOW_TINYTWIN },
+ { (USB_VID_GTEK << 16) + USB_PID_TINYTWIN_3,
+ RC_MAP_DIGITALNOW_TINYTWIN },
{ }
};
static void af9015_set_remote_config(struct usb_device *udev,
struct dvb_usb_device_properties *props)
{
- const struct af9015_setup *table = NULL;
-
- if (dvb_usb_af9015_remote) {
- /* load remote defined as module param */
- table = af9015_setup_match(dvb_usb_af9015_remote,
- af9015_setup_modparam);
- } else {
- u16 vendor = le16_to_cpu(udev->descriptor.idVendor);
-
- table = af9015_setup_match(af9015_config.eeprom_sum,
- af9015_setup_hashes);
-
- if (!table && vendor == USB_VID_AFATECH) {
- /* Check USB manufacturer and product strings and try
- to determine correct remote in case of chip vendor
- reference IDs are used.
- DO NOT ADD ANYTHING NEW HERE. Use hashes instead.
- */
- char manufacturer[10];
- memset(manufacturer, 0, sizeof(manufacturer));
- usb_string(udev, udev->descriptor.iManufacturer,
- manufacturer, sizeof(manufacturer));
- if (!strcmp("MSI", manufacturer)) {
- /* iManufacturer 1 MSI
- iProduct 2 MSI K-VOX */
- table = af9015_setup_match(
- AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
- af9015_setup_modparam);
- } else if (udev->descriptor.idProduct ==
- cpu_to_le16(USB_PID_TREKSTOR_DVBT)) {
- table = &(const struct af9015_setup){ 0,
- ir_codes_af9015_table_trekstor,
- ARRAY_SIZE(ir_codes_af9015_table_trekstor),
- af9015_ir_table_trekstor,
- ARRAY_SIZE(af9015_ir_table_trekstor)
- };
- }
- } else if (!table)
- table = af9015_setup_match(vendor, af9015_setup_usbids);
+ u16 vid = le16_to_cpu(udev->descriptor.idVendor);
+ u16 pid = le16_to_cpu(udev->descriptor.idProduct);
+
+ /* try to load remote based module param */
+ props->rc.core.rc_codes = af9015_rc_setup_match(
+ dvb_usb_af9015_remote, af9015_rc_setup_modparam);
+
+ /* try to load remote based eeprom hash */
+ if (!props->rc.core.rc_codes)
+ props->rc.core.rc_codes = af9015_rc_setup_match(
+ af9015_config.eeprom_sum, af9015_rc_setup_hashes);
+
+ /* try to load remote based USB ID */
+ if (!props->rc.core.rc_codes)
+ props->rc.core.rc_codes = af9015_rc_setup_match(
+ (vid << 16) + pid, af9015_rc_setup_usbids);
+
+ /* try to load remote based USB iManufacturer string */
+ if (!props->rc.core.rc_codes && vid == USB_VID_AFATECH) {
+ /* Check USB manufacturer and product strings and try
+ to determine correct remote in case of chip vendor
+ reference IDs are used.
+ DO NOT ADD ANYTHING NEW HERE. Use hashes instead. */
+ char manufacturer[10];
+ memset(manufacturer, 0, sizeof(manufacturer));
+ usb_string(udev, udev->descriptor.iManufacturer,
+ manufacturer, sizeof(manufacturer));
+ if (!strcmp("MSI", manufacturer)) {
+ /* iManufacturer 1 MSI
+ iProduct 2 MSI K-VOX */
+ props->rc.core.rc_codes = af9015_rc_setup_match(
+ AF9015_REMOTE_MSI_DIGIVOX_MINI_II_V3,
+ af9015_rc_setup_modparam);
+ }
}
- if (table) {
- props->rc_key_map = table->rc_key_map;
- props->rc_key_map_size = table->rc_key_map_size;
- af9015_config.ir_table = table->ir_table;
- af9015_config.ir_table_size = table->ir_table_size;
- }
+ /* finally load "empty" just for leaving IR receiver enabled */
+ if (!props->rc.core.rc_codes)
+ props->rc.core.rc_codes = RC_MAP_EMPTY;
+
+ return;
}
static int af9015_read_config(struct usb_device *udev)
@@ -877,10 +828,9 @@ static int af9015_read_config(struct usb_device *udev)
deb_info("%s: IR mode:%d\n", __func__, val);
for (i = 0; i < af9015_properties_count; i++) {
- if (val == AF9015_IR_MODE_DISABLED) {
- af9015_properties[i].rc_key_map = NULL;
- af9015_properties[i].rc_key_map_size = 0;
- } else
+ if (val == AF9015_IR_MODE_DISABLED)
+ af9015_properties[i].rc.core.rc_codes = NULL;
+ else
af9015_set_remote_config(udev, &af9015_properties[i]);
}
@@ -992,20 +942,19 @@ static int af9015_read_config(struct usb_device *udev)
case AF9013_TUNER_MT2060_2:
case AF9013_TUNER_TDA18271:
case AF9013_TUNER_QT1010A:
+ case AF9013_TUNER_TDA18218:
af9015_af9013_config[i].rf_spec_inv = 1;
break;
case AF9013_TUNER_MXL5003D:
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
+ case AF9013_TUNER_MXL5007T:
af9015_af9013_config[i].rf_spec_inv = 0;
break;
case AF9013_TUNER_MC44S803:
af9015_af9013_config[i].gpio[1] = AF9013_GPIO_LO;
af9015_af9013_config[i].rf_spec_inv = 1;
break;
- case AF9013_TUNER_TDA18218:
- warn("tuner NXP TDA18218 not supported yet");
- return -ENODEV;
default:
warn("tuner id:%d not supported, please report!", val);
return -ENODEV;
@@ -1020,9 +969,13 @@ error:
err("eeprom read failed:%d", ret);
/* AverMedia AVerTV Volar Black HD (A850) device have bad EEPROM
- content :-( Override some wrong values here. */
+ content :-( Override some wrong values here. Ditto for the
+ AVerTV Red HD+ (A850T) device. */
if (le16_to_cpu(udev->descriptor.idVendor) == USB_VID_AVERMEDIA &&
- le16_to_cpu(udev->descriptor.idProduct) == USB_PID_AVERMEDIA_A850) {
+ ((le16_to_cpu(udev->descriptor.idProduct) ==
+ USB_PID_AVERMEDIA_A850) ||
+ (le16_to_cpu(udev->descriptor.idProduct) ==
+ USB_PID_AVERMEDIA_A850T))) {
deb_info("%s: AverMedia A850: overriding config\n", __func__);
/* disable dual mode */
af9015_config.dual_mode = 0;
@@ -1059,36 +1012,53 @@ static int af9015_identify_state(struct usb_device *udev,
return ret;
}
-static int af9015_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int af9015_rc_query(struct dvb_usb_device *d)
{
- u8 buf[8];
- struct req_t req = {GET_IR_CODE, 0, 0, 0, 0, sizeof(buf), buf};
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
- int i, ret;
-
- memset(buf, 0, sizeof(buf));
+ struct af9015_state *priv = d->priv;
+ int ret;
+ u8 buf[16];
- ret = af9015_ctrl_msg(d, &req);
+ /* read registers needed to detect remote controller code */
+ ret = af9015_read_regs(d, 0x98d9, buf, sizeof(buf));
if (ret)
- return ret;
+ goto error;
- *event = 0;
- *state = REMOTE_NO_KEY_PRESSED;
+ if (buf[14] || buf[15]) {
+ deb_rc("%s: key pressed %02x %02x %02x %02x\n", __func__,
+ buf[12], buf[13], buf[14], buf[15]);
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (!buf[1] && rc5_custom(&keymap[i]) == buf[0] &&
- rc5_data(&keymap[i]) == buf[2]) {
- *event = keymap[i].event;
- *state = REMOTE_KEY_PRESSED;
- break;
+ /* clean IR code from mem */
+ ret = af9015_write_regs(d, 0x98e5, "\x00\x00\x00\x00", 4);
+ if (ret)
+ goto error;
+
+ if (buf[14] == (u8) ~buf[15]) {
+ if (buf[12] == (u8) ~buf[13]) {
+ /* NEC */
+ priv->rc_keycode = buf[12] << 8 | buf[14];
+ } else {
+ /* NEC extended*/
+ priv->rc_keycode = buf[12] << 16 |
+ buf[13] << 8 | buf[14];
+ }
+ rc_keydown(d->rc_dev, priv->rc_keycode, 0);
+ } else {
+ priv->rc_keycode = 0; /* clear just for sure */
}
+ } else if (priv->rc_repeat != buf[6] || buf[0]) {
+ deb_rc("%s: key repeated\n", __func__);
+ rc_keydown(d->rc_dev, priv->rc_keycode, 0);
+ } else {
+ deb_rc("%s: no key press\n", __func__);
}
- if (!buf[1])
- deb_rc("%s: %02x %02x %02x %02x %02x %02x %02x %02x\n",
- __func__, buf[0], buf[1], buf[2], buf[3], buf[4],
- buf[5], buf[6], buf[7]);
- return 0;
+ priv->rc_repeat = buf[6];
+
+error:
+ if (ret)
+ err("%s: failed:%d", __func__, ret);
+
+ return ret;
}
/* init 2nd I2C adapter */
@@ -1100,11 +1070,6 @@ static int af9015_i2c_init(struct dvb_usb_device *d)
strncpy(state->i2c_adap.name, d->desc->name,
sizeof(state->i2c_adap.name));
-#ifdef I2C_ADAP_CLASS_TV_DIGITAL
- state->i2c_adap.class = I2C_ADAP_CLASS_TV_DIGITAL,
-#else
- state->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
-#endif
state->i2c_adap.algo = d->props.i2c_algo;
state->i2c_adap.algo_data = NULL;
state->i2c_adap.dev.parent = &d->udev->dev;
@@ -1166,7 +1131,7 @@ static struct qt1010_config af9015_qt1010_config = {
static struct tda18271_config af9015_tda18271_config = {
.gate = TDA18271_GATE_DIGITAL,
- .small_i2c = 1,
+ .small_i2c = TDA18271_16_BYTE_CHUNK_INIT,
};
static struct mxl5005s_config af9015_mxl5003_config = {
@@ -1208,12 +1173,22 @@ static struct mc44s803_config af9015_mc44s803_config = {
.dig_out = 1,
};
+static struct tda18218_config af9015_tda18218_config = {
+ .i2c_address = 0xc0,
+ .i2c_wr_max = 21, /* max wr bytes AF9015 I2C adap can handle at once */
+};
+
+static struct mxl5007t_config af9015_mxl5007t_config = {
+ .xtal_freq_hz = MxL_XTAL_24_MHZ,
+ .if_freq_hz = MxL_IF_4_57_MHZ,
+};
+
static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
{
struct af9015_state *state = adap->dev->priv;
struct i2c_adapter *i2c_adap;
int ret;
- deb_info("%s: \n", __func__);
+ deb_info("%s:\n", __func__);
/* select I2C adapter */
if (adap->id == 0)
@@ -1238,6 +1213,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
ret = dvb_attach(tda18271_attach, adap->fe, 0xc0, i2c_adap,
&af9015_tda18271_config) == NULL ? -ENODEV : 0;
break;
+ case AF9013_TUNER_TDA18218:
+ ret = dvb_attach(tda18218_attach, adap->fe, i2c_adap,
+ &af9015_tda18218_config) == NULL ? -ENODEV : 0;
+ break;
case AF9013_TUNER_MXL5003D:
ret = dvb_attach(mxl5005s_attach, adap->fe, i2c_adap,
&af9015_mxl5003_config) == NULL ? -ENODEV : 0;
@@ -1255,6 +1234,10 @@ static int af9015_tuner_attach(struct dvb_usb_adapter *adap)
ret = dvb_attach(mc44s803_attach, adap->fe, i2c_adap,
&af9015_mc44s803_config) == NULL ? -ENODEV : 0;
break;
+ case AF9013_TUNER_MXL5007T:
+ ret = dvb_attach(mxl5007t_attach, adap->fe, i2c_adap,
+ 0xc0, &af9015_mxl5007t_config) == NULL ? -ENODEV : 0;
+ break;
case AF9013_TUNER_UNKNOWN:
default:
ret = -ENODEV;
@@ -1299,10 +1282,17 @@ static struct usb_device_id af9015_usb_table[] = {
{USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV2000DS)},
/* 30 */{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_UB383_T)},
{USB_DEVICE(USB_VID_KWORLD_2, USB_PID_KWORLD_395U_4)},
+ {USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A815M)},
+ {USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_STICK_RC)},
+ {USB_DEVICE(USB_VID_TERRATEC,
+ USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC)},
+/* 35 */{USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_A850T)},
+ {USB_DEVICE(USB_VID_GTEK, USB_PID_TINYTWIN_3)},
{0},
};
MODULE_DEVICE_TABLE(usb, af9015_usb_table);
+#define AF9015_RC_INTERVAL 500
static struct dvb_usb_device_properties af9015_properties[] = {
{
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -1353,12 +1343,17 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc.core = {
+ .protocol = RC_TYPE_NEC,
+ .module_name = "af9015",
+ .rc_query = af9015_rc_query,
+ .rc_interval = AF9015_RC_INTERVAL,
+ .allowed_protos = RC_TYPE_NEC,
+ },
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 9, /* max 9 */
+ .num_device_descs = 12, /* check max from dvb-usb.h */
.devices = {
{
.name = "Afatech AF9015 DVB-T USB2.0 stick",
@@ -1386,7 +1381,8 @@ static struct dvb_usb_device_properties af9015_properties[] = {
{
.name = "DigitalNow TinyTwin DVB-T Receiver",
.cold_ids = {&af9015_usb_table[5],
- &af9015_usb_table[28], NULL},
+ &af9015_usb_table[28],
+ &af9015_usb_table[36], NULL},
.warm_ids = {NULL},
},
{
@@ -1410,6 +1406,21 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {&af9015_usb_table[9], NULL},
.warm_ids = {NULL},
},
+ {
+ .name = "TerraTec Cinergy T Stick RC",
+ .cold_ids = {&af9015_usb_table[33], NULL},
+ .warm_ids = {NULL},
+ },
+ {
+ .name = "TerraTec Cinergy T Stick Dual RC",
+ .cold_ids = {&af9015_usb_table[34], NULL},
+ .warm_ids = {NULL},
+ },
+ {
+ .name = "AverMedia AVerTV Red HD+ (A850T)",
+ .cold_ids = {&af9015_usb_table[35], NULL},
+ .warm_ids = {NULL},
+ },
}
}, {
.caps = DVB_USB_IS_AN_I2C_ADAPTER,
@@ -1460,12 +1471,17 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc.core = {
+ .protocol = RC_TYPE_NEC,
+ .module_name = "af9015",
+ .rc_query = af9015_rc_query,
+ .rc_interval = AF9015_RC_INTERVAL,
+ .allowed_protos = RC_TYPE_NEC,
+ },
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 9, /* max 9 */
+ .num_device_descs = 9, /* check max from dvb-usb.h */
.devices = {
{
.name = "Xtensions XD-380",
@@ -1567,12 +1583,17 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.identify_state = af9015_identify_state,
- .rc_query = af9015_rc_query,
- .rc_interval = 150,
+ .rc.core = {
+ .protocol = RC_TYPE_NEC,
+ .module_name = "af9015",
+ .rc_query = af9015_rc_query,
+ .rc_interval = AF9015_RC_INTERVAL,
+ .allowed_protos = RC_TYPE_NEC,
+ },
.i2c_algo = &af9015_i2c_algo,
- .num_device_descs = 8, /* max 9 */
+ .num_device_descs = 9, /* check max from dvb-usb.h */
.devices = {
{
.name = "AverMedia AVerTV Volar GPS 805 (A805)",
@@ -1617,6 +1638,11 @@ static struct dvb_usb_device_properties af9015_properties[] = {
.cold_ids = {&af9015_usb_table[30], NULL},
.warm_ids = {NULL},
},
+ {
+ .name = "AverMedia AVerTV Volar M (A815Mac)",
+ .cold_ids = {&af9015_usb_table[32], NULL},
+ .warm_ids = {NULL},
+ },
}
},
};
@@ -1660,7 +1686,7 @@ static int af9015_usb_probe(struct usb_interface *intf,
static void af9015_i2c_exit(struct dvb_usb_device *d)
{
struct af9015_state *state = d->priv;
- deb_info("%s: \n", __func__);
+ deb_info("%s:\n", __func__);
/* remove 2nd I2C adapter */
if (d->state & DVB_USB_STATE_I2C)
@@ -1670,7 +1696,7 @@ static void af9015_i2c_exit(struct dvb_usb_device *d)
static void af9015_usb_device_exit(struct usb_interface *intf)
{
struct dvb_usb_device *d = usb_get_intfdata(intf);
- deb_info("%s: \n", __func__);
+ deb_info("%s:\n", __func__);
/* remove 2nd I2C adapter */
if (d != NULL && d->desc != NULL)
diff --git a/drivers/media/dvb/dvb-usb/af9015.h b/drivers/media/dvb/dvb-usb/af9015.h
index 63b2a4907b7e..f20cfa6ed690 100644
--- a/drivers/media/dvb/dvb-usb/af9015.h
+++ b/drivers/media/dvb/dvb-usb/af9015.h
@@ -100,6 +100,8 @@ enum af9015_ir_mode {
struct af9015_state {
struct i2c_adapter i2c_adap; /* I2C adapter for 2nd FE */
+ u8 rc_repeat;
+ u32 rc_keycode;
};
struct af9015_config {
@@ -108,8 +110,6 @@ struct af9015_config {
u16 firmware_size;
u16 firmware_checksum;
u32 eeprom_sum;
- u8 *ir_table;
- u16 ir_table_size;
};
enum af9015_remote {
@@ -121,735 +121,4 @@ enum af9015_remote {
/* 5 */ AF9015_REMOTE_AVERMEDIA_KS,
};
-/* LeadTek - Y04G0051 */
-/* Leadtek WinFast DTV Dongle Gold */
-static struct dvb_usb_rc_key ir_codes_af9015_table_leadtek[] = {
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x0028, KEY_OK },
- { 0x004f, KEY_RIGHT },
- { 0x0050, KEY_LEFT },
- { 0x0051, KEY_DOWN },
- { 0x0052, KEY_UP },
- { 0x011a, KEY_POWER2 },
- { 0x04b4, KEY_TV },
- { 0x04b3, KEY_RED },
- { 0x04b2, KEY_GREEN },
- { 0x04b1, KEY_YELLOW },
- { 0x04b0, KEY_BLUE },
- { 0x003d, KEY_TEXT },
- { 0x0113, KEY_SLEEP },
- { 0x0010, KEY_MUTE },
- { 0x0105, KEY_ESC },
- { 0x0009, KEY_SCREEN },
- { 0x010f, KEY_MENU },
- { 0x003f, KEY_CHANNEL },
- { 0x0013, KEY_REWIND },
- { 0x0012, KEY_PLAY },
- { 0x0011, KEY_FASTFORWARD },
- { 0x0005, KEY_PREVIOUS },
- { 0x0029, KEY_STOP },
- { 0x002b, KEY_NEXT },
- { 0x0041, KEY_EPG },
- { 0x0019, KEY_VIDEO },
- { 0x0016, KEY_AUDIO },
- { 0x0037, KEY_DOT },
- { 0x002a, KEY_AGAIN },
- { 0x002c, KEY_CAMERA },
- { 0x003c, KEY_NEW },
- { 0x0115, KEY_RECORD },
- { 0x010b, KEY_TIME },
- { 0x0043, KEY_VOLUMEUP },
- { 0x0042, KEY_VOLUMEDOWN },
- { 0x004b, KEY_CHANNELUP },
- { 0x004e, KEY_CHANNELDOWN },
-};
-
-static u8 af9015_ir_table_leadtek[] = {
- 0x03, 0xfc, 0x00, 0xff, 0x1a, 0x01, 0x00, /* KEY_POWER2 */
- 0x03, 0xfc, 0x56, 0xa9, 0xb4, 0x04, 0x00, /* KEY_TV */
- 0x03, 0xfc, 0x4b, 0xb4, 0xb3, 0x04, 0x00, /* KEY_RED */
- 0x03, 0xfc, 0x4c, 0xb3, 0xb2, 0x04, 0x00, /* KEY_GREEN */
- 0x03, 0xfc, 0x4d, 0xb2, 0xb1, 0x04, 0x00, /* KEY_YELLOW */
- 0x03, 0xfc, 0x4e, 0xb1, 0xb0, 0x04, 0x00, /* KEY_BLUE */
- 0x03, 0xfc, 0x1f, 0xe0, 0x3d, 0x00, 0x00, /* KEY_TEXT */
- 0x03, 0xfc, 0x40, 0xbf, 0x13, 0x01, 0x00, /* KEY_SLEEP */
- 0x03, 0xfc, 0x14, 0xeb, 0x10, 0x00, 0x00, /* KEY_MUTE */
- 0x03, 0xfc, 0x49, 0xb6, 0x05, 0x01, 0x00, /* KEY_ESC */
- 0x03, 0xfc, 0x50, 0xaf, 0x29, 0x00, 0x00, /* KEY_STOP (1)*/
- 0x03, 0xfc, 0x0c, 0xf3, 0x52, 0x00, 0x00, /* KEY_UP */
- 0x03, 0xfc, 0x03, 0xfc, 0x09, 0x00, 0x00, /* KEY_SCREEN */
- 0x03, 0xfc, 0x08, 0xf7, 0x50, 0x00, 0x00, /* KEY_LEFT */
- 0x03, 0xfc, 0x13, 0xec, 0x28, 0x00, 0x00, /* KEY_OK (1) */
- 0x03, 0xfc, 0x04, 0xfb, 0x4f, 0x00, 0x00, /* KEY_RIGHT */
- 0x03, 0xfc, 0x4f, 0xb0, 0x0f, 0x01, 0x00, /* KEY_MENU */
- 0x03, 0xfc, 0x10, 0xef, 0x51, 0x00, 0x00, /* KEY_DOWN */
- 0x03, 0xfc, 0x51, 0xae, 0x3f, 0x00, 0x00, /* KEY_CHANNEL */
- 0x03, 0xfc, 0x42, 0xbd, 0x13, 0x00, 0x00, /* KEY_REWIND */
- 0x03, 0xfc, 0x43, 0xbc, 0x12, 0x00, 0x00, /* KEY_PLAY */
- 0x03, 0xfc, 0x44, 0xbb, 0x11, 0x00, 0x00, /* KEY_FASTFORWARD */
- 0x03, 0xfc, 0x52, 0xad, 0x19, 0x00, 0x00, /* KEY_VIDEO (1) */
- 0x03, 0xfc, 0x54, 0xab, 0x05, 0x00, 0x00, /* KEY_PREVIOUS */
- 0x03, 0xfc, 0x46, 0xb9, 0x29, 0x00, 0x00, /* KEY_STOP (2) */
- 0x03, 0xfc, 0x55, 0xaa, 0x2b, 0x00, 0x00, /* KEY_NEXT */
- 0x03, 0xfc, 0x53, 0xac, 0x41, 0x00, 0x00, /* KEY_EPG */
- 0x03, 0xfc, 0x05, 0xfa, 0x1e, 0x00, 0x00, /* KEY_1 */
- 0x03, 0xfc, 0x06, 0xf9, 0x1f, 0x00, 0x00, /* KEY_2 */
- 0x03, 0xfc, 0x07, 0xf8, 0x20, 0x00, 0x00, /* KEY_3 */
- 0x03, 0xfc, 0x1e, 0xe1, 0x19, 0x00, 0x00, /* KEY_VIDEO (2) */
- 0x03, 0xfc, 0x09, 0xf6, 0x21, 0x00, 0x00, /* KEY_4 */
- 0x03, 0xfc, 0x0a, 0xf5, 0x22, 0x00, 0x00, /* KEY_5 */
- 0x03, 0xfc, 0x0b, 0xf4, 0x23, 0x00, 0x00, /* KEY_6 */
- 0x03, 0xfc, 0x1b, 0xe4, 0x16, 0x00, 0x00, /* KEY_AUDIO */
- 0x03, 0xfc, 0x0d, 0xf2, 0x24, 0x00, 0x00, /* KEY_7 */
- 0x03, 0xfc, 0x0e, 0xf1, 0x25, 0x00, 0x00, /* KEY_8 */
- 0x03, 0xfc, 0x0f, 0xf0, 0x26, 0x00, 0x00, /* KEY_9 */
- 0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* KEY_OK (2) */
- 0x03, 0xfc, 0x41, 0xbe, 0x37, 0x00, 0x00, /* KEY_DOT */
- 0x03, 0xfc, 0x12, 0xed, 0x27, 0x00, 0x00, /* KEY_0 */
- 0x03, 0xfc, 0x11, 0xee, 0x2a, 0x00, 0x00, /* KEY_AGAIN */
- 0x03, 0xfc, 0x48, 0xb7, 0x2c, 0x00, 0x00, /* KEY_CAMERA */
- 0x03, 0xfc, 0x4a, 0xb5, 0x3c, 0x00, 0x00, /* KEY_NEW */
- 0x03, 0xfc, 0x47, 0xb8, 0x15, 0x01, 0x00, /* KEY_RECORD */
- 0x03, 0xfc, 0x45, 0xba, 0x0b, 0x01, 0x00, /* KEY_TIME */
- 0x03, 0xfc, 0x5e, 0xa1, 0x43, 0x00, 0x00, /* KEY_VOLUMEUP */
- 0x03, 0xfc, 0x5a, 0xa5, 0x42, 0x00, 0x00, /* KEY_VOLUMEDOWN */
- 0x03, 0xfc, 0x5b, 0xa4, 0x4b, 0x00, 0x00, /* KEY_CHANNELUP */
- 0x03, 0xfc, 0x5f, 0xa0, 0x4e, 0x00, 0x00, /* KEY_CHANNELDOWN */
-};
-
-/* TwinHan AzureWave AD-TU700(704J) */
-static struct dvb_usb_rc_key ir_codes_af9015_table_twinhan[] = {
- { 0x053f, KEY_POWER },
- { 0x0019, KEY_FAVORITES }, /* Favorite List */
- { 0x0004, KEY_TEXT }, /* Teletext */
- { 0x000e, KEY_POWER },
- { 0x000e, KEY_INFO }, /* Preview */
- { 0x0008, KEY_EPG }, /* Info/EPG */
- { 0x000f, KEY_LIST }, /* Record List */
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x0029, KEY_CANCEL }, /* Cancel */
- { 0x004c, KEY_CLEAR }, /* Clear */
- { 0x002a, KEY_BACK }, /* Back */
- { 0x002b, KEY_TAB }, /* Tab */
- { 0x0052, KEY_UP }, /* up arrow */
- { 0x0051, KEY_DOWN }, /* down arrow */
- { 0x004f, KEY_RIGHT }, /* right arrow */
- { 0x0050, KEY_LEFT }, /* left arrow */
- { 0x0028, KEY_ENTER }, /* Enter / ok */
- { 0x0252, KEY_VOLUMEUP },
- { 0x0251, KEY_VOLUMEDOWN },
- { 0x004e, KEY_CHANNELDOWN },
- { 0x004b, KEY_CHANNELUP },
- { 0x004a, KEY_RECORD },
- { 0x0111, KEY_PLAY },
- { 0x0017, KEY_PAUSE },
- { 0x000c, KEY_REWIND }, /* FR << */
- { 0x0011, KEY_FASTFORWARD }, /* FF >> */
- { 0x0115, KEY_PREVIOUS }, /* Replay */
- { 0x010e, KEY_NEXT }, /* Skip */
- { 0x0013, KEY_CAMERA }, /* Capture */
- { 0x010f, KEY_LANGUAGE }, /* SAP */
- { 0x0113, KEY_TV2 }, /* PIP */
- { 0x001d, KEY_ZOOM }, /* Full Screen */
- { 0x0117, KEY_SUBTITLE }, /* Subtitle / CC */
- { 0x0010, KEY_MUTE },
- { 0x0119, KEY_AUDIO }, /* L/R */ /* TODO better event */
- { 0x0116, KEY_SLEEP }, /* Hibernate */
- { 0x0116, KEY_SWITCHVIDEOMODE },
- /* A/V */ /* TODO does not work */
- { 0x0006, KEY_AGAIN }, /* Recall */
- { 0x0116, KEY_KPPLUS }, /* Zoom+ */ /* TODO does not work */
- { 0x0116, KEY_KPMINUS }, /* Zoom- */ /* TODO does not work */
- { 0x0215, KEY_RED },
- { 0x020a, KEY_GREEN },
- { 0x021c, KEY_YELLOW },
- { 0x0205, KEY_BLUE },
-};
-
-static u8 af9015_ir_table_twinhan[] = {
- 0x00, 0xff, 0x16, 0xe9, 0x3f, 0x05, 0x00,
- 0x00, 0xff, 0x07, 0xf8, 0x16, 0x01, 0x00,
- 0x00, 0xff, 0x14, 0xeb, 0x11, 0x01, 0x00,
- 0x00, 0xff, 0x1a, 0xe5, 0x4d, 0x00, 0x00,
- 0x00, 0xff, 0x4c, 0xb3, 0x17, 0x00, 0x00,
- 0x00, 0xff, 0x12, 0xed, 0x11, 0x00, 0x00,
- 0x00, 0xff, 0x40, 0xbf, 0x0c, 0x00, 0x00,
- 0x00, 0xff, 0x11, 0xee, 0x4a, 0x00, 0x00,
- 0x00, 0xff, 0x54, 0xab, 0x13, 0x00, 0x00,
- 0x00, 0xff, 0x41, 0xbe, 0x15, 0x01, 0x00,
- 0x00, 0xff, 0x42, 0xbd, 0x0e, 0x01, 0x00,
- 0x00, 0xff, 0x43, 0xbc, 0x17, 0x01, 0x00,
- 0x00, 0xff, 0x50, 0xaf, 0x0f, 0x01, 0x00,
- 0x00, 0xff, 0x4d, 0xb2, 0x1d, 0x00, 0x00,
- 0x00, 0xff, 0x47, 0xb8, 0x13, 0x01, 0x00,
- 0x00, 0xff, 0x05, 0xfa, 0x4b, 0x00, 0x00,
- 0x00, 0xff, 0x02, 0xfd, 0x4e, 0x00, 0x00,
- 0x00, 0xff, 0x0e, 0xf1, 0x06, 0x00, 0x00,
- 0x00, 0xff, 0x1e, 0xe1, 0x52, 0x02, 0x00,
- 0x00, 0xff, 0x0a, 0xf5, 0x51, 0x02, 0x00,
- 0x00, 0xff, 0x10, 0xef, 0x10, 0x00, 0x00,
- 0x00, 0xff, 0x49, 0xb6, 0x19, 0x01, 0x00,
- 0x00, 0xff, 0x15, 0xea, 0x27, 0x00, 0x00,
- 0x00, 0xff, 0x03, 0xfc, 0x1e, 0x00, 0x00,
- 0x00, 0xff, 0x01, 0xfe, 0x1f, 0x00, 0x00,
- 0x00, 0xff, 0x06, 0xf9, 0x20, 0x00, 0x00,
- 0x00, 0xff, 0x09, 0xf6, 0x21, 0x00, 0x00,
- 0x00, 0xff, 0x1d, 0xe2, 0x22, 0x00, 0x00,
- 0x00, 0xff, 0x1f, 0xe0, 0x23, 0x00, 0x00,
- 0x00, 0xff, 0x0d, 0xf2, 0x24, 0x00, 0x00,
- 0x00, 0xff, 0x19, 0xe6, 0x25, 0x00, 0x00,
- 0x00, 0xff, 0x1b, 0xe4, 0x26, 0x00, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0x2b, 0x00, 0x00,
- 0x00, 0xff, 0x4a, 0xb5, 0x4c, 0x00, 0x00,
- 0x00, 0xff, 0x4b, 0xb4, 0x52, 0x00, 0x00,
- 0x00, 0xff, 0x51, 0xae, 0x51, 0x00, 0x00,
- 0x00, 0xff, 0x52, 0xad, 0x4f, 0x00, 0x00,
- 0x00, 0xff, 0x4e, 0xb1, 0x50, 0x00, 0x00,
- 0x00, 0xff, 0x0c, 0xf3, 0x29, 0x00, 0x00,
- 0x00, 0xff, 0x4f, 0xb0, 0x28, 0x00, 0x00,
- 0x00, 0xff, 0x13, 0xec, 0x2a, 0x00, 0x00,
- 0x00, 0xff, 0x17, 0xe8, 0x19, 0x00, 0x00,
- 0x00, 0xff, 0x04, 0xfb, 0x0f, 0x00, 0x00,
- 0x00, 0xff, 0x48, 0xb7, 0x0e, 0x00, 0x00,
- 0x00, 0xff, 0x0f, 0xf0, 0x04, 0x00, 0x00,
- 0x00, 0xff, 0x1c, 0xe3, 0x08, 0x00, 0x00,
- 0x00, 0xff, 0x18, 0xe7, 0x15, 0x02, 0x00,
- 0x00, 0xff, 0x53, 0xac, 0x0a, 0x02, 0x00,
- 0x00, 0xff, 0x5e, 0xa1, 0x1c, 0x02, 0x00,
- 0x00, 0xff, 0x5f, 0xa0, 0x05, 0x02, 0x00,
-};
-
-/* A-Link DTU(m) */
-static struct dvb_usb_rc_key ir_codes_af9015_table_a_link[] = {
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x002e, KEY_CHANNELUP },
- { 0x002d, KEY_CHANNELDOWN },
- { 0x0428, KEY_ZOOM },
- { 0x0041, KEY_MUTE },
- { 0x0042, KEY_VOLUMEDOWN },
- { 0x0043, KEY_VOLUMEUP },
- { 0x0044, KEY_GOTO }, /* jump */
- { 0x0545, KEY_POWER },
-};
-
-static u8 af9015_ir_table_a_link[] = {
- 0x08, 0xf7, 0x12, 0xed, 0x45, 0x05, 0x00, /* power */
- 0x08, 0xf7, 0x1a, 0xe5, 0x41, 0x00, 0x00, /* mute */
- 0x08, 0xf7, 0x01, 0xfe, 0x1e, 0x00, 0x00, /* 1 */
- 0x08, 0xf7, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
- 0x08, 0xf7, 0x03, 0xfc, 0x24, 0x00, 0x00, /* 7 */
- 0x08, 0xf7, 0x05, 0xfa, 0x28, 0x04, 0x00, /* zoom */
- 0x08, 0xf7, 0x00, 0xff, 0x43, 0x00, 0x00, /* volume up */
- 0x08, 0xf7, 0x16, 0xe9, 0x42, 0x00, 0x00, /* volume down */
- 0x08, 0xf7, 0x0f, 0xf0, 0x1f, 0x00, 0x00, /* 2 */
- 0x08, 0xf7, 0x0d, 0xf2, 0x22, 0x00, 0x00, /* 5 */
- 0x08, 0xf7, 0x1b, 0xe4, 0x25, 0x00, 0x00, /* 8 */
- 0x08, 0xf7, 0x06, 0xf9, 0x27, 0x00, 0x00, /* 0 */
- 0x08, 0xf7, 0x14, 0xeb, 0x2e, 0x00, 0x00, /* channel up */
- 0x08, 0xf7, 0x1d, 0xe2, 0x2d, 0x00, 0x00, /* channel down */
- 0x08, 0xf7, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
- 0x08, 0xf7, 0x18, 0xe7, 0x23, 0x00, 0x00, /* 6 */
- 0x08, 0xf7, 0x04, 0xfb, 0x26, 0x00, 0x00, /* 9 */
- 0x08, 0xf7, 0x07, 0xf8, 0x44, 0x00, 0x00, /* jump */
-};
-
-/* MSI DIGIVOX mini II V3.0 */
-static struct dvb_usb_rc_key ir_codes_af9015_table_msi[] = {
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x030f, KEY_CHANNELUP },
- { 0x030e, KEY_CHANNELDOWN },
- { 0x0042, KEY_VOLUMEDOWN },
- { 0x0043, KEY_VOLUMEUP },
- { 0x0545, KEY_POWER },
- { 0x0052, KEY_UP }, /* up */
- { 0x0051, KEY_DOWN }, /* down */
- { 0x0028, KEY_ENTER },
-};
-
-static u8 af9015_ir_table_msi[] = {
- 0x03, 0xfc, 0x17, 0xe8, 0x45, 0x05, 0x00, /* power */
- 0x03, 0xfc, 0x0d, 0xf2, 0x51, 0x00, 0x00, /* down */
- 0x03, 0xfc, 0x03, 0xfc, 0x52, 0x00, 0x00, /* up */
- 0x03, 0xfc, 0x1a, 0xe5, 0x1e, 0x00, 0x00, /* 1 */
- 0x03, 0xfc, 0x02, 0xfd, 0x1f, 0x00, 0x00, /* 2 */
- 0x03, 0xfc, 0x04, 0xfb, 0x20, 0x00, 0x00, /* 3 */
- 0x03, 0xfc, 0x1c, 0xe3, 0x21, 0x00, 0x00, /* 4 */
- 0x03, 0xfc, 0x08, 0xf7, 0x22, 0x00, 0x00, /* 5 */
- 0x03, 0xfc, 0x1d, 0xe2, 0x23, 0x00, 0x00, /* 6 */
- 0x03, 0xfc, 0x11, 0xee, 0x24, 0x00, 0x00, /* 7 */
- 0x03, 0xfc, 0x0b, 0xf4, 0x25, 0x00, 0x00, /* 8 */
- 0x03, 0xfc, 0x10, 0xef, 0x26, 0x00, 0x00, /* 9 */
- 0x03, 0xfc, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
- 0x03, 0xfc, 0x14, 0xeb, 0x43, 0x00, 0x00, /* volume up */
- 0x03, 0xfc, 0x1f, 0xe0, 0x42, 0x00, 0x00, /* volume down */
- 0x03, 0xfc, 0x15, 0xea, 0x0f, 0x03, 0x00, /* channel up */
- 0x03, 0xfc, 0x05, 0xfa, 0x0e, 0x03, 0x00, /* channel down */
- 0x03, 0xfc, 0x16, 0xe9, 0x28, 0x00, 0x00, /* enter */
-};
-
-/* MYGICTV U718 */
-static struct dvb_usb_rc_key ir_codes_af9015_table_mygictv[] = {
- { 0x003d, KEY_SWITCHVIDEOMODE },
- /* TV / AV */
- { 0x0545, KEY_POWER },
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0027, KEY_0 },
- { 0x0041, KEY_MUTE },
- { 0x002a, KEY_ESC }, /* Esc */
- { 0x002e, KEY_CHANNELUP },
- { 0x002d, KEY_CHANNELDOWN },
- { 0x0042, KEY_VOLUMEDOWN },
- { 0x0043, KEY_VOLUMEUP },
- { 0x0052, KEY_UP }, /* up arrow */
- { 0x0051, KEY_DOWN }, /* down arrow */
- { 0x004f, KEY_RIGHT }, /* right arrow */
- { 0x0050, KEY_LEFT }, /* left arrow */
- { 0x0028, KEY_ENTER }, /* ok */
- { 0x0115, KEY_RECORD },
- { 0x0313, KEY_PLAY },
- { 0x0113, KEY_PAUSE },
- { 0x0116, KEY_STOP },
- { 0x0307, KEY_REWIND }, /* FR << */
- { 0x0309, KEY_FASTFORWARD }, /* FF >> */
- { 0x003b, KEY_TIME }, /* TimeShift */
- { 0x003e, KEY_CAMERA }, /* Snapshot */
- { 0x0316, KEY_CYCLEWINDOWS }, /* yellow, min / max */
- { 0x0000, KEY_ZOOM }, /* 'select' (?) */
- { 0x0316, KEY_SHUFFLE }, /* Shuffle */
- { 0x0345, KEY_POWER },
-};
-
-static u8 af9015_ir_table_mygictv[] = {
- 0x02, 0xbd, 0x0c, 0xf3, 0x3d, 0x00, 0x00, /* TV / AV */
- 0x02, 0xbd, 0x14, 0xeb, 0x45, 0x05, 0x00, /* power */
- 0x02, 0xbd, 0x00, 0xff, 0x1e, 0x00, 0x00, /* 1 */
- 0x02, 0xbd, 0x01, 0xfe, 0x1f, 0x00, 0x00, /* 2 */
- 0x02, 0xbd, 0x02, 0xfd, 0x20, 0x00, 0x00, /* 3 */
- 0x02, 0xbd, 0x03, 0xfc, 0x21, 0x00, 0x00, /* 4 */
- 0x02, 0xbd, 0x04, 0xfb, 0x22, 0x00, 0x00, /* 5 */
- 0x02, 0xbd, 0x05, 0xfa, 0x23, 0x00, 0x00, /* 6 */
- 0x02, 0xbd, 0x06, 0xf9, 0x24, 0x00, 0x00, /* 7 */
- 0x02, 0xbd, 0x07, 0xf8, 0x25, 0x00, 0x00, /* 8 */
- 0x02, 0xbd, 0x08, 0xf7, 0x26, 0x00, 0x00, /* 9 */
- 0x02, 0xbd, 0x09, 0xf6, 0x27, 0x00, 0x00, /* 0 */
- 0x02, 0xbd, 0x0a, 0xf5, 0x41, 0x00, 0x00, /* mute */
- 0x02, 0xbd, 0x1c, 0xe3, 0x2a, 0x00, 0x00, /* esc */
- 0x02, 0xbd, 0x1f, 0xe0, 0x43, 0x00, 0x00, /* volume up */
- 0x02, 0xbd, 0x12, 0xed, 0x52, 0x00, 0x00, /* up arrow */
- 0x02, 0xbd, 0x11, 0xee, 0x50, 0x00, 0x00, /* left arrow */
- 0x02, 0xbd, 0x15, 0xea, 0x28, 0x00, 0x00, /* ok */
- 0x02, 0xbd, 0x10, 0xef, 0x4f, 0x00, 0x00, /* right arrow */
- 0x02, 0xbd, 0x13, 0xec, 0x51, 0x00, 0x00, /* down arrow */
- 0x02, 0xbd, 0x0e, 0xf1, 0x42, 0x00, 0x00, /* volume down */
- 0x02, 0xbd, 0x19, 0xe6, 0x15, 0x01, 0x00, /* record */
- 0x02, 0xbd, 0x1e, 0xe1, 0x13, 0x03, 0x00, /* play */
- 0x02, 0xbd, 0x16, 0xe9, 0x16, 0x01, 0x00, /* stop */
- 0x02, 0xbd, 0x0b, 0xf4, 0x28, 0x04, 0x00, /* yellow, min / max */
- 0x02, 0xbd, 0x0f, 0xf0, 0x3b, 0x00, 0x00, /* time shift */
- 0x02, 0xbd, 0x18, 0xe7, 0x2e, 0x00, 0x00, /* channel up */
- 0x02, 0xbd, 0x1a, 0xe5, 0x2d, 0x00, 0x00, /* channel down */
- 0x02, 0xbd, 0x17, 0xe8, 0x3e, 0x00, 0x00, /* snapshot */
- 0x02, 0xbd, 0x40, 0xbf, 0x13, 0x01, 0x00, /* pause */
- 0x02, 0xbd, 0x41, 0xbe, 0x09, 0x03, 0x00, /* FF >> */
- 0x02, 0xbd, 0x42, 0xbd, 0x07, 0x03, 0x00, /* FR << */
- 0x02, 0xbd, 0x43, 0xbc, 0x00, 0x00, 0x00, /* 'select' (?) */
- 0x02, 0xbd, 0x44, 0xbb, 0x16, 0x03, 0x00, /* shuffle */
- 0x02, 0xbd, 0x45, 0xba, 0x45, 0x03, 0x00, /* power */
-};
-
-/* KWorld PlusTV Dual DVB-T Stick (DVB-T 399U) */
-static u8 af9015_ir_table_kworld[] = {
- 0x86, 0x6b, 0x0c, 0xf3, 0x2e, 0x07, 0x00,
- 0x86, 0x6b, 0x16, 0xe9, 0x2d, 0x07, 0x00,
- 0x86, 0x6b, 0x1d, 0xe2, 0x37, 0x07, 0x00,
- 0x86, 0x6b, 0x00, 0xff, 0x1e, 0x07, 0x00,
- 0x86, 0x6b, 0x01, 0xfe, 0x1f, 0x07, 0x00,
- 0x86, 0x6b, 0x02, 0xfd, 0x20, 0x07, 0x00,
- 0x86, 0x6b, 0x03, 0xfc, 0x21, 0x07, 0x00,
- 0x86, 0x6b, 0x04, 0xfb, 0x22, 0x07, 0x00,
- 0x86, 0x6b, 0x05, 0xfa, 0x23, 0x07, 0x00,
- 0x86, 0x6b, 0x06, 0xf9, 0x24, 0x07, 0x00,
- 0x86, 0x6b, 0x07, 0xf8, 0x25, 0x07, 0x00,
- 0x86, 0x6b, 0x08, 0xf7, 0x26, 0x07, 0x00,
- 0x86, 0x6b, 0x09, 0xf6, 0x4d, 0x07, 0x00,
- 0x86, 0x6b, 0x0a, 0xf5, 0x4e, 0x07, 0x00,
- 0x86, 0x6b, 0x14, 0xeb, 0x4f, 0x07, 0x00,
- 0x86, 0x6b, 0x1e, 0xe1, 0x50, 0x07, 0x00,
- 0x86, 0x6b, 0x17, 0xe8, 0x52, 0x07, 0x00,
- 0x86, 0x6b, 0x1f, 0xe0, 0x51, 0x07, 0x00,
- 0x86, 0x6b, 0x0e, 0xf1, 0x0b, 0x07, 0x00,
- 0x86, 0x6b, 0x20, 0xdf, 0x0c, 0x07, 0x00,
- 0x86, 0x6b, 0x42, 0xbd, 0x0d, 0x07, 0x00,
- 0x86, 0x6b, 0x0b, 0xf4, 0x0e, 0x07, 0x00,
- 0x86, 0x6b, 0x43, 0xbc, 0x0f, 0x07, 0x00,
- 0x86, 0x6b, 0x10, 0xef, 0x10, 0x07, 0x00,
- 0x86, 0x6b, 0x21, 0xde, 0x11, 0x07, 0x00,
- 0x86, 0x6b, 0x13, 0xec, 0x12, 0x07, 0x00,
- 0x86, 0x6b, 0x11, 0xee, 0x13, 0x07, 0x00,
- 0x86, 0x6b, 0x12, 0xed, 0x14, 0x07, 0x00,
- 0x86, 0x6b, 0x19, 0xe6, 0x15, 0x07, 0x00,
- 0x86, 0x6b, 0x1a, 0xe5, 0x16, 0x07, 0x00,
- 0x86, 0x6b, 0x1b, 0xe4, 0x17, 0x07, 0x00,
- 0x86, 0x6b, 0x4b, 0xb4, 0x18, 0x07, 0x00,
- 0x86, 0x6b, 0x40, 0xbf, 0x19, 0x07, 0x00,
- 0x86, 0x6b, 0x44, 0xbb, 0x1a, 0x07, 0x00,
- 0x86, 0x6b, 0x41, 0xbe, 0x1b, 0x07, 0x00,
- 0x86, 0x6b, 0x22, 0xdd, 0x1c, 0x07, 0x00,
- 0x86, 0x6b, 0x15, 0xea, 0x1d, 0x07, 0x00,
- 0x86, 0x6b, 0x0f, 0xf0, 0x3f, 0x07, 0x00,
- 0x86, 0x6b, 0x1c, 0xe3, 0x40, 0x07, 0x00,
- 0x86, 0x6b, 0x4a, 0xb5, 0x41, 0x07, 0x00,
- 0x86, 0x6b, 0x48, 0xb7, 0x42, 0x07, 0x00,
- 0x86, 0x6b, 0x49, 0xb6, 0x43, 0x07, 0x00,
- 0x86, 0x6b, 0x18, 0xe7, 0x44, 0x07, 0x00,
- 0x86, 0x6b, 0x23, 0xdc, 0x45, 0x07, 0x00,
-};
-
-/* AverMedia Volar X */
-static struct dvb_usb_rc_key ir_codes_af9015_table_avermedia[] = {
- { 0x053d, KEY_PROG1 }, /* SOURCE */
- { 0x0512, KEY_POWER }, /* POWER */
- { 0x051e, KEY_1 }, /* 1 */
- { 0x051f, KEY_2 }, /* 2 */
- { 0x0520, KEY_3 }, /* 3 */
- { 0x0521, KEY_4 }, /* 4 */
- { 0x0522, KEY_5 }, /* 5 */
- { 0x0523, KEY_6 }, /* 6 */
- { 0x0524, KEY_7 }, /* 7 */
- { 0x0525, KEY_8 }, /* 8 */
- { 0x0526, KEY_9 }, /* 9 */
- { 0x053f, KEY_LEFT }, /* L / DISPLAY */
- { 0x0527, KEY_0 }, /* 0 */
- { 0x050f, KEY_RIGHT }, /* R / CH RTN */
- { 0x0518, KEY_PROG2 }, /* SNAP SHOT */
- { 0x051c, KEY_PROG3 }, /* 16-CH PREV */
- { 0x052d, KEY_VOLUMEDOWN }, /* VOL DOWN */
- { 0x053e, KEY_ZOOM }, /* FULL SCREEN */
- { 0x052e, KEY_VOLUMEUP }, /* VOL UP */
- { 0x0510, KEY_MUTE }, /* MUTE */
- { 0x0504, KEY_AUDIO }, /* AUDIO */
- { 0x0515, KEY_RECORD }, /* RECORD */
- { 0x0511, KEY_PLAY }, /* PLAY */
- { 0x0516, KEY_STOP }, /* STOP */
- { 0x050c, KEY_PLAYPAUSE }, /* TIMESHIFT / PAUSE */
- { 0x0505, KEY_BACK }, /* << / RED */
- { 0x0509, KEY_FORWARD }, /* >> / YELLOW */
- { 0x0517, KEY_TEXT }, /* TELETEXT */
- { 0x050a, KEY_EPG }, /* EPG */
- { 0x0513, KEY_MENU }, /* MENU */
-
- { 0x050e, KEY_CHANNELUP }, /* CH UP */
- { 0x050d, KEY_CHANNELDOWN }, /* CH DOWN */
- { 0x0519, KEY_FIRST }, /* |<< / GREEN */
- { 0x0508, KEY_LAST }, /* >>| / BLUE */
-};
-
-static u8 af9015_ir_table_avermedia[] = {
- 0x02, 0xfd, 0x00, 0xff, 0x12, 0x05, 0x00,
- 0x02, 0xfd, 0x01, 0xfe, 0x3d, 0x05, 0x00,
- 0x02, 0xfd, 0x03, 0xfc, 0x17, 0x05, 0x00,
- 0x02, 0xfd, 0x04, 0xfb, 0x0a, 0x05, 0x00,
- 0x02, 0xfd, 0x05, 0xfa, 0x1e, 0x05, 0x00,
- 0x02, 0xfd, 0x06, 0xf9, 0x1f, 0x05, 0x00,
- 0x02, 0xfd, 0x07, 0xf8, 0x20, 0x05, 0x00,
- 0x02, 0xfd, 0x09, 0xf6, 0x21, 0x05, 0x00,
- 0x02, 0xfd, 0x0a, 0xf5, 0x22, 0x05, 0x00,
- 0x02, 0xfd, 0x0b, 0xf4, 0x23, 0x05, 0x00,
- 0x02, 0xfd, 0x0d, 0xf2, 0x24, 0x05, 0x00,
- 0x02, 0xfd, 0x0e, 0xf1, 0x25, 0x05, 0x00,
- 0x02, 0xfd, 0x0f, 0xf0, 0x26, 0x05, 0x00,
- 0x02, 0xfd, 0x11, 0xee, 0x27, 0x05, 0x00,
- 0x02, 0xfd, 0x08, 0xf7, 0x04, 0x05, 0x00,
- 0x02, 0xfd, 0x0c, 0xf3, 0x3e, 0x05, 0x00,
- 0x02, 0xfd, 0x10, 0xef, 0x1c, 0x05, 0x00,
- 0x02, 0xfd, 0x12, 0xed, 0x3f, 0x05, 0x00,
- 0x02, 0xfd, 0x13, 0xec, 0x0f, 0x05, 0x00,
- 0x02, 0xfd, 0x14, 0xeb, 0x10, 0x05, 0x00,
- 0x02, 0xfd, 0x15, 0xea, 0x13, 0x05, 0x00,
- 0x02, 0xfd, 0x17, 0xe8, 0x18, 0x05, 0x00,
- 0x02, 0xfd, 0x18, 0xe7, 0x11, 0x05, 0x00,
- 0x02, 0xfd, 0x19, 0xe6, 0x15, 0x05, 0x00,
- 0x02, 0xfd, 0x1a, 0xe5, 0x0c, 0x05, 0x00,
- 0x02, 0xfd, 0x1b, 0xe4, 0x16, 0x05, 0x00,
- 0x02, 0xfd, 0x1c, 0xe3, 0x09, 0x05, 0x00,
- 0x02, 0xfd, 0x1d, 0xe2, 0x05, 0x05, 0x00,
- 0x02, 0xfd, 0x1e, 0xe1, 0x2d, 0x05, 0x00,
- 0x02, 0xfd, 0x1f, 0xe0, 0x2e, 0x05, 0x00,
- 0x03, 0xfc, 0x00, 0xff, 0x08, 0x05, 0x00,
- 0x03, 0xfc, 0x01, 0xfe, 0x19, 0x05, 0x00,
- 0x03, 0xfc, 0x02, 0xfd, 0x0d, 0x05, 0x00,
- 0x03, 0xfc, 0x03, 0xfc, 0x0e, 0x05, 0x00,
-};
-
-static u8 af9015_ir_table_avermedia_ks[] = {
- 0x05, 0xfa, 0x01, 0xfe, 0x12, 0x05, 0x00,
- 0x05, 0xfa, 0x02, 0xfd, 0x0e, 0x05, 0x00,
- 0x05, 0xfa, 0x03, 0xfc, 0x0d, 0x05, 0x00,
- 0x05, 0xfa, 0x04, 0xfb, 0x2e, 0x05, 0x00,
- 0x05, 0xfa, 0x05, 0xfa, 0x2d, 0x05, 0x00,
- 0x05, 0xfa, 0x06, 0xf9, 0x10, 0x05, 0x00,
- 0x05, 0xfa, 0x07, 0xf8, 0x0f, 0x05, 0x00,
- 0x05, 0xfa, 0x08, 0xf7, 0x3d, 0x05, 0x00,
- 0x05, 0xfa, 0x09, 0xf6, 0x1e, 0x05, 0x00,
- 0x05, 0xfa, 0x0a, 0xf5, 0x1f, 0x05, 0x00,
- 0x05, 0xfa, 0x0b, 0xf4, 0x20, 0x05, 0x00,
- 0x05, 0xfa, 0x0c, 0xf3, 0x21, 0x05, 0x00,
- 0x05, 0xfa, 0x0d, 0xf2, 0x22, 0x05, 0x00,
- 0x05, 0xfa, 0x0e, 0xf1, 0x23, 0x05, 0x00,
- 0x05, 0xfa, 0x0f, 0xf0, 0x24, 0x05, 0x00,
- 0x05, 0xfa, 0x10, 0xef, 0x25, 0x05, 0x00,
- 0x05, 0xfa, 0x11, 0xee, 0x26, 0x05, 0x00,
- 0x05, 0xfa, 0x12, 0xed, 0x27, 0x05, 0x00,
- 0x05, 0xfa, 0x13, 0xec, 0x04, 0x05, 0x00,
- 0x05, 0xfa, 0x15, 0xea, 0x0a, 0x05, 0x00,
- 0x05, 0xfa, 0x16, 0xe9, 0x11, 0x05, 0x00,
- 0x05, 0xfa, 0x17, 0xe8, 0x15, 0x05, 0x00,
- 0x05, 0xfa, 0x18, 0xe7, 0x16, 0x05, 0x00,
- 0x05, 0xfa, 0x1c, 0xe3, 0x05, 0x05, 0x00,
- 0x05, 0xfa, 0x1d, 0xe2, 0x09, 0x05, 0x00,
- 0x05, 0xfa, 0x4d, 0xb2, 0x3f, 0x05, 0x00,
- 0x05, 0xfa, 0x56, 0xa9, 0x3e, 0x05, 0x00
-};
-
-/* Digittrade DVB-T USB Stick */
-static struct dvb_usb_rc_key ir_codes_af9015_table_digittrade[] = {
- { 0x010f, KEY_LAST }, /* RETURN */
- { 0x0517, KEY_TEXT }, /* TELETEXT */
- { 0x0108, KEY_EPG }, /* EPG */
- { 0x0513, KEY_POWER }, /* POWER */
- { 0x0109, KEY_ZOOM }, /* FULLSCREEN */
- { 0x0040, KEY_AUDIO }, /* DUAL SOUND */
- { 0x002c, KEY_PRINT }, /* SNAPSHOT */
- { 0x0516, KEY_SUBTITLE }, /* SUBTITLE */
- { 0x0052, KEY_CHANNELUP }, /* CH Up */
- { 0x0051, KEY_CHANNELDOWN },/* Ch Dn */
- { 0x0057, KEY_VOLUMEUP }, /* Vol Up */
- { 0x0056, KEY_VOLUMEDOWN }, /* Vol Dn */
- { 0x0110, KEY_MUTE }, /* MUTE */
- { 0x0027, KEY_0 },
- { 0x001e, KEY_1 },
- { 0x001f, KEY_2 },
- { 0x0020, KEY_3 },
- { 0x0021, KEY_4 },
- { 0x0022, KEY_5 },
- { 0x0023, KEY_6 },
- { 0x0024, KEY_7 },
- { 0x0025, KEY_8 },
- { 0x0026, KEY_9 },
- { 0x0117, KEY_PLAYPAUSE }, /* TIMESHIFT */
- { 0x0115, KEY_RECORD }, /* RECORD */
- { 0x0313, KEY_PLAY }, /* PLAY */
- { 0x0116, KEY_STOP }, /* STOP */
- { 0x0113, KEY_PAUSE }, /* PAUSE */
-};
-
-static u8 af9015_ir_table_digittrade[] = {
- 0x00, 0xff, 0x06, 0xf9, 0x13, 0x05, 0x00,
- 0x00, 0xff, 0x4d, 0xb2, 0x17, 0x01, 0x00,
- 0x00, 0xff, 0x1f, 0xe0, 0x2c, 0x00, 0x00,
- 0x00, 0xff, 0x0a, 0xf5, 0x15, 0x01, 0x00,
- 0x00, 0xff, 0x0e, 0xf1, 0x16, 0x01, 0x00,
- 0x00, 0xff, 0x09, 0xf6, 0x09, 0x01, 0x00,
- 0x00, 0xff, 0x01, 0xfe, 0x08, 0x01, 0x00,
- 0x00, 0xff, 0x05, 0xfa, 0x10, 0x01, 0x00,
- 0x00, 0xff, 0x02, 0xfd, 0x56, 0x00, 0x00,
- 0x00, 0xff, 0x40, 0xbf, 0x57, 0x00, 0x00,
- 0x00, 0xff, 0x19, 0xe6, 0x52, 0x00, 0x00,
- 0x00, 0xff, 0x17, 0xe8, 0x51, 0x00, 0x00,
- 0x00, 0xff, 0x10, 0xef, 0x0f, 0x01, 0x00,
- 0x00, 0xff, 0x54, 0xab, 0x27, 0x00, 0x00,
- 0x00, 0xff, 0x1b, 0xe4, 0x1e, 0x00, 0x00,
- 0x00, 0xff, 0x11, 0xee, 0x1f, 0x00, 0x00,
- 0x00, 0xff, 0x15, 0xea, 0x20, 0x00, 0x00,
- 0x00, 0xff, 0x12, 0xed, 0x21, 0x00, 0x00,
- 0x00, 0xff, 0x16, 0xe9, 0x22, 0x00, 0x00,
- 0x00, 0xff, 0x4c, 0xb3, 0x23, 0x00, 0x00,
- 0x00, 0xff, 0x48, 0xb7, 0x24, 0x00, 0x00,
- 0x00, 0xff, 0x04, 0xfb, 0x25, 0x00, 0x00,
- 0x00, 0xff, 0x00, 0xff, 0x26, 0x00, 0x00,
- 0x00, 0xff, 0x1e, 0xe1, 0x13, 0x03, 0x00,
- 0x00, 0xff, 0x1a, 0xe5, 0x13, 0x01, 0x00,
- 0x00, 0xff, 0x03, 0xfc, 0x17, 0x05, 0x00,
- 0x00, 0xff, 0x0d, 0xf2, 0x16, 0x05, 0x00,
- 0x00, 0xff, 0x1d, 0xe2, 0x40, 0x00, 0x00,
-};
-
-/* TREKSTOR DVB-T USB Stick */
-static struct dvb_usb_rc_key ir_codes_af9015_table_trekstor[] = {
- { 0x0704, KEY_AGAIN }, /* Home */
- { 0x0705, KEY_MUTE }, /* Mute */
- { 0x0706, KEY_UP }, /* Up */
- { 0x0707, KEY_DOWN }, /* Down */
- { 0x0709, KEY_RIGHT }, /* Right */
- { 0x070a, KEY_ENTER }, /* OK */
- { 0x070b, KEY_FASTFORWARD }, /* Fast forward */
- { 0x070c, KEY_REWIND }, /* Rewind */
- { 0x070d, KEY_PLAY }, /* Play/Pause */
- { 0x070e, KEY_VOLUMEUP }, /* Volume + */
- { 0x070f, KEY_VOLUMEDOWN }, /* Volume - */
- { 0x0710, KEY_RECORD }, /* Record */
- { 0x0711, KEY_STOP }, /* Stop */
- { 0x0712, KEY_ZOOM }, /* TV */
- { 0x0713, KEY_EPG }, /* Info/EPG */
- { 0x0714, KEY_CHANNELDOWN }, /* Channel - */
- { 0x0715, KEY_CHANNELUP }, /* Channel + */
- { 0x071e, KEY_1 },
- { 0x071f, KEY_2 },
- { 0x0720, KEY_3 },
- { 0x0721, KEY_4 },
- { 0x0722, KEY_5 },
- { 0x0723, KEY_6 },
- { 0x0724, KEY_7 },
- { 0x0725, KEY_8 },
- { 0x0726, KEY_9 },
- { 0x0708, KEY_LEFT }, /* LEFT */
- { 0x0727, KEY_0 },
-};
-
-static u8 af9015_ir_table_trekstor[] = {
- 0x00, 0xff, 0x86, 0x79, 0x04, 0x07, 0x00,
- 0x00, 0xff, 0x85, 0x7a, 0x05, 0x07, 0x00,
- 0x00, 0xff, 0x87, 0x78, 0x06, 0x07, 0x00,
- 0x00, 0xff, 0x8c, 0x73, 0x07, 0x07, 0x00,
- 0x00, 0xff, 0x89, 0x76, 0x09, 0x07, 0x00,
- 0x00, 0xff, 0x88, 0x77, 0x0a, 0x07, 0x00,
- 0x00, 0xff, 0x8a, 0x75, 0x0b, 0x07, 0x00,
- 0x00, 0xff, 0x9e, 0x61, 0x0c, 0x07, 0x00,
- 0x00, 0xff, 0x8d, 0x72, 0x0d, 0x07, 0x00,
- 0x00, 0xff, 0x8b, 0x74, 0x0e, 0x07, 0x00,
- 0x00, 0xff, 0x9b, 0x64, 0x0f, 0x07, 0x00,
- 0x00, 0xff, 0x9d, 0x62, 0x10, 0x07, 0x00,
- 0x00, 0xff, 0x8e, 0x71, 0x11, 0x07, 0x00,
- 0x00, 0xff, 0x9c, 0x63, 0x12, 0x07, 0x00,
- 0x00, 0xff, 0x8f, 0x70, 0x13, 0x07, 0x00,
- 0x00, 0xff, 0x93, 0x6c, 0x14, 0x07, 0x00,
- 0x00, 0xff, 0x97, 0x68, 0x15, 0x07, 0x00,
- 0x00, 0xff, 0x92, 0x6d, 0x1e, 0x07, 0x00,
- 0x00, 0xff, 0x96, 0x69, 0x1f, 0x07, 0x00,
- 0x00, 0xff, 0x9a, 0x65, 0x20, 0x07, 0x00,
- 0x00, 0xff, 0x91, 0x6e, 0x21, 0x07, 0x00,
- 0x00, 0xff, 0x95, 0x6a, 0x22, 0x07, 0x00,
- 0x00, 0xff, 0x99, 0x66, 0x23, 0x07, 0x00,
- 0x00, 0xff, 0x90, 0x6f, 0x24, 0x07, 0x00,
- 0x00, 0xff, 0x94, 0x6b, 0x25, 0x07, 0x00,
- 0x00, 0xff, 0x98, 0x67, 0x26, 0x07, 0x00,
- 0x00, 0xff, 0x9f, 0x60, 0x08, 0x07, 0x00,
- 0x00, 0xff, 0x84, 0x7b, 0x27, 0x07, 0x00,
-};
-
-/* MSI DIGIVOX mini III */
-static struct dvb_usb_rc_key ir_codes_af9015_table_msi_digivox_iii[] = {
- { 0x0713, KEY_POWER }, /* [red power button] */
- { 0x073b, KEY_VIDEO }, /* Source */
- { 0x073e, KEY_ZOOM }, /* Zoom */
- { 0x070b, KEY_POWER2 }, /* ShutDown */
- { 0x071e, KEY_1 },
- { 0x071f, KEY_2 },
- { 0x0720, KEY_3 },
- { 0x0721, KEY_4 },
- { 0x0722, KEY_5 },
- { 0x0723, KEY_6 },
- { 0x0724, KEY_7 },
- { 0x0725, KEY_8 },
- { 0x0726, KEY_9 },
- { 0x0727, KEY_0 },
- { 0x0752, KEY_CHANNELUP }, /* CH+ */
- { 0x0751, KEY_CHANNELDOWN }, /* CH- */
- { 0x0750, KEY_VOLUMEUP }, /* Vol+ */
- { 0x074f, KEY_VOLUMEDOWN }, /* Vol- */
- { 0x0705, KEY_ESC }, /* [back up arrow] */
- { 0x0708, KEY_OK }, /* [enter arrow] */
- { 0x073f, KEY_RECORD }, /* Rec */
- { 0x0716, KEY_STOP }, /* Stop */
- { 0x072a, KEY_PLAY }, /* Play */
- { 0x073c, KEY_MUTE }, /* Mute */
- { 0x0718, KEY_UP },
- { 0x0707, KEY_DOWN },
- { 0x070f, KEY_LEFT },
- { 0x0715, KEY_RIGHT },
- { 0x0736, KEY_RED },
- { 0x0737, KEY_GREEN },
- { 0x072d, KEY_YELLOW },
- { 0x072e, KEY_BLUE },
-};
-
-static u8 af9015_ir_table_msi_digivox_iii[] = {
- 0x61, 0xd6, 0x43, 0xbc, 0x13, 0x07, 0x00, /* KEY_POWER */
- 0x61, 0xd6, 0x01, 0xfe, 0x3b, 0x07, 0x00, /* KEY_VIDEO */
- 0x61, 0xd6, 0x0b, 0xf4, 0x3e, 0x07, 0x00, /* KEY_ZOOM */
- 0x61, 0xd6, 0x03, 0xfc, 0x0b, 0x07, 0x00, /* KEY_POWER2 */
- 0x61, 0xd6, 0x04, 0xfb, 0x1e, 0x07, 0x00, /* KEY_1 */
- 0x61, 0xd6, 0x08, 0xf7, 0x1f, 0x07, 0x00, /* KEY_2 */
- 0x61, 0xd6, 0x02, 0xfd, 0x20, 0x07, 0x00, /* KEY_3 */
- 0x61, 0xd6, 0x0f, 0xf0, 0x21, 0x07, 0x00, /* KEY_4 */
- 0x61, 0xd6, 0x05, 0xfa, 0x22, 0x07, 0x00, /* KEY_5 */
- 0x61, 0xd6, 0x06, 0xf9, 0x23, 0x07, 0x00, /* KEY_6 */
- 0x61, 0xd6, 0x0c, 0xf3, 0x24, 0x07, 0x00, /* KEY_7 */
- 0x61, 0xd6, 0x0d, 0xf2, 0x25, 0x07, 0x00, /* KEY_8 */
- 0x61, 0xd6, 0x0a, 0xf5, 0x26, 0x07, 0x00, /* KEY_9 */
- 0x61, 0xd6, 0x11, 0xee, 0x27, 0x07, 0x00, /* KEY_0 */
- 0x61, 0xd6, 0x09, 0xf6, 0x52, 0x07, 0x00, /* KEY_CHANNELUP */
- 0x61, 0xd6, 0x07, 0xf8, 0x51, 0x07, 0x00, /* KEY_CHANNELDOWN */
- 0x61, 0xd6, 0x0e, 0xf1, 0x50, 0x07, 0x00, /* KEY_VOLUMEUP */
- 0x61, 0xd6, 0x13, 0xec, 0x4f, 0x07, 0x00, /* KEY_VOLUMEDOWN */
- 0x61, 0xd6, 0x10, 0xef, 0x05, 0x07, 0x00, /* KEY_ESC */
- 0x61, 0xd6, 0x12, 0xed, 0x08, 0x07, 0x00, /* KEY_OK */
- 0x61, 0xd6, 0x14, 0xeb, 0x3f, 0x07, 0x00, /* KEY_RECORD */
- 0x61, 0xd6, 0x15, 0xea, 0x16, 0x07, 0x00, /* KEY_STOP */
- 0x61, 0xd6, 0x16, 0xe9, 0x2a, 0x07, 0x00, /* KEY_PLAY */
- 0x61, 0xd6, 0x17, 0xe8, 0x3c, 0x07, 0x00, /* KEY_MUTE */
- 0x61, 0xd6, 0x18, 0xe7, 0x18, 0x07, 0x00, /* KEY_UP */
- 0x61, 0xd6, 0x19, 0xe6, 0x07, 0x07, 0x00, /* KEY_DOWN */
- 0x61, 0xd6, 0x1a, 0xe5, 0x0f, 0x07, 0x00, /* KEY_LEFT */
- 0x61, 0xd6, 0x1b, 0xe4, 0x15, 0x07, 0x00, /* KEY_RIGHT */
- 0x61, 0xd6, 0x1c, 0xe3, 0x36, 0x07, 0x00, /* KEY_RED */
- 0x61, 0xd6, 0x1d, 0xe2, 0x37, 0x07, 0x00, /* KEY_GREEN */
- 0x61, 0xd6, 0x1e, 0xe1, 0x2d, 0x07, 0x00, /* KEY_YELLOW */
- 0x61, 0xd6, 0x1f, 0xe0, 0x2e, 0x07, 0x00, /* KEY_BLUE */
-};
-
#endif
diff --git a/drivers/media/dvb/dvb-usb/anysee.c b/drivers/media/dvb/dvb-usb/anysee.c
index faca1ad88a67..6b402e943539 100644
--- a/drivers/media/dvb/dvb-usb/anysee.c
+++ b/drivers/media/dvb/dvb-usb/anysee.c
@@ -354,7 +354,7 @@ static int anysee_frontend_attach(struct dvb_usb_adapter *adap)
static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
{
struct anysee_state *state = adap->dev->priv;
- deb_info("%s: \n", __func__);
+ deb_info("%s:\n", __func__);
switch (state->tuner) {
case DVB_PLL_THOMSON_DTT7579:
@@ -374,78 +374,32 @@ static int anysee_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static int anysee_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+static int anysee_rc_query(struct dvb_usb_device *d)
{
u8 buf[] = {CMD_GET_IR_CODE};
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
u8 ircode[2];
- int i, ret;
+ int ret;
+
+ /* Remote controller is basic NEC using address byte 0x08.
+ Anysee device RC query returns only two bytes, status and code,
+ address byte is dropped. Also it does not return any value for
+ NEC RCs having address byte other than 0x08. Due to that, we
+ cannot use that device as standard NEC receiver.
+ It could be possible make hack which reads whole code directly
+ from device memory... */
- ret = anysee_ctrl_msg(d, buf, sizeof(buf), &ircode[0], 2);
+ ret = anysee_ctrl_msg(d, buf, sizeof(buf), ircode, sizeof(ircode));
if (ret)
return ret;
- *event = 0;
- *state = REMOTE_NO_KEY_PRESSED;
-
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == ircode[0] &&
- rc5_data(&keymap[i]) == ircode[1]) {
- *event = keymap[i].event;
- *state = REMOTE_KEY_PRESSED;
- return 0;
- }
+ if (ircode[0]) {
+ deb_rc("%s: key pressed %02x\n", __func__, ircode[1]);
+ rc_keydown(d->rc_dev, 0x08 << 8 | ircode[1], 0);
}
+
return 0;
}
-static struct dvb_usb_rc_key ir_codes_anysee_table[] = {
- { 0x0100, KEY_0 },
- { 0x0101, KEY_1 },
- { 0x0102, KEY_2 },
- { 0x0103, KEY_3 },
- { 0x0104, KEY_4 },
- { 0x0105, KEY_5 },
- { 0x0106, KEY_6 },
- { 0x0107, KEY_7 },
- { 0x0108, KEY_8 },
- { 0x0109, KEY_9 },
- { 0x010a, KEY_POWER },
- { 0x010b, KEY_DOCUMENTS }, /* * */
- { 0x0119, KEY_FAVORITES },
- { 0x0120, KEY_SLEEP },
- { 0x0121, KEY_MODE }, /* 4:3 / 16:9 select */
- { 0x0122, KEY_ZOOM },
- { 0x0147, KEY_TEXT },
- { 0x0116, KEY_TV }, /* TV / radio select */
- { 0x011e, KEY_LANGUAGE }, /* Second Audio Program */
- { 0x011a, KEY_SUBTITLE },
- { 0x011b, KEY_CAMERA }, /* screenshot */
- { 0x0142, KEY_MUTE },
- { 0x010e, KEY_MENU },
- { 0x010f, KEY_EPG },
- { 0x0117, KEY_INFO },
- { 0x0110, KEY_EXIT },
- { 0x0113, KEY_VOLUMEUP },
- { 0x0112, KEY_VOLUMEDOWN },
- { 0x0111, KEY_CHANNELUP },
- { 0x0114, KEY_CHANNELDOWN },
- { 0x0115, KEY_OK },
- { 0x011d, KEY_RED },
- { 0x011f, KEY_GREEN },
- { 0x011c, KEY_YELLOW },
- { 0x0144, KEY_BLUE },
- { 0x010c, KEY_SHUFFLE }, /* snapshot */
- { 0x0148, KEY_STOP },
- { 0x0150, KEY_PLAY },
- { 0x0151, KEY_PAUSE },
- { 0x0149, KEY_RECORD },
- { 0x0118, KEY_PREVIOUS }, /* |<< */
- { 0x010d, KEY_NEXT }, /* >>| */
- { 0x0124, KEY_PROG1 }, /* F1 */
- { 0x0125, KEY_PROG2 }, /* F2 */
-};
-
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties anysee_properties;
@@ -463,6 +417,11 @@ static int anysee_probe(struct usb_interface *intf,
if (intf->num_altsetting < 1)
return -ENODEV;
+ /*
+ * Anysee is always warm (its USB-bridge, Cypress FX2, uploads
+ * firmware from eeprom). If dvb_usb_device_init() succeeds that
+ * means d is a valid pointer.
+ */
ret = dvb_usb_device_init(intf, &anysee_properties, THIS_MODULE, &d,
adapter_nr);
if (ret)
@@ -479,10 +438,7 @@ static int anysee_probe(struct usb_interface *intf,
if (ret)
return ret;
- if (d)
- ret = anysee_init(d);
-
- return ret;
+ return anysee_init(d);
}
static struct usb_device_id anysee_table[] = {
@@ -518,10 +474,13 @@ static struct dvb_usb_device_properties anysee_properties = {
}
},
- .rc_key_map = ir_codes_anysee_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_anysee_table),
- .rc_query = anysee_rc_query,
- .rc_interval = 200, /* windows driver uses 500ms */
+ .rc.core = {
+ .rc_codes = RC_MAP_ANYSEE,
+ .protocol = RC_TYPE_OTHER,
+ .module_name = "anysee",
+ .rc_query = anysee_rc_query,
+ .rc_interval = 250, /* windows driver uses 500ms */
+ },
.i2c_algo = &anysee_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/az6027.c b/drivers/media/dvb/dvb-usb/az6027.c
index 6681ac1c56e3..57e2444d51ab 100644
--- a/drivers/media/dvb/dvb-usb/az6027.c
+++ b/drivers/media/dvb/dvb-usb/az6027.c
@@ -386,7 +386,7 @@ static int az6027_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
/* keys for the enclosed remote control */
-static struct dvb_usb_rc_key ir_codes_az6027_table[] = {
+static struct rc_map_table rc_map_az6027_table[] = {
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
};
@@ -1089,6 +1089,7 @@ static struct usb_device_id az6027_usb_table[] = {
{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_DVBS2CI_V2) },
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V1) },
{ USB_DEVICE(USB_VID_TECHNISAT, USB_PID_TECHNISAT_USB2_HDCI_V2) },
+ { USB_DEVICE(USB_VID_ELGATO, USB_PID_ELGATO_EYETV_SAT) },
{ },
};
@@ -1125,13 +1126,16 @@ static struct dvb_usb_device_properties az6027_properties = {
.power_ctrl = az6027_power_ctrl,
.read_mac_address = az6027_read_mac_addr,
*/
- .rc_key_map = ir_codes_az6027_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_az6027_table),
- .rc_interval = 400,
- .rc_query = az6027_rc_query,
+ .rc.legacy = {
+ .rc_map_table = rc_map_az6027_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_az6027_table),
+ .rc_interval = 400,
+ .rc_query = az6027_rc_query,
+ },
+
.i2c_algo = &az6027_i2c_algo,
- .num_device_descs = 5,
+ .num_device_descs = 6,
.devices = {
{
.name = "AZUREWAVE DVB-S/S2 USB2.0 (AZ6027)",
@@ -1153,6 +1157,10 @@ static struct dvb_usb_device_properties az6027_properties = {
.name = "Technisat SkyStar USB 2 HD CI",
.cold_ids = { &az6027_usb_table[4], NULL },
.warm_ids = { NULL },
+ }, {
+ .name = "Elgato EyeTV Sat",
+ .cold_ids = { &az6027_usb_table[5], NULL },
+ .warm_ids = { NULL },
},
{ NULL },
}
diff --git a/drivers/media/dvb/dvb-usb/cinergyT2-core.c b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
index 5a9c14bdc980..16f2ce2bc15a 100644
--- a/drivers/media/dvb/dvb-usb/cinergyT2-core.c
+++ b/drivers/media/dvb/dvb-usb/cinergyT2-core.c
@@ -84,7 +84,7 @@ static int cinergyt2_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_cinergyt2_table[] = {
+static struct rc_map_table rc_map_cinergyt2_table[] = {
{ 0x0401, KEY_POWER },
{ 0x0402, KEY_1 },
{ 0x0403, KEY_2 },
@@ -217,10 +217,12 @@ static struct dvb_usb_device_properties cinergyt2_properties = {
.power_ctrl = cinergyt2_power_ctrl,
- .rc_interval = 50,
- .rc_key_map = ir_codes_cinergyt2_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_cinergyt2_table),
- .rc_query = cinergyt2_rc_query,
+ .rc.legacy = {
+ .rc_interval = 50,
+ .rc_map_table = rc_map_cinergyt2_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_cinergyt2_table),
+ .rc_query = cinergyt2_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 1,
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index 0eb490889162..acb5fb2d2e73 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -385,7 +385,7 @@ static int cxusb_d680_dmb_streaming_ctrl(
static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
u8 ircode[4];
int i;
@@ -394,10 +394,10 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[2] &&
rc5_data(&keymap[i]) == ircode[3]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
@@ -410,7 +410,7 @@ static int cxusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
int *state)
{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
u8 ircode[4];
int i;
struct i2c_msg msg = { .addr = 0x6b, .flags = I2C_M_RD,
@@ -422,10 +422,10 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
if (cxusb_i2c_xfer(&d->i2c_adap, &msg, 1) != 1)
return 0;
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[1] &&
rc5_data(&keymap[i]) == ircode[2]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
@@ -438,7 +438,7 @@ static int cxusb_bluebird2_rc_query(struct dvb_usb_device *d, u32 *event,
static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
int *state)
{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
u8 ircode[2];
int i;
@@ -448,10 +448,10 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
if (cxusb_ctrl_msg(d, 0x10, NULL, 0, ircode, 2) < 0)
return 0;
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
if (rc5_custom(&keymap[i]) == ircode[0] &&
rc5_data(&keymap[i]) == ircode[1]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
@@ -461,7 +461,7 @@ static int cxusb_d680_dmb_rc_query(struct dvb_usb_device *d, u32 *event,
return 0;
}
-static struct dvb_usb_rc_key ir_codes_dvico_mce_table[] = {
+static struct rc_map_table rc_map_dvico_mce_table[] = {
{ 0xfe02, KEY_TV },
{ 0xfe0e, KEY_MP3 },
{ 0xfe1a, KEY_DVD },
@@ -509,7 +509,7 @@ static struct dvb_usb_rc_key ir_codes_dvico_mce_table[] = {
{ 0xfe4e, KEY_POWER },
};
-static struct dvb_usb_rc_key ir_codes_dvico_portable_table[] = {
+static struct rc_map_table rc_map_dvico_portable_table[] = {
{ 0xfc02, KEY_SETUP }, /* Profile */
{ 0xfc43, KEY_POWER2 },
{ 0xfc06, KEY_EPG },
@@ -548,7 +548,7 @@ static struct dvb_usb_rc_key ir_codes_dvico_portable_table[] = {
{ 0xfc00, KEY_UNKNOWN }, /* HD */
};
-static struct dvb_usb_rc_key ir_codes_d680_dmb_table[] = {
+static struct rc_map_table rc_map_d680_dmb_table[] = {
{ 0x0038, KEY_UNKNOWN }, /* TV/AV */
{ 0x080c, KEY_ZOOM },
{ 0x0800, KEY_0 },
@@ -923,7 +923,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
return -EIO;
/* try to determine if there is no IR decoder on the I2C bus */
- for (i = 0; adap->dev->props.rc_key_map != NULL && i < 5; i++) {
+ for (i = 0; adap->dev->props.rc.legacy.rc_map_table != NULL && i < 5; i++) {
msleep(20);
if (cxusb_i2c_xfer(&adap->dev->i2c_adap, &msg, 1) != 1)
goto no_IR;
@@ -931,7 +931,7 @@ static int cxusb_dualdig4_frontend_attach(struct dvb_usb_adapter *adap)
continue;
if (ircode[2] + ircode[3] != 0xff) {
no_IR:
- adap->dev->props.rc_key_map = NULL;
+ adap->dev->props.rc.legacy.rc_map_table = NULL;
info("No IR receiver detected on this device.");
break;
}
@@ -1026,8 +1026,10 @@ static int cxusb_dualdig4_rev2_frontend_attach(struct dvb_usb_adapter *adap)
cxusb_bluebird_gpio_pulse(adap->dev, 0x02, 1);
if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
- &cxusb_dualdig4_rev2_config) < 0)
+ &cxusb_dualdig4_rev2_config) < 0) {
+ printk(KERN_WARNING "Unable to enumerate dib7000p\n");
return -ENODEV;
+ }
adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
&cxusb_dualdig4_rev2_config);
@@ -1449,10 +1451,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgh064f_properties = {
.i2c_algo = &cxusb_i2c_algo,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
+ .rc_query = cxusb_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -1500,10 +1504,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dee1601_properties = {
.i2c_algo = &cxusb_i2c_algo,
- .rc_interval = 150,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 150,
+ .rc_map_table = rc_map_dvico_mce_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table),
+ .rc_query = cxusb_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -1559,10 +1565,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_lgz201_properties = {
.i2c_algo = &cxusb_i2c_algo,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
+ .rc_query = cxusb_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
.num_device_descs = 1,
@@ -1609,10 +1617,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dtt7579_properties = {
.i2c_algo = &cxusb_i2c_algo,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
+ .rc_query = cxusb_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -1658,10 +1668,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_dualdig4_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
- .rc_query = cxusb_bluebird2_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_dvico_mce_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table),
+ .rc_query = cxusb_bluebird2_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1706,10 +1718,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_bluebird2_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
+ .rc_query = cxusb_bluebird2_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1756,10 +1770,12 @@ static struct dvb_usb_device_properties cxusb_bluebird_nano2_needsfirmware_prope
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_portable_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_portable_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_dvico_portable_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_portable_table),
+ .rc_query = cxusb_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1847,10 +1863,12 @@ struct dvb_usb_device_properties cxusb_bluebird_dualdig4_rev2_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_dvico_mce_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dvico_mce_table),
- .rc_query = cxusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_dvico_mce_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dvico_mce_table),
+ .rc_query = cxusb_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1895,10 +1913,12 @@ static struct dvb_usb_device_properties cxusb_d680_dmb_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_d680_dmb_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_d680_dmb_table),
- .rc_query = cxusb_d680_dmb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_d680_dmb_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table),
+ .rc_query = cxusb_d680_dmb_rc_query,
+ },
.num_device_descs = 1,
.devices = {
@@ -1944,10 +1964,12 @@ static struct dvb_usb_device_properties cxusb_mygica_d689_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .rc_interval = 100,
- .rc_key_map = ir_codes_d680_dmb_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_d680_dmb_table),
- .rc_query = cxusb_d680_dmb_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_d680_dmb_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_d680_dmb_table),
+ .rc_query = cxusb_d680_dmb_rc_query,
+ },
.num_device_descs = 1,
.devices = {
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 83fc24a6c31a..3537d65c04bc 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -60,6 +60,7 @@ extern int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
extern struct i2c_algorithm dib0700_i2c_algo;
extern int dib0700_identify_state(struct usb_device *udev, struct dvb_usb_device_properties *props,
struct dvb_usb_device_description **desc, int *cold);
+extern int dib0700_change_protocol(struct rc_dev *dev, u64 rc_type);
extern int dib0700_device_count;
extern int dvb_usb_dib0700_ir_proto;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index 4f961d2d1817..98ffb40728e3 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,10 +13,6 @@ int dvb_usb_dib0700_debug;
module_param_named(debug,dvb_usb_dib0700_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=fw,4=fwdata,8=data (or-able))." DVB_USB_DEBUG_STATUS);
-int dvb_usb_dib0700_ir_proto = 1;
-module_param(dvb_usb_dib0700_ir_proto, int, 0644);
-MODULE_PARM_DESC(dvb_usb_dib0700_ir_proto, "set ir protocol (0=NEC, 1=RC5 (default), 2=RC6).");
-
static int nb_packet_buffer_size = 21;
module_param(nb_packet_buffer_size, int, 0644);
MODULE_PARM_DESC(nb_packet_buffer_size,
@@ -53,7 +49,7 @@ static int dib0700_ctrl_wr(struct dvb_usb_device *d, u8 *tx, u8 txlen)
int status;
deb_data(">>> ");
- debug_dump(tx,txlen,deb_data);
+ debug_dump(tx, txlen, deb_data);
status = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev,0),
tx[0], USB_TYPE_VENDOR | USB_DIR_OUT, 0, 0, tx, txlen,
@@ -98,7 +94,7 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
deb_info("ep 0 read error (status = %d)\n",status);
deb_data("<<< ");
- debug_dump(rx,rxlen,deb_data);
+ debug_dump(rx, rxlen, deb_data);
return status; /* length in case of success */
}
@@ -106,28 +102,29 @@ int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen
int dib0700_set_gpio(struct dvb_usb_device *d, enum dib07x0_gpios gpio, u8 gpio_dir, u8 gpio_val)
{
u8 buf[3] = { REQUEST_SET_GPIO, gpio, ((gpio_dir & 0x01) << 7) | ((gpio_val & 0x01) << 6) };
- return dib0700_ctrl_wr(d,buf,3);
+ return dib0700_ctrl_wr(d, buf, sizeof(buf));
}
static int dib0700_set_usb_xfer_len(struct dvb_usb_device *d, u16 nb_ts_packets)
{
- struct dib0700_state *st = d->priv;
- u8 b[3];
- int ret;
-
- if (st->fw_version >= 0x10201) {
- b[0] = REQUEST_SET_USB_XFER_LEN;
- b[1] = (nb_ts_packets >> 8)&0xff;
- b[2] = nb_ts_packets & 0xff;
-
- deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
-
- ret = dib0700_ctrl_wr(d, b, 3);
- } else {
- deb_info("this firmware does not allow to change the USB xfer len\n");
- ret = -EIO;
- }
- return ret;
+ struct dib0700_state *st = d->priv;
+ u8 b[3];
+ int ret;
+
+ if (st->fw_version >= 0x10201) {
+ b[0] = REQUEST_SET_USB_XFER_LEN;
+ b[1] = (nb_ts_packets >> 8) & 0xff;
+ b[2] = nb_ts_packets & 0xff;
+
+ deb_info("set the USB xfer len to %i Ts packet\n", nb_ts_packets);
+
+ ret = dib0700_ctrl_wr(d, b, sizeof(b));
+ } else {
+ deb_info("this firmware does not allow to change the USB xfer len\n");
+ ret = -EIO;
+ }
+
+ return ret;
}
/*
@@ -178,7 +175,8 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
value = ((en_start << 7) | (en_stop << 6) |
(msg[i].len & 0x3F)) << 8 | i2c_dest;
/* I2C ctrl + FE bus; */
- index = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+ index = ((gen_mode << 6) & 0xC0) |
+ ((bus_mode << 4) & 0x30);
result = usb_control_msg(d->udev,
usb_rcvctrlpipe(d->udev, 0),
@@ -198,11 +196,12 @@ static int dib0700_i2c_xfer_new(struct i2c_adapter *adap, struct i2c_msg *msg,
} else {
/* Write request */
buf[0] = REQUEST_NEW_I2C_WRITE;
- buf[1] = (msg[i].addr << 1);
+ buf[1] = msg[i].addr << 1;
buf[2] = (en_start << 7) | (en_stop << 6) |
(msg[i].len & 0x3F);
/* I2C ctrl + FE bus; */
- buf[3] = ((gen_mode<<6)&0xC0) | ((bus_mode<<4)&0x30);
+ buf[3] = ((gen_mode << 6) & 0xC0) |
+ ((bus_mode << 4) & 0x30);
/* The Actual i2c payload */
memcpy(&buf[4], msg[i].buf, msg[i].len);
@@ -240,7 +239,7 @@ static int dib0700_i2c_xfer_legacy(struct i2c_adapter *adap,
for (i = 0; i < num; i++) {
/* fill in the address */
- buf[1] = (msg[i].addr << 1);
+ buf[1] = msg[i].addr << 1;
/* fill the buffer */
memcpy(&buf[2], msg[i].buf, msg[i].len);
@@ -368,7 +367,8 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
u8 buf[260];
while ((ret = dvb_usb_get_hexline(fw, &hx, &pos)) > 0) {
- deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",hx.addr, hx.len, hx.chk);
+ deb_fwdata("writing to address 0x%08x (buffer: 0x%02x %02x)\n",
+ hx.addr, hx.len, hx.chk);
buf[0] = hx.len;
buf[1] = (hx.addr >> 8) & 0xff;
@@ -408,16 +408,16 @@ int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw
REQUEST_GET_VERSION,
USB_TYPE_VENDOR | USB_DIR_IN, 0, 0,
b, sizeof(b), USB_CTRL_GET_TIMEOUT);
- fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
+ fw_version = (b[8] << 24) | (b[9] << 16) | (b[10] << 8) | b[11];
/* set the buffer size - DVB-USB is allocating URB buffers
* only after the firwmare download was successful */
for (i = 0; i < dib0700_device_count; i++) {
for (adap_num = 0; adap_num < dib0700_devices[i].num_adapters;
adap_num++) {
- if (fw_version >= 0x10201)
+ if (fw_version >= 0x10201) {
dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = 188*nb_packet_buffer_size;
- else {
+ } else {
/* for fw version older than 1.20.1,
* the buffersize has to be n times 512 */
dib0700_devices[i].adapter[adap_num].stream.u.bulk.buffersize = ((188*nb_packet_buffer_size+188/2)/512)*512;
@@ -453,7 +453,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
if (st->disable_streaming_master_mode == 1)
b[2] = 0x00;
else
- b[2] = (0x01 << 4); /* Master mode */
+ b[2] = 0x01 << 4; /* Master mode */
b[3] = 0x00;
@@ -466,11 +466,44 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
b[2] |= st->channel_state;
- deb_info("data for streaming: %x %x\n",b[1],b[2]);
+ deb_info("data for streaming: %x %x\n", b[1], b[2]);
return dib0700_ctrl_wr(adap->dev, b, 4);
}
+int dib0700_change_protocol(struct rc_dev *rc, u64 rc_type)
+{
+ struct dvb_usb_device *d = rc->priv;
+ struct dib0700_state *st = d->priv;
+ u8 rc_setup[3] = { REQUEST_SET_RC, 0, 0 };
+ int new_proto, ret;
+
+ /* Set the IR mode */
+ if (rc_type == RC_TYPE_RC5)
+ new_proto = 1;
+ else if (rc_type == RC_TYPE_NEC)
+ new_proto = 0;
+ else if (rc_type == RC_TYPE_RC6) {
+ if (st->fw_version < 0x10200)
+ return -EINVAL;
+
+ new_proto = 2;
+ } else
+ return -EINVAL;
+
+ rc_setup[1] = new_proto;
+
+ ret = dib0700_ctrl_wr(d, rc_setup, sizeof(rc_setup));
+ if (ret < 0) {
+ err("ir protocol setup failed");
+ return ret;
+ }
+
+ d->props.rc.core.protocol = rc_type;
+
+ return ret;
+}
+
/* Number of keypresses to ignore before start repeating */
#define RC_REPEAT_DELAY_V1_20 10
@@ -478,7 +511,13 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
struct dib0700_rc_response {
u8 report_id;
u8 data_state;
- u16 system;
+ union {
+ u16 system16;
+ struct {
+ u8 not_system;
+ u8 system;
+ };
+ };
u8 data;
u8 not_data;
};
@@ -487,28 +526,23 @@ struct dib0700_rc_response {
static void dib0700_rc_urb_completion(struct urb *purb)
{
struct dvb_usb_device *d = purb->context;
- struct dvb_usb_rc_key *keymap;
struct dib0700_state *st;
- struct dib0700_rc_response poll_reply;
- u8 *buf;
- int found = 0;
- u32 event;
- int state;
- int i;
+ struct dib0700_rc_response *poll_reply;
+ u32 uninitialized_var(keycode);
+ u8 toggle;
deb_info("%s()\n", __func__);
if (d == NULL)
return;
- if (d->rc_input_dev == NULL) {
+ if (d->rc_dev == NULL) {
/* This will occur if disable_rc_polling=1 */
usb_free_urb(purb);
return;
}
- keymap = d->props.rc_key_map;
st = d->priv;
- buf = (u8 *)purb->transfer_buffer;
+ poll_reply = purb->transfer_buffer;
if (purb->status < 0) {
deb_info("discontinuing polling\n");
@@ -521,104 +555,52 @@ static void dib0700_rc_urb_completion(struct urb *purb)
goto resubmit;
}
- /* Set initial results in case we exit the function early */
- event = 0;
- state = REMOTE_NO_KEY_PRESSED;
-
- deb_data("IR raw %02X %02X %02X %02X %02X %02X (len %d)\n", buf[0],
- buf[1], buf[2], buf[3], buf[4], buf[5], purb->actual_length);
+ deb_data("IR ID = %02X state = %02X System = %02X %02X Cmd = %02X %02X (len %d)\n",
+ poll_reply->report_id, poll_reply->data_state,
+ poll_reply->system, poll_reply->not_system,
+ poll_reply->data, poll_reply->not_data,
+ purb->actual_length);
- switch (dvb_usb_dib0700_ir_proto) {
- case 0:
- /* NEC Protocol */
- poll_reply.report_id = 0;
- poll_reply.data_state = 1;
- poll_reply.system = buf[2];
- poll_reply.data = buf[4];
- poll_reply.not_data = buf[5];
+ switch (d->props.rc.core.protocol) {
+ case RC_TYPE_NEC:
+ toggle = 0;
/* NEC protocol sends repeat code as 0 0 0 FF */
- if ((poll_reply.system == 0x00) && (poll_reply.data == 0x00)
- && (poll_reply.not_data == 0xff)) {
- poll_reply.data_state = 2;
+ if ((poll_reply->system == 0x00) && (poll_reply->data == 0x00)
+ && (poll_reply->not_data == 0xff)) {
+ poll_reply->data_state = 2;
break;
}
+
+ if ((poll_reply->system ^ poll_reply->not_system) != 0xff) {
+ deb_data("NEC extended protocol\n");
+ /* NEC extended code - 24 bits */
+ keycode = be16_to_cpu(poll_reply->system16) << 8 | poll_reply->data;
+ } else {
+ deb_data("NEC normal protocol\n");
+ /* normal NEC code - 16 bits */
+ keycode = poll_reply->system << 8 | poll_reply->data;
+ }
+
break;
default:
+ deb_data("RC5 protocol\n");
/* RC5 Protocol */
- poll_reply.report_id = buf[0];
- poll_reply.data_state = buf[1];
- poll_reply.system = (buf[2] << 8) | buf[3];
- poll_reply.data = buf[4];
- poll_reply.not_data = buf[5];
+ toggle = poll_reply->report_id;
+ keycode = poll_reply->system << 8 | poll_reply->data;
+
break;
}
- if ((poll_reply.data + poll_reply.not_data) != 0xff) {
+ if ((poll_reply->data + poll_reply->not_data) != 0xff) {
/* Key failed integrity check */
err("key failed integrity check: %04x %02x %02x",
- poll_reply.system,
- poll_reply.data, poll_reply.not_data);
- goto resubmit;
- }
-
- deb_data("rid=%02x ds=%02x sm=%04x d=%02x nd=%02x\n",
- poll_reply.report_id, poll_reply.data_state,
- poll_reply.system, poll_reply.data, poll_reply.not_data);
-
- /* Find the key in the map */
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == (poll_reply.system & 0xff) &&
- rc5_data(&keymap[i]) == poll_reply.data) {
- event = keymap[i].event;
- found = 1;
- break;
- }
- }
-
- if (found == 0) {
- err("Unknown remote controller key: %04x %02x %02x",
- poll_reply.system, poll_reply.data, poll_reply.not_data);
- d->last_event = 0;
+ poll_reply->system,
+ poll_reply->data, poll_reply->not_data);
goto resubmit;
}
- if (poll_reply.data_state == 1) {
- /* New key hit */
- st->rc_counter = 0;
- event = keymap[i].event;
- state = REMOTE_KEY_PRESSED;
- d->last_event = keymap[i].event;
- } else if (poll_reply.data_state == 2) {
- /* Key repeated */
- st->rc_counter++;
-
- /* prevents unwanted double hits */
- if (st->rc_counter > RC_REPEAT_DELAY_V1_20) {
- event = d->last_event;
- state = REMOTE_KEY_PRESSED;
- st->rc_counter = RC_REPEAT_DELAY_V1_20;
- }
- } else {
- err("Unknown data state [%d]", poll_reply.data_state);
- }
-
- switch (state) {
- case REMOTE_NO_KEY_PRESSED:
- break;
- case REMOTE_KEY_PRESSED:
- deb_info("key pressed\n");
- d->last_event = event;
- case REMOTE_KEY_REPEAT:
- deb_info("key repeated\n");
- input_event(d->rc_input_dev, EV_KEY, event, 1);
- input_sync(d->rc_input_dev);
- input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
- input_sync(d->rc_input_dev);
- break;
- default:
- break;
- }
+ rc_keydown(d->rc_dev, keycode, toggle);
resubmit:
/* Clean the buffer before we requeue */
@@ -631,21 +613,10 @@ resubmit:
int dib0700_rc_setup(struct dvb_usb_device *d)
{
struct dib0700_state *st = d->priv;
- u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
struct urb *purb;
int ret;
- int i;
-
- if (d->props.rc_key_map == NULL)
- return 0;
-
- /* Set the IR mode */
- i = dib0700_ctrl_wr(d, rc_setup, 3);
- if (i<0) {
- err("ir protocol setup failed");
- return -1;
- }
+ /* Poll-based. Don't initialize bulk mode */
if (st->fw_version < 0x10200)
return 0;
@@ -653,14 +624,14 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
purb = usb_alloc_urb(0, GFP_KERNEL);
if (purb == NULL) {
err("rc usb alloc urb failed\n");
- return -1;
+ return -ENOMEM;
}
purb->transfer_buffer = kzalloc(RC_MSG_SIZE_V1_20, GFP_KERNEL);
if (purb->transfer_buffer == NULL) {
err("rc kzalloc failed\n");
usb_free_urb(purb);
- return -1;
+ return -ENOMEM;
}
purb->status = -EINPROGRESS;
@@ -669,12 +640,10 @@ int dib0700_rc_setup(struct dvb_usb_device *d)
dib0700_rc_urb_completion, d);
ret = usb_submit_urb(purb, GFP_ATOMIC);
- if (ret != 0) {
+ if (ret)
err("rc submit urb failed\n");
- return -1;
- }
- return 0;
+ return ret;
}
static int dib0700_probe(struct usb_interface *intf,
@@ -698,6 +667,12 @@ static int dib0700_probe(struct usb_interface *intf,
st->fw_version = fw_version;
st->nb_packet_buffer_size = (u32)nb_packet_buffer_size;
+ /* Disable polling mode on newer firmwares */
+ if (st->fw_version >= 0x10200)
+ dev->props.rc.core.bulk_mode = true;
+ else
+ dev->props.rc.core.bulk_mode = false;
+
dib0700_rc_setup(dev);
return 0;
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index 800800a9649e..defd83964ce2 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -473,16 +473,19 @@ static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
/* Number of keypresses to ignore before start repeating */
#define RC_REPEAT_DELAY 6
-static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
+/*
+ * This function is used only when firmware is < 1.20 version. Newer
+ * firmwares use bulk mode, with functions implemented at dib0700_core,
+ * at dib0700_rc_urb_completion()
+ */
+static int dib0700_rc_query_old_firmware(struct dvb_usb_device *d)
{
u8 key[4];
+ u32 keycode;
+ u8 toggle;
int i;
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
struct dib0700_state *st = d->priv;
- *event = 0;
- *state = REMOTE_NO_KEY_PRESSED;
-
if (st->fw_version >= 0x10200) {
/* For 1.20 firmware , We need to keep the RC polling
callback so we can reuse the input device setup in
@@ -491,348 +494,45 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
- i=dib0700_ctrl_rd(d,rc_request,2,key,4);
- if (i<=0) {
+ i = dib0700_ctrl_rd(d, rc_request, 2, key, 4);
+ if (i <= 0) {
err("RC Query Failed");
return -1;
}
/* losing half of KEY_0 events from Philipps rc5 remotes.. */
- if (key[0]==0 && key[1]==0 && key[2]==0 && key[3]==0) return 0;
+ if (key[0] == 0 && key[1] == 0 && key[2] == 0 && key[3] == 0)
+ return 0;
/* info("%d: %2X %2X %2X %2X",dvb_usb_dib0700_ir_proto,(int)key[3-2],(int)key[3-3],(int)key[3-1],(int)key[3]); */
dib0700_rc_setup(d); /* reset ir sensor data to prevent false events */
- switch (dvb_usb_dib0700_ir_proto) {
- case 0: {
+ d->last_event = 0;
+ switch (d->props.rc.core.protocol) {
+ case RC_TYPE_NEC:
/* NEC protocol sends repeat code as 0 0 0 FF */
if ((key[3-2] == 0x00) && (key[3-3] == 0x00) &&
- (key[3] == 0xFF)) {
- st->rc_counter++;
- if (st->rc_counter > RC_REPEAT_DELAY) {
- *event = d->last_event;
- *state = REMOTE_KEY_PRESSED;
- st->rc_counter = RC_REPEAT_DELAY;
- }
- return 0;
- }
- for (i=0;i<d->props.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == key[3-2] &&
- rc5_data(&keymap[i]) == key[3-3]) {
- st->rc_counter = 0;
- *event = keymap[i].event;
- *state = REMOTE_KEY_PRESSED;
- d->last_event = keymap[i].event;
- return 0;
- }
+ (key[3] == 0xff))
+ keycode = d->last_event;
+ else {
+ keycode = key[3-2] << 8 | key[3-3];
+ d->last_event = keycode;
}
+
+ rc_keydown(d->rc_dev, keycode, 0);
break;
- }
- default: {
+ default:
/* RC-5 protocol changes toggle bit on new keypress */
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (rc5_custom(&keymap[i]) == key[3-2] &&
- rc5_data(&keymap[i]) == key[3-3]) {
- if (d->last_event == keymap[i].event &&
- key[3-1] == st->rc_toggle) {
- st->rc_counter++;
- /* prevents unwanted double hits */
- if (st->rc_counter > RC_REPEAT_DELAY) {
- *event = d->last_event;
- *state = REMOTE_KEY_PRESSED;
- st->rc_counter = RC_REPEAT_DELAY;
- }
-
- return 0;
- }
- st->rc_counter = 0;
- *event = keymap[i].event;
- *state = REMOTE_KEY_PRESSED;
- st->rc_toggle = key[3-1];
- d->last_event = keymap[i].event;
- return 0;
- }
- }
+ keycode = key[3-2] << 8 | key[3-3];
+ toggle = key[3-1];
+ rc_keydown(d->rc_dev, keycode, toggle);
+
break;
}
- }
- err("Unknown remote controller key: %2X %2X %2X %2X", (int) key[3-2], (int) key[3-3], (int) key[3-1], (int) key[3]);
- d->last_event = 0;
return 0;
}
-static struct dvb_usb_rc_key ir_codes_dib0700_table[] = {
- /* Key codes for the tiny Pinnacle remote*/
- { 0x0700, KEY_MUTE },
- { 0x0701, KEY_MENU }, /* Pinnacle logo */
- { 0x0739, KEY_POWER },
- { 0x0703, KEY_VOLUMEUP },
- { 0x0709, KEY_VOLUMEDOWN },
- { 0x0706, KEY_CHANNELUP },
- { 0x070c, KEY_CHANNELDOWN },
- { 0x070f, KEY_1 },
- { 0x0715, KEY_2 },
- { 0x0710, KEY_3 },
- { 0x0718, KEY_4 },
- { 0x071b, KEY_5 },
- { 0x071e, KEY_6 },
- { 0x0711, KEY_7 },
- { 0x0721, KEY_8 },
- { 0x0712, KEY_9 },
- { 0x0727, KEY_0 },
- { 0x0724, KEY_SCREEN }, /* 'Square' key */
- { 0x072a, KEY_TEXT }, /* 'T' key */
- { 0x072d, KEY_REWIND },
- { 0x0730, KEY_PLAY },
- { 0x0733, KEY_FASTFORWARD },
- { 0x0736, KEY_RECORD },
- { 0x073c, KEY_STOP },
- { 0x073f, KEY_CANCEL }, /* '?' key */
- /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
- { 0xeb01, KEY_POWER },
- { 0xeb02, KEY_1 },
- { 0xeb03, KEY_2 },
- { 0xeb04, KEY_3 },
- { 0xeb05, KEY_4 },
- { 0xeb06, KEY_5 },
- { 0xeb07, KEY_6 },
- { 0xeb08, KEY_7 },
- { 0xeb09, KEY_8 },
- { 0xeb0a, KEY_9 },
- { 0xeb0b, KEY_VIDEO },
- { 0xeb0c, KEY_0 },
- { 0xeb0d, KEY_REFRESH },
- { 0xeb0f, KEY_EPG },
- { 0xeb10, KEY_UP },
- { 0xeb11, KEY_LEFT },
- { 0xeb12, KEY_OK },
- { 0xeb13, KEY_RIGHT },
- { 0xeb14, KEY_DOWN },
- { 0xeb16, KEY_INFO },
- { 0xeb17, KEY_RED },
- { 0xeb18, KEY_GREEN },
- { 0xeb19, KEY_YELLOW },
- { 0xeb1a, KEY_BLUE },
- { 0xeb1b, KEY_CHANNELUP },
- { 0xeb1c, KEY_VOLUMEUP },
- { 0xeb1d, KEY_MUTE },
- { 0xeb1e, KEY_VOLUMEDOWN },
- { 0xeb1f, KEY_CHANNELDOWN },
- { 0xeb40, KEY_PAUSE },
- { 0xeb41, KEY_HOME },
- { 0xeb42, KEY_MENU }, /* DVD Menu */
- { 0xeb43, KEY_SUBTITLE },
- { 0xeb44, KEY_TEXT }, /* Teletext */
- { 0xeb45, KEY_DELETE },
- { 0xeb46, KEY_TV },
- { 0xeb47, KEY_DVD },
- { 0xeb48, KEY_STOP },
- { 0xeb49, KEY_VIDEO },
- { 0xeb4a, KEY_AUDIO }, /* Music */
- { 0xeb4b, KEY_SCREEN }, /* Pic */
- { 0xeb4c, KEY_PLAY },
- { 0xeb4d, KEY_BACK },
- { 0xeb4e, KEY_REWIND },
- { 0xeb4f, KEY_FASTFORWARD },
- { 0xeb54, KEY_PREVIOUS },
- { 0xeb58, KEY_RECORD },
- { 0xeb5c, KEY_NEXT },
-
- /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
- { 0x1e00, KEY_0 },
- { 0x1e01, KEY_1 },
- { 0x1e02, KEY_2 },
- { 0x1e03, KEY_3 },
- { 0x1e04, KEY_4 },
- { 0x1e05, KEY_5 },
- { 0x1e06, KEY_6 },
- { 0x1e07, KEY_7 },
- { 0x1e08, KEY_8 },
- { 0x1e09, KEY_9 },
- { 0x1e0a, KEY_KPASTERISK },
- { 0x1e0b, KEY_RED },
- { 0x1e0c, KEY_RADIO },
- { 0x1e0d, KEY_MENU },
- { 0x1e0e, KEY_GRAVE }, /* # */
- { 0x1e0f, KEY_MUTE },
- { 0x1e10, KEY_VOLUMEUP },
- { 0x1e11, KEY_VOLUMEDOWN },
- { 0x1e12, KEY_CHANNEL },
- { 0x1e14, KEY_UP },
- { 0x1e15, KEY_DOWN },
- { 0x1e16, KEY_LEFT },
- { 0x1e17, KEY_RIGHT },
- { 0x1e18, KEY_VIDEO },
- { 0x1e19, KEY_AUDIO },
- { 0x1e1a, KEY_MEDIA },
- { 0x1e1b, KEY_EPG },
- { 0x1e1c, KEY_TV },
- { 0x1e1e, KEY_NEXT },
- { 0x1e1f, KEY_BACK },
- { 0x1e20, KEY_CHANNELUP },
- { 0x1e21, KEY_CHANNELDOWN },
- { 0x1e24, KEY_LAST }, /* Skip backwards */
- { 0x1e25, KEY_OK },
- { 0x1e29, KEY_BLUE},
- { 0x1e2e, KEY_GREEN },
- { 0x1e30, KEY_PAUSE },
- { 0x1e32, KEY_REWIND },
- { 0x1e34, KEY_FASTFORWARD },
- { 0x1e35, KEY_PLAY },
- { 0x1e36, KEY_STOP },
- { 0x1e37, KEY_RECORD },
- { 0x1e38, KEY_YELLOW },
- { 0x1e3b, KEY_GOTO },
- { 0x1e3d, KEY_POWER },
-
- /* Key codes for the Leadtek Winfast DTV Dongle */
- { 0x0042, KEY_POWER },
- { 0x077c, KEY_TUNER },
- { 0x0f4e, KEY_PRINT }, /* PREVIEW */
- { 0x0840, KEY_SCREEN }, /* full screen toggle*/
- { 0x0f71, KEY_DOT }, /* frequency */
- { 0x0743, KEY_0 },
- { 0x0c41, KEY_1 },
- { 0x0443, KEY_2 },
- { 0x0b7f, KEY_3 },
- { 0x0e41, KEY_4 },
- { 0x0643, KEY_5 },
- { 0x097f, KEY_6 },
- { 0x0d7e, KEY_7 },
- { 0x057c, KEY_8 },
- { 0x0a40, KEY_9 },
- { 0x0e4e, KEY_CLEAR },
- { 0x047c, KEY_CHANNEL }, /* show channel number */
- { 0x0f41, KEY_LAST }, /* recall */
- { 0x0342, KEY_MUTE },
- { 0x064c, KEY_RESERVED }, /* PIP button*/
- { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
- { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
- { 0x0b70, KEY_RECORD },
- { 0x037d, KEY_VOLUMEUP },
- { 0x017d, KEY_VOLUMEDOWN },
- { 0x0242, KEY_CHANNELUP },
- { 0x007d, KEY_CHANNELDOWN },
-
- /* Key codes for Nova-TD "credit card" remote control. */
- { 0x1d00, KEY_0 },
- { 0x1d01, KEY_1 },
- { 0x1d02, KEY_2 },
- { 0x1d03, KEY_3 },
- { 0x1d04, KEY_4 },
- { 0x1d05, KEY_5 },
- { 0x1d06, KEY_6 },
- { 0x1d07, KEY_7 },
- { 0x1d08, KEY_8 },
- { 0x1d09, KEY_9 },
- { 0x1d0a, KEY_TEXT },
- { 0x1d0d, KEY_MENU },
- { 0x1d0f, KEY_MUTE },
- { 0x1d10, KEY_VOLUMEUP },
- { 0x1d11, KEY_VOLUMEDOWN },
- { 0x1d12, KEY_CHANNEL },
- { 0x1d14, KEY_UP },
- { 0x1d15, KEY_DOWN },
- { 0x1d16, KEY_LEFT },
- { 0x1d17, KEY_RIGHT },
- { 0x1d1c, KEY_TV },
- { 0x1d1e, KEY_NEXT },
- { 0x1d1f, KEY_BACK },
- { 0x1d20, KEY_CHANNELUP },
- { 0x1d21, KEY_CHANNELDOWN },
- { 0x1d24, KEY_LAST },
- { 0x1d25, KEY_OK },
- { 0x1d30, KEY_PAUSE },
- { 0x1d32, KEY_REWIND },
- { 0x1d34, KEY_FASTFORWARD },
- { 0x1d35, KEY_PLAY },
- { 0x1d36, KEY_STOP },
- { 0x1d37, KEY_RECORD },
- { 0x1d3b, KEY_GOTO },
- { 0x1d3d, KEY_POWER },
-
- /* Key codes for the Pixelview SBTVD remote (proto NEC) */
- { 0x8613, KEY_MUTE },
- { 0x8612, KEY_POWER },
- { 0x8601, KEY_1 },
- { 0x8602, KEY_2 },
- { 0x8603, KEY_3 },
- { 0x8604, KEY_4 },
- { 0x8605, KEY_5 },
- { 0x8606, KEY_6 },
- { 0x8607, KEY_7 },
- { 0x8608, KEY_8 },
- { 0x8609, KEY_9 },
- { 0x8600, KEY_0 },
- { 0x860d, KEY_CHANNELUP },
- { 0x8619, KEY_CHANNELDOWN },
- { 0x8610, KEY_VOLUMEUP },
- { 0x860c, KEY_VOLUMEDOWN },
-
- { 0x860a, KEY_CAMERA },
- { 0x860b, KEY_ZOOM },
- { 0x861b, KEY_BACKSPACE },
- { 0x8615, KEY_ENTER },
-
- { 0x861d, KEY_UP },
- { 0x861e, KEY_DOWN },
- { 0x860e, KEY_LEFT },
- { 0x860f, KEY_RIGHT },
-
- { 0x8618, KEY_RECORD },
- { 0x861a, KEY_STOP },
-
- /* Key codes for the EvolutePC TVWay+ remote (proto NEC) */
- { 0x7a00, KEY_MENU },
- { 0x7a01, KEY_RECORD },
- { 0x7a02, KEY_PLAY },
- { 0x7a03, KEY_STOP },
- { 0x7a10, KEY_CHANNELUP },
- { 0x7a11, KEY_CHANNELDOWN },
- { 0x7a12, KEY_VOLUMEUP },
- { 0x7a13, KEY_VOLUMEDOWN },
- { 0x7a40, KEY_POWER },
- { 0x7a41, KEY_MUTE },
-
- /* Key codes for the Elgato EyeTV Diversity silver remote,
- set dvb_usb_dib0700_ir_proto=0 */
- { 0x4501, KEY_POWER },
- { 0x4502, KEY_MUTE },
- { 0x4503, KEY_1 },
- { 0x4504, KEY_2 },
- { 0x4505, KEY_3 },
- { 0x4506, KEY_4 },
- { 0x4507, KEY_5 },
- { 0x4508, KEY_6 },
- { 0x4509, KEY_7 },
- { 0x450a, KEY_8 },
- { 0x450b, KEY_9 },
- { 0x450c, KEY_LAST },
- { 0x450d, KEY_0 },
- { 0x450e, KEY_ENTER },
- { 0x450f, KEY_RED },
- { 0x4510, KEY_CHANNELUP },
- { 0x4511, KEY_GREEN },
- { 0x4512, KEY_VOLUMEDOWN },
- { 0x4513, KEY_OK },
- { 0x4514, KEY_VOLUMEUP },
- { 0x4515, KEY_YELLOW },
- { 0x4516, KEY_CHANNELDOWN },
- { 0x4517, KEY_BLUE },
- { 0x4518, KEY_LEFT }, /* Skip backwards */
- { 0x4519, KEY_PLAYPAUSE },
- { 0x451a, KEY_RIGHT }, /* Skip forward */
- { 0x451b, KEY_REWIND },
- { 0x451c, KEY_L }, /* Live */
- { 0x451d, KEY_FASTFORWARD },
- { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
- { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
- { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
- { 0x4541, KEY_SCREEN }, /* Full screen toggle, 'Hold' for Teletext */
- { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
-};
-
/* STK7700P: Hauppauge Nova-T Stick, AVerMedia Volar */
static struct dibx000_agc_config stk7700p_7000m_mt2060_agc_config = {
BAND_UHF | BAND_VHF,
@@ -1240,6 +940,58 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
return adap->fe == NULL ? -ENODEV : 0;
}
+/* STK7770P */
+static struct dib7000p_config dib7770p_dib7000p_config = {
+ .output_mpeg2_in_188_bytes = 1,
+
+ .agc_config_count = 1,
+ .agc = &dib7070_agc_config,
+ .bw = &dib7070_bw_config_12_mhz,
+ .tuner_is_baseband = 1,
+ .spur_protect = 1,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+
+ .hostbus_diversity = 1,
+ .enable_current_mirror = 1,
+ .disable_sample_and_hold = 0,
+};
+
+static int stk7770p_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct usb_device_descriptor *p = &adap->dev->udev->descriptor;
+ if (p->idVendor == cpu_to_le16(USB_VID_PINNACLE) &&
+ p->idProduct == cpu_to_le16(USB_PID_PINNACLE_PCTV72E))
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+ else
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO9, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO4, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO7, GPIO_OUT, 1);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 0);
+
+ dib0700_ctrl_clock(adap->dev, 72, 1);
+
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+
+ if (dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ &dib7770p_dib7000p_config) != 0) {
+ err("%s: dib7000p_i2c_enumeration failed. Cannot continue\n",
+ __func__);
+ return -ENODEV;
+ }
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ &dib7770p_dib7000p_config);
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
/* DIB807x generic */
static struct dibx000_agc_config dib807x_agc_config[2] = {
{
@@ -2081,7 +1833,7 @@ struct usb_device_id dib0700_usb_id_table[] = {
/* 60 */{ USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS_2) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XPVR) },
{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK807XP) },
- { USB_DEVICE(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD) },
+ { USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x000, 0x3f00) },
{ USB_DEVICE(USB_VID_EVOLUTEPC, USB_PID_TVWAY_PLUS) },
/* 65 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73ESE) },
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV282E) },
@@ -2168,10 +1920,15 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -2197,10 +1954,15 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -2251,11 +2013,15 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
-
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2288,10 +2054,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2358,11 +2130,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
-
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2397,11 +2174,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
-
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
@@ -2431,7 +2213,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
}
},
- .num_device_descs = 7,
+ .num_device_descs = 6,
.devices = {
{ "DiBcom STK7070PD reference design",
{ &dib0700_usb_id_table[17], NULL },
@@ -2458,15 +2240,65 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[44], NULL },
{ NULL },
},
+ },
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 2,
+ .adapter = {
+ {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk70x0p_pid_filter,
+ .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+ .frontend_attach = stk7070pd_frontend_attach0,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }, {
+ .caps = DVB_USB_ADAP_HAS_PID_FILTER | DVB_USB_ADAP_PID_FILTER_CAN_BE_TURNED_OFF,
+ .pid_filter_count = 32,
+ .pid_filter = stk70x0p_pid_filter,
+ .pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
+ .frontend_attach = stk7070pd_frontend_attach1,
+ .tuner_attach = dib7070p_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x03),
+
+ .size_of_priv = sizeof(struct dib0700_adapter_state),
+ }
+ },
+
+ .num_device_descs = 1,
+ .devices = {
{ "Elgato EyeTV Diversity",
{ &dib0700_usb_id_table[68], NULL },
{ NULL },
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_NEC_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
@@ -2525,10 +2357,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
@@ -2554,10 +2393,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
@@ -2592,7 +2438,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
.pid_filter_count = 32,
.pid_filter = stk70x0p_pid_filter,
.pid_filter_ctrl = stk70x0p_pid_filter_ctrl,
- .frontend_attach = stk7070p_frontend_attach,
+ .frontend_attach = stk7770p_frontend_attach,
.tuner_attach = dib7770p_tuner_attach,
DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
@@ -2615,10 +2461,17 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
@@ -2653,11 +2506,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
-
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_NEC_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 2,
.adapter = {
@@ -2697,10 +2555,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
.num_adapters = 1,
.adapter = {
@@ -2728,10 +2592,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dib0700_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dib0700_table),
- .rc_query = dib0700_rc_query
+ .rc.core = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_codes = RC_MAP_DIB0700_RC5_TABLE,
+ .module_name = "dib0700",
+ .rc_query = dib0700_rc_query_old_firmware,
+ .allowed_protos = RC_TYPE_RC5 |
+ RC_TYPE_RC6 |
+ RC_TYPE_NEC,
+ .change_protocol = dib0700_change_protocol,
+ },
},
};
diff --git a/drivers/media/dvb/dvb-usb/dibusb-common.c b/drivers/media/dvb/dvb-usb/dibusb-common.c
index bc08bc0b723c..956f7ae2e510 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-common.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-common.c
@@ -327,7 +327,7 @@ EXPORT_SYMBOL(dibusb_dib3000mc_tuner_attach);
/*
* common remote control stuff
*/
-struct dvb_usb_rc_key ir_codes_dibusb_table[] = {
+struct rc_map_table rc_map_dibusb_table[] = {
/* Key codes for the little Artec T1/Twinhan/HAMA/ remote. */
{ 0x0016, KEY_POWER },
{ 0x0010, KEY_MUTE },
@@ -456,7 +456,7 @@ struct dvb_usb_rc_key ir_codes_dibusb_table[] = {
{ 0x804e, KEY_ENTER },
{ 0x804f, KEY_VOLUMEDOWN },
};
-EXPORT_SYMBOL(ir_codes_dibusb_table);
+EXPORT_SYMBOL(rc_map_dibusb_table);
int dibusb_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mb.c b/drivers/media/dvb/dvb-usb/dibusb-mb.c
index eb2e6f050fbe..04d91bdd3562 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mb.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mb.c
@@ -211,10 +211,12 @@ static struct dvb_usb_device_properties dibusb1_1_properties = {
.power_ctrl = dibusb_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
@@ -295,10 +297,12 @@ static struct dvb_usb_device_properties dibusb1_1_an2235_properties = {
},
.power_ctrl = dibusb_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
@@ -359,10 +363,12 @@ static struct dvb_usb_device_properties dibusb2_0b_properties = {
},
.power_ctrl = dibusb2_0_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
@@ -416,10 +422,12 @@ static struct dvb_usb_device_properties artec_t1_usb2_properties = {
},
.power_ctrl = dibusb2_0_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* wow, that is ugly ... I want to load it to the driver dynamically */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dibusb-mc.c b/drivers/media/dvb/dvb-usb/dibusb-mc.c
index 588308eb6638..c1d9094b61e5 100644
--- a/drivers/media/dvb/dvb-usb/dibusb-mc.c
+++ b/drivers/media/dvb/dvb-usb/dibusb-mc.c
@@ -81,10 +81,12 @@ static struct dvb_usb_device_properties dibusb_mc_properties = {
},
.power_ctrl = dibusb2_0_power_ctrl,
- .rc_interval = DEFAULT_RC_INTERVAL,
- .rc_key_map = ir_codes_dibusb_table,
- .rc_key_map_size = 111, /* FIXME */
- .rc_query = dibusb_rc_query,
+ .rc.legacy = {
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_map_table = rc_map_dibusb_table,
+ .rc_map_size = 111, /* FIXME */
+ .rc_query = dibusb_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dibusb.h b/drivers/media/dvb/dvb-usb/dibusb.h
index 3d50ac59088f..e47c321b3ffc 100644
--- a/drivers/media/dvb/dvb-usb/dibusb.h
+++ b/drivers/media/dvb/dvb-usb/dibusb.h
@@ -124,7 +124,7 @@ extern int dibusb2_0_power_ctrl(struct dvb_usb_device *, int);
#define DEFAULT_RC_INTERVAL 150
//#define DEFAULT_RC_INTERVAL 100000
-extern struct dvb_usb_rc_key ir_codes_dibusb_table[];
+extern struct rc_map_table rc_map_dibusb_table[];
extern int dibusb_rc_query(struct dvb_usb_device *, u32 *, int *);
extern int dibusb_read_eeprom_byte(struct dvb_usb_device *, u8, u8 *);
diff --git a/drivers/media/dvb/dvb-usb/digitv.c b/drivers/media/dvb/dvb-usb/digitv.c
index e826077094fa..f2dbce7edb3b 100644
--- a/drivers/media/dvb/dvb-usb/digitv.c
+++ b/drivers/media/dvb/dvb-usb/digitv.c
@@ -161,7 +161,7 @@ static int digitv_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_digitv_table[] = {
+static struct rc_map_table rc_map_digitv_table[] = {
{ 0x5f55, KEY_0 },
{ 0x6f55, KEY_1 },
{ 0x9f55, KEY_2 },
@@ -237,10 +237,10 @@ static int digitv_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
/* if something is inside the buffer, simulate key press */
if (key[1] != 0)
{
- for (i = 0; i < d->props.rc_key_map_size; i++) {
- if (rc5_custom(&d->props.rc_key_map[i]) == key[1] &&
- rc5_data(&d->props.rc_key_map[i]) == key[2]) {
- *event = d->props.rc_key_map[i].event;
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
+ if (rc5_custom(&d->props.rc.legacy.rc_map_table[i]) == key[1] &&
+ rc5_data(&d->props.rc.legacy.rc_map_table[i]) == key[2]) {
+ *event = d->props.rc.legacy.rc_map_table[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
}
@@ -310,10 +310,12 @@ static struct dvb_usb_device_properties digitv_properties = {
},
.identify_state = digitv_identify_state,
- .rc_interval = 1000,
- .rc_key_map = ir_codes_digitv_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_digitv_table),
- .rc_query = digitv_rc_query,
+ .rc.legacy = {
+ .rc_interval = 1000,
+ .rc_map_table = rc_map_digitv_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_digitv_table),
+ .rc_query = digitv_rc_query,
+ },
.i2c_algo = &digitv_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/dtt200u.c b/drivers/media/dvb/dvb-usb/dtt200u.c
index f57e59044d4d..ecd86eca2548 100644
--- a/drivers/media/dvb/dvb-usb/dtt200u.c
+++ b/drivers/media/dvb/dvb-usb/dtt200u.c
@@ -57,7 +57,7 @@ static int dtt200u_pid_filter(struct dvb_usb_adapter *adap, int index, u16 pid,
/* remote control */
/* key list for the tiny remote control (Yakumo, don't know about the others) */
-static struct dvb_usb_rc_key ir_codes_dtt200u_table[] = {
+static struct rc_map_table rc_map_dtt200u_table[] = {
{ 0x8001, KEY_MUTE },
{ 0x8002, KEY_CHANNELDOWN },
{ 0x8003, KEY_VOLUMEDOWN },
@@ -161,10 +161,12 @@ static struct dvb_usb_device_properties dtt200u_properties = {
},
.power_ctrl = dtt200u_power_ctrl,
- .rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
- .rc_query = dtt200u_rc_query,
+ .rc.legacy = {
+ .rc_interval = 300,
+ .rc_map_table = rc_map_dtt200u_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
+ .rc_query = dtt200u_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -206,10 +208,12 @@ static struct dvb_usb_device_properties wt220u_properties = {
},
.power_ctrl = dtt200u_power_ctrl,
- .rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
- .rc_query = dtt200u_rc_query,
+ .rc.legacy = {
+ .rc_interval = 300,
+ .rc_map_table = rc_map_dtt200u_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
+ .rc_query = dtt200u_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -251,10 +255,12 @@ static struct dvb_usb_device_properties wt220u_fc_properties = {
},
.power_ctrl = dtt200u_power_ctrl,
- .rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
- .rc_query = dtt200u_rc_query,
+ .rc.legacy = {
+ .rc_interval = 300,
+ .rc_map_table = rc_map_dtt200u_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
+ .rc_query = dtt200u_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
@@ -296,10 +302,12 @@ static struct dvb_usb_device_properties wt220u_zl0353_properties = {
},
.power_ctrl = dtt200u_power_ctrl,
- .rc_interval = 300,
- .rc_key_map = ir_codes_dtt200u_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dtt200u_table),
- .rc_query = dtt200u_rc_query,
+ .rc.legacy = {
+ .rc_interval = 300,
+ .rc_map_table = rc_map_dtt200u_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dtt200u_table),
+ .rc_query = dtt200u_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x01,
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
index cead089bbb4f..88e4a62abc44 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-i2c.c
@@ -20,7 +20,6 @@ int dvb_usb_i2c_init(struct dvb_usb_device *d)
}
strlcpy(d->i2c_adap.name, d->desc->name, sizeof(d->i2c_adap.name));
- d->i2c_adap.class = I2C_CLASS_TV_DIGITAL,
d->i2c_adap.algo = d->props.i2c_algo;
d->i2c_adap.algo_data = NULL;
d->i2c_adap.dev.parent = &d->udev->dev;
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 085c4e457e0e..1a6310b61923 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -32,6 +32,7 @@
#define USB_VID_EMPIA 0xeb1a
#define USB_VID_GENPIX 0x09c0
#define USB_VID_GRANDTEC 0x5032
+#define USB_VID_GTEK 0x1f4d
#define USB_VID_HANFTEK 0x15f4
#define USB_VID_HAUPPAUGE 0x2040
#define USB_VID_HYPER_PALTEK 0x1025
@@ -133,6 +134,8 @@
#define USB_PID_KWORLD_VSTREAM_WARM 0x17df
#define USB_PID_TERRATEC_CINERGY_T_USB_XE 0x0055
#define USB_PID_TERRATEC_CINERGY_T_USB_XE_REV2 0x0069
+#define USB_PID_TERRATEC_CINERGY_T_STICK_RC 0x0097
+#define USB_PID_TERRATEC_CINERGY_T_STICK_DUAL_RC 0x0099
#define USB_PID_TWINHAN_VP7041_COLD 0x3201
#define USB_PID_TWINHAN_VP7041_WARM 0x3202
#define USB_PID_TWINHAN_VP7020_COLD 0x3203
@@ -143,6 +146,7 @@
#define USB_PID_TWINHAN_VP7021_WARM 0x3208
#define USB_PID_TINYTWIN 0x3226
#define USB_PID_TINYTWIN_2 0xe402
+#define USB_PID_TINYTWIN_3 0x9016
#define USB_PID_DNTV_TINYUSB2_COLD 0x3223
#define USB_PID_DNTV_TINYUSB2_WARM 0x3224
#define USB_PID_ULTIMA_TVBOX_COLD 0x8105
@@ -196,8 +200,11 @@
#define USB_PID_AVERMEDIA_A309 0xa309
#define USB_PID_AVERMEDIA_A310 0xa310
#define USB_PID_AVERMEDIA_A850 0x850a
+#define USB_PID_AVERMEDIA_A850T 0x850b
#define USB_PID_AVERMEDIA_A805 0xa805
+#define USB_PID_AVERMEDIA_A815M 0x815a
#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
+#define USB_PID_TECHNOTREND_CONNECT_CT3650 0x300d
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY_2 0x0081
#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058
@@ -266,6 +273,7 @@
#define USB_PID_GENPIX_8PSK_REV_2 0x0202
#define USB_PID_GENPIX_SKYWALKER_1 0x0203
#define USB_PID_GENPIX_SKYWALKER_CW3K 0x0204
+#define USB_PID_GENPIX_SKYWALKER_2 0x0206
#define USB_PID_SIGMATEK_DVB_110 0x6610
#define USB_PID_MSI_DIGI_VOX_MINI_II 0x1513
#define USB_PID_MSI_DIGIVOX_DUO 0x8801
@@ -293,6 +301,7 @@
#define USB_PID_ELGATO_EYETV_DIVERSITY 0x0011
#define USB_PID_ELGATO_EYETV_DTT 0x0021
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
+#define USB_PID_ELGATO_EYETV_SAT 0x002a
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
#define USB_PID_FRIIO_WHITE 0x0001
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-init.c b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
index 5d91f70d2d2d..2e3ea0fa28e0 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-init.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-init.c
@@ -15,7 +15,7 @@
/* debug */
int dvb_usb_debug;
-module_param_named(debug,dvb_usb_debug, int, 0644);
+module_param_named(debug, dvb_usb_debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,pll=4,ts=8,err=16,rc=32,fw=64,mem=128,uxfer=256 (or-able))." DVB_USB_DEBUG_STATUS);
int dvb_usb_disable_rc_polling;
@@ -29,7 +29,7 @@ MODULE_PARM_DESC(force_pid_filter_usage, "force all dvb-usb-devices to use a PID
static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
{
struct dvb_usb_adapter *adap;
- int ret,n;
+ int ret, n;
for (n = 0; n < d->props.num_adapters; n++) {
adap = &d->adapter[n];
@@ -38,7 +38,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
memcpy(&adap->props, &d->props.adapter[n], sizeof(struct dvb_usb_adapter_properties));
-/* speed - when running at FULL speed we need a HW PID filter */
+ /* speed - when running at FULL speed we need a HW PID filter */
if (d->udev->speed == USB_SPEED_FULL && !(adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER)) {
err("This USB2.0 device cannot be run on a USB1.1 port. (it lacks a hardware PID filter)");
return -ENODEV;
@@ -46,7 +46,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
if ((d->udev->speed == USB_SPEED_FULL && adap->props.caps & DVB_USB_ADAP_HAS_PID_FILTER) ||
(adap->props.caps & DVB_USB_ADAP_NEED_PID_FILTERING)) {
- info("will use the device's hardware PID filter (table count: %d).",adap->props.pid_filter_count);
+ info("will use the device's hardware PID filter (table count: %d).", adap->props.pid_filter_count);
adap->pid_filtering = 1;
adap->max_feed_count = adap->props.pid_filter_count;
} else {
@@ -64,9 +64,9 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
}
if (adap->props.size_of_priv > 0) {
- adap->priv = kzalloc(adap->props.size_of_priv,GFP_KERNEL);
+ adap->priv = kzalloc(adap->props.size_of_priv, GFP_KERNEL);
if (adap->priv == NULL) {
- err("no memory for priv for adapter %d.",n);
+ err("no memory for priv for adapter %d.", n);
return -ENOMEM;
}
}
@@ -86,8 +86,8 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
* sometimes a timeout occures, this helps
*/
if (d->props.generic_bulk_ctrl_endpoint != 0) {
- usb_clear_halt(d->udev,usb_sndbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
- usb_clear_halt(d->udev,usb_rcvbulkpipe(d->udev,d->props.generic_bulk_ctrl_endpoint));
+ usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
+ usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, d->props.generic_bulk_ctrl_endpoint));
}
return 0;
@@ -96,6 +96,7 @@ static int dvb_usb_adapter_init(struct dvb_usb_device *d, short *adapter_nrs)
static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
{
int n;
+
for (n = 0; n < d->num_adapters_initialized; n++) {
dvb_usb_adapter_frontend_exit(&d->adapter[n]);
dvb_usb_adapter_dvb_exit(&d->adapter[n]);
@@ -111,11 +112,11 @@ static int dvb_usb_adapter_exit(struct dvb_usb_device *d)
/* general initialization functions */
static int dvb_usb_exit(struct dvb_usb_device *d)
{
- deb_info("state before exiting everything: %x\n",d->state);
+ deb_info("state before exiting everything: %x\n", d->state);
dvb_usb_remote_exit(d);
dvb_usb_adapter_exit(d);
dvb_usb_i2c_exit(d);
- deb_info("state should be zero now: %x\n",d->state);
+ deb_info("state should be zero now: %x\n", d->state);
d->state = DVB_USB_STATE_INIT;
kfree(d->priv);
kfree(d);
@@ -132,14 +133,14 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
d->state = DVB_USB_STATE_INIT;
if (d->props.size_of_priv > 0) {
- d->priv = kzalloc(d->props.size_of_priv,GFP_KERNEL);
+ d->priv = kzalloc(d->props.size_of_priv, GFP_KERNEL);
if (d->priv == NULL) {
err("no memory for priv in 'struct dvb_usb_device'");
return -ENOMEM;
}
}
-/* check the capabilities and set appropriate variables */
+ /* check the capabilities and set appropriate variables */
dvb_usb_device_power_ctrl(d, 1);
if ((ret = dvb_usb_i2c_init(d)) ||
@@ -157,16 +158,17 @@ static int dvb_usb_init(struct dvb_usb_device *d, short *adapter_nums)
}
/* determine the name and the state of the just found USB device */
-static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device *udev,struct dvb_usb_device_properties *props, int *cold)
+static struct dvb_usb_device_description *dvb_usb_find_device(struct usb_device *udev, struct dvb_usb_device_properties *props, int *cold)
{
- int i,j;
+ int i, j;
struct dvb_usb_device_description *desc = NULL;
+
*cold = -1;
for (i = 0; i < props->num_device_descs; i++) {
for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].cold_ids[j] != NULL; j++) {
- deb_info("check for cold %x %x\n",props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
+ deb_info("check for cold %x %x\n", props->devices[i].cold_ids[j]->idVendor, props->devices[i].cold_ids[j]->idProduct);
if (props->devices[i].cold_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
props->devices[i].cold_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
*cold = 1;
@@ -179,7 +181,7 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device
break;
for (j = 0; j < DVB_USB_ID_MAX_NUM && props->devices[i].warm_ids[j] != NULL; j++) {
- deb_info("check for warm %x %x\n",props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
+ deb_info("check for warm %x %x\n", props->devices[i].warm_ids[j]->idVendor, props->devices[i].warm_ids[j]->idProduct);
if (props->devices[i].warm_ids[j]->idVendor == le16_to_cpu(udev->descriptor.idVendor) &&
props->devices[i].warm_ids[j]->idProduct == le16_to_cpu(udev->descriptor.idProduct)) {
*cold = 0;
@@ -190,7 +192,7 @@ static struct dvb_usb_device_description * dvb_usb_find_device(struct usb_device
}
if (desc != NULL && props->identify_state != NULL)
- props->identify_state(udev,props,&desc,cold);
+ props->identify_state(udev, props, &desc, cold);
return desc;
}
@@ -202,7 +204,7 @@ int dvb_usb_device_power_ctrl(struct dvb_usb_device *d, int onoff)
else
d->powered--;
- if (d->powered == 0 || (onoff && d->powered == 1)) { // when switching from 1 to 0 or from 0 to 1
+ if (d->powered == 0 || (onoff && d->powered == 1)) { /* when switching from 1 to 0 or from 0 to 1 */
deb_info("power control: %d\n", onoff);
if (d->props.power_ctrl)
return d->props.power_ctrl(d, onoff);
@@ -222,32 +224,32 @@ int dvb_usb_device_init(struct usb_interface *intf,
struct dvb_usb_device *d = NULL;
struct dvb_usb_device_description *desc = NULL;
- int ret = -ENOMEM,cold=0;
+ int ret = -ENOMEM, cold = 0;
if (du != NULL)
*du = NULL;
- if ((desc = dvb_usb_find_device(udev,props,&cold)) == NULL) {
+ if ((desc = dvb_usb_find_device(udev, props, &cold)) == NULL) {
deb_err("something went very wrong, device was not found in current device list - let's see what comes next.\n");
return -ENODEV;
}
if (cold) {
- info("found a '%s' in cold state, will try to load a firmware",desc->name);
- ret = dvb_usb_download_firmware(udev,props);
+ info("found a '%s' in cold state, will try to load a firmware", desc->name);
+ ret = dvb_usb_download_firmware(udev, props);
if (!props->no_reconnect || ret != 0)
return ret;
}
- info("found a '%s' in warm state.",desc->name);
- d = kzalloc(sizeof(struct dvb_usb_device),GFP_KERNEL);
+ info("found a '%s' in warm state.", desc->name);
+ d = kzalloc(sizeof(struct dvb_usb_device), GFP_KERNEL);
if (d == NULL) {
err("no memory for 'struct dvb_usb_device'");
return -ENOMEM;
}
d->udev = udev;
- memcpy(&d->props,props,sizeof(struct dvb_usb_device_properties));
+ memcpy(&d->props, props, sizeof(struct dvb_usb_device_properties));
d->desc = desc;
d->owner = owner;
@@ -259,9 +261,9 @@ int dvb_usb_device_init(struct usb_interface *intf,
ret = dvb_usb_init(d, adapter_nums);
if (ret == 0)
- info("%s successfully initialized and connected.",desc->name);
+ info("%s successfully initialized and connected.", desc->name);
else
- info("%s error while loading driver (%d)",desc->name,ret);
+ info("%s error while loading driver (%d)", desc->name, ret);
return ret;
}
EXPORT_SYMBOL(dvb_usb_device_init);
@@ -271,12 +273,12 @@ void dvb_usb_device_exit(struct usb_interface *intf)
struct dvb_usb_device *d = usb_get_intfdata(intf);
const char *name = "generic DVB-USB module";
- usb_set_intfdata(intf,NULL);
+ usb_set_intfdata(intf, NULL);
if (d != NULL && d->desc != NULL) {
name = d->desc->name;
dvb_usb_exit(d);
}
- info("%s successfully deinitialized and disconnected.",name);
+ info("%s successfully deinitialized and disconnected.", name);
}
EXPORT_SYMBOL(dvb_usb_device_exit);
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
index 852fe89539cf..23005b3cf30b 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-remote.c
@@ -8,29 +8,29 @@
#include "dvb-usb-common.h"
#include <linux/usb/input.h>
-static int dvb_usb_getkeycode(struct input_dev *dev,
+static int legacy_dvb_usb_getkeycode(struct input_dev *dev,
unsigned int scancode, unsigned int *keycode)
{
struct dvb_usb_device *d = input_get_drvdata(dev);
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
int i;
/* See if we can match the raw key code. */
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (keymap[i].scan == scancode) {
- *keycode = keymap[i].event;
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+ if (keymap[i].scancode == scancode) {
+ *keycode = keymap[i].keycode;
return 0;
}
/*
* If is there extra space, returns KEY_RESERVED,
- * otherwise, input core won't let dvb_usb_setkeycode
+ * otherwise, input core won't let legacy_dvb_usb_setkeycode
* to work
*/
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (keymap[i].event == KEY_RESERVED ||
- keymap[i].event == KEY_UNKNOWN) {
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+ if (keymap[i].keycode == KEY_RESERVED ||
+ keymap[i].keycode == KEY_UNKNOWN) {
*keycode = KEY_RESERVED;
return 0;
}
@@ -38,27 +38,27 @@ static int dvb_usb_getkeycode(struct input_dev *dev,
return -EINVAL;
}
-static int dvb_usb_setkeycode(struct input_dev *dev,
+static int legacy_dvb_usb_setkeycode(struct input_dev *dev,
unsigned int scancode, unsigned int keycode)
{
struct dvb_usb_device *d = input_get_drvdata(dev);
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
int i;
/* Search if it is replacing an existing keycode */
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (keymap[i].scan == scancode) {
- keymap[i].event = keycode;
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+ if (keymap[i].scancode == scancode) {
+ keymap[i].keycode = keycode;
return 0;
}
/* Search if is there a clean entry. If so, use it */
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (keymap[i].event == KEY_RESERVED ||
- keymap[i].event == KEY_UNKNOWN) {
- keymap[i].scan = scancode;
- keymap[i].event = keycode;
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+ if (keymap[i].keycode == KEY_RESERVED ||
+ keymap[i].keycode == KEY_UNKNOWN) {
+ keymap[i].scancode = scancode;
+ keymap[i].keycode = keycode;
return 0;
}
@@ -78,7 +78,7 @@ static int dvb_usb_setkeycode(struct input_dev *dev,
*
* TODO: Fix the repeat rate of the input device.
*/
-static void dvb_usb_read_remote_control(struct work_struct *work)
+static void legacy_dvb_usb_read_remote_control(struct work_struct *work)
{
struct dvb_usb_device *d =
container_of(work, struct dvb_usb_device, rc_query_work.work);
@@ -92,7 +92,7 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
if (dvb_usb_disable_rc_polling)
return;
- if (d->props.rc_query(d,&event,&state)) {
+ if (d->props.rc.legacy.rc_query(d,&event,&state)) {
err("error while querying for an remote control event.");
goto schedule;
}
@@ -106,10 +106,10 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
d->last_event = event;
case REMOTE_KEY_REPEAT:
deb_rc("key repeated\n");
- input_event(d->rc_input_dev, EV_KEY, event, 1);
- input_sync(d->rc_input_dev);
- input_event(d->rc_input_dev, EV_KEY, d->last_event, 0);
- input_sync(d->rc_input_dev);
+ input_event(d->input_dev, EV_KEY, event, 1);
+ input_sync(d->input_dev);
+ input_event(d->input_dev, EV_KEY, d->last_event, 0);
+ input_sync(d->input_dev);
break;
default:
break;
@@ -151,22 +151,13 @@ static void dvb_usb_read_remote_control(struct work_struct *work)
*/
schedule:
- schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+ schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc.legacy.rc_interval));
}
-int dvb_usb_remote_init(struct dvb_usb_device *d)
+static int legacy_dvb_usb_remote_init(struct dvb_usb_device *d)
{
+ int i, err, rc_interval;
struct input_dev *input_dev;
- int i;
- int err;
-
- if (d->props.rc_key_map == NULL ||
- d->props.rc_query == NULL ||
- dvb_usb_disable_rc_polling)
- return 0;
-
- usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
- strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
input_dev = input_allocate_device();
if (!input_dev)
@@ -177,39 +168,142 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
input_dev->phys = d->rc_phys;
usb_to_input_id(d->udev, &input_dev->id);
input_dev->dev.parent = &d->udev->dev;
- input_dev->getkeycode = dvb_usb_getkeycode;
- input_dev->setkeycode = dvb_usb_setkeycode;
+ d->input_dev = input_dev;
+ d->rc_dev = NULL;
+
+ input_dev->getkeycode = legacy_dvb_usb_getkeycode;
+ input_dev->setkeycode = legacy_dvb_usb_setkeycode;
/* set the bits for the keys */
- deb_rc("key map size: %d\n", d->props.rc_key_map_size);
- for (i = 0; i < d->props.rc_key_map_size; i++) {
+ deb_rc("key map size: %d\n", d->props.rc.legacy.rc_map_size);
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++) {
deb_rc("setting bit for event %d item %d\n",
- d->props.rc_key_map[i].event, i);
- set_bit(d->props.rc_key_map[i].event, input_dev->keybit);
+ d->props.rc.legacy.rc_map_table[i].keycode, i);
+ set_bit(d->props.rc.legacy.rc_map_table[i].keycode, input_dev->keybit);
}
- /* Start the remote-control polling. */
- if (d->props.rc_interval < 40)
- d->props.rc_interval = 100; /* default */
-
/* setting these two values to non-zero, we have to manage key repeats */
- input_dev->rep[REP_PERIOD] = d->props.rc_interval;
- input_dev->rep[REP_DELAY] = d->props.rc_interval + 150;
+ input_dev->rep[REP_PERIOD] = d->props.rc.legacy.rc_interval;
+ input_dev->rep[REP_DELAY] = d->props.rc.legacy.rc_interval + 150;
input_set_drvdata(input_dev, d);
err = input_register_device(input_dev);
- if (err) {
+ if (err)
input_free_device(input_dev);
+
+ rc_interval = d->props.rc.legacy.rc_interval;
+
+ INIT_DELAYED_WORK(&d->rc_query_work, legacy_dvb_usb_read_remote_control);
+
+ info("schedule remote query interval to %d msecs.", rc_interval);
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(rc_interval));
+
+ d->state |= DVB_USB_STATE_REMOTE;
+
+ return err;
+}
+
+/* Remote-control poll function - called every dib->rc_query_interval ms to see
+ * whether the remote control has received anything.
+ *
+ * TODO: Fix the repeat rate of the input device.
+ */
+static void dvb_usb_read_remote_control(struct work_struct *work)
+{
+ struct dvb_usb_device *d =
+ container_of(work, struct dvb_usb_device, rc_query_work.work);
+ int err;
+
+ /* TODO: need a lock here. We can simply skip checking for the remote control
+ if we're busy. */
+
+ /* when the parameter has been set to 1 via sysfs while the
+ * driver was running, or when bulk mode is enabled after IR init
+ */
+ if (dvb_usb_disable_rc_polling || d->props.rc.core.bulk_mode)
+ return;
+
+ err = d->props.rc.core.rc_query(d);
+ if (err)
+ err("error %d while querying for an remote control event.", err);
+
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(d->props.rc.core.rc_interval));
+}
+
+static int rc_core_dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+ int err, rc_interval;
+ struct rc_dev *dev;
+
+ dev = rc_allocate_device();
+ if (!dev)
+ return -ENOMEM;
+
+ dev->driver_name = d->props.rc.core.module_name;
+ dev->map_name = d->props.rc.core.rc_codes;
+ dev->change_protocol = d->props.rc.core.change_protocol;
+ dev->allowed_protos = d->props.rc.core.allowed_protos;
+ dev->driver_type = RC_DRIVER_SCANCODE;
+ usb_to_input_id(d->udev, &dev->input_id);
+ dev->input_name = "IR-receiver inside an USB DVB receiver";
+ dev->input_phys = d->rc_phys;
+ dev->dev.parent = &d->udev->dev;
+ dev->priv = d;
+
+ err = rc_register_device(dev);
+ if (err < 0) {
+ rc_free_device(dev);
return err;
}
- d->rc_input_dev = input_dev;
+ d->input_dev = NULL;
+ d->rc_dev = dev;
+ if (!d->props.rc.core.rc_query || d->props.rc.core.bulk_mode)
+ return 0;
+
+ /* Polling mode - initialize a work queue for handling it */
INIT_DELAYED_WORK(&d->rc_query_work, dvb_usb_read_remote_control);
- info("schedule remote query interval to %d msecs.", d->props.rc_interval);
- schedule_delayed_work(&d->rc_query_work,msecs_to_jiffies(d->props.rc_interval));
+ rc_interval = d->props.rc.core.rc_interval;
+
+ info("schedule remote query interval to %d msecs.", rc_interval);
+ schedule_delayed_work(&d->rc_query_work,
+ msecs_to_jiffies(rc_interval));
+
+ return 0;
+}
+
+int dvb_usb_remote_init(struct dvb_usb_device *d)
+{
+ int err;
+
+ if (dvb_usb_disable_rc_polling)
+ return 0;
+
+ if (d->props.rc.legacy.rc_map_table && d->props.rc.legacy.rc_query)
+ d->props.rc.mode = DVB_RC_LEGACY;
+ else if (d->props.rc.core.rc_codes)
+ d->props.rc.mode = DVB_RC_CORE;
+ else
+ return 0;
+
+ usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+ strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+
+ /* Start the remote-control polling. */
+ if (d->props.rc.legacy.rc_interval < 40)
+ d->props.rc.legacy.rc_interval = 100; /* default */
+
+ if (d->props.rc.mode == DVB_RC_LEGACY)
+ err = legacy_dvb_usb_remote_init(d);
+ else
+ err = rc_core_dvb_usb_remote_init(d);
+ if (err)
+ return err;
d->state |= DVB_USB_STATE_REMOTE;
@@ -219,9 +313,11 @@ int dvb_usb_remote_init(struct dvb_usb_device *d)
int dvb_usb_remote_exit(struct dvb_usb_device *d)
{
if (d->state & DVB_USB_STATE_REMOTE) {
- cancel_rearming_delayed_work(&d->rc_query_work);
- flush_scheduled_work();
- input_unregister_device(d->rc_input_dev);
+ cancel_delayed_work_sync(&d->rc_query_work);
+ if (d->props.rc.mode == DVB_RC_LEGACY)
+ input_unregister_device(d->input_dev);
+ else
+ rc_unregister_device(d->rc_dev);
}
d->state &= ~DVB_USB_STATE_REMOTE;
return 0;
@@ -234,7 +330,7 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
u8 keybuf[5], u32 *event, int *state)
{
int i;
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
*event = 0;
*state = REMOTE_NO_KEY_PRESSED;
switch (keybuf[0]) {
@@ -247,10 +343,10 @@ int dvb_usb_nec_rc_key_to_event(struct dvb_usb_device *d,
break;
}
/* See if we can match the raw key code. */
- for (i = 0; i < d->props.rc_key_map_size; i++)
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
if (rc5_custom(&keymap[i]) == keybuf[1] &&
rc5_data(&keymap[i]) == keybuf[3]) {
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
*state = REMOTE_KEY_PRESSED;
return 0;
}
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb.h b/drivers/media/dvb/dvb-usb/dvb-usb.h
index 4a9f676087bf..65fa9268e7f7 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb.h
@@ -14,6 +14,7 @@
#include <linux/usb.h>
#include <linux/firmware.h>
#include <linux/mutex.h>
+#include <media/rc-core.h>
#include "dvb_frontend.h"
#include "dvb_demux.h"
@@ -74,30 +75,19 @@ struct dvb_usb_device_description {
struct usb_device_id *warm_ids[DVB_USB_ID_MAX_NUM];
};
-/**
- * struct dvb_usb_rc_key - a remote control key and its input-event
- * @custom: the vendor/custom part of the key
- * @data: the actual key part
- * @event: the input event assigned to key identified by custom and data
- */
-struct dvb_usb_rc_key {
- u16 scan;
- u32 event;
-};
-
-static inline u8 rc5_custom(struct dvb_usb_rc_key *key)
+static inline u8 rc5_custom(struct rc_map_table *key)
{
- return (key->scan >> 8) & 0xff;
+ return (key->scancode >> 8) & 0xff;
}
-static inline u8 rc5_data(struct dvb_usb_rc_key *key)
+static inline u8 rc5_data(struct rc_map_table *key)
{
- return key->scan & 0xff;
+ return key->scancode & 0xff;
}
-static inline u8 rc5_scan(struct dvb_usb_rc_key *key)
+static inline u8 rc5_scan(struct rc_map_table *key)
{
- return key->scan & 0xffff;
+ return key->scancode & 0xffff;
}
struct dvb_usb_device;
@@ -168,6 +158,57 @@ struct dvb_usb_adapter_properties {
};
/**
+ * struct dvb_rc_legacy - old properties of remote controller
+ * @rc_map_table: a hard-wired array of struct rc_map_table (NULL to disable
+ * remote control handling).
+ * @rc_map_size: number of items in @rc_map_table.
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ */
+struct dvb_rc_legacy {
+/* remote control properties */
+#define REMOTE_NO_KEY_PRESSED 0x00
+#define REMOTE_KEY_PRESSED 0x01
+#define REMOTE_KEY_REPEAT 0x02
+ struct rc_map_table *rc_map_table;
+ int rc_map_size;
+ int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
+ int rc_interval;
+};
+
+/**
+ * struct dvb_rc properties of remote controller, using rc-core
+ * @rc_codes: name of rc codes table
+ * @protocol: type of protocol(s) currently used by the driver
+ * @allowed_protos: protocol(s) supported by the driver
+ * @change_protocol: callback to change protocol
+ * @rc_query: called to query an event event.
+ * @rc_interval: time in ms between two queries.
+ * @bulk_mode: device supports bulk mode for RC (disable polling mode)
+ */
+struct dvb_rc {
+ char *rc_codes;
+ u64 protocol;
+ u64 allowed_protos;
+ int (*change_protocol)(struct rc_dev *dev, u64 rc_type);
+ char *module_name;
+ int (*rc_query) (struct dvb_usb_device *d);
+ int rc_interval;
+ bool bulk_mode; /* uses bulk mode */
+};
+
+/**
+ * enum dvb_usb_mode - Specifies if it is using a legacy driver or a new one
+ * based on rc-core
+ * This is initialized/used only inside dvb-usb-remote.c.
+ * It shouldn't be set by the drivers.
+ */
+enum dvb_usb_mode {
+ DVB_RC_LEGACY,
+ DVB_RC_CORE,
+};
+
+/**
* struct dvb_usb_device_properties - properties of a dvb-usb-device
* @usb_ctrl: which USB device-side controller is in use. Needed for firmware
* download.
@@ -185,11 +226,7 @@ struct dvb_usb_adapter_properties {
* @identify_state: called to determine the state (cold or warm), when it
* is not distinguishable by the USB IDs.
*
- * @rc_key_map: a hard-wired array of struct dvb_usb_rc_key (NULL to disable
- * remote control handling).
- * @rc_key_map_size: number of items in @rc_key_map.
- * @rc_query: called to query an event event.
- * @rc_interval: time in ms between two queries.
+ * @rc: remote controller properties
*
* @i2c_algo: i2c_algorithm if the device has I2CoverUSB.
*
@@ -233,14 +270,11 @@ struct dvb_usb_device_properties {
int (*identify_state) (struct usb_device *, struct dvb_usb_device_properties *,
struct dvb_usb_device_description **, int *);
-/* remote control properties */
-#define REMOTE_NO_KEY_PRESSED 0x00
-#define REMOTE_KEY_PRESSED 0x01
-#define REMOTE_KEY_REPEAT 0x02
- struct dvb_usb_rc_key *rc_key_map;
- int rc_key_map_size;
- int (*rc_query) (struct dvb_usb_device *, u32 *, int *);
- int rc_interval;
+ struct {
+ enum dvb_usb_mode mode; /* Drivers shouldn't touch on it */
+ struct dvb_rc_legacy legacy;
+ struct dvb_rc core;
+ } rc;
struct i2c_algorithm *i2c_algo;
@@ -353,7 +387,8 @@ struct dvb_usb_adapter {
*
* @i2c_adap: device's i2c_adapter if it uses I2CoverUSB
*
- * @rc_input_dev: input device for the remote control.
+ * @rc_dev: rc device for the remote control (rc-core mode)
+ * @input_dev: input device for the remote control (legacy mode)
* @rc_query_work: struct work_struct frequent rc queries
* @last_event: last triggered event
* @last_state: last state (no, pressed, repeat)
@@ -386,7 +421,8 @@ struct dvb_usb_device {
struct dvb_usb_adapter adapter[MAX_NO_OF_ADAPTER_PER_DEVICE];
/* remote control */
- struct input_dev *rc_input_dev;
+ struct rc_dev *rc_dev;
+ struct input_dev *input_dev;
char rc_phys[64];
struct delayed_work rc_query_work;
u32 last_event;
diff --git a/drivers/media/dvb/dvb-usb/dw2102.c b/drivers/media/dvb/dvb-usb/dw2102.c
index e8fb85380672..2c307ba0d28b 100644
--- a/drivers/media/dvb/dvb-usb/dw2102.c
+++ b/drivers/media/dvb/dvb-usb/dw2102.c
@@ -73,8 +73,8 @@
"Please see linux/Documentation/dvb/ for more details " \
"on firmware-problems."
-struct ir_codes_dvb_usb_table_table {
- struct dvb_usb_rc_key *rc_keys;
+struct rc_map_dvb_usb_table_table {
+ struct rc_map_table *rc_keys;
int rc_keys_size;
};
@@ -948,7 +948,7 @@ static int dw3101_tuner_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_dw210x_table[] = {
+static struct rc_map_table rc_map_dw210x_table[] = {
{ 0xf80a, KEY_Q }, /*power*/
{ 0xf80c, KEY_M }, /*mute*/
{ 0xf811, KEY_1 },
@@ -982,7 +982,7 @@ static struct dvb_usb_rc_key ir_codes_dw210x_table[] = {
{ 0xf81b, KEY_B }, /*recall*/
};
-static struct dvb_usb_rc_key ir_codes_tevii_table[] = {
+static struct rc_map_table rc_map_tevii_table[] = {
{ 0xf80a, KEY_POWER },
{ 0xf80c, KEY_MUTE },
{ 0xf811, KEY_1 },
@@ -1032,7 +1032,7 @@ static struct dvb_usb_rc_key ir_codes_tevii_table[] = {
{ 0xf858, KEY_SWITCHVIDEOMODE },
};
-static struct dvb_usb_rc_key ir_codes_tbs_table[] = {
+static struct rc_map_table rc_map_tbs_table[] = {
{ 0xf884, KEY_POWER },
{ 0xf894, KEY_MUTE },
{ 0xf887, KEY_1 },
@@ -1067,16 +1067,16 @@ static struct dvb_usb_rc_key ir_codes_tbs_table[] = {
{ 0xf89b, KEY_MODE }
};
-static struct ir_codes_dvb_usb_table_table keys_tables[] = {
- { ir_codes_dw210x_table, ARRAY_SIZE(ir_codes_dw210x_table) },
- { ir_codes_tevii_table, ARRAY_SIZE(ir_codes_tevii_table) },
- { ir_codes_tbs_table, ARRAY_SIZE(ir_codes_tbs_table) },
+static struct rc_map_dvb_usb_table_table keys_tables[] = {
+ { rc_map_dw210x_table, ARRAY_SIZE(rc_map_dw210x_table) },
+ { rc_map_tevii_table, ARRAY_SIZE(rc_map_tevii_table) },
+ { rc_map_tbs_table, ARRAY_SIZE(rc_map_tbs_table) },
};
static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
- struct dvb_usb_rc_key *keymap = d->props.rc_key_map;
- int keymap_size = d->props.rc_key_map_size;
+ struct rc_map_table *keymap = d->props.rc.legacy.rc_map_table;
+ int keymap_size = d->props.rc.legacy.rc_map_size;
u8 key[2];
struct i2c_msg msg = {
.addr = DW2102_RC_QUERY,
@@ -1096,7 +1096,7 @@ static int dw2102_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
for (i = 0; i < keymap_size ; i++) {
if (rc5_data(&keymap[i]) == msg.buf[0]) {
*state = REMOTE_KEY_PRESSED;
- *event = keymap[i].event;
+ *event = keymap[i].keycode;
break;
}
@@ -1185,14 +1185,14 @@ static int dw2102_load_firmware(struct usb_device *dev,
/* init registers */
switch (dev->descriptor.idProduct) {
case USB_PID_PROF_1100:
- s6x0_properties.rc_key_map = ir_codes_tbs_table;
- s6x0_properties.rc_key_map_size =
- ARRAY_SIZE(ir_codes_tbs_table);
+ s6x0_properties.rc.legacy.rc_map_table = rc_map_tbs_table;
+ s6x0_properties.rc.legacy.rc_map_size =
+ ARRAY_SIZE(rc_map_tbs_table);
break;
case USB_PID_TEVII_S650:
- dw2104_properties.rc_key_map = ir_codes_tevii_table;
- dw2104_properties.rc_key_map_size =
- ARRAY_SIZE(ir_codes_tevii_table);
+ dw2104_properties.rc.legacy.rc_map_table = rc_map_tevii_table;
+ dw2104_properties.rc.legacy.rc_map_size =
+ ARRAY_SIZE(rc_map_tevii_table);
case USB_PID_DW2104:
reset = 1;
dw210x_op_rw(dev, 0xc4, 0x0000, 0, &reset, 1,
@@ -1255,10 +1255,13 @@ static struct dvb_usb_device_properties dw2102_properties = {
.no_reconnect = 1,
.i2c_algo = &dw2102_serit_i2c_algo,
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
- .rc_interval = 150,
- .rc_query = dw2102_rc_query,
+
+ .rc.legacy = {
+ .rc_map_table = rc_map_dw210x_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x81,
/* parameter for the MPEG2-data transfer */
@@ -1306,10 +1309,12 @@ static struct dvb_usb_device_properties dw2104_properties = {
.no_reconnect = 1,
.i2c_algo = &dw2104_i2c_algo,
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
- .rc_interval = 150,
- .rc_query = dw2102_rc_query,
+ .rc.legacy = {
+ .rc_map_table = rc_map_dw210x_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x81,
/* parameter for the MPEG2-data transfer */
@@ -1353,10 +1358,12 @@ static struct dvb_usb_device_properties dw3101_properties = {
.no_reconnect = 1,
.i2c_algo = &dw3101_i2c_algo,
- .rc_key_map = ir_codes_dw210x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_dw210x_table),
- .rc_interval = 150,
- .rc_query = dw2102_rc_query,
+ .rc.legacy = {
+ .rc_map_table = rc_map_dw210x_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_dw210x_table),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x81,
/* parameter for the MPEG2-data transfer */
@@ -1396,10 +1403,12 @@ static struct dvb_usb_device_properties s6x0_properties = {
.no_reconnect = 1,
.i2c_algo = &s6x0_i2c_algo,
- .rc_key_map = ir_codes_tevii_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_tevii_table),
- .rc_interval = 150,
- .rc_query = dw2102_rc_query,
+ .rc.legacy = {
+ .rc_map_table = rc_map_tevii_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_tevii_table),
+ .rc_interval = 150,
+ .rc_query = dw2102_rc_query,
+ },
.generic_bulk_ctrl_endpoint = 0x81,
.num_adapters = 1,
@@ -1459,8 +1468,8 @@ static int dw2102_probe(struct usb_interface *intf,
/* fill only different fields */
p7500->firmware = "dvb-usb-p7500.fw";
p7500->devices[0] = d7500;
- p7500->rc_key_map = ir_codes_tbs_table;
- p7500->rc_key_map_size = ARRAY_SIZE(ir_codes_tbs_table);
+ p7500->rc.legacy.rc_map_table = rc_map_tbs_table;
+ p7500->rc.legacy.rc_map_size = ARRAY_SIZE(rc_map_tbs_table);
p7500->adapter->frontend_attach = prof_7500_frontend_attach;
if (0 == dvb_usb_device_init(intf, &dw2102_properties,
diff --git a/drivers/media/dvb/dvb-usb/friio-fe.c b/drivers/media/dvb/dvb-usb/friio-fe.c
index 93c21ddd0b77..015b4e8af1a5 100644
--- a/drivers/media/dvb/dvb-usb/friio-fe.c
+++ b/drivers/media/dvb/dvb-usb/friio-fe.c
@@ -75,7 +75,7 @@ static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
return 0;
}
-static int _jdvbt90502_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int _jdvbt90502_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct jdvbt90502_state *state = fe->demodulator_priv;
int err, i;
diff --git a/drivers/media/dvb/dvb-usb/gp8psk-fe.c b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
index 7a7f1b2b681c..60d11e57e7d0 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk-fe.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk-fe.c
@@ -109,7 +109,7 @@ static int gp8psk_fe_read_signal_strength(struct dvb_frontend* fe, u16 *strength
static int gp8psk_fe_get_tune_settings(struct dvb_frontend* fe, struct dvb_frontend_tune_settings *tune)
{
- tune->min_delay_ms = 200;
+ tune->min_delay_ms = 800;
return 0;
}
@@ -334,7 +334,7 @@ success:
static struct dvb_frontend_ops gp8psk_fe_ops = {
.info = {
- .name = "Genpix 8psk-to-USB2 DVB-S",
+ .name = "Genpix DVB-S",
.type = FE_QPSK,
.frequency_min = 800000,
.frequency_max = 2250000,
@@ -349,7 +349,7 @@ static struct dvb_frontend_ops gp8psk_fe_ops = {
* FE_CAN_QAM_16 is for compatibility
* (Myth incorrectly detects Turbo-QPSK as plain QAM-16)
*/
- FE_CAN_QPSK | FE_CAN_QAM_16
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_TURBO_FEC
},
.release = gp8psk_fe_release,
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.c b/drivers/media/dvb/dvb-usb/gp8psk.c
index 45106ac49674..1cb3d9a66e02 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.c
+++ b/drivers/media/dvb/dvb-usb/gp8psk.c
@@ -24,6 +24,33 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,xfer=2,rc=4 (or-able))." DV
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+static int gp8psk_get_fw_version(struct dvb_usb_device *d, u8 *fw_vers)
+{
+ return (gp8psk_usb_in_op(d, GET_FW_VERS, 0, 0, fw_vers, 6));
+}
+
+static int gp8psk_get_fpga_version(struct dvb_usb_device *d, u8 *fpga_vers)
+{
+ return (gp8psk_usb_in_op(d, GET_FPGA_VERS, 0, 0, fpga_vers, 1));
+}
+
+static void gp8psk_info(struct dvb_usb_device *d)
+{
+ u8 fpga_vers, fw_vers[6];
+
+ if (!gp8psk_get_fw_version(d, fw_vers))
+ info("FW Version = %i.%02i.%i (0x%x) Build %4i/%02i/%02i",
+ fw_vers[2], fw_vers[1], fw_vers[0], GP8PSK_FW_VERS(fw_vers),
+ 2000 + fw_vers[5], fw_vers[4], fw_vers[3]);
+ else
+ info("failed to get FW version");
+
+ if (!gp8psk_get_fpga_version(d, &fpga_vers))
+ info("FPGA Version = %i", fpga_vers);
+ else
+ info("failed to get FPGA version");
+}
+
int gp8psk_usb_in_op(struct dvb_usb_device *d, u8 req, u16 value, u16 index, u8 *b, int blen)
{
int ret = 0,try = 0;
@@ -146,6 +173,7 @@ static int gp8psk_power_ctrl(struct dvb_usb_device *d, int onoff)
gp8psk_usb_out_op(d, CW3K_INIT, 1, 0, NULL, 0);
if (gp8psk_usb_in_op(d, BOOT_8PSK, 1, 0, &buf, 1))
return -EINVAL;
+ gp8psk_info(d);
}
if (gp_product_id == USB_PID_GENPIX_8PSK_REV_1_WARM)
@@ -227,6 +255,7 @@ static struct usb_device_id gp8psk_usb_table [] = {
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_1_WARM) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_8PSK_REV_2) },
{ USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_1) },
+ { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_2) },
/* { USB_DEVICE(USB_VID_GENPIX, USB_PID_GENPIX_SKYWALKER_CW3K) }, */
{ 0 },
};
@@ -258,7 +287,7 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.generic_bulk_ctrl_endpoint = 0x01,
- .num_device_descs = 3,
+ .num_device_descs = 4,
.devices = {
{ .name = "Genpix 8PSK-to-USB2 Rev.1 DVB-S receiver",
.cold_ids = { &gp8psk_usb_table[0], NULL },
@@ -272,6 +301,10 @@ static struct dvb_usb_device_properties gp8psk_properties = {
.cold_ids = { NULL },
.warm_ids = { &gp8psk_usb_table[3], NULL },
},
+ { .name = "Genpix SkyWalker-2 DVB-S receiver",
+ .cold_ids = { NULL },
+ .warm_ids = { &gp8psk_usb_table[4], NULL },
+ },
{ NULL },
}
};
@@ -306,6 +339,6 @@ module_init(gp8psk_usb_module_init);
module_exit(gp8psk_usb_module_exit);
MODULE_AUTHOR("Alan Nisota <alannisota@gamil.com>");
-MODULE_DESCRIPTION("Driver for Genpix 8psk-to-USB2 DVB-S");
+MODULE_DESCRIPTION("Driver for Genpix DVB-S");
MODULE_VERSION("1.1");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/gp8psk.h b/drivers/media/dvb/dvb-usb/gp8psk.h
index e83a57506cfa..831749a518cb 100644
--- a/drivers/media/dvb/dvb-usb/gp8psk.h
+++ b/drivers/media/dvb/dvb-usb/gp8psk.h
@@ -25,7 +25,6 @@ extern int dvb_usb_gp8psk_debug;
#define deb_xfer(args...) dprintk(dvb_usb_gp8psk_debug,0x02,args)
#define deb_rc(args...) dprintk(dvb_usb_gp8psk_debug,0x04,args)
#define deb_fe(args...) dprintk(dvb_usb_gp8psk_debug,0x08,args)
-/* gp8psk commands */
/* Twinhan Vendor requests */
#define TH_COMMAND_IN 0xC0
@@ -49,8 +48,10 @@ extern int dvb_usb_gp8psk_debug;
#define SET_DVB_MODE 0x8E
#define SET_DN_SWITCH 0x8F
#define GET_SIGNAL_LOCK 0x90 /* in */
+#define GET_FW_VERS 0x92
#define GET_SERIAL_NUMBER 0x93 /* in */
#define USE_EXTRA_VOLT 0x94
+#define GET_FPGA_VERS 0x95
#define CW3K_INIT 0x9d
/* PSK_configuration bits */
@@ -88,6 +89,11 @@ extern int dvb_usb_gp8psk_debug;
#define PRODUCT_STRING_READ 0x0D
#define FW_BCD_VERSION_READ 0x14
+/* firmware revision id's */
+#define GP8PSK_FW_REV1 0x020604
+#define GP8PSK_FW_REV2 0x020704
+#define GP8PSK_FW_VERS(_fw_vers) ((_fw_vers)[2]<<0x10 | (_fw_vers)[1]<<0x08 | (_fw_vers)[0])
+
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,
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.c b/drivers/media/dvb/dvb-usb/lmedm04.c
new file mode 100644
index 000000000000..9eea4188303b
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/lmedm04.c
@@ -0,0 +1,1113 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
+ * LME2510C + LG TDQY-P001F
+ * LME2510 + LG TDQY-P001F
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MV001F (LME2510+LGTDQY-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * For firmware see Documentation/dvb/lmedm04.txt
+ *
+ * I2C addresses:
+ * 0xd0 - STV0288 - Demodulator
+ * 0xc0 - Sharp IX2505V - Tuner
+ * --or--
+ * 0x1c - TDA10086 - Demodulator
+ * 0xc0 - TDA8263 - Tuner
+ *
+ * ***Please Note***
+ * There are other variants of the DM04
+ * ***NOT SUPPORTED***
+ * MV0194 (LME2510+SHARP0194)
+ * MVB0194 (LME2510C+SHARP0194)
+ *
+ *
+ * VID = 3344 PID LME2510=1122 LME2510C=1120
+ *
+ * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
+ * LME2510(C)(C) Leaguerme (Shenzhen) MicroElectronics Co., Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ *
+ * Known Issues :
+ * LME2510: Non Intel USB chipsets fail to maintain High Speed on
+ * Boot or Hot Plug.
+ *
+ * QQbox suffers from noise on LNB voltage.
+ *
+ * PID functions have been removed from this driver version due to
+ * problems with different firmware and application versions.
+ */
+#define DVB_USB_LOG_PREFIX "LME2510(C)"
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#include "dvb-usb.h"
+#include "lmedm04.h"
+#include "tda826x.h"
+#include "tda10086.h"
+#include "stv0288.h"
+#include "ix2505v.h"
+
+
+
+/* debug */
+static int dvb_usb_lme2510_debug;
+#define l_dprintk(var, level, args...) do { \
+ if ((var >= level)) \
+ printk(KERN_DEBUG DVB_USB_LOG_PREFIX ": " args); \
+} while (0)
+
+#define deb_info(level, args...) l_dprintk(dvb_usb_lme2510_debug, level, args)
+#define debug_data_snipet(level, name, p) \
+ deb_info(level, name" (%02x%02x%02x%02x%02x%02x%02x%02x)", \
+ *p, *(p+1), *(p+2), *(p+3), *(p+4), \
+ *(p+5), *(p+6), *(p+7));
+
+
+module_param_named(debug, dvb_usb_lme2510_debug, int, 0644);
+MODULE_PARM_DESC(debug, "set debugging level (1=info (or-able))."
+ DVB_USB_DEBUG_STATUS);
+
+static int dvb_usb_lme2510_firmware;
+module_param_named(firmware, dvb_usb_lme2510_firmware, int, 0644);
+MODULE_PARM_DESC(firmware, "set default firmware 0=Sharp7395 1=LG");
+
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+#define TUNER_LG 0x1
+#define TUNER_S7395 0x2
+
+struct lme2510_state {
+ u8 id;
+ u8 tuner_config;
+ u8 signal_lock;
+ u8 signal_level;
+ u8 signal_sn;
+ u8 time_key;
+ u8 i2c_talk_onoff;
+ u8 i2c_gate;
+ u8 i2c_tuner_gate_w;
+ u8 i2c_tuner_gate_r;
+ u8 i2c_tuner_addr;
+ u8 stream_on;
+ void *buffer;
+ struct urb *lme_urb;
+ void *usb_buffer;
+
+};
+
+static int lme2510_bulk_write(struct usb_device *dev,
+ u8 *snd, int len, u8 pipe)
+{
+ int ret, actual_l;
+
+ ret = usb_bulk_msg(dev, usb_sndbulkpipe(dev, pipe),
+ snd, len , &actual_l, 100);
+ return ret;
+}
+
+static int lme2510_bulk_read(struct usb_device *dev,
+ u8 *rev, int len, u8 pipe)
+{
+ int ret, actual_l;
+
+ ret = usb_bulk_msg(dev, usb_rcvbulkpipe(dev, pipe),
+ rev, len , &actual_l, 200);
+ return ret;
+}
+
+static int lme2510_usb_talk(struct dvb_usb_device *d,
+ u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ struct lme2510_state *st = d->priv;
+ u8 *buff;
+ int ret = 0;
+
+ if (st->usb_buffer == NULL) {
+ st->usb_buffer = kmalloc(512, GFP_KERNEL);
+ if (st->usb_buffer == NULL) {
+ info("MEM Error no memory");
+ return -ENOMEM;
+ }
+ }
+ buff = st->usb_buffer;
+
+ /* the read/write capped at 512 */
+ memcpy(buff, wbuf, (wlen > 512) ? 512 : wlen);
+
+ ret = mutex_lock_interruptible(&d->usb_mutex);
+
+ if (ret < 0)
+ return -EAGAIN;
+
+ ret |= usb_clear_halt(d->udev, usb_sndbulkpipe(d->udev, 0x01));
+
+ ret |= lme2510_bulk_write(d->udev, buff, wlen , 0x01);
+
+ msleep(10);
+
+ ret |= usb_clear_halt(d->udev, usb_rcvbulkpipe(d->udev, 0x01));
+
+ ret |= lme2510_bulk_read(d->udev, buff, (rlen > 512) ?
+ 512 : rlen , 0x01);
+
+ if (rlen > 0)
+ memcpy(rbuf, buff, rlen);
+
+ mutex_unlock(&d->usb_mutex);
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme2510_stream_restart(struct dvb_usb_device *d)
+{
+ static u8 stream_on[] = LME_ST_ON_W;
+ int ret;
+ u8 rbuff[10];
+ /*Restart Stream Command*/
+ ret = lme2510_usb_talk(d, stream_on, sizeof(stream_on),
+ rbuff, sizeof(rbuff));
+ return ret;
+}
+static int lme2510_remote_keypress(struct dvb_usb_adapter *adap, u16 keypress)
+{
+ struct dvb_usb_device *d = adap->dev;
+
+ deb_info(1, "INT Key Keypress =%04x", keypress);
+
+ if (keypress > 0)
+ rc_keydown(d->rc_dev, keypress, 0);
+
+ return 0;
+}
+
+static void lme2510_int_response(struct urb *lme_urb)
+{
+ struct dvb_usb_adapter *adap = lme_urb->context;
+ struct lme2510_state *st = adap->dev->priv;
+ static u8 *ibuf, *rbuf;
+ int i = 0, offset;
+
+ switch (lme_urb->status) {
+ case 0:
+ case -ETIMEDOUT:
+ break;
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default:
+ info("Error %x", lme_urb->status);
+ break;
+ }
+
+ rbuf = (u8 *) lme_urb->transfer_buffer;
+
+ offset = ((lme_urb->actual_length/8) > 4)
+ ? 4 : (lme_urb->actual_length/8) ;
+
+ for (i = 0; i < offset; ++i) {
+ ibuf = (u8 *)&rbuf[i*8];
+ deb_info(5, "INT O/S C =%02x C/O=%02x Type =%02x%02x",
+ offset, i, ibuf[0], ibuf[1]);
+
+ switch (ibuf[0]) {
+ case 0xaa:
+ debug_data_snipet(1, "INT Remote data snipet in", ibuf);
+ lme2510_remote_keypress(adap,
+ (u16)(ibuf[4]<<8)+ibuf[5]);
+ break;
+ case 0xbb:
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (ibuf[2] > 0)
+ st->signal_lock = ibuf[2];
+ st->signal_level = ibuf[4];
+ st->signal_sn = ibuf[3];
+ st->time_key = ibuf[7];
+ break;
+ case TUNER_S7395:
+ /* Tweak for earlier firmware*/
+ if (ibuf[1] == 0x03) {
+ if (ibuf[2] > 1)
+ st->signal_lock = ibuf[2];
+ st->signal_level = ibuf[3];
+ st->signal_sn = ibuf[4];
+ } else {
+ st->signal_level = ibuf[4];
+ st->signal_sn = ibuf[5];
+ st->signal_lock =
+ (st->signal_lock & 0xf7) +
+ ((ibuf[2] & 0x01) << 0x03);
+ }
+ break;
+ default:
+ break;
+ }
+ debug_data_snipet(5, "INT Remote data snipet in", ibuf);
+ break;
+ case 0xcc:
+ debug_data_snipet(1, "INT Control data snipet", ibuf);
+ break;
+ default:
+ debug_data_snipet(1, "INT Unknown data snipet", ibuf);
+ break;
+ }
+ }
+ usb_submit_urb(lme_urb, GFP_ATOMIC);
+}
+
+static int lme2510_int_read(struct dvb_usb_adapter *adap)
+{
+ struct lme2510_state *lme_int = adap->dev->priv;
+
+ lme_int->lme_urb = usb_alloc_urb(0, GFP_ATOMIC);
+
+ if (lme_int->lme_urb == NULL)
+ return -ENOMEM;
+
+ lme_int->buffer = usb_alloc_coherent(adap->dev->udev, 5000, GFP_ATOMIC,
+ &lme_int->lme_urb->transfer_dma);
+
+ if (lme_int->buffer == NULL)
+ return -ENOMEM;
+
+ usb_fill_int_urb(lme_int->lme_urb,
+ adap->dev->udev,
+ usb_rcvintpipe(adap->dev->udev, 0xa),
+ lme_int->buffer,
+ 4096,
+ lme2510_int_response,
+ adap,
+ 11);
+
+ lme_int->lme_urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_submit_urb(lme_int->lme_urb, GFP_ATOMIC);
+ info("INT Interupt Service Started");
+
+ return 0;
+}
+
+static int lme2510_return_status(struct usb_device *dev)
+{
+ int ret = 0;
+ u8 data[10] = {0};
+
+ ret |= usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x06, 0x80, 0x0302, 0x00, data, 0x0006, 200);
+ info("Firmware Status: %x (%x)", ret , data[2]);
+
+ return (ret < 0) ? -ENODEV : data[2];
+}
+
+static int lme2510_msg(struct dvb_usb_device *d,
+ u8 *wbuf, int wlen, u8 *rbuf, int rlen)
+{
+ int ret = 0;
+ struct lme2510_state *st = d->priv;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ if (st->i2c_talk_onoff == 1) {
+
+ ret = lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (wbuf[2] == 0x1c) {
+ if (wbuf[3] == 0x0e) {
+ st->signal_lock = rbuf[1];
+ if ((st->stream_on & 1) &&
+ (st->signal_lock & 0x10)) {
+ lme2510_stream_restart(d);
+ st->i2c_talk_onoff = 0;
+ }
+ msleep(80);
+ }
+ }
+ break;
+ case TUNER_S7395:
+ if (wbuf[2] == 0xd0) {
+ if (wbuf[3] == 0x24) {
+ st->signal_lock = rbuf[1];
+ if ((st->stream_on & 1) &&
+ (st->signal_lock & 0x8)) {
+ lme2510_stream_restart(d);
+ st->i2c_talk_onoff = 0;
+ }
+ }
+ if ((wbuf[3] != 0x6) & (wbuf[3] != 0x5))
+ msleep(5);
+ }
+ break;
+ default:
+ break;
+ }
+ } else {
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ switch (wbuf[3]) {
+ case 0x0e:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_lock;
+ break;
+ case 0x43:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_level;
+ break;
+ case 0x1c:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_sn;
+ break;
+ case 0x15:
+ case 0x16:
+ case 0x17:
+ case 0x18:
+ rbuf[0] = 0x55;
+ rbuf[1] = 0x00;
+ break;
+ default:
+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 1;
+ break;
+ }
+ break;
+ case TUNER_S7395:
+ switch (wbuf[3]) {
+ case 0x10:
+ rbuf[0] = 0x55;
+ rbuf[1] = (st->signal_level & 0x80)
+ ? 0 : (st->signal_level * 2);
+ break;
+ case 0x2d:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_sn;
+ break;
+ case 0x24:
+ rbuf[0] = 0x55;
+ rbuf[1] = st->signal_lock;
+ break;
+ case 0x2e:
+ case 0x26:
+ case 0x27:
+ rbuf[0] = 0x55;
+ rbuf[1] = 0x00;
+ break;
+ default:
+ lme2510_usb_talk(d, wbuf, wlen, rbuf, rlen);
+ st->i2c_talk_onoff = 1;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ deb_info(4, "I2C From Interupt Message out(%02x) in(%02x)",
+ wbuf[3], rbuf[1]);
+
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
+}
+
+
+static int lme2510_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ struct lme2510_state *st = d->priv;
+ static u8 obuf[64], ibuf[512];
+ int i, read, read_o;
+ u16 len;
+ u8 gate = st->i2c_gate;
+
+ if (gate == 0)
+ gate = 5;
+
+ if (num > 2)
+ warn("more than 2 i2c messages"
+ "at a time is not handled yet. TODO.");
+
+ for (i = 0; i < num; i++) {
+ read_o = 1 & (msg[i].flags & I2C_M_RD);
+ read = i+1 < num && (msg[i+1].flags & I2C_M_RD);
+ read |= read_o;
+ gate = (msg[i].addr == st->i2c_tuner_addr)
+ ? (read) ? st->i2c_tuner_gate_r
+ : st->i2c_tuner_gate_w
+ : st->i2c_gate;
+ obuf[0] = gate | (read << 7);
+
+ if (gate == 5)
+ obuf[1] = (read) ? 2 : msg[i].len + 1;
+ else
+ obuf[1] = msg[i].len + read + 1;
+
+ obuf[2] = msg[i].addr;
+ if (read) {
+ if (read_o)
+ len = 3;
+ else {
+ memcpy(&obuf[3], msg[i].buf, msg[i].len);
+ obuf[msg[i].len+3] = msg[i+1].len;
+ len = msg[i].len+4;
+ }
+ } else {
+ memcpy(&obuf[3], msg[i].buf, msg[i].len);
+ len = msg[i].len+3;
+ }
+
+ if (lme2510_msg(d, obuf, len, ibuf, 512) < 0) {
+ deb_info(1, "i2c transfer failed.");
+ return -EAGAIN;
+ }
+
+ if (read) {
+ if (read_o)
+ memcpy(msg[i].buf, &ibuf[1], msg[i].len);
+ else {
+ memcpy(msg[i+1].buf, &ibuf[1], msg[i+1].len);
+ i++;
+ }
+ }
+ }
+ return i;
+}
+
+static u32 lme2510_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm lme2510_i2c_algo = {
+ .master_xfer = lme2510_i2c_xfer,
+ .functionality = lme2510_i2c_func,
+};
+
+/* Callbacks for DVB USB */
+static int lme2510_identify_state(struct usb_device *udev,
+ struct dvb_usb_device_properties *props,
+ struct dvb_usb_device_description **desc,
+ int *cold)
+{
+ if (lme2510_return_status(udev) == 0x44)
+ *cold = 1;
+ else
+ *cold = 0;
+ return 0;
+}
+
+static int lme2510_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ struct lme2510_state *st = adap->dev->priv;
+ static u8 clear_reg_3[] = LME_CLEAR_PID;
+ static u8 rbuf[1];
+ int ret = 0, rlen = sizeof(rbuf);
+
+ deb_info(1, "STM (%02x)", onoff);
+
+ /* Streaming is started by FE_HAS_LOCK */
+ if (onoff == 1)
+ st->stream_on = 1;
+ else {
+ deb_info(1, "STM Steam Off");
+ /* mutex is here only to avoid collision with I2C */
+ ret = mutex_lock_interruptible(&adap->dev->i2c_mutex);
+
+ ret |= lme2510_usb_talk(adap->dev, clear_reg_3,
+ sizeof(clear_reg_3), rbuf, rlen);
+ st->stream_on = 0;
+ st->i2c_talk_onoff = 1;
+
+ mutex_unlock(&adap->dev->i2c_mutex);
+ }
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme2510_int_service(struct dvb_usb_adapter *adap)
+{
+ struct dvb_usb_device *d = adap->dev;
+ struct rc_dev *rc;
+ int ret;
+
+ info("STA Configuring Remote");
+
+ rc = rc_allocate_device();
+ if (!rc)
+ return -ENOMEM;
+
+ usb_make_path(d->udev, d->rc_phys, sizeof(d->rc_phys));
+ strlcat(d->rc_phys, "/ir0", sizeof(d->rc_phys));
+
+ rc->input_name = "LME2510 Remote Control";
+ rc->input_phys = d->rc_phys;
+ rc->map_name = RC_MAP_LME2510;
+ rc->driver_name = "LME 2510";
+ usb_to_input_id(d->udev, &rc->input_id);
+
+ ret = rc_register_device(rc);
+ if (ret) {
+ rc_free_device(rc);
+ return ret;
+ }
+ d->rc_dev = rc;
+
+ /* Start the Interupt */
+ ret = lme2510_int_read(adap);
+ if (ret < 0) {
+ rc_unregister_device(rc);
+ info("INT Unable to start Interupt Service");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static u8 check_sum(u8 *p, u8 len)
+{
+ u8 sum = 0;
+ while (len--)
+ sum += *p++;
+ return sum;
+}
+
+static int lme2510_download_firmware(struct usb_device *dev,
+ const struct firmware *fw)
+{
+ int ret = 0;
+ u8 data[512] = {0};
+ u16 j, wlen, len_in, start, end;
+ u8 packet_size, dlen, i;
+ u8 *fw_data;
+
+ packet_size = 0x31;
+ len_in = 1;
+
+
+ info("FRM Starting Firmware Download");
+
+ for (i = 1; i < 3; i++) {
+ start = (i == 1) ? 0 : 512;
+ end = (i == 1) ? 512 : fw->size;
+ for (j = start; j < end; j += (packet_size+1)) {
+ fw_data = (u8 *)(fw->data + j);
+ if ((end - j) > packet_size) {
+ data[0] = i;
+ dlen = packet_size;
+ } else {
+ data[0] = i | 0x80;
+ dlen = (u8)(end - j)-1;
+ }
+ data[1] = dlen;
+ memcpy(&data[2], fw_data, dlen+1);
+ wlen = (u8) dlen + 4;
+ data[wlen-1] = check_sum(fw_data, dlen+1);
+ deb_info(1, "Data S=%02x:E=%02x CS= %02x", data[3],
+ data[dlen+2], data[dlen+3]);
+ ret |= lme2510_bulk_write(dev, data, wlen, 1);
+ ret |= lme2510_bulk_read(dev, data, len_in , 1);
+ ret |= (data[0] == 0x88) ? 0 : -1;
+ }
+ }
+
+ usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x06, 0x80, 0x0200, 0x00, data, 0x0109, 1000);
+
+
+ data[0] = 0x8a;
+ len_in = 1;
+ msleep(2000);
+ ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Resetting*/
+ ret |= lme2510_bulk_read(dev, data, len_in, 1);
+ msleep(400);
+
+ if (ret < 0)
+ info("FRM Firmware Download Failed (%04x)" , ret);
+ else
+ info("FRM Firmware Download Completed - Resetting Device");
+
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+/* Default firmware for LME2510C */
+const char lme_firmware[50] = "dvb-usb-lme2510c-s7395.fw";
+
+static void lme_coldreset(struct usb_device *dev)
+{
+ int ret = 0, len_in;
+ u8 data[512] = {0};
+
+ data[0] = 0x0a;
+ len_in = 1;
+ info("FRM Firmware Cold Reset");
+ ret |= lme2510_bulk_write(dev, data , len_in, 1); /*Cold Resetting*/
+ ret |= lme2510_bulk_read(dev, data, len_in, 1);
+
+ return;
+}
+
+static int lme_firmware_switch(struct usb_device *udev, int cold)
+{
+ const struct firmware *fw = NULL;
+ char lme2510c_s7395[] = "dvb-usb-lme2510c-s7395.fw";
+ char lme2510c_lg[] = "dvb-usb-lme2510c-lg.fw";
+ char *firm_msg[] = {"Loading", "Switching to"};
+ int ret;
+
+ cold = (cold > 0) ? (cold & 1) : 0;
+
+ if (udev->descriptor.idProduct == 0x1122)
+ return 0;
+
+ switch (dvb_usb_lme2510_firmware) {
+ case 0:
+ default:
+ memcpy(&lme_firmware, lme2510c_s7395, sizeof(lme2510c_s7395));
+ ret = request_firmware(&fw, lme_firmware, &udev->dev);
+ if (ret == 0) {
+ info("FRM %s S7395 Firmware", firm_msg[cold]);
+ break;
+ }
+ if (cold == 0)
+ dvb_usb_lme2510_firmware = 1;
+ else
+ cold = 0;
+ case 1:
+ memcpy(&lme_firmware, lme2510c_lg, sizeof(lme2510c_lg));
+ ret = request_firmware(&fw, lme_firmware, &udev->dev);
+ if (ret == 0) {
+ info("FRM %s LG Firmware", firm_msg[cold]);
+ break;
+ }
+ info("FRM No Firmware Found - please install");
+ dvb_usb_lme2510_firmware = 0;
+ cold = 0;
+ break;
+ }
+
+ release_firmware(fw);
+
+ if (cold) {
+ lme_coldreset(udev);
+ return -ENODEV;
+ }
+
+ return ret;
+}
+
+static int lme2510_kill_urb(struct usb_data_stream *stream)
+{
+ int i;
+
+ for (i = 0; i < stream->urbs_submitted; i++) {
+ deb_info(3, "killing URB no. %d.", i);
+ /* stop the URB */
+ usb_kill_urb(stream->urb_list[i]);
+ }
+ stream->urbs_submitted = 0;
+
+ return 0;
+}
+
+static struct tda10086_config tda10086_config = {
+ .demod_address = 0x1c,
+ .invert = 0,
+ .diseqc_tone = 1,
+ .xtal_freq = TDA10086_XTAL_16M,
+};
+
+static struct stv0288_config lme_config = {
+ .demod_address = 0xd0,
+ .min_delay_ms = 15,
+ .inittab = s7395_inittab,
+};
+
+static struct ix2505v_config lme_tuner = {
+ .tuner_address = 0xc0,
+ .min_delay_ms = 100,
+ .tuner_gain = 0x0,
+ .tuner_chargepump = 0x3,
+};
+
+static int dm04_lme2510_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct dvb_usb_adapter *adap = fe->dvb->priv;
+ static u8 voltage_low[] = LME_VOLTAGE_L;
+ static u8 voltage_high[] = LME_VOLTAGE_H;
+ static u8 rbuf[1];
+ int ret = 0, len = 3, rlen = 1;
+
+ if (mutex_lock_interruptible(&adap->dev->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_18:
+ ret |= lme2510_usb_talk(adap->dev,
+ voltage_high, len, rbuf, rlen);
+ break;
+
+ case SEC_VOLTAGE_OFF:
+ case SEC_VOLTAGE_13:
+ default:
+ ret |= lme2510_usb_talk(adap->dev,
+ voltage_low, len, rbuf, rlen);
+ break;
+ }
+
+ mutex_unlock(&adap->dev->i2c_mutex);
+
+ return (ret < 0) ? -ENODEV : 0;
+}
+
+static int lme_name(struct dvb_usb_adapter *adap)
+{
+ struct lme2510_state *st = adap->dev->priv;
+ const char *desc = adap->dev->desc->name;
+ char *fe_name[] = {"", " LG TDQY-P001F", " SHARP:BS2F7HZ7395"};
+ char *name = adap->fe->ops.info.name;
+
+ strlcpy(name, desc, 128);
+ strlcat(name, fe_name[st->tuner_config], 128);
+
+ return 0;
+}
+
+static int dm04_lme2510_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct lme2510_state *st = adap->dev->priv;
+
+ int ret = 0;
+
+ st->i2c_talk_onoff = 1;
+
+ st->i2c_gate = 4;
+ adap->fe = dvb_attach(tda10086_attach, &tda10086_config,
+ &adap->dev->i2c_adap);
+
+ if (adap->fe) {
+ info("TUN Found Frontend TDA10086");
+ st->i2c_tuner_gate_w = 4;
+ st->i2c_tuner_gate_r = 4;
+ st->i2c_tuner_addr = 0xc0;
+ st->tuner_config = TUNER_LG;
+ if (dvb_usb_lme2510_firmware != 1) {
+ dvb_usb_lme2510_firmware = 1;
+ ret = lme_firmware_switch(adap->dev->udev, 1);
+ } else /*stops LG/Sharp multi tuner problems*/
+ dvb_usb_lme2510_firmware = 0;
+ goto end;
+ }
+
+ st->i2c_gate = 5;
+ adap->fe = dvb_attach(stv0288_attach, &lme_config,
+ &adap->dev->i2c_adap);
+
+ if (adap->fe) {
+ info("FE Found Stv0288");
+ st->i2c_tuner_gate_w = 4;
+ st->i2c_tuner_gate_r = 5;
+ st->i2c_tuner_addr = 0xc0;
+ st->tuner_config = TUNER_S7395;
+ if (dvb_usb_lme2510_firmware != 0) {
+ dvb_usb_lme2510_firmware = 0;
+ ret = lme_firmware_switch(adap->dev->udev, 1);
+ }
+ } else {
+ info("DM04 Not Supported");
+ return -ENODEV;
+ }
+
+end: if (ret) {
+ kfree(adap->fe);
+ adap->fe = NULL;
+ return -ENODEV;
+ }
+
+ adap->fe->ops.set_voltage = dm04_lme2510_set_voltage;
+ ret = lme_name(adap);
+
+ return ret;
+}
+
+static int dm04_lme2510_tuner(struct dvb_usb_adapter *adap)
+{
+ struct lme2510_state *st = adap->dev->priv;
+ char *tun_msg[] = {"", "TDA8263", "IX2505V"};
+ int ret = 0;
+
+ switch (st->tuner_config) {
+ case TUNER_LG:
+ if (dvb_attach(tda826x_attach, adap->fe, 0xc0,
+ &adap->dev->i2c_adap, 1))
+ ret = st->tuner_config;
+ break;
+ case TUNER_S7395:
+ if (dvb_attach(ix2505v_attach , adap->fe, &lme_tuner,
+ &adap->dev->i2c_adap))
+ ret = st->tuner_config;
+ break;
+ default:
+ break;
+ }
+
+ if (ret)
+ info("TUN Found %s tuner", tun_msg[ret]);
+ else {
+ info("TUN No tuner found --- reseting device");
+ lme_coldreset(adap->dev->udev);
+ return -ENODEV;
+ }
+
+ /* Start the Interupt & Remote*/
+ ret = lme2510_int_service(adap);
+
+ return ret;
+}
+
+static int lme2510_powerup(struct dvb_usb_device *d, int onoff)
+{
+ struct lme2510_state *st = d->priv;
+ static u8 lnb_on[] = LNB_ON;
+ static u8 lnb_off[] = LNB_OFF;
+ static u8 rbuf[1];
+ int ret, len = 3, rlen = 1;
+
+ ret = mutex_lock_interruptible(&d->i2c_mutex);
+
+ if (onoff)
+ ret |= lme2510_usb_talk(d, lnb_on, len, rbuf, rlen);
+ else
+ ret |= lme2510_usb_talk(d, lnb_off, len, rbuf, rlen);
+
+ st->i2c_talk_onoff = 1;
+
+ mutex_unlock(&d->i2c_mutex);
+
+ return ret;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties lme2510_properties;
+static struct dvb_usb_device_properties lme2510c_properties;
+
+static int lme2510_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *udev = interface_to_usbdev(intf);
+ int ret = 0;
+
+ usb_reset_configuration(udev);
+
+ usb_set_interface(udev, intf->cur_altsetting->desc.bInterfaceNumber, 1);
+
+ if (udev->speed != USB_SPEED_HIGH) {
+ ret = usb_reset_device(udev);
+ info("DEV Failed to connect in HIGH SPEED mode");
+ return -ENODEV;
+ }
+
+ lme_firmware_switch(udev, 0);
+
+ if (0 == dvb_usb_device_init(intf, &lme2510_properties,
+ THIS_MODULE, NULL, adapter_nr)) {
+ info("DEV registering device driver");
+ return 0;
+ }
+ if (0 == dvb_usb_device_init(intf, &lme2510c_properties,
+ THIS_MODULE, NULL, adapter_nr)) {
+ info("DEV registering device driver");
+ return 0;
+ }
+
+ info("DEV lme2510 Error");
+ return -ENODEV;
+
+}
+
+static struct usb_device_id lme2510_table[] = {
+ { USB_DEVICE(0x3344, 0x1122) }, /* LME2510 */
+ { USB_DEVICE(0x3344, 0x1120) }, /* LME2510C */
+ {} /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE(usb, lme2510_table);
+
+static struct dvb_usb_device_properties lme2510_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .download_firmware = lme2510_download_firmware,
+ .firmware = "dvb-usb-lme2510-lg.fw",
+
+ .size_of_priv = sizeof(struct lme2510_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = lme2510_streaming_ctrl,
+ .frontend_attach = dm04_lme2510_frontend_attach,
+ .tuner_attach = dm04_lme2510_tuner,
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x06,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+
+ }
+ }
+ }
+ }
+ },
+ .power_ctrl = lme2510_powerup,
+ .identify_state = lme2510_identify_state,
+ .i2c_algo = &lme2510_i2c_algo,
+ .generic_bulk_ctrl_endpoint = 0,
+ .num_device_descs = 1,
+ .devices = {
+ { "DM04_LME2510_DVB-S",
+ { &lme2510_table[0], NULL },
+ },
+
+ }
+};
+
+static struct dvb_usb_device_properties lme2510c_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+ .download_firmware = lme2510_download_firmware,
+ .firmware = lme_firmware,
+ .size_of_priv = sizeof(struct lme2510_state),
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = lme2510_streaming_ctrl,
+ .frontend_attach = dm04_lme2510_frontend_attach,
+ .tuner_attach = dm04_lme2510_tuner,
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_BULK,
+ .count = 10,
+ .endpoint = 0x8,
+ .u = {
+ .bulk = {
+ .buffersize = 4096,
+
+ }
+ }
+ }
+ }
+ },
+ .power_ctrl = lme2510_powerup,
+ .identify_state = lme2510_identify_state,
+ .i2c_algo = &lme2510_i2c_algo,
+ .generic_bulk_ctrl_endpoint = 0,
+ .num_device_descs = 1,
+ .devices = {
+ { "DM04_LME2510C_DVB-S",
+ { &lme2510_table[1], NULL },
+ },
+ }
+};
+
+void *lme2510_exit_int(struct dvb_usb_device *d)
+{
+ struct lme2510_state *st = d->priv;
+ struct dvb_usb_adapter *adap = &d->adapter[0];
+ void *buffer = NULL;
+
+ if (adap != NULL) {
+ lme2510_kill_urb(&adap->stream);
+ adap->feedcount = 0;
+ }
+
+ if (st->lme_urb != NULL) {
+ st->i2c_talk_onoff = 1;
+ st->signal_lock = 0;
+ st->signal_level = 0;
+ st->signal_sn = 0;
+ buffer = st->usb_buffer;
+ usb_kill_urb(st->lme_urb);
+ usb_free_coherent(d->udev, 5000, st->buffer,
+ st->lme_urb->transfer_dma);
+ info("Interupt Service Stopped");
+ rc_unregister_device(d->rc_dev);
+ info("Remote Stopped");
+ }
+ return buffer;
+}
+
+void lme2510_exit(struct usb_interface *intf)
+{
+ struct dvb_usb_device *d = usb_get_intfdata(intf);
+ void *usb_buffer;
+
+ if (d != NULL) {
+ usb_buffer = lme2510_exit_int(d);
+ dvb_usb_device_exit(intf);
+ kfree(usb_buffer);
+ }
+}
+
+static struct usb_driver lme2510_driver = {
+ .name = "LME2510C_DVB-S",
+ .probe = lme2510_probe,
+ .disconnect = lme2510_exit,
+ .id_table = lme2510_table,
+};
+
+/* module stuff */
+static int __init lme2510_module_init(void)
+{
+ int result = usb_register(&lme2510_driver);
+ if (result) {
+ err("usb_register failed. Error number %d", result);
+ return result;
+ }
+
+ return 0;
+}
+
+static void __exit lme2510_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&lme2510_driver);
+}
+
+module_init(lme2510_module_init);
+module_exit(lme2510_module_exit);
+
+MODULE_AUTHOR("Malcolm Priestley <tvboxspy@gmail.com>");
+MODULE_DESCRIPTION("LME2510(C) DVB-S USB2.0");
+MODULE_VERSION("1.74");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/dvb-usb/lmedm04.h b/drivers/media/dvb/dvb-usb/lmedm04.h
new file mode 100644
index 000000000000..e6af16c1e3e5
--- /dev/null
+++ b/drivers/media/dvb/dvb-usb/lmedm04.h
@@ -0,0 +1,173 @@
+/* DVB USB compliant linux driver for
+ *
+ * DM04/QQBOX DVB-S USB BOX LME2510C + SHARP:BS2F7HZ7395
+ * LME2510C + LG TDQY-P001F
+ * LME2510 + LG TDQY-P001F
+ *
+ * MVB7395 (LME2510C+SHARP:BS2F7HZ7395)
+ * SHARP:BS2F7HZ7395 = (STV0288+Sharp IX2505V)
+ *
+ * MVB001F (LME2510+LGTDQT-P001F)
+ * LG TDQY - P001F =(TDA8263 + TDA10086H)
+ *
+ * MVB0001F (LME2510C+LGTDQT-P001F)
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ * *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_LME2510_H_
+#define _DVB_USB_LME2510_H_
+
+/* Streamer & PID
+ *
+ * Note: These commands do not actually stop the streaming
+ * but form some kind of packet filtering/stream count
+ * or tuning related functions.
+ * 06 XX
+ * offset 1 = 00 Enable Streaming
+ *
+ *
+ * PID
+ * 03 XX XX ----> reg number ---> setting....20 XX
+ * offset 1 = length
+ * offset 2 = start of data
+ * end byte -1 = 20
+ * end byte = clear pid always a0, other wise 9c, 9a ??
+ *
+*/
+#define LME_ST_ON_W {0x06, 0x00}
+#define LME_CLEAR_PID {0x03, 0x02, 0x20, 0xa0}
+
+/* LNB Voltage
+ * 07 XX XX
+ * offset 1 = 01
+ * offset 2 = 00=Voltage low 01=Voltage high
+ *
+ * LNB Power
+ * 03 01 XX
+ * offset 2 = 00=ON 01=OFF
+ */
+
+#define LME_VOLTAGE_L {0x07, 0x01, 0x00}
+#define LME_VOLTAGE_H {0x07, 0x01, 0x01}
+#define LNB_ON {0x3a, 0x01, 0x00}
+#define LNB_OFF {0x3a, 0x01, 0x01}
+
+/* Initial stv0288 settings for 7395 Frontend */
+static u8 s7395_inittab[] = {
+ 0x01, 0x15,
+ 0x02, 0x20,
+ 0x03, 0xa0,
+ 0x04, 0xa0,
+ 0x05, 0x12,
+ 0x06, 0x00,
+ 0x09, 0x00,
+ 0x0a, 0x04,
+ 0x0b, 0x00,
+ 0x0c, 0x00,
+ 0x0d, 0x00,
+ 0x0e, 0xc1,
+ 0x0f, 0x54,
+ 0x11, 0x7a,
+ 0x12, 0x03,
+ 0x13, 0x48,
+ 0x14, 0x84,
+ 0x15, 0xc5,
+ 0x16, 0xb8,
+ 0x17, 0x9c,
+ 0x18, 0x00,
+ 0x19, 0xa6,
+ 0x1a, 0x88,
+ 0x1b, 0x8f,
+ 0x1c, 0xf0,
+ 0x20, 0x0b,
+ 0x21, 0x54,
+ 0x22, 0xff,
+ 0x23, 0x01,
+ 0x28, 0x46,
+ 0x29, 0x66,
+ 0x2a, 0x90,
+ 0x2b, 0xfa,
+ 0x2c, 0xd9,
+ 0x30, 0x0,
+ 0x31, 0x1e,
+ 0x32, 0x14,
+ 0x33, 0x0f,
+ 0x34, 0x09,
+ 0x35, 0x0c,
+ 0x36, 0x05,
+ 0x37, 0x2f,
+ 0x38, 0x16,
+ 0x39, 0xbd,
+ 0x3a, 0x0,
+ 0x3b, 0x13,
+ 0x3c, 0x11,
+ 0x3d, 0x30,
+ 0x40, 0x63,
+ 0x41, 0x04,
+ 0x42, 0x60,
+ 0x43, 0x00,
+ 0x44, 0x00,
+ 0x45, 0x00,
+ 0x46, 0x00,
+ 0x47, 0x00,
+ 0x4a, 0x00,
+ 0x50, 0x12,
+ 0x51, 0x36,
+ 0x52, 0x21,
+ 0x53, 0x94,
+ 0x54, 0xb2,
+ 0x55, 0x29,
+ 0x56, 0x64,
+ 0x57, 0x2b,
+ 0x58, 0x54,
+ 0x59, 0x86,
+ 0x5a, 0x00,
+ 0x5b, 0x9b,
+ 0x5c, 0x08,
+ 0x5d, 0x7f,
+ 0x5e, 0xff,
+ 0x5f, 0x8d,
+ 0x70, 0x0,
+ 0x71, 0x0,
+ 0x72, 0x0,
+ 0x74, 0x0,
+ 0x75, 0x0,
+ 0x76, 0x0,
+ 0x81, 0x0,
+ 0x82, 0x3f,
+ 0x83, 0x3f,
+ 0x84, 0x0,
+ 0x85, 0x0,
+ 0x88, 0x0,
+ 0x89, 0x0,
+ 0x8a, 0x0,
+ 0x8b, 0x0,
+ 0x8c, 0x0,
+ 0x90, 0x0,
+ 0x91, 0x0,
+ 0x92, 0x0,
+ 0x93, 0x0,
+ 0x94, 0x1c,
+ 0x97, 0x0,
+ 0xa0, 0x48,
+ 0xa1, 0x0,
+ 0xb0, 0xb8,
+ 0xb1, 0x3a,
+ 0xb2, 0x10,
+ 0xb3, 0x82,
+ 0xb4, 0x80,
+ 0xb5, 0x82,
+ 0xb6, 0x82,
+ 0xb7, 0x82,
+ 0xb8, 0x20,
+ 0xb9, 0x0,
+ 0xf0, 0x0,
+ 0xf1, 0x0,
+ 0xf2, 0xc0,
+ 0xff, 0xff,
+};
+#endif
diff --git a/drivers/media/dvb/dvb-usb/m920x.c b/drivers/media/dvb/dvb-usb/m920x.c
index c211fef45fc3..da9dc91ce910 100644
--- a/drivers/media/dvb/dvb-usb/m920x.c
+++ b/drivers/media/dvb/dvb-usb/m920x.c
@@ -69,7 +69,7 @@ static int m920x_init(struct dvb_usb_device *d, struct m920x_inits *rc_seq)
int adap_enabled[M9206_MAX_ADAPTERS] = { 0 };
/* Remote controller init. */
- if (d->props.rc_query) {
+ if (d->props.rc.legacy.rc_query) {
deb("Initialising remote control\n");
while (rc_seq->address) {
if ((ret = m920x_write(d->udev, M9206_CORE,
@@ -142,9 +142,9 @@ static int m920x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
if ((ret = m920x_read(d->udev, M9206_CORE, 0x0, M9206_RC_KEY, rc_state + 1, 1)) != 0)
goto unlock;
- for (i = 0; i < d->props.rc_key_map_size; i++)
- if (rc5_data(&d->props.rc_key_map[i]) == rc_state[1]) {
- *event = d->props.rc_key_map[i].event;
+ for (i = 0; i < d->props.rc.legacy.rc_map_size; i++)
+ if (rc5_data(&d->props.rc.legacy.rc_map_table[i]) == rc_state[1]) {
+ *event = d->props.rc.legacy.rc_map_table[i].keycode;
switch(rc_state[0]) {
case 0x80:
@@ -589,7 +589,7 @@ static struct m920x_inits pinnacle310e_init[] = {
};
/* ir keymaps */
-static struct dvb_usb_rc_key ir_codes_megasky_table [] = {
+static struct rc_map_table rc_map_megasky_table[] = {
{ 0x0012, KEY_POWER },
{ 0x001e, KEY_CYCLEWINDOWS }, /* min/max */
{ 0x0002, KEY_CHANNELUP },
@@ -608,7 +608,7 @@ static struct dvb_usb_rc_key ir_codes_megasky_table [] = {
{ 0x000e, KEY_COFFEE }, /* "MTS" */
};
-static struct dvb_usb_rc_key ir_codes_tvwalkertwin_table [] = {
+static struct rc_map_table rc_map_tvwalkertwin_table[] = {
{ 0x0001, KEY_ZOOM }, /* Full Screen */
{ 0x0002, KEY_CAMERA }, /* snapshot */
{ 0x0003, KEY_MUTE },
@@ -628,7 +628,7 @@ static struct dvb_usb_rc_key ir_codes_tvwalkertwin_table [] = {
{ 0x001e, KEY_VOLUMEUP },
};
-static struct dvb_usb_rc_key ir_codes_pinnacle310e_table[] = {
+static struct rc_map_table rc_map_pinnacle310e_table[] = {
{ 0x16, KEY_POWER },
{ 0x17, KEY_FAVORITES },
{ 0x0f, KEY_TEXT },
@@ -784,10 +784,12 @@ static struct dvb_usb_device_properties megasky_properties = {
.firmware = "dvb-usb-megasky-02.fw",
.download_firmware = m920x_firmware_download,
- .rc_interval = 100,
- .rc_key_map = ir_codes_megasky_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_megasky_table),
- .rc_query = m920x_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_megasky_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_megasky_table),
+ .rc_query = m920x_rc_query,
+ },
.size_of_priv = sizeof(struct m920x_state),
@@ -885,10 +887,12 @@ static struct dvb_usb_device_properties tvwalkertwin_properties = {
.firmware = "dvb-usb-tvwalkert.fw",
.download_firmware = m920x_firmware_download,
- .rc_interval = 100,
- .rc_key_map = ir_codes_tvwalkertwin_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_tvwalkertwin_table),
- .rc_query = m920x_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_tvwalkertwin_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_tvwalkertwin_table),
+ .rc_query = m920x_rc_query,
+ },
.size_of_priv = sizeof(struct m920x_state),
@@ -992,10 +996,12 @@ static struct dvb_usb_device_properties pinnacle_pctv310e_properties = {
.usb_ctrl = DEVICE_SPECIFIC,
.download_firmware = NULL,
- .rc_interval = 100,
- .rc_key_map = ir_codes_pinnacle310e_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_pinnacle310e_table),
- .rc_query = m920x_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_pinnacle310e_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_pinnacle310e_table),
+ .rc_query = m920x_rc_query,
+ },
.size_of_priv = sizeof(struct m920x_state),
diff --git a/drivers/media/dvb/dvb-usb/nova-t-usb2.c b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
index d195a587cc65..9d3cd2de46fc 100644
--- a/drivers/media/dvb/dvb-usb/nova-t-usb2.c
+++ b/drivers/media/dvb/dvb-usb/nova-t-usb2.c
@@ -21,7 +21,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define deb_ee(args...) dprintk(debug,0x02,args)
/* Hauppauge NOVA-T USB2 keys */
-static struct dvb_usb_rc_key ir_codes_haupp_table [] = {
+static struct rc_map_table rc_map_haupp_table[] = {
{ 0x1e00, KEY_0 },
{ 0x1e01, KEY_1 },
{ 0x1e02, KEY_2 },
@@ -91,14 +91,14 @@ static int nova_t_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
deb_rc("raw key code 0x%02x, 0x%02x, 0x%02x to c: %02x d: %02x toggle: %d\n",key[1],key[2],key[3],custom,data,toggle);
- for (i = 0; i < ARRAY_SIZE(ir_codes_haupp_table); i++) {
- if (rc5_data(&ir_codes_haupp_table[i]) == data &&
- rc5_custom(&ir_codes_haupp_table[i]) == custom) {
+ for (i = 0; i < ARRAY_SIZE(rc_map_haupp_table); i++) {
+ if (rc5_data(&rc_map_haupp_table[i]) == data &&
+ rc5_custom(&rc_map_haupp_table[i]) == custom) {
- deb_rc("c: %x, d: %x\n", rc5_data(&ir_codes_haupp_table[i]),
- rc5_custom(&ir_codes_haupp_table[i]));
+ deb_rc("c: %x, d: %x\n", rc5_data(&rc_map_haupp_table[i]),
+ rc5_custom(&rc_map_haupp_table[i]));
- *event = ir_codes_haupp_table[i].event;
+ *event = rc_map_haupp_table[i].keycode;
*state = REMOTE_KEY_PRESSED;
if (st->old_toggle == toggle) {
if (st->last_repeat_count++ < 2)
@@ -195,10 +195,12 @@ static struct dvb_usb_device_properties nova_t_properties = {
.power_ctrl = dibusb2_0_power_ctrl,
.read_mac_address = nova_t_read_mac_address,
- .rc_interval = 100,
- .rc_key_map = ir_codes_haupp_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_haupp_table),
- .rc_query = nova_t_rc_query,
+ .rc.legacy = {
+ .rc_interval = 100,
+ .rc_map_table = rc_map_haupp_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_haupp_table),
+ .rc_query = nova_t_rc_query,
+ },
.i2c_algo = &dibusb_i2c_algo,
diff --git a/drivers/media/dvb/dvb-usb/opera1.c b/drivers/media/dvb/dvb-usb/opera1.c
index dfb81ff1d9a7..1f1b7d6980a5 100644
--- a/drivers/media/dvb/dvb-usb/opera1.c
+++ b/drivers/media/dvb/dvb-usb/opera1.c
@@ -35,7 +35,7 @@
struct opera1_state {
u32 last_key_pressed;
};
-struct ir_codes_opera_table {
+struct rc_map_opera_table {
u32 keycode;
u32 event;
};
@@ -331,7 +331,7 @@ static int opera1_pid_filter_control(struct dvb_usb_adapter *adap, int onoff)
return 0;
}
-static struct dvb_usb_rc_key ir_codes_opera1_table[] = {
+static struct rc_map_table rc_map_opera1_table[] = {
{0x5fa0, KEY_1},
{0x51af, KEY_2},
{0x5da2, KEY_3},
@@ -404,12 +404,12 @@ static int opera1_rc_query(struct dvb_usb_device *dev, u32 * event, int *state)
send_key = (send_key & 0xffff) | 0x0100;
- for (i = 0; i < ARRAY_SIZE(ir_codes_opera1_table); i++) {
- if (rc5_scan(&ir_codes_opera1_table[i]) == (send_key & 0xffff)) {
+ for (i = 0; i < ARRAY_SIZE(rc_map_opera1_table); i++) {
+ if (rc5_scan(&rc_map_opera1_table[i]) == (send_key & 0xffff)) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_opera1_table[i].event;
+ *event = rc_map_opera1_table[i].keycode;
opst->last_key_pressed =
- ir_codes_opera1_table[i].event;
+ rc_map_opera1_table[i].keycode;
break;
}
opst->last_key_pressed = 0;
@@ -483,9 +483,7 @@ static int opera1_xilinx_load_firmware(struct usb_device *dev,
}
}
kfree(p);
- if (fw) {
- release_firmware(fw);
- }
+ release_firmware(fw);
return ret;
}
@@ -498,10 +496,12 @@ static struct dvb_usb_device_properties opera1_properties = {
.power_ctrl = opera1_power_ctrl,
.i2c_algo = &opera1_i2c_algo,
- .rc_key_map = ir_codes_opera1_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_opera1_table),
- .rc_interval = 200,
- .rc_query = opera1_rc_query,
+ .rc.legacy = {
+ .rc_map_table = rc_map_opera1_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_opera1_table),
+ .rc_interval = 200,
+ .rc_query = opera1_rc_query,
+ },
.read_mac_address = opera1_read_mac_address,
.generic_bulk_ctrl_endpoint = 0x00,
/* parameter for the MPEG2-data transfer */
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index 20ca9d9ee99b..0d4709ff9cbb 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -29,6 +29,8 @@
#include "tda826x.h"
#include "tda10086.h"
+#include "tda1002x.h"
+#include "tda827x.h"
#include "lnbp21.h"
/* debug */
@@ -41,6 +43,7 @@ DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct ttusb2_state {
u8 id;
+ u16 last_rc_key;
};
static int ttusb2_msg(struct dvb_usb_device *d, u8 cmd,
@@ -126,6 +129,33 @@ static struct i2c_algorithm ttusb2_i2c_algo = {
.functionality = ttusb2_i2c_func,
};
+/* command to poll IR receiver (copied from pctv452e.c) */
+#define CMD_GET_IR_CODE 0x1b
+
+/* IR */
+static int tt3650_rc_query(struct dvb_usb_device *d)
+{
+ int ret;
+ u8 rx[9]; /* A CMD_GET_IR_CODE reply is 9 bytes long */
+ struct ttusb2_state *st = d->priv;
+ ret = ttusb2_msg(d, CMD_GET_IR_CODE, NULL, 0, rx, sizeof(rx));
+ if (ret != 0)
+ return ret;
+
+ if (rx[8] & 0x01) {
+ /* got a "press" event */
+ st->last_rc_key = (rx[3] << 8) | rx[2];
+ deb_info("%s: cmd=0x%02x sys=0x%02x\n", __func__, rx[2], rx[3]);
+ rc_keydown(d->rc_dev, st->last_rc_key, 0);
+ } else if (st->last_rc_key) {
+ rc_keyup(d->rc_dev);
+ st->last_rc_key = 0;
+ }
+
+ return 0;
+}
+
+
/* Callbacks for DVB USB */
static int ttusb2_identify_state (struct usb_device *udev, struct
dvb_usb_device_properties *props, struct dvb_usb_device_description **desc,
@@ -150,7 +180,17 @@ static struct tda10086_config tda10086_config = {
.xtal_freq = TDA10086_XTAL_16M,
};
-static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
+static struct tda10023_config tda10023_config = {
+ .demod_address = 0x0c,
+ .invert = 0,
+ .xtal = 16000000,
+ .pll_m = 11,
+ .pll_p = 3,
+ .pll_n = 1,
+ .deltaf = 0xa511,
+};
+
+static int ttusb2_frontend_tda10086_attach(struct dvb_usb_adapter *adap)
{
if (usb_set_interface(adap->dev->udev,0,3) < 0)
err("set interface to alts=3 failed");
@@ -163,7 +203,27 @@ static int ttusb2_frontend_attach(struct dvb_usb_adapter *adap)
return 0;
}
-static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
+static int ttusb2_frontend_tda10023_attach(struct dvb_usb_adapter *adap)
+{
+ if (usb_set_interface(adap->dev->udev, 0, 3) < 0)
+ err("set interface to alts=3 failed");
+ if ((adap->fe = dvb_attach(tda10023_attach, &tda10023_config, &adap->dev->i2c_adap, 0x48)) == NULL) {
+ deb_info("TDA10023 attach failed\n");
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int ttusb2_tuner_tda827x_attach(struct dvb_usb_adapter *adap)
+{
+ if (dvb_attach(tda827x_attach, adap->fe, 0x61, &adap->dev->i2c_adap, NULL) == NULL) {
+ printk(KERN_ERR "%s: No tda827x found!\n", __func__);
+ return -ENODEV;
+ }
+ return 0;
+}
+
+static int ttusb2_tuner_tda826x_attach(struct dvb_usb_adapter *adap)
{
if (dvb_attach(tda826x_attach, adap->fe, 0x60, &adap->dev->i2c_adap, 0) == NULL) {
deb_info("TDA8263 attach failed\n");
@@ -180,6 +240,7 @@ static int ttusb2_tuner_attach(struct dvb_usb_adapter *adap)
/* DVB USB Driver stuff */
static struct dvb_usb_device_properties ttusb2_properties;
static struct dvb_usb_device_properties ttusb2_properties_s2400;
+static struct dvb_usb_device_properties ttusb2_properties_ct3650;
static int ttusb2_probe(struct usb_interface *intf,
const struct usb_device_id *id)
@@ -187,6 +248,8 @@ static int ttusb2_probe(struct usb_interface *intf,
if (0 == dvb_usb_device_init(intf, &ttusb2_properties,
THIS_MODULE, NULL, adapter_nr) ||
0 == dvb_usb_device_init(intf, &ttusb2_properties_s2400,
+ THIS_MODULE, NULL, adapter_nr) ||
+ 0 == dvb_usb_device_init(intf, &ttusb2_properties_ct3650,
THIS_MODULE, NULL, adapter_nr))
return 0;
return -ENODEV;
@@ -197,6 +260,8 @@ static struct usb_device_id ttusb2_table [] = {
{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
{ USB_DEVICE(USB_VID_TECHNOTREND,
USB_PID_TECHNOTREND_CONNECT_S2400) },
+ { USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_CONNECT_CT3650) },
{} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, ttusb2_table);
@@ -214,8 +279,8 @@ static struct dvb_usb_device_properties ttusb2_properties = {
{
.streaming_ctrl = NULL, // ttusb2_streaming_ctrl,
- .frontend_attach = ttusb2_frontend_attach,
- .tuner_attach = ttusb2_tuner_attach,
+ .frontend_attach = ttusb2_frontend_tda10086_attach,
+ .tuner_attach = ttusb2_tuner_tda826x_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
@@ -266,8 +331,8 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
{
.streaming_ctrl = NULL,
- .frontend_attach = ttusb2_frontend_attach,
- .tuner_attach = ttusb2_tuner_attach,
+ .frontend_attach = ttusb2_frontend_tda10086_attach,
+ .tuner_attach = ttusb2_tuner_tda826x_attach,
/* parameter for the MPEG2-data transfer */
.stream = {
@@ -301,6 +366,59 @@ static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
}
};
+static struct dvb_usb_device_properties ttusb2_properties_ct3650 = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+
+ .size_of_priv = sizeof(struct ttusb2_state),
+
+ .rc.core = {
+ .rc_interval = 150, /* Less than IR_KEYPRESS_TIMEOUT */
+ .rc_codes = RC_MAP_TT_1500,
+ .rc_query = tt3650_rc_query,
+ .allowed_protos = RC_TYPE_UNKNOWN,
+ },
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = NULL,
+
+ .frontend_attach = ttusb2_frontend_tda10023_attach,
+ .tuner_attach = ttusb2_tuner_tda827x_attach,
+
+ /* parameter for the MPEG2-data transfer */
+ .stream = {
+ .type = USB_ISOC,
+ .count = 5,
+ .endpoint = 0x02,
+ .u = {
+ .isoc = {
+ .framesperurb = 4,
+ .framesize = 940,
+ .interval = 1,
+ }
+ }
+ }
+ },
+ },
+
+ .power_ctrl = ttusb2_power_ctrl,
+ .identify_state = ttusb2_identify_state,
+
+ .i2c_algo = &ttusb2_i2c_algo,
+
+ .generic_bulk_ctrl_endpoint = 0x01,
+
+ .num_device_descs = 1,
+ .devices = {
+ { "Technotrend TT-connect CT-3650",
+ .warm_ids = { &ttusb2_table[3], NULL },
+ },
+ }
+};
+
static struct usb_driver ttusb2_driver = {
.name = "dvb_usb_ttusb2",
.probe = ttusb2_probe,
diff --git a/drivers/media/dvb/dvb-usb/vp702x.c b/drivers/media/dvb/dvb-usb/vp702x.c
index 4d332451653b..7890e75600df 100644
--- a/drivers/media/dvb/dvb-usb/vp702x.c
+++ b/drivers/media/dvb/dvb-usb/vp702x.c
@@ -174,7 +174,7 @@ static int vp702x_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
}
/* keys for the enclosed remote control */
-static struct dvb_usb_rc_key ir_codes_vp702x_table[] = {
+static struct rc_map_table rc_map_vp702x_table[] = {
{ 0x0001, KEY_1 },
{ 0x0002, KEY_2 },
};
@@ -197,10 +197,10 @@ static int vp702x_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
- for (i = 0; i < ARRAY_SIZE(ir_codes_vp702x_table); i++)
- if (rc5_custom(&ir_codes_vp702x_table[i]) == key[1]) {
+ for (i = 0; i < ARRAY_SIZE(rc_map_vp702x_table); i++)
+ if (rc5_custom(&rc_map_vp702x_table[i]) == key[1]) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_vp702x_table[i].event;
+ *event = rc_map_vp702x_table[i].keycode;
break;
}
return 0;
@@ -283,10 +283,12 @@ static struct dvb_usb_device_properties vp702x_properties = {
},
.read_mac_address = vp702x_read_mac_addr,
- .rc_key_map = ir_codes_vp702x_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_vp702x_table),
- .rc_interval = 400,
- .rc_query = vp702x_rc_query,
+ .rc.legacy = {
+ .rc_map_table = rc_map_vp702x_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_vp702x_table),
+ .rc_interval = 400,
+ .rc_query = vp702x_rc_query,
+ },
.num_device_descs = 1,
.devices = {
diff --git a/drivers/media/dvb/dvb-usb/vp7045.c b/drivers/media/dvb/dvb-usb/vp7045.c
index 036893fa4480..ab0ab3c35e80 100644
--- a/drivers/media/dvb/dvb-usb/vp7045.c
+++ b/drivers/media/dvb/dvb-usb/vp7045.c
@@ -99,7 +99,7 @@ static int vp7045_power_ctrl(struct dvb_usb_device *d, int onoff)
/* The keymapping struct. Somehow this should be loaded to the driver, but
* currently it is hardcoded. */
-static struct dvb_usb_rc_key ir_codes_vp7045_table[] = {
+static struct rc_map_table rc_map_vp7045_table[] = {
{ 0x0016, KEY_POWER },
{ 0x0010, KEY_MUTE },
{ 0x0003, KEY_1 },
@@ -165,10 +165,10 @@ static int vp7045_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
return 0;
}
- for (i = 0; i < ARRAY_SIZE(ir_codes_vp7045_table); i++)
- if (rc5_data(&ir_codes_vp7045_table[i]) == key) {
+ for (i = 0; i < ARRAY_SIZE(rc_map_vp7045_table); i++)
+ if (rc5_data(&rc_map_vp7045_table[i]) == key) {
*state = REMOTE_KEY_PRESSED;
- *event = ir_codes_vp7045_table[i].event;
+ *event = rc_map_vp7045_table[i].keycode;
break;
}
return 0;
@@ -259,10 +259,12 @@ static struct dvb_usb_device_properties vp7045_properties = {
.power_ctrl = vp7045_power_ctrl,
.read_mac_address = vp7045_read_mac_addr,
- .rc_interval = 400,
- .rc_key_map = ir_codes_vp7045_table,
- .rc_key_map_size = ARRAY_SIZE(ir_codes_vp7045_table),
- .rc_query = vp7045_rc_query,
+ .rc.legacy = {
+ .rc_interval = 400,
+ .rc_map_table = rc_map_vp7045_table,
+ .rc_map_size = ARRAY_SIZE(rc_map_vp7045_table),
+ .rc_query = vp7045_rc_query,
+ },
.num_device_descs = 2,
.devices = {
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
index 26333b4f4d3e..b34ca7afb0e6 100644
--- a/drivers/media/dvb/firewire/firedtv-1394.c
+++ b/drivers/media/dvb/firewire/firedtv-1394.c
@@ -58,7 +58,7 @@ static void rawiso_activity_cb(struct hpsb_iso *iso)
num = hpsb_iso_n_ready(iso);
if (!fdtv) {
- dev_err(fdtv->device, "received at unknown iso channel\n");
+ pr_err("received at unknown iso channel\n");
goto out;
}
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
index 28294af752db..f0f1842fab60 100644
--- a/drivers/media/dvb/firewire/firedtv-avc.c
+++ b/drivers/media/dvb/firewire/firedtv-avc.c
@@ -24,6 +24,8 @@
#include <linux/wait.h>
#include <linux/workqueue.h>
+#include <dvb_frontend.h>
+
#include "firedtv.h"
#define FCP_COMMAND_REGISTER 0xfffff0000b00ULL
@@ -130,6 +132,20 @@ MODULE_PARM_DESC(debug, "Verbose logging (none = 0"
", FCP payloads = " __stringify(AVC_DEBUG_FCP_PAYLOADS)
", or a combination, or all = -1)");
+/*
+ * This is a workaround since there is no vendor specific command to retrieve
+ * ca_info using AVC. If this parameter is not used, ca_system_id will be
+ * filled with application_manufacturer from ca_app_info.
+ * Digital Everywhere have said that adding ca_info is on their TODO list.
+ */
+static unsigned int num_fake_ca_system_ids;
+static int fake_ca_system_ids[4] = { -1, -1, -1, -1 };
+module_param_array(fake_ca_system_ids, int, &num_fake_ca_system_ids, 0644);
+MODULE_PARM_DESC(fake_ca_system_ids, "If your CAM application manufacturer "
+ "does not have the same ca_system_id as your CAS, you can "
+ "override what ca_system_ids are presented to the "
+ "application by setting this field to an array of ids.");
+
static const char *debug_fcp_ctype(unsigned int ctype)
{
static const char *ctypes[] = {
@@ -368,10 +384,30 @@ static int avc_tuner_tuneqpsk(struct firedtv *fdtv,
c->operand[12] = 0;
if (fdtv->type == FIREDTV_DVB_S2) {
- c->operand[13] = 0x1;
- c->operand[14] = 0xff;
- c->operand[15] = 0xff;
-
+ if (fdtv->fe.dtv_property_cache.delivery_system == SYS_DVBS2) {
+ switch (fdtv->fe.dtv_property_cache.modulation) {
+ case QAM_16: c->operand[13] = 0x1; break;
+ case QPSK: c->operand[13] = 0x2; break;
+ case PSK_8: c->operand[13] = 0x3; break;
+ default: c->operand[13] = 0x2; break;
+ }
+ switch (fdtv->fe.dtv_property_cache.rolloff) {
+ case ROLLOFF_AUTO: c->operand[14] = 0x2; break;
+ case ROLLOFF_35: c->operand[14] = 0x2; break;
+ case ROLLOFF_20: c->operand[14] = 0x0; break;
+ case ROLLOFF_25: c->operand[14] = 0x1; break;
+ /* case ROLLOFF_NONE: c->operand[14] = 0xff; break; */
+ }
+ switch (fdtv->fe.dtv_property_cache.pilot) {
+ case PILOT_AUTO: c->operand[15] = 0x0; break;
+ case PILOT_OFF: c->operand[15] = 0x0; break;
+ case PILOT_ON: c->operand[15] = 0x1; break;
+ }
+ } else {
+ c->operand[13] = 0x1; /* auto modulation */
+ c->operand[14] = 0xff; /* disable rolloff */
+ c->operand[15] = 0xff; /* disable pilot */
+ }
return 16;
} else {
return 13;
@@ -977,7 +1013,7 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
{
struct avc_command_frame *c = (void *)fdtv->avc_data;
struct avc_response_frame *r = (void *)fdtv->avc_data;
- int pos, ret;
+ int i, pos, ret;
mutex_lock(&fdtv->avc_mutex);
@@ -1004,9 +1040,18 @@ int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
app_info[1] = (EN50221_TAG_CA_INFO >> 8) & 0xff;
app_info[2] = (EN50221_TAG_CA_INFO >> 0) & 0xff;
- app_info[3] = 2;
- app_info[4] = r->operand[pos + 0];
- app_info[5] = r->operand[pos + 1];
+ if (num_fake_ca_system_ids == 0) {
+ app_info[3] = 2;
+ app_info[4] = r->operand[pos + 0];
+ app_info[5] = r->operand[pos + 1];
+ } else {
+ app_info[3] = num_fake_ca_system_ids * 2;
+ for (i = 0; i < num_fake_ca_system_ids; i++) {
+ app_info[4 + i * 2] =
+ (fake_ca_system_ids[i] >> 8) & 0xff;
+ app_info[5 + i * 2] = fake_ca_system_ids[i] & 0xff;
+ }
+ }
*len = app_info[3] + 4;
out:
mutex_unlock(&fdtv->avc_mutex);
diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c
index d3c2cf60de76..8ffb565f0704 100644
--- a/drivers/media/dvb/firewire/firedtv-ci.c
+++ b/drivers/media/dvb/firewire/firedtv-ci.c
@@ -220,6 +220,7 @@ static const struct file_operations fdtv_ca_fops = {
.open = dvb_generic_open,
.release = dvb_generic_release,
.poll = fdtv_ca_io_poll,
+ .llseek = noop_llseek,
};
static struct dvb_device fdtv_ca = {
diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c
index e49cdc88b0c7..d10920e2f3a2 100644
--- a/drivers/media/dvb/firewire/firedtv-fe.c
+++ b/drivers/media/dvb/firewire/firedtv-fe.c
@@ -155,6 +155,16 @@ static int fdtv_get_frontend(struct dvb_frontend *fe,
return -EOPNOTSUPP;
}
+static int fdtv_get_property(struct dvb_frontend *fe, struct dtv_property *tvp)
+{
+ return 0;
+}
+
+static int fdtv_set_property(struct dvb_frontend *fe, struct dtv_property *tvp)
+{
+ return 0;
+}
+
void fdtv_frontend_init(struct firedtv *fdtv)
{
struct dvb_frontend_ops *ops = &fdtv->fe.ops;
@@ -166,6 +176,9 @@ void fdtv_frontend_init(struct firedtv *fdtv)
ops->set_frontend = fdtv_set_frontend;
ops->get_frontend = fdtv_get_frontend;
+ ops->get_property = fdtv_get_property;
+ ops->set_property = fdtv_set_property;
+
ops->read_status = fdtv_read_status;
ops->read_ber = fdtv_read_ber;
ops->read_signal_strength = fdtv_read_signal_strength;
@@ -179,7 +192,6 @@ void fdtv_frontend_init(struct firedtv *fdtv)
switch (fdtv->type) {
case FIREDTV_DVB_S:
- case FIREDTV_DVB_S2:
fi->type = FE_QPSK;
fi->frequency_min = 950000;
@@ -188,7 +200,7 @@ void fdtv_frontend_init(struct firedtv *fdtv)
fi->symbol_rate_min = 1000000;
fi->symbol_rate_max = 40000000;
- fi->caps = FE_CAN_INVERSION_AUTO |
+ fi->caps = FE_CAN_INVERSION_AUTO |
FE_CAN_FEC_1_2 |
FE_CAN_FEC_2_3 |
FE_CAN_FEC_3_4 |
@@ -198,6 +210,26 @@ void fdtv_frontend_init(struct firedtv *fdtv)
FE_CAN_QPSK;
break;
+ case FIREDTV_DVB_S2:
+ fi->type = FE_QPSK;
+
+ fi->frequency_min = 950000;
+ fi->frequency_max = 2150000;
+ fi->frequency_stepsize = 125;
+ fi->symbol_rate_min = 1000000;
+ fi->symbol_rate_max = 40000000;
+
+ fi->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_2G_MODULATION;
+ break;
+
case FIREDTV_DVB_C:
fi->type = FE_QAM;
diff --git a/drivers/media/dvb/firewire/firedtv-fw.c b/drivers/media/dvb/firewire/firedtv-fw.c
index 75afe4f81e33..7424b0493f9d 100644
--- a/drivers/media/dvb/firewire/firedtv-fw.c
+++ b/drivers/media/dvb/firewire/firedtv-fw.c
@@ -194,8 +194,8 @@ static const struct firedtv_backend backend = {
static void handle_fcp(struct fw_card *card, struct fw_request *request,
int tcode, int destination, int source, int generation,
- int speed, unsigned long long offset,
- void *payload, size_t length, void *callback_data)
+ unsigned long long offset, void *payload, size_t length,
+ void *callback_data)
{
struct firedtv *f, *fdtv = NULL;
struct fw_device *device;
diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c
index fcf3828472b8..f82d4a93feb3 100644
--- a/drivers/media/dvb/firewire/firedtv-rc.c
+++ b/drivers/media/dvb/firewire/firedtv-rc.c
@@ -172,7 +172,8 @@ void fdtv_unregister_rc(struct firedtv *fdtv)
void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
{
- u16 *keycode = fdtv->remote_ctrl_dev->keycode;
+ struct input_dev *idev = fdtv->remote_ctrl_dev;
+ u16 *keycode = idev->keycode;
if (code >= 0x0300 && code <= 0x031f)
code = keycode[code - 0x0300];
@@ -188,6 +189,8 @@ void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
return;
}
- input_report_key(fdtv->remote_ctrl_dev, code, 1);
- input_report_key(fdtv->remote_ctrl_dev, code, 0);
+ input_report_key(idev, code, 1);
+ input_sync(idev);
+ input_report_key(idev, code, 0);
+ input_sync(idev);
}
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index cd7f9b7cbffa..b8519ba511e5 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -1,7 +1,7 @@
config DVB_FE_CUSTOMISE
bool "Customise the frontend modules to build"
depends on DVB_CORE
- default N
+ default y if EXPERT
help
This allows the user to select/deselect frontend drivers for their
hardware from the build.
@@ -12,9 +12,8 @@ config DVB_FE_CUSTOMISE
If unsure say N.
-if DVB_FE_CUSTOMISE
-
menu "Customise DVB Frontends"
+ visible if DVB_FE_CUSTOMISE
comment "Multistandard (satellite) frontends"
depends on DVB_CORE
@@ -257,6 +256,13 @@ config DVB_CX22702
help
A DVB-T tuner module. Say Y when you want to support this frontend.
+config DVB_S5H1432
+ tristate "Samsung s5h1432 demodulator (OFDM)"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
config DVB_DRX397XD
tristate "Micronas DRX3975D/DRX3977D based"
depends on DVB_CORE && I2C
@@ -455,16 +461,8 @@ config DVB_LGDT330X
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
-config DVB_LGDT3304
- tristate "LG Electronics LGDT3304"
- depends on DVB_CORE && I2C
- default m if DVB_FE_CUSTOMISE
- help
- An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
- to support this frontend.
-
config DVB_LGDT3305
- tristate "LG Electronics LGDT3305 based"
+ tristate "LG Electronics LGDT3304 and LGDT3305 based"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
@@ -499,7 +497,7 @@ comment "ISDB-T (terrestrial) frontends"
depends on DVB_CORE
config DVB_S921
- tristate "Sharp S921 tuner"
+ tristate "Sharp S921 frontend"
depends on DVB_CORE && I2C
default m if DVB_FE_CUSTOMISE
help
@@ -514,6 +512,14 @@ config DVB_DIB8000
A driver for DiBcom's DiB8000 ISDB-T/ISDB-Tsb demodulator.
Say Y when you want to support this frontend.
+config DVB_MB86A20S
+ tristate "Fujitsu mb86a20s"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ A driver for Fujitsu mb86a20s ISDB-T/ISDB-Tsb demodulator.
+ Say Y when you want to support this frontend.
+
comment "Digital terrestrial only tuners/PLL"
depends on DVB_CORE
@@ -584,6 +590,7 @@ config DVB_LGS8GL5
config DVB_LGS8GXX
tristate "Legend Silicon LGS8913/LGS8GL5/LGS8GXX DMB-TH demodulator"
depends on DVB_CORE && I2C
+ select FW_LOADER
default m if DVB_FE_CUSTOMISE
help
A DMB-TH tuner module. Say Y when you want to support this frontend.
@@ -606,11 +613,16 @@ config DVB_TDA665x
Currently supported tuners:
* Panasonic ENV57H12D5 (ET-50DT)
+config DVB_IX2505V
+ tristate "Sharp IX2505V silicon tuner"
+ 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.
+
comment "Tools to develop new frontends"
config DVB_DUMMY_FE
tristate "Dummy frontend driver"
default n
endmenu
-
-endif
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 874e8ada4d1d..b1d9525aa7e3 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -5,7 +5,6 @@
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/
EXTRA_CFLAGS += -Idrivers/media/common/tuners/
-s921-objs := s921_module.o s921_core.o
stb0899-objs = stb0899_drv.o stb0899_algo.o
stv0900-objs = stv0900_core.o stv0900_sw.o
au8522-objs = au8522_dig.o au8522_decoder.o
@@ -16,6 +15,7 @@ obj-$(CONFIG_DVB_STB0899) += stb0899.o
obj-$(CONFIG_DVB_STB6100) += stb6100.o
obj-$(CONFIG_DVB_SP8870) += sp8870.o
obj-$(CONFIG_DVB_CX22700) += cx22700.o
+obj-$(CONFIG_DVB_S5H1432) += s5h1432.o
obj-$(CONFIG_DVB_CX24110) += cx24110.o
obj-$(CONFIG_DVB_TDA8083) += tda8083.o
obj-$(CONFIG_DVB_L64781) += l64781.o
@@ -45,7 +45,6 @@ obj-$(CONFIG_DVB_OR51132) += or51132.o
obj-$(CONFIG_DVB_BCM3510) += bcm3510.o
obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
-obj-$(CONFIG_DVB_LGDT3304) += lgdt3304.o
obj-$(CONFIG_DVB_LGDT3305) += lgdt3305.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
@@ -82,3 +81,5 @@ obj-$(CONFIG_DVB_ISL6423) += isl6423.o
obj-$(CONFIG_DVB_EC100) += ec100.o
obj-$(CONFIG_DVB_DS3000) += ds3000.o
obj-$(CONFIG_DVB_MB86A16) += mb86a16.o
+obj-$(CONFIG_DVB_MB86A20S) += mb86a20s.o
+obj-$(CONFIG_DVB_IX2505V) += ix2505v.o
diff --git a/drivers/media/dvb/frontends/af9013.c b/drivers/media/dvb/frontends/af9013.c
index 12e018b4107d..ba25fa0b0fc2 100644
--- a/drivers/media/dvb/frontends/af9013.c
+++ b/drivers/media/dvb/frontends/af9013.c
@@ -1,5 +1,5 @@
/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
*
@@ -42,6 +42,8 @@ struct af9013_state {
struct af9013_config config;
+ /* tuner/demod RF and IF AGC limits used for signal strength calc */
+ u8 signal_strength_en, rf_50, rf_80, if_50, if_80;
u16 signal_strength;
u32 ber;
u32 ucblocks;
@@ -220,184 +222,37 @@ static u32 af913_div(u32 a, u32 b, u32 x)
static int af9013_set_coeff(struct af9013_state *state, fe_bandwidth_t bw)
{
- int ret = 0;
- u8 i = 0;
- u8 buf[24];
- 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);
-
+ int ret, i, j, found;
deb_info("%s: adc_clock:%d bw:%d\n", __func__,
state->config.adc_clock, bw);
- switch (state->config.adc_clock) {
- case 28800: /* 28.800 MHz */
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- ns_coeff1_2048nu = 0x01e79e7a;
- ns_coeff1_8191nu = 0x0079eb6e;
- ns_coeff1_8192nu = 0x0079e79e;
- ns_coeff1_8193nu = 0x0079e3cf;
- ns_coeff2_2k = 0x00f3cf3d;
- ns_coeff2_8k = 0x003cf3cf;
- break;
- case BANDWIDTH_7_MHZ:
- ns_coeff1_2048nu = 0x0238e38e;
- ns_coeff1_8191nu = 0x008e3d55;
- ns_coeff1_8192nu = 0x008e38e4;
- ns_coeff1_8193nu = 0x008e3472;
- ns_coeff2_2k = 0x011c71c7;
- ns_coeff2_8k = 0x00471c72;
- break;
- case BANDWIDTH_8_MHZ:
- ns_coeff1_2048nu = 0x028a28a3;
- ns_coeff1_8191nu = 0x00a28f3d;
- ns_coeff1_8192nu = 0x00a28a29;
- ns_coeff1_8193nu = 0x00a28514;
- ns_coeff2_2k = 0x01451451;
- ns_coeff2_8k = 0x00514514;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- case 20480: /* 20.480 MHz */
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- ns_coeff1_2048nu = 0x02adb6dc;
- ns_coeff1_8191nu = 0x00ab7313;
- ns_coeff1_8192nu = 0x00ab6db7;
- ns_coeff1_8193nu = 0x00ab685c;
- ns_coeff2_2k = 0x0156db6e;
- ns_coeff2_8k = 0x0055b6dc;
- break;
- case BANDWIDTH_7_MHZ:
- ns_coeff1_2048nu = 0x03200001;
- ns_coeff1_8191nu = 0x00c80640;
- ns_coeff1_8192nu = 0x00c80000;
- ns_coeff1_8193nu = 0x00c7f9c0;
- ns_coeff2_2k = 0x01900000;
- ns_coeff2_8k = 0x00640000;
- break;
- case BANDWIDTH_8_MHZ:
- ns_coeff1_2048nu = 0x03924926;
- ns_coeff1_8191nu = 0x00e4996e;
- ns_coeff1_8192nu = 0x00e49249;
- ns_coeff1_8193nu = 0x00e48b25;
- ns_coeff2_2k = 0x01c92493;
- ns_coeff2_8k = 0x00724925;
+ /* lookup coeff from table */
+ for (i = 0, found = 0; i < ARRAY_SIZE(coeff_table); i++) {
+ if (coeff_table[i].adc_clock == state->config.adc_clock &&
+ coeff_table[i].bw == bw) {
+ found = 1;
break;
- default:
- ret = -EINVAL;
}
- break;
- case 28000: /* 28.000 MHz */
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- ns_coeff1_2048nu = 0x01f58d10;
- ns_coeff1_8191nu = 0x007d672f;
- ns_coeff1_8192nu = 0x007d6344;
- ns_coeff1_8193nu = 0x007d5f59;
- ns_coeff2_2k = 0x00fac688;
- ns_coeff2_8k = 0x003eb1a2;
- break;
- case BANDWIDTH_7_MHZ:
- ns_coeff1_2048nu = 0x02492492;
- ns_coeff1_8191nu = 0x00924db7;
- ns_coeff1_8192nu = 0x00924925;
- ns_coeff1_8193nu = 0x00924492;
- ns_coeff2_2k = 0x01249249;
- ns_coeff2_8k = 0x00492492;
- break;
- case BANDWIDTH_8_MHZ:
- ns_coeff1_2048nu = 0x029cbc15;
- ns_coeff1_8191nu = 0x00a7343f;
- ns_coeff1_8192nu = 0x00a72f05;
- ns_coeff1_8193nu = 0x00a729cc;
- ns_coeff2_2k = 0x014e5e0a;
- ns_coeff2_8k = 0x00539783;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- case 25000: /* 25.000 MHz */
- switch (bw) {
- case BANDWIDTH_6_MHZ:
- ns_coeff1_2048nu = 0x0231bcb5;
- ns_coeff1_8191nu = 0x008c7391;
- ns_coeff1_8192nu = 0x008c6f2d;
- ns_coeff1_8193nu = 0x008c6aca;
- ns_coeff2_2k = 0x0118de5b;
- ns_coeff2_8k = 0x00463797;
- break;
- case BANDWIDTH_7_MHZ:
- ns_coeff1_2048nu = 0x028f5c29;
- ns_coeff1_8191nu = 0x00a3dc29;
- ns_coeff1_8192nu = 0x00a3d70a;
- ns_coeff1_8193nu = 0x00a3d1ec;
- ns_coeff2_2k = 0x0147ae14;
- ns_coeff2_8k = 0x0051eb85;
- break;
- case BANDWIDTH_8_MHZ:
- ns_coeff1_2048nu = 0x02ecfb9d;
- ns_coeff1_8191nu = 0x00bb44c1;
- ns_coeff1_8192nu = 0x00bb3ee7;
- ns_coeff1_8193nu = 0x00bb390d;
- ns_coeff2_2k = 0x01767dce;
- ns_coeff2_8k = 0x005d9f74;
- break;
- default:
- ret = -EINVAL;
- }
- break;
- default:
- err("invalid xtal");
- return -EINVAL;
}
- if (ret) {
- err("invalid bandwidth");
- return ret;
+
+ if (!found) {
+ err("invalid bw or clock");
+ ret = -EINVAL;
+ goto error;
}
- buf[i++] = (u8) ((ns_coeff1_2048nu & 0x03000000) >> 24);
- buf[i++] = (u8) ((ns_coeff1_2048nu & 0x00ff0000) >> 16);
- buf[i++] = (u8) ((ns_coeff1_2048nu & 0x0000ff00) >> 8);
- buf[i++] = (u8) ((ns_coeff1_2048nu & 0x000000ff));
- buf[i++] = (u8) ((ns_coeff2_2k & 0x01c00000) >> 22);
- buf[i++] = (u8) ((ns_coeff2_2k & 0x003fc000) >> 14);
- buf[i++] = (u8) ((ns_coeff2_2k & 0x00003fc0) >> 6);
- buf[i++] = (u8) ((ns_coeff2_2k & 0x0000003f));
- buf[i++] = (u8) ((ns_coeff1_8191nu & 0x03000000) >> 24);
- buf[i++] = (u8) ((ns_coeff1_8191nu & 0x00ffc000) >> 16);
- buf[i++] = (u8) ((ns_coeff1_8191nu & 0x0000ff00) >> 8);
- buf[i++] = (u8) ((ns_coeff1_8191nu & 0x000000ff));
- buf[i++] = (u8) ((ns_coeff1_8192nu & 0x03000000) >> 24);
- buf[i++] = (u8) ((ns_coeff1_8192nu & 0x00ffc000) >> 16);
- buf[i++] = (u8) ((ns_coeff1_8192nu & 0x0000ff00) >> 8);
- buf[i++] = (u8) ((ns_coeff1_8192nu & 0x000000ff));
- buf[i++] = (u8) ((ns_coeff1_8193nu & 0x03000000) >> 24);
- buf[i++] = (u8) ((ns_coeff1_8193nu & 0x00ffc000) >> 16);
- buf[i++] = (u8) ((ns_coeff1_8193nu & 0x0000ff00) >> 8);
- buf[i++] = (u8) ((ns_coeff1_8193nu & 0x000000ff));
- buf[i++] = (u8) ((ns_coeff2_8k & 0x01c00000) >> 22);
- buf[i++] = (u8) ((ns_coeff2_8k & 0x003fc000) >> 14);
- buf[i++] = (u8) ((ns_coeff2_8k & 0x00003fc0) >> 6);
- buf[i++] = (u8) ((ns_coeff2_8k & 0x0000003f));
-
- deb_info("%s: coeff:", __func__);
- debug_dump(buf, sizeof(buf), deb_info);
+ deb_info("%s: coeff: ", __func__);
+ debug_dump(coeff_table[i].val, sizeof(coeff_table[i].val), deb_info);
/* program */
- for (i = 0; i < sizeof(buf); i++) {
- ret = af9013_write_reg(state, 0xae00 + i, buf[i]);
+ for (j = 0; j < sizeof(coeff_table[i].val); j++) {
+ ret = af9013_write_reg(state, 0xae00 + j,
+ coeff_table[i].val[j]);
if (ret)
break;
}
+error:
return ret;
}
@@ -479,11 +334,24 @@ static int af9013_set_freq_ctrl(struct af9013_state *state, fe_bandwidth_t bw)
if_sample_freq = 3300000; /* 3.3 MHz */
break;
case BANDWIDTH_7_MHZ:
- if_sample_freq = 3800000; /* 3.8 MHz */
+ if_sample_freq = 3500000; /* 3.5 MHz */
+ break;
+ case BANDWIDTH_8_MHZ:
+ default:
+ if_sample_freq = 4000000; /* 4.0 MHz */
+ break;
+ }
+ } else if (state->config.tuner == AF9013_TUNER_TDA18218) {
+ switch (bw) {
+ case BANDWIDTH_6_MHZ:
+ if_sample_freq = 3000000; /* 3 MHz */
+ break;
+ case BANDWIDTH_7_MHZ:
+ if_sample_freq = 3500000; /* 3.5 MHz */
break;
case BANDWIDTH_8_MHZ:
default:
- if_sample_freq = 4300000; /* 4.3 MHz */
+ if_sample_freq = 4000000; /* 4 MHz */
break;
}
}
@@ -761,6 +629,10 @@ static int af9013_set_frontend(struct dvb_frontend *fe,
state->frequency = params->frequency;
+ /* program tuner */
+ if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe, params);
+
/* program CFOE coefficients */
ret = af9013_set_coeff(state, params->u.ofdm.bandwidth);
if (ret)
@@ -791,10 +663,6 @@ static int af9013_set_frontend(struct dvb_frontend *fe,
if (ret)
goto error;
- /* program tuner */
- if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, params);
-
/* program TPS and bandwidth, check if auto mode needed */
ret = af9013_set_ofdm_params(state, &params->u.ofdm, &auto_mode);
if (ret)
@@ -1096,46 +964,32 @@ error:
static int af9013_update_signal_strength(struct dvb_frontend *fe)
{
struct af9013_state *state = fe->demodulator_priv;
- int ret;
- u8 tmp0;
- u8 rf_gain, rf_50, rf_80, if_gain, if_50, if_80;
+ int ret = 0;
+ u8 rf_gain, if_gain;
int signal_strength;
deb_info("%s\n", __func__);
- state->signal_strength = 0;
-
- ret = af9013_read_reg_bits(state, 0x9bee, 0, 1, &tmp0);
- if (ret)
- goto error;
- if (tmp0) {
- ret = af9013_read_reg(state, 0x9bbd, &rf_50);
- if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9bd0, &rf_80);
- if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9be2, &if_50);
- if (ret)
- goto error;
- ret = af9013_read_reg(state, 0x9be4, &if_80);
- if (ret)
- goto error;
+ if (state->signal_strength_en) {
ret = af9013_read_reg(state, 0xd07c, &rf_gain);
if (ret)
goto error;
ret = af9013_read_reg(state, 0xd07d, &if_gain);
if (ret)
goto error;
- signal_strength = (0xffff / (9 * (rf_50 + if_50) - \
- 11 * (rf_80 + if_80))) * (10 * (rf_gain + if_gain) - \
- 11 * (rf_80 + if_80));
+ signal_strength = (0xffff / \
+ (9 * (state->rf_50 + state->if_50) - \
+ 11 * (state->rf_80 + state->if_80))) * \
+ (10 * (rf_gain + if_gain) - \
+ 11 * (state->rf_80 + state->if_80));
if (signal_strength < 0)
signal_strength = 0;
else if (signal_strength > 0xffff)
signal_strength = 0xffff;
state->signal_strength = signal_strength;
+ } else {
+ state->signal_strength = 0;
}
error:
@@ -1184,45 +1038,49 @@ static int af9013_read_status(struct dvb_frontend *fe, fe_status_t *status)
u8 tmp;
*status = 0;
- /* TPS lock */
- ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
- if (ret)
- goto error;
- if (tmp)
- *status |= FE_HAS_VITERBI | FE_HAS_CARRIER | FE_HAS_SIGNAL;
-
/* MPEG2 lock */
ret = af9013_read_reg_bits(state, 0xd507, 6, 1, &tmp);
if (ret)
goto error;
if (tmp)
- *status |= FE_HAS_SYNC | FE_HAS_LOCK;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI |
+ FE_HAS_SYNC | FE_HAS_LOCK;
- if (!(*status & FE_HAS_SIGNAL)) {
- /* AGC lock */
- ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
+ if (!*status) {
+ /* TPS lock */
+ ret = af9013_read_reg_bits(state, 0xd330, 3, 1, &tmp);
if (ret)
goto error;
if (tmp)
- *status |= FE_HAS_SIGNAL;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER |
+ FE_HAS_VITERBI;
}
- if (!(*status & FE_HAS_CARRIER)) {
+ if (!*status) {
/* CFO lock */
ret = af9013_read_reg_bits(state, 0xd333, 7, 1, &tmp);
if (ret)
goto error;
if (tmp)
- *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
}
- if (!(*status & FE_HAS_CARRIER)) {
+ if (!*status) {
/* SFOE lock */
ret = af9013_read_reg_bits(state, 0xd334, 6, 1, &tmp);
if (ret)
goto error;
if (tmp)
- *status |= FE_HAS_CARRIER;
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ }
+
+ if (!*status) {
+ /* AGC lock */
+ ret = af9013_read_reg_bits(state, 0xd1a0, 6, 1, &tmp);
+ if (ret)
+ goto error;
+ if (tmp)
+ *status |= FE_HAS_SIGNAL;
}
ret = af9013_update_statistics(fe);
@@ -1364,6 +1222,7 @@ static int af9013_init(struct dvb_frontend *fe)
break;
case AF9013_TUNER_MXL5005D:
case AF9013_TUNER_MXL5005R:
+ case AF9013_TUNER_MXL5007T:
len = ARRAY_SIZE(tuner_init_mxl5005);
init = tuner_init_mxl5005;
break;
@@ -1389,6 +1248,7 @@ static int af9013_init(struct dvb_frontend *fe)
init = tuner_init_mt2060_2;
break;
case AF9013_TUNER_TDA18271:
+ case AF9013_TUNER_TDA18218:
len = ARRAY_SIZE(tuner_init_tda18271);
init = tuner_init_tda18271;
break;
@@ -1434,6 +1294,27 @@ static int af9013_init(struct dvb_frontend *fe)
if (ret)
goto error;
+ /* read values needed for signal strength calculation */
+ ret = af9013_read_reg_bits(state, 0x9bee, 0, 1,
+ &state->signal_strength_en);
+ if (ret)
+ goto error;
+
+ if (state->signal_strength_en) {
+ ret = af9013_read_reg(state, 0x9bbd, &state->rf_50);
+ if (ret)
+ goto error;
+ ret = af9013_read_reg(state, 0x9bd0, &state->rf_80);
+ if (ret)
+ goto error;
+ ret = af9013_read_reg(state, 0x9be2, &state->if_50);
+ if (ret)
+ goto error;
+ ret = af9013_read_reg(state, 0x9be4, &state->if_80);
+ if (ret)
+ goto error;
+ }
+
error:
return ret;
}
@@ -1574,7 +1455,7 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
{
int ret;
struct af9013_state *state = NULL;
- u8 buf[3], i;
+ u8 buf[4], i;
/* allocate memory for the internal state */
state = kzalloc(sizeof(struct af9013_state), GFP_KERNEL);
@@ -1607,12 +1488,12 @@ struct dvb_frontend *af9013_attach(const struct af9013_config *config,
}
/* firmware version */
- for (i = 0; i < 3; i++) {
+ for (i = 0; i < 4; i++) {
ret = af9013_read_reg(state, 0x5103 + i, &buf[i]);
if (ret)
goto error;
}
- info("firmware version:%d.%d.%d", buf[0], buf[1], buf[2]);
+ info("firmware version:%d.%d.%d.%d", buf[0], buf[1], buf[2], buf[3]);
/* settings for mp2if */
if (state->config.output_mode == AF9013_OUTPUT_MODE_USB) {
diff --git a/drivers/media/dvb/frontends/af9013.h b/drivers/media/dvb/frontends/af9013.h
index e90fa92b1c1d..e53d873f7555 100644
--- a/drivers/media/dvb/frontends/af9013.h
+++ b/drivers/media/dvb/frontends/af9013.h
@@ -1,5 +1,5 @@
/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
*
@@ -44,6 +44,7 @@ enum af9013_tuner {
AF9013_TUNER_MT2060_2 = 147, /* Microtune */
AF9013_TUNER_TDA18271 = 156, /* NXP */
AF9013_TUNER_QT1010A = 162, /* Quantek */
+ AF9013_TUNER_MXL5007T = 177, /* MaxLinear */
AF9013_TUNER_TDA18218 = 179, /* NXP */
};
diff --git a/drivers/media/dvb/frontends/af9013_priv.h b/drivers/media/dvb/frontends/af9013_priv.h
index 163e251d0b73..e00b2a4a2db6 100644
--- a/drivers/media/dvb/frontends/af9013_priv.h
+++ b/drivers/media/dvb/frontends/af9013_priv.h
@@ -1,5 +1,5 @@
/*
- * DVB USB Linux driver for Afatech AF9015 DVB-T USB2.0 receiver
+ * Afatech AF9013 demodulator driver
*
* Copyright (C) 2007 Antti Palosaari <crope@iki.fi>
*
@@ -60,6 +60,56 @@ struct snr_table {
u8 snr;
};
+struct coeff {
+ u32 adc_clock;
+ fe_bandwidth_t bw;
+ u8 val[24];
+};
+
+/* pre-calculated coeff lookup table */
+static struct coeff coeff_table[] = {
+ /* 28.800 MHz */
+ { 28800, BANDWIDTH_8_MHZ, { 0x02, 0x8a, 0x28, 0xa3, 0x05, 0x14,
+ 0x51, 0x11, 0x00, 0xa2, 0x8f, 0x3d, 0x00, 0xa2, 0x8a,
+ 0x29, 0x00, 0xa2, 0x85, 0x14, 0x01, 0x45, 0x14, 0x14 } },
+ { 28800, BANDWIDTH_7_MHZ, { 0x02, 0x38, 0xe3, 0x8e, 0x04, 0x71,
+ 0xc7, 0x07, 0x00, 0x8e, 0x3d, 0x55, 0x00, 0x8e, 0x38,
+ 0xe4, 0x00, 0x8e, 0x34, 0x72, 0x01, 0x1c, 0x71, 0x32 } },
+ { 28800, BANDWIDTH_6_MHZ, { 0x01, 0xe7, 0x9e, 0x7a, 0x03, 0xcf,
+ 0x3c, 0x3d, 0x00, 0x79, 0xeb, 0x6e, 0x00, 0x79, 0xe7,
+ 0x9e, 0x00, 0x79, 0xe3, 0xcf, 0x00, 0xf3, 0xcf, 0x0f } },
+ /* 20.480 MHz */
+ { 20480, BANDWIDTH_8_MHZ, { 0x03, 0x92, 0x49, 0x26, 0x07, 0x24,
+ 0x92, 0x13, 0x00, 0xe4, 0x99, 0x6e, 0x00, 0xe4, 0x92,
+ 0x49, 0x00, 0xe4, 0x8b, 0x25, 0x01, 0xc9, 0x24, 0x25 } },
+ { 20480, BANDWIDTH_7_MHZ, { 0x03, 0x20, 0x00, 0x01, 0x06, 0x40,
+ 0x00, 0x00, 0x00, 0xc8, 0x06, 0x40, 0x00, 0xc8, 0x00,
+ 0x00, 0x00, 0xc7, 0xf9, 0xc0, 0x01, 0x90, 0x00, 0x00 } },
+ { 20480, BANDWIDTH_6_MHZ, { 0x02, 0xad, 0xb6, 0xdc, 0x05, 0x5b,
+ 0x6d, 0x2e, 0x00, 0xab, 0x73, 0x13, 0x00, 0xab, 0x6d,
+ 0xb7, 0x00, 0xab, 0x68, 0x5c, 0x01, 0x56, 0xdb, 0x1c } },
+ /* 28.000 MHz */
+ { 28000, BANDWIDTH_8_MHZ, { 0x02, 0x9c, 0xbc, 0x15, 0x05, 0x39,
+ 0x78, 0x0a, 0x00, 0xa7, 0x34, 0x3f, 0x00, 0xa7, 0x2f,
+ 0x05, 0x00, 0xa7, 0x29, 0xcc, 0x01, 0x4e, 0x5e, 0x03 } },
+ { 28000, BANDWIDTH_7_MHZ, { 0x02, 0x49, 0x24, 0x92, 0x04, 0x92,
+ 0x49, 0x09, 0x00, 0x92, 0x4d, 0xb7, 0x00, 0x92, 0x49,
+ 0x25, 0x00, 0x92, 0x44, 0x92, 0x01, 0x24, 0x92, 0x12 } },
+ { 28000, BANDWIDTH_6_MHZ, { 0x01, 0xf5, 0x8d, 0x10, 0x03, 0xeb,
+ 0x1a, 0x08, 0x00, 0x7d, 0x67, 0x2f, 0x00, 0x7d, 0x63,
+ 0x44, 0x00, 0x7d, 0x5f, 0x59, 0x00, 0xfa, 0xc6, 0x22 } },
+ /* 25.000 MHz */
+ { 25000, BANDWIDTH_8_MHZ, { 0x02, 0xec, 0xfb, 0x9d, 0x05, 0xd9,
+ 0xf7, 0x0e, 0x00, 0xbb, 0x44, 0xc1, 0x00, 0xbb, 0x3e,
+ 0xe7, 0x00, 0xbb, 0x39, 0x0d, 0x01, 0x76, 0x7d, 0x34 } },
+ { 25000, BANDWIDTH_7_MHZ, { 0x02, 0x8f, 0x5c, 0x29, 0x05, 0x1e,
+ 0xb8, 0x14, 0x00, 0xa3, 0xdc, 0x29, 0x00, 0xa3, 0xd7,
+ 0x0a, 0x00, 0xa3, 0xd1, 0xec, 0x01, 0x47, 0xae, 0x05 } },
+ { 25000, BANDWIDTH_6_MHZ, { 0x02, 0x31, 0xbc, 0xb5, 0x04, 0x63,
+ 0x79, 0x1b, 0x00, 0x8c, 0x73, 0x91, 0x00, 0x8c, 0x6f,
+ 0x2d, 0x00, 0x8c, 0x6a, 0xca, 0x01, 0x18, 0xde, 0x17 } },
+};
+
/* QPSK SNR lookup table */
static struct snr_table qpsk_snr_table[] = {
{ 0x0b4771, 0 },
@@ -132,6 +182,8 @@ static struct regdesc ofsm_init[] = {
{ 0xd740, 2, 1, 0x00 },
{ 0xd740, 3, 1, 0x01 },
{ 0xd3c1, 4, 1, 0x01 },
+ { 0x9124, 0, 8, 0x58 },
+ { 0x9125, 0, 2, 0x02 },
{ 0xd3a2, 0, 8, 0x00 },
{ 0xd3a3, 0, 8, 0x04 },
{ 0xd305, 0, 8, 0x32 },
@@ -143,7 +195,7 @@ static struct regdesc ofsm_init[] = {
{ 0x911b, 0, 1, 0x01 },
{ 0x9bce, 0, 4, 0x02 },
{ 0x9116, 0, 1, 0x01 },
- { 0x9bd1, 0, 1, 0x01 },
+ { 0x9122, 0, 8, 0xd0 },
{ 0xd2e0, 0, 8, 0xd0 },
{ 0xd2e9, 0, 4, 0x0d },
{ 0xd38c, 0, 8, 0xfc },
@@ -165,7 +217,6 @@ static struct regdesc ofsm_init[] = {
{ 0xd081, 4, 4, 0x09 },
{ 0xd098, 4, 4, 0x0f },
{ 0xd098, 0, 4, 0x03 },
- { 0xdbc0, 3, 1, 0x01 },
{ 0xdbc0, 4, 1, 0x01 },
{ 0xdbc7, 0, 8, 0x08 },
{ 0xdbc8, 4, 4, 0x00 },
@@ -179,6 +230,7 @@ static struct regdesc ofsm_init[] = {
{ 0xd0f0, 0, 7, 0x1a },
{ 0xd0f1, 4, 1, 0x01 },
{ 0xd0f2, 0, 8, 0x0c },
+ { 0xd101, 5, 3, 0x06 },
{ 0xd103, 0, 4, 0x08 },
{ 0xd0f8, 0, 7, 0x20 },
{ 0xd111, 5, 1, 0x00 },
@@ -478,9 +530,10 @@ static struct regdesc tuner_init_mxl5003d[] = {
{ 0x9bd9, 0, 8, 0x08 },
};
-/* MaxLinear MXL5005 tuner init
+/* MaxLinear MXL5005S & MXL5007T tuner init
AF9013_TUNER_MXL5005D = 13
- AF9013_TUNER_MXL5005R = 30 */
+ AF9013_TUNER_MXL5005R = 30
+ AF9013_TUNER_MXL5007T = 177 */
static struct regdesc tuner_init_mxl5005[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x07 },
@@ -789,8 +842,9 @@ static struct regdesc tuner_init_unknown[] = {
{ 0x9bd9, 0, 8, 0x08 },
};
-/* NXP TDA18271 tuner init
- AF9013_TUNER_TDA18271 = 156 */
+/* NXP TDA18271 & TDA18218 tuner init
+ AF9013_TUNER_TDA18271 = 156
+ AF9013_TUNER_TDA18218 = 179 */
static struct regdesc tuner_init_tda18271[] = {
{ 0x9bd5, 0, 8, 0x01 },
{ 0x9bd6, 0, 8, 0x04 },
diff --git a/drivers/media/dvb/frontends/atbm8830.c b/drivers/media/dvb/frontends/atbm8830.c
index 43aac2f85c2e..1539ea1f81ac 100644
--- a/drivers/media/dvb/frontends/atbm8830.c
+++ b/drivers/media/dvb/frontends/atbm8830.c
@@ -50,8 +50,7 @@ static int atbm8830_write_reg(struct atbm_state *priv, u16 reg, u8 data)
msg2.addr = dev_addr;
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n",
- __func__, reg, data);
+ dprintk("%s: reg=0x%04X, data=0x%02X\n", __func__, reg, data);
ret = i2c_transfer(priv->i2c, &msg1, 1);
if (ret != 1)
@@ -77,8 +76,7 @@ static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
ret = i2c_transfer(priv->i2c, &msg1, 1);
if (ret != 1) {
- dprintk(KERN_DEBUG "%s: error reg=0x%04x, ret=%i\n",
- __func__, reg, ret);
+ dprintk("%s: error reg=0x%04x, ret=%i\n", __func__, reg, ret);
return -EIO;
}
@@ -88,7 +86,7 @@ static int atbm8830_read_reg(struct atbm_state *priv, u16 reg, u8 *p_data)
*p_data = buf2[0];
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%04X, data=0x%02X\n",
+ dprintk("%s: reg=0x%04X, data=0x%02X\n",
__func__, reg, buf2[0]);
return 0;
diff --git a/drivers/media/dvb/frontends/au8522_decoder.c b/drivers/media/dvb/frontends/au8522_decoder.c
index 68dba3a4b4da..b537891a4cc9 100644
--- a/drivers/media/dvb/frontends/au8522_decoder.c
+++ b/drivers/media/dvb/frontends/au8522_decoder.c
@@ -36,7 +36,6 @@
#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/v4l2-device.h>
#include "au8522.h"
#include "au8522_priv.h"
@@ -279,10 +278,18 @@ static void setup_decoder_defaults(struct au8522_state *state, u8 input_mode)
AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS);
au8522_writereg(state, AU8522_TVDEC_COMB_HDIF_THR3_REG06BH,
AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
- AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
- au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
- AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
+ if (input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13 ||
+ input_mode == AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH24) {
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+ AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO);
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+ AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO);
+ } else {
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH,
+ AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS);
+ au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH,
+ AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS);
+ }
au8522_writereg(state, AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH,
AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS);
au8522_writereg(state, AU8522_TVDEC_UV_SEP_THR_REG06FH,
@@ -348,9 +355,11 @@ static void au8522_setup_cvbs_mode(struct au8522_state *state)
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
+ /* PGA in automatic mode */
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
- au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
- au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
+
+ /* Enable clamping control */
+ au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
AU8522_INPUT_CONTROL_REG081H_CVBS_CH1);
@@ -367,14 +376,14 @@ static void au8522_setup_cvbs_tuner_mode(struct au8522_state *state)
au8522_writereg(state, AU8522_MODULE_CLOCK_CONTROL_REG0A3H,
AU8522_MODULE_CLOCK_CONTROL_REG0A3H_CVBS);
- /* It's not clear why they turn off the PGA before enabling the clamp
- control, but the Windows trace does it so we will too... */
+ /* It's not clear why we have to have the PGA in automatic mode while
+ enabling clamp control, but it's what Windows does */
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
/* Enable clamping control */
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x0e);
- /* Turn on the PGA */
+ /* Disable automatic PGA (since the CVBS is coming from the tuner) */
au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x10);
/* Set input mode to CVBS on channel 4 with SIF audio input enabled */
@@ -397,7 +406,10 @@ static void au8522_setup_svideo_mode(struct au8522_state *state)
au8522_writereg(state, AU8522_INPUT_CONTROL_REG081H,
AU8522_INPUT_CONTROL_REG081H_SVIDEO_CH13);
- /* Disable clamping control (required for S-video) */
+ /* PGA in automatic mode */
+ au8522_writereg(state, AU8522_PGA_CONTROL_REG082H, 0x00);
+
+ /* Enable clamping control */
au8522_writereg(state, AU8522_CLAMPING_CONTROL_REG083H, 0x00);
setup_decoder_defaults(state,
@@ -411,29 +423,15 @@ static void au8522_setup_svideo_mode(struct au8522_state *state)
static void disable_audio_input(struct au8522_state *state)
{
- /* This can probably be optimized */
au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x00);
au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x00);
au8522_writereg(state, AU8522_AUDIO_VOLUME_REG0F4H, 0x00);
- au8522_writereg(state, AU8522_I2C_CONTROL_REG1_REG091H, 0x80);
- au8522_writereg(state, AU8522_I2C_CONTROL_REG0_REG090H, 0x84);
-
- au8522_writereg(state, AU8522_ENA_USB_REG101H, 0x00);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_L_REG0F2H, 0x7F);
- au8522_writereg(state, AU8522_AUDIO_VOLUME_R_REG0F3H, 0x7F);
- au8522_writereg(state, AU8522_REG0F9H, AU8522_REG0F9H_AUDIO);
- au8522_writereg(state, AU8522_AUDIO_MODE_REG0F1H, 0x40);
-
- au8522_writereg(state, AU8522_GPIO_DATA_REG0E2H, 0x11);
- msleep(5);
- au8522_writereg(state, AU8522_GPIO_DATA_REG0E2H, 0x00);
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_1_REG0A5H, 0x04);
- au8522_writereg(state, AU8522_AUDIOFREQ_REG606H, 0x03);
au8522_writereg(state, AU8522_I2S_CTRL_2_REG112H, 0x02);
au8522_writereg(state, AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H,
- AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_CVBS);
+ AU8522_SYSTEM_MODULE_CONTROL_0_REG0A4H_SVIDEO);
}
/* 0=disable, 1=SIF */
@@ -567,30 +565,6 @@ static int au8522_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
/* ----------------------------------------------------------------------- */
-static int au8522_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int au8522_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- /* Not yet implemented */
- break;
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int au8522_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -647,7 +621,7 @@ static int au8522_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
return v4l2_ctrl_query_fill(qc, 0, 255, 1,
AU8522_TVDEC_CONTRAST_REG00BH_CVBS);
case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 109);
case V4L2_CID_SATURATION:
return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
case V4L2_CID_HUE:
@@ -772,8 +746,6 @@ static const struct v4l2_subdev_audio_ops au8522_audio_ops = {
static const struct v4l2_subdev_video_ops au8522_video_ops = {
.s_routing = au8522_s_video_routing,
- .g_fmt = au8522_g_fmt,
- .s_fmt = au8522_s_fmt,
.s_stream = au8522_s_stream,
};
@@ -857,9 +829,25 @@ static const struct i2c_device_id au8522_id[] = {
MODULE_DEVICE_TABLE(i2c, au8522_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "au8522",
- .probe = au8522_probe,
- .remove = au8522_remove,
- .id_table = au8522_id,
+static struct i2c_driver au8522_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "au8522",
+ },
+ .probe = au8522_probe,
+ .remove = au8522_remove,
+ .id_table = au8522_id,
};
+
+static __init int init_au8522(void)
+{
+ return i2c_add_driver(&au8522_driver);
+}
+
+static __exit void exit_au8522(void)
+{
+ i2c_del_driver(&au8522_driver);
+}
+
+module_init(init_au8522);
+module_exit(exit_au8522);
diff --git a/drivers/media/dvb/frontends/au8522_priv.h b/drivers/media/dvb/frontends/au8522_priv.h
index 609cf04bc312..751e17d692a9 100644
--- a/drivers/media/dvb/frontends/au8522_priv.h
+++ b/drivers/media/dvb/frontends/au8522_priv.h
@@ -397,7 +397,9 @@ void au8522_release_state(struct au8522_state *state);
#define AU8522_TVDEC_COMB_HDIF_THR2_REG06AH_CVBS 0x0A
#define AU8522_TVDEC_COMB_HDIF_THR3_REG06BH_CVBS 0x32
#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_CVBS 0x34
+#define AU8522_TVDEC_COMB_DCDIF_THR1_REG06CH_SVIDEO 0x2a
#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_CVBS 0x05
+#define AU8522_TVDEC_COMB_DCDIF_THR2_REG06DH_SVIDEO 0x15
#define AU8522_TVDEC_COMB_DCDIF_THR3_REG06EH_CVBS 0x6E
#define AU8522_TVDEC_UV_SEP_THR_REG06FH_CVBS 0x0F
#define AU8522_TVDEC_COMB_DC_THR1_NTSC_REG070H_CVBS 0x80
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 00b5c7e91d5d..ff6c4983051c 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -54,7 +54,7 @@ MODULE_PARM_DESC(debug, "Enable verbose debug messages");
#define dprintk if (debug) printk
/* Register values to initialise the demod */
-static u8 init_tab[] = {
+static const u8 init_tab[] = {
0x00, 0x00, /* Stop aquisition */
0x0B, 0x06,
0x09, 0x01,
@@ -92,52 +92,56 @@ static int cx22702_writereg(struct cx22702_state *state, u8 reg, u8 data)
ret = i2c_transfer(state->i2c, &msg, 1);
- if (ret != 1)
+ if (unlikely(ret != 1)) {
printk(KERN_ERR
"%s: error (reg == 0x%02x, val == 0x%02x, ret == %i)\n",
__func__, reg, data, ret);
+ return -1;
+ }
- return (ret != 1) ? -1 : 0;
+ return 0;
}
static u8 cx22702_readreg(struct cx22702_state *state, u8 reg)
{
int ret;
- u8 b0[] = { reg };
- u8 b1[] = { 0 };
+ u8 data;
struct i2c_msg msg[] = {
{ .addr = state->config->demod_address, .flags = 0,
- .buf = b0, .len = 1 },
+ .buf = &reg, .len = 1 },
{ .addr = state->config->demod_address, .flags = I2C_M_RD,
- .buf = b1, .len = 1 } };
+ .buf = &data, .len = 1 } };
ret = i2c_transfer(state->i2c, msg, 2);
- if (ret != 2)
- printk(KERN_ERR "%s: readreg error (ret == %i)\n",
- __func__, ret);
+ if (unlikely(ret != 2)) {
+ printk(KERN_ERR "%s: error (reg == 0x%02x, ret == %i)\n",
+ __func__, reg, ret);
+ return 0;
+ }
- return b1[0];
+ return data;
}
static int cx22702_set_inversion(struct cx22702_state *state, int inversion)
{
u8 val;
+ val = cx22702_readreg(state, 0x0C);
switch (inversion) {
case INVERSION_AUTO:
return -EOPNOTSUPP;
case INVERSION_ON:
- val = cx22702_readreg(state, 0x0C);
- return cx22702_writereg(state, 0x0C, val | 0x01);
+ val |= 0x01;
+ break;
case INVERSION_OFF:
- val = cx22702_readreg(state, 0x0C);
- return cx22702_writereg(state, 0x0C, val & 0xfe);
+ val &= 0xfe;
+ break;
default:
return -EINVAL;
}
-
+ return cx22702_writereg(state, 0x0C, val);
}
/* Retrieve the demod settings */
@@ -244,13 +248,15 @@ static int cx22702_get_tps(struct cx22702_state *state,
static int cx22702_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct cx22702_state *state = fe->demodulator_priv;
+ u8 val;
+
dprintk("%s(%d)\n", __func__, enable);
+ val = cx22702_readreg(state, 0x0D);
if (enable)
- return cx22702_writereg(state, 0x0D,
- cx22702_readreg(state, 0x0D) & 0xfe);
+ val &= 0xfe;
else
- return cx22702_writereg(state, 0x0D,
- cx22702_readreg(state, 0x0D) | 1);
+ val |= 0x01;
+ return cx22702_writereg(state, 0x0D, val);
}
/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
@@ -270,23 +276,21 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
cx22702_set_inversion(state, p->inversion);
/* set bandwidth */
+ val = cx22702_readreg(state, 0x0C) & 0xcf;
switch (p->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
- cx22702_writereg(state, 0x0C,
- (cx22702_readreg(state, 0x0C) & 0xcf) | 0x20);
+ val |= 0x20;
break;
case BANDWIDTH_7_MHZ:
- cx22702_writereg(state, 0x0C,
- (cx22702_readreg(state, 0x0C) & 0xcf) | 0x10);
+ val |= 0x10;
break;
case BANDWIDTH_8_MHZ:
- cx22702_writereg(state, 0x0C,
- cx22702_readreg(state, 0x0C) & 0xcf);
break;
default:
dprintk("%s: invalid bandwidth\n", __func__);
return -EINVAL;
}
+ cx22702_writereg(state, 0x0C, val);
p->u.ofdm.code_rate_LP = FEC_AUTO; /* temp hack as manual not working */
@@ -312,33 +316,31 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
/* manually programmed values */
- val = 0;
- switch (p->u.ofdm.constellation) {
+ switch (p->u.ofdm.constellation) { /* mask 0x18 */
case QPSK:
- val = (val & 0xe7);
+ val = 0x00;
break;
case QAM_16:
- val = (val & 0xe7) | 0x08;
+ val = 0x08;
break;
case QAM_64:
- val = (val & 0xe7) | 0x10;
+ val = 0x10;
break;
default:
dprintk("%s: invalid constellation\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.hierarchy_information) {
+ switch (p->u.ofdm.hierarchy_information) { /* mask 0x07 */
case HIERARCHY_NONE:
- val = (val & 0xf8);
break;
case HIERARCHY_1:
- val = (val & 0xf8) | 1;
+ val |= 0x01;
break;
case HIERARCHY_2:
- val = (val & 0xf8) | 2;
+ val |= 0x02;
break;
case HIERARCHY_4:
- val = (val & 0xf8) | 3;
+ val |= 0x03;
break;
default:
dprintk("%s: invalid hierarchy\n", __func__);
@@ -346,44 +348,42 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x06, val);
- val = 0;
- switch (p->u.ofdm.code_rate_HP) {
+ switch (p->u.ofdm.code_rate_HP) { /* mask 0x38 */
case FEC_NONE:
case FEC_1_2:
- val = (val & 0xc7);
+ val = 0x00;
break;
case FEC_2_3:
- val = (val & 0xc7) | 0x08;
+ val = 0x08;
break;
case FEC_3_4:
- val = (val & 0xc7) | 0x10;
+ val = 0x10;
break;
case FEC_5_6:
- val = (val & 0xc7) | 0x18;
+ val = 0x18;
break;
case FEC_7_8:
- val = (val & 0xc7) | 0x20;
+ val = 0x20;
break;
default:
dprintk("%s: invalid code_rate_HP\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.code_rate_LP) {
+ switch (p->u.ofdm.code_rate_LP) { /* mask 0x07 */
case FEC_NONE:
case FEC_1_2:
- val = (val & 0xf8);
break;
case FEC_2_3:
- val = (val & 0xf8) | 1;
+ val |= 0x01;
break;
case FEC_3_4:
- val = (val & 0xf8) | 2;
+ val |= 0x02;
break;
case FEC_5_6:
- val = (val & 0xf8) | 3;
+ val |= 0x03;
break;
case FEC_7_8:
- val = (val & 0xf8) | 4;
+ val |= 0x04;
break;
default:
dprintk("%s: invalid code_rate_LP\n", __func__);
@@ -391,30 +391,28 @@ static int cx22702_set_tps(struct dvb_frontend *fe,
}
cx22702_writereg(state, 0x07, val);
- val = 0;
- switch (p->u.ofdm.guard_interval) {
+ switch (p->u.ofdm.guard_interval) { /* mask 0x0c */
case GUARD_INTERVAL_1_32:
- val = (val & 0xf3);
+ val = 0x00;
break;
case GUARD_INTERVAL_1_16:
- val = (val & 0xf3) | 0x04;
+ val = 0x04;
break;
case GUARD_INTERVAL_1_8:
- val = (val & 0xf3) | 0x08;
+ val = 0x08;
break;
case GUARD_INTERVAL_1_4:
- val = (val & 0xf3) | 0x0c;
+ val = 0x0c;
break;
default:
dprintk("%s: invalid guard_interval\n", __func__);
return -EINVAL;
}
- switch (p->u.ofdm.transmission_mode) {
+ switch (p->u.ofdm.transmission_mode) { /* mask 0x03 */
case TRANSMISSION_MODE_2K:
- val = (val & 0xfc);
break;
case TRANSMISSION_MODE_8K:
- val = (val & 0xfc) | 1;
+ val |= 0x1;
break;
default:
dprintk("%s: invalid transmission_mode\n", __func__);
@@ -505,7 +503,7 @@ static int cx22702_read_signal_strength(struct dvb_frontend *fe,
{
struct cx22702_state *state = fe->demodulator_priv;
- u16 rs_ber = 0;
+ u16 rs_ber;
rs_ber = cx22702_readreg(state, 0x23);
*signal_strength = (rs_ber << 8) | rs_ber;
@@ -516,7 +514,7 @@ static int cx22702_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct cx22702_state *state = fe->demodulator_priv;
- u16 rs_ber = 0;
+ u16 rs_ber;
if (cx22702_readreg(state, 0xE4) & 0x02) {
/* Realtime statistics */
rs_ber = (cx22702_readreg(state, 0xDE) & 0x7F) << 7
@@ -572,7 +570,7 @@ static void cx22702_release(struct dvb_frontend *fe)
kfree(state);
}
-static struct dvb_frontend_ops cx22702_ops;
+static const struct dvb_frontend_ops cx22702_ops;
struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
struct i2c_adapter *i2c)
@@ -587,7 +585,6 @@ struct dvb_frontend *cx22702_attach(const struct cx22702_config *config,
/* setup the state */
state->config = config;
state->i2c = i2c;
- state->prevUCBlocks = 0;
/* check if the demod is there */
if (cx22702_readreg(state, 0x1f) != 0x3)
@@ -605,7 +602,7 @@ error:
}
EXPORT_SYMBOL(cx22702_attach);
-static struct dvb_frontend_ops cx22702_ops = {
+static const struct dvb_frontend_ops cx22702_ops = {
.info = {
.name = "Conexant CX22702 DVB-T",
diff --git a/drivers/media/dvb/frontends/cx24110.c b/drivers/media/dvb/frontends/cx24110.c
index 00a4e8f03304..7a1a5bc337d8 100644
--- a/drivers/media/dvb/frontends/cx24110.c
+++ b/drivers/media/dvb/frontends/cx24110.c
@@ -310,7 +310,7 @@ static int cx24110_set_symbolrate (struct cx24110_state* state, u32 srate)
}
-static int _cx24110_pll_write (struct dvb_frontend* fe, u8 *buf, int len)
+static int _cx24110_pll_write (struct dvb_frontend* fe, const u8 buf[], int len)
{
struct cx24110_state *state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index d8f921b6fafd..fad6a990a39b 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -1108,7 +1108,6 @@ struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
strlcpy(state->tuner_i2c_adapter.name, "CX24123 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
- state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &cx24123_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
i2c_set_adapdata(&state->tuner_i2c_adapter, state);
diff --git a/drivers/media/dvb/frontends/dib3000mb.c b/drivers/media/dvb/frontends/dib3000mb.c
index ad4c8cfd8090..e80c59796368 100644
--- a/drivers/media/dvb/frontends/dib3000mb.c
+++ b/drivers/media/dvb/frontends/dib3000mb.c
@@ -38,11 +38,10 @@
#define DRIVER_DESC "DiBcom 3000M-B DVB-T demodulator"
#define DRIVER_AUTHOR "Patrick Boettcher, patrick.boettcher@desy.de"
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-able)).");
-#endif
+
#define deb_info(args...) dprintk(0x01,args)
#define deb_i2c(args...) dprintk(0x02,args)
#define deb_srch(args...) dprintk(0x04,args)
@@ -51,12 +50,6 @@ MODULE_PARM_DESC(debug, "set debugging level (1=info,2=xfer,4=setfe,8=getfe (|-a
#define deb_setf(args...) dprintk(0x04,args)
#define deb_getf(args...) dprintk(0x08,args)
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
-static int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debugging level (1=info,2=i2c,4=srch (|-able)).");
-#endif
-
static int dib3000_read_reg(struct dib3000_state *state, u16 reg)
{
u8 wb[] = { ((reg >> 8) | 0x80) & 0xff, reg & 0xff };
diff --git a/drivers/media/dvb/frontends/dib3000mb_priv.h b/drivers/media/dvb/frontends/dib3000mb_priv.h
index 1a12747fdc91..16c526591f36 100644
--- a/drivers/media/dvb/frontends/dib3000mb_priv.h
+++ b/drivers/media/dvb/frontends/dib3000mb_priv.h
@@ -37,12 +37,8 @@
/* debug */
-#ifdef CONFIG_DVB_DIBCOM_DEBUG
#define dprintk(level,args...) \
do { if ((debug & level)) { printk(args); } } while (0)
-#else
-#define dprintk(args...) do { } while (0)
-#endif
/* mask for enabling a specific pid for the pid_filter */
#define DIB3000_ACTIVATE_PID_FILTERING (0x2000)
diff --git a/drivers/media/dvb/frontends/dib3000mc.c b/drivers/media/dvb/frontends/dib3000mc.c
index afad252abf41..088e7fadbe3d 100644
--- a/drivers/media/dvb/frontends/dib3000mc.c
+++ b/drivers/media/dvb/frontends/dib3000mc.c
@@ -822,7 +822,7 @@ int dib3000mc_i2c_enumeration(struct i2c_adapter *i2c, int no_of_demods, u8 defa
dmcst = kzalloc(sizeof(struct dib3000mc_state), GFP_KERNEL);
if (dmcst == NULL)
- return -ENODEV;
+ return -ENOMEM;
dmcst->i2c_adap = i2c;
diff --git a/drivers/media/dvb/frontends/dib7000m.c b/drivers/media/dvb/frontends/dib7000m.c
index 0f09fd31cb29..c7f5ccf54aa5 100644
--- a/drivers/media/dvb/frontends/dib7000m.c
+++ b/drivers/media/dvb/frontends/dib7000m.c
@@ -805,7 +805,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
value = 0;
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
- case /* 4K MODE */ 255: value |= (2 << 7); break;
+ case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
default:
case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
}
@@ -866,7 +866,7 @@ static void dib7000m_set_channel(struct dib7000m_state *state, struct dvb_fronte
/* P_dvsy_sync_wait */
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_8K: value = 256; break;
- case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_4K: value = 128; break;
case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
@@ -1020,7 +1020,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
value = (6 << 8) | 0x80;
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (7 << 12); break;
- case /* 4K MODE */ 255: value |= (8 << 12); break;
+ case TRANSMISSION_MODE_4K: value |= (8 << 12); break;
default:
case TRANSMISSION_MODE_8K: value |= (9 << 12); break;
}
@@ -1030,7 +1030,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
value = (0 << 4);
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= 0x6; break;
- case /* 4K MODE */ 255: value |= 0x7; break;
+ case TRANSMISSION_MODE_4K: value |= 0x7; break;
default:
case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
@@ -1040,7 +1040,7 @@ static int dib7000m_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
value = (0 << 4);
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= 0x6; break;
- case /* 4K MODE */ 255: value |= 0x7; break;
+ case TRANSMISSION_MODE_4K: value |= 0x7; break;
default:
case TRANSMISSION_MODE_8K: value |= 0x8; break;
}
diff --git a/drivers/media/dvb/frontends/dib7000p.c b/drivers/media/dvb/frontends/dib7000p.c
index 2e28b973dfd3..6aa02cb80733 100644
--- a/drivers/media/dvb/frontends/dib7000p.c
+++ b/drivers/media/dvb/frontends/dib7000p.c
@@ -260,6 +260,9 @@ static void dib7000p_set_adc_state(struct dib7000p_state *state, enum dibx000_ad
// dprintk( "908: %x, 909: %x\n", reg_908, reg_909);
+ reg_909 |= (state->cfg.disable_sample_and_hold & 1) << 4;
+ reg_908 |= (state->cfg.enable_current_mirror & 1) << 7;
+
dib7000p_write_word(state, 908, reg_908);
dib7000p_write_word(state, 909, reg_909);
}
@@ -714,7 +717,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
value = 0;
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: value |= (0 << 7); break;
- case /* 4K MODE */ 255: value |= (2 << 7); break;
+ case TRANSMISSION_MODE_4K: value |= (2 << 7); break;
default:
case TRANSMISSION_MODE_8K: value |= (1 << 7); break;
}
@@ -767,7 +770,7 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
/* P_dvsy_sync_wait */
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_8K: value = 256; break;
- case /* 4K MODE */ 255: value = 128; break;
+ case TRANSMISSION_MODE_4K: value = 128; break;
case TRANSMISSION_MODE_2K:
default: value = 64; break;
}
@@ -778,7 +781,10 @@ static void dib7000p_set_channel(struct dib7000p_state *state, struct dvb_fronte
default:
case GUARD_INTERVAL_1_32: value *= 1; break;
}
- state->div_sync_wait = (value * 3) / 2 + 32; // add 50% SFN margin + compensate for one DVSY-fifo TODO
+ if (state->cfg.diversity_delay == 0)
+ state->div_sync_wait = (value * 3) / 2 + 48; // add 50% SFN margin + compensate for one DVSY-fifo
+ else
+ state->div_sync_wait = (value * 3) / 2 + state->cfg.diversity_delay; // add 50% SFN margin + compensate for one DVSY-fifo
/* deactive the possibility of diversity reception if extended interleaver */
state->div_force_off = !1 && ch->u.ofdm.transmission_mode != TRANSMISSION_MODE_8K;
@@ -988,7 +994,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
tmp = (6 << 8) | 0x80;
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: tmp |= (7 << 12); break;
- case /* 4K MODE */ 255: tmp |= (8 << 12); break;
+ case TRANSMISSION_MODE_4K: tmp |= (8 << 12); break;
default:
case TRANSMISSION_MODE_8K: tmp |= (9 << 12); break;
}
@@ -998,7 +1004,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
tmp = (0 << 4);
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
- case /* 4K MODE */ 255: tmp |= 0x7; break;
+ case TRANSMISSION_MODE_4K: tmp |= 0x7; break;
default:
case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
@@ -1008,7 +1014,7 @@ static int dib7000p_tune(struct dvb_frontend *demod, struct dvb_frontend_paramet
tmp = (0 << 4);
switch (ch->u.ofdm.transmission_mode) {
case TRANSMISSION_MODE_2K: tmp |= 0x6; break;
- case /* 4K MODE */ 255: tmp |= 0x7; break;
+ case TRANSMISSION_MODE_4K: tmp |= 0x7; break;
default:
case TRANSMISSION_MODE_8K: tmp |= 0x8; break;
}
diff --git a/drivers/media/dvb/frontends/dib7000p.h b/drivers/media/dvb/frontends/dib7000p.h
index 805dd13a97ee..da17345bf5bd 100644
--- a/drivers/media/dvb/frontends/dib7000p.h
+++ b/drivers/media/dvb/frontends/dib7000p.h
@@ -33,6 +33,11 @@ struct dib7000p_config {
int (*agc_control) (struct dvb_frontend *, u8 before);
u8 output_mode;
+ u8 disable_sample_and_hold : 1;
+
+ u8 enable_current_mirror : 1;
+ u8 diversity_delay;
+
};
#define DEFAULT_DIB7000P_I2C_ADDRESS 18
diff --git a/drivers/media/dvb/frontends/dibx000_common.c b/drivers/media/dvb/frontends/dibx000_common.c
index 980e02f1575e..2311c0a3406c 100644
--- a/drivers/media/dvb/frontends/dibx000_common.c
+++ b/drivers/media/dvb/frontends/dibx000_common.c
@@ -130,7 +130,7 @@ static int i2c_adapter_init(struct i2c_adapter *i2c_adap,
struct dibx000_i2c_master *mst)
{
strncpy(i2c_adap->name, name, sizeof(i2c_adap->name));
- i2c_adap->class = I2C_CLASS_TV_DIGITAL, i2c_adap->algo = algo;
+ i2c_adap->algo = algo;
i2c_adap->algo_data = NULL;
i2c_set_adapdata(i2c_adap, mst);
if (i2c_add_adapter(i2c_adap) < 0)
diff --git a/drivers/media/dvb/frontends/drx397xD.c b/drivers/media/dvb/frontends/drx397xD.c
index f74cca6dc26b..a05007c80985 100644
--- a/drivers/media/dvb/frontends/drx397xD.c
+++ b/drivers/media/dvb/frontends/drx397xD.c
@@ -232,7 +232,7 @@ static int write_fw(struct drx397xD_state *s, enum blob_ix ix)
exit_rc:
read_unlock(&fw[s->chip_rev].lock);
- return 0;
+ return rc;
}
/* Function is not endian safe, use the RD16 wrapper below */
diff --git a/drivers/media/dvb/frontends/ds3000.c b/drivers/media/dvb/frontends/ds3000.c
index 78001e8bcdb7..fc61d9230db8 100644
--- a/drivers/media/dvb/frontends/ds3000.c
+++ b/drivers/media/dvb/frontends/ds3000.c
@@ -969,15 +969,12 @@ struct dvb_frontend *ds3000_attach(const struct ds3000_config *config,
dprintk("%s\n", __func__);
/* allocate memory for the internal state */
- state = kmalloc(sizeof(struct ds3000_state), GFP_KERNEL);
+ state = kzalloc(sizeof(struct ds3000_state), GFP_KERNEL);
if (state == NULL) {
printk(KERN_ERR "Unable to kmalloc\n");
goto error2;
}
- /* setup the state */
- memset(state, 0, sizeof(struct ds3000_state));
-
state->config = config;
state->i2c = i2c;
state->prevUCBS2 = 0;
diff --git a/drivers/media/dvb/frontends/ix2505v.c b/drivers/media/dvb/frontends/ix2505v.c
new file mode 100644
index 000000000000..6c2e929bd79f
--- /dev/null
+++ b/drivers/media/dvb/frontends/ix2505v.c
@@ -0,0 +1,323 @@
+/**
+ * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
+ *
+ * Copyright (C) 2010 Malcolm Priestley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/dvb/frontend.h>
+#include <linux/slab.h>
+#include <linux/types.h>
+
+#include "ix2505v.h"
+
+static int ix2505v_debug;
+#define dprintk(level, args...) do { \
+ if (ix2505v_debug & level) \
+ printk(KERN_DEBUG "ix2505v: " args); \
+} while (0)
+
+#define deb_info(args...) dprintk(0x01, args)
+#define deb_i2c(args...) dprintk(0x02, args)
+
+struct ix2505v_state {
+ struct i2c_adapter *i2c;
+ const struct ix2505v_config *config;
+ u32 frequency;
+};
+
+/**
+ * Data read format of the Sharp IX2505V B0017
+ *
+ * byte1: 1 | 1 | 0 | 0 | 0 | MA1 | MA0 | 1
+ * byte2: POR | FL | RD2 | RD1 | RD0 | X | X | X
+ *
+ * byte1 = address
+ * byte2;
+ * POR = Power on Reset (VCC H=<2.2v L=>2.2v)
+ * FL = Phase Lock (H=lock L=unlock)
+ * RD0-2 = Reserved internal operations
+ *
+ * Only POR can be used to check the tuner is present
+ *
+ * Caution: after byte2 the I2C reverts to write mode continuing to read
+ * may corrupt tuning data.
+ *
+ */
+
+static int ix2505v_read_status_reg(struct ix2505v_state *state)
+{
+ u8 addr = state->config->tuner_address;
+ u8 b2[] = {0};
+ int ret;
+
+ struct i2c_msg msg[1] = {
+ { .addr = addr, .flags = I2C_M_RD, .buf = b2, .len = 1 }
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 1);
+ deb_i2c("Read %s ", __func__);
+
+ return (ret == 1) ? (int) b2[0] : -1;
+}
+
+static int ix2505v_write(struct ix2505v_state *state, u8 buf[], u8 count)
+{
+ struct i2c_msg msg[1] = {
+ { .addr = state->config->tuner_address, .flags = 0,
+ .buf = buf, .len = count },
+ };
+
+ int ret;
+
+ ret = i2c_transfer(state->i2c, msg, 1);
+
+ if (ret != 1) {
+ deb_i2c("%s: i2c error, ret=%d\n", __func__, ret);
+ return -EIO;
+ }
+
+ return 0;
+}
+
+static int ix2505v_release(struct dvb_frontend *fe)
+{
+ struct ix2505v_state *state = fe->tuner_priv;
+
+ fe->tuner_priv = NULL;
+ kfree(state);
+
+ return 0;
+}
+
+/**
+ * Data write format of the Sharp IX2505V B0017
+ *
+ * byte1: 1 | 1 | 0 | 0 | 0 | 0(MA1)| 0(MA0)| 0
+ * byte2: 0 | BG1 | BG2 | N8 | N7 | N6 | N5 | N4
+ * byte3: N3 | N2 | N1 | A5 | A4 | A3 | A2 | A1
+ * byte4: 1 | 1(C1) | 1(C0) | PD5 | PD4 | TM | 0(RTS)| 1(REF)
+ * byte5: BA2 | BA1 | BA0 | PSC | PD3 |PD2/TS2|DIV/TS1|PD0/TS0
+ *
+ * byte1 = address
+ *
+ * Write order
+ * 1) byte1 -> byte2 -> byte3 -> byte4 -> byte5
+ * 2) byte1 -> byte4 -> byte5 -> byte2 -> byte3
+ * 3) byte1 -> byte2 -> byte3 -> byte4
+ * 4) byte1 -> byte4 -> byte5 -> byte2
+ * 5) byte1 -> byte2 -> byte3
+ * 6) byte1 -> byte4 -> byte5
+ * 7) byte1 -> byte2
+ * 8) byte1 -> byte4
+ *
+ * Recommended Setup
+ * 1 -> 8 -> 6
+ */
+
+static int ix2505v_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct ix2505v_state *state = fe->tuner_priv;
+ u32 frequency = params->frequency;
+ u32 b_w = (params->u.qpsk.symbol_rate * 27) / 32000;
+ u32 div_factor, N , A, x;
+ int ret = 0, len;
+ u8 gain, cc, ref, psc, local_osc, lpf;
+ u8 data[4] = {0};
+
+ if ((frequency < fe->ops.info.frequency_min)
+ || (frequency > fe->ops.info.frequency_max))
+ return -EINVAL;
+
+ if (state->config->tuner_gain)
+ gain = (state->config->tuner_gain < 4)
+ ? state->config->tuner_gain : 0;
+ else
+ gain = 0x0;
+
+ if (state->config->tuner_chargepump)
+ cc = state->config->tuner_chargepump;
+ else
+ cc = 0x3;
+
+ ref = 8; /* REF =1 */
+ psc = 32; /* PSC = 0 */
+
+ div_factor = (frequency * ref) / 40; /* local osc = 4Mhz */
+ x = div_factor / psc;
+ N = x/100;
+ A = ((x - (N * 100)) * psc) / 100;
+
+ data[0] = ((gain & 0x3) << 5) | (N >> 3);
+ data[1] = (N << 5) | (A & 0x1f);
+ data[2] = 0x81 | ((cc & 0x3) << 5) ; /*PD5,PD4 & TM = 0|C1,C0|REF=1*/
+
+ deb_info("Frq=%d x=%d N=%d A=%d\n", frequency, x, N, A);
+
+ if (frequency <= 1065000)
+ local_osc = (6 << 5) | 2;
+ else if (frequency <= 1170000)
+ local_osc = (7 << 5) | 2;
+ else if (frequency <= 1300000)
+ local_osc = (1 << 5);
+ else if (frequency <= 1445000)
+ local_osc = (2 << 5);
+ else if (frequency <= 1607000)
+ local_osc = (3 << 5);
+ else if (frequency <= 1778000)
+ local_osc = (4 << 5);
+ else if (frequency <= 1942000)
+ local_osc = (5 << 5);
+ else /*frequency up to 2150000*/
+ local_osc = (6 << 5);
+
+ data[3] = local_osc; /* all other bits set 0 */
+
+ if (b_w <= 10000)
+ lpf = 0xc;
+ else if (b_w <= 12000)
+ lpf = 0x2;
+ else if (b_w <= 14000)
+ lpf = 0xa;
+ else if (b_w <= 16000)
+ lpf = 0x6;
+ else if (b_w <= 18000)
+ lpf = 0xe;
+ else if (b_w <= 20000)
+ lpf = 0x1;
+ else if (b_w <= 22000)
+ lpf = 0x9;
+ else if (b_w <= 24000)
+ lpf = 0x5;
+ else if (b_w <= 26000)
+ lpf = 0xd;
+ else if (b_w <= 28000)
+ lpf = 0x3;
+ else
+ lpf = 0xb;
+
+ deb_info("Osc=%x b_w=%x lpf=%x\n", local_osc, b_w, lpf);
+ deb_info("Data 0=[%x%x%x%x]\n", data[0], data[1], data[2], data[3]);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ len = sizeof(data);
+
+ ret |= ix2505v_write(state, data, len);
+
+ data[2] |= 0x4; /* set TM = 1 other bits same */
+
+ len = 1;
+ ret |= ix2505v_write(state, &data[2], len); /* write byte 4 only */
+
+ msleep(10);
+
+ data[2] |= ((lpf >> 2) & 0x3) << 3; /* lpf */
+ data[3] |= (lpf & 0x3) << 2;
+
+ deb_info("Data 2=[%x%x]\n", data[2], data[3]);
+
+ len = 2;
+ ret |= ix2505v_write(state, &data[2], len); /* write byte 4 & 5 */
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (state->config->min_delay_ms)
+ msleep(state->config->min_delay_ms);
+
+ state->frequency = frequency;
+
+ return ret;
+}
+
+static int ix2505v_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct ix2505v_state *state = fe->tuner_priv;
+
+ *frequency = state->frequency;
+
+ return 0;
+}
+
+static struct dvb_tuner_ops ix2505v_tuner_ops = {
+ .info = {
+ .name = "Sharp IX2505V (B0017)",
+ .frequency_min = 950000,
+ .frequency_max = 2175000
+ },
+ .release = ix2505v_release,
+ .set_params = ix2505v_set_params,
+ .get_frequency = ix2505v_get_frequency,
+};
+
+struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+ const struct ix2505v_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct ix2505v_state *state = NULL;
+ int ret;
+
+ if (NULL == config) {
+ deb_i2c("%s: no config ", __func__);
+ goto error;
+ }
+
+ state = kzalloc(sizeof(struct ix2505v_state), GFP_KERNEL);
+ if (NULL == state)
+ return NULL;
+
+ state->config = config;
+ state->i2c = i2c;
+
+ if (state->config->tuner_write_only) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = ix2505v_read_status_reg(state);
+
+ if (ret & 0x80) {
+ deb_i2c("%s: No IX2505V found\n", __func__);
+ goto error;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ fe->tuner_priv = state;
+
+ memcpy(&fe->ops.tuner_ops, &ix2505v_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+ deb_i2c("%s: initialization (%s addr=0x%02x) ok\n",
+ __func__, fe->ops.tuner_ops.info.name, config->tuner_address);
+
+ return fe;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(ix2505v_attach);
+
+module_param_named(debug, ix2505v_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
+MODULE_DESCRIPTION("DVB IX2505V tuner driver");
+MODULE_AUTHOR("Malcolm Priestley");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/ix2505v.h b/drivers/media/dvb/frontends/ix2505v.h
new file mode 100644
index 000000000000..67e89d616d50
--- /dev/null
+++ b/drivers/media/dvb/frontends/ix2505v.h
@@ -0,0 +1,64 @@
+/**
+ * Driver for Sharp IX2505V (marked B0017) DVB-S silicon tuner
+ *
+ * Copyright (C) 2010 Malcolm Priestley
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License Version 2, as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef DVB_IX2505V_H
+#define DVB_IX2505V_H
+
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+
+/**
+ * Attach a ix2505v tuner to the supplied frontend structure.
+ *
+ * @param fe Frontend to attach to.
+ * @param config ix2505v_config structure
+ * @return FE pointer on success, NULL on failure.
+ */
+
+struct ix2505v_config {
+ u8 tuner_address;
+
+ /*Baseband AMP gain control 0/1=0dB(default) 2=-2bB 3=-4dB */
+ u8 tuner_gain;
+
+ /*Charge pump output +/- 0=120 1=260 2=555 3=1200(default) */
+ u8 tuner_chargepump;
+
+ /* delay after tune */
+ int min_delay_ms;
+
+ /* disables reads*/
+ u8 tuner_write_only;
+
+};
+
+#if defined(CONFIG_DVB_IX2505V) || \
+ (defined(CONFIG_DVB_IX2505V_MODULE) && defined(MODULE))
+extern struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+ const struct ix2505v_config *config, struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *ix2505v_attach(struct dvb_frontend *fe,
+ const struct ix2505v_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* DVB_IX2505V_H */
diff --git a/drivers/media/dvb/frontends/lgdt3304.c b/drivers/media/dvb/frontends/lgdt3304.c
deleted file mode 100644
index 45a529b06b9d..000000000000
--- a/drivers/media/dvb/frontends/lgdt3304.c
+++ /dev/null
@@ -1,380 +0,0 @@
-/*
- * Driver for LG ATSC lgdt3304 driver
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "lgdt3304.h"
-
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"lgdt3304 debugging (default off)");
-
-#define dprintk(fmt, args...) if (debug) do {\
- printk("lgdt3304 debug: " fmt, ##args); } while (0)
-
-struct lgdt3304_state
-{
- struct dvb_frontend frontend;
- fe_modulation_t current_modulation;
- __u32 snr;
- __u32 current_frequency;
- __u8 addr;
- struct i2c_adapter *i2c;
-};
-
-static int i2c_write_demod_bytes (struct dvb_frontend *fe, __u8 *buf, int len)
-{
- struct lgdt3304_state *state = fe->demodulator_priv;
- struct i2c_msg i2cmsgs = {
- .addr = state->addr,
- .flags = 0,
- .len = 3,
- .buf = buf
- };
- int i;
- int err;
-
- for (i=0; i<len-1; i+=3){
- if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
- printk("%s i2c_transfer error %d\n", __func__, err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
- i2cmsgs.buf += 3;
- }
- return 0;
-}
-
-static int lgdt3304_i2c_read_reg(struct dvb_frontend *fe, unsigned int reg)
-{
- struct lgdt3304_state *state = fe->demodulator_priv;
- struct i2c_msg i2cmsgs[2];
- int ret;
- __u8 buf;
-
- __u8 regbuf[2] = { reg>>8, reg&0xff };
-
- i2cmsgs[0].addr = state->addr;
- i2cmsgs[0].flags = 0;
- i2cmsgs[0].len = 2;
- i2cmsgs[0].buf = regbuf;
-
- i2cmsgs[1].addr = state->addr;
- i2cmsgs[1].flags = I2C_M_RD;
- i2cmsgs[1].len = 1;
- i2cmsgs[1].buf = &buf;
-
- if((ret = i2c_transfer(state->i2c, i2cmsgs, 2))<0) {
- printk("%s i2c_transfer error %d\n", __func__, ret);
- return ret;
- }
-
- return buf;
-}
-
-static int lgdt3304_i2c_write_reg(struct dvb_frontend *fe, int reg, int val)
-{
- struct lgdt3304_state *state = fe->demodulator_priv;
- char buffer[3] = { reg>>8, reg&0xff, val };
- int ret;
-
- struct i2c_msg i2cmsgs = {
- .addr = state->addr,
- .flags = 0,
- .len = 3,
- .buf=buffer
- };
- ret = i2c_transfer(state->i2c, &i2cmsgs, 1);
- if (ret != 1) {
- printk("%s i2c_transfer error %d\n", __func__, ret);
- return ret;
- }
-
- return 0;
-}
-
-
-static int lgdt3304_soft_Reset(struct dvb_frontend *fe)
-{
- lgdt3304_i2c_write_reg(fe, 0x0002, 0x9a);
- lgdt3304_i2c_write_reg(fe, 0x0002, 0x9b);
- mdelay(200);
- return 0;
-}
-
-static int lgdt3304_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
- int err = 0;
-
- static __u8 lgdt3304_vsb8_data[] = {
- /* 16bit , 8bit */
- /* regs , val */
- 0x00, 0x00, 0x02,
- 0x00, 0x00, 0x13,
- 0x00, 0x0d, 0x02,
- 0x00, 0x0e, 0x02,
- 0x00, 0x12, 0x32,
- 0x00, 0x13, 0xc4,
- 0x01, 0x12, 0x17,
- 0x01, 0x13, 0x15,
- 0x01, 0x14, 0x18,
- 0x01, 0x15, 0xff,
- 0x01, 0x16, 0x2c,
- 0x02, 0x14, 0x67,
- 0x02, 0x24, 0x8d,
- 0x04, 0x27, 0x12,
- 0x04, 0x28, 0x4f,
- 0x03, 0x08, 0x80,
- 0x03, 0x09, 0x00,
- 0x03, 0x0d, 0x00,
- 0x03, 0x0e, 0x1c,
- 0x03, 0x14, 0xe1,
- 0x05, 0x0e, 0x5b,
- };
-
- /* not yet tested .. */
- static __u8 lgdt3304_qam64_data[] = {
- /* 16bit , 8bit */
- /* regs , val */
- 0x00, 0x00, 0x18,
- 0x00, 0x0d, 0x02,
- //0x00, 0x0e, 0x02,
- 0x00, 0x12, 0x2a,
- 0x00, 0x13, 0x00,
- 0x03, 0x14, 0xe3,
- 0x03, 0x0e, 0x1c,
- 0x03, 0x08, 0x66,
- 0x03, 0x09, 0x66,
- 0x03, 0x0a, 0x08,
- 0x03, 0x0b, 0x9b,
- 0x05, 0x0e, 0x5b,
- };
-
-
- /* tested with KWorld a340 */
- static __u8 lgdt3304_qam256_data[] = {
- /* 16bit , 8bit */
- /* regs , val */
- 0x00, 0x00, 0x01, //0x19,
- 0x00, 0x12, 0x2a,
- 0x00, 0x13, 0x80,
- 0x00, 0x0d, 0x02,
- 0x03, 0x14, 0xe3,
-
- 0x03, 0x0e, 0x1c,
- 0x03, 0x08, 0x66,
- 0x03, 0x09, 0x66,
- 0x03, 0x0a, 0x08,
- 0x03, 0x0b, 0x9b,
-
- 0x03, 0x0d, 0x14,
- //0x05, 0x0e, 0x5b,
- 0x01, 0x06, 0x4a,
- 0x01, 0x07, 0x3d,
- 0x01, 0x08, 0x70,
- 0x01, 0x09, 0xa3,
-
- 0x05, 0x04, 0xfd,
-
- 0x00, 0x0d, 0x82,
-
- 0x05, 0x0e, 0x5b,
-
- 0x05, 0x0e, 0x5b,
-
- 0x00, 0x02, 0x9a,
-
- 0x00, 0x02, 0x9b,
-
- 0x00, 0x00, 0x01,
- 0x00, 0x12, 0x2a,
- 0x00, 0x13, 0x80,
- 0x00, 0x0d, 0x02,
- 0x03, 0x14, 0xe3,
-
- 0x03, 0x0e, 0x1c,
- 0x03, 0x08, 0x66,
- 0x03, 0x09, 0x66,
- 0x03, 0x0a, 0x08,
- 0x03, 0x0b, 0x9b,
-
- 0x03, 0x0d, 0x14,
- 0x01, 0x06, 0x4a,
- 0x01, 0x07, 0x3d,
- 0x01, 0x08, 0x70,
- 0x01, 0x09, 0xa3,
-
- 0x05, 0x04, 0xfd,
-
- 0x00, 0x0d, 0x82,
-
- 0x05, 0x0e, 0x5b,
- };
-
- struct lgdt3304_state *state = fe->demodulator_priv;
- if (state->current_modulation != param->u.vsb.modulation) {
- switch(param->u.vsb.modulation) {
- case VSB_8:
- err = i2c_write_demod_bytes(fe, lgdt3304_vsb8_data,
- sizeof(lgdt3304_vsb8_data));
- break;
- case QAM_64:
- err = i2c_write_demod_bytes(fe, lgdt3304_qam64_data,
- sizeof(lgdt3304_qam64_data));
- break;
- case QAM_256:
- err = i2c_write_demod_bytes(fe, lgdt3304_qam256_data,
- sizeof(lgdt3304_qam256_data));
- break;
- default:
- break;
- }
-
- if (err) {
- printk("%s error setting modulation\n", __func__);
- } else {
- state->current_modulation = param->u.vsb.modulation;
- }
- }
- state->current_frequency = param->frequency;
-
- lgdt3304_soft_Reset(fe);
-
-
- if (fe->ops.tuner_ops.set_params)
- fe->ops.tuner_ops.set_params(fe, param);
-
- return 0;
-}
-
-static int lgdt3304_init(struct dvb_frontend *fe) {
- return 0;
-}
-
-static int lgdt3304_sleep(struct dvb_frontend *fe) {
- return 0;
-}
-
-
-static int lgdt3304_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct lgdt3304_state *state = fe->demodulator_priv;
- int r011d;
- int qam_lck;
-
- *status = 0;
- dprintk("lgdt read status\n");
-
- r011d = lgdt3304_i2c_read_reg(fe, 0x011d);
-
- dprintk("%02x\n", r011d);
-
- switch(state->current_modulation) {
- case VSB_8:
- if (r011d & 0x80) {
- dprintk("VSB Locked\n");
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_LOCK;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_SIGNAL;
- }
- break;
- case QAM_64:
- case QAM_256:
- qam_lck = r011d & 0x7;
- switch(qam_lck) {
- case 0x0: dprintk("Unlock\n");
- break;
- case 0x4: dprintk("1st Lock in acquisition state\n");
- break;
- case 0x6: dprintk("2nd Lock in acquisition state\n");
- break;
- case 0x7: dprintk("Final Lock in good reception state\n");
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_LOCK;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_SIGNAL;
- break;
- }
- break;
- default:
- printk("%s unhandled modulation\n", __func__);
- }
-
-
- return 0;
-}
-
-static int lgdt3304_read_ber(struct dvb_frontend *fe, __u32 *ber)
-{
- dprintk("read ber\n");
- return 0;
-}
-
-static int lgdt3304_read_snr(struct dvb_frontend *fe, __u16 *snr)
-{
- dprintk("read snr\n");
- return 0;
-}
-
-static int lgdt3304_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
-{
- dprintk("read ucblocks\n");
- return 0;
-}
-
-static void lgdt3304_release(struct dvb_frontend *fe)
-{
- struct lgdt3304_state *state = (struct lgdt3304_state *)fe->demodulator_priv;
- kfree(state);
-}
-
-static struct dvb_frontend_ops demod_lgdt3304={
- .info = {
- .name = "LG 3304",
- .type = FE_ATSC,
- .frequency_min = 54000000,
- .frequency_max = 858000000,
- .frequency_stepsize = 62500,
- .symbol_rate_min = 5056941,
- .symbol_rate_max = 10762000,
- .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
- },
- .init = lgdt3304_init,
- .sleep = lgdt3304_sleep,
- .set_frontend = lgdt3304_set_parameters,
- .read_snr = lgdt3304_read_snr,
- .read_ber = lgdt3304_read_ber,
- .read_status = lgdt3304_read_status,
- .read_ucblocks = lgdt3304_read_ucblocks,
- .release = lgdt3304_release,
-};
-
-struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
- struct i2c_adapter *i2c)
-{
-
- struct lgdt3304_state *state;
- state = kzalloc(sizeof(struct lgdt3304_state), GFP_KERNEL);
- if (state == NULL)
- return NULL;
- state->addr = config->i2c_address;
- state->i2c = i2c;
-
- memcpy(&state->frontend.ops, &demod_lgdt3304, sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
- return &state->frontend;
-}
-
-EXPORT_SYMBOL_GPL(lgdt3304_attach);
-MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
-MODULE_DESCRIPTION("LGE LGDT3304 DVB-T demodulator driver");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/lgdt3304.h b/drivers/media/dvb/frontends/lgdt3304.h
deleted file mode 100644
index fc409fe59acb..000000000000
--- a/drivers/media/dvb/frontends/lgdt3304.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
- * Driver for DVB-T lgdt3304 demodulator
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@gmail.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef LGDT3304_H
-#define LGDT3304_H
-
-#include <linux/dvb/frontend.h>
-
-struct lgdt3304_config
-{
- /* demodulator's I2C address */
- u8 i2c_address;
-};
-
-#if defined(CONFIG_DVB_LGDT3304) || (defined(CONFIG_DVB_LGDT3304_MODULE) && defined(MODULE))
-extern struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
- struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* lgdt3304_attach(const struct lgdt3304_config *config,
- struct i2c_adapter *i2c)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif /* CONFIG_DVB_LGDT */
-
-#endif /* LGDT3304_H */
diff --git a/drivers/media/dvb/frontends/lgdt3305.c b/drivers/media/dvb/frontends/lgdt3305.c
index d69c775f8645..3272881cb112 100644
--- a/drivers/media/dvb/frontends/lgdt3305.c
+++ b/drivers/media/dvb/frontends/lgdt3305.c
@@ -1,7 +1,9 @@
/*
- * Support for LGDT3305 - VSB/QAM
+ * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
*
- * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ * Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * LGDT3304 support by Jarod Wilson <jarod@redhat.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -65,6 +67,8 @@ struct lgdt3305_state {
/* ------------------------------------------------------------------------ */
+/* FIXME: verify & document the LGDT3304 registers */
+
#define LGDT3305_GEN_CTRL_1 0x0000
#define LGDT3305_GEN_CTRL_2 0x0001
#define LGDT3305_GEN_CTRL_3 0x0002
@@ -358,7 +362,12 @@ static int lgdt3305_rfagc_loop(struct lgdt3305_state *state,
case QAM_256:
agcdelay = 0x046b;
rfbw = 0x8889;
- ifbw = 0x8888;
+ /* FIXME: investigate optimal ifbw & rfbw values for the
+ * DT3304 and re-write this switch..case block */
+ if (state->cfg->demod_chip == LGDT3304)
+ ifbw = 0x6666;
+ else /* (state->cfg->demod_chip == LGDT3305) */
+ ifbw = 0x8888;
break;
default:
return -EINVAL;
@@ -410,8 +419,18 @@ static int lgdt3305_agc_setup(struct lgdt3305_state *state,
lg_dbg("lockdten = %d, acqen = %d\n", lockdten, acqen);
/* control agc function */
- lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
- lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+ switch (state->cfg->demod_chip) {
+ case LGDT3304:
+ lgdt3305_write_reg(state, 0x0314, 0xe1 | lockdten << 1);
+ lgdt3305_set_reg_bit(state, 0x030e, 2, acqen);
+ break;
+ case LGDT3305:
+ lgdt3305_write_reg(state, LGDT3305_AGC_CTRL_4, 0xe1 | lockdten << 1);
+ lgdt3305_set_reg_bit(state, LGDT3305_AGC_CTRL_1, 2, acqen);
+ break;
+ default:
+ return -EINVAL;
+ }
return lgdt3305_rfagc_loop(state, param);
}
@@ -577,61 +596,79 @@ static int lgdt3305_init(struct dvb_frontend *fe)
struct lgdt3305_state *state = fe->demodulator_priv;
int ret;
+ static struct lgdt3305_reg lgdt3304_init_data[] = {
+ { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, },
+ { .reg = 0x000d, .val = 0x02, },
+ { .reg = 0x000e, .val = 0x02, },
+ { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, },
+ { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, },
+ { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTRL_7, .val = 0xf9, },
+ { .reg = 0x0112, .val = 0x17, },
+ { .reg = 0x0113, .val = 0x15, },
+ { .reg = 0x0114, .val = 0x18, },
+ { .reg = 0x0115, .val = 0xff, },
+ { .reg = 0x0116, .val = 0x3c, },
+ { .reg = 0x0214, .val = 0x67, },
+ { .reg = 0x0424, .val = 0x8d, },
+ { .reg = 0x0427, .val = 0x12, },
+ { .reg = 0x0428, .val = 0x4f, },
+ { .reg = LGDT3305_IFBW_1, .val = 0x80, },
+ { .reg = LGDT3305_IFBW_2, .val = 0x00, },
+ { .reg = 0x030a, .val = 0x08, },
+ { .reg = 0x030b, .val = 0x9b, },
+ { .reg = 0x030d, .val = 0x00, },
+ { .reg = 0x030e, .val = 0x1c, },
+ { .reg = 0x0314, .val = 0xe1, },
+ { .reg = 0x000d, .val = 0x82, },
+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, },
+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x5b, },
+ };
+
static struct lgdt3305_reg lgdt3305_init_data[] = {
- { .reg = LGDT3305_GEN_CTRL_1,
- .val = 0x03, },
- { .reg = LGDT3305_GEN_CTRL_2,
- .val = 0xb0, },
- { .reg = LGDT3305_GEN_CTRL_3,
- .val = 0x01, },
- { .reg = LGDT3305_GEN_CONTROL,
- .val = 0x6f, },
- { .reg = LGDT3305_GEN_CTRL_4,
- .val = 0x03, },
- { .reg = LGDT3305_DGTL_AGC_REF_1,
- .val = 0x32, },
- { .reg = LGDT3305_DGTL_AGC_REF_2,
- .val = 0xc4, },
- { .reg = LGDT3305_CR_CTR_FREQ_1,
- .val = 0x00, },
- { .reg = LGDT3305_CR_CTR_FREQ_2,
- .val = 0x00, },
- { .reg = LGDT3305_CR_CTR_FREQ_3,
- .val = 0x00, },
- { .reg = LGDT3305_CR_CTR_FREQ_4,
- .val = 0x00, },
- { .reg = LGDT3305_CR_CTRL_7,
- .val = 0x79, },
- { .reg = LGDT3305_AGC_POWER_REF_1,
- .val = 0x32, },
- { .reg = LGDT3305_AGC_POWER_REF_2,
- .val = 0xc4, },
- { .reg = LGDT3305_AGC_DELAY_PT_1,
- .val = 0x0d, },
- { .reg = LGDT3305_AGC_DELAY_PT_2,
- .val = 0x30, },
- { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1,
- .val = 0x80, },
- { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2,
- .val = 0x00, },
- { .reg = LGDT3305_IFBW_1,
- .val = 0x80, },
- { .reg = LGDT3305_IFBW_2,
- .val = 0x00, },
- { .reg = LGDT3305_AGC_CTRL_1,
- .val = 0x30, },
- { .reg = LGDT3305_AGC_CTRL_4,
- .val = 0x61, },
- { .reg = LGDT3305_FEC_BLOCK_CTRL,
- .val = 0xff, },
- { .reg = LGDT3305_TP_CTRL_1,
- .val = 0x1b, },
+ { .reg = LGDT3305_GEN_CTRL_1, .val = 0x03, },
+ { .reg = LGDT3305_GEN_CTRL_2, .val = 0xb0, },
+ { .reg = LGDT3305_GEN_CTRL_3, .val = 0x01, },
+ { .reg = LGDT3305_GEN_CONTROL, .val = 0x6f, },
+ { .reg = LGDT3305_GEN_CTRL_4, .val = 0x03, },
+ { .reg = LGDT3305_DGTL_AGC_REF_1, .val = 0x32, },
+ { .reg = LGDT3305_DGTL_AGC_REF_2, .val = 0xc4, },
+ { .reg = LGDT3305_CR_CTR_FREQ_1, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_2, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_3, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTR_FREQ_4, .val = 0x00, },
+ { .reg = LGDT3305_CR_CTRL_7, .val = 0x79, },
+ { .reg = LGDT3305_AGC_POWER_REF_1, .val = 0x32, },
+ { .reg = LGDT3305_AGC_POWER_REF_2, .val = 0xc4, },
+ { .reg = LGDT3305_AGC_DELAY_PT_1, .val = 0x0d, },
+ { .reg = LGDT3305_AGC_DELAY_PT_2, .val = 0x30, },
+ { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_1, .val = 0x80, },
+ { .reg = LGDT3305_RFAGC_LOOP_FLTR_BW_2, .val = 0x00, },
+ { .reg = LGDT3305_IFBW_1, .val = 0x80, },
+ { .reg = LGDT3305_IFBW_2, .val = 0x00, },
+ { .reg = LGDT3305_AGC_CTRL_1, .val = 0x30, },
+ { .reg = LGDT3305_AGC_CTRL_4, .val = 0x61, },
+ { .reg = LGDT3305_FEC_BLOCK_CTRL, .val = 0xff, },
+ { .reg = LGDT3305_TP_CTRL_1, .val = 0x1b, },
};
lg_dbg("\n");
- ret = lgdt3305_write_regs(state, lgdt3305_init_data,
- ARRAY_SIZE(lgdt3305_init_data));
+ switch (state->cfg->demod_chip) {
+ case LGDT3304:
+ ret = lgdt3305_write_regs(state, lgdt3304_init_data,
+ ARRAY_SIZE(lgdt3304_init_data));
+ break;
+ case LGDT3305:
+ ret = lgdt3305_write_regs(state, lgdt3305_init_data,
+ ARRAY_SIZE(lgdt3305_init_data));
+ break;
+ default:
+ ret = -EINVAL;
+ }
if (lg_fail(ret))
goto fail;
@@ -640,6 +677,76 @@ fail:
return ret;
}
+static int lgdt3304_set_parameters(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *param)
+{
+ struct lgdt3305_state *state = fe->demodulator_priv;
+ int ret;
+
+ lg_dbg("(%d, %d)\n", param->frequency, param->u.vsb.modulation);
+
+ if (fe->ops.tuner_ops.set_params) {
+ ret = fe->ops.tuner_ops.set_params(fe, param);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ if (lg_fail(ret))
+ goto fail;
+ state->current_frequency = param->frequency;
+ }
+
+ ret = lgdt3305_set_modulation(state, param);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lgdt3305_passband_digital_agc(state, param);
+ if (lg_fail(ret))
+ goto fail;
+
+ ret = lgdt3305_agc_setup(state, param);
+ if (lg_fail(ret))
+ goto fail;
+
+ /* reg 0x030d is 3304-only... seen in vsb and qam usbsnoops... */
+ switch (param->u.vsb.modulation) {
+ case VSB_8:
+ lgdt3305_write_reg(state, 0x030d, 0x00);
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_1, 0x4f);
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_2, 0x0c);
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_3, 0xac);
+ lgdt3305_write_reg(state, LGDT3305_CR_CTR_FREQ_4, 0xba);
+ break;
+ case QAM_64:
+ case QAM_256:
+ lgdt3305_write_reg(state, 0x030d, 0x14);
+ ret = lgdt3305_set_if(state, param);
+ if (lg_fail(ret))
+ goto fail;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+
+ ret = lgdt3305_spectral_inversion(state, param,
+ state->cfg->spectral_inversion
+ ? 1 : 0);
+ if (lg_fail(ret))
+ goto fail;
+
+ state->current_modulation = param->u.vsb.modulation;
+
+ ret = lgdt3305_mpeg_mode(state, state->cfg->mpeg_mode);
+ if (lg_fail(ret))
+ goto fail;
+
+ /* lgdt3305_mpeg_mode_polarity calls lgdt3305_soft_reset */
+ ret = lgdt3305_mpeg_mode_polarity(state,
+ state->cfg->tpclk_edge,
+ state->cfg->tpvalid_polarity);
+fail:
+ return ret;
+}
+
static int lgdt3305_set_parameters(struct dvb_frontend *fe,
struct dvb_frontend_parameters *param)
{
@@ -848,6 +955,10 @@ static int lgdt3305_read_status(struct dvb_frontend *fe, fe_status_t *status)
switch (state->current_modulation) {
case QAM_256:
case QAM_64:
+ /* signal bit is unreliable on the DT3304 in QAM mode */
+ if (((LGDT3304 == state->cfg->demod_chip)) && (cr_lock))
+ *status |= FE_HAS_SIGNAL;
+
ret = lgdt3305_read_fec_lock_status(state, &fec_lock);
if (lg_fail(ret))
goto fail;
@@ -993,6 +1104,7 @@ static void lgdt3305_release(struct dvb_frontend *fe)
kfree(state);
}
+static struct dvb_frontend_ops lgdt3304_ops;
static struct dvb_frontend_ops lgdt3305_ops;
struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
@@ -1013,11 +1125,21 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
state->cfg = config;
state->i2c_adap = i2c_adap;
- memcpy(&state->frontend.ops, &lgdt3305_ops,
- sizeof(struct dvb_frontend_ops));
+ switch (config->demod_chip) {
+ case LGDT3304:
+ memcpy(&state->frontend.ops, &lgdt3304_ops,
+ sizeof(struct dvb_frontend_ops));
+ break;
+ case LGDT3305:
+ memcpy(&state->frontend.ops, &lgdt3305_ops,
+ sizeof(struct dvb_frontend_ops));
+ break;
+ default:
+ goto fail;
+ }
state->frontend.demodulator_priv = state;
- /* verify that we're talking to a lg dt3305 */
+ /* verify that we're talking to a lg dt3304/5 */
ret = lgdt3305_read_reg(state, LGDT3305_GEN_CTRL_2, &val);
if ((lg_fail(ret)) | (val == 0))
goto fail;
@@ -1036,12 +1158,35 @@ struct dvb_frontend *lgdt3305_attach(const struct lgdt3305_config *config,
return &state->frontend;
fail:
- lg_warn("unable to detect LGDT3305 hardware\n");
+ lg_warn("unable to detect %s hardware\n",
+ config->demod_chip ? "LGDT3304" : "LGDT3305");
kfree(state);
return NULL;
}
EXPORT_SYMBOL(lgdt3305_attach);
+static struct dvb_frontend_ops lgdt3304_ops = {
+ .info = {
+ .name = "LG Electronics LGDT3304 VSB/QAM Frontend",
+ .type = FE_ATSC,
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+ .i2c_gate_ctrl = lgdt3305_i2c_gate_ctrl,
+ .init = lgdt3305_init,
+ .set_frontend = lgdt3304_set_parameters,
+ .get_frontend = lgdt3305_get_frontend,
+ .get_tune_settings = lgdt3305_get_tune_settings,
+ .read_status = lgdt3305_read_status,
+ .read_ber = lgdt3305_read_ber,
+ .read_signal_strength = lgdt3305_read_signal_strength,
+ .read_snr = lgdt3305_read_snr,
+ .read_ucblocks = lgdt3305_read_ucblocks,
+ .release = lgdt3305_release,
+};
+
static struct dvb_frontend_ops lgdt3305_ops = {
.info = {
.name = "LG Electronics LGDT3305 VSB/QAM Frontend",
@@ -1065,10 +1210,10 @@ static struct dvb_frontend_ops lgdt3305_ops = {
.release = lgdt3305_release,
};
-MODULE_DESCRIPTION("LG Electronics LGDT3305 ATSC/QAM-B Demodulator Driver");
+MODULE_DESCRIPTION("LG Electronics LGDT3304/5 ATSC/QAM-B Demodulator Driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.1");
+MODULE_VERSION("0.2");
/*
* Local variables:
diff --git a/drivers/media/dvb/frontends/lgdt3305.h b/drivers/media/dvb/frontends/lgdt3305.h
index 9cb11c9cae53..02172eca4d47 100644
--- a/drivers/media/dvb/frontends/lgdt3305.h
+++ b/drivers/media/dvb/frontends/lgdt3305.h
@@ -1,7 +1,7 @@
/*
- * Support for LGDT3305 - VSB/QAM
+ * Support for LG Electronics LGDT3304 and LGDT3305 - VSB/QAM
*
- * Copyright (C) 2008, 2009 Michael Krufky <mkrufky@linuxtv.org>
+ * Copyright (C) 2008, 2009, 2010 Michael Krufky <mkrufky@linuxtv.org>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -41,6 +41,11 @@ enum lgdt3305_tp_valid_polarity {
LGDT3305_TP_VALID_HIGH = 1,
};
+enum lgdt_demod_chip_type {
+ LGDT3305 = 0,
+ LGDT3304 = 1,
+};
+
struct lgdt3305_config {
u8 i2c_addr;
@@ -65,6 +70,7 @@ struct lgdt3305_config {
enum lgdt3305_mpeg_mode mpeg_mode;
enum lgdt3305_tp_clock_edge tpclk_edge;
enum lgdt3305_tp_valid_polarity tpvalid_polarity;
+ enum lgdt_demod_chip_type demod_chip;
};
#if defined(CONFIG_DVB_LGDT3305) || (defined(CONFIG_DVB_LGDT3305_MODULE) && \
diff --git a/drivers/media/dvb/frontends/lgs8gxx.c b/drivers/media/dvb/frontends/lgs8gxx.c
index dee53960e7e8..1172b54689f8 100644
--- a/drivers/media/dvb/frontends/lgs8gxx.c
+++ b/drivers/media/dvb/frontends/lgs8gxx.c
@@ -24,6 +24,7 @@
*/
#include <asm/div64.h>
+#include <linux/firmware.h>
#include "dvb_frontend.h"
@@ -46,42 +47,6 @@ module_param(fake_signal_str, int, 0644);
MODULE_PARM_DESC(fake_signal_str, "fake signal strength for LGS8913."
"Signal strength calculation is slow.(default:on).");
-static const u8 lgs8g75_initdat[] = {
- 0x01, 0x30, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
- 0xE4, 0xF5, 0xA8, 0xF5, 0xB8, 0xF5, 0x88, 0xF5,
- 0x89, 0xF5, 0x87, 0x75, 0xD0, 0x00, 0x11, 0x50,
- 0x11, 0x50, 0xF4, 0xF5, 0x80, 0xF5, 0x90, 0xF5,
- 0xA0, 0xF5, 0xB0, 0x75, 0x81, 0x30, 0x80, 0x01,
- 0x32, 0x90, 0x80, 0x12, 0x74, 0xFF, 0xF0, 0x90,
- 0x80, 0x13, 0x74, 0x1F, 0xF0, 0x90, 0x80, 0x23,
- 0x74, 0x01, 0xF0, 0x90, 0x80, 0x22, 0xF0, 0x90,
- 0x00, 0x48, 0x74, 0x00, 0xF0, 0x90, 0x80, 0x4D,
- 0x74, 0x05, 0xF0, 0x90, 0x80, 0x09, 0xE0, 0x60,
- 0x21, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x1B, 0x12,
- 0x00, 0xDD, 0x14, 0x60, 0x15, 0x12, 0x00, 0xDD,
- 0x14, 0x60, 0x0F, 0x12, 0x00, 0xDD, 0x14, 0x60,
- 0x09, 0x12, 0x00, 0xDD, 0x14, 0x60, 0x03, 0x12,
- 0x00, 0xDD, 0x90, 0x80, 0x42, 0xE0, 0x60, 0x0B,
- 0x14, 0x60, 0x0C, 0x14, 0x60, 0x0D, 0x14, 0x60,
- 0x0E, 0x01, 0xB3, 0x74, 0x04, 0x01, 0xB9, 0x74,
- 0x05, 0x01, 0xB9, 0x74, 0x07, 0x01, 0xB9, 0x74,
- 0x0A, 0xC0, 0xE0, 0x74, 0xC8, 0x12, 0x00, 0xE2,
- 0xD0, 0xE0, 0x14, 0x70, 0xF4, 0x90, 0x80, 0x09,
- 0xE0, 0x70, 0xAE, 0x12, 0x00, 0xF6, 0x12, 0x00,
- 0xFE, 0x90, 0x00, 0x48, 0xE0, 0x04, 0xF0, 0x90,
- 0x80, 0x4E, 0xF0, 0x01, 0x73, 0x90, 0x80, 0x08,
- 0xF0, 0x22, 0xF8, 0x7A, 0x0C, 0x79, 0xFD, 0x00,
- 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xD9,
- 0xF6, 0xDA, 0xF2, 0xD8, 0xEE, 0x22, 0x90, 0x80,
- 0x65, 0xE0, 0x54, 0xFD, 0xF0, 0x22, 0x90, 0x80,
- 0x65, 0xE0, 0x44, 0xC2, 0xF0, 0x22
-};
-
/* LGS8GXX internal helper functions */
static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
@@ -95,13 +60,12 @@ static int lgs8gxx_write_reg(struct lgs8gxx_state *priv, u8 reg, u8 data)
msg.addr += 0x02;
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
- __func__, reg, data);
+ dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, data);
ret = i2c_transfer(priv->i2c, &msg, 1);
if (ret != 1)
- dprintk(KERN_DEBUG "%s: error reg=0x%x, data=0x%x, ret=%i\n",
+ dprintk("%s: error reg=0x%x, data=0x%x, ret=%i\n",
__func__, reg, data, ret);
return (ret != 1) ? -1 : 0;
@@ -126,15 +90,13 @@ static int lgs8gxx_read_reg(struct lgs8gxx_state *priv, u8 reg, u8 *p_data)
ret = i2c_transfer(priv->i2c, msg, 2);
if (ret != 2) {
- dprintk(KERN_DEBUG "%s: error reg=0x%x, ret=%i\n",
- __func__, reg, ret);
+ dprintk("%s: error reg=0x%x, ret=%i\n", __func__, reg, ret);
return -1;
}
*p_data = b1[0];
if (debug >= 2)
- printk(KERN_DEBUG "%s: reg=0x%02X, data=0x%02X\n",
- __func__, reg, b1[0]);
+ dprintk("%s: reg=0x%02X, data=0x%02X\n", __func__, reg, b1[0]);
return 0;
}
@@ -627,9 +589,14 @@ static int lgs8913_init(struct lgs8gxx_state *priv)
static int lgs8g75_init_data(struct lgs8gxx_state *priv)
{
- const u8 *p = lgs8g75_initdat;
+ const struct firmware *fw;
+ int rc;
int i;
+ rc = request_firmware(&fw, "lgs8g75.fw", &priv->i2c->dev);
+ if (rc)
+ return rc;
+
lgs8gxx_write_reg(priv, 0xC6, 0x40);
lgs8gxx_write_reg(priv, 0x3D, 0x04);
@@ -640,16 +607,16 @@ static int lgs8g75_init_data(struct lgs8gxx_state *priv)
lgs8gxx_write_reg(priv, 0x3B, 0x00);
lgs8gxx_write_reg(priv, 0x38, 0x00);
- for (i = 0; i < sizeof(lgs8g75_initdat); i++) {
+ for (i = 0; i < fw->size; i++) {
lgs8gxx_write_reg(priv, 0x38, 0x00);
lgs8gxx_write_reg(priv, 0x3A, (u8)(i&0xff));
lgs8gxx_write_reg(priv, 0x3B, (u8)(i>>8));
- lgs8gxx_write_reg(priv, 0x3C, *p);
- p++;
+ lgs8gxx_write_reg(priv, 0x3C, fw->data[i]);
}
lgs8gxx_write_reg(priv, 0x38, 0x00);
+ release_firmware(fw);
return 0;
}
@@ -692,7 +659,7 @@ static void lgs8gxx_release(struct dvb_frontend *fe)
}
-static int lgs8gxx_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int lgs8gxx_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct lgs8gxx_state *priv = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/mb86a16.c b/drivers/media/dvb/frontends/mb86a16.c
index 599d1aa519a3..33b63235b86e 100644
--- a/drivers/media/dvb/frontends/mb86a16.c
+++ b/drivers/media/dvb/frontends/mb86a16.c
@@ -1833,7 +1833,6 @@ static struct dvb_frontend_ops mb86a16_ops = {
.get_frontend_algo = mb86a16_frontend_algo,
.search = mb86a16_search,
- .read_status = mb86a16_read_status,
.init = mb86a16_init,
.sleep = mb86a16_sleep,
.read_status = mb86a16_read_status,
diff --git a/drivers/media/dvb/frontends/mb86a20s.c b/drivers/media/dvb/frontends/mb86a20s.c
new file mode 100644
index 000000000000..cc4acd2f920d
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a20s.c
@@ -0,0 +1,639 @@
+/*
+ * Fujitu mb86a20s ISDB-T/ISDB-Tsb Module driver
+ *
+ * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
+ *
+ * FIXME: Need to port to DVB v5.2 API
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "mb86a20s.h"
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define rc(args...) do { \
+ printk(KERN_ERR "mb86a20s: " args); \
+} while (0)
+
+#define dprintk(args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_DEBUG "mb86a20s: %s: ", __func__); \
+ printk(args); \
+ } \
+ } while (0)
+
+struct mb86a20s_state {
+ struct i2c_adapter *i2c;
+ const struct mb86a20s_config *config;
+
+ struct dvb_frontend frontend;
+
+ bool need_init;
+};
+
+struct regdata {
+ u8 reg;
+ u8 data;
+};
+
+/*
+ * Initialization sequence: Use whatevere default values that PV SBTVD
+ * does on its initialisation, obtained via USB snoop
+ */
+static struct regdata mb86a20s_init[] = {
+ { 0x70, 0x0f },
+ { 0x70, 0xff },
+ { 0x08, 0x01 },
+ { 0x09, 0x3e },
+ { 0x50, 0xd1 },
+ { 0x51, 0x22 },
+ { 0x39, 0x01 },
+ { 0x71, 0x00 },
+ { 0x28, 0x2a },
+ { 0x29, 0x00 },
+ { 0x2a, 0xff },
+ { 0x2b, 0x80 },
+ { 0x28, 0x20 },
+ { 0x29, 0x33 },
+ { 0x2a, 0xdf },
+ { 0x2b, 0xa9 },
+ { 0x3b, 0x21 },
+ { 0x3c, 0x3a },
+ { 0x01, 0x0d },
+ { 0x04, 0x08 },
+ { 0x05, 0x05 },
+ { 0x04, 0x0e },
+ { 0x05, 0x00 },
+ { 0x04, 0x0f },
+ { 0x05, 0x14 },
+ { 0x04, 0x0b },
+ { 0x05, 0x8c },
+ { 0x04, 0x00 },
+ { 0x05, 0x00 },
+ { 0x04, 0x01 },
+ { 0x05, 0x07 },
+ { 0x04, 0x02 },
+ { 0x05, 0x0f },
+ { 0x04, 0x03 },
+ { 0x05, 0xa0 },
+ { 0x04, 0x09 },
+ { 0x05, 0x00 },
+ { 0x04, 0x0a },
+ { 0x05, 0xff },
+ { 0x04, 0x27 },
+ { 0x05, 0x64 },
+ { 0x04, 0x28 },
+ { 0x05, 0x00 },
+ { 0x04, 0x1e },
+ { 0x05, 0xff },
+ { 0x04, 0x29 },
+ { 0x05, 0x0a },
+ { 0x04, 0x32 },
+ { 0x05, 0x0a },
+ { 0x04, 0x14 },
+ { 0x05, 0x02 },
+ { 0x04, 0x04 },
+ { 0x05, 0x00 },
+ { 0x04, 0x05 },
+ { 0x05, 0x22 },
+ { 0x04, 0x06 },
+ { 0x05, 0x0e },
+ { 0x04, 0x07 },
+ { 0x05, 0xd8 },
+ { 0x04, 0x12 },
+ { 0x05, 0x00 },
+ { 0x04, 0x13 },
+ { 0x05, 0xff },
+ { 0x52, 0x01 },
+ { 0x50, 0xa7 },
+ { 0x51, 0x00 },
+ { 0x50, 0xa8 },
+ { 0x51, 0xff },
+ { 0x50, 0xa9 },
+ { 0x51, 0xff },
+ { 0x50, 0xaa },
+ { 0x51, 0x00 },
+ { 0x50, 0xab },
+ { 0x51, 0xff },
+ { 0x50, 0xac },
+ { 0x51, 0xff },
+ { 0x50, 0xad },
+ { 0x51, 0x00 },
+ { 0x50, 0xae },
+ { 0x51, 0xff },
+ { 0x50, 0xaf },
+ { 0x51, 0xff },
+ { 0x5e, 0x07 },
+ { 0x50, 0xdc },
+ { 0x51, 0x01 },
+ { 0x50, 0xdd },
+ { 0x51, 0xf4 },
+ { 0x50, 0xde },
+ { 0x51, 0x01 },
+ { 0x50, 0xdf },
+ { 0x51, 0xf4 },
+ { 0x50, 0xe0 },
+ { 0x51, 0x01 },
+ { 0x50, 0xe1 },
+ { 0x51, 0xf4 },
+ { 0x50, 0xb0 },
+ { 0x51, 0x07 },
+ { 0x50, 0xb2 },
+ { 0x51, 0xff },
+ { 0x50, 0xb3 },
+ { 0x51, 0xff },
+ { 0x50, 0xb4 },
+ { 0x51, 0xff },
+ { 0x50, 0xb5 },
+ { 0x51, 0xff },
+ { 0x50, 0xb6 },
+ { 0x51, 0xff },
+ { 0x50, 0xb7 },
+ { 0x51, 0xff },
+ { 0x50, 0x50 },
+ { 0x51, 0x02 },
+ { 0x50, 0x51 },
+ { 0x51, 0x04 },
+ { 0x45, 0x04 },
+ { 0x48, 0x04 },
+ { 0x50, 0xd5 },
+ { 0x51, 0x01 }, /* Serial */
+ { 0x50, 0xd6 },
+ { 0x51, 0x1f },
+ { 0x50, 0xd2 },
+ { 0x51, 0x03 },
+ { 0x50, 0xd7 },
+ { 0x51, 0x3f },
+ { 0x1c, 0x01 },
+ { 0x28, 0x06 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x03 },
+ { 0x28, 0x07 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x0d },
+ { 0x28, 0x08 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x02 },
+ { 0x28, 0x09 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x01 },
+ { 0x28, 0x0a },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x21 },
+ { 0x28, 0x0b },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x29 },
+ { 0x28, 0x0c },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x16 },
+ { 0x28, 0x0d },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x31 },
+ { 0x28, 0x0e },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x0e },
+ { 0x28, 0x0f },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x4e },
+ { 0x28, 0x10 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x46 },
+ { 0x28, 0x11 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x0f },
+ { 0x28, 0x12 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x56 },
+ { 0x28, 0x13 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x35 },
+ { 0x28, 0x14 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x01 },
+ { 0x2b, 0xbe },
+ { 0x28, 0x15 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x01 },
+ { 0x2b, 0x84 },
+ { 0x28, 0x16 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x03 },
+ { 0x2b, 0xee },
+ { 0x28, 0x17 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x98 },
+ { 0x28, 0x18 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x00 },
+ { 0x2b, 0x9f },
+ { 0x28, 0x19 },
+ { 0x29, 0x00 },
+ { 0x2a, 0x07 },
+ { 0x2b, 0xb2 },
+ { 0x28, 0x1a },
+ { 0x29, 0x00 },
+ { 0x2a, 0x06 },
+ { 0x2b, 0xc2 },
+ { 0x28, 0x1b },
+ { 0x29, 0x00 },
+ { 0x2a, 0x07 },
+ { 0x2b, 0x4a },
+ { 0x28, 0x1c },
+ { 0x29, 0x00 },
+ { 0x2a, 0x01 },
+ { 0x2b, 0xbc },
+ { 0x28, 0x1d },
+ { 0x29, 0x00 },
+ { 0x2a, 0x04 },
+ { 0x2b, 0xba },
+ { 0x28, 0x1e },
+ { 0x29, 0x00 },
+ { 0x2a, 0x06 },
+ { 0x2b, 0x14 },
+ { 0x50, 0x1e },
+ { 0x51, 0x5d },
+ { 0x50, 0x22 },
+ { 0x51, 0x00 },
+ { 0x50, 0x23 },
+ { 0x51, 0xc8 },
+ { 0x50, 0x24 },
+ { 0x51, 0x00 },
+ { 0x50, 0x25 },
+ { 0x51, 0xf0 },
+ { 0x50, 0x26 },
+ { 0x51, 0x00 },
+ { 0x50, 0x27 },
+ { 0x51, 0xc3 },
+ { 0x50, 0x39 },
+ { 0x51, 0x02 },
+ { 0x50, 0xd5 },
+ { 0x51, 0x01 },
+ { 0xd0, 0x00 },
+};
+
+static struct regdata mb86a20s_reset_reception[] = {
+ { 0x70, 0xf0 },
+ { 0x70, 0xff },
+ { 0x08, 0x01 },
+ { 0x08, 0x00 },
+};
+
+static int mb86a20s_i2c_writereg(struct mb86a20s_state *state,
+ u8 i2c_addr, int reg, int data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = {
+ .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+ };
+ int rc;
+
+ rc = i2c_transfer(state->i2c, &msg, 1);
+ if (rc != 1) {
+ printk("%s: writereg error (rc == %i, reg == 0x%02x,"
+ " data == 0x%02x)\n", __func__, rc, reg, data);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int mb86a20s_i2c_writeregdata(struct mb86a20s_state *state,
+ u8 i2c_addr, struct regdata *rd, int size)
+{
+ int i, rc;
+
+ for (i = 0; i < size; i++) {
+ rc = mb86a20s_i2c_writereg(state, i2c_addr, rd[i].reg,
+ rd[i].data);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int mb86a20s_i2c_readreg(struct mb86a20s_state *state,
+ u8 i2c_addr, u8 reg)
+{
+ u8 val;
+ int rc;
+ struct i2c_msg msg[] = {
+ { .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+ };
+
+ rc = i2c_transfer(state->i2c, msg, 2);
+
+ if (rc != 2) {
+ rc("%s: reg=0x%x (error=%d)\n", __func__, reg, rc);
+ return rc;
+ }
+
+ return val;
+}
+
+#define mb86a20s_readreg(state, reg) \
+ mb86a20s_i2c_readreg(state, state->config->demod_address, reg)
+#define mb86a20s_writereg(state, reg, val) \
+ mb86a20s_i2c_writereg(state, state->config->demod_address, reg, val)
+#define mb86a20s_writeregdata(state, regdata) \
+ mb86a20s_i2c_writeregdata(state, state->config->demod_address, \
+ regdata, ARRAY_SIZE(regdata))
+
+static int mb86a20s_initfe(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc;
+ u8 regD5 = 1;
+
+ dprintk("\n");
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Initialize the frontend */
+ rc = mb86a20s_writeregdata(state, mb86a20s_init);
+ if (rc < 0)
+ goto err;
+
+ if (!state->config->is_serial) {
+ regD5 &= ~1;
+
+ rc = mb86a20s_writereg(state, 0x50, 0xd5);
+ if (rc < 0)
+ goto err;
+ rc = mb86a20s_writereg(state, 0x51, regD5);
+ if (rc < 0)
+ goto err;
+ }
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+err:
+ if (rc < 0) {
+ state->need_init = true;
+ printk(KERN_INFO "mb86a20s: Init failed. Will try again later\n");
+ } else {
+ state->need_init = false;
+ dprintk("Initialization succeded.\n");
+ }
+ return rc;
+}
+
+static int mb86a20s_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ unsigned rf_max, rf_min, rf;
+ u8 val;
+
+ dprintk("\n");
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ /* Does a binary search to get RF strength */
+ rf_max = 0xfff;
+ rf_min = 0;
+ do {
+ rf = (rf_max + rf_min) / 2;
+ mb86a20s_writereg(state, 0x04, 0x1f);
+ mb86a20s_writereg(state, 0x05, rf >> 8);
+ mb86a20s_writereg(state, 0x04, 0x20);
+ mb86a20s_writereg(state, 0x04, rf);
+
+ val = mb86a20s_readreg(state, 0x02);
+ if (val & 0x08)
+ rf_min = (rf_max + rf_min) / 2;
+ else
+ rf_max = (rf_max + rf_min) / 2;
+ if (rf_max - rf_min < 4) {
+ *strength = (((rf_max + rf_min) / 2) * 65535) / 4095;
+ break;
+ }
+ } while (1);
+
+ dprintk("signal strength = %d\n", *strength);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return 0;
+}
+
+static int mb86a20s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ u8 val;
+
+ dprintk("\n");
+ *status = 0;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ val = mb86a20s_readreg(state, 0x0a) & 0xf;
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (val >= 2)
+ *status |= FE_HAS_SIGNAL;
+
+ if (val >= 4)
+ *status |= FE_HAS_CARRIER;
+
+ if (val >= 5)
+ *status |= FE_HAS_VITERBI;
+
+ if (val >= 7)
+ *status |= FE_HAS_SYNC;
+
+ if (val >= 8) /* Maybe 9? */
+ *status |= FE_HAS_LOCK;
+
+ dprintk("val = %d, status = 0x%02x\n", val, *status);
+
+ return 0;
+}
+
+static int mb86a20s_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+ int rc;
+
+ dprintk("\n");
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ dprintk("Calling tuner set parameters\n");
+ fe->ops.tuner_ops.set_params(fe, p);
+
+ /*
+ * Make it more reliable: if, for some reason, the initial
+ * device initialization doesn't happen, initialize it when
+ * a SBTVD parameters are adjusted.
+ *
+ * Unfortunately, due to a hard to track bug at tda829x/tda18271,
+ * the agc callback logic is not called during DVB attach time,
+ * causing mb86a20s to not be initialized with Kworld SBTVD.
+ * So, this hack is needed, in order to make Kworld SBTVD to work.
+ */
+ if (state->need_init)
+ mb86a20s_initfe(fe);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ rc = mb86a20s_writeregdata(state, mb86a20s_reset_reception);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ return rc;
+}
+
+static int mb86a20s_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+
+ /* FIXME: For now, it does nothing */
+
+ fe->dtv_property_cache.bandwidth_hz = 6000000;
+ fe->dtv_property_cache.transmission_mode = TRANSMISSION_MODE_AUTO;
+ fe->dtv_property_cache.guard_interval = GUARD_INTERVAL_AUTO;
+ fe->dtv_property_cache.isdbt_partial_reception = 0;
+
+ return 0;
+}
+
+static int mb86a20s_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ unsigned int mode_flags,
+ unsigned int *delay,
+ fe_status_t *status)
+{
+ int rc = 0;
+
+ dprintk("\n");
+
+ if (params != NULL)
+ rc = mb86a20s_set_frontend(fe, params);
+
+ if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+ mb86a20s_read_status(fe, status);
+
+ return rc;
+}
+
+static void mb86a20s_release(struct dvb_frontend *fe)
+{
+ struct mb86a20s_state *state = fe->demodulator_priv;
+
+ dprintk("\n");
+
+ kfree(state);
+}
+
+static struct dvb_frontend_ops mb86a20s_ops;
+
+struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
+ struct i2c_adapter *i2c)
+{
+ u8 rev;
+
+ /* allocate memory for the internal state */
+ struct mb86a20s_state *state =
+ kzalloc(sizeof(struct mb86a20s_state), GFP_KERNEL);
+
+ dprintk("\n");
+ if (state == NULL) {
+ rc("Unable to kzalloc\n");
+ goto error;
+ }
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &mb86a20s_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ /* Check if it is a mb86a20s frontend */
+ rev = mb86a20s_readreg(state, 0);
+
+ if (rev == 0x13) {
+ printk(KERN_INFO "Detected a Fujitsu mb86a20s frontend\n");
+ } else {
+ printk(KERN_ERR "Frontend revision %d is unknown - aborting.\n",
+ rev);
+ goto error;
+ }
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(mb86a20s_attach);
+
+static struct dvb_frontend_ops mb86a20s_ops = {
+ /* Use dib8000 values per default */
+ .info = {
+ .name = "Fujitsu mb86A20s",
+ .type = FE_OFDM,
+ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_RECOVER |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_QAM_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+ /* Actually, those values depend on the used tuner */
+ .frequency_min = 45000000,
+ .frequency_max = 864000000,
+ .frequency_stepsize = 62500,
+ },
+
+ .release = mb86a20s_release,
+
+ .init = mb86a20s_initfe,
+ .set_frontend = mb86a20s_set_frontend,
+ .get_frontend = mb86a20s_get_frontend,
+ .read_status = mb86a20s_read_status,
+ .read_signal_strength = mb86a20s_read_signal_strength,
+ .tune = mb86a20s_tune,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Fujitsu mb86A20s hardware");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/mb86a20s.h b/drivers/media/dvb/frontends/mb86a20s.h
new file mode 100644
index 000000000000..bf22e77888b9
--- /dev/null
+++ b/drivers/media/dvb/frontends/mb86a20s.h
@@ -0,0 +1,52 @@
+/*
+ * Fujitsu mb86a20s driver
+ *
+ * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef MB86A20S_H
+#define MB86A20S_H
+
+#include <linux/dvb/frontend.h>
+
+/**
+ * struct mb86a20s_config - Define the per-device attributes of the frontend
+ *
+ * @demod_address: the demodulator's i2c address
+ */
+
+struct mb86a20s_config {
+ u8 demod_address;
+ bool is_serial;
+};
+
+#if defined(CONFIG_DVB_MB86A20S) || (defined(CONFIG_DVB_MB86A20S_MODULE) \
+ && defined(MODULE))
+extern struct dvb_frontend *mb86a20s_attach(const struct mb86a20s_config *config,
+ struct i2c_adapter *i2c);
+extern struct i2c_adapter *mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *);
+#else
+static inline struct dvb_frontend *mb86a20s_attach(
+ const struct mb86a20s_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+static struct i2c_adapter *
+ mb86a20s_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* MB86A20S */
diff --git a/drivers/media/dvb/frontends/mt352.c b/drivers/media/dvb/frontends/mt352.c
index beba5aa0db50..319672f8e1a7 100644
--- a/drivers/media/dvb/frontends/mt352.c
+++ b/drivers/media/dvb/frontends/mt352.c
@@ -69,7 +69,7 @@ static int mt352_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
return 0;
}
-static int _mt352_write(struct dvb_frontend* fe, u8* ibuf, int ilen)
+static int _mt352_write(struct dvb_frontend* fe, const u8 ibuf[], int ilen)
{
int err,i;
for (i=0; i < ilen-1; i++)
diff --git a/drivers/media/dvb/frontends/mt352.h b/drivers/media/dvb/frontends/mt352.h
index 595092f9f0c4..ca2562d6f289 100644
--- a/drivers/media/dvb/frontends/mt352.h
+++ b/drivers/media/dvb/frontends/mt352.h
@@ -63,7 +63,7 @@ static inline struct dvb_frontend* mt352_attach(const struct mt352_config* confi
}
#endif // CONFIG_DVB_MT352
-static inline int mt352_write(struct dvb_frontend *fe, u8 *buf, int len) {
+static inline int mt352_write(struct dvb_frontend *fe, const u8 buf[], int len) {
int r = 0;
if (fe->ops.write)
r = fe->ops.write(fe, buf, len);
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 2e9fd2893ede..e87b747ea99c 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -920,7 +920,6 @@ struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
/* create tuner i2c adapter */
strlcpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus",
sizeof(state->tuner_i2c_adapter.name));
- state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
state->tuner_i2c_adapter.algo_data = NULL;
i2c_set_adapdata(&state->tuner_i2c_adapter, state);
diff --git a/drivers/media/dvb/frontends/s5h1432.c b/drivers/media/dvb/frontends/s5h1432.c
new file mode 100644
index 000000000000..0c6dcb90d168
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1432.c
@@ -0,0 +1,415 @@
+/*
+ * Samsung s5h1432 DVB-T demodulator driver
+ *
+ * Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "s5h1432.h"
+
+struct s5h1432_state {
+
+ struct i2c_adapter *i2c;
+
+ /* configuration settings */
+ const struct s5h1432_config *config;
+
+ struct dvb_frontend frontend;
+
+ fe_modulation_t current_modulation;
+ unsigned int first_tune:1;
+
+ u32 current_frequency;
+ int if_freq;
+
+ u8 inversion;
+};
+
+static int debug;
+
+#define dprintk(arg...) do { \
+ if (debug) \
+ printk(arg); \
+ } while (0)
+
+static int s5h1432_writereg(struct s5h1432_state *state,
+ u8 addr, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf[] = { reg, data };
+
+ struct i2c_msg msg = {.addr = addr, .flags = 0, .buf = buf, .len = 2 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk(KERN_ERR "%s: writereg error 0x%02x 0x%02x 0x%04x, "
+ "ret == %i)\n", __func__, addr, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static u8 s5h1432_readreg(struct s5h1432_state *state, u8 addr, u8 reg)
+{
+ int ret;
+ u8 b0[] = { reg };
+ u8 b1[] = { 0 };
+
+ struct i2c_msg msg[] = {
+ {.addr = addr, .flags = 0, .buf = b0, .len = 1},
+ {.addr = addr, .flags = I2C_M_RD, .buf = b1, .len = 1}
+ };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+ __func__, ret);
+ return b1[0];
+}
+
+static int s5h1432_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int s5h1432_set_channel_bandwidth(struct dvb_frontend *fe,
+ u32 bandwidth)
+{
+ struct s5h1432_state *state = fe->demodulator_priv;
+
+ u8 reg = 0;
+
+ /* Register [0x2E] bit 3:2 : 8MHz = 0; 7MHz = 1; 6MHz = 2 */
+ reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x2E);
+ reg &= ~(0x0C);
+ switch (bandwidth) {
+ case 6:
+ reg |= 0x08;
+ break;
+ case 7:
+ reg |= 0x04;
+ break;
+ case 8:
+ reg |= 0x00;
+ break;
+ default:
+ return 0;
+ }
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2E, reg);
+ return 1;
+}
+
+static int s5h1432_set_IF(struct dvb_frontend *fe, u32 ifFreqHz)
+{
+ struct s5h1432_state *state = fe->demodulator_priv;
+
+ switch (ifFreqHz) {
+ case TAIWAN_HI_IF_FREQ_44_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x15);
+ break;
+ case EUROPE_HI_IF_FREQ_36_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0x40);
+ break;
+ case IF_FREQ_6_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xe0);
+ break;
+ case IF_FREQ_3point3_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
+ break;
+ case IF_FREQ_3point5_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x55);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x55);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xED);
+ break;
+ case IF_FREQ_4_MHZ:
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0xAA);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0xAA);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEA);
+ break;
+ default:
+ {
+ u32 value = 0;
+ value = (u32) (((48000 - (ifFreqHz / 1000)) * 512 *
+ (u32) 32768) / (48 * 1000));
+ printk(KERN_INFO
+ "Default IFFreq %d :reg value = 0x%x\n",
+ ifFreqHz, value);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4,
+ (u8) value & 0xFF);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5,
+ (u8) (value >> 8) & 0xFF);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7,
+ (u8) (value >> 16) & 0xFF);
+ break;
+ }
+
+ }
+
+ return 1;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int s5h1432_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ u32 dvb_bandwidth = 8;
+ struct s5h1432_state *state = fe->demodulator_priv;
+
+ if (p->frequency == state->current_frequency) {
+ /*current_frequency = p->frequency; */
+ /*state->current_frequency = p->frequency; */
+ } else {
+ fe->ops.tuner_ops.set_params(fe, p);
+ msleep(300);
+ s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
+ switch (p->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ dvb_bandwidth = 6;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ case BANDWIDTH_7_MHZ:
+ dvb_bandwidth = 7;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ case BANDWIDTH_8_MHZ:
+ dvb_bandwidth = 8;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ default:
+ return 0;
+ }
+ /*fe->ops.tuner_ops.set_params(fe, p); */
+/*Soft Reset chip*/
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+ s5h1432_set_channel_bandwidth(fe, dvb_bandwidth);
+ switch (p->u.ofdm.bandwidth) {
+ case BANDWIDTH_6_MHZ:
+ dvb_bandwidth = 6;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ case BANDWIDTH_7_MHZ:
+ dvb_bandwidth = 7;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ case BANDWIDTH_8_MHZ:
+ dvb_bandwidth = 8;
+ s5h1432_set_IF(fe, IF_FREQ_4_MHZ);
+ break;
+ default:
+ return 0;
+ }
+ /*fe->ops.tuner_ops.set_params(fe,p); */
+ /*Soft Reset chip*/
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+ }
+
+ state->current_frequency = p->frequency;
+
+ return 0;
+}
+
+static int s5h1432_init(struct dvb_frontend *fe)
+{
+ struct s5h1432_state *state = fe->demodulator_priv;
+
+ u8 reg = 0;
+ state->current_frequency = 0;
+ printk(KERN_INFO " s5h1432_init().\n");
+
+ /*Set VSB mode as default, this also does a soft reset */
+ /*Initialize registers */
+
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x04, 0xa8);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x05, 0x01);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x07, 0x70);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x19, 0x80);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1b, 0x9D);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1c, 0x30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1d, 0x20);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x1B);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x2e, 0x40);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, 0x84);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x50, 0x5a);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x5a, 0xd3);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x68, 0x50);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xb8, 0x3c);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xc4, 0x10);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xcc, 0x9c);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xDA, 0x00);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe1, 0x94);
+ /* s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf4, 0xa1); */
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xf9, 0x00);
+
+ /*For NXP tuner*/
+
+ /*Set 3.3MHz as default IF frequency */
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe4, 0x66);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe5, 0x66);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0xe7, 0xEE);
+ /* Set reg 0x1E to get the full dynamic range */
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x1e, 0x31);
+
+ /* Mode setting in demod */
+ reg = s5h1432_readreg(state, S5H1432_I2C_TOP_ADDR, 0x42);
+ reg |= 0x80;
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x42, reg);
+ /* Serial mode */
+
+ /* Soft Reset chip */
+
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1a);
+ msleep(30);
+ s5h1432_writereg(state, S5H1432_I2C_TOP_ADDR, 0x09, 0x1b);
+
+
+ return 0;
+}
+
+static int s5h1432_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ return 0;
+}
+
+static int s5h1432_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
+{
+ return 0;
+}
+
+static int s5h1432_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ return 0;
+}
+
+static int s5h1432_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+
+ return 0;
+}
+
+static int s5h1432_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ return 0;
+}
+
+static int s5h1432_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ return 0;
+}
+
+static int s5h1432_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ return 0;
+}
+
+static void s5h1432_release(struct dvb_frontend *fe)
+{
+ struct s5h1432_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s5h1432_ops;
+
+struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct s5h1432_state *state = NULL;
+
+ printk(KERN_INFO " Enter s5h1432_attach(). attach success!\n");
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct s5h1432_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->current_modulation = QAM_16;
+ state->inversion = state->config->inversion;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &s5h1432_ops,
+ sizeof(struct dvb_frontend_ops));
+
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(s5h1432_attach);
+
+static struct dvb_frontend_ops s5h1432_ops = {
+
+ .info = {
+ .name = "Samsung s5h1432 DVB-T Frontend",
+ .type = FE_OFDM,
+ .frequency_min = 177000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166666,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER},
+
+ .init = s5h1432_init,
+ .sleep = s5h1432_sleep,
+ .set_frontend = s5h1432_set_frontend,
+ .get_frontend = s5h1432_get_frontend,
+ .get_tune_settings = s5h1432_get_tune_settings,
+ .read_status = s5h1432_read_status,
+ .read_ber = s5h1432_read_ber,
+ .read_signal_strength = s5h1432_read_signal_strength,
+ .read_snr = s5h1432_read_snr,
+ .read_ucblocks = s5h1432_read_ucblocks,
+ .release = s5h1432_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Samsung s5h1432 DVB-T Demodulator driver");
+MODULE_AUTHOR("Bill Liu");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s5h1432.h b/drivers/media/dvb/frontends/s5h1432.h
new file mode 100644
index 000000000000..b57438c32546
--- /dev/null
+++ b/drivers/media/dvb/frontends/s5h1432.h
@@ -0,0 +1,91 @@
+/*
+ * Samsung s5h1432 VSB/QAM demodulator driver
+ *
+ * Copyright (C) 2009 Bill Liu <Bill.Liu@Conexant.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ *
+ */
+
+#ifndef __S5H1432_H__
+#define __S5H1432_H__
+
+#include <linux/dvb/frontend.h>
+
+#define S5H1432_I2C_TOP_ADDR (0x02 >> 1)
+
+#define TAIWAN_HI_IF_FREQ_44_MHZ 44000000
+#define EUROPE_HI_IF_FREQ_36_MHZ 36000000
+#define IF_FREQ_6_MHZ 6000000
+#define IF_FREQ_3point3_MHZ 3300000
+#define IF_FREQ_3point5_MHZ 3500000
+#define IF_FREQ_4_MHZ 4000000
+
+struct s5h1432_config {
+
+ /* serial/parallel output */
+#define S5H1432_PARALLEL_OUTPUT 0
+#define S5H1432_SERIAL_OUTPUT 1
+ u8 output_mode;
+
+ /* GPIO Setting */
+#define S5H1432_GPIO_OFF 0
+#define S5H1432_GPIO_ON 1
+ u8 gpio;
+
+ /* MPEG signal timing */
+#define S5H1432_MPEGTIMING_CONTINOUS_INVERTING_CLOCK 0
+#define S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK 1
+#define S5H1432_MPEGTIMING_NONCONTINOUS_INVERTING_CLOCK 2
+#define S5H1432_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK 3
+ u16 mpeg_timing;
+
+ /* IF Freq for QAM and VSB in KHz */
+#define S5H1432_IF_3250 3250
+#define S5H1432_IF_3500 3500
+#define S5H1432_IF_4000 4000
+#define S5H1432_IF_5380 5380
+#define S5H1432_IF_44000 44000
+#define S5H1432_VSB_IF_DEFAULT s5h1432_IF_44000
+#define S5H1432_QAM_IF_DEFAULT s5h1432_IF_44000
+ u16 qam_if;
+ u16 vsb_if;
+
+ /* Spectral Inversion */
+#define S5H1432_INVERSION_OFF 0
+#define S5H1432_INVERSION_ON 1
+ u8 inversion;
+
+ /* Return lock status based on tuner lock, or demod lock */
+#define S5H1432_TUNERLOCKING 0
+#define S5H1432_DEMODLOCKING 1
+ u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_S5H1432) || \
+ (defined(CONFIG_DVB_S5H1432_MODULE) && defined(MODULE))
+extern struct dvb_frontend *s5h1432_attach(const struct s5h1432_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *s5h1432_attach(const struct s5h1432_config
+ *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_s5h1432 */
+
+#endif /* __s5h1432_H__ */
diff --git a/drivers/media/dvb/frontends/s921.c b/drivers/media/dvb/frontends/s921.c
new file mode 100644
index 000000000000..ca0103d5f148
--- /dev/null
+++ b/drivers/media/dvb/frontends/s921.c
@@ -0,0 +1,548 @@
+/*
+ * Sharp VA3A5JZ921 One Seg Broadcast Module driver
+ * This device is labeled as just S. 921 at the top of the frontend can
+ *
+ * Copyright (C) 2009-2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009-2010 Douglas Landgraf <dougsland@redhat.com>
+ *
+ * Developed for Leadership SBTVD 1seg device sold in Brazil
+ *
+ * Frontend module based on cx24123 driver, getting some info from
+ * the old s921 driver.
+ *
+ * FIXME: Need to port to DVB v5.2 API
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <asm/div64.h>
+
+#include "dvb_frontend.h"
+#include "s921.h"
+
+static int debug = 1;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
+
+#define rc(args...) do { \
+ printk(KERN_ERR "s921: " args); \
+} while (0)
+
+#define dprintk(args...) \
+ do { \
+ if (debug) { \
+ printk(KERN_DEBUG "s921: %s: ", __func__); \
+ printk(args); \
+ } \
+ } while (0)
+
+struct s921_state {
+ struct i2c_adapter *i2c;
+ const struct s921_config *config;
+
+ struct dvb_frontend frontend;
+
+ /* The Demod can't easily provide these, we cache them */
+ u32 currentfreq;
+};
+
+/*
+ * Various tuner defaults need to be established for a given frequency kHz.
+ * fixme: The bounds on the bands do not match the doc in real life.
+ * fixme: Some of them have been moved, other might need adjustment.
+ */
+static struct s921_bandselect_val {
+ u32 freq_low;
+ u8 band_reg;
+} s921_bandselect[] = {
+ { 0, 0x7b },
+ { 485140000, 0x5b },
+ { 515140000, 0x3b },
+ { 545140000, 0x1b },
+ { 599140000, 0xfb },
+ { 623140000, 0xdb },
+ { 659140000, 0xbb },
+ { 713140000, 0x9b },
+};
+
+struct regdata {
+ u8 reg;
+ u8 data;
+};
+
+static struct regdata s921_init[] = {
+ { 0x01, 0x80 }, /* Probably, a reset sequence */
+ { 0x01, 0x40 },
+ { 0x01, 0x80 },
+ { 0x01, 0x40 },
+
+ { 0x02, 0x00 },
+ { 0x03, 0x40 },
+ { 0x04, 0x01 },
+ { 0x05, 0x00 },
+ { 0x06, 0x00 },
+ { 0x07, 0x00 },
+ { 0x08, 0x00 },
+ { 0x09, 0x00 },
+ { 0x0a, 0x00 },
+ { 0x0b, 0x5a },
+ { 0x0c, 0x00 },
+ { 0x0d, 0x00 },
+ { 0x0f, 0x00 },
+ { 0x13, 0x1b },
+ { 0x14, 0x80 },
+ { 0x15, 0x40 },
+ { 0x17, 0x70 },
+ { 0x18, 0x01 },
+ { 0x19, 0x12 },
+ { 0x1a, 0x01 },
+ { 0x1b, 0x12 },
+ { 0x1c, 0xa0 },
+ { 0x1d, 0x00 },
+ { 0x1e, 0x0a },
+ { 0x1f, 0x08 },
+ { 0x20, 0x40 },
+ { 0x21, 0xff },
+ { 0x22, 0x4c },
+ { 0x23, 0x4e },
+ { 0x24, 0x4c },
+ { 0x25, 0x00 },
+ { 0x26, 0x00 },
+ { 0x27, 0xf4 },
+ { 0x28, 0x60 },
+ { 0x29, 0x88 },
+ { 0x2a, 0x40 },
+ { 0x2b, 0x40 },
+ { 0x2c, 0xff },
+ { 0x2d, 0x00 },
+ { 0x2e, 0xff },
+ { 0x2f, 0x00 },
+ { 0x30, 0x20 },
+ { 0x31, 0x06 },
+ { 0x32, 0x0c },
+ { 0x34, 0x0f },
+ { 0x37, 0xfe },
+ { 0x38, 0x00 },
+ { 0x39, 0x63 },
+ { 0x3a, 0x10 },
+ { 0x3b, 0x10 },
+ { 0x47, 0x00 },
+ { 0x49, 0xe5 },
+ { 0x4b, 0x00 },
+ { 0x50, 0xc0 },
+ { 0x52, 0x20 },
+ { 0x54, 0x5a },
+ { 0x55, 0x5b },
+ { 0x56, 0x40 },
+ { 0x57, 0x70 },
+ { 0x5c, 0x50 },
+ { 0x5d, 0x00 },
+ { 0x62, 0x17 },
+ { 0x63, 0x2f },
+ { 0x64, 0x6f },
+ { 0x68, 0x00 },
+ { 0x69, 0x89 },
+ { 0x6a, 0x00 },
+ { 0x6b, 0x00 },
+ { 0x6c, 0x00 },
+ { 0x6d, 0x00 },
+ { 0x6e, 0x00 },
+ { 0x70, 0x10 },
+ { 0x71, 0x00 },
+ { 0x75, 0x00 },
+ { 0x76, 0x30 },
+ { 0x77, 0x01 },
+ { 0xaf, 0x00 },
+ { 0xb0, 0xa0 },
+ { 0xb2, 0x3d },
+ { 0xb3, 0x25 },
+ { 0xb4, 0x8b },
+ { 0xb5, 0x4b },
+ { 0xb6, 0x3f },
+ { 0xb7, 0xff },
+ { 0xb8, 0xff },
+ { 0xb9, 0xfc },
+ { 0xba, 0x00 },
+ { 0xbb, 0x00 },
+ { 0xbc, 0x00 },
+ { 0xd0, 0x30 },
+ { 0xe4, 0x84 },
+ { 0xf0, 0x48 },
+ { 0xf1, 0x19 },
+ { 0xf2, 0x5a },
+ { 0xf3, 0x8e },
+ { 0xf4, 0x2d },
+ { 0xf5, 0x07 },
+ { 0xf6, 0x5a },
+ { 0xf7, 0xba },
+ { 0xf8, 0xd7 },
+};
+
+static struct regdata s921_prefreq[] = {
+ { 0x47, 0x60 },
+ { 0x68, 0x00 },
+ { 0x69, 0x89 },
+ { 0xf0, 0x48 },
+ { 0xf1, 0x19 },
+};
+
+static struct regdata s921_postfreq[] = {
+ { 0xf5, 0xae },
+ { 0xf6, 0xb7 },
+ { 0xf7, 0xba },
+ { 0xf8, 0xd7 },
+ { 0x68, 0x0a },
+ { 0x69, 0x09 },
+};
+
+static int s921_i2c_writereg(struct s921_state *state,
+ u8 i2c_addr, int reg, int data)
+{
+ u8 buf[] = { reg, data };
+ struct i2c_msg msg = {
+ .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+ };
+ int rc;
+
+ rc = i2c_transfer(state->i2c, &msg, 1);
+ if (rc != 1) {
+ printk("%s: writereg rcor(rc == %i, reg == 0x%02x,"
+ " data == 0x%02x)\n", __func__, rc, reg, data);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int s921_i2c_writeregdata(struct s921_state *state, u8 i2c_addr,
+ struct regdata *rd, int size)
+{
+ int i, rc;
+
+ for (i = 0; i < size; i++) {
+ rc = s921_i2c_writereg(state, i2c_addr, rd[i].reg, rd[i].data);
+ if (rc < 0)
+ return rc;
+ }
+ return 0;
+}
+
+static int s921_i2c_readreg(struct s921_state *state, u8 i2c_addr, u8 reg)
+{
+ u8 val;
+ int rc;
+ struct i2c_msg msg[] = {
+ { .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &val, .len = 1 }
+ };
+
+ rc = i2c_transfer(state->i2c, msg, 2);
+
+ if (rc != 2) {
+ rc("%s: reg=0x%x (rcor=%d)\n", __func__, reg, rc);
+ return rc;
+ }
+
+ return val;
+}
+
+#define s921_readreg(state, reg) \
+ s921_i2c_readreg(state, state->config->demod_address, reg)
+#define s921_writereg(state, reg, val) \
+ s921_i2c_writereg(state, state->config->demod_address, reg, val)
+#define s921_writeregdata(state, regdata) \
+ s921_i2c_writeregdata(state, state->config->demod_address, \
+ regdata, ARRAY_SIZE(regdata))
+
+static int s921_pll_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s921_state *state = fe->demodulator_priv;
+ int band, rc, i;
+ unsigned long f_offset;
+ u8 f_switch;
+ u64 offset;
+
+ dprintk("frequency=%i\n", p->frequency);
+
+ for (band = 0; band < ARRAY_SIZE(s921_bandselect); band++)
+ if (p->frequency < s921_bandselect[band].freq_low)
+ break;
+ band--;
+
+ if (band < 0) {
+ rc("%s: frequency out of range\n", __func__);
+ return -EINVAL;
+ }
+
+ f_switch = s921_bandselect[band].band_reg;
+
+ offset = ((u64)p->frequency) * 258;
+ do_div(offset, 6000000);
+ f_offset = ((unsigned long)offset) + 2321;
+
+ rc = s921_writeregdata(state, s921_prefreq);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_writereg(state, 0xf2, (f_offset >> 8) & 0xff);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_writereg(state, 0xf3, f_offset & 0xff);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_writereg(state, 0xf4, f_switch);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_writeregdata(state, s921_postfreq);
+ if (rc < 0)
+ return rc;
+
+ for (i = 0 ; i < 6; i++) {
+ rc = s921_readreg(state, 0x80);
+ dprintk("status 0x80: %02x\n", rc);
+ }
+ rc = s921_writereg(state, 0x01, 0x40);
+ if (rc < 0)
+ return rc;
+
+ rc = s921_readreg(state, 0x01);
+ dprintk("status 0x01: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x80);
+ dprintk("status 0x80: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x80);
+ dprintk("status 0x80: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x32);
+ dprintk("status 0x32: %02x\n", rc);
+
+ dprintk("pll tune band=%d, pll=%d\n", f_switch, (int)f_offset);
+
+ return 0;
+}
+
+static int s921_initfe(struct dvb_frontend *fe)
+{
+ struct s921_state *state = fe->demodulator_priv;
+ int rc;
+
+ dprintk("\n");
+
+ rc = s921_writeregdata(state, s921_init);
+ if (rc < 0)
+ return rc;
+
+ return 0;
+}
+
+static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct s921_state *state = fe->demodulator_priv;
+ int regstatus, rc;
+
+ *status = 0;
+
+ rc = s921_readreg(state, 0x81);
+ if (rc < 0)
+ return rc;
+
+ regstatus = rc << 8;
+
+ rc = s921_readreg(state, 0x82);
+ if (rc < 0)
+ return rc;
+
+ regstatus |= rc;
+
+ dprintk("status = %04x\n", regstatus);
+
+ /* Full Sync - We don't know what each bit means on regs 0x81/0x82 */
+ if ((regstatus & 0xff) == 0x40) {
+ *status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC |
+ FE_HAS_LOCK;
+ } else if (regstatus & 0x40) {
+ /* This is close to Full Sync, but not enough to get useful info */
+ *status = FE_HAS_SIGNAL |
+ FE_HAS_CARRIER |
+ FE_HAS_VITERBI |
+ FE_HAS_SYNC;
+ }
+
+ return 0;
+}
+
+static int s921_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+ fe_status_t status;
+ struct s921_state *state = fe->demodulator_priv;
+ int rc;
+
+ /* FIXME: Use the proper register for it... 0x80? */
+ rc = s921_read_status(fe, &status);
+ if (rc < 0)
+ return rc;
+
+ *strength = (status & FE_HAS_LOCK) ? 0xffff : 0;
+
+ dprintk("strength = 0x%04x\n", *strength);
+
+ rc = s921_readreg(state, 0x01);
+ dprintk("status 0x01: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x80);
+ dprintk("status 0x80: %02x\n", rc);
+
+ rc = s921_readreg(state, 0x32);
+ dprintk("status 0x32: %02x\n", rc);
+
+ return 0;
+}
+
+static int s921_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s921_state *state = fe->demodulator_priv;
+ int rc;
+
+ dprintk("\n");
+
+ /* FIXME: We don't know how to use non-auto mode */
+
+ rc = s921_pll_tune(fe, p);
+ if (rc < 0)
+ return rc;
+
+ state->currentfreq = p->frequency;
+
+ return 0;
+}
+
+static int s921_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct s921_state *state = fe->demodulator_priv;
+
+ /* FIXME: Probably it is possible to get it from regs f1 and f2 */
+ p->frequency = state->currentfreq;
+
+ return 0;
+}
+
+static int s921_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ unsigned int mode_flags,
+ unsigned int *delay,
+ fe_status_t *status)
+{
+ int rc = 0;
+
+ dprintk("\n");
+
+ if (params != NULL)
+ rc = s921_set_frontend(fe, params);
+
+ if (!(mode_flags & FE_TUNE_MODE_ONESHOT))
+ s921_read_status(fe, status);
+
+ return rc;
+}
+
+static int s921_get_algo(struct dvb_frontend *fe)
+{
+ return 1; /* FE_ALGO_HW */
+}
+
+static void s921_release(struct dvb_frontend *fe)
+{
+ struct s921_state *state = fe->demodulator_priv;
+
+ dprintk("\n");
+ kfree(state);
+}
+
+static struct dvb_frontend_ops s921_ops;
+
+struct dvb_frontend *s921_attach(const struct s921_config *config,
+ struct i2c_adapter *i2c)
+{
+ /* allocate memory for the internal state */
+ struct s921_state *state =
+ kzalloc(sizeof(struct s921_state), GFP_KERNEL);
+
+ dprintk("\n");
+ if (state == NULL) {
+ rc("Unable to kzalloc\n");
+ goto rcor;
+ }
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &s921_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ return &state->frontend;
+
+rcor:
+ kfree(state);
+
+ return NULL;
+}
+EXPORT_SYMBOL(s921_attach);
+
+static struct dvb_frontend_ops s921_ops = {
+ /* Use dib8000 values per default */
+ .info = {
+ .name = "Sharp S921",
+ .type = FE_OFDM,
+ .frequency_min = 470000000,
+ /*
+ * Max should be 770MHz instead, according with Sharp docs,
+ * but Leadership doc says it works up to 806 MHz. This is
+ * required to get channel 69, used in Brazil
+ */
+ .frequency_max = 806000000,
+ .frequency_tolerance = 0,
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_RECOVER |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = s921_release,
+
+ .init = s921_initfe,
+ .set_frontend = s921_set_frontend,
+ .get_frontend = s921_get_frontend,
+ .read_status = s921_read_status,
+ .read_signal_strength = s921_read_signal_strength,
+ .tune = s921_tune,
+ .get_frontend_algo = s921_get_algo,
+};
+
+MODULE_DESCRIPTION("DVB Frontend module for Sharp S921 hardware");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_AUTHOR("Douglas Landgraf <dougsland@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s921.h b/drivers/media/dvb/frontends/s921.h
new file mode 100644
index 000000000000..f220d8299c81
--- /dev/null
+++ b/drivers/media/dvb/frontends/s921.h
@@ -0,0 +1,47 @@
+/*
+ * Sharp s921 driver
+ *
+ * Copyright (C) 2009 Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2009 Douglas Landgraf <dougsland@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ */
+
+#ifndef S921_H
+#define S921_H
+
+#include <linux/dvb/frontend.h>
+
+struct s921_config {
+ /* the demodulator's i2c address */
+ u8 demod_address;
+};
+
+#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) \
+ && defined(MODULE))
+extern struct dvb_frontend *s921_attach(const struct s921_config *config,
+ struct i2c_adapter *i2c);
+extern struct i2c_adapter *s921_get_tuner_i2c_adapter(struct dvb_frontend *);
+#else
+static inline struct dvb_frontend *s921_attach(
+ const struct s921_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+static struct i2c_adapter *
+ s921_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif /* S921_H */
diff --git a/drivers/media/dvb/frontends/s921_core.c b/drivers/media/dvb/frontends/s921_core.c
deleted file mode 100644
index 974b52be9aea..000000000000
--- a/drivers/media/dvb/frontends/s921_core.c
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Driver for Sharp s921 driver
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
- *
- */
-
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include "s921_core.h"
-
-static int s921_isdb_init(struct s921_isdb_t *dev);
-static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params);
-static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params);
-static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data);
-
-static u8 init_table[]={ 0x01, 0x40, 0x02, 0x00, 0x03, 0x40, 0x04, 0x01,
- 0x05, 0x00, 0x06, 0x00, 0x07, 0x00, 0x08, 0x00,
- 0x09, 0x00, 0x0a, 0x00, 0x0b, 0x5a, 0x0c, 0x00,
- 0x0d, 0x00, 0x0f, 0x00, 0x13, 0x1b, 0x14, 0x80,
- 0x15, 0x40, 0x17, 0x70, 0x18, 0x01, 0x19, 0x12,
- 0x1a, 0x01, 0x1b, 0x12, 0x1c, 0xa0, 0x1d, 0x00,
- 0x1e, 0x0a, 0x1f, 0x08, 0x20, 0x40, 0x21, 0xff,
- 0x22, 0x4c, 0x23, 0x4e, 0x24, 0x4c, 0x25, 0x00,
- 0x26, 0x00, 0x27, 0xf4, 0x28, 0x60, 0x29, 0x88,
- 0x2a, 0x40, 0x2b, 0x40, 0x2c, 0xff, 0x2d, 0x00,
- 0x2e, 0xff, 0x2f, 0x00, 0x30, 0x20, 0x31, 0x06,
- 0x32, 0x0c, 0x34, 0x0f, 0x37, 0xfe, 0x38, 0x00,
- 0x39, 0x63, 0x3a, 0x10, 0x3b, 0x10, 0x47, 0x00,
- 0x49, 0xe5, 0x4b, 0x00, 0x50, 0xc0, 0x52, 0x20,
- 0x54, 0x5a, 0x55, 0x5b, 0x56, 0x40, 0x57, 0x70,
- 0x5c, 0x50, 0x5d, 0x00, 0x62, 0x17, 0x63, 0x2f,
- 0x64, 0x6f, 0x68, 0x00, 0x69, 0x89, 0x6a, 0x00,
- 0x6b, 0x00, 0x6c, 0x00, 0x6d, 0x00, 0x6e, 0x00,
- 0x70, 0x00, 0x71, 0x00, 0x75, 0x00, 0x76, 0x30,
- 0x77, 0x01, 0xaf, 0x00, 0xb0, 0xa0, 0xb2, 0x3d,
- 0xb3, 0x25, 0xb4, 0x8b, 0xb5, 0x4b, 0xb6, 0x3f,
- 0xb7, 0xff, 0xb8, 0xff, 0xb9, 0xfc, 0xba, 0x00,
- 0xbb, 0x00, 0xbc, 0x00, 0xd0, 0x30, 0xe4, 0x84,
- 0xf0, 0x48, 0xf1, 0x19, 0xf2, 0x5a, 0xf3, 0x8e,
- 0xf4, 0x2d, 0xf5, 0x07, 0xf6, 0x5a, 0xf7, 0xba,
- 0xf8, 0xd7 };
-
-static u8 c_table[]={ 0x58, 0x8a, 0x7b, 0x59, 0x8c, 0x7b, 0x5a, 0x8e, 0x5b,
- 0x5b, 0x90, 0x5b, 0x5c, 0x92, 0x5b, 0x5d, 0x94, 0x5b,
- 0x5e, 0x96, 0x5b, 0x5f, 0x98, 0x3b, 0x60, 0x9a, 0x3b,
- 0x61, 0x9c, 0x3b, 0x62, 0x9e, 0x3b, 0x63, 0xa0, 0x3b,
- 0x64, 0xa2, 0x1b, 0x65, 0xa4, 0x1b, 0x66, 0xa6, 0x1b,
- 0x67, 0xa8, 0x1b, 0x68, 0xaa, 0x1b, 0x69, 0xac, 0x1b,
- 0x6a, 0xae, 0x1b, 0x6b, 0xb0, 0x1b, 0x6c, 0xb2, 0x1b,
- 0x6d, 0xb4, 0xfb, 0x6e, 0xb6, 0xfb, 0x6f, 0xb8, 0xfb,
- 0x70, 0xba, 0xfb, 0x71, 0xbc, 0xdb, 0x72, 0xbe, 0xdb,
- 0x73, 0xc0, 0xdb, 0x74, 0xc2, 0xdb, 0x75, 0xc4, 0xdb,
- 0x76, 0xc6, 0xdb, 0x77, 0xc8, 0xbb, 0x78, 0xca, 0xbb,
- 0x79, 0xcc, 0xbb, 0x7a, 0xce, 0xbb, 0x7b, 0xd0, 0xbb,
- 0x7c, 0xd2, 0xbb, 0x7d, 0xd4, 0xbb, 0x7e, 0xd6, 0xbb,
- 0x7f, 0xd8, 0xbb, 0x80, 0xda, 0x9b, 0x81, 0xdc, 0x9b,
- 0x82, 0xde, 0x9b, 0x83, 0xe0, 0x9b, 0x84, 0xe2, 0x9b,
- 0x85, 0xe4, 0x9b, 0x86, 0xe6, 0x9b, 0x87, 0xe8, 0x9b,
- 0x88, 0xea, 0x9b, 0x89, 0xec, 0x9b };
-
-int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data) {
- switch(cmd) {
- case ISDB_T_CMD_INIT:
- s921_isdb_init(dev);
- break;
- case ISDB_T_CMD_SET_PARAM:
- s921_isdb_set_parameters(dev, data);
- break;
- case ISDB_T_CMD_TUNE:
- s921_isdb_tune(dev, data);
- break;
- case ISDB_T_CMD_GET_STATUS:
- s921_isdb_get_status(dev, data);
- break;
- default:
- printk("unhandled command\n");
- return -EINVAL;
- }
- return 0;
-}
-
-static int s921_isdb_init(struct s921_isdb_t *dev) {
- unsigned int i;
- unsigned int ret;
- printk("isdb_init\n");
- for (i = 0; i < sizeof(init_table); i+=2) {
- ret = dev->i2c_write(dev->priv_dev, init_table[i], init_table[i+1]);
- if (ret != 0) {
- printk("i2c write failed\n");
- return ret;
- }
- }
- return 0;
-}
-
-static int s921_isdb_set_parameters(struct s921_isdb_t *dev, struct s921_isdb_t_transmission_mode_params *params) {
-
- int ret;
- /* auto is sufficient for now, lateron this should be reflected in an extra interface */
-
-
-
- ret = dev->i2c_write(dev->priv_dev, 0xb0, 0xa0); //mod_b2);
- ret = dev->i2c_write(dev->priv_dev, 0xb2, 0x3d); //mod_b2);
-
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb3, 0x25); //mod_b3);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb4, 0x8b); //mod_b4);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb5, 0x4b); //mod_b5);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb6, 0x3f); //mod_b6);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xb7, 0x3f); //mod_b7);
- if (ret < 0)
- return -EINVAL;
-
- return E_OK;
-}
-
-static int s921_isdb_tune(struct s921_isdb_t *dev, struct s921_isdb_t_tune_params *params) {
-
- int ret;
- int index;
-
- index = (params->frequency - 473143000)/6000000;
-
- if (index > 48) {
- return -EINVAL;
- }
-
- dev->i2c_write(dev->priv_dev, 0x47, 0x60);
-
- ret = dev->i2c_write(dev->priv_dev, 0x68, 0x00);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0x69, 0x89);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf0, 0x48);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf1, 0x19);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf2, c_table[index*3]);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf3, c_table[index*3+1]);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf4, c_table[index*3+2]);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf5, 0xae);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf6, 0xb7);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf7, 0xba);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0xf8, 0xd7);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0x68, 0x0a);
- if (ret < 0)
- return -EINVAL;
-
- ret = dev->i2c_write(dev->priv_dev, 0x69, 0x09);
- if (ret < 0)
- return -EINVAL;
-
- dev->i2c_write(dev->priv_dev, 0x01, 0x40);
- return 0;
-}
-
-static int s921_isdb_get_status(struct s921_isdb_t *dev, void *data) {
- unsigned int *ret = (unsigned int*)data;
- u8 ifagc_dt;
- u8 rfagc_dt;
-
- mdelay(10);
- ifagc_dt = dev->i2c_read(dev->priv_dev, 0x81);
- rfagc_dt = dev->i2c_read(dev->priv_dev, 0x82);
- if (rfagc_dt == 0x40) {
- *ret = 1;
- }
- return 0;
-}
diff --git a/drivers/media/dvb/frontends/s921_core.h b/drivers/media/dvb/frontends/s921_core.h
deleted file mode 100644
index de2f10a44e72..000000000000
--- a/drivers/media/dvb/frontends/s921_core.h
+++ /dev/null
@@ -1,114 +0,0 @@
-#ifndef _S921_CORE_H
-#define _S921_CORE_H
-//#define u8 unsigned int
-//#define u32 unsigned int
-
-
-
-//#define EINVAL -1
-#define E_OK 0
-
-struct s921_isdb_t {
- void *priv_dev;
- int (*i2c_write)(void *dev, u8 reg, u8 val);
- int (*i2c_read)(void *dev, u8 reg);
-};
-
-#define ISDB_T_CMD_INIT 0
-#define ISDB_T_CMD_SET_PARAM 1
-#define ISDB_T_CMD_TUNE 2
-#define ISDB_T_CMD_GET_STATUS 3
-
-struct s921_isdb_t_tune_params {
- u32 frequency;
-};
-
-struct s921_isdb_t_status {
-};
-
-struct s921_isdb_t_transmission_mode_params {
- u8 mode;
- u8 layer_a_mode;
-#define ISDB_T_LA_MODE_1 0
-#define ISDB_T_LA_MODE_2 1
-#define ISDB_T_LA_MODE_3 2
- u8 layer_a_carrier_modulation;
-#define ISDB_T_LA_CM_DQPSK 0
-#define ISDB_T_LA_CM_QPSK 1
-#define ISDB_T_LA_CM_16QAM 2
-#define ISDB_T_LA_CM_64QAM 3
-#define ISDB_T_LA_CM_NOLAYER 4
- u8 layer_a_code_rate;
-#define ISDB_T_LA_CR_1_2 0
-#define ISDB_T_LA_CR_2_3 1
-#define ISDB_T_LA_CR_3_4 2
-#define ISDB_T_LA_CR_5_6 4
-#define ISDB_T_LA_CR_7_8 8
-#define ISDB_T_LA_CR_NOLAYER 16
- u8 layer_a_time_interleave;
-#define ISDB_T_LA_TI_0 0
-#define ISDB_T_LA_TI_1 1
-#define ISDB_T_LA_TI_2 2
-#define ISDB_T_LA_TI_4 4
-#define ISDB_T_LA_TI_8 8
-#define ISDB_T_LA_TI_16 16
-#define ISDB_T_LA_TI_32 32
- u8 layer_a_nseg;
-
- u8 layer_b_mode;
-#define ISDB_T_LB_MODE_1 0
-#define ISDB_T_LB_MODE_2 1
-#define ISDB_T_LB_MODE_3 2
- u8 layer_b_carrier_modulation;
-#define ISDB_T_LB_CM_DQPSK 0
-#define ISDB_T_LB_CM_QPSK 1
-#define ISDB_T_LB_CM_16QAM 2
-#define ISDB_T_LB_CM_64QAM 3
-#define ISDB_T_LB_CM_NOLAYER 4
- u8 layer_b_code_rate;
-#define ISDB_T_LB_CR_1_2 0
-#define ISDB_T_LB_CR_2_3 1
-#define ISDB_T_LB_CR_3_4 2
-#define ISDB_T_LB_CR_5_6 4
-#define ISDB_T_LB_CR_7_8 8
-#define ISDB_T_LB_CR_NOLAYER 16
- u8 layer_b_time_interleave;
-#define ISDB_T_LB_TI_0 0
-#define ISDB_T_LB_TI_1 1
-#define ISDB_T_LB_TI_2 2
-#define ISDB_T_LB_TI_4 4
-#define ISDB_T_LB_TI_8 8
-#define ISDB_T_LB_TI_16 16
-#define ISDB_T_LB_TI_32 32
- u8 layer_b_nseg;
-
- u8 layer_c_mode;
-#define ISDB_T_LC_MODE_1 0
-#define ISDB_T_LC_MODE_2 1
-#define ISDB_T_LC_MODE_3 2
- u8 layer_c_carrier_modulation;
-#define ISDB_T_LC_CM_DQPSK 0
-#define ISDB_T_LC_CM_QPSK 1
-#define ISDB_T_LC_CM_16QAM 2
-#define ISDB_T_LC_CM_64QAM 3
-#define ISDB_T_LC_CM_NOLAYER 4
- u8 layer_c_code_rate;
-#define ISDB_T_LC_CR_1_2 0
-#define ISDB_T_LC_CR_2_3 1
-#define ISDB_T_LC_CR_3_4 2
-#define ISDB_T_LC_CR_5_6 4
-#define ISDB_T_LC_CR_7_8 8
-#define ISDB_T_LC_CR_NOLAYER 16
- u8 layer_c_time_interleave;
-#define ISDB_T_LC_TI_0 0
-#define ISDB_T_LC_TI_1 1
-#define ISDB_T_LC_TI_2 2
-#define ISDB_T_LC_TI_4 4
-#define ISDB_T_LC_TI_8 8
-#define ISDB_T_LC_TI_16 16
-#define ISDB_T_LC_TI_32 32
- u8 layer_c_nseg;
-};
-
-int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
-#endif
diff --git a/drivers/media/dvb/frontends/s921_module.c b/drivers/media/dvb/frontends/s921_module.c
deleted file mode 100644
index 0eefff61cc50..000000000000
--- a/drivers/media/dvb/frontends/s921_module.c
+++ /dev/null
@@ -1,192 +0,0 @@
-/*
- * Driver for Sharp s921 driver
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
- *
- * All rights reserved.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include "dvb_frontend.h"
-#include "s921_module.h"
-#include "s921_core.h"
-
-static unsigned int debug = 0;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"s921 debugging (default off)");
-
-#define dprintk(fmt, args...) if (debug) do {\
- printk("s921 debug: " fmt, ##args); } while (0)
-
-struct s921_state
-{
- struct dvb_frontend frontend;
- fe_modulation_t current_modulation;
- __u32 snr;
- __u32 current_frequency;
- __u8 addr;
- struct s921_isdb_t dev;
- struct i2c_adapter *i2c;
-};
-
-static int s921_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *param) {
- struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
- struct s921_isdb_t_transmission_mode_params params;
- struct s921_isdb_t_tune_params tune_params;
-
- tune_params.frequency = param->frequency;
- s921_isdb_cmd(&state->dev, ISDB_T_CMD_SET_PARAM, &params);
- s921_isdb_cmd(&state->dev, ISDB_T_CMD_TUNE, &tune_params);
- mdelay(100);
- return 0;
-}
-
-static int s921_init(struct dvb_frontend *fe) {
- printk("s921 init\n");
- return 0;
-}
-
-static int s921_sleep(struct dvb_frontend *fe) {
- printk("s921 sleep\n");
- return 0;
-}
-
-static int s921_read_status(struct dvb_frontend *fe, fe_status_t *status)
-{
- struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
- unsigned int ret;
- mdelay(5);
- s921_isdb_cmd(&state->dev, ISDB_T_CMD_GET_STATUS, &ret);
- *status = 0;
-
- printk("status: %02x\n", ret);
- if (ret == 1) {
- *status |= FE_HAS_CARRIER;
- *status |= FE_HAS_VITERBI;
- *status |= FE_HAS_LOCK;
- *status |= FE_HAS_SYNC;
- *status |= FE_HAS_SIGNAL;
- }
-
- return 0;
-}
-
-static int s921_read_ber(struct dvb_frontend *fe, __u32 *ber)
-{
- dprintk("read ber\n");
- return 0;
-}
-
-static int s921_read_snr(struct dvb_frontend *fe, __u16 *snr)
-{
- dprintk("read snr\n");
- return 0;
-}
-
-static int s921_read_ucblocks(struct dvb_frontend *fe, __u32 *ucblocks)
-{
- dprintk("read ucblocks\n");
- return 0;
-}
-
-static void s921_release(struct dvb_frontend *fe)
-{
- struct s921_state *state = (struct s921_state *)fe->demodulator_priv;
- kfree(state);
-}
-
-static struct dvb_frontend_ops demod_s921={
- .info = {
- .name = "SHARP S921",
- .type = FE_OFDM,
- .frequency_min = 473143000,
- .frequency_max = 767143000,
- .frequency_stepsize = 6000000,
- .frequency_tolerance = 0,
- .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
- FE_CAN_FEC_3_4 | FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 |
- FE_CAN_FEC_AUTO |
- FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
- FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
- FE_CAN_HIERARCHY_AUTO | FE_CAN_RECOVER |
- FE_CAN_MUTE_TS
- },
- .init = s921_init,
- .sleep = s921_sleep,
- .set_frontend = s921_set_parameters,
- .read_snr = s921_read_snr,
- .read_ber = s921_read_ber,
- .read_status = s921_read_status,
- .read_ucblocks = s921_read_ucblocks,
- .release = s921_release,
-};
-
-static int s921_write(void *dev, u8 reg, u8 val) {
- struct s921_state *state = dev;
- char buf[2]={reg,val};
- int err;
- struct i2c_msg i2cmsgs = {
- .addr = state->addr,
- .flags = 0,
- .len = 2,
- .buf = buf
- };
-
- if((err = i2c_transfer(state->i2c, &i2cmsgs, 1))<0) {
- printk("%s i2c_transfer error %d\n", __func__, err);
- if (err < 0)
- return err;
- else
- return -EREMOTEIO;
- }
-
- return 0;
-}
-
-static int s921_read(void *dev, u8 reg) {
- struct s921_state *state = dev;
- u8 b1;
- int ret;
- struct i2c_msg msg[2] = { { .addr = state->addr,
- .flags = 0,
- .buf = &reg, .len = 1 },
- { .addr = state->addr,
- .flags = I2C_M_RD,
- .buf = &b1, .len = 1 } };
-
- ret = i2c_transfer(state->i2c, msg, 2);
- if (ret != 2)
- return ret;
- return b1;
-}
-
-struct dvb_frontend* s921_attach(const struct s921_config *config,
- struct i2c_adapter *i2c)
-{
-
- struct s921_state *state;
- state = kzalloc(sizeof(struct s921_state), GFP_KERNEL);
- if (state == NULL)
- return NULL;
-
- state->addr = config->i2c_address;
- state->i2c = i2c;
- state->dev.i2c_write = &s921_write;
- state->dev.i2c_read = &s921_read;
- state->dev.priv_dev = state;
-
- s921_isdb_cmd(&state->dev, ISDB_T_CMD_INIT, NULL);
-
- memcpy(&state->frontend.ops, &demod_s921, sizeof(struct dvb_frontend_ops));
- state->frontend.demodulator_priv = state;
- return &state->frontend;
-}
-
-EXPORT_SYMBOL_GPL(s921_attach);
-MODULE_AUTHOR("Markus Rechberger <mrechberger@empiatech.com>");
-MODULE_DESCRIPTION("Sharp S921 ISDB-T 1Seg");
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/s921_module.h b/drivers/media/dvb/frontends/s921_module.h
deleted file mode 100644
index 78660424ba95..000000000000
--- a/drivers/media/dvb/frontends/s921_module.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * Driver for DVB-T s921 demodulator
- *
- * Copyright (C) 2008 Markus Rechberger <mrechberger@sundtek.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- *
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
- */
-
-#ifndef S921_MODULE_H
-#define S921_MODULE_H
-
-#include <linux/dvb/frontend.h>
-#include "s921_core.h"
-
-int s921_isdb_init(struct s921_isdb_t *dev);
-int s921_isdb_cmd(struct s921_isdb_t *dev, u32 cmd, void *data);
-
-struct s921_config
-{
- /* demodulator's I2C address */
- u8 i2c_address;
-};
-
-#if defined(CONFIG_DVB_S921) || (defined(CONFIG_DVB_S921_MODULE) && defined(MODULE))
-extern struct dvb_frontend* s921_attach(const struct s921_config *config,
- struct i2c_adapter *i2c);
-#else
-static inline struct dvb_frontend* s921_attach(const struct s921_config *config,
- struct i2c_adapter *i2c)
-{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
- return NULL;
-}
-#endif /* CONFIG_DVB_S921 */
-
-#endif /* S921_H */
diff --git a/drivers/media/dvb/frontends/si21xx.c b/drivers/media/dvb/frontends/si21xx.c
index d21a327db629..4b0c99a08a85 100644
--- a/drivers/media/dvb/frontends/si21xx.c
+++ b/drivers/media/dvb/frontends/si21xx.c
@@ -268,7 +268,7 @@ static int si21_writereg(struct si21xx_state *state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-static int si21_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int si21_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct si21xx_state *state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/stb0899_drv.c b/drivers/media/dvb/frontends/stb0899_drv.c
index 8e38fcee564e..37a222d9ddb3 100644
--- a/drivers/media/dvb/frontends/stb0899_drv.c
+++ b/drivers/media/dvb/frontends/stb0899_drv.c
@@ -714,7 +714,7 @@ static int stb0899_send_diseqc_msg(struct dvb_frontend *fe, struct dvb_diseqc_ma
reg = stb0899_read_reg(state, STB0899_DISCNTRL1);
STB0899_SETFIELD_VAL(DISPRECHARGE, reg, 0);
stb0899_write_reg(state, STB0899_DISCNTRL1, reg);
-
+ msleep(100);
return 0;
}
diff --git a/drivers/media/dvb/frontends/stb6100.c b/drivers/media/dvb/frontends/stb6100.c
index f73c13323e90..64673b8b64a2 100644
--- a/drivers/media/dvb/frontends/stb6100.c
+++ b/drivers/media/dvb/frontends/stb6100.c
@@ -51,7 +51,7 @@ module_param(verbose, int, 0644);
if (x > y) \
printk(format, ##arg); \
} \
-} while(0)
+} while (0)
struct stb6100_lkup {
u32 val_low;
@@ -117,7 +117,10 @@ static const struct stb6100_regmask stb6100_template[] = {
[STB6100_TEST3] = { 0x00, 0xde },
};
-static void stb6100_normalise_regs(u8 regs[])
+/*
+ * Currently unused. Some boards might need it in the future
+ */
+static inline void stb6100_normalise_regs(u8 regs[])
{
int i;
@@ -157,13 +160,25 @@ static int stb6100_read_reg(struct stb6100_state *state, u8 reg)
u8 regs[STB6100_NUMREGS];
int rc;
+ struct i2c_msg msg = {
+ .addr = state->config->tuner_address + reg,
+ .flags = I2C_M_RD,
+ .buf = regs,
+ .len = 1
+ };
+
+ rc = i2c_transfer(state->i2c, &msg, 1);
+
if (unlikely(reg >= STB6100_NUMREGS)) {
dprintk(verbose, FE_ERROR, 1, "Invalid register offset 0x%x", reg);
return -EINVAL;
}
- if ((rc = stb6100_read_regs(state, regs)) < 0)
- return rc;
- return (unsigned int)regs[reg];
+ if (unlikely(verbose > FE_DEBUG)) {
+ dprintk(verbose, FE_DEBUG, 1, " Read from 0x%02x", state->config->tuner_address);
+ dprintk(verbose, FE_DEBUG, 1, " %s: 0x%02x", stb6100_regnames[reg], regs[0]);
+ }
+
+ return (unsigned int)regs[0];
}
static int stb6100_write_reg_range(struct stb6100_state *state, u8 buf[], int start, int len)
@@ -211,20 +226,17 @@ static int stb6100_write_reg(struct stb6100_state *state, u8 reg, u8 data)
return stb6100_write_reg_range(state, &data, reg, 1);
}
-static int stb6100_write_regs(struct stb6100_state *state, u8 regs[])
-{
- stb6100_normalise_regs(regs);
- return stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 1);
-}
static int stb6100_get_status(struct dvb_frontend *fe, u32 *status)
{
int rc;
struct stb6100_state *state = fe->tuner_priv;
- if ((rc = stb6100_read_reg(state, STB6100_LD)) < 0)
+ rc = stb6100_read_reg(state, STB6100_LD);
+ if (rc < 0) {
+ dprintk(verbose, FE_ERROR, 1, "%s failed", __func__);
return rc;
-
+ }
return (rc & STB6100_LD_LOCK) ? TUNER_STATUS_LOCKED : 0;
}
@@ -234,7 +246,8 @@ static int stb6100_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
u8 f;
struct stb6100_state *state = fe->tuner_priv;
- if ((rc = stb6100_read_reg(state, STB6100_F)) < 0)
+ rc = stb6100_read_reg(state, STB6100_F);
+ if (rc < 0)
return rc;
f = rc & STB6100_F_F;
@@ -265,14 +278,21 @@ static int stb6100_set_bandwidth(struct dvb_frontend *fe, u32 bandwidth)
/* Turn on LPF bandwidth setting clock control,
* set bandwidth, wait 10ms, turn off.
*/
- if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK)) < 0)
+ rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d | STB6100_FCCK_FCCK);
+ if (rc < 0)
return rc;
- if ((rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp)) < 0)
+ rc = stb6100_write_reg(state, STB6100_F, 0xc0 | tmp);
+ if (rc < 0)
return rc;
- msleep(1);
- if ((rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d)) < 0)
+
+ msleep(5); /* This is dangerous as another (related) thread may start */
+
+ rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
+ if (rc < 0)
return rc;
+ msleep(10); /* This is dangerous as another (related) thread may start */
+
return 0;
}
@@ -284,7 +304,8 @@ static int stb6100_get_frequency(struct dvb_frontend *fe, u32 *frequency)
struct stb6100_state *state = fe->tuner_priv;
u8 regs[STB6100_NUMREGS];
- if ((rc = stb6100_read_regs(state, regs)) < 0)
+ rc = stb6100_read_regs(state, regs);
+ if (rc < 0)
return rc;
odiv = (regs[STB6100_VCO] & STB6100_VCO_ODIV) >> STB6100_VCO_ODIV_SHIFT;
@@ -312,8 +333,7 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
u8 regs[STB6100_NUMREGS];
u8 g, psd2, odiv;
- if ((rc = stb6100_read_regs(state, regs)) < 0)
- return rc;
+ dprintk(verbose, FE_DEBUG, 1, "Version 2010-8-14 13:51");
if (fe->ops.get_frontend) {
dprintk(verbose, FE_DEBUG, 1, "Get frontend parameters");
@@ -321,96 +341,140 @@ static int stb6100_set_frequency(struct dvb_frontend *fe, u32 frequency)
}
srate = p.u.qpsk.symbol_rate;
- regs[STB6100_DLB] = 0xdc;
- /* Disable LPEN */
- regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL Loop disabled */
+ /* Set up tuner cleanly, LPF calibration on */
+ rc = stb6100_write_reg(state, STB6100_FCCK, 0x4d | STB6100_FCCK_FCCK);
+ if (rc < 0)
+ return rc; /* allow LPF calibration */
- if ((rc = stb6100_write_regs(state, regs)) < 0)
+ /* PLL Loop disabled, bias on, VCO on, synth on */
+ regs[STB6100_LPEN] = 0xeb;
+ rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
+ if (rc < 0)
return rc;
- /* Baseband gain. */
- if (srate >= 15000000)
- g = 9; // +4 dB
- else if (srate >= 5000000)
- g = 11; // +8 dB
- else
- g = 14; // +14 dB
-
- regs[STB6100_G] = (regs[STB6100_G] & ~STB6100_G_G) | g;
- regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
- regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
+ /* Program the registers with their data values */
/* VCO divide ratio (LO divide ratio, VCO prescaler enable). */
if (frequency <= 1075000)
odiv = 1;
else
odiv = 0;
- regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_ODIV) | (odiv << STB6100_VCO_ODIV_SHIFT);
- if ((frequency > 1075000) && (frequency <= 1325000))
- psd2 = 0;
- else
- psd2 = 1;
- regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
+ /* VCO enabled, seach clock off as per LL3.7, 3.4.1 */
+ regs[STB6100_VCO] = 0xe0 | (odiv << STB6100_VCO_ODIV_SHIFT);
/* OSM */
for (ptr = lkup;
(ptr->val_high != 0) && !CHKRANGE(frequency, ptr->val_low, ptr->val_high);
ptr++);
+
if (ptr->val_high == 0) {
printk(KERN_ERR "%s: frequency out of range: %u kHz\n", __func__, frequency);
return -EINVAL;
}
regs[STB6100_VCO] = (regs[STB6100_VCO] & ~STB6100_VCO_OSM) | ptr->reg;
+ rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+ if (rc < 0)
+ return rc;
+ if ((frequency > 1075000) && (frequency <= 1325000))
+ psd2 = 0;
+ else
+ psd2 = 1;
/* F(VCO) = F(LO) * (ODIV == 0 ? 2 : 4) */
fvco = frequency << (1 + odiv);
/* N(I) = floor(f(VCO) / (f(XTAL) * (PSD2 ? 2 : 1))) */
nint = fvco / (state->reference << psd2);
/* N(F) = round(f(VCO) / f(XTAL) * (PSD2 ? 2 : 1) - N(I)) * 2 ^ 9 */
nfrac = DIV_ROUND_CLOSEST((fvco - (nint * state->reference << psd2))
- << (9 - psd2),
- state->reference);
+ << (9 - psd2), state->reference);
+
+ /* NI */
+ regs[STB6100_NI] = nint;
+ rc = stb6100_write_reg(state, STB6100_NI, regs[STB6100_NI]);
+ if (rc < 0)
+ return rc;
+
+ /* NF */
+ regs[STB6100_NF_LSB] = nfrac;
+ rc = stb6100_write_reg(state, STB6100_NF_LSB, regs[STB6100_NF_LSB]);
+ if (rc < 0)
+ return rc;
+
+ /* K */
+ regs[STB6100_K] = (0x38 & ~STB6100_K_PSD2) | (psd2 << STB6100_K_PSD2_SHIFT);
+ regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
+ rc = stb6100_write_reg(state, STB6100_K, regs[STB6100_K]);
+ if (rc < 0)
+ return rc;
+
+ /* G Baseband gain. */
+ if (srate >= 15000000)
+ g = 9; /* +4 dB */
+ else if (srate >= 5000000)
+ g = 11; /* +8 dB */
+ else
+ g = 14; /* +14 dB */
+
+ regs[STB6100_G] = (0x10 & ~STB6100_G_G) | g;
+ regs[STB6100_G] &= ~STB6100_G_GCT; /* mask GCT */
+ regs[STB6100_G] |= (1 << 5); /* 2Vp-p Mode */
+ rc = stb6100_write_reg(state, STB6100_G, regs[STB6100_G]);
+ if (rc < 0)
+ return rc;
+
+ /* F we don't write as it is set up in BW set */
+
+ /* DLB set DC servo loop BW to 160Hz (LLA 3.8 / 2.1) */
+ regs[STB6100_DLB] = 0xcc;
+ rc = stb6100_write_reg(state, STB6100_DLB, regs[STB6100_DLB]);
+ if (rc < 0)
+ return rc;
+
dprintk(verbose, FE_DEBUG, 1,
"frequency = %u, srate = %u, g = %u, odiv = %u, psd2 = %u, fxtal = %u, osm = %u, fvco = %u, N(I) = %u, N(F) = %u",
frequency, srate, (unsigned int)g, (unsigned int)odiv,
(unsigned int)psd2, state->reference,
ptr->reg, fvco, nint, nfrac);
- regs[STB6100_NI] = nint;
- regs[STB6100_NF_LSB] = nfrac;
- regs[STB6100_K] = (regs[STB6100_K] & ~STB6100_K_NF_MSB) | ((nfrac >> 8) & STB6100_K_NF_MSB);
- regs[STB6100_VCO] |= STB6100_VCO_OSCH; /* VCO search enabled */
- regs[STB6100_VCO] |= STB6100_VCO_OCK; /* VCO search clock off */
- regs[STB6100_FCCK] |= STB6100_FCCK_FCCK; /* LPF BW setting clock enabled */
- regs[STB6100_LPEN] &= ~STB6100_LPEN_LPEN; /* PLL loop disabled */
- /* Power up. */
- regs[STB6100_LPEN] |= STB6100_LPEN_SYNP | STB6100_LPEN_OSCP | STB6100_LPEN_BEN;
- msleep(2);
- if ((rc = stb6100_write_regs(state, regs)) < 0)
+ /* Set up the test registers */
+ regs[STB6100_TEST1] = 0x8f;
+ rc = stb6100_write_reg(state, STB6100_TEST1, regs[STB6100_TEST1]);
+ if (rc < 0)
+ return rc;
+ regs[STB6100_TEST3] = 0xde;
+ rc = stb6100_write_reg(state, STB6100_TEST3, regs[STB6100_TEST3]);
+ if (rc < 0)
return rc;
- msleep(2);
- regs[STB6100_LPEN] |= STB6100_LPEN_LPEN; /* PLL loop enabled */
- if ((rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN])) < 0)
+ /* Bring up tuner according to LLA 3.7 3.4.1, step 2 */
+ regs[STB6100_LPEN] = 0xfb; /* PLL Loop enabled, bias on, VCO on, synth on */
+ rc = stb6100_write_reg(state, STB6100_LPEN, regs[STB6100_LPEN]);
+ if (rc < 0)
return rc;
+ msleep(2);
+
+ /* Bring up tuner according to LLA 3.7 3.4.1, step 3 */
regs[STB6100_VCO] &= ~STB6100_VCO_OCK; /* VCO fast search */
- if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
+ rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+ if (rc < 0)
return rc;
- msleep(10); /* wait for LO to lock */
+ msleep(10); /* This is dangerous as another (related) thread may start */ /* wait for LO to lock */
+
regs[STB6100_VCO] &= ~STB6100_VCO_OSCH; /* vco search disabled */
regs[STB6100_VCO] |= STB6100_VCO_OCK; /* search clock off */
- if ((rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO])) < 0)
- return rc;
- regs[STB6100_FCCK] &= ~STB6100_FCCK_FCCK; /* LPF BW clock disabled */
- stb6100_normalise_regs(regs);
- if ((rc = stb6100_write_reg_range(state, &regs[1], 1, STB6100_NUMREGS - 3)) < 0)
+ rc = stb6100_write_reg(state, STB6100_VCO, regs[STB6100_VCO]);
+ if (rc < 0)
return rc;
- msleep(100);
+ rc = stb6100_write_reg(state, STB6100_FCCK, 0x0d);
+ if (rc < 0)
+ return rc; /* Stop LPF calibration */
+ msleep(10); /* This is dangerous as another (related) thread may start */
+ /* wait for stabilisation, (should not be necessary) */
return 0;
}
@@ -433,8 +497,8 @@ static int stb6100_init(struct dvb_frontend *fe)
state->bandwidth = status->bandwidth * 1000; /* Hz */
state->reference = status->refclock / 1000; /* kHz */
- /* Set default bandwidth. */
- return stb6100_set_bandwidth(fe, state->bandwidth);
+ /* Set default bandwidth. Modified, PN 13-May-10 */
+ return 0;
}
static int stb6100_get_state(struct dvb_frontend *fe,
@@ -506,7 +570,7 @@ static struct dvb_tuner_ops stb6100_ops = {
};
struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
- struct stb6100_config *config,
+ const struct stb6100_config *config,
struct i2c_adapter *i2c)
{
struct stb6100_state *state = NULL;
diff --git a/drivers/media/dvb/frontends/stb6100.h b/drivers/media/dvb/frontends/stb6100.h
index 395d056599a6..2ab096614b3f 100644
--- a/drivers/media/dvb/frontends/stb6100.h
+++ b/drivers/media/dvb/frontends/stb6100.h
@@ -97,13 +97,13 @@ struct stb6100_state {
#if defined(CONFIG_DVB_STB6100) || (defined(CONFIG_DVB_STB6100_MODULE) && defined(MODULE))
extern struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
- struct stb6100_config *config,
+ const struct stb6100_config *config,
struct i2c_adapter *i2c);
#else
static inline struct dvb_frontend *stb6100_attach(struct dvb_frontend *fe,
- struct stb6100_config *config,
+ const struct stb6100_config *config,
struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: Driver disabled by Kconfig\n", __func__);
diff --git a/drivers/media/dvb/frontends/stv0288.c b/drivers/media/dvb/frontends/stv0288.c
index 2930a5d6768a..63db8fd2754c 100644
--- a/drivers/media/dvb/frontends/stv0288.c
+++ b/drivers/media/dvb/frontends/stv0288.c
@@ -6,6 +6,8 @@
Copyright (C) 2008 Igor M. Liplianin <liplianin@me.by>
Removed stb6000 specific tuner code and revised some
procedures.
+ 2010-09-01 Josef Pavlik <josef@pavlik.it>
+ Fixed diseqc_msg, diseqc_burst and set_tone problems
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
@@ -78,7 +80,7 @@ static int stv0288_writeregI(struct stv0288_state *state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-static int stv0288_write(struct dvb_frontend *fe, u8 *buf, int len)
+static int stv0288_write(struct dvb_frontend *fe, const u8 buf[], int len)
{
struct stv0288_state *state = fe->demodulator_priv;
@@ -156,14 +158,13 @@ static int stv0288_send_diseqc_msg(struct dvb_frontend *fe,
stv0288_writeregI(state, 0x09, 0);
msleep(30);
- stv0288_writeregI(state, 0x05, 0x16);
+ stv0288_writeregI(state, 0x05, 0x12);/* modulated mode, single shot */
for (i = 0; i < m->msg_len; i++) {
if (stv0288_writeregI(state, 0x06, m->msg[i]))
return -EREMOTEIO;
- msleep(12);
}
-
+ msleep(m->msg_len*12);
return 0;
}
@@ -174,13 +175,14 @@ static int stv0288_send_diseqc_burst(struct dvb_frontend *fe,
dprintk("%s\n", __func__);
- if (stv0288_writeregI(state, 0x05, 0x16))/* burst mode */
+ if (stv0288_writeregI(state, 0x05, 0x03))/* burst mode, single shot */
return -EREMOTEIO;
if (stv0288_writeregI(state, 0x06, burst == SEC_MINI_A ? 0x00 : 0xff))
return -EREMOTEIO;
- if (stv0288_writeregI(state, 0x06, 0x12))
+ msleep(15);
+ if (stv0288_writeregI(state, 0x05, 0x12))
return -EREMOTEIO;
return 0;
@@ -192,18 +194,19 @@ static int stv0288_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_ON:
- if (stv0288_writeregI(state, 0x05, 0x10))/* burst mode */
+ if (stv0288_writeregI(state, 0x05, 0x10))/* cont carrier */
return -EREMOTEIO;
- return stv0288_writeregI(state, 0x06, 0xff);
+ break;
case SEC_TONE_OFF:
- if (stv0288_writeregI(state, 0x05, 0x13))/* burst mode */
+ if (stv0288_writeregI(state, 0x05, 0x12))/* burst mode off*/
return -EREMOTEIO;
- return stv0288_writeregI(state, 0x06, 0x00);
+ break;
default:
return -EINVAL;
}
+ return 0;
}
static u8 stv0288_inittab[] = {
@@ -486,7 +489,7 @@ static int stv0288_set_frontend(struct dvb_frontend *fe,
tda[2] = 0x0; /* CFRL */
for (tm = -6; tm < 7;) {
/* Viterbi status */
- if (stv0288_readreg(state, 0x24) & 0x80)
+ if (stv0288_readreg(state, 0x24) & 0x8)
break;
tda[2] += 40;
diff --git a/drivers/media/dvb/frontends/stv0299.c b/drivers/media/dvb/frontends/stv0299.c
index 968874469726..4e3db3a42e06 100644
--- a/drivers/media/dvb/frontends/stv0299.c
+++ b/drivers/media/dvb/frontends/stv0299.c
@@ -92,7 +92,7 @@ static int stv0299_writeregI (struct stv0299_state* state, u8 reg, u8 data)
return (ret != 1) ? -EREMOTEIO : 0;
}
-static int stv0299_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int stv0299_write(struct dvb_frontend* fe, const u8 buf[], int len)
{
struct stv0299_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/stv0299.h b/drivers/media/dvb/frontends/stv0299.h
index 0fd96e22b650..ba219b767a69 100644
--- a/drivers/media/dvb/frontends/stv0299.h
+++ b/drivers/media/dvb/frontends/stv0299.h
@@ -65,7 +65,7 @@ struct stv0299_config
* First of each pair is the register, second is the value.
* List should be terminated with an 0xff, 0xff pair.
*/
- u8* inittab;
+ const u8* inittab;
/* master clock to use */
u32 mclk;
diff --git a/drivers/media/dvb/frontends/stv090x.c b/drivers/media/dvb/frontends/stv090x.c
index 425e7a43ae19..4e0fc2c8a41c 100644
--- a/drivers/media/dvb/frontends/stv090x.c
+++ b/drivers/media/dvb/frontends/stv090x.c
@@ -1483,8 +1483,8 @@ static int stv090x_start_search(struct stv090x_state *state)
if (STV090x_WRITE_DEMOD(state, FFECFG, 0x41) < 0)
goto err;
- if ((state->search_mode == STV090x_DVBS1) ||
- (state->search_mode == STV090x_DSS) ||
+ if ((state->search_mode == STV090x_SEARCH_DVBS1) ||
+ (state->search_mode == STV090x_SEARCH_DSS) ||
(state->search_mode == STV090x_SEARCH_AUTO)) {
if (STV090x_WRITE_DEMOD(state, VITSCALE, 0x82) < 0)
@@ -2940,7 +2940,7 @@ static int stv090x_optimize_track(struct stv090x_state *state)
STV090x_WRITE_DEMOD(state, ERRCTRL1, 0x67); /* PER */
break;
- case STV090x_UNKNOWN:
+ case STV090x_ERROR:
default:
reg = STV090x_READ_DEMOD(state, DMDCFGMD);
STV090x_SETFIELD_Px(reg, DVBS1_ENABLE_FIELD, 1);
diff --git a/drivers/media/dvb/frontends/stv6110x.c b/drivers/media/dvb/frontends/stv6110x.c
index 42591ce1aaad..f36cab12bdc7 100644
--- a/drivers/media/dvb/frontends/stv6110x.c
+++ b/drivers/media/dvb/frontends/stv6110x.c
@@ -303,7 +303,10 @@ static int stv6110x_set_mode(struct dvb_frontend *fe, enum tuner_mode mode)
static int stv6110x_sleep(struct dvb_frontend *fe)
{
- return stv6110x_set_mode(fe, TUNER_SLEEP);
+ if (fe->tuner_priv)
+ return stv6110x_set_mode(fe, TUNER_SLEEP);
+
+ return 0;
}
static int stv6110x_get_status(struct dvb_frontend *fe, u32 *status)
diff --git a/drivers/media/dvb/frontends/tda10048.c b/drivers/media/dvb/frontends/tda10048.c
index 4e2a7c8b2f62..93f6a75c238e 100644
--- a/drivers/media/dvb/frontends/tda10048.c
+++ b/drivers/media/dvb/frontends/tda10048.c
@@ -25,6 +25,7 @@
#include <linux/string.h>
#include <linux/slab.h>
#include <linux/delay.h>
+#include <linux/math64.h>
#include <asm/div64.h>
#include "dvb_frontend.h"
#include "dvb_math.h"
@@ -49,8 +50,8 @@
#define TDA10048_CONF_C4_1 0x1E
#define TDA10048_CONF_C4_2 0x1F
#define TDA10048_CODE_IN_RAM 0x20
-#define TDA10048_CHANNEL_INFO_1_R 0x22
-#define TDA10048_CHANNEL_INFO_2_R 0x23
+#define TDA10048_CHANNEL_INFO1_R 0x22
+#define TDA10048_CHANNEL_INFO2_R 0x23
#define TDA10048_CHANNEL_INFO1 0x24
#define TDA10048_CHANNEL_INFO2 0x25
#define TDA10048_TIME_ERROR_R 0x26
@@ -63,8 +64,8 @@
#define TDA10048_IT_STAT 0x32
#define TDA10048_DSP_AD_LSB 0x3C
#define TDA10048_DSP_AD_MSB 0x3D
-#define TDA10048_DSP_REF_LSB 0x3E
-#define TDA10048_DSP_REF_MSB 0x3F
+#define TDA10048_DSP_REG_LSB 0x3E
+#define TDA10048_DSP_REG_MSB 0x3F
#define TDA10048_CONF_TRISTATE1 0x44
#define TDA10048_CONF_TRISTATE2 0x45
#define TDA10048_CONF_POLARITY 0x46
@@ -112,7 +113,7 @@
#define TDA10048_FREE_REG_1 0xB2
#define TDA10048_FREE_REG_2 0xB3
#define TDA10048_CONF_C3_1 0xC0
-#define TDA10048_CYBER_CTRL 0xC2
+#define TDA10048_CVBER_CTRL 0xC2
#define TDA10048_CBER_NMAX_LSB 0xC4
#define TDA10048_CBER_NMAX_MSB 0xC5
#define TDA10048_CBER_LSB 0xC6
@@ -120,7 +121,7 @@
#define TDA10048_VBER_LSB 0xC8
#define TDA10048_VBER_MID 0xC9
#define TDA10048_VBER_MSB 0xCA
-#define TDA10048_CYBER_LUT 0xCC
+#define TDA10048_CVBER_LUT 0xCC
#define TDA10048_UNCOR_CTRL 0xCD
#define TDA10048_UNCOR_CPT_LSB 0xCE
#define TDA10048_UNCOR_CPT_MSB 0xCF
@@ -183,7 +184,7 @@ static struct init_tab {
{ TDA10048_AGC_IF_MAX, 0xff },
{ TDA10048_AGC_THRESHOLD_MSB, 0x00 },
{ TDA10048_AGC_THRESHOLD_LSB, 0x70 },
- { TDA10048_CYBER_CTRL, 0x38 },
+ { TDA10048_CVBER_CTRL, 0x38 },
{ TDA10048_AGC_GAINS, 0x12 },
{ TDA10048_CONF_XO, 0x00 },
{ TDA10048_CONF_TS1, 0x07 },
@@ -688,7 +689,7 @@ static int tda10048_get_tps(struct tda10048_state *state,
p->guard_interval = GUARD_INTERVAL_1_4;
break;
}
- switch (val & 0x02) {
+ switch (val & 0x03) {
case 0:
p->transmission_mode = TRANSMISSION_MODE_2K;
break;
@@ -765,6 +766,8 @@ static int tda10048_set_frontend(struct dvb_frontend *fe,
/* Enable demod TPS auto detection and begin acquisition */
tda10048_writereg(state, TDA10048_AUTO, 0x57);
+ /* trigger cber and vber acquisition */
+ tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x3B);
return 0;
}
@@ -830,12 +833,27 @@ static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status)
static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct tda10048_state *state = fe->demodulator_priv;
+ static u32 cber_current;
+ u32 cber_nmax;
+ u64 cber_tmp;
dprintk(1, "%s()\n", __func__);
- /* TODO: A reset may be required here */
- *ber = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
- tda10048_readreg(state, TDA10048_CBER_LSB);
+ /* update cber on interrupt */
+ if (tda10048_readreg(state, TDA10048_SOFT_IT_C3) & 0x01) {
+ cber_tmp = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
+ tda10048_readreg(state, TDA10048_CBER_LSB);
+ cber_nmax = tda10048_readreg(state, TDA10048_CBER_NMAX_MSB) << 8 |
+ tda10048_readreg(state, TDA10048_CBER_NMAX_LSB);
+ cber_tmp *= 100000000;
+ cber_tmp *= 2;
+ cber_tmp = div_u64(cber_tmp, (cber_nmax * 32) + 1);
+ cber_current = (u32)cber_tmp;
+ /* retrigger cber acquisition */
+ tda10048_writereg(state, TDA10048_CVBER_CTRL, 0x39);
+ }
+ /* actual cber is (*ber)/1e8 */
+ *ber = cber_current;
return 0;
}
@@ -1015,6 +1033,9 @@ static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
*ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
+ /* clear the uncorrected TS packets counter when saturated */
+ if (*ucblocks == 0xFFFF)
+ tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x80);
return 0;
}
diff --git a/drivers/media/dvb/frontends/tda1004x.c b/drivers/media/dvb/frontends/tda1004x.c
index f2a8abe0a243..ea485d923550 100644
--- a/drivers/media/dvb/frontends/tda1004x.c
+++ b/drivers/media/dvb/frontends/tda1004x.c
@@ -598,7 +598,7 @@ static int tda1004x_decode_fec(int tdafec)
return -1;
}
-static int tda1004x_write(struct dvb_frontend* fe, u8 *buf, int len)
+static int tda1004x_write(struct dvb_frontend* fe, const u8 buf[], int len)
{
struct tda1004x_state* state = fe->demodulator_priv;
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 8c612719adfc..adbbf6d3d044 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -64,7 +64,7 @@ static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
return 0;
}
-static int zl10353_write(struct dvb_frontend *fe, u8 *ibuf, int ilen)
+static int zl10353_write(struct dvb_frontend *fe, const u8 ibuf[], int ilen)
{
int err, i;
for (i = 0; i < ilen - 1; i++)
diff --git a/drivers/media/dvb/mantis/Kconfig b/drivers/media/dvb/mantis/Kconfig
index f7b72a32adf3..a13a50503134 100644
--- a/drivers/media/dvb/mantis/Kconfig
+++ b/drivers/media/dvb/mantis/Kconfig
@@ -1,6 +1,6 @@
config MANTIS_CORE
tristate "Mantis/Hopper PCI bridge based devices"
- depends on PCI && I2C && INPUT
+ depends on PCI && I2C && INPUT && RC_CORE
help
Support for PCI cards based on the Mantis and Hopper PCi bridge.
@@ -10,9 +10,15 @@ config MANTIS_CORE
config DVB_MANTIS
tristate "MANTIS based cards"
depends on MANTIS_CORE && DVB_CORE && PCI && I2C
- select DVB_MB86A16
- select DVB_ZL10353
- select DVB_STV0299
+ select DVB_MB86A16 if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select DVB_STV0299 if !DVB_FE_CUSTOMISE
+ select DVB_LNBP21 if !DVB_FE_CUSTOMISE
+ select DVB_STB0899 if !DVB_FE_CUSTOMISE
+ select DVB_STB6100 if !DVB_FE_CUSTOMISE
+ select DVB_TDA665x if !DVB_FE_CUSTOMISE
+ select DVB_TDA10021 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_PLL
help
Support for PCI cards based on the Mantis PCI bridge.
@@ -23,7 +29,7 @@ config DVB_MANTIS
config DVB_HOPPER
tristate "HOPPER based cards"
depends on MANTIS_CORE && DVB_CORE && PCI && I2C
- select DVB_ZL10353
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_PLL
help
Support for PCI cards based on the Hopper PCI bridge.
diff --git a/drivers/media/dvb/mantis/hopper_cards.c b/drivers/media/dvb/mantis/hopper_cards.c
index 09e9fc785189..70e73afefb3d 100644
--- a/drivers/media/dvb/mantis/hopper_cards.c
+++ b/drivers/media/dvb/mantis/hopper_cards.c
@@ -251,6 +251,8 @@ static struct pci_device_id hopper_pci_table[] = {
{ }
};
+MODULE_DEVICE_TABLE(pci, hopper_pci_table);
+
static struct pci_driver hopper_pci_driver = {
.name = DRIVER_NAME,
.id_table = hopper_pci_table,
diff --git a/drivers/media/dvb/mantis/hopper_vp3028.c b/drivers/media/dvb/mantis/hopper_vp3028.c
index 96674c78e86b..68a29f8bdf73 100644
--- a/drivers/media/dvb/mantis/hopper_vp3028.c
+++ b/drivers/media/dvb/mantis/hopper_vp3028.c
@@ -47,17 +47,17 @@ static int vp3028_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
struct mantis_hwconfig *config = mantis->hwconfig;
int err = 0;
- gpio_set_bits(mantis, config->reset, 0);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
msleep(100);
err = mantis_frontend_power(mantis, POWER_ON);
msleep(100);
- gpio_set_bits(mantis, config->reset, 1);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
err = mantis_frontend_power(mantis, POWER_ON);
if (err == 0) {
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
- fe = zl10353_attach(&hopper_vp3028_config, adapter);
+ fe = dvb_attach(zl10353_attach, &hopper_vp3028_config, adapter);
if (!fe)
return -1;
diff --git a/drivers/media/dvb/mantis/mantis_cards.c b/drivers/media/dvb/mantis/mantis_cards.c
index cf4b39ffdaad..40da225098cc 100644
--- a/drivers/media/dvb/mantis/mantis_cards.c
+++ b/drivers/media/dvb/mantis/mantis_cards.c
@@ -281,6 +281,8 @@ static struct pci_device_id mantis_pci_table[] = {
{ }
};
+MODULE_DEVICE_TABLE(pci, mantis_pci_table);
+
static struct pci_driver mantis_pci_driver = {
.name = DRIVER_NAME,
.id_table = mantis_pci_table,
diff --git a/drivers/media/dvb/mantis/mantis_common.h b/drivers/media/dvb/mantis/mantis_common.h
index d0b645a483c9..bd400d21b81f 100644
--- a/drivers/media/dvb/mantis/mantis_common.h
+++ b/drivers/media/dvb/mantis/mantis_common.h
@@ -171,7 +171,9 @@ struct mantis_pci {
struct work_struct uart_work;
spinlock_t uart_lock;
- struct input_dev *rc;
+ struct rc_dev *rc;
+ char input_name[80];
+ char input_phys[80];
};
#define MANTIS_HIF_STATUS (mantis->gpio_status)
diff --git a/drivers/media/dvb/mantis/mantis_core.c b/drivers/media/dvb/mantis/mantis_core.c
index 8113b23ce448..22524a8e6f61 100644
--- a/drivers/media/dvb/mantis/mantis_core.c
+++ b/drivers/media/dvb/mantis/mantis_core.c
@@ -91,10 +91,7 @@ static int get_mac_address(struct mantis_pci *mantis)
return err;
}
dprintk(verbose, MANTIS_ERROR, 0,
- " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
- mantis->mac_address[0], mantis->mac_address[1],
- mantis->mac_address[2], mantis->mac_address[3],
- mantis->mac_address[4], mantis->mac_address[5]);
+ " MAC Address=[%pM]\n", mantis->mac_address);
return 0;
}
diff --git a/drivers/media/dvb/mantis/mantis_dvb.c b/drivers/media/dvb/mantis/mantis_dvb.c
index 99d82eec3b03..e5180e45d310 100644
--- a/drivers/media/dvb/mantis/mantis_dvb.c
+++ b/drivers/media/dvb/mantis/mantis_dvb.c
@@ -47,15 +47,15 @@ int mantis_frontend_power(struct mantis_pci *mantis, enum mantis_power power)
switch (power) {
case POWER_ON:
dprintk(MANTIS_DEBUG, 1, "Power ON");
- gpio_set_bits(mantis, config->power, POWER_ON);
+ mantis_gpio_set_bits(mantis, config->power, POWER_ON);
msleep(100);
- gpio_set_bits(mantis, config->power, POWER_ON);
+ mantis_gpio_set_bits(mantis, config->power, POWER_ON);
msleep(100);
break;
case POWER_OFF:
dprintk(MANTIS_DEBUG, 1, "Power OFF");
- gpio_set_bits(mantis, config->power, POWER_OFF);
+ mantis_gpio_set_bits(mantis, config->power, POWER_OFF);
msleep(100);
break;
@@ -73,13 +73,13 @@ void mantis_frontend_soft_reset(struct mantis_pci *mantis)
struct mantis_hwconfig *config = mantis->hwconfig;
dprintk(MANTIS_DEBUG, 1, "Frontend RESET");
- gpio_set_bits(mantis, config->reset, 0);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
msleep(100);
- gpio_set_bits(mantis, config->reset, 0);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
msleep(100);
- gpio_set_bits(mantis, config->reset, 1);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
msleep(100);
- gpio_set_bits(mantis, config->reset, 1);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
msleep(100);
return;
@@ -117,6 +117,7 @@ static int mantis_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
if (mantis->feeds == 1) {
dprintk(MANTIS_DEBUG, 1, "mantis start feed & dma");
mantis_dma_start(mantis);
+ tasklet_enable(&mantis->tasklet);
}
return mantis->feeds;
@@ -136,6 +137,7 @@ static int mantis_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
mantis->feeds--;
if (mantis->feeds == 0) {
dprintk(MANTIS_DEBUG, 1, "mantis stop feed and dma");
+ tasklet_disable(&mantis->tasklet);
mantis_dma_stop(mantis);
}
@@ -216,6 +218,7 @@ int __devinit mantis_dvb_init(struct mantis_pci *mantis)
dvb_net_init(&mantis->dvb_adapter, &mantis->dvbnet, &mantis->demux.dmx);
tasklet_init(&mantis->tasklet, mantis_dma_xfer, (unsigned long) mantis);
+ tasklet_disable(&mantis->tasklet);
if (mantis->hwconfig) {
result = config->frontend_init(mantis, mantis->fe);
if (result < 0) {
diff --git a/drivers/media/dvb/mantis/mantis_evm.c b/drivers/media/dvb/mantis/mantis_evm.c
index a7b369a439d6..9f73c2cfc9ea 100644
--- a/drivers/media/dvb/mantis/mantis_evm.c
+++ b/drivers/media/dvb/mantis/mantis_evm.c
@@ -111,7 +111,7 @@ void mantis_evmgr_exit(struct mantis_ca *ca)
struct mantis_pci *mantis = ca->ca_priv;
dprintk(MANTIS_DEBUG, 1, "Mantis Host I/F Event manager exiting");
- flush_scheduled_work();
+ flush_work_sync(&ca->hif_evm_work);
mantis_hif_exit(ca);
mantis_pcmcia_exit(ca);
}
diff --git a/drivers/media/dvb/mantis/mantis_i2c.c b/drivers/media/dvb/mantis/mantis_i2c.c
index 7870bcf9689a..e7794517fe26 100644
--- a/drivers/media/dvb/mantis/mantis_i2c.c
+++ b/drivers/media/dvb/mantis/mantis_i2c.c
@@ -229,7 +229,6 @@ int __devinit mantis_i2c_init(struct mantis_pci *mantis)
i2c_set_adapdata(i2c_adapter, mantis);
i2c_adapter->owner = THIS_MODULE;
- i2c_adapter->class = I2C_CLASS_TV_DIGITAL;
i2c_adapter->algo = &mantis_algo;
i2c_adapter->algo_data = NULL;
i2c_adapter->timeout = 500;
diff --git a/drivers/media/dvb/mantis/mantis_input.c b/drivers/media/dvb/mantis/mantis_input.c
index 3d4e4663220c..db6d54d3fec0 100644
--- a/drivers/media/dvb/mantis/mantis_input.c
+++ b/drivers/media/dvb/mantis/mantis_input.c
@@ -18,8 +18,7 @@
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
-#include <linux/input.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#include <linux/pci.h>
#include "dmxdev.h"
@@ -33,8 +32,9 @@
#include "mantis_uart.h"
#define MODULE_NAME "mantis_core"
+#define RC_MAP_MANTIS "rc-mantis"
-static struct ir_scancode mantis_ir_table[] = {
+static struct rc_map_table mantis_ir_table[] = {
{ 0x29, KEY_POWER },
{ 0x28, KEY_FAVORITES },
{ 0x30, KEY_TEXT },
@@ -95,56 +95,65 @@ static struct ir_scancode mantis_ir_table[] = {
{ 0x00, KEY_BLUE },
};
-struct ir_scancode_table ir_mantis = {
- .scan = mantis_ir_table,
- .size = ARRAY_SIZE(mantis_ir_table),
+static struct rc_map_list ir_mantis_map = {
+ .map = {
+ .scan = mantis_ir_table,
+ .size = ARRAY_SIZE(mantis_ir_table),
+ .rc_type = RC_TYPE_UNKNOWN,
+ .name = RC_MAP_MANTIS,
+ }
};
-EXPORT_SYMBOL_GPL(ir_mantis);
int mantis_input_init(struct mantis_pci *mantis)
{
- struct input_dev *rc;
- struct ir_input_state rc_state;
- char name[80], dev[80];
+ struct rc_dev *dev;
int err;
- rc = input_allocate_device();
- if (!rc) {
- dprintk(MANTIS_ERROR, 1, "Input device allocate failed");
- return -ENOMEM;
- }
-
- sprintf(name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
- sprintf(dev, "pci-%s/ir0", pci_name(mantis->pdev));
+ err = rc_map_register(&ir_mantis_map);
+ if (err)
+ goto out;
- rc->name = name;
- rc->phys = dev;
+ dev = rc_allocate_device();
+ if (!dev) {
+ dprintk(MANTIS_ERROR, 1, "Remote device allocation failed");
+ err = -ENOMEM;
+ goto out_map;
+ }
- ir_input_init(rc, &rc_state, IR_TYPE_OTHER);
+ sprintf(mantis->input_name, "Mantis %s IR receiver", mantis->hwconfig->model_name);
+ sprintf(mantis->input_phys, "pci-%s/ir0", pci_name(mantis->pdev));
- rc->id.bustype = BUS_PCI;
- rc->id.vendor = mantis->vendor_id;
- rc->id.product = mantis->device_id;
- rc->id.version = 1;
- rc->dev = mantis->pdev->dev;
+ dev->input_name = mantis->input_name;
+ dev->input_phys = mantis->input_phys;
+ dev->input_id.bustype = BUS_PCI;
+ dev->input_id.vendor = mantis->vendor_id;
+ dev->input_id.product = mantis->device_id;
+ dev->input_id.version = 1;
+ dev->driver_name = MODULE_NAME;
+ dev->map_name = RC_MAP_MANTIS;
+ dev->dev.parent = &mantis->pdev->dev;
- err = __ir_input_register(rc, &ir_mantis, NULL, MODULE_NAME);
+ err = rc_register_device(dev);
if (err) {
dprintk(MANTIS_ERROR, 1, "IR device registration failed, ret = %d", err);
- input_free_device(rc);
- return -ENODEV;
+ goto out_dev;
}
- mantis->rc = rc;
-
+ mantis->rc = dev;
return 0;
+
+out_dev:
+ rc_free_device(dev);
+out_map:
+ rc_map_unregister(&ir_mantis_map);
+out:
+ return err;
}
int mantis_exit(struct mantis_pci *mantis)
{
- struct input_dev *rc = mantis->rc;
-
- ir_input_unregister(rc);
-
+ rc_unregister_device(mantis->rc);
+ rc_map_unregister(&ir_mantis_map);
return 0;
}
+
diff --git a/drivers/media/dvb/mantis/mantis_ioc.c b/drivers/media/dvb/mantis/mantis_ioc.c
index de148ded52d8..479086dbb9a8 100644
--- a/drivers/media/dvb/mantis/mantis_ioc.c
+++ b/drivers/media/dvb/mantis/mantis_ioc.c
@@ -68,21 +68,14 @@ int mantis_get_mac(struct mantis_pci *mantis)
return err;
}
- dprintk(MANTIS_ERROR, 0,
- " MAC Address=[%02x:%02x:%02x:%02x:%02x:%02x]\n",
- mac_addr[0],
- mac_addr[1],
- mac_addr[2],
- mac_addr[3],
- mac_addr[4],
- mac_addr[5]);
+ dprintk(MANTIS_ERROR, 0, " MAC Address=[%pM]\n", mac_addr);
return 0;
}
EXPORT_SYMBOL_GPL(mantis_get_mac);
/* Turn the given bit on or off. */
-void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
+void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
{
u32 cur;
@@ -97,7 +90,7 @@ void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value)
mmwrite(mantis->gpio_status, MANTIS_GPIF_ADDR);
mmwrite(0x00, MANTIS_GPIF_DOUT);
}
-EXPORT_SYMBOL_GPL(gpio_set_bits);
+EXPORT_SYMBOL_GPL(mantis_gpio_set_bits);
int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl)
{
diff --git a/drivers/media/dvb/mantis/mantis_ioc.h b/drivers/media/dvb/mantis/mantis_ioc.h
index 188fe5a81614..d56e002b2955 100644
--- a/drivers/media/dvb/mantis/mantis_ioc.h
+++ b/drivers/media/dvb/mantis/mantis_ioc.h
@@ -44,7 +44,7 @@ enum mantis_stream_control {
};
extern int mantis_get_mac(struct mantis_pci *mantis);
-extern void gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
+extern void mantis_gpio_set_bits(struct mantis_pci *mantis, u32 bitpos, u8 value);
extern int mantis_stream_control(struct mantis_pci *mantis, enum mantis_stream_control stream_ctl);
diff --git a/drivers/media/dvb/mantis/mantis_uart.c b/drivers/media/dvb/mantis/mantis_uart.c
index 7d2f2398fa8b..97b889e8a341 100644
--- a/drivers/media/dvb/mantis/mantis_uart.c
+++ b/drivers/media/dvb/mantis/mantis_uart.c
@@ -182,5 +182,6 @@ void mantis_uart_exit(struct mantis_pci *mantis)
{
/* disable interrupt */
mmwrite(mmread(MANTIS_UART_CTL) & 0xffef, MANTIS_UART_CTL);
+ flush_work_sync(&mantis->uart_work);
}
EXPORT_SYMBOL_GPL(mantis_uart_exit);
diff --git a/drivers/media/dvb/mantis/mantis_vp1033.c b/drivers/media/dvb/mantis/mantis_vp1033.c
index 4a723bda0031..deec927c7f7a 100644
--- a/drivers/media/dvb/mantis/mantis_vp1033.c
+++ b/drivers/media/dvb/mantis/mantis_vp1033.c
@@ -173,7 +173,7 @@ static int vp1033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for STV0299 (DVB-S)");
- fe = stv0299_attach(&lgtdqcs001f_config, adapter);
+ fe = dvb_attach(stv0299_attach, &lgtdqcs001f_config, adapter);
if (fe) {
fe->ops.tuner_ops.set_params = lgtdqcs001f_tuner_set;
diff --git a/drivers/media/dvb/mantis/mantis_vp1034.c b/drivers/media/dvb/mantis/mantis_vp1034.c
index 8e6ae558ee57..26bc0cbe84d4 100644
--- a/drivers/media/dvb/mantis/mantis_vp1034.c
+++ b/drivers/media/dvb/mantis/mantis_vp1034.c
@@ -50,13 +50,13 @@ int vp1034_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
switch (voltage) {
case SEC_VOLTAGE_13:
dprintk(MANTIS_ERROR, 1, "Polarization=[13V]");
- gpio_set_bits(mantis, 13, 1);
- gpio_set_bits(mantis, 14, 0);
+ mantis_gpio_set_bits(mantis, 13, 1);
+ mantis_gpio_set_bits(mantis, 14, 0);
break;
case SEC_VOLTAGE_18:
dprintk(MANTIS_ERROR, 1, "Polarization=[18V]");
- gpio_set_bits(mantis, 13, 1);
- gpio_set_bits(mantis, 14, 1);
+ mantis_gpio_set_bits(mantis, 13, 1);
+ mantis_gpio_set_bits(mantis, 14, 1);
break;
case SEC_VOLTAGE_OFF:
dprintk(MANTIS_ERROR, 1, "Frontend (dummy) POWERDOWN");
@@ -82,7 +82,7 @@ static int vp1034_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for MB86A16 (DVB-S/DSS)");
- fe = mb86a16_attach(&vp1034_mb86a16_config, adapter);
+ fe = dvb_attach(mb86a16_attach, &vp1034_mb86a16_config, adapter);
if (fe) {
dprintk(MANTIS_ERROR, 1,
"found MB86A16 DVB-S/DSS frontend @0x%02x",
diff --git a/drivers/media/dvb/mantis/mantis_vp1041.c b/drivers/media/dvb/mantis/mantis_vp1041.c
index d1aa2bc0c155..38a436ca2fdf 100644
--- a/drivers/media/dvb/mantis/mantis_vp1041.c
+++ b/drivers/media/dvb/mantis/mantis_vp1041.c
@@ -316,14 +316,14 @@ static int vp1041_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
if (err == 0) {
mantis_frontend_soft_reset(mantis);
msleep(250);
- mantis->fe = stb0899_attach(&vp1041_stb0899_config, adapter);
+ mantis->fe = dvb_attach(stb0899_attach, &vp1041_stb0899_config, adapter);
if (mantis->fe) {
dprintk(MANTIS_ERROR, 1,
"found STB0899 DVB-S/DVB-S2 frontend @0x%02x",
vp1041_stb0899_config.demod_address);
- if (stb6100_attach(mantis->fe, &vp1041_stb6100_config, adapter)) {
- if (!lnbp21_attach(mantis->fe, adapter, 0, 0))
+ if (dvb_attach(stb6100_attach, mantis->fe, &vp1041_stb6100_config, adapter)) {
+ if (!dvb_attach(lnbp21_attach, mantis->fe, adapter, 0, 0))
dprintk(MANTIS_ERROR, 1, "No LNBP21 found!");
}
} else {
diff --git a/drivers/media/dvb/mantis/mantis_vp2033.c b/drivers/media/dvb/mantis/mantis_vp2033.c
index 10ce81790a8c..06da0ddf05a7 100644
--- a/drivers/media/dvb/mantis/mantis_vp2033.c
+++ b/drivers/media/dvb/mantis/mantis_vp2033.c
@@ -132,7 +132,7 @@ static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
- fe = tda10021_attach(&vp2033_tda1002x_cu1216_config,
+ fe = dvb_attach(tda10021_attach, &vp2033_tda1002x_cu1216_config,
adapter,
read_pwm(mantis));
@@ -141,7 +141,7 @@ static int vp2033_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
vp2033_tda1002x_cu1216_config.demod_address);
} else {
- fe = tda10023_attach(&vp2033_tda10023_cu1216_config,
+ fe = dvb_attach(tda10023_attach, &vp2033_tda10023_cu1216_config,
adapter,
read_pwm(mantis));
diff --git a/drivers/media/dvb/mantis/mantis_vp2040.c b/drivers/media/dvb/mantis/mantis_vp2040.c
index a7ca233e800b..f72b137b7652 100644
--- a/drivers/media/dvb/mantis/mantis_vp2040.c
+++ b/drivers/media/dvb/mantis/mantis_vp2040.c
@@ -132,7 +132,7 @@ static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for CU1216 (DVB-C)");
- fe = tda10021_attach(&vp2040_tda1002x_cu1216_config,
+ fe = dvb_attach(tda10021_attach, &vp2040_tda1002x_cu1216_config,
adapter,
read_pwm(mantis));
@@ -141,7 +141,7 @@ static int vp2040_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
"found Philips CU1216 DVB-C frontend (TDA10021) @ 0x%02x",
vp2040_tda1002x_cu1216_config.demod_address);
} else {
- fe = tda10023_attach(&vp2040_tda10023_cu1216_config,
+ fe = dvb_attach(tda10023_attach, &vp2040_tda10023_cu1216_config,
adapter,
read_pwm(mantis));
diff --git a/drivers/media/dvb/mantis/mantis_vp3030.c b/drivers/media/dvb/mantis/mantis_vp3030.c
index 1f4334214953..c09308cd3ac6 100644
--- a/drivers/media/dvb/mantis/mantis_vp3030.c
+++ b/drivers/media/dvb/mantis/mantis_vp3030.c
@@ -59,21 +59,21 @@ static int vp3030_frontend_init(struct mantis_pci *mantis, struct dvb_frontend *
struct mantis_hwconfig *config = mantis->hwconfig;
int err = 0;
- gpio_set_bits(mantis, config->reset, 0);
+ mantis_gpio_set_bits(mantis, config->reset, 0);
msleep(100);
err = mantis_frontend_power(mantis, POWER_ON);
msleep(100);
- gpio_set_bits(mantis, config->reset, 1);
+ mantis_gpio_set_bits(mantis, config->reset, 1);
if (err == 0) {
msleep(250);
dprintk(MANTIS_ERROR, 1, "Probing for 10353 (DVB-T)");
- fe = zl10353_attach(&mantis_vp3030_config, adapter);
+ fe = dvb_attach(zl10353_attach, &mantis_vp3030_config, adapter);
if (!fe)
return -1;
- tda665x_attach(fe, &env57h12d5_config, adapter);
+ dvb_attach(tda665x_attach, fe, &env57h12d5_config, adapter);
} else {
dprintk(MANTIS_ERROR, 1, "Frontend on <%s> POWER ON failed! <%d>",
adapter->name,
diff --git a/drivers/media/dvb/ngene/ngene-cards.c b/drivers/media/dvb/ngene/ngene-cards.c
index 692c3e226e83..4692a41ad95b 100644
--- a/drivers/media/dvb/ngene/ngene-cards.c
+++ b/drivers/media/dvb/ngene/ngene-cards.c
@@ -217,6 +217,19 @@ static struct ngene_info ngene_info_cineS2v5 = {
.fw_version = 15,
};
+static struct ngene_info ngene_info_duoFlexS2 = {
+ .type = NGENE_SIDEWINDER,
+ .name = "Digital Devices DuoFlex S2 miniPCIe",
+ .io_type = {NGENE_IO_TSIN, NGENE_IO_TSIN},
+ .demod_attach = {demod_attach_stv0900, demod_attach_stv0900},
+ .tuner_attach = {tuner_attach_stv6110, tuner_attach_stv6110},
+ .fe_config = {&fe_cineS2, &fe_cineS2},
+ .tuner_config = {&tuner_cineS2_0, &tuner_cineS2_1},
+ .lnb = {0x0a, 0x08},
+ .tsf = {3, 3},
+ .fw_version = 15,
+};
+
static struct ngene_info ngene_info_m780 = {
.type = NGENE_APP,
.name = "Aver M780 ATSC/QAM-B",
@@ -256,6 +269,8 @@ static const struct pci_device_id ngene_id_tbl[] __devinitdata = {
NGENE_ID(0x18c3, 0xdb01, ngene_info_satixS2),
NGENE_ID(0x18c3, 0xdb02, ngene_info_satixS2v2),
NGENE_ID(0x18c3, 0xdd00, ngene_info_cineS2v5),
+ NGENE_ID(0x18c3, 0xdd10, ngene_info_duoFlexS2),
+ NGENE_ID(0x18c3, 0xdd20, ngene_info_duoFlexS2),
NGENE_ID(0x1461, 0x062e, ngene_info_m780),
{0}
};
diff --git a/drivers/media/dvb/ngene/ngene-core.c b/drivers/media/dvb/ngene/ngene-core.c
index c8b4dfa0ab5f..dc073bdc623a 100644
--- a/drivers/media/dvb/ngene/ngene-core.c
+++ b/drivers/media/dvb/ngene/ngene-core.c
@@ -34,7 +34,6 @@
#include <linux/io.h>
#include <asm/div64.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
@@ -53,8 +52,6 @@ MODULE_PARM_DESC(debug, "Print debugging information.");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
-#define COMMAND_TIMEOUT_WORKAROUND
-
#define dprintk if (debug) printk
#define ngwriteb(dat, adr) writeb((dat), (char *)(dev->iomem + (adr)))
@@ -147,24 +144,24 @@ static void demux_tasklet(unsigned long data)
} else {
if (chan->HWState == HWSTATE_RUN) {
u32 Flags = 0;
+ IBufferExchange *exch1 = chan->pBufferExchange;
+ IBufferExchange *exch2 = chan->pBufferExchange2;
if (Cur->ngeneBuffer.SR.Flags & 0x01)
Flags |= BEF_EVEN_FIELD;
if (Cur->ngeneBuffer.SR.Flags & 0x20)
Flags |= BEF_OVERFLOW;
- if (chan->pBufferExchange)
- chan->pBufferExchange(chan,
- Cur->Buffer1,
- chan->
- Capture1Length,
- Cur->ngeneBuffer.
- SR.Clock, Flags);
- if (chan->pBufferExchange2)
- chan->pBufferExchange2(chan,
- Cur->Buffer2,
- chan->
- Capture2Length,
- Cur->ngeneBuffer.
- SR.Clock, Flags);
+ spin_unlock_irq(&chan->state_lock);
+ if (exch1)
+ exch1(chan, Cur->Buffer1,
+ chan->Capture1Length,
+ Cur->ngeneBuffer.SR.Clock,
+ Flags);
+ if (exch2)
+ exch2(chan, Cur->Buffer2,
+ chan->Capture2Length,
+ Cur->ngeneBuffer.SR.Clock,
+ Flags);
+ spin_lock_irq(&chan->state_lock);
} else if (chan->HWState != HWSTATE_STOP)
chan->HWState = HWSTATE_RUN;
}
@@ -572,11 +569,7 @@ static int ngene_command_stream_control(struct ngene *dev, u8 stream,
u16 BsSPI = ((stream & 1) ? 0x9800 : 0x9700);
u16 BsSDO = 0x9B00;
- /* down(&dev->stream_mutex); */
- while (down_trylock(&dev->stream_mutex)) {
- printk(KERN_INFO DEVICE_NAME ": SC locked\n");
- msleep(1);
- }
+ down(&dev->stream_mutex);
memset(&com, 0, sizeof(com));
com.cmd.hdr.Opcode = CMD_CONTROL;
com.cmd.hdr.Length = sizeof(struct FW_STREAM_CONTROL) - 2;
@@ -1252,14 +1245,17 @@ static int ngene_load_firm(struct ngene *dev)
version = 15;
size = 23466;
fw_name = "ngene_15.fw";
+ dev->cmd_timeout_workaround = true;
break;
case 16:
size = 23498;
fw_name = "ngene_16.fw";
+ dev->cmd_timeout_workaround = true;
break;
case 17:
size = 24446;
fw_name = "ngene_17.fw";
+ dev->cmd_timeout_workaround = true;
break;
}
@@ -1299,6 +1295,10 @@ static void ngene_stop(struct ngene *dev)
ngwritel(0, NGENE_EVENT);
ngwritel(0, NGENE_EVENT_HI);
free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+ if (dev->msi_enabled)
+ pci_disable_msi(dev->pci_dev);
+#endif
}
static int ngene_start(struct ngene *dev)
@@ -1333,6 +1333,30 @@ static int ngene_start(struct ngene *dev)
if (stat < 0)
goto fail;
+#ifdef CONFIG_PCI_MSI
+ /* enable MSI if kernel and card support it */
+ if (pci_msi_enabled() && dev->card_info->msi_supported) {
+ unsigned long flags;
+
+ ngwritel(0, NGENE_INT_ENABLE);
+ free_irq(dev->pci_dev->irq, dev);
+ stat = pci_enable_msi(dev->pci_dev);
+ if (stat) {
+ printk(KERN_INFO DEVICE_NAME
+ ": MSI not available\n");
+ flags = IRQF_SHARED;
+ } else {
+ flags = 0;
+ dev->msi_enabled = true;
+ }
+ stat = request_irq(dev->pci_dev->irq, irq_handler,
+ flags, "nGene", dev);
+ if (stat < 0)
+ goto fail2;
+ ngwritel(1, NGENE_INT_ENABLE);
+ }
+#endif
+
stat = ngene_i2c_init(dev, 0);
if (stat < 0)
goto fail;
@@ -1358,10 +1382,18 @@ static int ngene_start(struct ngene *dev)
bconf = BUFFER_CONFIG_3333;
stat = ngene_command_config_buf(dev, bconf);
}
- return stat;
+ if (!stat)
+ return stat;
+
+ /* otherwise error: fall through */
fail:
ngwritel(0, NGENE_INT_ENABLE);
free_irq(dev->pci_dev->irq, dev);
+#ifdef CONFIG_PCI_MSI
+fail2:
+ if (dev->msi_enabled)
+ pci_disable_msi(dev->pci_dev);
+#endif
return stat;
}
@@ -1379,10 +1411,8 @@ static void release_channel(struct ngene_channel *chan)
struct ngene_info *ni = dev->card_info;
int io = ni->io_type[chan->number];
-#ifdef COMMAND_TIMEOUT_WORKAROUND
- if (chan->running)
+ if (chan->dev->cmd_timeout_workaround && chan->running)
set_transfer(chan, 0);
-#endif
tasklet_kill(&chan->demux_tasklet);
@@ -1486,7 +1516,7 @@ static int init_channels(struct ngene *dev)
void __devexit ngene_remove(struct pci_dev *pdev)
{
- struct ngene *dev = (struct ngene *)pci_get_drvdata(pdev);
+ struct ngene *dev = pci_get_drvdata(pdev);
int i;
tasklet_kill(&dev->event_tasklet);
@@ -1507,12 +1537,11 @@ int __devinit ngene_probe(struct pci_dev *pci_dev,
if (pci_enable_device(pci_dev) < 0)
return -ENODEV;
- dev = vmalloc(sizeof(struct ngene));
+ dev = vzalloc(sizeof(struct ngene));
if (dev == NULL) {
stat = -ENOMEM;
goto fail0;
}
- memset(dev, 0, sizeof(struct ngene));
dev->pci_dev = pci_dev;
dev->card_info = (struct ngene_info *)id->driver_data;
diff --git a/drivers/media/dvb/ngene/ngene-dvb.c b/drivers/media/dvb/ngene/ngene-dvb.c
index 96013eb353cd..3832e5983c19 100644
--- a/drivers/media/dvb/ngene/ngene-dvb.c
+++ b/drivers/media/dvb/ngene/ngene-dvb.c
@@ -35,17 +35,13 @@
#include <linux/io.h>
#include <asm/div64.h>
#include <linux/pci.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
-#include <linux/version.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
#include "ngene.h"
-#define COMMAND_TIMEOUT_WORKAROUND
-
/****************************************************************************/
/* COMMAND API interface ****************************************************/
@@ -69,9 +65,7 @@ void *tsin_exchange(void *priv, void *buf, u32 len, u32 clock, u32 flags)
struct ngene_channel *chan = priv;
-#ifdef COMMAND_TIMEOUT_WORKAROUND
if (chan->users > 0)
-#endif
dvb_dmx_swfilter(&chan->demux, buf, len);
return NULL;
}
@@ -106,11 +100,8 @@ int ngene_start_feed(struct dvb_demux_feed *dvbdmxfeed)
struct ngene_channel *chan = dvbdmx->priv;
if (chan->users == 0) {
-#ifdef COMMAND_TIMEOUT_WORKAROUND
- if (!chan->running)
-#endif
+ if (!chan->dev->cmd_timeout_workaround || !chan->running)
set_transfer(chan, 1);
- /* msleep(10); */
}
return ++chan->users;
@@ -124,9 +115,8 @@ int ngene_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
if (--chan->users)
return chan->users;
-#ifndef COMMAND_TIMEOUT_WORKAROUND
- set_transfer(chan, 0);
-#endif
+ if (!chan->dev->cmd_timeout_workaround)
+ set_transfer(chan, 0);
return 0;
}
diff --git a/drivers/media/dvb/ngene/ngene-i2c.c b/drivers/media/dvb/ngene/ngene-i2c.c
index 2ef54ca6badd..d28554f8ce99 100644
--- a/drivers/media/dvb/ngene/ngene-i2c.c
+++ b/drivers/media/dvb/ngene/ngene-i2c.c
@@ -37,9 +37,7 @@
#include <asm/div64.h>
#include <linux/pci.h>
#include <linux/pci_ids.h>
-#include <linux/smp_lock.h>
#include <linux/timer.h>
-#include <linux/version.h>
#include <linux/byteorder/generic.h>
#include <linux/firmware.h>
#include <linux/vmalloc.h>
@@ -166,7 +164,6 @@ int ngene_i2c_init(struct ngene *dev, int dev_nr)
struct i2c_adapter *adap = &(dev->channel[dev_nr].i2c_adapter);
i2c_set_adapdata(adap, &(dev->channel[dev_nr]));
- adap->class = I2C_CLASS_TV_DIGITAL | I2C_CLASS_TV_ANALOG;
strcpy(adap->name, "nGene");
diff --git a/drivers/media/dvb/ngene/ngene.h b/drivers/media/dvb/ngene/ngene.h
index 676fcbb79026..8fb4200f83f8 100644
--- a/drivers/media/dvb/ngene/ngene.h
+++ b/drivers/media/dvb/ngene/ngene.h
@@ -725,6 +725,8 @@ struct ngene {
u32 device_version;
u32 fw_interface_version;
u32 icounts;
+ bool msi_enabled;
+ bool cmd_timeout_workaround;
u8 *CmdDoneByte;
int BootFirmware;
@@ -797,6 +799,7 @@ struct ngene_info {
#define NGENE_VBOX_V2 7
int fw_version;
+ bool msi_supported;
char *name;
int io_type[MAX_STREAM];
diff --git a/drivers/media/dvb/pluto2/pluto2.c b/drivers/media/dvb/pluto2/pluto2.c
index 1c798219dc7c..6ca6713d527a 100644
--- a/drivers/media/dvb/pluto2/pluto2.c
+++ b/drivers/media/dvb/pluto2/pluto2.c
@@ -647,7 +647,6 @@ static int __devinit pluto2_probe(struct pci_dev *pdev,
i2c_set_adapdata(&pluto->i2c_adap, pluto);
strcpy(pluto->i2c_adap.name, DRIVER_NAME);
pluto->i2c_adap.owner = THIS_MODULE;
- pluto->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
pluto->i2c_adap.dev.parent = &pdev->dev;
pluto->i2c_adap.algo_data = &pluto->i2c_bit;
pluto->i2c_bit.data = pluto;
diff --git a/drivers/media/dvb/pt1/pt1.c b/drivers/media/dvb/pt1/pt1.c
index 69ad94934ec2..0486919c1d0f 100644
--- a/drivers/media/dvb/pt1/pt1.c
+++ b/drivers/media/dvb/pt1/pt1.c
@@ -1087,7 +1087,6 @@ pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
pt1_update_power(pt1);
i2c_adap = &pt1->i2c_adap;
- i2c_adap->class = I2C_CLASS_TV_DIGITAL;
i2c_adap->algo = &pt1_i2c_algo;
i2c_adap->algo_data = NULL;
i2c_adap->dev.parent = &pdev->dev;
diff --git a/drivers/media/dvb/siano/Kconfig b/drivers/media/dvb/siano/Kconfig
index 85a222c4eaa0..bc6456eb2c4f 100644
--- a/drivers/media/dvb/siano/Kconfig
+++ b/drivers/media/dvb/siano/Kconfig
@@ -4,7 +4,7 @@
config SMS_SIANO_MDTV
tristate "Siano SMS1xxx based MDTV receiver"
- depends on DVB_CORE && INPUT && HAS_DMA
+ depends on DVB_CORE && RC_CORE && HAS_DMA
---help---
Choose Y or M here if you have MDTV receiver with a Siano chipset.
diff --git a/drivers/media/dvb/siano/sms-cards.c b/drivers/media/dvb/siano/sms-cards.c
index cff77e2eb557..25b43e587fa6 100644
--- a/drivers/media/dvb/siano/sms-cards.c
+++ b/drivers/media/dvb/siano/sms-cards.c
@@ -64,9 +64,11 @@ static struct sms_board sms_boards[] = {
.type = SMS_NOVA_B0,
.fw[DEVICE_MODE_ISDBT_BDA] = "sms1xxx-hcw-55xxx-isdbt-02.fw",
.fw[DEVICE_MODE_DVBT_BDA] = "sms1xxx-hcw-55xxx-dvbt-02.fw",
+ .rc_codes = RC_MAP_RC5_HAUPPAUGE_NEW,
.board_cfg.leds_power = 26,
.board_cfg.led0 = 27,
.board_cfg.led1 = 28,
+ .board_cfg.ir = 9,
.led_power = 26,
.led_lo = 27,
.led_hi = 28,
diff --git a/drivers/media/dvb/siano/sms-cards.h b/drivers/media/dvb/siano/sms-cards.h
index 8f19fc000b46..d8cdf756f7cf 100644
--- a/drivers/media/dvb/siano/sms-cards.h
+++ b/drivers/media/dvb/siano/sms-cards.h
@@ -75,7 +75,7 @@ struct sms_board {
enum sms_device_type_st type;
char *name, *fw[DEVICE_MODE_MAX];
struct sms_board_gpio_cfg board_cfg;
- enum ir_kb_type ir_kb_type;
+ char *rc_codes; /* Name of IR codes table */
/* gpios */
int led_power, led_hi, led_lo, lna_ctrl, rf_switch;
diff --git a/drivers/media/dvb/siano/smscoreapi.c b/drivers/media/dvb/siano/smscoreapi.c
index 0c87a3c3899a..78765ed28063 100644
--- a/drivers/media/dvb/siano/smscoreapi.c
+++ b/drivers/media/dvb/siano/smscoreapi.c
@@ -116,9 +116,7 @@ static struct smscore_registry_entry_t *smscore_find_registry(char *devpath)
return entry;
}
}
- entry = (struct smscore_registry_entry_t *)
- kmalloc(sizeof(struct smscore_registry_entry_t),
- GFP_KERNEL);
+ entry = kmalloc(sizeof(struct smscore_registry_entry_t), GFP_KERNEL);
if (entry) {
entry->mode = default_mode;
strcpy(entry->devpath, devpath);
@@ -440,7 +438,7 @@ static int smscore_init_ir(struct smscore_device_t *coredev)
int rc;
void *buffer;
- coredev->ir.input_dev = NULL;
+ coredev->ir.dev = NULL;
ir_io = sms_get_board(smscore_get_board_id(coredev))->board_cfg.ir;
if (ir_io) {/* only if IR port exist we use IR sub-module */
sms_info("IR loading");
@@ -1100,31 +1098,26 @@ EXPORT_SYMBOL_GPL(smscore_onresponse);
*
* @return pointer to descriptor on success, NULL on error.
*/
-struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+
+struct smscore_buffer_t *get_entry(struct smscore_device_t *coredev)
{
struct smscore_buffer_t *cb = NULL;
unsigned long flags;
- DEFINE_WAIT(wait);
-
spin_lock_irqsave(&coredev->bufferslock, flags);
+ if (!list_empty(&coredev->buffers)) {
+ cb = (struct smscore_buffer_t *) coredev->buffers.next;
+ list_del(&cb->entry);
+ }
+ spin_unlock_irqrestore(&coredev->bufferslock, flags);
+ return cb;
+}
- /* This function must return a valid buffer, since the buffer list is
- * finite, we check that there is an available buffer, if not, we wait
- * until such buffer become available.
- */
-
- prepare_to_wait(&coredev->buffer_mng_waitq, &wait, TASK_INTERRUPTIBLE);
-
- if (list_empty(&coredev->buffers))
- schedule();
-
- finish_wait(&coredev->buffer_mng_waitq, &wait);
-
- cb = (struct smscore_buffer_t *) coredev->buffers.next;
- list_del(&cb->entry);
+struct smscore_buffer_t *smscore_getbuffer(struct smscore_device_t *coredev)
+{
+ struct smscore_buffer_t *cb = NULL;
- spin_unlock_irqrestore(&coredev->bufferslock, flags);
+ wait_event(coredev->buffer_mng_waitq, (cb = get_entry(coredev)));
return cb;
}
@@ -1297,7 +1290,7 @@ int smsclient_sendrequest(struct smscore_client_t *client,
EXPORT_SYMBOL_GPL(smsclient_sendrequest);
-/* old GPIO managments implementation */
+/* old GPIO managements implementation */
int smscore_configure_gpio(struct smscore_device_t *coredev, u32 pin,
struct smscore_config_gpio *pinconfig)
{
@@ -1511,8 +1504,7 @@ int smscore_gpio_set_level(struct smscore_device_t *coredev, u8 PinNum,
u32 msgData[3]; /* keep it 3 ! */
} *pMsg;
- if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER) ||
- (PinNum > MAX_GPIO_PIN_NUMBER))
+ if ((NewLevel > 1) || (PinNum > MAX_GPIO_PIN_NUMBER))
return -EINVAL;
totalLen = sizeof(struct SmsMsgHdr_ST) +
diff --git a/drivers/media/dvb/siano/smsir.c b/drivers/media/dvb/siano/smsir.c
index a56eac76e0f0..37bc5c4b8ad8 100644
--- a/drivers/media/dvb/siano/smsir.c
+++ b/drivers/media/dvb/siano/smsir.c
@@ -4,6 +4,11 @@
MDTV receiver kernel modules.
Copyright (C) 2006-2009, Uri Shkolnik
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+ - Ported the driver to use rc-core
+ - IR raw event decoding is now done at rc-core
+ - Code almost re-written
+
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
@@ -27,275 +32,83 @@
#include "smsir.h"
#include "sms-cards.h"
-/* In order to add new IR remote control -
- * 1) Add it to the <enum ir_kb_type> @ smsir,h,
- * 2) Add its map to keyboard_layout_maps below
- * 3) Set your board (sms-cards sub-module) to use it
- */
-
-static struct keyboard_layout_map_t keyboard_layout_maps[] = {
- [SMS_IR_KB_DEFAULT_TV] = {
- .ir_protocol = IR_RC5,
- .rc5_kbd_address = KEYBOARD_ADDRESS_TV1,
- .keyboard_layout_map = {
- KEY_0, KEY_1, KEY_2,
- KEY_3, KEY_4, KEY_5,
- KEY_6, KEY_7, KEY_8,
- KEY_9, 0, 0, KEY_POWER,
- KEY_MUTE, 0, 0,
- KEY_VOLUMEUP, KEY_VOLUMEDOWN,
- KEY_BRIGHTNESSUP,
- KEY_BRIGHTNESSDOWN, KEY_CHANNELUP,
- KEY_CHANNELDOWN,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
- }
- },
- [SMS_IR_KB_HCW_SILVER] = {
- .ir_protocol = IR_RC5,
- .rc5_kbd_address = KEYBOARD_ADDRESS_LIGHTING1,
- .keyboard_layout_map = {
- KEY_0, KEY_1, KEY_2,
- KEY_3, KEY_4, KEY_5,
- KEY_6, KEY_7, KEY_8,
- KEY_9, KEY_TEXT, KEY_RED,
- KEY_RADIO, KEY_MENU,
- KEY_SUBTITLE,
- KEY_MUTE, KEY_VOLUMEUP,
- KEY_VOLUMEDOWN, KEY_PREVIOUS, 0,
- KEY_UP, KEY_DOWN, KEY_LEFT,
- KEY_RIGHT, KEY_VIDEO, KEY_AUDIO,
- KEY_MHP, KEY_EPG, KEY_TV,
- 0, KEY_NEXTSONG, KEY_EXIT,
- KEY_CHANNELUP, KEY_CHANNELDOWN,
- KEY_CHANNEL, 0,
- KEY_PREVIOUSSONG, KEY_ENTER,
- KEY_SLEEP, 0, 0, KEY_BLUE,
- 0, 0, 0, 0, KEY_GREEN, 0,
- KEY_PAUSE, 0, KEY_REWIND,
- 0, KEY_FASTFORWARD, KEY_PLAY,
- KEY_STOP, KEY_RECORD,
- KEY_YELLOW, 0, 0, KEY_SELECT,
- KEY_ZOOM, KEY_POWER, 0, 0
- }
- },
- { } /* Terminating entry */
-};
-
-static u32 ir_pos;
-static u32 ir_word;
-static u32 ir_toggle;
-
-#define RC5_PUSH_BIT(dst, bit, pos) \
- { dst <<= 1; dst |= bit; pos++; }
-
-
-static void sms_ir_rc5_event(struct smscore_device_t *coredev,
- u32 toggle, u32 addr, u32 cmd)
-{
- bool toggle_changed;
- u16 keycode;
-
- sms_log("IR RC5 word: address %d, command %d, toggle %d",
- addr, cmd, toggle);
-
- toggle_changed = ir_toggle != toggle;
- /* keep toggle */
- ir_toggle = toggle;
-
- if (addr !=
- keyboard_layout_maps[coredev->ir.ir_kb_type].rc5_kbd_address)
- return; /* Check for valid address */
-
- keycode =
- keyboard_layout_maps
- [coredev->ir.ir_kb_type].keyboard_layout_map[cmd];
+#define MODULE_NAME "smsmdtv"
- if (!toggle_changed &&
- (keycode != KEY_VOLUMEUP && keycode != KEY_VOLUMEDOWN))
- return; /* accept only repeated volume, reject other keys */
-
- sms_log("kernel input keycode (from ir) %d", keycode);
- input_report_key(coredev->ir.input_dev, keycode, 1);
- input_sync(coredev->ir.input_dev);
-
-}
-
-/* decode raw bit pattern to RC5 code */
-/* taken from ir-functions.c */
-static u32 ir_rc5_decode(unsigned int code)
+void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
{
-/* unsigned int org_code = code;*/
- unsigned int pair;
- unsigned int rc5 = 0;
int i;
+ const s32 *samples = (const void *)buf;
- for (i = 0; i < 14; ++i) {
- pair = code & 0x3;
- code >>= 2;
-
- rc5 <<= 1;
- switch (pair) {
- case 0:
- case 2:
- break;
- case 1:
- rc5 |= 1;
- break;
- case 3:
-/* dprintk(1, "ir-common: ir_rc5_decode(%x) bad code\n", org_code);*/
- sms_log("bad code");
- return 0;
- }
- }
-/*
- dprintk(1, "ir-common: code=%x, rc5=%x, start=%x,
- toggle=%x, address=%x, "
- "instr=%x\n", rc5, org_code, RC5_START(rc5),
- RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
-*/
- return rc5;
-}
-
-static void sms_rc5_parse_word(struct smscore_device_t *coredev)
-{
- #define RC5_START(x) (((x)>>12)&3)
- #define RC5_TOGGLE(x) (((x)>>11)&1)
- #define RC5_ADDR(x) (((x)>>6)&0x1F)
- #define RC5_INSTR(x) ((x)&0x3F)
-
- int i, j;
- u32 rc5_word = 0;
+ for (i = 0; i < len >> 2; i++) {
+ DEFINE_IR_RAW_EVENT(ev);
- /* Reverse the IR word direction */
- for (i = 0 ; i < 28 ; i++)
- RC5_PUSH_BIT(rc5_word, (ir_word>>i)&1, j)
+ ev.duration = abs(samples[i]) * 1000; /* Convert to ns */
+ ev.pulse = (samples[i] > 0) ? false : true;
- rc5_word = ir_rc5_decode(rc5_word);
- /* sms_log("temp = 0x%x, rc5_code = 0x%x", ir_word, rc5_word); */
-
- sms_ir_rc5_event(coredev,
- RC5_TOGGLE(rc5_word),
- RC5_ADDR(rc5_word),
- RC5_INSTR(rc5_word));
-}
-
-
-static void sms_rc5_accumulate_bits(struct smscore_device_t *coredev,
- s32 ir_sample)
-{
- #define RC5_TIME_GRANULARITY 200
- #define RC5_DEF_BIT_TIME 889
- #define RC5_MAX_SAME_BIT_CONT 4
- #define RC5_WORD_LEN 27 /* 28 bit */
-
- u32 i, j;
- s32 delta_time;
- u32 time = (ir_sample > 0) ? ir_sample : (0-ir_sample);
- u32 level = (ir_sample < 0) ? 0 : 1;
-
- for (i = RC5_MAX_SAME_BIT_CONT; i > 0; i--) {
- delta_time = time - (i*RC5_DEF_BIT_TIME) + RC5_TIME_GRANULARITY;
- if (delta_time < 0)
- continue; /* not so many consecutive bits */
- if (delta_time > (2 * RC5_TIME_GRANULARITY)) {
- /* timeout */
- if (ir_pos == (RC5_WORD_LEN-1))
- /* complete last bit */
- RC5_PUSH_BIT(ir_word, level, ir_pos)
-
- if (ir_pos == RC5_WORD_LEN)
- sms_rc5_parse_word(coredev);
- else if (ir_pos) /* timeout within a word */
- sms_log("IR error parsing a word");
-
- ir_pos = 0;
- ir_word = 0;
- /* sms_log("timeout %d", time); */
- break;
- }
- /* The time is within the range of this number of bits */
- for (j = 0 ; j < i ; j++)
- RC5_PUSH_BIT(ir_word, level, ir_pos)
-
- break;
+ ir_raw_event_store(coredev->ir.dev, &ev);
}
-}
-
-void sms_ir_event(struct smscore_device_t *coredev, const char *buf, int len)
-{
- #define IR_DATA_RECEIVE_MAX_LEN 520 /* 128*4 + 4 + 4 */
- u32 i;
- enum ir_protocol ir_protocol =
- keyboard_layout_maps[coredev->ir.ir_kb_type]
- .ir_protocol;
- s32 *samples;
- int count = len>>2;
-
- samples = (s32 *)buf;
-/* sms_log("IR buffer received, length = %d", count);*/
-
- for (i = 0; i < count; i++)
- if (ir_protocol == IR_RC5)
- sms_rc5_accumulate_bits(coredev, samples[i]);
- /* IR_RCMM not implemented */
+ ir_raw_event_handle(coredev->ir.dev);
}
int sms_ir_init(struct smscore_device_t *coredev)
{
- struct input_dev *input_dev;
+ int err;
+ int board_id = smscore_get_board_id(coredev);
+ struct rc_dev *dev;
- sms_log("Allocating input device");
- input_dev = input_allocate_device();
- if (!input_dev) {
+ sms_log("Allocating rc device");
+ dev = rc_allocate_device();
+ if (!dev) {
sms_err("Not enough memory");
return -ENOMEM;
}
- coredev->ir.input_dev = input_dev;
- coredev->ir.ir_kb_type =
- sms_get_board(smscore_get_board_id(coredev))->ir_kb_type;
- coredev->ir.keyboard_layout_map =
- keyboard_layout_maps[coredev->ir.ir_kb_type].
- keyboard_layout_map;
- sms_log("IR remote keyboard type is %d", coredev->ir.ir_kb_type);
-
coredev->ir.controller = 0; /* Todo: vega/nova SPI number */
coredev->ir.timeout = IR_DEFAULT_TIMEOUT;
sms_log("IR port %d, timeout %d ms",
coredev->ir.controller, coredev->ir.timeout);
- snprintf(coredev->ir.name,
- IR_DEV_NAME_MAX_LEN,
- "SMS IR w/kbd type %d",
- coredev->ir.ir_kb_type);
- input_dev->name = coredev->ir.name;
- input_dev->phys = coredev->ir.name;
- input_dev->dev.parent = coredev->device;
+ snprintf(coredev->ir.name, sizeof(coredev->ir.name),
+ "SMS IR (%s)", sms_get_board(board_id)->name);
+
+ strlcpy(coredev->ir.phys, coredev->devpath, sizeof(coredev->ir.phys));
+ strlcat(coredev->ir.phys, "/ir0", sizeof(coredev->ir.phys));
+
+ dev->input_name = coredev->ir.name;
+ dev->input_phys = coredev->ir.phys;
+ dev->dev.parent = coredev->device;
- /* Key press events only */
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- input_dev->keybit[BIT_WORD(BTN_0)] = BIT_MASK(BTN_0);
+#if 0
+ /* TODO: properly initialize the parameters bellow */
+ dev->input_id.bustype = BUS_USB;
+ dev->input_id.version = 1;
+ dev->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ dev->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+#endif
- sms_log("Input device (IR) %s is set for key events", input_dev->name);
+ dev->priv = coredev;
+ dev->driver_type = RC_DRIVER_IR_RAW;
+ dev->allowed_protos = RC_TYPE_ALL;
+ dev->map_name = sms_get_board(board_id)->rc_codes;
+ dev->driver_name = MODULE_NAME;
- if (input_register_device(input_dev)) {
+ sms_log("Input device (IR) %s is set for key events", dev->input_name);
+
+ err = rc_register_device(dev);
+ if (err < 0) {
sms_err("Failed to register device");
- input_free_device(input_dev);
- return -EACCES;
+ rc_free_device(dev);
+ return err;
}
+ coredev->ir.dev = dev;
return 0;
}
void sms_ir_exit(struct smscore_device_t *coredev)
{
- if (coredev->ir.input_dev)
- input_unregister_device(coredev->ir.input_dev);
+ if (coredev->ir.dev)
+ rc_unregister_device(coredev->ir.dev);
sms_log("");
}
-
diff --git a/drivers/media/dvb/siano/smsir.h b/drivers/media/dvb/siano/smsir.h
index b7d703e2d338..ae92b3a8587e 100644
--- a/drivers/media/dvb/siano/smsir.h
+++ b/drivers/media/dvb/siano/smsir.h
@@ -4,6 +4,11 @@ Siano Mobile Silicon, Inc.
MDTV receiver kernel modules.
Copyright (C) 2006-2009, Uri Shkolnik
+ Copyright (c) 2010 - Mauro Carvalho Chehab
+ - Ported the driver to use rc-core
+ - IR raw event decoding is now done at rc-core
+ - Code almost re-written
+
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
@@ -23,63 +28,20 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#define __SMS_IR_H__
#include <linux/input.h>
+#include <media/rc-core.h>
-#define IR_DEV_NAME_MAX_LEN 23 /* "SMS IR kbd type nn\0" */
-#define IR_KEYBOARD_LAYOUT_SIZE 64
#define IR_DEFAULT_TIMEOUT 100
-enum ir_kb_type {
- SMS_IR_KB_DEFAULT_TV,
- SMS_IR_KB_HCW_SILVER
-};
-
-enum rc5_keyboard_address {
- KEYBOARD_ADDRESS_TV1 = 0,
- KEYBOARD_ADDRESS_TV2 = 1,
- KEYBOARD_ADDRESS_TELETEXT = 2,
- KEYBOARD_ADDRESS_VIDEO = 3,
- KEYBOARD_ADDRESS_LV1 = 4,
- KEYBOARD_ADDRESS_VCR1 = 5,
- KEYBOARD_ADDRESS_VCR2 = 6,
- KEYBOARD_ADDRESS_EXPERIMENTAL = 7,
- KEYBOARD_ADDRESS_SAT1 = 8,
- KEYBOARD_ADDRESS_CAMERA = 9,
- KEYBOARD_ADDRESS_SAT2 = 10,
- KEYBOARD_ADDRESS_CDV = 12,
- KEYBOARD_ADDRESS_CAMCORDER = 13,
- KEYBOARD_ADDRESS_PRE_AMP = 16,
- KEYBOARD_ADDRESS_TUNER = 17,
- KEYBOARD_ADDRESS_RECORDER1 = 18,
- KEYBOARD_ADDRESS_PRE_AMP1 = 19,
- KEYBOARD_ADDRESS_CD_PLAYER = 20,
- KEYBOARD_ADDRESS_PHONO = 21,
- KEYBOARD_ADDRESS_SATA = 22,
- KEYBOARD_ADDRESS_RECORDER2 = 23,
- KEYBOARD_ADDRESS_CDR = 26,
- KEYBOARD_ADDRESS_LIGHTING = 29,
- KEYBOARD_ADDRESS_LIGHTING1 = 30, /* KEYBOARD_ADDRESS_HCW_SILVER */
- KEYBOARD_ADDRESS_PHONE = 31,
- KEYBOARD_ADDRESS_NOT_RC5 = 0xFFFF
-};
-
-enum ir_protocol {
- IR_RC5,
- IR_RCMM
-};
-
-struct keyboard_layout_map_t {
- enum ir_protocol ir_protocol;
- enum rc5_keyboard_address rc5_kbd_address;
- u16 keyboard_layout_map[IR_KEYBOARD_LAYOUT_SIZE];
-};
-
struct smscore_device_t;
struct ir_t {
- struct input_dev *input_dev;
- enum ir_kb_type ir_kb_type;
- char name[IR_DEV_NAME_MAX_LEN+1];
- u16 *keyboard_layout_map;
+ struct rc_dev *dev;
+ char name[40];
+ char phys[32];
+
+ char *rc_codes;
+ u64 protocol;
+
u32 timeout;
u32 controller;
};
diff --git a/drivers/media/dvb/siano/smsusb.c b/drivers/media/dvb/siano/smsusb.c
index a9c27fb69ba7..0b8da57cf4c3 100644
--- a/drivers/media/dvb/siano/smsusb.c
+++ b/drivers/media/dvb/siano/smsusb.c
@@ -288,8 +288,7 @@ static int smsusb1_setmode(void *context, int mode)
static void smsusb_term_device(struct usb_interface *intf)
{
- struct smsusb_device_t *dev =
- (struct smsusb_device_t *) usb_get_intfdata(intf);
+ struct smsusb_device_t *dev = usb_get_intfdata(intf);
if (dev) {
smsusb_stop_streaming(dev);
@@ -352,8 +351,7 @@ static int smsusb_init_device(struct usb_interface *intf, int board_id)
params.num_buffers = MAX_BUFFERS;
params.sendrequest_handler = smsusb_sendrequest;
params.context = dev;
- snprintf(params.devpath, sizeof(params.devpath),
- "usb\\%d-%s", dev->udev->bus->busnum, dev->udev->devpath);
+ usb_make_path(dev->udev, params.devpath, sizeof(params.devpath));
/* register in smscore */
rc = smscore_register_device(&params, &dev->coredev);
@@ -446,8 +444,7 @@ static void smsusb_disconnect(struct usb_interface *intf)
static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
{
- struct smsusb_device_t *dev =
- (struct smsusb_device_t *)usb_get_intfdata(intf);
+ struct smsusb_device_t *dev = usb_get_intfdata(intf);
printk(KERN_INFO "%s: Entering status %d.\n", __func__, msg.event);
smsusb_stop_streaming(dev);
return 0;
@@ -456,8 +453,7 @@ static int smsusb_suspend(struct usb_interface *intf, pm_message_t msg)
static int smsusb_resume(struct usb_interface *intf)
{
int rc, i;
- struct smsusb_device_t *dev =
- (struct smsusb_device_t *)usb_get_intfdata(intf);
+ struct smsusb_device_t *dev = usb_get_intfdata(intf);
struct usb_device *udev = interface_to_usbdev(intf);
printk(KERN_INFO "%s: Entering.\n", __func__);
diff --git a/drivers/media/dvb/ttpci/Kconfig b/drivers/media/dvb/ttpci/Kconfig
index d8d4214fd65f..44afab2fdc2d 100644
--- a/drivers/media/dvb/ttpci/Kconfig
+++ b/drivers/media/dvb/ttpci/Kconfig
@@ -68,13 +68,14 @@ config DVB_BUDGET
select DVB_VES1820 if !DVB_FE_CUSTOMISE
select DVB_L64781 if !DVB_FE_CUSTOMISE
select DVB_TDA8083 if !DVB_FE_CUSTOMISE
- select DVB_TDA10021 if !DVB_FE_CUSTOMISE
- select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select DVB_S5H1420 if !DVB_FE_CUSTOMISE
select DVB_TDA10086 if !DVB_FE_CUSTOMISE
select DVB_TDA826X if !DVB_FE_CUSTOMISE
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
+ select DVB_ISL6423 if !DVB_FE_CUSTOMISE
+ select DVB_STV090x if !DVB_FE_CUSTOMISE
+ select DVB_STV6110x if !DVB_FE_CUSTOMISE
help
Support for simple SAA7146 based DVB cards (so called Budget-
or Nova-PCI cards) without onboard MPEG2 decoder, and without
@@ -88,7 +89,6 @@ config DVB_BUDGET
config DVB_BUDGET_CI
tristate "Budget cards with onboard CI connector"
depends on DVB_BUDGET_CORE && I2C
- depends on INPUT # due to IR
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_STV0299 if !DVB_FE_CUSTOMISE
select DVB_TDA1004X if !DVB_FE_CUSTOMISE
@@ -97,7 +97,7 @@ config DVB_BUDGET_CI
select DVB_LNBP21 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
select MEDIA_TUNER_TDA827X if !MEDIA_TUNER_CUSTOMISE
- select VIDEO_IR
+ depends on RC_CORE
help
Support for simple SAA7146 based DVB cards
(so called Budget- or Nova-PCI cards) without onboard
diff --git a/drivers/media/dvb/ttpci/av7110.c b/drivers/media/dvb/ttpci/av7110.c
index a6be529eec5c..fc0a60f8a1e1 100644
--- a/drivers/media/dvb/ttpci/av7110.c
+++ b/drivers/media/dvb/ttpci/av7110.c
@@ -26,7 +26,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
@@ -730,6 +730,7 @@ static const struct file_operations dvb_osd_fops = {
.unlocked_ioctl = dvb_generic_ioctl,
.open = dvb_generic_open,
.release = dvb_generic_release,
+ .llseek = noop_llseek,
};
static struct dvb_device dvbdev_osd = {
@@ -2290,12 +2291,7 @@ static int frontend_init(struct av7110 *av7110)
/* Budgetpatch note:
* Original hardware design by Roberto Deza:
* There is a DVB_Wiki at
- * http://212.227.36.83/linuxtv/wiki/index.php/Main_Page
- * where is described this 'DVB TT Budget Patch', on Card Modding:
- * http://212.227.36.83/linuxtv/wiki/index.php/DVB_TT_Budget_Patch
- * On the short description there is also a link to a external file,
- * with more details:
- * http://perso.wanadoo.es/jesussolano/Ttf_tsc1.zip
+ * http://www.linuxtv.org/
*
* New software triggering design by Emard that works on
* original Roberto Deza's hardware:
@@ -2476,7 +2472,6 @@ static int __devinit av7110_attach(struct saa7146_dev* dev,
get recognized before the main driver is fully loaded */
saa7146_write(dev, GPIO_CTRL, 0x500000);
- av7110->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
strlcpy(av7110->i2c_adap.name, pci_ext->ext_priv, sizeof(av7110->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &av7110->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120); /* 275 kHz */
@@ -2890,7 +2885,7 @@ MODULE_DEVICE_TABLE(pci, pci_tbl);
static struct saa7146_extension av7110_extension_driver = {
- .name = "dvb",
+ .name = "av7110",
.flags = SAA7146_USE_I2C_IRQ,
.module = THIS_MODULE,
diff --git a/drivers/media/dvb/ttpci/av7110_av.c b/drivers/media/dvb/ttpci/av7110_av.c
index 13efba942dac..952b33dbac4f 100644
--- a/drivers/media/dvb/ttpci/av7110_av.c
+++ b/drivers/media/dvb/ttpci/av7110_av.c
@@ -25,7 +25,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include <linux/types.h>
@@ -245,8 +245,11 @@ int av7110_pes_play(void *dest, struct dvb_ringbuffer *buf, int dlen)
return -1;
}
while (1) {
- if ((len = dvb_ringbuffer_avail(buf)) < 6)
+ len = dvb_ringbuffer_avail(buf);
+ if (len < 6) {
+ wake_up(&buf->queue);
return -1;
+ }
sync = DVB_RINGBUFFER_PEEK(buf, 0) << 24;
sync |= DVB_RINGBUFFER_PEEK(buf, 1) << 16;
sync |= DVB_RINGBUFFER_PEEK(buf, 2) << 8;
@@ -1521,6 +1524,7 @@ static const struct file_operations dvb_video_fops = {
.open = dvb_video_open,
.release = dvb_video_release,
.poll = dvb_video_poll,
+ .llseek = noop_llseek,
};
static struct dvb_device dvbdev_video = {
@@ -1539,6 +1543,7 @@ static const struct file_operations dvb_audio_fops = {
.open = dvb_audio_open,
.release = dvb_audio_release,
.poll = dvb_audio_poll,
+ .llseek = noop_llseek,
};
static struct dvb_device dvbdev_audio = {
diff --git a/drivers/media/dvb/ttpci/av7110_ca.c b/drivers/media/dvb/ttpci/av7110_ca.c
index 4eba35a018e3..9fc1dd0ba4c3 100644
--- a/drivers/media/dvb/ttpci/av7110_ca.c
+++ b/drivers/media/dvb/ttpci/av7110_ca.c
@@ -25,7 +25,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include <linux/kernel.h>
@@ -277,7 +277,7 @@ static int dvb_ca_ioctl(struct file *file, unsigned int cmd, void *parg)
{
ca_slot_info_t *info=(ca_slot_info_t *)parg;
- if (info->num > 1)
+ if (info->num < 0 || info->num > 1)
return -EINVAL;
av7110->ci_slot[info->num].num = info->num;
av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ?
@@ -353,6 +353,7 @@ static const struct file_operations dvb_ca_fops = {
.open = dvb_ca_open,
.release = dvb_generic_release,
.poll = dvb_ca_poll,
+ .llseek = default_llseek,
};
static struct dvb_device dvbdev_ca = {
diff --git a/drivers/media/dvb/ttpci/av7110_hw.c b/drivers/media/dvb/ttpci/av7110_hw.c
index e162691b515d..f1cbfe526989 100644
--- a/drivers/media/dvb/ttpci/av7110_hw.c
+++ b/drivers/media/dvb/ttpci/av7110_hw.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
/* for debugging ARM communication: */
diff --git a/drivers/media/dvb/ttpci/av7110_ir.c b/drivers/media/dvb/ttpci/av7110_ir.c
index b070e88d8c6b..908f272fe26c 100644
--- a/drivers/media/dvb/ttpci/av7110_ir.c
+++ b/drivers/media/dvb/ttpci/av7110_ir.c
@@ -312,6 +312,7 @@ static ssize_t av7110_ir_proc_write(struct file *file, const char __user *buffer
static const struct file_operations av7110_ir_proc_fops = {
.owner = THIS_MODULE,
.write = av7110_ir_proc_write,
+ .llseek = noop_llseek,
};
/* interrupt handler */
diff --git a/drivers/media/dvb/ttpci/av7110_v4l.c b/drivers/media/dvb/ttpci/av7110_v4l.c
index 8986d967d2f4..cdd31cae46c4 100644
--- a/drivers/media/dvb/ttpci/av7110_v4l.c
+++ b/drivers/media/dvb/ttpci/av7110_v4l.c
@@ -22,7 +22,7 @@
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include <linux/kernel.h>
@@ -100,6 +100,7 @@ static struct v4l2_input inputs[4] = {
.tuner = 0, /* ignored */
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
+ .capabilities = V4L2_IN_CAP_STD,
}, {
.index = 1,
.name = "Television",
@@ -108,6 +109,7 @@ static struct v4l2_input inputs[4] = {
.tuner = 0,
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
+ .capabilities = V4L2_IN_CAP_STD,
}, {
.index = 2,
.name = "Video",
@@ -116,6 +118,7 @@ static struct v4l2_input inputs[4] = {
.tuner = 0,
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
+ .capabilities = V4L2_IN_CAP_STD,
}, {
.index = 3,
.name = "Y/C",
@@ -124,6 +127,7 @@ static struct v4l2_input inputs[4] = {
.tuner = 0,
.std = V4L2_STD_PAL_BG|V4L2_STD_NTSC_M,
.status = 0,
+ .capabilities = V4L2_IN_CAP_STD,
}
};
diff --git a/drivers/media/dvb/ttpci/budget-av.c b/drivers/media/dvb/ttpci/budget-av.c
index 983672aa2450..e957d7690bcc 100644
--- a/drivers/media/dvb/ttpci/budget-av.c
+++ b/drivers/media/dvb/ttpci/budget-av.c
@@ -30,7 +30,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include "budget.h"
@@ -1406,8 +1406,10 @@ static int budget_av_detach(struct saa7146_dev *dev)
#define KNC1_INPUTS 2
static struct v4l2_input knc1_inputs[KNC1_INPUTS] = {
- {0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
- {1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0},
+ { 0, "Composite", V4L2_INPUT_TYPE_TUNER, 1, 0,
+ V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 1, "S-Video", V4L2_INPUT_TYPE_CAMERA, 2, 0,
+ V4L2_STD_PAL_BG | V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
};
static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 461714396331..b82756db5bd1 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -26,16 +26,15 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include <linux/module.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/input.h>
#include <linux/spinlock.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include "budget.h"
@@ -96,7 +95,7 @@ MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
struct budget_ci_ir {
- struct input_dev *dev;
+ struct rc_dev *dev;
struct tasklet_struct msp430_irq_tasklet;
char name[72]; /* 40 + 32 for (struct saa7146_dev).name */
char phys[32];
@@ -118,7 +117,7 @@ struct budget_ci {
static void msp430_ir_interrupt(unsigned long data)
{
struct budget_ci *budget_ci = (struct budget_ci *) data;
- struct input_dev *dev = budget_ci->ir.dev;
+ struct rc_dev *dev = budget_ci->ir.dev;
u32 command = ttpci_budget_debiread(&budget_ci->budget, DEBINOSWAP, DEBIADDR_IR, 2, 1, 0) >> 8;
/*
@@ -160,19 +159,17 @@ static void msp430_ir_interrupt(unsigned long data)
budget_ci->ir.rc5_device != (command & 0x1f))
return;
- ir_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
+ rc_keydown(dev, budget_ci->ir.ir_key, (command & 0x20) ? 1 : 0);
}
static int msp430_ir_init(struct budget_ci *budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
- struct input_dev *input_dev = budget_ci->ir.dev;
+ struct rc_dev *dev;
int error;
- char *ir_codes = NULL;
-
- budget_ci->ir.dev = input_dev = input_allocate_device();
- if (!input_dev) {
+ dev = rc_allocate_device();
+ if (!dev) {
printk(KERN_ERR "budget_ci: IR interface initialisation failed\n");
return -ENOMEM;
}
@@ -182,19 +179,20 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
snprintf(budget_ci->ir.phys, sizeof(budget_ci->ir.phys),
"pci-%s/ir0", pci_name(saa->pci));
- input_dev->name = budget_ci->ir.name;
-
- input_dev->phys = budget_ci->ir.phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ dev->driver_name = MODULE_NAME;
+ dev->input_name = budget_ci->ir.name;
+ dev->input_phys = budget_ci->ir.phys;
+ dev->input_id.bustype = BUS_PCI;
+ dev->input_id.version = 1;
+ dev->scanmask = 0xff;
if (saa->pci->subsystem_vendor) {
- input_dev->id.vendor = saa->pci->subsystem_vendor;
- input_dev->id.product = saa->pci->subsystem_device;
+ dev->input_id.vendor = saa->pci->subsystem_vendor;
+ dev->input_id.product = saa->pci->subsystem_device;
} else {
- input_dev->id.vendor = saa->pci->vendor;
- input_dev->id.product = saa->pci->device;
+ dev->input_id.vendor = saa->pci->vendor;
+ dev->input_id.product = saa->pci->device;
}
- input_dev->dev.parent = &saa->pci->dev;
+ dev->dev.parent = &saa->pci->dev;
if (rc5_device < 0)
budget_ci->ir.rc5_device = IR_DEVICE_ANY;
@@ -208,32 +206,32 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
case 0x1011:
case 0x1012:
/* The hauppauge keymap is a superset of these remotes */
- ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ dev->map_name = RC_MAP_HAUPPAUGE_NEW;
if (rc5_device < 0)
budget_ci->ir.rc5_device = 0x1f;
break;
case 0x1010:
case 0x1017:
+ case 0x1019:
case 0x101a:
/* for the Technotrend 1500 bundled remote */
- ir_codes = RC_MAP_TT_1500;
+ dev->map_name = RC_MAP_TT_1500;
break;
default:
/* unknown remote */
- ir_codes = RC_MAP_BUDGET_CI_OLD;
+ dev->map_name = RC_MAP_BUDGET_CI_OLD;
break;
}
- error = ir_input_register(input_dev, ir_codes, NULL, MODULE_NAME);
+ error = rc_register_device(dev);
if (error) {
printk(KERN_ERR "budget_ci: could not init driver for IR device (code %d)\n", error);
+ rc_free_device(dev);
return error;
}
- /* note: these must be after input_register_device */
- input_dev->rep[REP_DELAY] = 400;
- input_dev->rep[REP_PERIOD] = 250;
+ budget_ci->ir.dev = dev;
tasklet_init(&budget_ci->ir.msp430_irq_tasklet, msp430_ir_interrupt,
(unsigned long) budget_ci);
@@ -247,13 +245,12 @@ static int msp430_ir_init(struct budget_ci *budget_ci)
static void msp430_ir_deinit(struct budget_ci *budget_ci)
{
struct saa7146_dev *saa = budget_ci->budget.dev;
- struct input_dev *dev = budget_ci->ir.dev;
SAA7146_IER_DISABLE(saa, MASK_06);
saa7146_setgpio(saa, 3, SAA7146_GPIO_INPUT);
tasklet_kill(&budget_ci->ir.msp430_irq_tasklet);
- ir_input_unregister(dev);
+ rc_unregister_device(budget_ci->ir.dev);
}
static int ciintf_read_attribute_mem(struct dvb_ca_en50221 *ca, int slot, int address)
diff --git a/drivers/media/dvb/ttpci/budget-core.c b/drivers/media/dvb/ttpci/budget-core.c
index ba18e56d5f11..37666d4edab6 100644
--- a/drivers/media/dvb/ttpci/budget-core.c
+++ b/drivers/media/dvb/ttpci/budget-core.c
@@ -31,7 +31,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
@@ -495,8 +495,6 @@ int ttpci_budget_init(struct budget *budget, struct saa7146_dev *dev,
if (bi->type != BUDGET_FS_ACTIVY)
saa7146_write(dev, GPIO_CTRL, 0x500000); /* GPIO 3 = 1 */
- budget->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
-
strlcpy(budget->i2c_adap.name, budget->card->name, sizeof(budget->i2c_adap.name));
saa7146_i2c_adapter_prepare(dev, &budget->i2c_adap, SAA7146_I2C_BUS_BIT_RATE_120);
diff --git a/drivers/media/dvb/ttpci/budget-patch.c b/drivers/media/dvb/ttpci/budget-patch.c
index 9c92f9ddd223..579835590690 100644
--- a/drivers/media/dvb/ttpci/budget-patch.c
+++ b/drivers/media/dvb/ttpci/budget-patch.c
@@ -27,7 +27,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include "av7110.h"
diff --git a/drivers/media/dvb/ttpci/budget.c b/drivers/media/dvb/ttpci/budget.c
index 874a10a9d493..d238fb9371a7 100644
--- a/drivers/media/dvb/ttpci/budget.c
+++ b/drivers/media/dvb/ttpci/budget.c
@@ -31,7 +31,7 @@
* Or, point your browser to http://www.gnu.org/copyleft/gpl.html
*
*
- * the project's page is at http://www.linuxtv.org/dvb/
+ * the project's page is at http://www.linuxtv.org/
*/
#include "budget.h"
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 4a3f2b8ea37d..40625b26ac10 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -1694,7 +1694,6 @@ static int ttusb_probe(struct usb_interface *intf, const struct usb_device_id *i
i2c_set_adapdata(&ttusb->i2c_adap, ttusb);
- ttusb->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
ttusb->i2c_adap.algo = &ttusb_dec_algo;
ttusb->i2c_adap.algo_data = NULL;
ttusb->i2c_adap.dev.parent = &udev->dev;
diff --git a/drivers/media/radio/Kconfig b/drivers/media/radio/Kconfig
index 83567b898d09..ecdffa6aac66 100644
--- a/drivers/media/radio/Kconfig
+++ b/drivers/media/radio/Kconfig
@@ -151,20 +151,6 @@ config RADIO_GEMTEK_PROBE
following ports will be probed: 0x20c, 0x30c, 0x24c, 0x34c, 0x248 and
0x28c.
-config RADIO_GEMTEK_PCI
- tristate "GemTek PCI Radio Card support"
- depends on VIDEO_V4L2 && PCI
- ---help---
- Choose Y here if you have this PCI FM radio card.
-
- In order to control your radio card, you will need to use programs
- that are compatible with the Video for Linux API. Information on
- this API and pointers to "v4l" programs may be found at
- <file:Documentation/video4linux/API.html>.
-
- To compile this driver as a module, choose M here: the
- module will be called radio-gemtek-pci.
-
config RADIO_MAXIRADIO
tristate "Guillemot MAXI Radio FM 2000 radio"
depends on VIDEO_V4L2 && PCI
@@ -452,4 +438,20 @@ config RADIO_TIMBERDALE
found behind the Timberdale FPGA on the Russellville board.
Enabling this driver will automatically select the DSP and tuner.
+config RADIO_WL1273
+ tristate "Texas Instruments WL1273 I2C FM Radio"
+ depends on I2C && VIDEO_V4L2
+ select MFD_WL1273_CORE
+ select FW_LOADER
+ ---help---
+ Choose Y here if you have this FM radio chip.
+
+ In order to control your radio card, you will need to use programs
+ that are compatible with the Video For Linux 2 API. Information on
+ this API and pointers to "v4l2" programs may be found at
+ <file:Documentation/video4linux/API.html>.
+
+ To compile this driver as a module, choose M here: the
+ module will be called radio-wl1273.
+
endif # RADIO_ADAPTERS
diff --git a/drivers/media/radio/Makefile b/drivers/media/radio/Makefile
index f615583b4837..717656d2f749 100644
--- a/drivers/media/radio/Makefile
+++ b/drivers/media/radio/Makefile
@@ -13,7 +13,6 @@ obj-$(CONFIG_RADIO_MAXIRADIO) += radio-maxiradio.o
obj-$(CONFIG_RADIO_RTRACK) += radio-aimslab.o
obj-$(CONFIG_RADIO_ZOLTRIX) += radio-zoltrix.o
obj-$(CONFIG_RADIO_GEMTEK) += radio-gemtek.o
-obj-$(CONFIG_RADIO_GEMTEK_PCI) += radio-gemtek-pci.o
obj-$(CONFIG_RADIO_TRUST) += radio-trust.o
obj-$(CONFIG_I2C_SI4713) += si4713-i2c.o
obj-$(CONFIG_RADIO_SI4713) += radio-si4713.o
@@ -26,5 +25,6 @@ obj-$(CONFIG_RADIO_TEA5764) += radio-tea5764.o
obj-$(CONFIG_RADIO_SAA7706H) += saa7706h.o
obj-$(CONFIG_RADIO_TEF6862) += tef6862.o
obj-$(CONFIG_RADIO_TIMBERDALE) += radio-timb.o
+obj-$(CONFIG_RADIO_WL1273) += radio-wl1273.o
EXTRA_CFLAGS += -Isound
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index 5bf4985daede..4ce10dbeadd8 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -31,7 +31,7 @@
#include <linux/module.h> /* Modules */
#include <linux/init.h> /* Initdata */
#include <linux/ioport.h> /* request_region */
-#include <linux/delay.h> /* udelay */
+#include <linux/delay.h> /* msleep */
#include <linux/videodev2.h> /* kernel radio structs */
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#include <linux/io.h> /* outb, outb_p */
@@ -71,27 +71,17 @@ static struct rtrack rtrack_card;
/* local things */
-static void sleep_delay(long n)
-{
- /* Sleep nicely for 'n' uS */
- int d = n / msecs_to_jiffies(1000);
- if (!d)
- udelay(n);
- else
- msleep(jiffies_to_msecs(d));
-}
-
static void rt_decvol(struct rtrack *rt)
{
outb(0x58, rt->io); /* volume down + sigstr + on */
- sleep_delay(100000);
+ msleep(100);
outb(0xd8, rt->io); /* volume steady + sigstr + on */
}
static void rt_incvol(struct rtrack *rt)
{
outb(0x98, rt->io); /* volume up + sigstr + on */
- sleep_delay(100000);
+ msleep(100);
outb(0xd8, rt->io); /* volume steady + sigstr + on */
}
@@ -120,7 +110,7 @@ static int rt_setvol(struct rtrack *rt, int vol)
if (vol == 0) { /* volume = 0 means mute the card */
outb(0x48, rt->io); /* volume down but still "on" */
- sleep_delay(2000000); /* make sure it's totally down */
+ msleep(2000); /* make sure it's totally down */
outb(0xd0, rt->io); /* volume steady, off */
rt->curvol = 0; /* track the volume state! */
mutex_unlock(&rt->lock);
@@ -155,7 +145,7 @@ static void send_0_byte(struct rtrack *rt)
outb_p(128+64+16+8+ 1, rt->io); /* on + wr-enable + data low */
outb_p(128+64+16+8+2+1, rt->io); /* clock */
}
- sleep_delay(1000);
+ msleep(1);
}
static void send_1_byte(struct rtrack *rt)
@@ -169,7 +159,7 @@ static void send_1_byte(struct rtrack *rt)
outb_p(128+64+16+8+4+2+1, rt->io); /* clock */
}
- sleep_delay(1000);
+ msleep(1);
}
static int rt_setfreq(struct rtrack *rt, unsigned long freq)
@@ -361,7 +351,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations rtrack_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops rtrack_ioctl_ops = {
@@ -412,13 +402,6 @@ static int __init rtrack_init(void)
rt->vdev.release = video_device_release_empty;
video_set_drvdata(&rt->vdev, rt);
- if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(&rt->v4l2_dev);
- release_region(rt->io, 2);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
-
/* Set up the I/O locking */
mutex_init(&rt->lock);
@@ -427,9 +410,16 @@ static int __init rtrack_init(void)
/* this ensures that the volume is all the way down */
outb(0x48, rt->io); /* volume down but still "on" */
- sleep_delay(2000000); /* make sure it's totally down */
+ msleep(2000); /* make sure it's totally down */
outb(0xc0, rt->io); /* steady volume, mute card */
+ if (video_register_device(&rt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(&rt->v4l2_dev);
+ release_region(rt->io, 2);
+ return -EINVAL;
+ }
+ v4l2_info(v4l2_dev, "AIMSlab RadioTrack/RadioReveal card driver.\n");
+
return 0;
}
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index c22311393624..dd8a6ab0d437 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -324,7 +324,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static const struct v4l2_file_operations aztech_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops aztech_ioctl_ops = {
@@ -375,6 +375,8 @@ static int __init aztech_init(void)
az->vdev.ioctl_ops = &aztech_ioctl_ops;
az->vdev.release = video_device_release_empty;
video_set_drvdata(&az->vdev, az);
+ /* mute card - prevents noisy bootups */
+ outb(0, az->io);
if (video_register_device(&az->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
@@ -383,8 +385,6 @@ static int __init aztech_init(void)
}
v4l2_info(v4l2_dev, "Aztech radio card driver v1.00/19990224 rkroll@exploits.org\n");
- /* mute card - prevents noisy bootups */
- outb(0, az->io);
return 0;
}
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 482d0f3be5ff..bc9ad0897c55 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -328,11 +328,10 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
unsigned char readbuf[RDS_BUFFER];
int i = 0;
+ mutex_lock(&dev->lock);
if (dev->rdsstat == 0) {
- mutex_lock(&dev->lock);
dev->rdsstat = 1;
outb(0x80, dev->io); /* Select RDS fifo */
- mutex_unlock(&dev->lock);
init_timer(&dev->readtimer);
dev->readtimer.function = cadet_handler;
dev->readtimer.data = (unsigned long)dev;
@@ -340,12 +339,15 @@ static ssize_t cadet_read(struct file *file, char __user *data, size_t count, lo
add_timer(&dev->readtimer);
}
if (dev->rdsin == dev->rdsout) {
+ mutex_unlock(&dev->lock);
if (file->f_flags & O_NONBLOCK)
return -EWOULDBLOCK;
interruptible_sleep_on(&dev->read_queue);
+ mutex_lock(&dev->lock);
}
while (i < count && dev->rdsin != dev->rdsout)
readbuf[i++] = dev->rdsbuf[dev->rdsout++];
+ mutex_unlock(&dev->lock);
if (copy_to_user(data, readbuf, i))
return -EFAULT;
@@ -374,7 +376,8 @@ static int vidioc_g_tuner(struct file *file, void *priv,
switch (v->index) {
case 0:
strlcpy(v->name, "FM", sizeof(v->name));
- v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS;
+ v->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_RDS_BLOCK_IO;
v->rangelow = 1400; /* 87.5 MHz */
v->rangehigh = 1728; /* 108.0 MHz */
v->rxsubchans = cadet_getstereo(dev);
@@ -524,9 +527,11 @@ static int cadet_open(struct file *file)
{
struct cadet *dev = video_drvdata(file);
+ mutex_lock(&dev->lock);
dev->users++;
if (1 == dev->users)
init_waitqueue_head(&dev->read_queue);
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -534,11 +539,13 @@ static int cadet_release(struct file *file)
{
struct cadet *dev = video_drvdata(file);
+ mutex_lock(&dev->lock);
dev->users--;
if (0 == dev->users) {
del_timer_sync(&dev->readtimer);
dev->rdsstat = 0;
}
+ mutex_unlock(&dev->lock);
return 0;
}
@@ -558,7 +565,7 @@ static const struct v4l2_file_operations cadet_fops = {
.open = cadet_open,
.release = cadet_release,
.read = cadet_read,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = cadet_poll,
};
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
deleted file mode 100644
index 79039674a0e0..000000000000
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ /dev/null
@@ -1,478 +0,0 @@
-/*
- ***************************************************************************
- *
- * radio-gemtek-pci.c - Gemtek PCI Radio driver
- * (C) 2001 Vladimir Shebordaev <vshebordaev@mail.ru>
- *
- ***************************************************************************
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation; either version 2 of
- * the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public
- * License along with this program; if not, write to the Free
- * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139,
- * USA.
- *
- ***************************************************************************
- *
- * Gemtek Corp still silently refuses to release any specifications
- * of their multimedia devices, so the protocol still has to be
- * reverse engineered.
- *
- * The v4l code was inspired by Jonas Munsin's Gemtek serial line
- * radio device driver.
- *
- * Please, let me know if this piece of code was useful :)
- *
- * TODO: multiple device support and portability were not tested
- *
- * Converted to V4L2 API by Mauro Carvalho Chehab <mchehab@infradead.org>
- *
- ***************************************************************************
- */
-
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/pci.h>
-#include <linux/videodev2.h>
-#include <linux/errno.h>
-#include <linux/version.h> /* for KERNEL_VERSION MACRO */
-#include <linux/io.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-ioctl.h>
-
-MODULE_AUTHOR("Vladimir Shebordaev <vshebordaev@mail.ru>");
-MODULE_DESCRIPTION("The video4linux driver for the Gemtek PCI Radio Card");
-MODULE_LICENSE("GPL");
-
-static int nr_radio = -1;
-static int mx = 1;
-
-module_param(mx, bool, 0);
-MODULE_PARM_DESC(mx, "single digit: 1 - turn off the turner upon module exit (default), 0 - do not");
-module_param(nr_radio, int, 0);
-MODULE_PARM_DESC(nr_radio, "video4linux device number to use");
-
-#define RADIO_VERSION KERNEL_VERSION(0, 0, 2)
-
-#ifndef PCI_VENDOR_ID_GEMTEK
-#define PCI_VENDOR_ID_GEMTEK 0x5046
-#endif
-
-#ifndef PCI_DEVICE_ID_GEMTEK_PR103
-#define PCI_DEVICE_ID_GEMTEK_PR103 0x1001
-#endif
-
-#ifndef GEMTEK_PCI_RANGE_LOW
-#define GEMTEK_PCI_RANGE_LOW (87*16000)
-#endif
-
-#ifndef GEMTEK_PCI_RANGE_HIGH
-#define GEMTEK_PCI_RANGE_HIGH (108*16000)
-#endif
-
-struct gemtek_pci {
- struct v4l2_device v4l2_dev;
- struct video_device vdev;
- struct mutex lock;
- struct pci_dev *pdev;
-
- u32 iobase;
- u32 length;
-
- u32 current_frequency;
- u8 mute;
-};
-
-static inline struct gemtek_pci *to_gemtek_pci(struct v4l2_device *v4l2_dev)
-{
- return container_of(v4l2_dev, struct gemtek_pci, v4l2_dev);
-}
-
-static inline u8 gemtek_pci_out(u16 value, u32 port)
-{
- outw(value, port);
-
- return (u8)value;
-}
-
-#define _b0(v) (*((u8 *)&v))
-
-static void __gemtek_pci_cmd(u16 value, u32 port, u8 *last_byte, int keep)
-{
- u8 byte = *last_byte;
-
- if (!value) {
- if (!keep)
- value = (u16)port;
- byte &= 0xfd;
- } else
- byte |= 2;
-
- _b0(value) = byte;
- outw(value, port);
- byte |= 1;
- _b0(value) = byte;
- outw(value, port);
- byte &= 0xfe;
- _b0(value) = byte;
- outw(value, port);
-
- *last_byte = byte;
-}
-
-static inline void gemtek_pci_nil(u32 port, u8 *last_byte)
-{
- __gemtek_pci_cmd(0x00, port, last_byte, false);
-}
-
-static inline void gemtek_pci_cmd(u16 cmd, u32 port, u8 *last_byte)
-{
- __gemtek_pci_cmd(cmd, port, last_byte, true);
-}
-
-static void gemtek_pci_setfrequency(struct gemtek_pci *card, unsigned long frequency)
-{
- int i;
- u32 value = frequency / 200 + 856;
- u16 mask = 0x8000;
- u8 last_byte;
- u32 port = card->iobase;
-
- mutex_lock(&card->lock);
- card->current_frequency = frequency;
- last_byte = gemtek_pci_out(0x06, port);
-
- i = 0;
- do {
- gemtek_pci_nil(port, &last_byte);
- i++;
- } while (i < 9);
-
- i = 0;
- do {
- gemtek_pci_cmd(value & mask, port, &last_byte);
- mask >>= 1;
- i++;
- } while (i < 16);
-
- outw(0x10, port);
- mutex_unlock(&card->lock);
-}
-
-
-static void gemtek_pci_mute(struct gemtek_pci *card)
-{
- mutex_lock(&card->lock);
- outb(0x1f, card->iobase);
- card->mute = true;
- mutex_unlock(&card->lock);
-}
-
-static void gemtek_pci_unmute(struct gemtek_pci *card)
-{
- if (card->mute) {
- gemtek_pci_setfrequency(card, card->current_frequency);
- card->mute = false;
- }
-}
-
-static int gemtek_pci_getsignal(struct gemtek_pci *card)
-{
- int sig;
-
- mutex_lock(&card->lock);
- sig = (inb(card->iobase) & 0x08) ? 0 : 1;
- mutex_unlock(&card->lock);
- return sig;
-}
-
-static int vidioc_querycap(struct file *file, void *priv,
- struct v4l2_capability *v)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- strlcpy(v->driver, "radio-gemtek-pci", sizeof(v->driver));
- strlcpy(v->card, "GemTek PCI Radio", sizeof(v->card));
- snprintf(v->bus_info, sizeof(v->bus_info), "PCI:%s", pci_name(card->pdev));
- 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 gemtek_pci *card = video_drvdata(file);
-
- if (v->index > 0)
- return -EINVAL;
-
- strlcpy(v->name, "FM", sizeof(v->name));
- v->type = V4L2_TUNER_RADIO;
- v->rangelow = GEMTEK_PCI_RANGE_LOW;
- v->rangehigh = GEMTEK_PCI_RANGE_HIGH;
- v->rxsubchans = V4L2_TUNER_SUB_MONO;
- v->capability = V4L2_TUNER_CAP_LOW;
- v->audmode = V4L2_TUNER_MODE_MONO;
- v->signal = 0xffff * gemtek_pci_getsignal(card);
- return 0;
-}
-
-static int vidioc_s_tuner(struct file *file, void *priv,
- struct v4l2_tuner *v)
-{
- return v->index ? -EINVAL : 0;
-}
-
-static int vidioc_s_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- if (f->tuner != 0 || f->type != V4L2_TUNER_RADIO)
- return -EINVAL;
- if (f->frequency < GEMTEK_PCI_RANGE_LOW ||
- f->frequency > GEMTEK_PCI_RANGE_HIGH)
- return -EINVAL;
- gemtek_pci_setfrequency(card, f->frequency);
- card->mute = false;
- return 0;
-}
-
-static int vidioc_g_frequency(struct file *file, void *priv,
- struct v4l2_frequency *f)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- if (f->tuner != 0)
- return -EINVAL;
- f->type = V4L2_TUNER_RADIO;
- f->frequency = card->current_frequency;
- return 0;
-}
-
-static int vidioc_queryctrl(struct file *file, void *priv,
- struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535, 65535);
- }
- return -EINVAL;
-}
-
-static int vidioc_g_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = card->mute;
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- if (card->mute)
- ctrl->value = 0;
- else
- ctrl->value = 65535;
- return 0;
- }
- return -EINVAL;
-}
-
-static int vidioc_s_ctrl(struct file *file, void *priv,
- struct v4l2_control *ctrl)
-{
- struct gemtek_pci *card = video_drvdata(file);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value)
- gemtek_pci_mute(card);
- else
- gemtek_pci_unmute(card);
- return 0;
- case V4L2_CID_AUDIO_VOLUME:
- if (ctrl->value)
- gemtek_pci_unmute(card);
- else
- gemtek_pci_mute(card);
- 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)
-{
- return i ? -EINVAL : 0;
-}
-
-static int vidioc_g_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- a->index = 0;
- strlcpy(a->name, "Radio", sizeof(a->name));
- a->capability = V4L2_AUDCAP_STEREO;
- return 0;
-}
-
-static int vidioc_s_audio(struct file *file, void *priv,
- struct v4l2_audio *a)
-{
- return a->index ? -EINVAL : 0;
-}
-
-enum {
- GEMTEK_PR103
-};
-
-static char *card_names[] __devinitdata = {
- "GEMTEK_PR103"
-};
-
-static struct pci_device_id gemtek_pci_id[] =
-{
- { PCI_VENDOR_ID_GEMTEK, PCI_DEVICE_ID_GEMTEK_PR103,
- PCI_ANY_ID, PCI_ANY_ID, 0, 0, GEMTEK_PR103 },
- { 0 }
-};
-
-MODULE_DEVICE_TABLE(pci, gemtek_pci_id);
-
-static const struct v4l2_file_operations gemtek_pci_fops = {
- .owner = THIS_MODULE,
- .ioctl = video_ioctl2,
-};
-
-static const struct v4l2_ioctl_ops gemtek_pci_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,
-};
-
-static int __devinit gemtek_pci_probe(struct pci_dev *pdev, const struct pci_device_id *pci_id)
-{
- struct gemtek_pci *card;
- struct v4l2_device *v4l2_dev;
- int res;
-
- card = kzalloc(sizeof(struct gemtek_pci), GFP_KERNEL);
- if (card == NULL) {
- dev_err(&pdev->dev, "out of memory\n");
- return -ENOMEM;
- }
-
- v4l2_dev = &card->v4l2_dev;
- mutex_init(&card->lock);
- card->pdev = pdev;
-
- strlcpy(v4l2_dev->name, "gemtek_pci", sizeof(v4l2_dev->name));
-
- res = v4l2_device_register(&pdev->dev, v4l2_dev);
- if (res < 0) {
- v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
- kfree(card);
- return res;
- }
-
- if (pci_enable_device(pdev))
- goto err_pci;
-
- card->iobase = pci_resource_start(pdev, 0);
- card->length = pci_resource_len(pdev, 0);
-
- if (request_region(card->iobase, card->length, card_names[pci_id->driver_data]) == NULL) {
- v4l2_err(v4l2_dev, "i/o port already in use\n");
- goto err_pci;
- }
-
- strlcpy(card->vdev.name, v4l2_dev->name, sizeof(card->vdev.name));
- card->vdev.v4l2_dev = v4l2_dev;
- card->vdev.fops = &gemtek_pci_fops;
- card->vdev.ioctl_ops = &gemtek_pci_ioctl_ops;
- card->vdev.release = video_device_release_empty;
- video_set_drvdata(&card->vdev, card);
-
- if (video_register_device(&card->vdev, VFL_TYPE_RADIO, nr_radio) < 0)
- goto err_video;
-
- gemtek_pci_mute(card);
-
- v4l2_info(v4l2_dev, "Gemtek PCI Radio (rev. %d) found at 0x%04x-0x%04x.\n",
- pdev->revision, card->iobase, card->iobase + card->length - 1);
-
- return 0;
-
-err_video:
- release_region(card->iobase, card->length);
-
-err_pci:
- v4l2_device_unregister(v4l2_dev);
- kfree(card);
- return -ENODEV;
-}
-
-static void __devexit gemtek_pci_remove(struct pci_dev *pdev)
-{
- struct v4l2_device *v4l2_dev = dev_get_drvdata(&pdev->dev);
- struct gemtek_pci *card = to_gemtek_pci(v4l2_dev);
-
- video_unregister_device(&card->vdev);
- v4l2_device_unregister(v4l2_dev);
-
- release_region(card->iobase, card->length);
-
- if (mx)
- gemtek_pci_mute(card);
-
- kfree(card);
-}
-
-static struct pci_driver gemtek_pci_driver = {
- .name = "gemtek_pci",
- .id_table = gemtek_pci_id,
- .probe = gemtek_pci_probe,
- .remove = __devexit_p(gemtek_pci_remove),
-};
-
-static int __init gemtek_pci_init(void)
-{
- return pci_register_driver(&gemtek_pci_driver);
-}
-
-static void __exit gemtek_pci_exit(void)
-{
- pci_unregister_driver(&gemtek_pci_driver);
-}
-
-module_init(gemtek_pci_init);
-module_exit(gemtek_pci_exit);
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 73985f641f07..259936422e49 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -378,7 +378,7 @@ static int gemtek_probe(struct gemtek *gt)
static const struct v4l2_file_operations gemtek_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
@@ -577,12 +577,6 @@ static int __init gemtek_init(void)
gt->vdev.release = video_device_release_empty;
video_set_drvdata(&gt->vdev, gt);
- if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(gt->io, 1);
- return -EBUSY;
- }
-
/* Set defaults */
gt->lastfreq = GEMTEK_LOWFREQ;
gt->bu2614data = 0;
@@ -590,6 +584,12 @@ static int __init gemtek_init(void)
if (initmute)
gemtek_mute(gt);
+ if (video_register_device(&gt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(gt->io, 1);
+ return -EBUSY;
+ }
+
return 0;
}
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index 08f1051979ca..6af61bfeb178 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -299,7 +299,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations maestro_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maestro_ioctl_ops = {
@@ -383,22 +383,20 @@ static int __devinit maestro_probe(struct pci_dev *pdev,
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+ if (!radio_power_on(dev)) {
+ retval = -EIO;
+ goto errfr1;
+ }
+
retval = video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr);
if (retval) {
v4l2_err(v4l2_dev, "can't register video device!\n");
goto errfr1;
}
- if (!radio_power_on(dev)) {
- retval = -EIO;
- goto errunr;
- }
-
v4l2_info(v4l2_dev, "version " DRIVER_VERSION "\n");
return 0;
-errunr:
- video_unregister_device(&dev->vdev);
errfr1:
v4l2_device_unregister(v4l2_dev);
errfr:
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 4349213b403b..5c2a9058c09f 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -13,7 +13,7 @@
* anybody does please mail me.
*
* For the pdf file see:
- * http://www.semiconductors.philips.com/pip/TEA5757H/V1
+ * http://www.nxp.com/acrobat_download2/expired_datasheets/TEA5757_5759_3.pdf
*
*
* CHANGES:
@@ -77,8 +77,8 @@ MODULE_PARM_DESC(debug, "activates debug info");
/* TEA5757 pin mappings */
static const int clk = 1, data = 2, wren = 4, mo_st = 8, power = 16;
-#define FREQ_LO (50 * 16000)
-#define FREQ_HI (150 * 16000)
+#define FREQ_LO (87 * 16000)
+#define FREQ_HI (108 * 16000)
#define FREQ_IF 171200 /* 10.7*16000 */
#define FREQ_STEP 200 /* 12.5*16 */
@@ -346,7 +346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
static const struct v4l2_file_operations maxiradio_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops maxiradio_ioctl_ops = {
diff --git a/drivers/media/radio/radio-miropcm20.c b/drivers/media/radio/radio-miropcm20.c
index 4ff885445fd4..3fb76e3834c9 100644
--- a/drivers/media/radio/radio-miropcm20.c
+++ b/drivers/media/radio/radio-miropcm20.c
@@ -33,6 +33,7 @@ struct pcm20 {
unsigned long freq;
int muted;
struct snd_miro_aci *aci;
+ struct mutex lock;
};
static struct pcm20 pcm20_card = {
@@ -72,7 +73,7 @@ static int pcm20_setfreq(struct pcm20 *dev, unsigned long freq)
static const struct v4l2_file_operations pcm20_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int vidioc_querycap(struct file *file, void *priv,
@@ -229,7 +230,7 @@ static int __init pcm20_init(void)
return -ENODEV;
}
strlcpy(v4l2_dev->name, "miropcm20", sizeof(v4l2_dev->name));
-
+ mutex_init(&dev->lock);
res = v4l2_device_register(NULL, v4l2_dev);
if (res < 0) {
@@ -242,6 +243,7 @@ static int __init pcm20_init(void)
dev->vdev.fops = &pcm20_fops;
dev->vdev.ioctl_ops = &pcm20_ioctl_ops;
dev->vdev.release = video_device_release_empty;
+ dev->vdev.lock = &dev->lock;
video_set_drvdata(&dev->vdev, dev);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0)
diff --git a/drivers/media/radio/radio-mr800.c b/drivers/media/radio/radio-mr800.c
index 353b82855949..e6b2d085a449 100644
--- a/drivers/media/radio/radio-mr800.c
+++ b/drivers/media/radio/radio-mr800.c
@@ -58,7 +58,6 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
@@ -176,8 +175,6 @@ static int amradio_set_mute(struct amradio_device *radio, char argument)
int retval;
int size;
- BUG_ON(!mutex_is_locked(&radio->lock));
-
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
@@ -207,8 +204,6 @@ static int amradio_setfreq(struct amradio_device *radio, int freq)
int size;
unsigned short freq_send = 0x10 + (freq >> 3) / 25;
- BUG_ON(!mutex_is_locked(&radio->lock));
-
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
@@ -253,8 +248,6 @@ static int amradio_set_stereo(struct amradio_device *radio, char argument)
int retval;
int size;
- BUG_ON(!mutex_is_locked(&radio->lock));
-
radio->buffer[0] = 0x00;
radio->buffer[1] = 0x55;
radio->buffer[2] = 0xaa;
@@ -290,11 +283,13 @@ static void usb_amradio_disconnect(struct usb_interface *intf)
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
- radio->usbdev = NULL;
- mutex_unlock(&radio->lock);
-
+ /* increase the device node's refcount */
+ get_device(&radio->videodev.dev);
v4l2_device_disconnect(&radio->v4l2_dev);
video_unregister_device(&radio->videodev);
+ mutex_unlock(&radio->lock);
+ /* decrease the device node's refcount, allowing it to be released */
+ put_device(&radio->videodev.dev);
}
/* vidioc_querycap - query device capabilities */
@@ -503,28 +498,18 @@ out:
static int usb_amradio_open(struct file *file)
{
struct amradio_device *radio = video_drvdata(file);
- int retval = 0;
-
- mutex_lock(&radio->lock);
-
- if (!radio->usbdev) {
- retval = -EIO;
- goto unlock;
- }
+ int retval;
file->private_data = radio;
retval = usb_autopm_get_interface(radio->intf);
if (retval)
- goto unlock;
+ return retval;
if (unlikely(!radio->initialized)) {
retval = usb_amradio_init(radio);
if (retval)
usb_autopm_put_interface(radio->intf);
}
-
-unlock:
- mutex_unlock(&radio->lock);
return retval;
}
@@ -532,37 +517,10 @@ unlock:
static int usb_amradio_close(struct file *file)
{
struct amradio_device *radio = file->private_data;
- int retval = 0;
-
- mutex_lock(&radio->lock);
- if (!radio->usbdev)
- retval = -EIO;
- else
+ if (video_is_registered(&radio->videodev))
usb_autopm_put_interface(radio->intf);
-
- mutex_unlock(&radio->lock);
- return retval;
-}
-
-static long usb_amradio_ioctl(struct file *file, unsigned int cmd,
- unsigned long arg)
-{
- struct amradio_device *radio = file->private_data;
- long retval = 0;
-
- mutex_lock(&radio->lock);
-
- if (!radio->usbdev) {
- retval = -EIO;
- goto unlock;
- }
-
- retval = video_ioctl2(file, cmd, arg);
-
-unlock:
- mutex_unlock(&radio->lock);
- return retval;
+ return 0;
}
/* Suspend device - stop device. Need to be checked and fixed */
@@ -571,15 +529,13 @@ static int usb_amradio_suspend(struct usb_interface *intf, pm_message_t message)
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
-
if (!radio->muted && radio->initialized) {
amradio_set_mute(radio, AMRADIO_STOP);
radio->muted = 0;
}
+ mutex_unlock(&radio->lock);
dev_info(&intf->dev, "going into suspend..\n");
-
- mutex_unlock(&radio->lock);
return 0;
}
@@ -589,7 +545,6 @@ static int usb_amradio_resume(struct usb_interface *intf)
struct amradio_device *radio = to_amradio_dev(usb_get_intfdata(intf));
mutex_lock(&radio->lock);
-
if (unlikely(!radio->initialized))
goto unlock;
@@ -604,9 +559,9 @@ static int usb_amradio_resume(struct usb_interface *intf)
amradio_set_mute(radio, AMRADIO_START);
unlock:
- dev_info(&intf->dev, "coming out of suspend..\n");
-
mutex_unlock(&radio->lock);
+
+ dev_info(&intf->dev, "coming out of suspend..\n");
return 0;
}
@@ -615,7 +570,7 @@ static const struct v4l2_file_operations usb_amradio_fops = {
.owner = THIS_MODULE,
.open = usb_amradio_open,
.release = usb_amradio_close,
- .ioctl = usb_amradio_ioctl,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops usb_amradio_ioctl_ops = {
@@ -671,19 +626,20 @@ static int usb_amradio_probe(struct usb_interface *intf,
goto err_v4l2;
}
+ mutex_init(&radio->lock);
+
strlcpy(radio->videodev.name, radio->v4l2_dev.name,
sizeof(radio->videodev.name));
radio->videodev.v4l2_dev = &radio->v4l2_dev;
radio->videodev.fops = &usb_amradio_fops;
radio->videodev.ioctl_ops = &usb_amradio_ioctl_ops;
radio->videodev.release = usb_amradio_video_device_release;
+ radio->videodev.lock = &radio->lock;
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
radio->curfreq = 95.16 * FREQ_MUL;
- mutex_init(&radio->lock);
-
video_set_drvdata(&radio->videodev, radio);
retval = video_register_device(&radio->videodev, VFL_TYPE_RADIO,
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index a79296aac9a9..8d6ea591bd18 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -266,7 +266,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations rtrack2_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops rtrack2_ioctl_ops = {
@@ -315,6 +315,10 @@ static int __init rtrack2_init(void)
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+ /* mute card - prevents noisy bootups */
+ outb(1, dev->io);
+ dev->muted = 1;
+
mutex_init(&dev->lock);
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
@@ -324,10 +328,6 @@ static int __init rtrack2_init(void)
v4l2_info(v4l2_dev, "AIMSlab Radiotrack II card driver.\n");
- /* mute card - prevents noisy bootups */
- outb(1, dev->io);
- dev->muted = 1;
-
return 0;
}
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 985359d18aa5..b5a5f89e238a 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -260,7 +260,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations fmi_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops fmi_ioctl_ops = {
@@ -382,6 +382,9 @@ static int __init fmi_init(void)
mutex_init(&fmi->lock);
+ /* mute card - prevents noisy bootups */
+ fmi_mute(fmi);
+
if (video_register_device(&fmi->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(fmi->io, 2);
@@ -391,8 +394,6 @@ static int __init fmi_init(void)
}
v4l2_info(v4l2_dev, "card driver at 0x%x\n", fmi->io);
- /* mute card - prevents noisy bootups */
- fmi_mute(fmi);
return 0;
}
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index 52c7bbb32b8b..dc3f04c52d5e 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -376,7 +376,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations fmr2_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops fmr2_ioctl_ops = {
@@ -424,6 +424,10 @@ static int __init fmr2_init(void)
fmr2->vdev.release = video_device_release_empty;
video_set_drvdata(&fmr2->vdev, fmr2);
+ /* mute card - prevents noisy bootups */
+ fmr2_mute(fmr2->io);
+ fmr2_product_info(fmr2);
+
if (video_register_device(&fmr2->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(v4l2_dev);
release_region(fmr2->io, 2);
@@ -431,11 +435,6 @@ static int __init fmr2_init(void)
}
v4l2_info(v4l2_dev, "SF16FMR2 radio card driver at 0x%x.\n", fmr2->io);
- /* mute card - prevents noisy bootups */
- mutex_lock(&fmr2->lock);
- fmr2_mute(fmr2->io);
- fmr2_product_info(fmr2);
- mutex_unlock(&fmr2->lock);
debug_print((KERN_DEBUG "card_type %d\n", fmr2->card_type));
return 0;
}
diff --git a/drivers/media/radio/radio-si4713.c b/drivers/media/radio/radio-si4713.c
index 13554ab13f76..726d367ad8d0 100644
--- a/drivers/media/radio/radio-si4713.c
+++ b/drivers/media/radio/radio-si4713.c
@@ -53,7 +53,8 @@ struct radio_si4713_device {
/* radio_si4713_fops - file operations interface */
static const struct v4l2_file_operations radio_si4713_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ /* Note: locking is done at the subdev level in the i2c driver. */
+ .unlocked_ioctl = video_ioctl2,
};
/* Video4Linux Interface */
@@ -291,19 +292,19 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
goto unregister_v4l2_dev;
}
- sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter, "si4713_i2c",
+ sd = v4l2_i2c_new_subdev_board(&rsdev->v4l2_dev, adapter,
pdata->subdev_board_info, NULL);
if (!sd) {
dev_err(&pdev->dev, "Cannot get v4l2 subdevice\n");
rval = -ENODEV;
- goto unregister_v4l2_dev;
+ goto put_adapter;
}
rsdev->radio_dev = video_device_alloc();
if (!rsdev->radio_dev) {
dev_err(&pdev->dev, "Failed to alloc video device.\n");
rval = -ENOMEM;
- goto unregister_v4l2_dev;
+ goto put_adapter;
}
memcpy(rsdev->radio_dev, &radio_si4713_vdev_template,
@@ -320,6 +321,8 @@ static int radio_si4713_pdriver_probe(struct platform_device *pdev)
free_vdev:
video_device_release(rsdev->radio_dev);
+put_adapter:
+ i2c_put_adapter(adapter);
unregister_v4l2_dev:
v4l2_device_unregister(&rsdev->v4l2_dev);
free_rsdev:
@@ -335,8 +338,12 @@ static int __exit radio_si4713_pdriver_remove(struct platform_device *pdev)
struct radio_si4713_device *rsdev = container_of(v4l2_dev,
struct radio_si4713_device,
v4l2_dev);
+ struct v4l2_subdev *sd = list_entry(v4l2_dev->subdevs.next,
+ struct v4l2_subdev, list);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
video_unregister_device(rsdev->radio_dev);
+ i2c_put_adapter(client->adapter);
v4l2_device_unregister(&rsdev->v4l2_dev);
kfree(rsdev);
diff --git a/drivers/media/radio/radio-tea5764.c b/drivers/media/radio/radio-tea5764.c
index 789d2ec66e19..0e71d816c725 100644
--- a/drivers/media/radio/radio-tea5764.c
+++ b/drivers/media/radio/radio-tea5764.c
@@ -142,7 +142,6 @@ struct tea5764_device {
struct video_device *videodev;
struct tea5764_regs regs;
struct mutex mutex;
- int users;
};
/* I2C code related */
@@ -458,41 +457,10 @@ static int vidioc_s_audio(struct file *file, void *priv,
return 0;
}
-static int tea5764_open(struct file *file)
-{
- /* Currently we support only one device */
- struct tea5764_device *radio = video_drvdata(file);
-
- 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,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops tea5764_ioctl_ops = {
@@ -527,7 +495,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
int ret;
PDEBUG("probe");
- radio = kmalloc(sizeof(struct tea5764_device), GFP_KERNEL);
+ radio = kzalloc(sizeof(struct tea5764_device), GFP_KERNEL);
if (!radio)
return -ENOMEM;
@@ -555,12 +523,7 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
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;
- }
+ radio->videodev->lock = &radio->mutex;
/* initialize and power off the chip */
tea5764_i2c_read(radio);
@@ -568,6 +531,12 @@ static int __devinit tea5764_i2c_probe(struct i2c_client *client,
tea5764_mute(radio, 1);
tea5764_power_down(radio);
+ ret = video_register_device(radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (ret < 0) {
+ PWARN("Could not register video device!");
+ goto errrel;
+ }
+
PINFO("registered.");
return 0;
errrel:
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index fc1c860fd438..a32663917059 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -338,7 +338,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations terratec_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops terratec_ioctl_ops = {
@@ -389,6 +389,9 @@ static int __init terratec_init(void)
mutex_init(&tt->lock);
+ /* mute card - prevents noisy bootups */
+ tt_write_vol(tt, 0);
+
if (video_register_device(&tt->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&tt->v4l2_dev);
release_region(tt->io, 2);
@@ -396,9 +399,6 @@ static int __init terratec_init(void)
}
v4l2_info(v4l2_dev, "TERRATEC ActivRadio Standalone card driver.\n");
-
- /* mute card - prevents noisy bootups */
- tt_write_vol(tt, 0);
return 0;
}
diff --git a/drivers/media/radio/radio-timb.c b/drivers/media/radio/radio-timb.c
index b8bb3ef47df5..a185610b376b 100644
--- a/drivers/media/radio/radio-timb.c
+++ b/drivers/media/radio/radio-timb.c
@@ -34,6 +34,7 @@ struct timbradio {
struct v4l2_subdev *sd_dsp;
struct video_device video_dev;
struct v4l2_device v4l2_dev;
+ struct mutex lock;
};
@@ -142,7 +143,7 @@ static const struct v4l2_ioctl_ops timbradio_ioctl_ops = {
static const struct v4l2_file_operations timbradio_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static int __devinit timbradio_probe(struct platform_device *pdev)
@@ -164,6 +165,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
}
tr->pdata = *pdata;
+ mutex_init(&tr->lock);
strlcpy(tr->video_dev.name, "Timberdale Radio",
sizeof(tr->video_dev.name));
@@ -171,6 +173,7 @@ static int __devinit timbradio_probe(struct platform_device *pdev)
tr->video_dev.ioctl_ops = &timbradio_ioctl_ops;
tr->video_dev.release = video_device_release_empty;
tr->video_dev.minor = -1;
+ tr->video_dev.lock = &tr->lock;
strlcpy(tr->v4l2_dev.name, DRIVER_NAME, sizeof(tr->v4l2_dev.name));
err = v4l2_device_register(NULL, &tr->v4l2_dev);
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index 9d6dcf8af5b0..22fa9cc28abe 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -344,7 +344,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations trust_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops trust_ioctl_ops = {
@@ -396,14 +396,6 @@ static int __init trust_init(void)
tr->vdev.release = video_device_release_empty;
video_set_drvdata(&tr->vdev, tr);
- if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(tr->io, 2);
- return -EINVAL;
- }
-
- v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
-
write_i2c(tr, 2, TDA7318_ADDR, 0x80); /* speaker att. LF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xa0); /* speaker att. RF = 0 dB */
write_i2c(tr, 2, TDA7318_ADDR, 0xc0); /* speaker att. LR = 0 dB */
@@ -418,6 +410,14 @@ static int __init trust_init(void)
/* mute card - prevents noisy bootups */
tr_setmute(tr, 1);
+ if (video_register_device(&tr->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(tr->io, 2);
+ return -EINVAL;
+ }
+
+ v4l2_info(v4l2_dev, "Trust FM Radio card driver v1.0.\n");
+
return 0;
}
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 03439282dfce..8dbbf08f2207 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -1,9 +1,6 @@
/* Typhoon Radio Card driver for radio support
* (c) 1999 Dr. Henrik Seidel <Henrik.Seidel@gmx.de>
*
- * Card manufacturer:
- * http://194.18.155.92/idc/prod2.idc?nr=50753&lang=e
- *
* Notes on the hardware
*
* This card has two output sockets, one for speakers and one for line.
@@ -320,7 +317,7 @@ static int vidioc_log_status(struct file *file, void *priv)
static const struct v4l2_file_operations typhoon_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops typhoon_ioctl_ops = {
@@ -347,18 +344,18 @@ static int __init typhoon_init(void)
strlcpy(v4l2_dev->name, "typhoon", sizeof(v4l2_dev->name));
dev->io = io;
- dev->curfreq = dev->mutefreq = mutefreq;
if (dev->io == -1) {
v4l2_err(v4l2_dev, "You must set an I/O address with io=0x316 or io=0x336\n");
return -EINVAL;
}
- if (dev->mutefreq < 87000 || dev->mutefreq > 108500) {
+ if (mutefreq < 87000 || mutefreq > 108500) {
v4l2_err(v4l2_dev, "You must set a frequency (in kHz) used when muting the card,\n");
v4l2_err(v4l2_dev, "e.g. with \"mutefreq=87500\" (87000 <= mutefreq <= 108500)\n");
return -EINVAL;
}
+ dev->curfreq = dev->mutefreq = mutefreq << 4;
mutex_init(&dev->lock);
if (!request_region(dev->io, 8, "typhoon")) {
@@ -381,17 +378,17 @@ static int __init typhoon_init(void)
dev->vdev.ioctl_ops = &typhoon_ioctl_ops;
dev->vdev.release = video_device_release_empty;
video_set_drvdata(&dev->vdev, dev);
+
+ /* mute card - prevents noisy bootups */
+ typhoon_mute(dev);
+
if (video_register_device(&dev->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
v4l2_device_unregister(&dev->v4l2_dev);
release_region(dev->io, 8);
return -EINVAL;
}
v4l2_info(v4l2_dev, "port 0x%x.\n", dev->io);
- v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", dev->mutefreq);
- dev->mutefreq <<= 4;
-
- /* mute card - prevents noisy bootups */
- typhoon_mute(dev);
+ v4l2_info(v4l2_dev, "mute frequency is %lu kHz.\n", mutefreq);
return 0;
}
diff --git a/drivers/media/radio/radio-wl1273.c b/drivers/media/radio/radio-wl1273.c
new file mode 100644
index 000000000000..7ecc8e657663
--- /dev/null
+++ b/drivers/media/radio/radio-wl1273.c
@@ -0,0 +1,2330 @@
+/*
+ * Driver for the Texas Instruments WL1273 FM radio.
+ *
+ * Copyright (C) 2010 Nokia Corporation
+ * Author: Matti J. Aaltonen <matti.j.aaltonen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * 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/delay.h>
+#include <linux/firmware.h>
+#include <linux/interrupt.h>
+#include <linux/mfd/wl1273-core.h>
+#include <linux/slab.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+
+#define DRIVER_DESC "Wl1273 FM Radio"
+
+#define WL1273_POWER_SET_OFF 0
+#define WL1273_POWER_SET_FM BIT(0)
+#define WL1273_POWER_SET_RDS BIT(1)
+#define WL1273_POWER_SET_RETENTION BIT(4)
+
+#define WL1273_PUPD_SET_OFF 0x00
+#define WL1273_PUPD_SET_ON 0x01
+#define WL1273_PUPD_SET_RETENTION 0x10
+
+#define WL1273_FREQ(x) (x * 10000 / 625)
+#define WL1273_INV_FREQ(x) (x * 625 / 10000)
+
+/*
+ * static int radio_nr - The number of the radio device
+ *
+ * The default is 0.
+ */
+static int radio_nr;
+module_param(radio_nr, int, 0);
+MODULE_PARM_DESC(radio_nr, "The number of the radio device. Default = 0");
+
+struct wl1273_device {
+ char *bus_type;
+
+ u8 forbidden;
+ unsigned int preemphasis;
+ unsigned int spacing;
+ unsigned int tx_power;
+ unsigned int rx_frequency;
+ unsigned int tx_frequency;
+ unsigned int rangelow;
+ unsigned int rangehigh;
+ unsigned int band;
+ bool stereo;
+
+ /* RDS */
+ unsigned int rds_on;
+ struct delayed_work work;
+
+ wait_queue_head_t read_queue;
+ struct mutex lock; /* for serializing fm radio operations */
+ struct completion busy;
+
+ unsigned char *buffer;
+ unsigned int buf_size;
+ unsigned int rd_index;
+ unsigned int wr_index;
+
+ /* Selected interrupts */
+ u16 irq_flags;
+ u16 irq_received;
+
+ struct v4l2_ctrl_handler ctrl_handler;
+ struct v4l2_device v4l2dev;
+ struct video_device videodev;
+ struct device *dev;
+ struct wl1273_core *core;
+ struct file *owner;
+ char *write_buf;
+ unsigned int rds_users;
+};
+
+#define WL1273_IRQ_MASK (WL1273_FR_EVENT | \
+ WL1273_POW_ENB_EVENT)
+
+/*
+ * static unsigned int rds_buf - the number of RDS buffer blocks used.
+ *
+ * The default number is 100.
+ */
+static unsigned int rds_buf = 100;
+module_param(rds_buf, uint, 0);
+MODULE_PARM_DESC(rds_buf, "Number of RDS buffer entries. Default = 100");
+
+static int wl1273_fm_read_reg(struct wl1273_core *core, u8 reg, u16 *value)
+{
+ struct i2c_client *client = core->client;
+ u8 b[2];
+ int r;
+
+ r = i2c_smbus_read_i2c_block_data(client, reg, sizeof(b), b);
+ if (r != 2) {
+ dev_err(&client->dev, "%s: Read: %d fails.\n", __func__, reg);
+ return -EREMOTEIO;
+ }
+
+ *value = (u16)b[0] << 8 | b[1];
+
+ return 0;
+}
+
+static int wl1273_fm_write_cmd(struct wl1273_core *core, u8 cmd, u16 param)
+{
+ struct i2c_client *client = core->client;
+ u8 buf[] = { (param >> 8) & 0xff, param & 0xff };
+ int r;
+
+ r = i2c_smbus_write_i2c_block_data(client, cmd, sizeof(buf), buf);
+ if (r) {
+ dev_err(&client->dev, "%s: Cmd: %d fails.\n", __func__, cmd);
+ return r;
+ }
+
+ return 0;
+}
+
+static int wl1273_fm_write_data(struct wl1273_core *core, u8 *data, u16 len)
+{
+ struct i2c_client *client = core->client;
+ struct i2c_msg msg;
+ int r;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+ msg.buf = data;
+ msg.len = len;
+
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r != 1) {
+ dev_err(&client->dev, "%s: write error.\n", __func__);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int wl1273_fm_write_fw(struct wl1273_core *core,
+ __u8 *fw, int len)
+{
+ struct i2c_client *client = core->client;
+ struct i2c_msg msg;
+ int i, r = 0;
+
+ msg.addr = client->addr;
+ msg.flags = 0;
+
+ for (i = 0; i <= len; i++) {
+ msg.len = fw[0];
+ msg.buf = fw + 1;
+
+ fw += msg.len + 1;
+ dev_dbg(&client->dev, "%s:len[%d]: %d\n", __func__, i, msg.len);
+
+ r = i2c_transfer(client->adapter, &msg, 1);
+ if (r < 0 && i < len + 1)
+ break;
+ }
+
+ dev_dbg(&client->dev, "%s: i: %d\n", __func__, i);
+ dev_dbg(&client->dev, "%s: len + 1: %d\n", __func__, len + 1);
+
+ /* Last transfer always fails. */
+ if (i == len || r == 1)
+ r = 0;
+
+ return r;
+}
+
+/**
+ * wl1273_fm_set_audio() - Set audio mode.
+ * @core: A pointer to the device struct.
+ * @new_mode: The new audio mode.
+ *
+ * Audio modes are WL1273_AUDIO_DIGITAL and WL1273_AUDIO_ANALOG.
+ */
+static int wl1273_fm_set_audio(struct wl1273_core *core, unsigned int new_mode)
+{
+ int r = 0;
+
+ if (core->mode == WL1273_MODE_OFF ||
+ core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ if (core->mode == WL1273_MODE_RX && new_mode == WL1273_AUDIO_DIGITAL) {
+ r = wl1273_fm_write_cmd(core, WL1273_PCM_MODE_SET,
+ WL1273_PCM_DEF_MODE);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
+ core->i2s_mode);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+ WL1273_AUDIO_ENABLE_I2S);
+ if (r)
+ goto out;
+
+ } else if (core->mode == WL1273_MODE_RX &&
+ new_mode == WL1273_AUDIO_ANALOG) {
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_ENABLE,
+ WL1273_AUDIO_ENABLE_ANALOG);
+ if (r)
+ goto out;
+
+ } else if (core->mode == WL1273_MODE_TX &&
+ new_mode == WL1273_AUDIO_DIGITAL) {
+ r = wl1273_fm_write_cmd(core, WL1273_I2S_MODE_CONFIG_SET,
+ core->i2s_mode);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
+ WL1273_AUDIO_IO_SET_I2S);
+ if (r)
+ goto out;
+
+ } else if (core->mode == WL1273_MODE_TX &&
+ new_mode == WL1273_AUDIO_ANALOG) {
+ r = wl1273_fm_write_cmd(core, WL1273_AUDIO_IO_SET,
+ WL1273_AUDIO_IO_SET_ANALOG);
+ if (r)
+ goto out;
+ }
+
+ core->audio_mode = new_mode;
+out:
+ return r;
+}
+
+/**
+ * wl1273_fm_set_volume() - Set volume.
+ * @core: A pointer to the device struct.
+ * @volume: The new volume value.
+ */
+static int wl1273_fm_set_volume(struct wl1273_core *core, unsigned int volume)
+{
+ u16 val;
+ int r;
+
+ if (volume > WL1273_MAX_VOLUME)
+ return -EINVAL;
+
+ if (core->volume == volume)
+ return 0;
+
+ val = volume;
+ r = wl1273_fm_read_reg(core, WL1273_VOLUME_SET, &val);
+ if (r)
+ return r;
+
+ core->volume = volume;
+ return 0;
+}
+
+#define WL1273_FIFO_HAS_DATA(status) (1 << 5 & status)
+#define WL1273_RDS_CORRECTABLE_ERROR (1 << 3)
+#define WL1273_RDS_UNCORRECTABLE_ERROR (1 << 4)
+
+static int wl1273_fm_rds(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ struct i2c_client *client = core->client;
+ u16 val;
+ u8 b0 = WL1273_RDS_DATA_GET, status;
+ struct v4l2_rds_data rds = { 0, 0, 0 };
+ struct i2c_msg msg[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .buf = &b0,
+ .len = 1,
+ },
+ {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .buf = (u8 *) &rds,
+ .len = sizeof(rds),
+ }
+ };
+ int r;
+
+ if (core->mode != WL1273_MODE_RX)
+ return 0;
+
+ r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+ if (r)
+ return r;
+
+ if ((val & 0x01) == 0) {
+ /* RDS decoder not synchronized */
+ return -EAGAIN;
+ }
+
+ /* copy all four RDS blocks to internal buffer */
+ do {
+ r = i2c_transfer(client->adapter, msg, ARRAY_SIZE(msg));
+ if (r != ARRAY_SIZE(msg)) {
+ dev_err(radio->dev, WL1273_FM_DRIVER_NAME
+ ": %s: read_rds error r == %i)\n",
+ __func__, r);
+ }
+
+ status = rds.block;
+
+ if (!WL1273_FIFO_HAS_DATA(status))
+ break;
+
+ /* copy bits 0-2 (the block ID) to bits 3-5 */
+ rds.block = V4L2_RDS_BLOCK_MSK & status;
+ rds.block |= rds.block << 3;
+
+ /* copy the error bits to standard positions */
+ if (WL1273_RDS_UNCORRECTABLE_ERROR & status) {
+ rds.block |= V4L2_RDS_BLOCK_ERROR;
+ rds.block &= ~V4L2_RDS_BLOCK_CORRECTED;
+ } else if (WL1273_RDS_CORRECTABLE_ERROR & status) {
+ rds.block &= ~V4L2_RDS_BLOCK_ERROR;
+ rds.block |= V4L2_RDS_BLOCK_CORRECTED;
+ }
+
+ /* copy RDS block to internal buffer */
+ memcpy(&radio->buffer[radio->wr_index], &rds, RDS_BLOCK_SIZE);
+ radio->wr_index += 3;
+
+ /* wrap write pointer */
+ if (radio->wr_index >= radio->buf_size)
+ radio->wr_index = 0;
+
+ /* check for overflow & start over */
+ if (radio->wr_index == radio->rd_index) {
+ dev_dbg(radio->dev, "RDS OVERFLOW");
+
+ radio->rd_index = 0;
+ radio->wr_index = 0;
+ break;
+ }
+ } while (WL1273_FIFO_HAS_DATA(status));
+
+ /* wake up read queue */
+ if (radio->wr_index != radio->rd_index)
+ wake_up_interruptible(&radio->read_queue);
+
+ return 0;
+}
+
+static irqreturn_t wl1273_fm_irq_thread_handler(int irq, void *dev_id)
+{
+ struct wl1273_device *radio = dev_id;
+ struct wl1273_core *core = radio->core;
+ u16 flags;
+ int r;
+
+ r = wl1273_fm_read_reg(core, WL1273_FLAG_GET, &flags);
+ if (r)
+ goto out;
+
+ if (flags & WL1273_BL_EVENT) {
+ radio->irq_received = flags;
+ dev_dbg(radio->dev, "IRQ: BL\n");
+ }
+
+ if (flags & WL1273_RDS_EVENT) {
+ msleep(200);
+
+ wl1273_fm_rds(radio);
+ }
+
+ if (flags & WL1273_BBLK_EVENT)
+ dev_dbg(radio->dev, "IRQ: BBLK\n");
+
+ if (flags & WL1273_LSYNC_EVENT)
+ dev_dbg(radio->dev, "IRQ: LSYNC\n");
+
+ if (flags & WL1273_LEV_EVENT) {
+ u16 level;
+
+ r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &level);
+ if (r)
+ goto out;
+
+ if (level > 14)
+ dev_dbg(radio->dev, "IRQ: LEV: 0x%x04\n", level);
+ }
+
+ if (flags & WL1273_IFFR_EVENT)
+ dev_dbg(radio->dev, "IRQ: IFFR\n");
+
+ if (flags & WL1273_PI_EVENT)
+ dev_dbg(radio->dev, "IRQ: PI\n");
+
+ if (flags & WL1273_PD_EVENT)
+ dev_dbg(radio->dev, "IRQ: PD\n");
+
+ if (flags & WL1273_STIC_EVENT)
+ dev_dbg(radio->dev, "IRQ: STIC\n");
+
+ if (flags & WL1273_MAL_EVENT)
+ dev_dbg(radio->dev, "IRQ: MAL\n");
+
+ if (flags & WL1273_POW_ENB_EVENT) {
+ complete(&radio->busy);
+ dev_dbg(radio->dev, "NOT BUSY\n");
+ dev_dbg(radio->dev, "IRQ: POW_ENB\n");
+ }
+
+ if (flags & WL1273_SCAN_OVER_EVENT)
+ dev_dbg(radio->dev, "IRQ: SCAN_OVER\n");
+
+ if (flags & WL1273_ERROR_EVENT)
+ dev_dbg(radio->dev, "IRQ: ERROR\n");
+
+ if (flags & WL1273_FR_EVENT) {
+ u16 freq;
+
+ dev_dbg(radio->dev, "IRQ: FR:\n");
+
+ if (core->mode == WL1273_MODE_RX) {
+ r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
+ TUNER_MODE_STOP_SEARCH);
+ if (r) {
+ dev_err(radio->dev,
+ "%s: TUNER_MODE_SET fails: %d\n",
+ __func__, r);
+ goto out;
+ }
+
+ r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &freq);
+ if (r)
+ goto out;
+
+ if (radio->band == WL1273_BAND_JAPAN)
+ radio->rx_frequency = WL1273_BAND_JAPAN_LOW +
+ freq * 50;
+ else
+ radio->rx_frequency = WL1273_BAND_OTHER_LOW +
+ freq * 50;
+ /*
+ * The driver works better with this msleep,
+ * the documentation doesn't mention it.
+ */
+ usleep_range(10000, 15000);
+
+ dev_dbg(radio->dev, "%dkHz\n", radio->rx_frequency);
+
+ } else {
+ r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &freq);
+ if (r)
+ goto out;
+
+ dev_dbg(radio->dev, "%dkHz\n", freq);
+ }
+ dev_dbg(radio->dev, "%s: NOT BUSY\n", __func__);
+ }
+
+out:
+ wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
+ radio->irq_flags);
+ complete(&radio->busy);
+
+ return IRQ_HANDLED;
+}
+
+static int wl1273_fm_set_tx_freq(struct wl1273_device *radio, unsigned int freq)
+{
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ if (freq < WL1273_BAND_TX_LOW) {
+ dev_err(radio->dev,
+ "Frequency out of range: %d < %d\n", freq,
+ WL1273_BAND_TX_LOW);
+ return -ERANGE;
+ }
+
+ if (freq > WL1273_BAND_TX_HIGH) {
+ dev_err(radio->dev,
+ "Frequency out of range: %d > %d\n", freq,
+ WL1273_BAND_TX_HIGH);
+ return -ERANGE;
+ }
+
+ /*
+ * The driver works better with this sleep,
+ * the documentation doesn't mention it.
+ */
+ usleep_range(5000, 10000);
+
+ dev_dbg(radio->dev, "%s: freq: %d kHz\n", __func__, freq);
+
+ /* Set the current tx channel */
+ r = wl1273_fm_write_cmd(core, WL1273_CHANL_SET, freq / 10);
+ if (r)
+ return r;
+
+ INIT_COMPLETION(radio->busy);
+
+ /* wait for the FR IRQ */
+ r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000));
+ if (!r)
+ return -ETIMEDOUT;
+
+ dev_dbg(radio->dev, "WL1273_CHANL_SET: %d\n", r);
+
+ /* Enable the output power */
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_ENB_SET, 1);
+ if (r)
+ return r;
+
+ INIT_COMPLETION(radio->busy);
+
+ /* wait for the POWER_ENB IRQ */
+ r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
+ if (!r)
+ return -ETIMEDOUT;
+
+ radio->tx_frequency = freq;
+ dev_dbg(radio->dev, "WL1273_POWER_ENB_SET: %d\n", r);
+
+ return 0;
+}
+
+static int wl1273_fm_set_rx_freq(struct wl1273_device *radio, unsigned int freq)
+{
+ struct wl1273_core *core = radio->core;
+ int r, f;
+
+ if (freq < radio->rangelow) {
+ dev_err(radio->dev,
+ "Frequency out of range: %d < %d\n", freq,
+ radio->rangelow);
+ r = -ERANGE;
+ goto err;
+ }
+
+ if (freq > radio->rangehigh) {
+ dev_err(radio->dev,
+ "Frequency out of range: %d > %d\n", freq,
+ radio->rangehigh);
+ r = -ERANGE;
+ goto err;
+ }
+
+ dev_dbg(radio->dev, "%s: %dkHz\n", __func__, freq);
+
+ wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+
+ if (radio->band == WL1273_BAND_JAPAN)
+ f = (freq - WL1273_BAND_JAPAN_LOW) / 50;
+ else
+ f = (freq - WL1273_BAND_OTHER_LOW) / 50;
+
+ r = wl1273_fm_write_cmd(core, WL1273_FREQ_SET, f);
+ if (r) {
+ dev_err(radio->dev, "FREQ_SET fails\n");
+ goto err;
+ }
+
+ r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET, TUNER_MODE_PRESET);
+ if (r) {
+ dev_err(radio->dev, "TUNER_MODE_SET fails\n");
+ goto err;
+ }
+
+ INIT_COMPLETION(radio->busy);
+
+ r = wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(2000));
+ if (!r) {
+ dev_err(radio->dev, "%s: TIMEOUT\n", __func__);
+ return -ETIMEDOUT;
+ }
+
+ radio->rd_index = 0;
+ radio->wr_index = 0;
+ radio->rx_frequency = freq;
+ return 0;
+err:
+ return r;
+}
+
+static int wl1273_fm_get_freq(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ unsigned int freq;
+ u16 f;
+ int r;
+
+ if (core->mode == WL1273_MODE_RX) {
+ r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &f);
+ if (r)
+ return r;
+
+ dev_dbg(radio->dev, "Freq get: 0x%04x\n", f);
+ if (radio->band == WL1273_BAND_JAPAN)
+ freq = WL1273_BAND_JAPAN_LOW + 50 * f;
+ else
+ freq = WL1273_BAND_OTHER_LOW + 50 * f;
+ } else {
+ r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &f);
+ if (r)
+ return r;
+
+ freq = f * 10;
+ }
+
+ return freq;
+}
+
+/**
+ * wl1273_fm_upload_firmware_patch() - Upload the firmware.
+ * @radio: A pointer to the device struct.
+ *
+ * The firmware file consists of arrays of bytes where the first byte
+ * gives the array length. The first byte in the file gives the
+ * number of these arrays.
+ */
+static int wl1273_fm_upload_firmware_patch(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ unsigned int packet_num;
+ const struct firmware *fw_p;
+ const char *fw_name = "radio-wl1273-fw.bin";
+ struct device *dev = radio->dev;
+ __u8 *ptr;
+ int r;
+
+ dev_dbg(dev, "%s:\n", __func__);
+
+ /*
+ * Uploading the firmware patch is not always necessary,
+ * so we only print an info message.
+ */
+ if (request_firmware(&fw_p, fw_name, dev)) {
+ dev_info(dev, "%s - %s not found\n", __func__, fw_name);
+
+ return 0;
+ }
+
+ ptr = (__u8 *) fw_p->data;
+ packet_num = ptr[0];
+ dev_dbg(dev, "%s: packets: %d\n", __func__, packet_num);
+
+ r = wl1273_fm_write_fw(core, ptr + 1, packet_num);
+ if (r) {
+ dev_err(dev, "FW upload error: %d\n", r);
+ goto out;
+ }
+
+ /* ignore possible error here */
+ wl1273_fm_write_cmd(core, WL1273_RESET, 0);
+
+ dev_dbg(dev, "%s - download OK, r: %d\n", __func__, r);
+out:
+ release_firmware(fw_p);
+ return r;
+}
+
+static int wl1273_fm_stop(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+
+ if (core->mode == WL1273_MODE_RX) {
+ int r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+ WL1273_POWER_SET_OFF);
+ if (r)
+ dev_err(radio->dev, "%s: POWER_SET fails: %d\n",
+ __func__, r);
+ } else if (core->mode == WL1273_MODE_TX) {
+ int r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_OFF);
+ if (r)
+ dev_err(radio->dev,
+ "%s: PUPD_SET fails: %d\n", __func__, r);
+ }
+
+ if (core->pdata->disable) {
+ core->pdata->disable();
+ dev_dbg(radio->dev, "Back to reset\n");
+ }
+
+ return 0;
+}
+
+static int wl1273_fm_start(struct wl1273_device *radio, int new_mode)
+{
+ struct wl1273_core *core = radio->core;
+ struct wl1273_fm_platform_data *pdata = core->pdata;
+ struct device *dev = radio->dev;
+ int r = -EINVAL;
+
+ if (pdata->enable && core->mode == WL1273_MODE_OFF) {
+ dev_dbg(radio->dev, "Out of reset\n");
+
+ pdata->enable();
+ msleep(250);
+ }
+
+ if (new_mode == WL1273_MODE_RX) {
+ u16 val = WL1273_POWER_SET_FM;
+
+ if (radio->rds_on)
+ val |= WL1273_POWER_SET_RDS;
+
+ /* If this fails try again */
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+ if (r) {
+ msleep(100);
+
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+ if (r) {
+ dev_err(dev, "%s: POWER_SET fails\n", __func__);
+ goto fail;
+ }
+ }
+
+ /* rds buffer configuration */
+ radio->wr_index = 0;
+ radio->rd_index = 0;
+
+ } else if (new_mode == WL1273_MODE_TX) {
+ /* If this fails try again once */
+ r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_ON);
+ if (r) {
+ msleep(100);
+ r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_ON);
+ if (r) {
+ dev_err(dev, "%s: PUPD_SET fails\n", __func__);
+ goto fail;
+ }
+ }
+
+ if (radio->rds_on)
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 1);
+ else
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 0);
+ } else {
+ dev_warn(dev, "%s: Illegal mode.\n", __func__);
+ }
+
+ if (core->mode == WL1273_MODE_OFF) {
+ r = wl1273_fm_upload_firmware_patch(radio);
+ if (r)
+ dev_warn(dev, "Firmware upload failed.\n");
+
+ /*
+ * Sometimes the chip is in a wrong power state at this point.
+ * So we set the power once again.
+ */
+ if (new_mode == WL1273_MODE_RX) {
+ u16 val = WL1273_POWER_SET_FM;
+
+ if (radio->rds_on)
+ val |= WL1273_POWER_SET_RDS;
+
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, val);
+ if (r) {
+ dev_err(dev, "%s: POWER_SET fails\n", __func__);
+ goto fail;
+ }
+ } else if (new_mode == WL1273_MODE_TX) {
+ r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_ON);
+ if (r) {
+ dev_err(dev, "%s: PUPD_SET fails\n", __func__);
+ goto fail;
+ }
+ }
+ }
+
+ return 0;
+fail:
+ if (pdata->disable)
+ pdata->disable();
+
+ dev_dbg(dev, "%s: return: %d\n", __func__, r);
+ return r;
+}
+
+static int wl1273_fm_suspend(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ /* Cannot go from OFF to SUSPENDED */
+ if (core->mode == WL1273_MODE_RX)
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+ WL1273_POWER_SET_RETENTION);
+ else if (core->mode == WL1273_MODE_TX)
+ r = wl1273_fm_write_cmd(core, WL1273_PUPD_SET,
+ WL1273_PUPD_SET_RETENTION);
+ else
+ r = -EINVAL;
+
+ if (r) {
+ dev_err(radio->dev, "%s: POWER_SET fails: %d\n", __func__, r);
+ goto out;
+ }
+
+out:
+ return r;
+}
+
+static int wl1273_fm_set_mode(struct wl1273_device *radio, int mode)
+{
+ struct wl1273_core *core = radio->core;
+ struct device *dev = radio->dev;
+ int old_mode;
+ int r;
+
+ dev_dbg(dev, "%s\n", __func__);
+ dev_dbg(dev, "Forbidden modes: 0x%02x\n", radio->forbidden);
+
+ old_mode = core->mode;
+ if (mode & radio->forbidden) {
+ r = -EPERM;
+ goto out;
+ }
+
+ switch (mode) {
+ case WL1273_MODE_RX:
+ case WL1273_MODE_TX:
+ r = wl1273_fm_start(radio, mode);
+ if (r) {
+ dev_err(dev, "%s: Cannot start.\n", __func__);
+ wl1273_fm_stop(radio);
+ goto out;
+ }
+
+ core->mode = mode;
+ r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
+ radio->irq_flags);
+ if (r) {
+ dev_err(dev, "INT_MASK_SET fails.\n");
+ goto out;
+ }
+
+ /* remember previous settings */
+ if (mode == WL1273_MODE_RX) {
+ r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency);
+ if (r) {
+ dev_err(dev, "set freq fails: %d.\n", r);
+ goto out;
+ }
+
+ r = core->set_volume(core, core->volume);
+ if (r) {
+ dev_err(dev, "set volume fails: %d.\n", r);
+ goto out;
+ }
+
+ dev_dbg(dev, "%s: Set vol: %d.\n", __func__,
+ core->volume);
+ } else {
+ r = wl1273_fm_set_tx_freq(radio, radio->tx_frequency);
+ if (r) {
+ dev_err(dev, "set freq fails: %d.\n", r);
+ goto out;
+ }
+ }
+
+ dev_dbg(radio->dev, "%s: Set audio mode.\n", __func__);
+
+ r = core->set_audio(core, core->audio_mode);
+ if (r)
+ dev_err(dev, "Cannot set audio mode.\n");
+ break;
+
+ case WL1273_MODE_OFF:
+ r = wl1273_fm_stop(radio);
+ if (r)
+ dev_err(dev, "%s: Off fails: %d\n", __func__, r);
+ else
+ core->mode = WL1273_MODE_OFF;
+
+ break;
+
+ case WL1273_MODE_SUSPENDED:
+ r = wl1273_fm_suspend(radio);
+ if (r)
+ dev_err(dev, "%s: Suspend fails: %d\n", __func__, r);
+ else
+ core->mode = WL1273_MODE_SUSPENDED;
+
+ break;
+
+ default:
+ dev_err(dev, "%s: Unknown mode: %d\n", __func__, mode);
+ r = -EINVAL;
+ break;
+ }
+out:
+ if (r)
+ core->mode = old_mode;
+
+ return r;
+}
+
+static int wl1273_fm_set_seek(struct wl1273_device *radio,
+ unsigned int wrap_around,
+ unsigned int seek_upward,
+ int level)
+{
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+ unsigned int dir = (seek_upward == 0) ? 0 : 1;
+ unsigned int f;
+
+ f = radio->rx_frequency;
+ dev_dbg(radio->dev, "rx_frequency: %d\n", f);
+
+ if (dir && f + radio->spacing <= radio->rangehigh)
+ r = wl1273_fm_set_rx_freq(radio, f + radio->spacing);
+ else if (dir && wrap_around)
+ r = wl1273_fm_set_rx_freq(radio, radio->rangelow);
+ else if (f - radio->spacing >= radio->rangelow)
+ r = wl1273_fm_set_rx_freq(radio, f - radio->spacing);
+ else if (wrap_around)
+ r = wl1273_fm_set_rx_freq(radio, radio->rangehigh);
+
+ if (r)
+ goto out;
+
+ if (level < SCHAR_MIN || level > SCHAR_MAX)
+ return -EINVAL;
+
+ INIT_COMPLETION(radio->busy);
+ dev_dbg(radio->dev, "%s: BUSY\n", __func__);
+
+ r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+ if (r)
+ goto out;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ r = wl1273_fm_write_cmd(core, WL1273_SEARCH_LVL_SET, level);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_SEARCH_DIR_SET, dir);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
+ TUNER_MODE_AUTO_SEEK);
+ if (r)
+ goto out;
+
+ wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
+ if (!(radio->irq_received & WL1273_BL_EVENT))
+ goto out;
+
+ radio->irq_received &= ~WL1273_BL_EVENT;
+
+ if (!wrap_around)
+ goto out;
+
+ /* Wrap around */
+ dev_dbg(radio->dev, "Wrap around in HW seek.\n");
+
+ if (seek_upward)
+ f = radio->rangelow;
+ else
+ f = radio->rangehigh;
+
+ r = wl1273_fm_set_rx_freq(radio, f);
+ if (r)
+ goto out;
+
+ INIT_COMPLETION(radio->busy);
+ dev_dbg(radio->dev, "%s: BUSY\n", __func__);
+
+ r = wl1273_fm_write_cmd(core, WL1273_TUNER_MODE_SET,
+ TUNER_MODE_AUTO_SEEK);
+ if (r)
+ goto out;
+
+ wait_for_completion_timeout(&radio->busy, msecs_to_jiffies(1000));
+out:
+ dev_dbg(radio->dev, "%s: Err: %d\n", __func__, r);
+ return r;
+}
+
+/**
+ * wl1273_fm_get_tx_ctune() - Get the TX tuning capacitor value.
+ * @radio: A pointer to the device struct.
+ */
+static unsigned int wl1273_fm_get_tx_ctune(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ struct device *dev = radio->dev;
+ u16 val;
+ int r;
+
+ if (core->mode == WL1273_MODE_OFF ||
+ core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ r = wl1273_fm_read_reg(core, WL1273_READ_FMANT_TUNE_VALUE, &val);
+ if (r) {
+ dev_err(dev, "%s: read error: %d\n", __func__, r);
+ goto out;
+ }
+
+out:
+ return val;
+}
+
+/**
+ * wl1273_fm_set_preemphasis() - Set the TX pre-emphasis value.
+ * @radio: A pointer to the device struct.
+ * @preemphasis: The new pre-amphasis value.
+ *
+ * Possible pre-emphasis values are: V4L2_PREEMPHASIS_DISABLED,
+ * V4L2_PREEMPHASIS_50_uS and V4L2_PREEMPHASIS_75_uS.
+ */
+static int wl1273_fm_set_preemphasis(struct wl1273_device *radio,
+ unsigned int preemphasis)
+{
+ struct wl1273_core *core = radio->core;
+ int r;
+ u16 em;
+
+ if (core->mode == WL1273_MODE_OFF ||
+ core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ mutex_lock(&core->lock);
+
+ switch (preemphasis) {
+ case V4L2_PREEMPHASIS_DISABLED:
+ em = 1;
+ break;
+ case V4L2_PREEMPHASIS_50_uS:
+ em = 0;
+ break;
+ case V4L2_PREEMPHASIS_75_uS:
+ em = 2;
+ break;
+ default:
+ r = -EINVAL;
+ goto out;
+ }
+
+ r = wl1273_fm_write_cmd(core, WL1273_PREMPH_SET, em);
+ if (r)
+ goto out;
+
+ radio->preemphasis = preemphasis;
+
+out:
+ mutex_unlock(&core->lock);
+ return r;
+}
+
+static int wl1273_fm_rds_on(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+ if (radio->rds_on)
+ return 0;
+
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET,
+ WL1273_POWER_SET_FM | WL1273_POWER_SET_RDS);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency);
+ if (r)
+ dev_err(radio->dev, "set freq fails: %d.\n", r);
+out:
+ return r;
+}
+
+static int wl1273_fm_rds_off(struct wl1273_device *radio)
+{
+ struct wl1273_core *core = radio->core;
+ int r;
+
+ if (!radio->rds_on)
+ return 0;
+
+ radio->irq_flags &= ~WL1273_RDS_EVENT;
+
+ r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET, radio->irq_flags);
+ if (r)
+ goto out;
+
+ /* stop rds reception */
+ cancel_delayed_work(&radio->work);
+
+ /* Service pending read */
+ wake_up_interruptible(&radio->read_queue);
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ r = wl1273_fm_write_cmd(core, WL1273_POWER_SET, WL1273_POWER_SET_FM);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_set_rx_freq(radio, radio->rx_frequency);
+ if (r)
+ dev_err(radio->dev, "set freq fails: %d.\n", r);
+out:
+ dev_dbg(radio->dev, "%s: exiting...\n", __func__);
+
+ return r;
+}
+
+static int wl1273_fm_set_rds(struct wl1273_device *radio, unsigned int new_mode)
+{
+ int r = 0;
+ struct wl1273_core *core = radio->core;
+
+ if (core->mode == WL1273_MODE_OFF ||
+ core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ if (new_mode == WL1273_RDS_RESET) {
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_CNTRL_SET, 1);
+ return r;
+ }
+
+ if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_OFF) {
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 0);
+ } else if (core->mode == WL1273_MODE_TX && new_mode == WL1273_RDS_ON) {
+ r = wl1273_fm_write_cmd(core, WL1273_RDS_DATA_ENB, 1);
+ } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_OFF) {
+ r = wl1273_fm_rds_off(radio);
+ } else if (core->mode == WL1273_MODE_RX && new_mode == WL1273_RDS_ON) {
+ r = wl1273_fm_rds_on(radio);
+ } else {
+ dev_err(radio->dev, "%s: Unknown mode: %d\n",
+ __func__, new_mode);
+ r = -EINVAL;
+ }
+
+ if (!r)
+ radio->rds_on = (new_mode == WL1273_RDS_ON) ? true : false;
+
+ return r;
+}
+
+static ssize_t wl1273_fm_fops_write(struct file *file, const char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ u16 val;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (radio->core->mode != WL1273_MODE_TX)
+ return count;
+
+ if (radio->rds_users == 0) {
+ dev_warn(radio->dev, "%s: RDS not on.\n", __func__);
+ return 0;
+ }
+
+ if (mutex_lock_interruptible(&radio->core->lock))
+ return -EINTR;
+ /*
+ * Multiple processes can open the device, but only
+ * one gets to write to it.
+ */
+ if (radio->owner && radio->owner != file) {
+ r = -EBUSY;
+ goto out;
+ }
+ radio->owner = file;
+
+ /* Manual Mode */
+ if (count > 255)
+ val = 255;
+ else
+ val = count;
+
+ wl1273_fm_write_cmd(radio->core, WL1273_RDS_CONFIG_DATA_SET, val);
+
+ if (copy_from_user(radio->write_buf + 1, buf, val)) {
+ r = -EFAULT;
+ goto out;
+ }
+
+ dev_dbg(radio->dev, "Count: %d\n", val);
+ dev_dbg(radio->dev, "From user: \"%s\"\n", radio->write_buf);
+
+ radio->write_buf[0] = WL1273_RDS_DATA_SET;
+ wl1273_fm_write_data(radio->core, radio->write_buf, val + 1);
+
+ r = val;
+out:
+ mutex_unlock(&radio->core->lock);
+
+ return r;
+}
+
+static unsigned int wl1273_fm_fops_poll(struct file *file,
+ struct poll_table_struct *pts)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+
+ if (radio->owner && radio->owner != file)
+ return -EBUSY;
+
+ radio->owner = file;
+
+ if (core->mode == WL1273_MODE_RX) {
+ poll_wait(file, &radio->read_queue, pts);
+
+ if (radio->rd_index != radio->wr_index)
+ return POLLIN | POLLRDNORM;
+
+ } else if (core->mode == WL1273_MODE_TX) {
+ return POLLOUT | POLLWRNORM;
+ }
+
+ return 0;
+}
+
+static int wl1273_fm_fops_open(struct file *file)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (core->mode == WL1273_MODE_RX && radio->rds_on &&
+ !radio->rds_users) {
+ dev_dbg(radio->dev, "%s: Mode: %d\n", __func__, core->mode);
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ radio->irq_flags |= WL1273_RDS_EVENT;
+
+ r = wl1273_fm_write_cmd(core, WL1273_INT_MASK_SET,
+ radio->irq_flags);
+ if (r) {
+ mutex_unlock(&core->lock);
+ goto out;
+ }
+
+ radio->rds_users++;
+
+ mutex_unlock(&core->lock);
+ }
+out:
+ return r;
+}
+
+static int wl1273_fm_fops_release(struct file *file)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (radio->rds_users > 0) {
+ radio->rds_users--;
+ if (radio->rds_users == 0) {
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ radio->irq_flags &= ~WL1273_RDS_EVENT;
+
+ if (core->mode == WL1273_MODE_RX) {
+ r = wl1273_fm_write_cmd(core,
+ WL1273_INT_MASK_SET,
+ radio->irq_flags);
+ if (r) {
+ mutex_unlock(&core->lock);
+ goto out;
+ }
+ }
+ mutex_unlock(&core->lock);
+ }
+ }
+
+ if (file == radio->owner)
+ radio->owner = NULL;
+out:
+ return r;
+}
+
+static ssize_t wl1273_fm_fops_read(struct file *file, char __user *buf,
+ size_t count, loff_t *ppos)
+{
+ int r = 0;
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ unsigned int block_count = 0;
+ u16 val;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (radio->core->mode != WL1273_MODE_RX)
+ return 0;
+
+ if (radio->rds_users == 0) {
+ dev_warn(radio->dev, "%s: RDS not on.\n", __func__);
+ return 0;
+ }
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ /*
+ * Multiple processes can open the device, but only
+ * one at a time gets read access.
+ */
+ if (radio->owner && radio->owner != file) {
+ r = -EBUSY;
+ goto out;
+ }
+ radio->owner = file;
+
+ r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+ if (r) {
+ dev_err(radio->dev, "%s: Get RDS_SYNC fails.\n", __func__);
+ goto out;
+ } else if (val == 0) {
+ dev_info(radio->dev, "RDS_SYNC: Not synchronized\n");
+ r = -ENODATA;
+ goto out;
+ }
+
+ /* block if no new data available */
+ while (radio->wr_index == radio->rd_index) {
+ if (file->f_flags & O_NONBLOCK) {
+ r = -EWOULDBLOCK;
+ goto out;
+ }
+
+ dev_dbg(radio->dev, "%s: Wait for RDS data.\n", __func__);
+ if (wait_event_interruptible(radio->read_queue,
+ radio->wr_index !=
+ radio->rd_index) < 0) {
+ r = -EINTR;
+ goto out;
+ }
+ }
+
+ /* calculate block count from byte count */
+ count /= RDS_BLOCK_SIZE;
+
+ /* copy RDS blocks from the internal buffer and to user buffer */
+ while (block_count < count) {
+ if (radio->rd_index == radio->wr_index)
+ break;
+
+ /* always transfer complete RDS blocks */
+ if (copy_to_user(buf, &radio->buffer[radio->rd_index],
+ RDS_BLOCK_SIZE))
+ break;
+
+ /* increment and wrap the read pointer */
+ radio->rd_index += RDS_BLOCK_SIZE;
+ if (radio->rd_index >= radio->buf_size)
+ radio->rd_index = 0;
+
+ /* increment counters */
+ block_count++;
+ buf += RDS_BLOCK_SIZE;
+ r += RDS_BLOCK_SIZE;
+ }
+
+out:
+ dev_dbg(radio->dev, "%s: exit\n", __func__);
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static const struct v4l2_file_operations wl1273_fops = {
+ .owner = THIS_MODULE,
+ .read = wl1273_fm_fops_read,
+ .write = wl1273_fm_fops_write,
+ .poll = wl1273_fm_fops_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .open = wl1273_fm_fops_open,
+ .release = wl1273_fm_fops_release,
+};
+
+static int wl1273_fm_vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *capability)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ strlcpy(capability->driver, WL1273_FM_DRIVER_NAME,
+ sizeof(capability->driver));
+ strlcpy(capability->card, "Texas Instruments Wl1273 FM Radio",
+ sizeof(capability->card));
+ strlcpy(capability->bus_info, radio->bus_type,
+ sizeof(capability->bus_info));
+
+ capability->capabilities = V4L2_CAP_HW_FREQ_SEEK |
+ V4L2_CAP_TUNER | V4L2_CAP_RADIO | V4L2_CAP_AUDIO |
+ V4L2_CAP_RDS_CAPTURE | V4L2_CAP_MODULATOR |
+ V4L2_CAP_RDS_OUTPUT;
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_g_input(struct file *file, void *priv,
+ unsigned int *i)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ *i = 0;
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_s_input(struct file *file, void *priv,
+ unsigned int i)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (i != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+/**
+ * wl1273_fm_set_tx_power() - Set the transmission power value.
+ * @core: A pointer to the device struct.
+ * @power: The new power value.
+ */
+static int wl1273_fm_set_tx_power(struct wl1273_device *radio, u16 power)
+{
+ int r;
+
+ if (radio->core->mode == WL1273_MODE_OFF ||
+ radio->core->mode == WL1273_MODE_SUSPENDED)
+ return -EPERM;
+
+ mutex_lock(&radio->core->lock);
+
+ /* Convert the dBuV value to chip presentation */
+ r = wl1273_fm_write_cmd(radio->core, WL1273_POWER_LEV_SET, 122 - power);
+ if (r)
+ goto out;
+
+ radio->tx_power = power;
+
+out:
+ mutex_unlock(&radio->core->lock);
+ return r;
+}
+
+#define WL1273_SPACING_50kHz 1
+#define WL1273_SPACING_100kHz 2
+#define WL1273_SPACING_200kHz 4
+
+static int wl1273_fm_tx_set_spacing(struct wl1273_device *radio,
+ unsigned int spacing)
+{
+ int r;
+
+ if (spacing == 0) {
+ r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
+ WL1273_SPACING_100kHz);
+ radio->spacing = 100;
+ } else if (spacing - 50000 < 25000) {
+ r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
+ WL1273_SPACING_50kHz);
+ radio->spacing = 50;
+ } else if (spacing - 100000 < 50000) {
+ r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
+ WL1273_SPACING_100kHz);
+ radio->spacing = 100;
+ } else {
+ r = wl1273_fm_write_cmd(radio->core, WL1273_SCAN_SPACING_SET,
+ WL1273_SPACING_200kHz);
+ radio->spacing = 200;
+ }
+
+ return r;
+}
+
+static int wl1273_fm_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct wl1273_device *radio = ctrl->priv;
+ struct wl1273_core *core = radio->core;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ switch (ctrl->id) {
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ ctrl->val = wl1273_fm_get_tx_ctune(radio);
+ break;
+
+ default:
+ dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n",
+ __func__, ctrl->id);
+ break;
+ }
+
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
+#define WL1273_MUTE_SOFT_ENABLE (1 << 0)
+#define WL1273_MUTE_AC (1 << 1)
+#define WL1273_MUTE_HARD_LEFT (1 << 2)
+#define WL1273_MUTE_HARD_RIGHT (1 << 3)
+#define WL1273_MUTE_SOFT_FORCE (1 << 4)
+
+static inline struct wl1273_device *to_radio(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct wl1273_device, ctrl_handler);
+}
+
+static int wl1273_fm_vidioc_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct wl1273_device *radio = to_radio(ctrl);
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ if (core->mode == WL1273_MODE_RX && ctrl->val)
+ r = wl1273_fm_write_cmd(core,
+ WL1273_MUTE_STATUS_SET,
+ WL1273_MUTE_HARD_LEFT |
+ WL1273_MUTE_HARD_RIGHT);
+ else if (core->mode == WL1273_MODE_RX)
+ r = wl1273_fm_write_cmd(core,
+ WL1273_MUTE_STATUS_SET, 0x0);
+ else if (core->mode == WL1273_MODE_TX && ctrl->val)
+ r = wl1273_fm_write_cmd(core, WL1273_MUTE, 1);
+ else if (core->mode == WL1273_MODE_TX)
+ r = wl1273_fm_write_cmd(core, WL1273_MUTE, 0);
+
+ mutex_unlock(&core->lock);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ if (ctrl->val == 0)
+ r = wl1273_fm_set_mode(radio, WL1273_MODE_OFF);
+ else
+ r = core->set_volume(core, core->volume);
+ break;
+
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ r = wl1273_fm_set_preemphasis(radio, ctrl->val);
+ break;
+
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ r = wl1273_fm_set_tx_power(radio, ctrl->val);
+ break;
+
+ default:
+ dev_warn(radio->dev, "%s: Unknown IOCTL: %d\n",
+ __func__, ctrl->id);
+ break;
+ }
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+ return r;
+}
+
+static int wl1273_fm_vidioc_g_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (audio->index > 1)
+ return -EINVAL;
+
+ strlcpy(audio->name, "Radio", sizeof(audio->name));
+ audio->capability = V4L2_AUDCAP_STEREO;
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_s_audio(struct file *file, void *priv,
+ struct v4l2_audio *audio)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (audio->index != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+#define WL1273_RDS_NOT_SYNCHRONIZED 0
+#define WL1273_RDS_SYNCHRONIZED 1
+
+static int wl1273_fm_vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ u16 val;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (tuner->index > 0)
+ return -EINVAL;
+
+ strlcpy(tuner->name, WL1273_FM_DRIVER_NAME, sizeof(tuner->name));
+ tuner->type = V4L2_TUNER_RADIO;
+
+ tuner->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW);
+ tuner->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH);
+
+ tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+
+ if (radio->stereo)
+ tuner->audmode = V4L2_TUNER_MODE_STEREO;
+ else
+ tuner->audmode = V4L2_TUNER_MODE_MONO;
+
+ if (core->mode != WL1273_MODE_RX)
+ return 0;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_read_reg(core, WL1273_STEREO_GET, &val);
+ if (r)
+ goto out;
+
+ if (val == 1)
+ tuner->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ else
+ tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+
+ r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val);
+ if (r)
+ goto out;
+
+ tuner->signal = (s16) val;
+ dev_dbg(radio->dev, "Signal: %d\n", tuner->signal);
+
+ tuner->afc = 0;
+
+ r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+ if (r)
+ goto out;
+
+ if (val == WL1273_RDS_SYNCHRONIZED)
+ tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int wl1273_fm_vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *tuner)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+ dev_dbg(radio->dev, "tuner->index: %d\n", tuner->index);
+ dev_dbg(radio->dev, "tuner->name: %s\n", tuner->name);
+ dev_dbg(radio->dev, "tuner->capability: 0x%04x\n", tuner->capability);
+ dev_dbg(radio->dev, "tuner->rxsubchans: 0x%04x\n", tuner->rxsubchans);
+ dev_dbg(radio->dev, "tuner->rangelow: %d\n", tuner->rangelow);
+ dev_dbg(radio->dev, "tuner->rangehigh: %d\n", tuner->rangehigh);
+
+ if (tuner->index > 0)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_set_mode(radio, WL1273_MODE_RX);
+ if (r)
+ goto out;
+
+ if (tuner->rxsubchans & V4L2_TUNER_SUB_RDS)
+ r = wl1273_fm_set_rds(radio, WL1273_RDS_ON);
+ else
+ r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF);
+
+ if (r)
+ dev_warn(radio->dev, "%s: RDS fails: %d\n", __func__, r);
+
+ if (tuner->audmode == V4L2_TUNER_MODE_MONO) {
+ r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+ WL1273_RX_MONO);
+ if (r < 0) {
+ dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n",
+ __func__, r);
+ goto out;
+ }
+ radio->stereo = false;
+ } else if (tuner->audmode == V4L2_TUNER_MODE_STEREO) {
+ r = wl1273_fm_write_cmd(core, WL1273_MOST_MODE_SET,
+ WL1273_RX_STEREO);
+ if (r < 0) {
+ dev_warn(radio->dev, "%s: MOST_MODE fails: %d\n",
+ __func__, r);
+ goto out;
+ }
+ radio->stereo = true;
+ } else {
+ dev_err(radio->dev, "%s: tuner->audmode: %d\n",
+ __func__, tuner->audmode);
+ r = -EINVAL;
+ goto out;
+ }
+
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int wl1273_fm_vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ freq->type = V4L2_TUNER_RADIO;
+ freq->frequency = WL1273_FREQ(wl1273_fm_get_freq(radio));
+
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *freq)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r;
+
+ dev_dbg(radio->dev, "%s: %d\n", __func__, freq->frequency);
+
+ if (freq->type != V4L2_TUNER_RADIO) {
+ dev_dbg(radio->dev,
+ "freq->type != V4L2_TUNER_RADIO: %d\n", freq->type);
+ return -EINVAL;
+ }
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ if (core->mode == WL1273_MODE_RX) {
+ dev_dbg(radio->dev, "freq: %d\n", freq->frequency);
+
+ r = wl1273_fm_set_rx_freq(radio,
+ WL1273_INV_FREQ(freq->frequency));
+ if (r)
+ dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
+ ": set frequency failed with %d\n", r);
+ } else {
+ r = wl1273_fm_set_tx_freq(radio,
+ WL1273_INV_FREQ(freq->frequency));
+ if (r)
+ dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
+ ": set frequency failed with %d\n", r);
+ }
+
+ mutex_unlock(&core->lock);
+
+ dev_dbg(radio->dev, "wl1273_vidioc_s_frequency: DONE\n");
+ return r;
+}
+
+#define WL1273_DEFAULT_SEEK_LEVEL 7
+
+static int wl1273_fm_vidioc_s_hw_freq_seek(struct file *file, void *priv,
+ struct v4l2_hw_freq_seek *seek)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (seek->tuner != 0 || seek->type != V4L2_TUNER_RADIO)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_set_mode(radio, WL1273_MODE_RX);
+ if (r)
+ goto out;
+
+ r = wl1273_fm_tx_set_spacing(radio, seek->spacing);
+ if (r)
+ dev_warn(radio->dev, "HW seek failed: %d\n", r);
+
+ r = wl1273_fm_set_seek(radio, seek->wrap_around, seek->seek_upward,
+ WL1273_DEFAULT_SEEK_LEVEL);
+ if (r)
+ dev_warn(radio->dev, "HW seek failed: %d\n", r);
+
+out:
+ mutex_unlock(&core->lock);
+ return r;
+}
+
+static int wl1273_fm_vidioc_s_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *modulator)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ int r = 0;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ if (modulator->index > 0)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_set_mode(radio, WL1273_MODE_TX);
+ if (r)
+ goto out;
+
+ if (modulator->txsubchans & V4L2_TUNER_SUB_RDS)
+ r = wl1273_fm_set_rds(radio, WL1273_RDS_ON);
+ else
+ r = wl1273_fm_set_rds(radio, WL1273_RDS_OFF);
+
+ if (modulator->txsubchans & V4L2_TUNER_SUB_MONO)
+ r = wl1273_fm_write_cmd(core, WL1273_MONO_SET, WL1273_TX_MONO);
+ else
+ r = wl1273_fm_write_cmd(core, WL1273_MONO_SET,
+ WL1273_RX_STEREO);
+ if (r < 0)
+ dev_warn(radio->dev, WL1273_FM_DRIVER_NAME
+ "MONO_SET fails: %d\n", r);
+out:
+ mutex_unlock(&core->lock);
+
+ return r;
+}
+
+static int wl1273_fm_vidioc_g_modulator(struct file *file, void *priv,
+ struct v4l2_modulator *modulator)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ u16 val;
+ int r;
+
+ dev_dbg(radio->dev, "%s\n", __func__);
+
+ strlcpy(modulator->name, WL1273_FM_DRIVER_NAME,
+ sizeof(modulator->name));
+
+ modulator->rangelow = WL1273_FREQ(WL1273_BAND_JAPAN_LOW);
+ modulator->rangehigh = WL1273_FREQ(WL1273_BAND_OTHER_HIGH);
+
+ modulator->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_RDS |
+ V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_RDS_BLOCK_IO;
+
+ if (core->mode != WL1273_MODE_TX)
+ return 0;
+
+ if (mutex_lock_interruptible(&core->lock))
+ return -EINTR;
+
+ r = wl1273_fm_read_reg(core, WL1273_MONO_SET, &val);
+ if (r)
+ goto out;
+
+ if (val == WL1273_TX_STEREO)
+ modulator->txsubchans = V4L2_TUNER_SUB_STEREO;
+ else
+ modulator->txsubchans = V4L2_TUNER_SUB_MONO;
+
+ if (radio->rds_on)
+ modulator->txsubchans |= V4L2_TUNER_SUB_RDS;
+out:
+ mutex_unlock(&core->lock);
+
+ return 0;
+}
+
+static int wl1273_fm_vidioc_log_status(struct file *file, void *priv)
+{
+ struct wl1273_device *radio = video_get_drvdata(video_devdata(file));
+ struct wl1273_core *core = radio->core;
+ struct device *dev = radio->dev;
+ u16 val;
+ int r;
+
+ dev_info(dev, DRIVER_DESC);
+
+ if (core->mode == WL1273_MODE_OFF) {
+ dev_info(dev, "Mode: Off\n");
+ return 0;
+ }
+
+ if (core->mode == WL1273_MODE_SUSPENDED) {
+ dev_info(dev, "Mode: Suspended\n");
+ return 0;
+ }
+
+ r = wl1273_fm_read_reg(core, WL1273_ASIC_ID_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get ASIC_ID fails.\n", __func__);
+ else
+ dev_info(dev, "ASIC_ID: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_ASIC_VER_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get ASIC_VER fails.\n", __func__);
+ else
+ dev_info(dev, "ASIC Version: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_FIRM_VER_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get FIRM_VER fails.\n", __func__);
+ else
+ dev_info(dev, "FW version: %d(0x%04x)\n", val, val);
+
+ r = wl1273_fm_read_reg(core, WL1273_BAND_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get BAND fails.\n", __func__);
+ else
+ dev_info(dev, "BAND: %d\n", val);
+
+ if (core->mode == WL1273_MODE_TX) {
+ r = wl1273_fm_read_reg(core, WL1273_PUPD_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get PUPD fails.\n", __func__);
+ else
+ dev_info(dev, "PUPD: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_CHANL_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get CHANL fails.\n", __func__);
+ else
+ dev_info(dev, "Tx frequency: %dkHz\n", val*10);
+ } else if (core->mode == WL1273_MODE_RX) {
+ int bf = radio->rangelow;
+
+ r = wl1273_fm_read_reg(core, WL1273_FREQ_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get FREQ fails.\n", __func__);
+ else
+ dev_info(dev, "RX Frequency: %dkHz\n", bf + val*50);
+
+ r = wl1273_fm_read_reg(core, WL1273_MOST_MODE_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get MOST_MODE fails.\n",
+ __func__);
+ else if (val == 0)
+ dev_info(dev, "MOST_MODE: Stereo according to blend\n");
+ else if (val == 1)
+ dev_info(dev, "MOST_MODE: Force mono output\n");
+ else
+ dev_info(dev, "MOST_MODE: Unexpected value: %d\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_MOST_BLEND_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get MOST_BLEND fails.\n", __func__);
+ else if (val == 0)
+ dev_info(dev,
+ "MOST_BLEND: Switched blend & hysteresis.\n");
+ else if (val == 1)
+ dev_info(dev, "MOST_BLEND: Soft blend.\n");
+ else
+ dev_info(dev, "MOST_BLEND: Unexpected val: %d\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_STEREO_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get STEREO fails.\n", __func__);
+ else if (val == 0)
+ dev_info(dev, "STEREO: Not detected\n");
+ else if (val == 1)
+ dev_info(dev, "STEREO: Detected\n");
+ else
+ dev_info(dev, "STEREO: Unexpected value: %d\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_RSSI_LVL_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get RSSI_LVL fails.\n", __func__);
+ else
+ dev_info(dev, "RX signal strength: %d\n", (s16) val);
+
+ r = wl1273_fm_read_reg(core, WL1273_POWER_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get POWER fails.\n", __func__);
+ else
+ dev_info(dev, "POWER: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_INT_MASK_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get INT_MASK fails.\n", __func__);
+ else
+ dev_info(dev, "INT_MASK: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_RDS_SYNC_GET, &val);
+ if (r)
+ dev_err(dev, "%s: Get RDS_SYNC fails.\n",
+ __func__);
+ else if (val == 0)
+ dev_info(dev, "RDS_SYNC: Not synchronized\n");
+
+ else if (val == 1)
+ dev_info(dev, "RDS_SYNC: Synchronized\n");
+ else
+ dev_info(dev, "RDS_SYNC: Unexpected value: %d\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_I2S_MODE_CONFIG_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get I2S_MODE_CONFIG fails.\n",
+ __func__);
+ else
+ dev_info(dev, "I2S_MODE_CONFIG: 0x%04x\n", val);
+
+ r = wl1273_fm_read_reg(core, WL1273_VOLUME_SET, &val);
+ if (r)
+ dev_err(dev, "%s: Get VOLUME fails.\n", __func__);
+ else
+ dev_info(dev, "VOLUME: 0x%04x\n", val);
+ }
+
+ return 0;
+}
+
+static void wl1273_vdev_release(struct video_device *dev)
+{
+}
+
+static const struct v4l2_ctrl_ops wl1273_ctrl_ops = {
+ .s_ctrl = wl1273_fm_vidioc_s_ctrl,
+ .g_volatile_ctrl = wl1273_fm_g_volatile_ctrl,
+};
+
+static const struct v4l2_ioctl_ops wl1273_ioctl_ops = {
+ .vidioc_querycap = wl1273_fm_vidioc_querycap,
+ .vidioc_g_input = wl1273_fm_vidioc_g_input,
+ .vidioc_s_input = wl1273_fm_vidioc_s_input,
+ .vidioc_g_audio = wl1273_fm_vidioc_g_audio,
+ .vidioc_s_audio = wl1273_fm_vidioc_s_audio,
+ .vidioc_g_tuner = wl1273_fm_vidioc_g_tuner,
+ .vidioc_s_tuner = wl1273_fm_vidioc_s_tuner,
+ .vidioc_g_frequency = wl1273_fm_vidioc_g_frequency,
+ .vidioc_s_frequency = wl1273_fm_vidioc_s_frequency,
+ .vidioc_s_hw_freq_seek = wl1273_fm_vidioc_s_hw_freq_seek,
+ .vidioc_g_modulator = wl1273_fm_vidioc_g_modulator,
+ .vidioc_s_modulator = wl1273_fm_vidioc_s_modulator,
+ .vidioc_log_status = wl1273_fm_vidioc_log_status,
+};
+
+static struct video_device wl1273_viddev_template = {
+ .fops = &wl1273_fops,
+ .ioctl_ops = &wl1273_ioctl_ops,
+ .name = WL1273_FM_DRIVER_NAME,
+ .release = wl1273_vdev_release,
+};
+
+static int wl1273_fm_radio_remove(struct platform_device *pdev)
+{
+ struct wl1273_device *radio = platform_get_drvdata(pdev);
+ struct wl1273_core *core = radio->core;
+
+ dev_info(&pdev->dev, "%s.\n", __func__);
+
+ free_irq(core->client->irq, radio);
+ core->pdata->free_resources();
+
+ v4l2_ctrl_handler_free(&radio->ctrl_handler);
+ video_unregister_device(&radio->videodev);
+ v4l2_device_unregister(&radio->v4l2dev);
+ kfree(radio->buffer);
+ kfree(radio->write_buf);
+ kfree(radio);
+
+ return 0;
+}
+
+static int __devinit wl1273_fm_radio_probe(struct platform_device *pdev)
+{
+ struct wl1273_core **core = pdev->dev.platform_data;
+ struct wl1273_device *radio;
+ struct v4l2_ctrl *ctrl;
+ int r = 0;
+
+ pr_debug("%s\n", __func__);
+
+ if (!core) {
+ dev_err(&pdev->dev, "No platform data.\n");
+ r = -EINVAL;
+ goto pdata_err;
+ }
+
+ radio = kzalloc(sizeof(*radio), GFP_KERNEL);
+ if (!radio) {
+ r = -ENOMEM;
+ goto pdata_err;
+ }
+
+ /* RDS buffer allocation */
+ radio->buf_size = rds_buf * RDS_BLOCK_SIZE;
+ radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
+ if (!radio->buffer) {
+ pr_err("Cannot allocate memory for RDS buffer.\n");
+ r = -ENOMEM;
+ goto err_kmalloc;
+ }
+
+ radio->core = *core;
+ radio->irq_flags = WL1273_IRQ_MASK;
+ radio->dev = &radio->core->client->dev;
+ radio->rds_on = false;
+ radio->core->mode = WL1273_MODE_OFF;
+ radio->tx_power = 118;
+ radio->core->audio_mode = WL1273_AUDIO_ANALOG;
+ radio->band = WL1273_BAND_OTHER;
+ radio->core->i2s_mode = WL1273_I2S_DEF_MODE;
+ radio->core->channel_number = 2;
+ radio->core->volume = WL1273_DEFAULT_VOLUME;
+ radio->rx_frequency = WL1273_BAND_OTHER_LOW;
+ radio->tx_frequency = WL1273_BAND_OTHER_HIGH;
+ radio->rangelow = WL1273_BAND_OTHER_LOW;
+ radio->rangehigh = WL1273_BAND_OTHER_HIGH;
+ radio->stereo = true;
+ radio->bus_type = "I2C";
+
+ radio->core->write = wl1273_fm_write_cmd;
+ radio->core->set_audio = wl1273_fm_set_audio;
+ radio->core->set_volume = wl1273_fm_set_volume;
+
+ if (radio->core->pdata->request_resources) {
+ r = radio->core->pdata->request_resources(radio->core->client);
+ if (r) {
+ dev_err(radio->dev, WL1273_FM_DRIVER_NAME
+ ": Cannot get platform data\n");
+ goto err_resources;
+ }
+
+ dev_dbg(radio->dev, "irq: %d\n", radio->core->client->irq);
+
+ r = request_threaded_irq(radio->core->client->irq, NULL,
+ wl1273_fm_irq_thread_handler,
+ IRQF_ONESHOT | IRQF_TRIGGER_FALLING,
+ "wl1273-fm", radio);
+ if (r < 0) {
+ dev_err(radio->dev, WL1273_FM_DRIVER_NAME
+ ": Unable to register IRQ handler: %d\n", r);
+ goto err_request_irq;
+ }
+ } else {
+ dev_err(radio->dev, WL1273_FM_DRIVER_NAME ": Core WL1273 IRQ"
+ " not configured");
+ r = -EINVAL;
+ goto err_resources;
+ }
+
+ init_completion(&radio->busy);
+ init_waitqueue_head(&radio->read_queue);
+
+ radio->write_buf = kmalloc(256, GFP_KERNEL);
+ if (!radio->write_buf) {
+ r = -ENOMEM;
+ goto write_buf_err;
+ }
+
+ radio->dev = &pdev->dev;
+ radio->v4l2dev.ctrl_handler = &radio->ctrl_handler;
+ radio->rds_users = 0;
+
+ r = v4l2_device_register(&pdev->dev, &radio->v4l2dev);
+ if (r) {
+ dev_err(&pdev->dev, "Cannot register v4l2_device.\n");
+ goto device_register_err;
+ }
+
+ /* V4L2 configuration */
+ memcpy(&radio->videodev, &wl1273_viddev_template,
+ sizeof(wl1273_viddev_template));
+
+ radio->videodev.v4l2_dev = &radio->v4l2dev;
+
+ v4l2_ctrl_handler_init(&radio->ctrl_handler, 6);
+
+ /* add in ascending ID order */
+ v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, WL1273_MAX_VOLUME, 1,
+ WL1273_DEFAULT_VOLUME);
+
+ v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 1);
+
+ v4l2_ctrl_new_std_menu(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_TUNE_PREEMPHASIS,
+ V4L2_PREEMPHASIS_75_uS, 0x03,
+ V4L2_PREEMPHASIS_50_uS);
+
+ v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_TUNE_POWER_LEVEL, 91, 122, 1, 118);
+
+ ctrl = v4l2_ctrl_new_std(&radio->ctrl_handler, &wl1273_ctrl_ops,
+ V4L2_CID_TUNE_ANTENNA_CAPACITOR,
+ 0, 255, 1, 255);
+ if (ctrl)
+ ctrl->is_volatile = 1;
+
+ if (radio->ctrl_handler.error) {
+ r = radio->ctrl_handler.error;
+ dev_err(&pdev->dev, "Ctrl handler error: %d\n", r);
+ goto handler_init_err;
+ }
+
+ video_set_drvdata(&radio->videodev, radio);
+ platform_set_drvdata(pdev, radio);
+
+ /* register video device */
+ r = video_register_device(&radio->videodev, VFL_TYPE_RADIO, radio_nr);
+ if (r) {
+ dev_err(&pdev->dev, WL1273_FM_DRIVER_NAME
+ ": Could not register video device\n");
+ goto handler_init_err;
+ }
+
+ return 0;
+
+handler_init_err:
+ v4l2_ctrl_handler_free(&radio->ctrl_handler);
+ v4l2_device_unregister(&radio->v4l2dev);
+device_register_err:
+ kfree(radio->write_buf);
+write_buf_err:
+ free_irq(radio->core->client->irq, radio);
+err_request_irq:
+ radio->core->pdata->free_resources();
+err_resources:
+ kfree(radio->buffer);
+err_kmalloc:
+ kfree(radio);
+pdata_err:
+ return r;
+}
+
+MODULE_ALIAS("platform:wl1273_fm_radio");
+
+static struct platform_driver wl1273_fm_radio_driver = {
+ .probe = wl1273_fm_radio_probe,
+ .remove = __devexit_p(wl1273_fm_radio_remove),
+ .driver = {
+ .name = "wl1273_fm_radio",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init wl1273_fm_module_init(void)
+{
+ pr_info("%s\n", __func__);
+ return platform_driver_register(&wl1273_fm_radio_driver);
+}
+module_init(wl1273_fm_module_init);
+
+static void __exit wl1273_fm_module_exit(void)
+{
+ flush_scheduled_work();
+ platform_driver_unregister(&wl1273_fm_radio_driver);
+ pr_info(DRIVER_DESC ", Exiting.\n");
+}
+module_exit(wl1273_fm_module_exit);
+
+MODULE_AUTHOR("Matti Aaltonen <matti.j.aaltonen@nokia.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index f31eab99c943..af99c5bd88c1 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -377,7 +377,7 @@ static int vidioc_s_audio(struct file *file, void *priv,
static const struct v4l2_file_operations zoltrix_fops =
{
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops zoltrix_ioctl_ops = {
@@ -424,20 +424,6 @@ static int __init zoltrix_init(void)
return res;
}
- strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
- zol->vdev.v4l2_dev = v4l2_dev;
- zol->vdev.fops = &zoltrix_fops;
- zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
- zol->vdev.release = video_device_release_empty;
- video_set_drvdata(&zol->vdev, zol);
-
- if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
- v4l2_device_unregister(v4l2_dev);
- release_region(zol->io, 2);
- return -EINVAL;
- }
- v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
-
mutex_init(&zol->lock);
/* mute card - prevents noisy bootups */
@@ -452,6 +438,20 @@ static int __init zoltrix_init(void)
zol->curvol = 0;
zol->stereo = 1;
+ strlcpy(zol->vdev.name, v4l2_dev->name, sizeof(zol->vdev.name));
+ zol->vdev.v4l2_dev = v4l2_dev;
+ zol->vdev.fops = &zoltrix_fops;
+ zol->vdev.ioctl_ops = &zoltrix_ioctl_ops;
+ zol->vdev.release = video_device_release_empty;
+ video_set_drvdata(&zol->vdev, zol);
+
+ if (video_register_device(&zol->vdev, VFL_TYPE_RADIO, radio_nr) < 0) {
+ v4l2_device_unregister(v4l2_dev);
+ release_region(zol->io, 2);
+ return -EINVAL;
+ }
+ v4l2_info(v4l2_dev, "Zoltrix Radio Plus card driver.\n");
+
return 0;
}
diff --git a/drivers/media/radio/si470x/radio-si470x-common.c b/drivers/media/radio/si470x/radio-si470x-common.c
index 47075fc71f11..60c176fe328e 100644
--- a/drivers/media/radio/si470x/radio-si470x-common.c
+++ b/drivers/media/radio/si470x/radio-si470x-common.c
@@ -357,7 +357,8 @@ int si470x_start(struct si470x_device *radio)
goto done;
/* sysconfig 1 */
- radio->registers[SYSCONFIG1] = SYSCONFIG1_DE;
+ radio->registers[SYSCONFIG1] =
+ (de << 11) & SYSCONFIG1_DE; /* DE*/
retval = si470x_set_register(radio, SYSCONFIG1);
if (retval < 0)
goto done;
@@ -408,17 +409,15 @@ done:
/*
* si470x_rds_on - switch on rds reception
*/
-int si470x_rds_on(struct si470x_device *radio)
+static int si470x_rds_on(struct si470x_device *radio)
{
int retval;
/* sysconfig 1 */
- mutex_lock(&radio->lock);
radio->registers[SYSCONFIG1] |= SYSCONFIG1_RDS;
retval = si470x_set_register(radio, SYSCONFIG1);
if (retval < 0)
radio->registers[SYSCONFIG1] &= ~SYSCONFIG1_RDS;
- mutex_unlock(&radio->lock);
return retval;
}
@@ -440,6 +439,7 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
unsigned int block_count = 0;
/* switch on rds reception */
+ mutex_lock(&radio->lock);
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
si470x_rds_on(radio);
@@ -480,9 +480,9 @@ static ssize_t si470x_fops_read(struct file *file, char __user *buf,
buf += 3;
retval += 3;
}
- mutex_unlock(&radio->lock);
done:
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -497,8 +497,11 @@ static unsigned int si470x_fops_poll(struct file *file,
int retval = 0;
/* switch on rds reception */
+
+ mutex_lock(&radio->lock);
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
si470x_rds_on(radio);
+ mutex_unlock(&radio->lock);
poll_wait(file, &radio->read_queue, pts);
@@ -516,7 +519,7 @@ static const struct v4l2_file_operations si470x_fops = {
.owner = THIS_MODULE,
.read = si470x_fops_read,
.poll = si470x_fops_poll,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.open = si470x_fops_open,
.release = si470x_fops_release,
};
@@ -572,6 +575,7 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -594,6 +598,8 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"get control failed with %d\n", retval);
+
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -607,6 +613,7 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -633,6 +640,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set control failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -662,6 +670,7 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -679,12 +688,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
/* driver constants */
strcpy(tuner->name, "FM");
tuner->type = V4L2_TUNER_RADIO;
-#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO |
- V4L2_TUNER_CAP_RDS;
-#else
- tuner->capability = V4L2_TUNER_CAP_LOW | V4L2_TUNER_CAP_STEREO;
-#endif
+ V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
/* range limits */
switch ((radio->registers[SYSCONFIG2] & SYSCONFIG2_BAND) >> 6) {
@@ -710,12 +715,10 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
else
tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-#if defined(CONFIG_USB_SI470X) || defined(CONFIG_USB_SI470X_MODULE)
/* If there is a reliable method of detecting an RDS channel,
then this code should check for that before setting this
RDS subchannel. */
tuner->rxsubchans |= V4L2_TUNER_SUB_RDS;
-#endif
/* mono/stereo selector */
if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
@@ -737,6 +740,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"get tuner failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -748,8 +752,9 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *tuner)
{
struct si470x_device *radio = video_drvdata(file);
- int retval = -EINVAL;
+ int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -776,6 +781,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set tuner failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -790,6 +796,7 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
int retval = 0;
/* safety checks */
+ mutex_lock(&radio->lock);
retval = si470x_disconnect_check(radio);
if (retval)
goto done;
@@ -806,6 +813,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"get frequency failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -819,6 +827,7 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -835,6 +844,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set frequency failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -848,6 +858,7 @@ static int si470x_vidioc_s_hw_freq_seek(struct file *file, void *priv,
struct si470x_device *radio = video_drvdata(file);
int retval = 0;
+ mutex_lock(&radio->lock);
/* safety checks */
retval = si470x_disconnect_check(radio);
if (retval)
@@ -864,6 +875,7 @@ done:
if (retval < 0)
dev_warn(&radio->videodev->dev,
"set hardware frequency seek failed with %d\n", retval);
+ mutex_unlock(&radio->lock);
return retval;
}
diff --git a/drivers/media/radio/si470x/radio-si470x-i2c.c b/drivers/media/radio/si470x/radio-si470x-i2c.c
index a5844d08d8b7..4ce541a5eb47 100644
--- a/drivers/media/radio/si470x/radio-si470x-i2c.c
+++ b/drivers/media/radio/si470x/radio-si470x-i2c.c
@@ -395,7 +395,7 @@ static int __devinit si470x_i2c_probe(struct i2c_client *client,
radio->registers[POWERCFG] = POWERCFG_ENABLE;
if (si470x_set_register(radio, POWERCFG) < 0) {
retval = -EIO;
- goto err_all;
+ goto err_video;
}
msleep(110);
@@ -482,7 +482,6 @@ static __devexit int si470x_i2c_remove(struct i2c_client *client)
cancel_work_sync(&radio->radio_work);
video_unregister_device(radio->videodev);
kfree(radio);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/media/radio/si470x/radio-si470x-usb.c b/drivers/media/radio/si470x/radio-si470x-usb.c
index 5ec13e50a9f0..392e84fe90ef 100644
--- a/drivers/media/radio/si470x/radio-si470x-usb.c
+++ b/drivers/media/radio/si470x/radio-si470x-usb.c
@@ -517,7 +517,7 @@ int si470x_fops_open(struct file *file)
struct si470x_device *radio = video_drvdata(file);
int retval;
- lock_kernel();
+ mutex_lock(&radio->lock);
radio->users++;
retval = usb_autopm_get_interface(radio->intf);
@@ -558,7 +558,7 @@ int si470x_fops_open(struct file *file)
}
done:
- unlock_kernel();
+ mutex_unlock(&radio->lock);
return retval;
}
@@ -577,7 +577,7 @@ int si470x_fops_release(struct file *file)
goto done;
}
- mutex_lock(&radio->disconnect_lock);
+ mutex_lock(&radio->lock);
radio->users--;
if (radio->users == 0) {
/* shutdown interrupt handler */
@@ -591,7 +591,7 @@ int si470x_fops_release(struct file *file)
video_unregister_device(radio->videodev);
kfree(radio->int_in_buffer);
kfree(radio->buffer);
- mutex_unlock(&radio->disconnect_lock);
+ mutex_unlock(&radio->lock);
kfree(radio);
goto done;
}
@@ -603,7 +603,7 @@ int si470x_fops_release(struct file *file)
retval = si470x_stop(radio);
usb_autopm_put_interface(radio->intf);
}
- mutex_unlock(&radio->disconnect_lock);
+ mutex_unlock(&radio->lock);
done:
return retval;
}
@@ -661,7 +661,6 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
radio->disconnected = 0;
radio->usbdev = interface_to_usbdev(intf);
radio->intf = intf;
- mutex_init(&radio->disconnect_lock);
mutex_init(&radio->lock);
iface_desc = intf->cur_altsetting;
@@ -830,7 +829,7 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
{
struct si470x_device *radio = usb_get_intfdata(intf);
- mutex_lock(&radio->disconnect_lock);
+ mutex_lock(&radio->lock);
radio->disconnected = 1;
usb_set_intfdata(intf, NULL);
if (radio->users == 0) {
@@ -843,10 +842,10 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
kfree(radio->int_in_buffer);
video_unregister_device(radio->videodev);
kfree(radio->buffer);
- mutex_unlock(&radio->disconnect_lock);
+ mutex_unlock(&radio->lock);
kfree(radio);
} else {
- mutex_unlock(&radio->disconnect_lock);
+ mutex_unlock(&radio->lock);
}
}
diff --git a/drivers/media/radio/si470x/radio-si470x.h b/drivers/media/radio/si470x/radio-si470x.h
index 3cd0a29cd6e7..4a4e908db04c 100644
--- a/drivers/media/radio/si470x/radio-si470x.h
+++ b/drivers/media/radio/si470x/radio-si470x.h
@@ -31,14 +31,12 @@
#include <linux/init.h>
#include <linux/sched.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/input.h>
#include <linux/version.h>
#include <linux/videodev2.h>
#include <linux/mutex.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
-#include <media/rds.h>
#include <asm/unaligned.h>
@@ -177,7 +175,6 @@ struct si470x_device {
/* driver management */
unsigned char disconnected;
- struct mutex disconnect_lock;
#endif
#if defined(CONFIG_I2C_SI470X) || defined(CONFIG_I2C_SI470X_MODULE)
@@ -221,7 +218,6 @@ int si470x_disconnect_check(struct si470x_device *radio);
int si470x_set_freq(struct si470x_device *radio, unsigned int freq);
int si470x_start(struct si470x_device *radio);
int si470x_stop(struct si470x_device *radio);
-int si470x_rds_on(struct si470x_device *radio);
int si470x_fops_open(struct file *file);
int si470x_fops_release(struct file *file);
int si470x_vidioc_querycap(struct file *file, void *priv,
diff --git a/drivers/media/radio/si4713-i2c.c b/drivers/media/radio/si4713-i2c.c
index ab63dd5b25c4..0fab6f8f7e24 100644
--- a/drivers/media/radio/si4713-i2c.c
+++ b/drivers/media/radio/si4713-i2c.c
@@ -27,6 +27,8 @@
#include <linux/interrupt.h>
#include <linux/i2c.h>
#include <linux/slab.h>
+#include <linux/gpio.h>
+#include <linux/regulator/consumer.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-common.h>
@@ -43,6 +45,11 @@ MODULE_AUTHOR("Eduardo Valentin <eduardo.valentin@nokia.com>");
MODULE_DESCRIPTION("I2C driver for Si4713 FM Radio Transmitter");
MODULE_VERSION("0.0.1");
+static const char *si4713_supply_names[SI4713_NUM_SUPPLIES] = {
+ "vio",
+ "vdd",
+};
+
#define DEFAULT_RDS_PI 0x00
#define DEFAULT_RDS_PTY 0x00
#define DEFAULT_RDS_PS_NAME ""
@@ -369,7 +376,17 @@ static int si4713_powerup(struct si4713_device *sdev)
if (sdev->power_state)
return 0;
- sdev->platform_data->set_power(1);
+ err = regulator_bulk_enable(ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ if (err) {
+ v4l2_err(&sdev->sd, "Failed to enable supplies: %d\n", err);
+ return err;
+ }
+ if (gpio_is_valid(sdev->gpio_reset)) {
+ udelay(50);
+ gpio_set_value(sdev->gpio_reset, 1);
+ }
+
err = si4713_send_command(sdev, SI4713_CMD_POWER_UP,
args, ARRAY_SIZE(args),
resp, ARRAY_SIZE(resp),
@@ -384,7 +401,13 @@ static int si4713_powerup(struct si4713_device *sdev)
err = si4713_write_property(sdev, SI4713_GPO_IEN,
SI4713_STC_INT | SI4713_CTS);
} else {
- sdev->platform_data->set_power(0);
+ if (gpio_is_valid(sdev->gpio_reset))
+ gpio_set_value(sdev->gpio_reset, 0);
+ err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ if (err)
+ v4l2_err(&sdev->sd,
+ "Failed to disable supplies: %d\n", err);
}
return err;
@@ -411,7 +434,13 @@ static int si4713_powerdown(struct si4713_device *sdev)
v4l2_dbg(1, debug, &sdev->sd, "Power down response: 0x%02x\n",
resp[0]);
v4l2_dbg(1, debug, &sdev->sd, "Device in reset mode\n");
- sdev->platform_data->set_power(0);
+ if (gpio_is_valid(sdev->gpio_reset))
+ gpio_set_value(sdev->gpio_reset, 0);
+ err = regulator_bulk_disable(ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ if (err)
+ v4l2_err(&sdev->sd,
+ "Failed to disable supplies: %d\n", err);
sdev->power_state = POWER_OFF;
}
@@ -1009,8 +1038,10 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev,
goto exit;
}
rval = copy_from_user(ps_name, control->string, len);
- if (rval < 0)
+ if (rval) {
+ rval = -EFAULT;
goto exit;
+ }
ps_name[len] = '\0';
if (strlen(ps_name) % vqc.step) {
@@ -1031,8 +1062,10 @@ static int si4713_write_econtrol_string(struct si4713_device *sdev,
goto exit;
}
rval = copy_from_user(radio_text, control->string, len);
- if (rval < 0)
+ if (rval) {
+ rval = -EFAULT;
goto exit;
+ }
radio_text[len] = '\0';
if (strlen(radio_text) % vqc.step) {
@@ -1367,6 +1400,8 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev,
}
rval = copy_to_user(control->string, sdev->rds_info.ps_name,
strlen(sdev->rds_info.ps_name) + 1);
+ if (rval)
+ rval = -EFAULT;
break;
case V4L2_CID_RDS_TX_RADIO_TEXT:
@@ -1377,6 +1412,8 @@ static int si4713_read_econtrol_string(struct si4713_device *sdev,
}
rval = copy_to_user(control->string, sdev->rds_info.radio_text,
strlen(sdev->rds_info.radio_text) + 1);
+ if (rval)
+ rval = -EFAULT;
break;
default:
@@ -1796,7 +1833,7 @@ static int si4713_g_modulator(struct v4l2_subdev *sd, struct v4l2_modulator *vm)
strncpy(vm->name, "FM Modulator", 32);
vm->capability = V4L2_TUNER_CAP_STEREO | V4L2_TUNER_CAP_LOW |
- V4L2_TUNER_CAP_RDS;
+ V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_CONTROLS;
/* Report current frequency range limits */
vm->rangelow = si4713_to_v4l2(FREQ_RANGE_LOW);
@@ -1959,7 +1996,8 @@ static int si4713_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
struct si4713_device *sdev;
- int rval;
+ struct si4713_platform_data *pdata = client->dev.platform_data;
+ int rval, i;
sdev = kzalloc(sizeof *sdev, GFP_KERNEL);
if (!sdev) {
@@ -1968,11 +2006,26 @@ static int si4713_probe(struct i2c_client *client,
goto exit;
}
- sdev->platform_data = client->dev.platform_data;
- if (!sdev->platform_data) {
- v4l2_err(&sdev->sd, "No platform data registered.\n");
- rval = -ENODEV;
- goto free_sdev;
+ sdev->gpio_reset = -1;
+ if (pdata && gpio_is_valid(pdata->gpio_reset)) {
+ rval = gpio_request(pdata->gpio_reset, "si4713 reset");
+ if (rval) {
+ dev_err(&client->dev,
+ "Failed to request gpio: %d\n", rval);
+ goto free_sdev;
+ }
+ sdev->gpio_reset = pdata->gpio_reset;
+ gpio_direction_output(sdev->gpio_reset, 0);
+ }
+
+ for (i = 0; i < ARRAY_SIZE(sdev->supplies); i++)
+ sdev->supplies[i].supply = si4713_supply_names[i];
+
+ rval = regulator_bulk_get(&client->dev, ARRAY_SIZE(sdev->supplies),
+ sdev->supplies);
+ if (rval) {
+ dev_err(&client->dev, "Cannot get regulators: %d\n", rval);
+ goto free_gpio;
}
v4l2_i2c_subdev_init(&sdev->sd, client, &si4713_subdev_ops);
@@ -1986,7 +2039,7 @@ static int si4713_probe(struct i2c_client *client,
client->name, sdev);
if (rval < 0) {
v4l2_err(&sdev->sd, "Could not request IRQ\n");
- goto free_sdev;
+ goto put_reg;
}
v4l2_dbg(1, debug, &sdev->sd, "IRQ requested.\n");
} else {
@@ -2004,6 +2057,11 @@ static int si4713_probe(struct i2c_client *client,
free_irq:
if (client->irq)
free_irq(client->irq, sdev);
+put_reg:
+ regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
+free_gpio:
+ if (gpio_is_valid(sdev->gpio_reset))
+ gpio_free(sdev->gpio_reset);
free_sdev:
kfree(sdev);
exit:
@@ -2023,7 +2081,9 @@ static int si4713_remove(struct i2c_client *client)
free_irq(client->irq, sdev);
v4l2_device_unregister_subdev(sd);
-
+ regulator_bulk_free(ARRAY_SIZE(sdev->supplies), sdev->supplies);
+ if (gpio_is_valid(sdev->gpio_reset))
+ gpio_free(sdev->gpio_reset);
kfree(sdev);
return 0;
diff --git a/drivers/media/radio/si4713-i2c.h b/drivers/media/radio/si4713-i2c.h
index faf8cff124f1..c6dfa7fb101c 100644
--- a/drivers/media/radio/si4713-i2c.h
+++ b/drivers/media/radio/si4713-i2c.h
@@ -211,6 +211,8 @@ struct acomp_info {
u32 enabled;
};
+#define SI4713_NUM_SUPPLIES 2
+
/*
* si4713_device - private data
*/
@@ -220,11 +222,12 @@ struct si4713_device {
/* private data structures */
struct mutex mutex;
struct completion work;
- struct si4713_platform_data *platform_data;
struct rds_info rds_info;
struct limiter_info limiter_info;
struct pilot_info pilot_info;
struct acomp_info acomp_info;
+ struct regulator_bulk_data supplies[SI4713_NUM_SUPPLIES];
+ int gpio_reset;
u32 frequency;
u32 preemphasis;
u32 mute;
diff --git a/drivers/media/radio/tef6862.c b/drivers/media/radio/tef6862.c
index 90cae90277e7..7c0d77751f6e 100644
--- a/drivers/media/radio/tef6862.c
+++ b/drivers/media/radio/tef6862.c
@@ -22,7 +22,6 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/slab.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
diff --git a/drivers/media/rc/Kconfig b/drivers/media/rc/Kconfig
new file mode 100644
index 000000000000..3785162f928e
--- /dev/null
+++ b/drivers/media/rc/Kconfig
@@ -0,0 +1,193 @@
+menuconfig RC_CORE
+ tristate "Remote Controller adapters"
+ depends on INPUT
+ default INPUT
+ ---help---
+ Enable support for Remote Controllers on Linux. This is
+ needed in order to support several video capture adapters.
+ Currently, all supported devices use InfraRed.
+
+ Enable this option if you have a video capture board even
+ if you don't need IR, as otherwise, you may not be able to
+ compile the driver for your adapter.
+
+if RC_CORE
+
+config LIRC
+ tristate
+ default y
+
+ ---help---
+ Enable this option to build the Linux Infrared Remote
+ Control (LIRC) core device interface driver. The LIRC
+ interface passes raw IR to and from userspace, where the
+ LIRC daemon handles protocol decoding for IR reception and
+ encoding for IR transmitting (aka "blasting").
+
+source "drivers/media/rc/keymaps/Kconfig"
+
+config IR_NEC_DECODER
+ tristate "Enable IR raw decoder for the NEC protocol"
+ depends on RC_CORE
+ select BITREVERSE
+ default y
+
+ ---help---
+ Enable this option if you have IR with NEC protocol, and
+ if the IR is decoded in software
+
+config IR_RC5_DECODER
+ tristate "Enable IR raw decoder for the RC-5 protocol"
+ depends on RC_CORE
+ select BITREVERSE
+ default y
+
+ ---help---
+ Enable this option if you have IR with RC-5 protocol, and
+ if the IR is decoded in software
+
+config IR_RC6_DECODER
+ tristate "Enable IR raw decoder for the RC6 protocol"
+ depends on RC_CORE
+ select BITREVERSE
+ default y
+
+ ---help---
+ Enable this option if you have an infrared remote control which
+ uses the RC6 protocol, and you need software decoding support.
+
+config IR_JVC_DECODER
+ tristate "Enable IR raw decoder for the JVC protocol"
+ depends on RC_CORE
+ select BITREVERSE
+ default y
+
+ ---help---
+ Enable this option if you have an infrared remote control which
+ uses the JVC protocol, and you need software decoding support.
+
+config IR_SONY_DECODER
+ tristate "Enable IR raw decoder for the Sony protocol"
+ depends on RC_CORE
+ default y
+
+ ---help---
+ Enable this option if you have an infrared remote control which
+ uses the Sony protocol, and you need software decoding support.
+
+config IR_RC5_SZ_DECODER
+ tristate "Enable IR raw decoder for the RC-5 (streamzap) protocol"
+ depends on RC_CORE
+ select BITREVERSE
+ default y
+
+ ---help---
+ Enable this option if you have IR with RC-5 (streamzap) protocol,
+ and if the IR is decoded in software. (The Streamzap PC Remote
+ uses an IR protocol that is almost standard RC-5, but not quite,
+ as it uses an additional bit).
+
+config IR_LIRC_CODEC
+ tristate "Enable IR to LIRC bridge"
+ depends on RC_CORE
+ depends on LIRC
+ default y
+
+ ---help---
+ Enable this option to pass raw IR to and from userspace via
+ the LIRC interface.
+
+config IR_ENE
+ tristate "ENE eHome Receiver/Transceiver (pnp id: ENE0100/ENE02xxx)"
+ depends on PNP
+ depends on RC_CORE
+ ---help---
+ Say Y here to enable support for integrated infrared receiver
+ /transceiver made by ENE.
+
+ You can see if you have it by looking at lspnp output.
+ Output should include ENE0100 ENE0200 or something similar.
+
+ To compile this driver as a module, choose M here: the
+ module will be called ene_ir.
+
+config IR_IMON
+ tristate "SoundGraph iMON Receiver and Display"
+ depends on USB_ARCH_HAS_HCD
+ depends on RC_CORE
+ select USB
+ ---help---
+ Say Y here if you want to use a SoundGraph iMON (aka Antec Veris)
+ IR Receiver and/or LCD/VFD/VGA display.
+
+ To compile this driver as a module, choose M here: the
+ module will be called imon.
+
+config IR_MCEUSB
+ tristate "Windows Media Center Ed. eHome Infrared Transceiver"
+ depends on USB_ARCH_HAS_HCD
+ depends on RC_CORE
+ select USB
+ ---help---
+ Say Y here if you want to use a Windows Media Center Edition
+ eHome Infrared Transceiver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called mceusb.
+
+config IR_NUVOTON
+ tristate "Nuvoton w836x7hg Consumer Infrared Transceiver"
+ depends on PNP
+ depends on RC_CORE
+ ---help---
+ Say Y here to enable support for integrated infrared receiver
+ /transciever made by Nuvoton (formerly Winbond). This chip is
+ found in the ASRock ION 330HT, as well as assorted Intel
+ DP55-series motherboards (and of course, possibly others).
+
+ To compile this driver as a module, choose M here: the
+ module will be called nuvoton-cir.
+
+config IR_STREAMZAP
+ tristate "Streamzap PC Remote IR Receiver"
+ depends on USB_ARCH_HAS_HCD
+ depends on RC_CORE
+ select USB
+ ---help---
+ Say Y here if you want to use a Streamzap PC Remote
+ Infrared Receiver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called streamzap.
+
+config IR_WINBOND_CIR
+ tristate "Winbond IR remote control"
+ depends on X86 && PNP
+ depends on RC_CORE
+ select NEW_LEDS
+ select LEDS_CLASS
+ select LEDS_TRIGGERS
+ select BITREVERSE
+ ---help---
+ Say Y here if you want to use the IR remote functionality found
+ in some Winbond SuperI/O chips. Currently only the WPCD376I
+ chip is supported (included in some Intel Media series
+ motherboards).
+
+ To compile this driver as a module, choose M here: the module will
+ be called winbond_cir.
+
+config RC_LOOPBACK
+ tristate "Remote Control Loopback Driver"
+ depends on RC_CORE
+ ---help---
+ Say Y here if you want support for the remote control loopback
+ driver which allows TX data to be sent back as RX data.
+ This is mostly useful for debugging purposes.
+
+ If you're not sure, select N here.
+
+ To compile this driver as a module, choose M here: the module will
+ be called rc_loopback.
+
+endif #RC_CORE
diff --git a/drivers/media/rc/Makefile b/drivers/media/rc/Makefile
new file mode 100644
index 000000000000..67b4f7fe2577
--- /dev/null
+++ b/drivers/media/rc/Makefile
@@ -0,0 +1,22 @@
+rc-core-objs := rc-main.o ir-raw.o
+
+obj-y += keymaps/
+
+obj-$(CONFIG_RC_CORE) += rc-core.o
+obj-$(CONFIG_LIRC) += lirc_dev.o
+obj-$(CONFIG_IR_NEC_DECODER) += ir-nec-decoder.o
+obj-$(CONFIG_IR_RC5_DECODER) += ir-rc5-decoder.o
+obj-$(CONFIG_IR_RC6_DECODER) += ir-rc6-decoder.o
+obj-$(CONFIG_IR_JVC_DECODER) += ir-jvc-decoder.o
+obj-$(CONFIG_IR_SONY_DECODER) += ir-sony-decoder.o
+obj-$(CONFIG_IR_RC5_SZ_DECODER) += ir-rc5-sz-decoder.o
+obj-$(CONFIG_IR_LIRC_CODEC) += ir-lirc-codec.o
+
+# stand-alone IR receivers/transmitters
+obj-$(CONFIG_IR_IMON) += imon.o
+obj-$(CONFIG_IR_MCEUSB) += mceusb.o
+obj-$(CONFIG_IR_NUVOTON) += nuvoton-cir.o
+obj-$(CONFIG_IR_ENE) += ene_ir.o
+obj-$(CONFIG_IR_STREAMZAP) += streamzap.o
+obj-$(CONFIG_IR_WINBOND_CIR) += winbond-cir.o
+obj-$(CONFIG_RC_LOOPBACK) += rc-loopback.o
diff --git a/drivers/media/rc/ene_ir.c b/drivers/media/rc/ene_ir.c
new file mode 100644
index 000000000000..1ac49139158d
--- /dev/null
+++ b/drivers/media/rc/ene_ir.c
@@ -0,0 +1,1213 @@
+/*
+ * driver for ENE KB3926 B/C/D/E/F CIR (pnp id: ENE0XXX)
+ *
+ * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@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
+ *
+ * Special thanks to:
+ * Sami R. <maesesami@gmail.com> for lot of help in debugging and therefore
+ * bringing to life support for transmission & learning mode.
+ *
+ * Charlie Andrews <charliethepilot@googlemail.com> for lots of help in
+ * bringing up the support of new firmware buffer that is popular
+ * on latest notebooks
+ *
+ * ENE for partial device documentation
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/pnp.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <media/rc-core.h>
+#include "ene_ir.h"
+
+static int sample_period;
+static bool learning_mode_force;
+static int debug;
+static bool txsim;
+
+static void ene_set_reg_addr(struct ene_device *dev, u16 reg)
+{
+ outb(reg >> 8, dev->hw_io + ENE_ADDR_HI);
+ outb(reg & 0xFF, dev->hw_io + ENE_ADDR_LO);
+}
+
+/* read a hardware register */
+static u8 ene_read_reg(struct ene_device *dev, u16 reg)
+{
+ u8 retval;
+ ene_set_reg_addr(dev, reg);
+ retval = inb(dev->hw_io + ENE_IO);
+ dbg_regs("reg %04x == %02x", reg, retval);
+ return retval;
+}
+
+/* write a hardware register */
+static void ene_write_reg(struct ene_device *dev, u16 reg, u8 value)
+{
+ dbg_regs("reg %04x <- %02x", reg, value);
+ ene_set_reg_addr(dev, reg);
+ outb(value, dev->hw_io + ENE_IO);
+}
+
+/* Set bits in hardware register */
+static void ene_set_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
+{
+ dbg_regs("reg %04x |= %02x", reg, mask);
+ ene_set_reg_addr(dev, reg);
+ outb(inb(dev->hw_io + ENE_IO) | mask, dev->hw_io + ENE_IO);
+}
+
+/* Clear bits in hardware register */
+static void ene_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask)
+{
+ dbg_regs("reg %04x &= ~%02x ", reg, mask);
+ ene_set_reg_addr(dev, reg);
+ outb(inb(dev->hw_io + ENE_IO) & ~mask, dev->hw_io + ENE_IO);
+}
+
+/* A helper to set/clear a bit in register according to boolean variable */
+static void ene_set_clear_reg_mask(struct ene_device *dev, u16 reg, u8 mask,
+ bool set)
+{
+ if (set)
+ ene_set_reg_mask(dev, reg, mask);
+ else
+ ene_clear_reg_mask(dev, reg, mask);
+}
+
+/* detect hardware features */
+static int ene_hw_detect(struct ene_device *dev)
+{
+ u8 chip_major, chip_minor;
+ u8 hw_revision, old_ver;
+ u8 fw_reg2, fw_reg1;
+
+ ene_clear_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
+ chip_major = ene_read_reg(dev, ENE_ECVER_MAJOR);
+ chip_minor = ene_read_reg(dev, ENE_ECVER_MINOR);
+ ene_set_reg_mask(dev, ENE_ECSTS, ENE_ECSTS_RSRVD);
+
+ hw_revision = ene_read_reg(dev, ENE_ECHV);
+ old_ver = ene_read_reg(dev, ENE_HW_VER_OLD);
+
+ dev->pll_freq = (ene_read_reg(dev, ENE_PLLFRH) << 4) +
+ (ene_read_reg(dev, ENE_PLLFRL) >> 4);
+
+ if (sample_period != ENE_DEFAULT_SAMPLE_PERIOD)
+ dev->rx_period_adjust =
+ dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 2 : 4;
+
+ if (hw_revision == 0xFF) {
+ ene_warn("device seems to be disabled");
+ ene_warn("send a mail to lirc-list@lists.sourceforge.net");
+ ene_warn("please attach output of acpidump and dmidecode");
+ return -ENODEV;
+ }
+
+ ene_notice("chip is 0x%02x%02x - kbver = 0x%02x, rev = 0x%02x",
+ chip_major, chip_minor, old_ver, hw_revision);
+
+ ene_notice("PLL freq = %d", dev->pll_freq);
+
+ if (chip_major == 0x33) {
+ ene_warn("chips 0x33xx aren't supported");
+ return -ENODEV;
+ }
+
+ if (chip_major == 0x39 && chip_minor == 0x26 && hw_revision == 0xC0) {
+ dev->hw_revision = ENE_HW_C;
+ ene_notice("KB3926C detected");
+ } else if (old_ver == 0x24 && hw_revision == 0xC0) {
+ dev->hw_revision = ENE_HW_B;
+ ene_notice("KB3926B detected");
+ } else {
+ dev->hw_revision = ENE_HW_D;
+ ene_notice("KB3926D or higher detected");
+ }
+
+ /* detect features hardware supports */
+ if (dev->hw_revision < ENE_HW_C)
+ return 0;
+
+ fw_reg1 = ene_read_reg(dev, ENE_FW1);
+ fw_reg2 = ene_read_reg(dev, ENE_FW2);
+
+ ene_notice("Firmware regs: %02x %02x", fw_reg1, fw_reg2);
+
+ dev->hw_use_gpio_0a = !!(fw_reg2 & ENE_FW2_GP0A);
+ dev->hw_learning_and_tx_capable = !!(fw_reg2 & ENE_FW2_LEARNING);
+ dev->hw_extra_buffer = !!(fw_reg1 & ENE_FW1_HAS_EXTRA_BUF);
+
+ if (dev->hw_learning_and_tx_capable)
+ dev->hw_fan_input = !!(fw_reg2 & ENE_FW2_FAN_INPUT);
+
+ ene_notice("Hardware features:");
+
+ if (dev->hw_learning_and_tx_capable) {
+ ene_notice("* Supports transmitting & learning mode");
+ ene_notice(" This feature is rare and therefore,");
+ ene_notice(" you are welcome to test it,");
+ ene_notice(" and/or contact the author via:");
+ ene_notice(" lirc-list@lists.sourceforge.net");
+ ene_notice(" or maximlevitsky@gmail.com");
+
+ ene_notice("* Uses GPIO %s for IR raw input",
+ dev->hw_use_gpio_0a ? "40" : "0A");
+
+ if (dev->hw_fan_input)
+ ene_notice("* Uses unused fan feedback input as source"
+ " of demodulated IR data");
+ }
+
+ if (!dev->hw_fan_input)
+ ene_notice("* Uses GPIO %s for IR demodulated input",
+ dev->hw_use_gpio_0a ? "0A" : "40");
+
+ if (dev->hw_extra_buffer)
+ ene_notice("* Uses new style input buffer");
+ return 0;
+}
+
+/* Read properities of hw sample buffer */
+static void ene_rx_setup_hw_buffer(struct ene_device *dev)
+{
+ u16 tmp;
+
+ ene_rx_read_hw_pointer(dev);
+ dev->r_pointer = dev->w_pointer;
+
+ if (!dev->hw_extra_buffer) {
+ dev->buffer_len = ENE_FW_PACKET_SIZE * 2;
+ return;
+ }
+
+ tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER);
+ tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER+1) << 8;
+ dev->extra_buf1_address = tmp;
+
+ dev->extra_buf1_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 2);
+
+ tmp = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 3);
+ tmp |= ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 4) << 8;
+ dev->extra_buf2_address = tmp;
+
+ dev->extra_buf2_len = ene_read_reg(dev, ENE_FW_SAMPLE_BUFFER + 5);
+
+ dev->buffer_len = dev->extra_buf1_len + dev->extra_buf2_len + 8;
+
+ ene_notice("Hardware uses 2 extended buffers:");
+ ene_notice(" 0x%04x - len : %d", dev->extra_buf1_address,
+ dev->extra_buf1_len);
+ ene_notice(" 0x%04x - len : %d", dev->extra_buf2_address,
+ dev->extra_buf2_len);
+
+ ene_notice("Total buffer len = %d", dev->buffer_len);
+
+ if (dev->buffer_len > 64 || dev->buffer_len < 16)
+ goto error;
+
+ if (dev->extra_buf1_address > 0xFBFC ||
+ dev->extra_buf1_address < 0xEC00)
+ goto error;
+
+ if (dev->extra_buf2_address > 0xFBFC ||
+ dev->extra_buf2_address < 0xEC00)
+ goto error;
+
+ if (dev->r_pointer > dev->buffer_len)
+ goto error;
+
+ ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+ return;
+error:
+ ene_warn("Error validating extra buffers, device probably won't work");
+ dev->hw_extra_buffer = false;
+ ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+}
+
+
+/* Restore the pointers to extra buffers - to make module reload work*/
+static void ene_rx_restore_hw_buffer(struct ene_device *dev)
+{
+ if (!dev->hw_extra_buffer)
+ return;
+
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 0,
+ dev->extra_buf1_address & 0xFF);
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 1,
+ dev->extra_buf1_address >> 8);
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 2, dev->extra_buf1_len);
+
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 3,
+ dev->extra_buf2_address & 0xFF);
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 4,
+ dev->extra_buf2_address >> 8);
+ ene_write_reg(dev, ENE_FW_SAMPLE_BUFFER + 5,
+ dev->extra_buf2_len);
+ ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_EXTRA_BUF_HND);
+}
+
+/* Read hardware write pointer */
+static void ene_rx_read_hw_pointer(struct ene_device *dev)
+{
+ if (dev->hw_extra_buffer)
+ dev->w_pointer = ene_read_reg(dev, ENE_FW_RX_POINTER);
+ else
+ dev->w_pointer = ene_read_reg(dev, ENE_FW2)
+ & ENE_FW2_BUF_WPTR ? 0 : ENE_FW_PACKET_SIZE;
+
+ dbg_verbose("RB: HW write pointer: %02x, driver read pointer: %02x",
+ dev->w_pointer, dev->r_pointer);
+}
+
+/* Gets address of next sample from HW ring buffer */
+static int ene_rx_get_sample_reg(struct ene_device *dev)
+{
+ int r_pointer;
+
+ if (dev->r_pointer == dev->w_pointer) {
+ dbg_verbose("RB: hit end, try update w_pointer");
+ ene_rx_read_hw_pointer(dev);
+ }
+
+ if (dev->r_pointer == dev->w_pointer) {
+ dbg_verbose("RB: end of data at %d", dev->r_pointer);
+ return 0;
+ }
+
+ dbg_verbose("RB: reading at offset %d", dev->r_pointer);
+ r_pointer = dev->r_pointer;
+
+ dev->r_pointer++;
+ if (dev->r_pointer == dev->buffer_len)
+ dev->r_pointer = 0;
+
+ dbg_verbose("RB: next read will be from offset %d", dev->r_pointer);
+
+ if (r_pointer < 8) {
+ dbg_verbose("RB: read at main buffer at %d", r_pointer);
+ return ENE_FW_SAMPLE_BUFFER + r_pointer;
+ }
+
+ r_pointer -= 8;
+
+ if (r_pointer < dev->extra_buf1_len) {
+ dbg_verbose("RB: read at 1st extra buffer at %d", r_pointer);
+ return dev->extra_buf1_address + r_pointer;
+ }
+
+ r_pointer -= dev->extra_buf1_len;
+
+ if (r_pointer < dev->extra_buf2_len) {
+ dbg_verbose("RB: read at 2nd extra buffer at %d", r_pointer);
+ return dev->extra_buf2_address + r_pointer;
+ }
+
+ dbg("attempt to read beyong ring bufer end");
+ return 0;
+}
+
+/* Sense current received carrier */
+void ene_rx_sense_carrier(struct ene_device *dev)
+{
+ DEFINE_IR_RAW_EVENT(ev);
+
+ int carrier, duty_cycle;
+ int period = ene_read_reg(dev, ENE_CIRCAR_PRD);
+ int hperiod = ene_read_reg(dev, ENE_CIRCAR_HPRD);
+
+ if (!(period & ENE_CIRCAR_PRD_VALID))
+ return;
+
+ period &= ~ENE_CIRCAR_PRD_VALID;
+
+ if (!period)
+ return;
+
+ dbg("RX: hardware carrier period = %02x", period);
+ dbg("RX: hardware carrier pulse period = %02x", hperiod);
+
+ carrier = 2000000 / period;
+ duty_cycle = (hperiod * 100) / period;
+ dbg("RX: sensed carrier = %d Hz, duty cycle %d%%",
+ carrier, duty_cycle);
+ if (dev->carrier_detect_enabled) {
+ ev.carrier_report = true;
+ ev.carrier = carrier;
+ ev.duty_cycle = duty_cycle;
+ ir_raw_event_store(dev->rdev, &ev);
+ }
+}
+
+/* this enables/disables the CIR RX engine */
+static void ene_rx_enable_cir_engine(struct ene_device *dev, bool enable)
+{
+ ene_set_clear_reg_mask(dev, ENE_CIRCFG,
+ ENE_CIRCFG_RX_EN | ENE_CIRCFG_RX_IRQ, enable);
+}
+
+/* this selects input for CIR engine. Ether GPIO 0A or GPIO40*/
+static void ene_rx_select_input(struct ene_device *dev, bool gpio_0a)
+{
+ ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_GPIO0A, gpio_0a);
+}
+
+/*
+ * this enables alternative input via fan tachometer sensor and bypasses
+ * the hw CIR engine
+ */
+static void ene_rx_enable_fan_input(struct ene_device *dev, bool enable)
+{
+ if (!dev->hw_fan_input)
+ return;
+
+ if (!enable)
+ ene_write_reg(dev, ENE_FAN_AS_IN1, 0);
+ else {
+ ene_write_reg(dev, ENE_FAN_AS_IN1, ENE_FAN_AS_IN1_EN);
+ ene_write_reg(dev, ENE_FAN_AS_IN2, ENE_FAN_AS_IN2_EN);
+ }
+}
+
+/* setup the receiver for RX*/
+static void ene_rx_setup(struct ene_device *dev)
+{
+ bool learning_mode = dev->learning_mode_enabled ||
+ dev->carrier_detect_enabled;
+ int sample_period_adjust = 0;
+
+ dbg("RX: setup receiver, learning mode = %d", learning_mode);
+
+
+ /* This selects RLC input and clears CFG2 settings */
+ ene_write_reg(dev, ENE_CIRCFG2, 0x00);
+
+ /* set sample period*/
+ if (sample_period == ENE_DEFAULT_SAMPLE_PERIOD)
+ sample_period_adjust =
+ dev->pll_freq == ENE_DEFAULT_PLL_FREQ ? 1 : 2;
+
+ ene_write_reg(dev, ENE_CIRRLC_CFG,
+ (sample_period + sample_period_adjust) |
+ ENE_CIRRLC_CFG_OVERFLOW);
+ /* revB doesn't support inputs */
+ if (dev->hw_revision < ENE_HW_C)
+ goto select_timeout;
+
+ if (learning_mode) {
+
+ WARN_ON(!dev->hw_learning_and_tx_capable);
+
+ /* Enable the opposite of the normal input
+ That means that if GPIO40 is normally used, use GPIO0A
+ and vice versa.
+ This input will carry non demodulated
+ signal, and we will tell the hw to demodulate it itself */
+ ene_rx_select_input(dev, !dev->hw_use_gpio_0a);
+ dev->rx_fan_input_inuse = false;
+
+ /* Enable carrier demodulation */
+ ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
+
+ /* Enable carrier detection */
+ ene_write_reg(dev, ENE_CIRCAR_PULS, 0x63);
+ ene_set_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT,
+ dev->carrier_detect_enabled || debug);
+ } else {
+ if (dev->hw_fan_input)
+ dev->rx_fan_input_inuse = true;
+ else
+ ene_rx_select_input(dev, dev->hw_use_gpio_0a);
+
+ /* Disable carrier detection & demodulation */
+ ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_CARR_DEMOD);
+ ene_clear_reg_mask(dev, ENE_CIRCFG2, ENE_CIRCFG2_CARR_DETECT);
+ }
+
+select_timeout:
+ if (dev->rx_fan_input_inuse) {
+ dev->rdev->rx_resolution = US_TO_NS(ENE_FW_SAMPLE_PERIOD_FAN);
+
+ /* Fan input doesn't support timeouts, it just ends the
+ input with a maximum sample */
+ dev->rdev->min_timeout = dev->rdev->max_timeout =
+ US_TO_NS(ENE_FW_SMPL_BUF_FAN_MSK *
+ ENE_FW_SAMPLE_PERIOD_FAN);
+ } else {
+ dev->rdev->rx_resolution = US_TO_NS(sample_period);
+
+ /* Theoreticly timeout is unlimited, but we cap it
+ * because it was seen that on one device, it
+ * would stop sending spaces after around 250 msec.
+ * Besides, this is close to 2^32 anyway and timeout is u32.
+ */
+ dev->rdev->min_timeout = US_TO_NS(127 * sample_period);
+ dev->rdev->max_timeout = US_TO_NS(200000);
+ }
+
+ if (dev->hw_learning_and_tx_capable)
+ dev->rdev->tx_resolution = US_TO_NS(sample_period);
+
+ if (dev->rdev->timeout > dev->rdev->max_timeout)
+ dev->rdev->timeout = dev->rdev->max_timeout;
+ if (dev->rdev->timeout < dev->rdev->min_timeout)
+ dev->rdev->timeout = dev->rdev->min_timeout;
+}
+
+/* Enable the device for receive */
+static void ene_rx_enable(struct ene_device *dev)
+{
+ u8 reg_value;
+
+ /* Enable system interrupt */
+ if (dev->hw_revision < ENE_HW_C) {
+ ene_write_reg(dev, ENEB_IRQ, dev->irq << 1);
+ ene_write_reg(dev, ENEB_IRQ_UNK1, 0x01);
+ } else {
+ reg_value = ene_read_reg(dev, ENE_IRQ) & 0xF0;
+ reg_value |= ENE_IRQ_UNK_EN;
+ reg_value &= ~ENE_IRQ_STATUS;
+ reg_value |= (dev->irq & ENE_IRQ_MASK);
+ ene_write_reg(dev, ENE_IRQ, reg_value);
+ }
+
+ /* Enable inputs */
+ ene_rx_enable_fan_input(dev, dev->rx_fan_input_inuse);
+ ene_rx_enable_cir_engine(dev, !dev->rx_fan_input_inuse);
+
+ /* ack any pending irqs - just in case */
+ ene_irq_status(dev);
+
+ /* enable firmware bits */
+ ene_set_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
+
+ /* enter idle mode */
+ ir_raw_event_set_idle(dev->rdev, true);
+ dev->rx_enabled = true;
+}
+
+/* Disable the device receiver */
+static void ene_rx_disable(struct ene_device *dev)
+{
+ /* disable inputs */
+ ene_rx_enable_cir_engine(dev, false);
+ ene_rx_enable_fan_input(dev, false);
+
+ /* disable hardware IRQ and firmware flag */
+ ene_clear_reg_mask(dev, ENE_FW1, ENE_FW1_ENABLE | ENE_FW1_IRQ);
+
+ ir_raw_event_set_idle(dev->rdev, true);
+ dev->rx_enabled = false;
+}
+
+/* This resets the receiver. Usefull to stop stream of spaces at end of
+ * transmission
+ */
+static void ene_rx_reset(struct ene_device *dev)
+{
+ ene_clear_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
+ ene_set_reg_mask(dev, ENE_CIRCFG, ENE_CIRCFG_RX_EN);
+}
+
+/* Set up the TX carrier frequency and duty cycle */
+static void ene_tx_set_carrier(struct ene_device *dev)
+{
+ u8 tx_puls_width;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+
+ ene_set_clear_reg_mask(dev, ENE_CIRCFG,
+ ENE_CIRCFG_TX_CARR, dev->tx_period > 0);
+
+ if (!dev->tx_period)
+ goto unlock;
+
+ BUG_ON(dev->tx_duty_cycle >= 100 || dev->tx_duty_cycle <= 0);
+
+ tx_puls_width = dev->tx_period / (100 / dev->tx_duty_cycle);
+
+ if (!tx_puls_width)
+ tx_puls_width = 1;
+
+ dbg("TX: pulse distance = %d * 500 ns", dev->tx_period);
+ dbg("TX: pulse width = %d * 500 ns", tx_puls_width);
+
+ ene_write_reg(dev, ENE_CIRMOD_PRD, dev->tx_period | ENE_CIRMOD_PRD_POL);
+ ene_write_reg(dev, ENE_CIRMOD_HPRD, tx_puls_width);
+unlock:
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+}
+
+/* Enable/disable transmitters */
+static void ene_tx_set_transmitters(struct ene_device *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ ene_set_clear_reg_mask(dev, ENE_GPIOFS8, ENE_GPIOFS8_GPIO41,
+ !!(dev->transmitter_mask & 0x01));
+ ene_set_clear_reg_mask(dev, ENE_GPIOFS1, ENE_GPIOFS1_GPIO0D,
+ !!(dev->transmitter_mask & 0x02));
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+}
+
+/* prepare transmission */
+static void ene_tx_enable(struct ene_device *dev)
+{
+ u8 conf1 = ene_read_reg(dev, ENE_CIRCFG);
+ u8 fwreg2 = ene_read_reg(dev, ENE_FW2);
+
+ dev->saved_conf1 = conf1;
+
+ /* Show information about currently connected transmitter jacks */
+ if (fwreg2 & ENE_FW2_EMMITER1_CONN)
+ dbg("TX: Transmitter #1 is connected");
+
+ if (fwreg2 & ENE_FW2_EMMITER2_CONN)
+ dbg("TX: Transmitter #2 is connected");
+
+ if (!(fwreg2 & (ENE_FW2_EMMITER1_CONN | ENE_FW2_EMMITER2_CONN)))
+ ene_warn("TX: transmitter cable isn't connected!");
+
+ /* disable receive on revc */
+ if (dev->hw_revision == ENE_HW_C)
+ conf1 &= ~ENE_CIRCFG_RX_EN;
+
+ /* Enable TX engine */
+ conf1 |= ENE_CIRCFG_TX_EN | ENE_CIRCFG_TX_IRQ;
+ ene_write_reg(dev, ENE_CIRCFG, conf1);
+}
+
+/* end transmission */
+static void ene_tx_disable(struct ene_device *dev)
+{
+ ene_write_reg(dev, ENE_CIRCFG, dev->saved_conf1);
+ dev->tx_buffer = NULL;
+}
+
+
+/* TX one sample - must be called with dev->hw_lock*/
+static void ene_tx_sample(struct ene_device *dev)
+{
+ u8 raw_tx;
+ u32 sample;
+ bool pulse = dev->tx_sample_pulse;
+
+ if (!dev->tx_buffer) {
+ ene_warn("TX: BUG: attempt to transmit NULL buffer");
+ return;
+ }
+
+ /* Grab next TX sample */
+ if (!dev->tx_sample) {
+
+ if (dev->tx_pos == dev->tx_len) {
+ if (!dev->tx_done) {
+ dbg("TX: no more data to send");
+ dev->tx_done = true;
+ goto exit;
+ } else {
+ dbg("TX: last sample sent by hardware");
+ ene_tx_disable(dev);
+ complete(&dev->tx_complete);
+ return;
+ }
+ }
+
+ sample = dev->tx_buffer[dev->tx_pos++];
+ dev->tx_sample_pulse = !dev->tx_sample_pulse;
+
+ dev->tx_sample = DIV_ROUND_CLOSEST(sample, sample_period);
+
+ if (!dev->tx_sample)
+ dev->tx_sample = 1;
+ }
+
+ raw_tx = min(dev->tx_sample , (unsigned int)ENE_CIRRLC_OUT_MASK);
+ dev->tx_sample -= raw_tx;
+
+ dbg("TX: sample %8d (%s)", raw_tx * sample_period,
+ pulse ? "pulse" : "space");
+ if (pulse)
+ raw_tx |= ENE_CIRRLC_OUT_PULSE;
+
+ ene_write_reg(dev,
+ dev->tx_reg ? ENE_CIRRLC_OUT1 : ENE_CIRRLC_OUT0, raw_tx);
+
+ dev->tx_reg = !dev->tx_reg;
+exit:
+ /* simulate TX done interrupt */
+ if (txsim)
+ mod_timer(&dev->tx_sim_timer, jiffies + HZ / 500);
+}
+
+/* timer to simulate tx done interrupt */
+static void ene_tx_irqsim(unsigned long data)
+{
+ struct ene_device *dev = (struct ene_device *)data;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ ene_tx_sample(dev);
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+}
+
+
+/* read irq status and ack it */
+static int ene_irq_status(struct ene_device *dev)
+{
+ u8 irq_status;
+ u8 fw_flags1, fw_flags2;
+ int retval = 0;
+
+ fw_flags2 = ene_read_reg(dev, ENE_FW2);
+
+ if (dev->hw_revision < ENE_HW_C) {
+ irq_status = ene_read_reg(dev, ENEB_IRQ_STATUS);
+
+ if (!(irq_status & ENEB_IRQ_STATUS_IR))
+ return 0;
+
+ ene_clear_reg_mask(dev, ENEB_IRQ_STATUS, ENEB_IRQ_STATUS_IR);
+ return ENE_IRQ_RX;
+ }
+
+ irq_status = ene_read_reg(dev, ENE_IRQ);
+ if (!(irq_status & ENE_IRQ_STATUS))
+ return 0;
+
+ /* original driver does that twice - a workaround ? */
+ ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
+ ene_write_reg(dev, ENE_IRQ, irq_status & ~ENE_IRQ_STATUS);
+
+ /* check RX interrupt */
+ if (fw_flags2 & ENE_FW2_RXIRQ) {
+ retval |= ENE_IRQ_RX;
+ ene_write_reg(dev, ENE_FW2, fw_flags2 & ~ENE_FW2_RXIRQ);
+ }
+
+ /* check TX interrupt */
+ fw_flags1 = ene_read_reg(dev, ENE_FW1);
+ if (fw_flags1 & ENE_FW1_TXIRQ) {
+ ene_write_reg(dev, ENE_FW1, fw_flags1 & ~ENE_FW1_TXIRQ);
+ retval |= ENE_IRQ_TX;
+ }
+
+ return retval;
+}
+
+/* interrupt handler */
+static irqreturn_t ene_isr(int irq, void *data)
+{
+ u16 hw_value, reg;
+ int hw_sample, irq_status;
+ bool pulse;
+ unsigned long flags;
+ irqreturn_t retval = IRQ_NONE;
+ struct ene_device *dev = (struct ene_device *)data;
+ DEFINE_IR_RAW_EVENT(ev);
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+
+ dbg_verbose("ISR called");
+ ene_rx_read_hw_pointer(dev);
+ irq_status = ene_irq_status(dev);
+
+ if (!irq_status)
+ goto unlock;
+
+ retval = IRQ_HANDLED;
+
+ if (irq_status & ENE_IRQ_TX) {
+ dbg_verbose("TX interrupt");
+ if (!dev->hw_learning_and_tx_capable) {
+ dbg("TX interrupt on unsupported device!");
+ goto unlock;
+ }
+ ene_tx_sample(dev);
+ }
+
+ if (!(irq_status & ENE_IRQ_RX))
+ goto unlock;
+
+ dbg_verbose("RX interrupt");
+
+ if (dev->hw_learning_and_tx_capable)
+ ene_rx_sense_carrier(dev);
+
+ /* On hardware that don't support extra buffer we need to trust
+ the interrupt and not track the read pointer */
+ if (!dev->hw_extra_buffer)
+ dev->r_pointer = dev->w_pointer == 0 ? ENE_FW_PACKET_SIZE : 0;
+
+ while (1) {
+
+ reg = ene_rx_get_sample_reg(dev);
+
+ dbg_verbose("next sample to read at: %04x", reg);
+ if (!reg)
+ break;
+
+ hw_value = ene_read_reg(dev, reg);
+
+ if (dev->rx_fan_input_inuse) {
+
+ int offset = ENE_FW_SMPL_BUF_FAN - ENE_FW_SAMPLE_BUFFER;
+
+ /* read high part of the sample */
+ hw_value |= ene_read_reg(dev, reg + offset) << 8;
+ pulse = hw_value & ENE_FW_SMPL_BUF_FAN_PLS;
+
+ /* clear space bit, and other unused bits */
+ hw_value &= ENE_FW_SMPL_BUF_FAN_MSK;
+ hw_sample = hw_value * ENE_FW_SAMPLE_PERIOD_FAN;
+
+ } else {
+ pulse = !(hw_value & ENE_FW_SAMPLE_SPACE);
+ hw_value &= ~ENE_FW_SAMPLE_SPACE;
+ hw_sample = hw_value * sample_period;
+
+ if (dev->rx_period_adjust) {
+ hw_sample *= 100;
+ hw_sample /= (100 + dev->rx_period_adjust);
+ }
+ }
+
+ if (!dev->hw_extra_buffer && !hw_sample) {
+ dev->r_pointer = dev->w_pointer;
+ continue;
+ }
+
+ dbg("RX: %d (%s)", hw_sample, pulse ? "pulse" : "space");
+
+ ev.duration = US_TO_NS(hw_sample);
+ ev.pulse = pulse;
+ ir_raw_event_store_with_filter(dev->rdev, &ev);
+ }
+
+ ir_raw_event_handle(dev->rdev);
+unlock:
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+ return retval;
+}
+
+/* Initialize default settings */
+static void ene_setup_default_settings(struct ene_device *dev)
+{
+ dev->tx_period = 32;
+ dev->tx_duty_cycle = 50; /*%*/
+ dev->transmitter_mask = 0x03;
+ dev->learning_mode_enabled = learning_mode_force;
+
+ /* Set reasonable default timeout */
+ dev->rdev->timeout = US_TO_NS(150000);
+}
+
+/* Upload all hardware settings at once. Used at load and resume time */
+static void ene_setup_hw_settings(struct ene_device *dev)
+{
+ if (dev->hw_learning_and_tx_capable) {
+ ene_tx_set_carrier(dev);
+ ene_tx_set_transmitters(dev);
+ }
+
+ ene_rx_setup(dev);
+}
+
+/* outside interface: called on first open*/
+static int ene_open(struct rc_dev *rdev)
+{
+ struct ene_device *dev = rdev->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ ene_rx_enable(dev);
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+ return 0;
+}
+
+/* outside interface: called on device close*/
+static void ene_close(struct rc_dev *rdev)
+{
+ struct ene_device *dev = rdev->priv;
+ unsigned long flags;
+ spin_lock_irqsave(&dev->hw_lock, flags);
+
+ ene_rx_disable(dev);
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+}
+
+/* outside interface: set transmitter mask */
+static int ene_set_tx_mask(struct rc_dev *rdev, u32 tx_mask)
+{
+ struct ene_device *dev = rdev->priv;
+ dbg("TX: attempt to set transmitter mask %02x", tx_mask);
+
+ /* invalid txmask */
+ if (!tx_mask || tx_mask & ~0x03) {
+ dbg("TX: invalid mask");
+ /* return count of transmitters */
+ return 2;
+ }
+
+ dev->transmitter_mask = tx_mask;
+ ene_tx_set_transmitters(dev);
+ return 0;
+}
+
+/* outside interface : set tx carrier */
+static int ene_set_tx_carrier(struct rc_dev *rdev, u32 carrier)
+{
+ struct ene_device *dev = rdev->priv;
+ u32 period = 2000000 / carrier;
+
+ dbg("TX: attempt to set tx carrier to %d kHz", carrier);
+
+ if (period && (period > ENE_CIRMOD_PRD_MAX ||
+ period < ENE_CIRMOD_PRD_MIN)) {
+
+ dbg("TX: out of range %d-%d kHz carrier",
+ 2000 / ENE_CIRMOD_PRD_MIN, 2000 / ENE_CIRMOD_PRD_MAX);
+ return -1;
+ }
+
+ dev->tx_period = period;
+ ene_tx_set_carrier(dev);
+ return 0;
+}
+
+/*outside interface : set tx duty cycle */
+static int ene_set_tx_duty_cycle(struct rc_dev *rdev, u32 duty_cycle)
+{
+ struct ene_device *dev = rdev->priv;
+ dbg("TX: setting duty cycle to %d%%", duty_cycle);
+ dev->tx_duty_cycle = duty_cycle;
+ ene_tx_set_carrier(dev);
+ return 0;
+}
+
+/* outside interface: enable learning mode */
+static int ene_set_learning_mode(struct rc_dev *rdev, int enable)
+{
+ struct ene_device *dev = rdev->priv;
+ unsigned long flags;
+ if (enable == dev->learning_mode_enabled)
+ return 0;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ dev->learning_mode_enabled = enable;
+ ene_rx_disable(dev);
+ ene_rx_setup(dev);
+ ene_rx_enable(dev);
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+ return 0;
+}
+
+static int ene_set_carrier_report(struct rc_dev *rdev, int enable)
+{
+ struct ene_device *dev = rdev->priv;
+ unsigned long flags;
+
+ if (enable == dev->carrier_detect_enabled)
+ return 0;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ dev->carrier_detect_enabled = enable;
+ ene_rx_disable(dev);
+ ene_rx_setup(dev);
+ ene_rx_enable(dev);
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+ return 0;
+}
+
+/* outside interface: enable or disable idle mode */
+static void ene_set_idle(struct rc_dev *rdev, bool idle)
+{
+ struct ene_device *dev = rdev->priv;
+
+ if (idle) {
+ ene_rx_reset(dev);
+ dbg("RX: end of data");
+ }
+}
+
+/* outside interface: transmit */
+static int ene_transmit(struct rc_dev *rdev, int *buf, u32 n)
+{
+ struct ene_device *dev = rdev->priv;
+ unsigned long flags;
+
+ dev->tx_buffer = buf;
+ dev->tx_len = n / sizeof(int);
+ dev->tx_pos = 0;
+ dev->tx_reg = 0;
+ dev->tx_done = 0;
+ dev->tx_sample = 0;
+ dev->tx_sample_pulse = 0;
+
+ dbg("TX: %d samples", dev->tx_len);
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+
+ ene_tx_enable(dev);
+
+ /* Transmit first two samples */
+ ene_tx_sample(dev);
+ ene_tx_sample(dev);
+
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+
+ if (wait_for_completion_timeout(&dev->tx_complete, 2 * HZ) == 0) {
+ dbg("TX: timeout");
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ ene_tx_disable(dev);
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+ } else
+ dbg("TX: done");
+ return n;
+}
+
+/* probe entry */
+static int ene_probe(struct pnp_dev *pnp_dev, const struct pnp_device_id *id)
+{
+ int error = -ENOMEM;
+ struct rc_dev *rdev;
+ struct ene_device *dev;
+
+ /* allocate memory */
+ dev = kzalloc(sizeof(struct ene_device), GFP_KERNEL);
+ rdev = rc_allocate_device();
+ if (!dev || !rdev)
+ goto error1;
+
+ /* validate resources */
+ error = -ENODEV;
+
+ /* init these to -1, as 0 is valid for both */
+ dev->hw_io = -1;
+ dev->irq = -1;
+
+ if (!pnp_port_valid(pnp_dev, 0) ||
+ pnp_port_len(pnp_dev, 0) < ENE_IO_SIZE)
+ goto error;
+
+ if (!pnp_irq_valid(pnp_dev, 0))
+ goto error;
+
+ spin_lock_init(&dev->hw_lock);
+
+ /* claim the resources */
+ error = -EBUSY;
+ dev->hw_io = pnp_port_start(pnp_dev, 0);
+ if (!request_region(dev->hw_io, ENE_IO_SIZE, ENE_DRIVER_NAME)) {
+ dev->hw_io = -1;
+ dev->irq = -1;
+ goto error;
+ }
+
+ dev->irq = pnp_irq(pnp_dev, 0);
+ if (request_irq(dev->irq, ene_isr,
+ IRQF_SHARED, ENE_DRIVER_NAME, (void *)dev)) {
+ dev->irq = -1;
+ goto error;
+ }
+
+ pnp_set_drvdata(pnp_dev, dev);
+ dev->pnp_dev = pnp_dev;
+
+ /* don't allow too short/long sample periods */
+ if (sample_period < 5 || sample_period > 0x7F)
+ sample_period = ENE_DEFAULT_SAMPLE_PERIOD;
+
+ /* detect hardware version and features */
+ error = ene_hw_detect(dev);
+ if (error)
+ goto error;
+
+ if (!dev->hw_learning_and_tx_capable && txsim) {
+ dev->hw_learning_and_tx_capable = true;
+ setup_timer(&dev->tx_sim_timer, ene_tx_irqsim,
+ (long unsigned int)dev);
+ ene_warn("Simulation of TX activated");
+ }
+
+ if (!dev->hw_learning_and_tx_capable)
+ learning_mode_force = false;
+
+ rdev->driver_type = RC_DRIVER_IR_RAW;
+ rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->priv = dev;
+ rdev->open = ene_open;
+ rdev->close = ene_close;
+ rdev->s_idle = ene_set_idle;
+ rdev->driver_name = ENE_DRIVER_NAME;
+ rdev->map_name = RC_MAP_RC6_MCE;
+ rdev->input_name = "ENE eHome Infrared Remote Receiver";
+
+ if (dev->hw_learning_and_tx_capable) {
+ rdev->s_learning_mode = ene_set_learning_mode;
+ init_completion(&dev->tx_complete);
+ rdev->tx_ir = ene_transmit;
+ rdev->s_tx_mask = ene_set_tx_mask;
+ rdev->s_tx_carrier = ene_set_tx_carrier;
+ rdev->s_tx_duty_cycle = ene_set_tx_duty_cycle;
+ rdev->s_carrier_report = ene_set_carrier_report;
+ rdev->input_name = "ENE eHome Infrared Remote Transceiver";
+ }
+
+ dev->rdev = rdev;
+
+ ene_rx_setup_hw_buffer(dev);
+ ene_setup_default_settings(dev);
+ ene_setup_hw_settings(dev);
+
+ device_set_wakeup_capable(&pnp_dev->dev, true);
+ device_set_wakeup_enable(&pnp_dev->dev, true);
+
+ error = rc_register_device(rdev);
+ if (error < 0)
+ goto error;
+
+ ene_notice("driver has been succesfully loaded");
+ return 0;
+error:
+ if (dev && dev->irq >= 0)
+ free_irq(dev->irq, dev);
+ if (dev && dev->hw_io >= 0)
+ release_region(dev->hw_io, ENE_IO_SIZE);
+error1:
+ rc_free_device(rdev);
+ kfree(dev);
+ return error;
+}
+
+/* main unload function */
+static void ene_remove(struct pnp_dev *pnp_dev)
+{
+ struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->hw_lock, flags);
+ ene_rx_disable(dev);
+ ene_rx_restore_hw_buffer(dev);
+ spin_unlock_irqrestore(&dev->hw_lock, flags);
+
+ free_irq(dev->irq, dev);
+ release_region(dev->hw_io, ENE_IO_SIZE);
+ rc_unregister_device(dev->rdev);
+ kfree(dev);
+}
+
+/* enable wake on IR (wakes on specific button on original remote) */
+static void ene_enable_wake(struct ene_device *dev, int enable)
+{
+ enable = enable && device_may_wakeup(&dev->pnp_dev->dev);
+ dbg("wake on IR %s", enable ? "enabled" : "disabled");
+ ene_set_clear_reg_mask(dev, ENE_FW1, ENE_FW1_WAKE, enable);
+}
+
+#ifdef CONFIG_PM
+static int ene_suspend(struct pnp_dev *pnp_dev, pm_message_t state)
+{
+ struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+ ene_enable_wake(dev, true);
+
+ /* TODO: add support for wake pattern */
+ return 0;
+}
+
+static int ene_resume(struct pnp_dev *pnp_dev)
+{
+ struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+ ene_setup_hw_settings(dev);
+
+ if (dev->rx_enabled)
+ ene_rx_enable(dev);
+
+ ene_enable_wake(dev, false);
+ return 0;
+}
+#endif
+
+static void ene_shutdown(struct pnp_dev *pnp_dev)
+{
+ struct ene_device *dev = pnp_get_drvdata(pnp_dev);
+ ene_enable_wake(dev, true);
+}
+
+static const struct pnp_device_id ene_ids[] = {
+ {.id = "ENE0100",},
+ {.id = "ENE0200",},
+ {.id = "ENE0201",},
+ {.id = "ENE0202",},
+ {},
+};
+
+static struct pnp_driver ene_driver = {
+ .name = ENE_DRIVER_NAME,
+ .id_table = ene_ids,
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+
+ .probe = ene_probe,
+ .remove = __devexit_p(ene_remove),
+#ifdef CONFIG_PM
+ .suspend = ene_suspend,
+ .resume = ene_resume,
+#endif
+ .shutdown = ene_shutdown,
+};
+
+static int __init ene_init(void)
+{
+ return pnp_register_driver(&ene_driver);
+}
+
+static void ene_exit(void)
+{
+ pnp_unregister_driver(&ene_driver);
+}
+
+module_param(sample_period, int, S_IRUGO);
+MODULE_PARM_DESC(sample_period, "Hardware sample period (50 us default)");
+
+module_param(learning_mode_force, bool, S_IRUGO);
+MODULE_PARM_DESC(learning_mode_force, "Enable learning mode by default");
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug level");
+
+module_param(txsim, bool, S_IRUGO);
+MODULE_PARM_DESC(txsim,
+ "Simulate TX features on unsupported hardware (dangerous)");
+
+MODULE_DEVICE_TABLE(pnp, ene_ids);
+MODULE_DESCRIPTION
+ ("Infrared input driver for KB3926B/C/D/E/F "
+ "(aka ENE0100/ENE0200/ENE0201/ENE0202) CIR port");
+
+MODULE_AUTHOR("Maxim Levitsky");
+MODULE_LICENSE("GPL");
+
+module_init(ene_init);
+module_exit(ene_exit);
diff --git a/drivers/media/rc/ene_ir.h b/drivers/media/rc/ene_ir.h
new file mode 100644
index 000000000000..337a41d4450b
--- /dev/null
+++ b/drivers/media/rc/ene_ir.h
@@ -0,0 +1,259 @@
+/*
+ * driver for ENE KB3926 B/C/D/E/F CIR (also known as ENE0XXX)
+ *
+ * Copyright (C) 2010 Maxim Levitsky <maximlevitsky@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
+ */
+#include <linux/spinlock.h>
+
+
+/* hardware address */
+#define ENE_STATUS 0 /* hardware status - unused */
+#define ENE_ADDR_HI 1 /* hi byte of register address */
+#define ENE_ADDR_LO 2 /* low byte of register address */
+#define ENE_IO 3 /* read/write window */
+#define ENE_IO_SIZE 4
+
+/* 8 bytes of samples, divided in 2 packets*/
+#define ENE_FW_SAMPLE_BUFFER 0xF8F0 /* sample buffer */
+#define ENE_FW_SAMPLE_SPACE 0x80 /* sample is space */
+#define ENE_FW_PACKET_SIZE 4
+
+/* first firmware flag register */
+#define ENE_FW1 0xF8F8 /* flagr */
+#define ENE_FW1_ENABLE 0x01 /* enable fw processing */
+#define ENE_FW1_TXIRQ 0x02 /* TX interrupt pending */
+#define ENE_FW1_HAS_EXTRA_BUF 0x04 /* fw uses extra buffer*/
+#define ENE_FW1_EXTRA_BUF_HND 0x08 /* extra buffer handshake bit*/
+#define ENE_FW1_LED_ON 0x10 /* turn on a led */
+
+#define ENE_FW1_WPATTERN 0x20 /* enable wake pattern */
+#define ENE_FW1_WAKE 0x40 /* enable wake from S3 */
+#define ENE_FW1_IRQ 0x80 /* enable interrupt */
+
+/* second firmware flag register */
+#define ENE_FW2 0xF8F9 /* flagw */
+#define ENE_FW2_BUF_WPTR 0x01 /* which half of the buffer to read */
+#define ENE_FW2_RXIRQ 0x04 /* RX IRQ pending*/
+#define ENE_FW2_GP0A 0x08 /* Use GPIO0A for demodulated input */
+#define ENE_FW2_EMMITER1_CONN 0x10 /* TX emmiter 1 connected */
+#define ENE_FW2_EMMITER2_CONN 0x20 /* TX emmiter 2 connected */
+
+#define ENE_FW2_FAN_INPUT 0x40 /* fan input used for demodulated data*/
+#define ENE_FW2_LEARNING 0x80 /* hardware supports learning and TX */
+
+/* firmware RX pointer for new style buffer */
+#define ENE_FW_RX_POINTER 0xF8FA
+
+/* high parts of samples for fan input (8 samples)*/
+#define ENE_FW_SMPL_BUF_FAN 0xF8FB
+#define ENE_FW_SMPL_BUF_FAN_PLS 0x8000 /* combined sample is pulse */
+#define ENE_FW_SMPL_BUF_FAN_MSK 0x0FFF /* combined sample maximum value */
+#define ENE_FW_SAMPLE_PERIOD_FAN 61 /* fan input has fixed sample period */
+
+/* transmitter ports */
+#define ENE_GPIOFS1 0xFC01
+#define ENE_GPIOFS1_GPIO0D 0x20 /* enable tx output on GPIO0D */
+#define ENE_GPIOFS8 0xFC08
+#define ENE_GPIOFS8_GPIO41 0x02 /* enable tx output on GPIO40 */
+
+/* IRQ registers block (for revision B) */
+#define ENEB_IRQ 0xFD09 /* IRQ number */
+#define ENEB_IRQ_UNK1 0xFD17 /* unknown setting = 1 */
+#define ENEB_IRQ_STATUS 0xFD80 /* irq status */
+#define ENEB_IRQ_STATUS_IR 0x20 /* IR irq */
+
+/* fan as input settings */
+#define ENE_FAN_AS_IN1 0xFE30 /* fan init reg 1 */
+#define ENE_FAN_AS_IN1_EN 0xCD
+#define ENE_FAN_AS_IN2 0xFE31 /* fan init reg 2 */
+#define ENE_FAN_AS_IN2_EN 0x03
+
+/* IRQ registers block (for revision C,D) */
+#define ENE_IRQ 0xFE9B /* new irq settings register */
+#define ENE_IRQ_MASK 0x0F /* irq number mask */
+#define ENE_IRQ_UNK_EN 0x10 /* always enabled */
+#define ENE_IRQ_STATUS 0x20 /* irq status and ACK */
+
+/* CIR Config register #1 */
+#define ENE_CIRCFG 0xFEC0
+#define ENE_CIRCFG_RX_EN 0x01 /* RX enable */
+#define ENE_CIRCFG_RX_IRQ 0x02 /* Enable hardware interrupt */
+#define ENE_CIRCFG_REV_POL 0x04 /* Input polarity reversed */
+#define ENE_CIRCFG_CARR_DEMOD 0x08 /* Enable carrier demodulator */
+
+#define ENE_CIRCFG_TX_EN 0x10 /* TX enable */
+#define ENE_CIRCFG_TX_IRQ 0x20 /* Send interrupt on TX done */
+#define ENE_CIRCFG_TX_POL_REV 0x40 /* TX polarity reversed */
+#define ENE_CIRCFG_TX_CARR 0x80 /* send TX carrier or not */
+
+/* CIR config register #2 */
+#define ENE_CIRCFG2 0xFEC1
+#define ENE_CIRCFG2_RLC 0x00
+#define ENE_CIRCFG2_RC5 0x01
+#define ENE_CIRCFG2_RC6 0x02
+#define ENE_CIRCFG2_NEC 0x03
+#define ENE_CIRCFG2_CARR_DETECT 0x10 /* Enable carrier detection */
+#define ENE_CIRCFG2_GPIO0A 0x20 /* Use GPIO0A instead of GPIO40 for input */
+#define ENE_CIRCFG2_FAST_SAMPL1 0x40 /* Fast leading pulse detection for RC6 */
+#define ENE_CIRCFG2_FAST_SAMPL2 0x80 /* Fast data detection for RC6 */
+
+/* Knobs for protocol decoding - will document when/if will use them */
+#define ENE_CIRPF 0xFEC2
+#define ENE_CIRHIGH 0xFEC3
+#define ENE_CIRBIT 0xFEC4
+#define ENE_CIRSTART 0xFEC5
+#define ENE_CIRSTART2 0xFEC6
+
+/* Actual register which contains RLC RX data - read by firmware */
+#define ENE_CIRDAT_IN 0xFEC7
+
+
+/* RLC configuration - sample period (1us resulution) + idle mode */
+#define ENE_CIRRLC_CFG 0xFEC8
+#define ENE_CIRRLC_CFG_OVERFLOW 0x80 /* interrupt on overflows if set */
+#define ENE_DEFAULT_SAMPLE_PERIOD 50
+
+/* Two byte RLC TX buffer */
+#define ENE_CIRRLC_OUT0 0xFEC9
+#define ENE_CIRRLC_OUT1 0xFECA
+#define ENE_CIRRLC_OUT_PULSE 0x80 /* Transmitted sample is pulse */
+#define ENE_CIRRLC_OUT_MASK 0x7F
+
+
+/* Carrier detect setting
+ * Low nibble - number of carrier pulses to average
+ * High nibble - number of initial carrier pulses to discard
+ */
+#define ENE_CIRCAR_PULS 0xFECB
+
+/* detected RX carrier period (resolution: 500 ns) */
+#define ENE_CIRCAR_PRD 0xFECC
+#define ENE_CIRCAR_PRD_VALID 0x80 /* data valid content valid */
+
+/* detected RX carrier pulse width (resolution: 500 ns) */
+#define ENE_CIRCAR_HPRD 0xFECD
+
+/* TX period (resolution: 500 ns, minimum 2)*/
+#define ENE_CIRMOD_PRD 0xFECE
+#define ENE_CIRMOD_PRD_POL 0x80 /* TX carrier polarity*/
+
+#define ENE_CIRMOD_PRD_MAX 0x7F /* 15.87 kHz */
+#define ENE_CIRMOD_PRD_MIN 0x02 /* 1 Mhz */
+
+/* TX pulse width (resolution: 500 ns)*/
+#define ENE_CIRMOD_HPRD 0xFECF
+
+/* Hardware versions */
+#define ENE_ECHV 0xFF00 /* hardware revision */
+#define ENE_PLLFRH 0xFF16
+#define ENE_PLLFRL 0xFF17
+#define ENE_DEFAULT_PLL_FREQ 1000
+
+#define ENE_ECSTS 0xFF1D
+#define ENE_ECSTS_RSRVD 0x04
+
+#define ENE_ECVER_MAJOR 0xFF1E /* chip version */
+#define ENE_ECVER_MINOR 0xFF1F
+#define ENE_HW_VER_OLD 0xFD00
+
+/******************************************************************************/
+
+#define ENE_DRIVER_NAME "ene_ir"
+
+#define ENE_IRQ_RX 1
+#define ENE_IRQ_TX 2
+
+#define ENE_HW_B 1 /* 3926B */
+#define ENE_HW_C 2 /* 3926C */
+#define ENE_HW_D 3 /* 3926D or later */
+
+#define ene_printk(level, text, ...) \
+ printk(level ENE_DRIVER_NAME ": " text "\n", ## __VA_ARGS__)
+
+#define ene_notice(text, ...) ene_printk(KERN_NOTICE, text, ## __VA_ARGS__)
+#define ene_warn(text, ...) ene_printk(KERN_WARNING, text, ## __VA_ARGS__)
+
+
+#define __dbg(level, format, ...) \
+ do { \
+ if (debug >= level) \
+ printk(KERN_DEBUG ENE_DRIVER_NAME \
+ ": " format "\n", ## __VA_ARGS__); \
+ } while (0)
+
+
+#define dbg(format, ...) __dbg(1, format, ## __VA_ARGS__)
+#define dbg_verbose(format, ...) __dbg(2, format, ## __VA_ARGS__)
+#define dbg_regs(format, ...) __dbg(3, format, ## __VA_ARGS__)
+
+struct ene_device {
+ struct pnp_dev *pnp_dev;
+ struct rc_dev *rdev;
+
+ /* hw IO settings */
+ long hw_io;
+ int irq;
+ spinlock_t hw_lock;
+
+ /* HW features */
+ int hw_revision; /* hardware revision */
+ bool hw_use_gpio_0a; /* gpio0a is demodulated input*/
+ bool hw_extra_buffer; /* hardware has 'extra buffer' */
+ bool hw_fan_input; /* fan input is IR data source */
+ bool hw_learning_and_tx_capable; /* learning & tx capable */
+ int pll_freq;
+ int buffer_len;
+
+ /* Extra RX buffer location */
+ int extra_buf1_address;
+ int extra_buf1_len;
+ int extra_buf2_address;
+ int extra_buf2_len;
+
+ /* HW state*/
+ int r_pointer; /* pointer to next sample to read */
+ int w_pointer; /* pointer to next sample hw will write */
+ bool rx_fan_input_inuse; /* is fan input in use for rx*/
+ int tx_reg; /* current reg used for TX */
+ u8 saved_conf1; /* saved FEC0 reg */
+ unsigned int tx_sample; /* current sample for TX */
+ bool tx_sample_pulse; /* current sample is pulse */
+
+ /* TX buffer */
+ int *tx_buffer; /* input samples buffer*/
+ int tx_pos; /* position in that bufer */
+ int tx_len; /* current len of tx buffer */
+ int tx_done; /* done transmitting */
+ /* one more sample pending*/
+ struct completion tx_complete; /* TX completion */
+ struct timer_list tx_sim_timer;
+
+ /* TX settings */
+ int tx_period;
+ int tx_duty_cycle;
+ int transmitter_mask;
+
+ /* RX settings */
+ bool learning_mode_enabled; /* learning input enabled */
+ bool carrier_detect_enabled; /* carrier detect enabled */
+ int rx_period_adjust;
+ bool rx_enabled;
+};
+
+static int ene_irq_status(struct ene_device *dev);
+static void ene_rx_read_hw_pointer(struct ene_device *dev);
diff --git a/drivers/media/IR/imon.c b/drivers/media/rc/imon.c
index 5e2045670004..e7dc6b46fdfa 100644
--- a/drivers/media/IR/imon.c
+++ b/drivers/media/rc/imon.c
@@ -1,7 +1,7 @@
/*
* imon.c: input and display driver for SoundGraph iMON IR/VFD/LCD
*
- * Copyright(C) 2009 Jarod Wilson <jarod@wilsonet.com>
+ * Copyright(C) 2010 Jarod Wilson <jarod@wilsonet.com>
* Portions based on the original lirc_imon driver,
* Copyright(C) 2004 Venky Raju(dev@venky.ws)
*
@@ -26,6 +26,8 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#define pr_fmt(fmt) KBUILD_MODNAME ":%s: " fmt, __func__
+
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -36,7 +38,7 @@
#include <linux/input.h>
#include <linux/usb.h>
#include <linux/usb/input.h>
-#include <media/ir-core.h>
+#include <media/rc-core.h>
#include <linux/time.h>
#include <linux/timer.h>
@@ -44,7 +46,7 @@
#define MOD_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
#define MOD_DESC "Driver for SoundGraph iMON MultiMedia IR/Display"
#define MOD_NAME "imon"
-#define MOD_VERSION "0.9.1"
+#define MOD_VERSION "0.9.2"
#define DISPLAY_MINOR_BASE 144
#define DEVICE_NAME "lcd%d"
@@ -86,14 +88,13 @@ static ssize_t lcd_write(struct file *file, const char *buf,
struct imon_context {
struct device *dev;
- struct ir_dev_props *props;
- struct ir_input_dev *ir;
/* Newer devices have two interfaces */
struct usb_device *usbdev_intf0;
struct usb_device *usbdev_intf1;
bool display_supported; /* not all controllers do */
bool display_isopen; /* display port has been opened */
+ bool rf_device; /* true if iMON 2.4G LT/DT RF device */
bool rf_isassociating; /* RF remote associating */
bool dev_present_intf0; /* USB device presence, interface 0 */
bool dev_present_intf1; /* USB device presence, interface 1 */
@@ -121,21 +122,26 @@ struct imon_context {
u16 vendor; /* usb vendor ID */
u16 product; /* usb product ID */
- struct input_dev *idev; /* input device for remote */
+ struct rc_dev *rdev; /* rc-core device for remote */
+ struct input_dev *idev; /* input device for panel & IR mouse */
struct input_dev *touch; /* input device for touchscreen */
+ spinlock_t kc_lock; /* make sure we get keycodes right */
u32 kc; /* current input keycode */
u32 last_keycode; /* last reported input keycode */
- u64 ir_type; /* iMON or MCE (RC6) IR protocol? */
- u8 mce_toggle_bit; /* last mce toggle bit */
+ u32 rc_scancode; /* the computed remote scancode */
+ u8 rc_toggle; /* the computed remote toggle bit */
+ u64 rc_type; /* iMON or MCE (RC6) IR protocol? */
bool release_code; /* some keys send a release code */
u8 display_type; /* store the display type */
bool pad_mouse; /* toggle kbd(0)/mouse(1) mode */
+ char name_rdev[128]; /* rc input device name */
+ char phys_rdev[64]; /* rc input device phys path */
+
char name_idev[128]; /* input device name */
char phys_idev[64]; /* input device phys path */
- struct timer_list itimer; /* input device timer, need for rc6 */
char name_touch[128]; /* touch screen name */
char phys_touch[64]; /* touch screen phys path */
@@ -151,7 +157,8 @@ static const struct file_operations vfd_fops = {
.owner = THIS_MODULE,
.open = &display_open,
.write = &vfd_write,
- .release = &display_close
+ .release = &display_close,
+ .llseek = noop_llseek,
};
/* lcd character device file operations */
@@ -159,7 +166,8 @@ static const struct file_operations lcd_fops = {
.owner = THIS_MODULE,
.open = &display_open,
.write = &lcd_write,
- .release = &display_close
+ .release = &display_close,
+ .llseek = noop_llseek,
};
enum {
@@ -287,6 +295,9 @@ static const struct {
{ 0x000100000000ffeell, KEY_VOLUMEUP },
{ 0x010000000000ffeell, KEY_VOLUMEDOWN },
{ 0x000000000100ffeell, KEY_MUTE },
+ /* 0xffdc iMON MCE VFD */
+ { 0x00010000ffffffeell, KEY_VOLUMEUP },
+ { 0x01000000ffffffeell, KEY_VOLUMEDOWN },
/* iMON Knob values */
{ 0x000100ffffffffeell, KEY_VOLUMEUP },
{ 0x010000ffffffffeell, KEY_VOLUMEDOWN },
@@ -305,7 +316,7 @@ MODULE_DEVICE_TABLE(usb, imon_usb_id_table);
static bool debug;
module_param(debug, bool, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes(default: no)");
+MODULE_PARM_DESC(debug, "Debug messages: 0=no, 1=yes (default: no)");
/* lcd, vfd, vga or none? should be auto-detected, but can be overridden... */
static int display_type;
@@ -363,15 +374,14 @@ static int display_open(struct inode *inode, struct file *file)
subminor = iminor(inode);
interface = usb_find_interface(&imon_driver, subminor);
if (!interface) {
- err("%s: could not find interface for minor %d",
- __func__, subminor);
+ pr_err("could not find interface for minor %d\n", subminor);
retval = -ENODEV;
goto exit;
}
ictx = usb_get_intfdata(interface);
if (!ictx) {
- err("%s: no context found for minor %d", __func__, subminor);
+ pr_err("no context found for minor %d\n", subminor);
retval = -ENODEV;
goto exit;
}
@@ -379,13 +389,13 @@ static int display_open(struct inode *inode, struct file *file)
mutex_lock(&ictx->lock);
if (!ictx->display_supported) {
- err("%s: display not supported by device", __func__);
+ pr_err("display not supported by device\n");
retval = -ENODEV;
} else if (ictx->display_isopen) {
- err("%s: display port is already open", __func__);
+ pr_err("display port is already open\n");
retval = -EBUSY;
} else {
- ictx->display_isopen = 1;
+ ictx->display_isopen = true;
file->private_data = ictx;
dev_dbg(ictx->dev, "display port opened\n");
}
@@ -406,23 +416,23 @@ static int display_close(struct inode *inode, struct file *file)
struct imon_context *ictx = NULL;
int retval = 0;
- ictx = (struct imon_context *)file->private_data;
+ ictx = file->private_data;
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
mutex_lock(&ictx->lock);
if (!ictx->display_supported) {
- err("%s: display not supported by device", __func__);
+ pr_err("display not supported by device\n");
retval = -ENODEV;
} else if (!ictx->display_isopen) {
- err("%s: display is not open", __func__);
+ pr_err("display is not open\n");
retval = -EIO;
} else {
- ictx->display_isopen = 0;
+ ictx->display_isopen = false;
dev_dbg(ictx->dev, "display port closed\n");
if (!ictx->dev_present_intf0) {
/*
@@ -491,26 +501,26 @@ static int send_packet(struct imon_context *ictx)
}
init_completion(&ictx->tx.finished);
- ictx->tx.busy = 1;
+ ictx->tx.busy = true;
smp_rmb(); /* ensure later readers know we're busy */
retval = usb_submit_urb(ictx->tx_urb, GFP_KERNEL);
if (retval) {
- ictx->tx.busy = 0;
+ ictx->tx.busy = false;
smp_rmb(); /* ensure later readers know we're not busy */
- err("%s: error submitting urb(%d)", __func__, retval);
+ pr_err("error submitting urb(%d)\n", retval);
} else {
/* Wait for transmission to complete (or abort) */
mutex_unlock(&ictx->lock);
retval = wait_for_completion_interruptible(
&ictx->tx.finished);
if (retval)
- err("%s: task interrupted", __func__);
+ pr_err("task interrupted\n");
mutex_lock(&ictx->lock);
retval = ictx->tx.status;
if (retval)
- err("%s: packet tx failed (%d)", __func__, retval);
+ pr_err("packet tx failed (%d)\n", retval);
}
kfree(control_req);
@@ -542,12 +552,12 @@ static int send_associate_24g(struct imon_context *ictx)
0x00, 0x00, 0x00, 0x20 };
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
if (!ictx->dev_present_intf0) {
- err("%s: no iMON device present", __func__);
+ pr_err("no iMON device present\n");
return -ENODEV;
}
@@ -575,7 +585,7 @@ static int send_set_imon_clock(struct imon_context *ictx,
int i;
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
@@ -636,8 +646,7 @@ static int send_set_imon_clock(struct imon_context *ictx,
memcpy(ictx->usb_tx_buf, clock_enable_pkt[i], 8);
retval = send_packet(ictx);
if (retval) {
- err("%s: send_packet failed for packet %d",
- __func__, i);
+ pr_err("send_packet failed for packet %d\n", i);
break;
}
}
@@ -682,7 +691,7 @@ static ssize_t store_associate_remote(struct device *d,
return -ENODEV;
mutex_lock(&ictx->lock);
- ictx->rf_isassociating = 1;
+ ictx->rf_isassociating = true;
send_associate_24g(ictx);
mutex_unlock(&ictx->lock);
@@ -776,7 +785,7 @@ static struct attribute *imon_display_sysfs_entries[] = {
NULL
};
-static struct attribute_group imon_display_attribute_group = {
+static struct attribute_group imon_display_attr_group = {
.attrs = imon_display_sysfs_entries
};
@@ -785,7 +794,7 @@ static struct attribute *imon_rf_sysfs_entries[] = {
NULL
};
-static struct attribute_group imon_rf_attribute_group = {
+static struct attribute_group imon_rf_attr_group = {
.attrs = imon_rf_sysfs_entries
};
@@ -811,22 +820,22 @@ static ssize_t vfd_write(struct file *file, const char *buf,
const unsigned char vfd_packet6[] = {
0x01, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF };
- ictx = (struct imon_context *)file->private_data;
+ ictx = file->private_data;
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
mutex_lock(&ictx->lock);
if (!ictx->dev_present_intf0) {
- err("%s: no iMON device present", __func__);
+ pr_err("no iMON device present\n");
retval = -ENODEV;
goto exit;
}
if (n_bytes <= 0 || n_bytes > 32) {
- err("%s: invalid payload size", __func__);
+ pr_err("invalid payload size\n");
retval = -EINVAL;
goto exit;
}
@@ -852,8 +861,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
retval = send_packet(ictx);
if (retval) {
- err("%s: send packet failed for packet #%d",
- __func__, seq/2);
+ pr_err("send packet failed for packet #%d\n", seq / 2);
goto exit;
} else {
seq += 2;
@@ -867,8 +875,7 @@ static ssize_t vfd_write(struct file *file, const char *buf,
ictx->usb_tx_buf[7] = (unsigned char) seq;
retval = send_packet(ictx);
if (retval)
- err("%s: send packet failed for packet #%d",
- __func__, seq / 2);
+ pr_err("send packet failed for packet #%d\n", seq / 2);
exit:
mutex_unlock(&ictx->lock);
@@ -895,23 +902,22 @@ static ssize_t lcd_write(struct file *file, const char *buf,
int retval = 0;
struct imon_context *ictx;
- ictx = (struct imon_context *)file->private_data;
+ ictx = file->private_data;
if (!ictx) {
- err("%s: no context for device", __func__);
+ pr_err("no context for device\n");
return -ENODEV;
}
mutex_lock(&ictx->lock);
if (!ictx->display_supported) {
- err("%s: no iMON display present", __func__);
+ pr_err("no iMON display present\n");
retval = -ENODEV;
goto exit;
}
if (n_bytes != 8) {
- err("%s: invalid payload size: %d (expecting 8)",
- __func__, (int) n_bytes);
+ pr_err("invalid payload size: %d (expected 8)\n", (int)n_bytes);
retval = -EINVAL;
goto exit;
}
@@ -923,7 +929,7 @@ static ssize_t lcd_write(struct file *file, const char *buf,
retval = send_packet(ictx);
if (retval) {
- err("%s: send packet failed!", __func__);
+ pr_err("send packet failed!\n");
goto exit;
} else {
dev_dbg(ictx->dev, "%s: write %d bytes to LCD\n",
@@ -950,23 +956,12 @@ static void usb_tx_callback(struct urb *urb)
ictx->tx.status = urb->status;
/* notify waiters that write has finished */
- ictx->tx.busy = 0;
+ ictx->tx.busy = false;
smp_rmb(); /* ensure later readers know we're not busy */
complete(&ictx->tx.finished);
}
/**
- * mce/rc6 keypresses have no distinct release code, use timer
- */
-static void imon_mce_timeout(unsigned long data)
-{
- struct imon_context *ictx = (struct imon_context *)data;
-
- input_report_key(ictx->idev, ictx->last_keycode, 0);
- input_sync(ictx->idev);
-}
-
-/**
* report touchscreen input
*/
static void imon_touch_display_timeout(unsigned long data)
@@ -988,51 +983,38 @@ static void imon_touch_display_timeout(unsigned long data)
* really just RC-6), but only one or the other at a time, as the signals
* are decoded onboard the receiver.
*/
-int imon_ir_change_protocol(void *priv, u64 ir_type)
+static int imon_ir_change_protocol(struct rc_dev *rc, u64 rc_type)
{
int retval;
- struct imon_context *ictx = priv;
+ struct imon_context *ictx = rc->priv;
struct device *dev = ictx->dev;
- bool pad_mouse;
unsigned char ir_proto_packet[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x86 };
- if (ir_type && !(ir_type & ictx->props->allowed_protos))
+ if (rc_type && !(rc_type & rc->allowed_protos))
dev_warn(dev, "Looks like you're trying to use an IR protocol "
"this device does not support\n");
- switch (ir_type) {
- case IR_TYPE_RC6:
+ switch (rc_type) {
+ case RC_TYPE_RC6:
dev_dbg(dev, "Configuring IR receiver for MCE protocol\n");
ir_proto_packet[0] = 0x01;
- pad_mouse = false;
- init_timer(&ictx->itimer);
- ictx->itimer.data = (unsigned long)ictx;
- ictx->itimer.function = imon_mce_timeout;
break;
- case IR_TYPE_UNKNOWN:
- case IR_TYPE_OTHER:
+ case RC_TYPE_UNKNOWN:
+ case RC_TYPE_OTHER:
dev_dbg(dev, "Configuring IR receiver for iMON protocol\n");
- if (pad_stabilize)
- pad_mouse = true;
- else {
+ if (!pad_stabilize)
dev_dbg(dev, "PAD stabilize functionality disabled\n");
- pad_mouse = false;
- }
/* ir_proto_packet[0] = 0x00; // already the default */
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
break;
default:
dev_warn(dev, "Unsupported IR protocol specified, overriding "
"to iMON IR protocol\n");
- if (pad_stabilize)
- pad_mouse = true;
- else {
+ if (!pad_stabilize)
dev_dbg(dev, "PAD stabilize functionality disabled\n");
- pad_mouse = false;
- }
/* ir_proto_packet[0] = 0x00; // already the default */
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
break;
}
@@ -1042,8 +1024,8 @@ int imon_ir_change_protocol(void *priv, u64 ir_type)
if (retval)
goto out;
- ictx->ir_type = ir_type;
- ictx->pad_mouse = pad_mouse;
+ ictx->rc_type = rc_type;
+ ictx->pad_mouse = false;
out:
return retval;
@@ -1147,20 +1129,21 @@ static int stabilize(int a, int b, u16 timeout, u16 threshold)
return result;
}
-static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code)
+static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 scancode)
{
- u32 scancode = be32_to_cpu(hw_code);
u32 keycode;
u32 release;
bool is_release_code = false;
/* Look for the initial press of a button */
- keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+ keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
+ ictx->rc_toggle = 0x0;
+ ictx->rc_scancode = scancode;
/* Look for the release of a button */
if (keycode == KEY_RESERVED) {
release = scancode & ~0x4000;
- keycode = ir_g_keycode_from_table(ictx->idev, release);
+ keycode = rc_g_keycode_from_table(ictx->rdev, release);
if (keycode != KEY_RESERVED)
is_release_code = true;
}
@@ -1170,9 +1153,8 @@ static u32 imon_remote_key_lookup(struct imon_context *ictx, u32 hw_code)
return keycode;
}
-static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code)
+static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 scancode)
{
- u32 scancode = be32_to_cpu(hw_code);
u32 keycode;
#define MCE_KEY_MASK 0x7000
@@ -1186,18 +1168,21 @@ static u32 imon_mce_key_lookup(struct imon_context *ictx, u32 hw_code)
* but we can't or them into all codes, as some keys are decoded in
* a different way w/o the same use of the toggle bit...
*/
- if ((scancode >> 24) & 0x80)
+ if (scancode & 0x80000000)
scancode = scancode | MCE_KEY_MASK | MCE_TOGGLE_BIT;
- keycode = ir_g_keycode_from_table(ictx->idev, scancode);
+ ictx->rc_scancode = scancode;
+ keycode = rc_g_keycode_from_table(ictx->rdev, scancode);
+
+ /* not used in mce mode, but make sure we know its false */
+ ictx->release_code = false;
return keycode;
}
-static u32 imon_panel_key_lookup(u64 hw_code)
+static u32 imon_panel_key_lookup(u64 code)
{
int i;
- u64 code = be64_to_cpu(hw_code);
u32 keycode = KEY_RESERVED;
for (i = 0; i < ARRAY_SIZE(imon_panel_key_table); i++) {
@@ -1215,8 +1200,11 @@ static bool imon_mouse_event(struct imon_context *ictx,
{
char rel_x = 0x00, rel_y = 0x00;
u8 right_shift = 1;
- bool mouse_input = 1;
+ bool mouse_input = true;
int dir = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ictx->kc_lock, flags);
/* newer iMON device PAD or mouse button */
if (ictx->product != 0xffdc && (buf[0] & 0x01) && len == 5) {
@@ -1246,7 +1234,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
} else if (ictx->kc == KEY_CHANNELDOWN && (buf[2] & 0x40) != 0x40) {
dir = -1;
} else
- mouse_input = 0;
+ mouse_input = false;
+
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
if (mouse_input) {
dev_dbg(ictx->dev, "sending mouse data via input subsystem\n");
@@ -1262,7 +1252,9 @@ static bool imon_mouse_event(struct imon_context *ictx,
buf[1] >> right_shift & 0x1);
}
input_sync(ictx->idev);
+ spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->last_keycode = ictx->kc;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
}
return mouse_input;
@@ -1284,8 +1276,8 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
int dir = 0;
char rel_x = 0x00, rel_y = 0x00;
u16 timeout, threshold;
- u64 temp_key;
- u32 remote_key;
+ u32 scancode = KEY_RESERVED;
+ unsigned long flags;
/*
* The imon directional pad functions more like a touchpad. Bytes 3 & 4
@@ -1304,31 +1296,41 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
rel_x = buf[2];
rel_y = buf[3];
- if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) {
+ if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) {
if ((buf[1] == 0) && ((rel_x != 0) || (rel_y != 0))) {
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
if (!dir) {
+ spin_lock_irqsave(&ictx->kc_lock,
+ flags);
ictx->kc = KEY_UNKNOWN;
+ spin_unlock_irqrestore(&ictx->kc_lock,
+ flags);
return;
}
buf[2] = dir & 0xFF;
buf[3] = (dir >> 8) & 0xFF;
- memcpy(&temp_key, buf, sizeof(temp_key));
- remote_key = (u32) (le64_to_cpu(temp_key)
- & 0xffffffff);
- ictx->kc = imon_remote_key_lookup(ictx,
- remote_key);
+ scancode = be32_to_cpu(*((u32 *)buf));
}
} else {
+ /*
+ * Hack alert: instead of using keycodes, we have
+ * to use hard-coded scancodes here...
+ */
if (abs(rel_y) > abs(rel_x)) {
buf[2] = (rel_y > 0) ? 0x7F : 0x80;
buf[3] = 0;
- ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP;
+ if (rel_y > 0)
+ scancode = 0x01007f00; /* KEY_DOWN */
+ else
+ scancode = 0x01008000; /* KEY_UP */
} else {
buf[2] = 0;
buf[3] = (rel_x > 0) ? 0x7F : 0x80;
- ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+ if (rel_x > 0)
+ scancode = 0x0100007f; /* KEY_RIGHT */
+ else
+ scancode = 0x01000080; /* KEY_LEFT */
}
}
@@ -1361,38 +1363,60 @@ static void imon_pad_to_keys(struct imon_context *ictx, unsigned char *buf)
buf[0] = 0x01;
buf[1] = buf[4] = buf[5] = buf[6] = buf[7] = 0;
- if (ictx->ir_type == IR_TYPE_OTHER && pad_stabilize) {
+ if (ictx->rc_type == RC_TYPE_OTHER && pad_stabilize) {
dir = stabilize((int)rel_x, (int)rel_y,
timeout, threshold);
if (!dir) {
+ spin_lock_irqsave(&ictx->kc_lock, flags);
ictx->kc = KEY_UNKNOWN;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
}
buf[2] = dir & 0xFF;
buf[3] = (dir >> 8) & 0xFF;
- memcpy(&temp_key, buf, sizeof(temp_key));
- remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
- ictx->kc = imon_remote_key_lookup(ictx, remote_key);
+ scancode = be32_to_cpu(*((u32 *)buf));
} else {
+ /*
+ * Hack alert: instead of using keycodes, we have
+ * to use hard-coded scancodes here...
+ */
if (abs(rel_y) > abs(rel_x)) {
buf[2] = (rel_y > 0) ? 0x7F : 0x80;
buf[3] = 0;
- ictx->kc = (rel_y > 0) ? KEY_DOWN : KEY_UP;
+ if (rel_y > 0)
+ scancode = 0x01007f00; /* KEY_DOWN */
+ else
+ scancode = 0x01008000; /* KEY_UP */
} else {
buf[2] = 0;
buf[3] = (rel_x > 0) ? 0x7F : 0x80;
- ictx->kc = (rel_x > 0) ? KEY_RIGHT : KEY_LEFT;
+ if (rel_x > 0)
+ scancode = 0x0100007f; /* KEY_RIGHT */
+ else
+ scancode = 0x01000080; /* KEY_LEFT */
}
}
}
+
+ if (scancode) {
+ spin_lock_irqsave(&ictx->kc_lock, flags);
+ ictx->kc = imon_remote_key_lookup(ictx, scancode);
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
+ }
}
+/**
+ * figure out if these is a press or a release. We don't actually
+ * care about repeats, as those will be auto-generated within the IR
+ * subsystem for repeating scancodes.
+ */
static int imon_parse_press_type(struct imon_context *ictx,
unsigned char *buf, u8 ktype)
{
int press_type = 0;
- int rep_delay = ictx->idev->rep[REP_DELAY];
- int rep_period = ictx->idev->rep[REP_PERIOD];
+ unsigned long flags;
+
+ spin_lock_irqsave(&ictx->kc_lock, flags);
/* key release of 0x02XXXXXX key */
if (ictx->kc == KEY_RESERVED && buf[0] == 0x02 && buf[3] == 0x00)
@@ -1408,22 +1432,10 @@ static int imon_parse_press_type(struct imon_context *ictx,
buf[2] == 0x81 && buf[3] == 0xb7)
ictx->kc = ictx->last_keycode;
- /* mce-specific button handling */
+ /* mce-specific button handling, no keyup events */
else if (ktype == IMON_KEY_MCE) {
- /* initial press */
- if (ictx->kc != ictx->last_keycode
- || buf[2] != ictx->mce_toggle_bit) {
- ictx->last_keycode = ictx->kc;
- ictx->mce_toggle_bit = buf[2];
- press_type = 1;
- mod_timer(&ictx->itimer,
- jiffies + msecs_to_jiffies(rep_delay));
- /* repeat */
- } else {
- press_type = 2;
- mod_timer(&ictx->itimer,
- jiffies + msecs_to_jiffies(rep_period));
- }
+ ictx->rc_toggle = buf[2];
+ press_type = 1;
/* incoherent or irrelevant data */
} else if (ictx->kc == KEY_RESERVED)
@@ -1437,6 +1449,8 @@ static int imon_parse_press_type(struct imon_context *ictx,
else
press_type = 1;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
+
return press_type;
}
@@ -1449,41 +1463,40 @@ static void imon_incoming_packet(struct imon_context *ictx,
int len = urb->actual_length;
unsigned char *buf = urb->transfer_buffer;
struct device *dev = ictx->dev;
+ unsigned long flags;
u32 kc;
- bool norelease = 0;
+ bool norelease = false;
int i;
- u64 temp_key;
- u64 panel_key = 0;
- u32 remote_key = 0;
- struct input_dev *idev = NULL;
+ u64 scancode;
int press_type = 0;
int msec;
struct timeval t;
static struct timeval prev_time = { 0, 0 };
- u8 ktype = IMON_KEY_IMON;
-
- idev = ictx->idev;
+ u8 ktype;
/* filter out junk data on the older 0xffdc imon devices */
- if ((buf[0] == 0xff) && (buf[7] == 0xff))
+ if ((buf[0] == 0xff) && (buf[1] == 0xff) && (buf[2] == 0xff))
return;
/* Figure out what key was pressed */
- memcpy(&temp_key, buf, sizeof(temp_key));
if (len == 8 && buf[7] == 0xee) {
+ scancode = be64_to_cpu(*((u64 *)buf));
ktype = IMON_KEY_PANEL;
- panel_key = le64_to_cpu(temp_key);
- kc = imon_panel_key_lookup(panel_key);
+ kc = imon_panel_key_lookup(scancode);
} else {
- remote_key = (u32) (le64_to_cpu(temp_key) & 0xffffffff);
- if (ictx->ir_type == IR_TYPE_RC6) {
+ scancode = be32_to_cpu(*((u32 *)buf));
+ if (ictx->rc_type == RC_TYPE_RC6) {
+ ktype = IMON_KEY_IMON;
if (buf[0] == 0x80)
ktype = IMON_KEY_MCE;
- kc = imon_mce_key_lookup(ictx, remote_key);
- } else
- kc = imon_remote_key_lookup(ictx, remote_key);
+ kc = imon_mce_key_lookup(ictx, scancode);
+ } else {
+ ktype = IMON_KEY_IMON;
+ kc = imon_remote_key_lookup(ictx, scancode);
+ }
}
+ spin_lock_irqsave(&ictx->kc_lock, flags);
/* keyboard/mouse mode toggle button */
if (kc == KEY_KEYBOARD && !ictx->release_code) {
ictx->last_keycode = kc;
@@ -1491,19 +1504,22 @@ static void imon_incoming_packet(struct imon_context *ictx,
ictx->pad_mouse = ~(ictx->pad_mouse) & 0x1;
dev_dbg(dev, "toggling to %s mode\n",
ictx->pad_mouse ? "mouse" : "keyboard");
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
} else {
- ictx->pad_mouse = 0;
+ ictx->pad_mouse = false;
dev_dbg(dev, "mouse mode disabled, passing key value\n");
}
}
ictx->kc = kc;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
/* send touchscreen events through input subsystem if touchpad data */
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA && len == 8 &&
buf[7] == 0x86) {
imon_touch_event(ictx, buf);
+ return;
/* look for mouse events with pad in mouse mode */
} else if (ictx->pad_mouse) {
@@ -1517,7 +1533,7 @@ static void imon_incoming_packet(struct imon_context *ictx,
!(buf[1] & 0x1 || buf[1] >> 2 & 0x1))) {
len = 8;
imon_pad_to_keys(ictx, buf);
- norelease = 1;
+ norelease = true;
}
if (debug) {
@@ -1531,36 +1547,55 @@ static void imon_incoming_packet(struct imon_context *ictx,
if (press_type < 0)
goto not_input_data;
+ spin_lock_irqsave(&ictx->kc_lock, flags);
if (ictx->kc == KEY_UNKNOWN)
goto unknown_key;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
+
+ if (ktype != IMON_KEY_PANEL) {
+ if (press_type == 0)
+ rc_keyup(ictx->rdev);
+ else {
+ rc_keydown(ictx->rdev, ictx->rc_scancode, ictx->rc_toggle);
+ spin_lock_irqsave(&ictx->kc_lock, flags);
+ ictx->last_keycode = ictx->kc;
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
+ }
+ return;
+ }
+
+ /* Only panel type events left to process now */
+ spin_lock_irqsave(&ictx->kc_lock, flags);
- /* KEY_MUTE repeats from MCE and knob need to be suppressed */
- if ((ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode)
- && (buf[7] == 0xee || ktype == IMON_KEY_MCE)) {
+ /* KEY_MUTE repeats from knob need to be suppressed */
+ if (ictx->kc == KEY_MUTE && ictx->kc == ictx->last_keycode) {
do_gettimeofday(&t);
msec = tv2int(&t, &prev_time);
prev_time = t;
- if (msec < idev->rep[REP_DELAY])
+ if (msec < ictx->idev->rep[REP_DELAY]) {
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
return;
+ }
}
+ kc = ictx->kc;
- input_report_key(idev, ictx->kc, press_type);
- input_sync(idev);
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
- /* panel keys and some remote keys don't generate a release */
- if (panel_key || norelease) {
- input_report_key(idev, ictx->kc, 0);
- input_sync(idev);
- }
+ input_report_key(ictx->idev, kc, press_type);
+ input_sync(ictx->idev);
- ictx->last_keycode = ictx->kc;
+ /* panel keys don't generate a release */
+ input_report_key(ictx->idev, kc, 0);
+ input_sync(ictx->idev);
+
+ ictx->last_keycode = kc;
return;
unknown_key:
+ spin_unlock_irqrestore(&ictx->kc_lock, flags);
dev_info(dev, "%s: unknown keypress, code 0x%llx\n", __func__,
- (panel_key ? be64_to_cpu(panel_key) :
- be32_to_cpu(remote_key)));
+ (long long)scancode);
return;
not_input_data:
@@ -1580,7 +1615,7 @@ not_input_data:
(buf[6] == 0x5E && buf[7] == 0xDF))) { /* DT */
dev_warn(dev, "%s: remote associated refid=%02X\n",
__func__, buf[1]);
- ictx->rf_isassociating = 0;
+ ictx->rf_isassociating = false;
}
}
@@ -1651,38 +1686,200 @@ static void usb_rx_callback_intf1(struct urb *urb)
usb_submit_urb(ictx->rx_urb_intf1, GFP_ATOMIC);
}
+/*
+ * The 0x15c2:0xffdc device ID was used for umpteen different imon
+ * devices, and all of them constantly spew interrupts, even when there
+ * is no actual data to report. However, byte 6 of this buffer looks like
+ * its unique across device variants, so we're trying to key off that to
+ * figure out which display type (if any) and what IR protocol the device
+ * actually supports. These devices have their IR protocol hard-coded into
+ * their firmware, they can't be changed on the fly like the newer hardware.
+ */
+static void imon_get_ffdc_type(struct imon_context *ictx)
+{
+ u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
+ u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
+ u64 allowed_protos = RC_TYPE_OTHER;
+
+ switch (ffdc_cfg_byte) {
+ /* iMON Knob, no display, iMON IR + vol knob */
+ case 0x21:
+ dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
+ ictx->display_supported = false;
+ break;
+ /* iMON 2.4G LT (usb stick), no display, iMON RF */
+ case 0x4e:
+ dev_info(ictx->dev, "0xffdc iMON 2.4G LT, iMON RF");
+ ictx->display_supported = false;
+ ictx->rf_device = true;
+ break;
+ /* iMON VFD, no IR (does have vol knob tho) */
+ case 0x35:
+ dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
+ detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ break;
+ /* iMON VFD, iMON IR */
+ case 0x24:
+ case 0x85:
+ dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
+ detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ break;
+ /* iMON VFD, MCE IR */
+ case 0x9e:
+ dev_info(ictx->dev, "0xffdc iMON VFD, MCE IR");
+ detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ allowed_protos = RC_TYPE_RC6;
+ break;
+ /* iMON LCD, MCE IR */
+ case 0x9f:
+ dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
+ detected_display_type = IMON_DISPLAY_TYPE_LCD;
+ allowed_protos = RC_TYPE_RC6;
+ break;
+ default:
+ dev_info(ictx->dev, "Unknown 0xffdc device, "
+ "defaulting to VFD and iMON IR");
+ detected_display_type = IMON_DISPLAY_TYPE_VFD;
+ break;
+ }
+
+ printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
+
+ ictx->display_type = detected_display_type;
+ ictx->rc_type = allowed_protos;
+}
+
+static void imon_set_display_type(struct imon_context *ictx)
+{
+ u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
+
+ /*
+ * Try to auto-detect the type of display if the user hasn't set
+ * it by hand via the display_type modparam. Default is VFD.
+ */
+
+ if (display_type == IMON_DISPLAY_TYPE_AUTO) {
+ switch (ictx->product) {
+ case 0xffdc:
+ /* set in imon_get_ffdc_type() */
+ configured_display_type = ictx->display_type;
+ break;
+ case 0x0034:
+ case 0x0035:
+ configured_display_type = IMON_DISPLAY_TYPE_VGA;
+ break;
+ case 0x0038:
+ case 0x0039:
+ case 0x0045:
+ configured_display_type = IMON_DISPLAY_TYPE_LCD;
+ break;
+ case 0x003c:
+ case 0x0041:
+ case 0x0042:
+ case 0x0043:
+ configured_display_type = IMON_DISPLAY_TYPE_NONE;
+ ictx->display_supported = false;
+ break;
+ case 0x0036:
+ case 0x0044:
+ default:
+ configured_display_type = IMON_DISPLAY_TYPE_VFD;
+ break;
+ }
+ } else {
+ configured_display_type = display_type;
+ if (display_type == IMON_DISPLAY_TYPE_NONE)
+ ictx->display_supported = false;
+ else
+ ictx->display_supported = true;
+ dev_info(ictx->dev, "%s: overriding display type to %d via "
+ "modparam\n", __func__, display_type);
+ }
+
+ ictx->display_type = configured_display_type;
+}
+
+static struct rc_dev *imon_init_rdev(struct imon_context *ictx)
+{
+ struct rc_dev *rdev;
+ int ret;
+ const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x88 };
+
+ rdev = rc_allocate_device();
+ if (!rdev) {
+ dev_err(ictx->dev, "remote control dev allocation failed\n");
+ goto out;
+ }
+
+ snprintf(ictx->name_rdev, sizeof(ictx->name_rdev),
+ "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
+ usb_make_path(ictx->usbdev_intf0, ictx->phys_rdev,
+ sizeof(ictx->phys_rdev));
+ strlcat(ictx->phys_rdev, "/input0", sizeof(ictx->phys_rdev));
+
+ rdev->input_name = ictx->name_rdev;
+ rdev->input_phys = ictx->phys_rdev;
+ usb_to_input_id(ictx->usbdev_intf0, &rdev->input_id);
+ rdev->dev.parent = ictx->dev;
+
+ rdev->priv = ictx;
+ rdev->driver_type = RC_DRIVER_SCANCODE;
+ rdev->allowed_protos = RC_TYPE_OTHER | RC_TYPE_RC6; /* iMON PAD or MCE */
+ rdev->change_protocol = imon_ir_change_protocol;
+ rdev->driver_name = MOD_NAME;
+
+ /* Enable front-panel buttons and/or knobs */
+ memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
+ ret = send_packet(ictx);
+ /* Not fatal, but warn about it */
+ if (ret)
+ dev_info(ictx->dev, "panel buttons/knobs setup failed\n");
+
+ if (ictx->product == 0xffdc) {
+ imon_get_ffdc_type(ictx);
+ rdev->allowed_protos = ictx->rc_type;
+ }
+
+ imon_set_display_type(ictx);
+
+ if (ictx->rc_type == RC_TYPE_RC6)
+ rdev->map_name = RC_MAP_IMON_MCE;
+ else
+ rdev->map_name = RC_MAP_IMON_PAD;
+
+ ret = rc_register_device(rdev);
+ if (ret < 0) {
+ dev_err(ictx->dev, "remote input dev register failed\n");
+ goto out;
+ }
+
+ return rdev;
+
+out:
+ rc_free_device(rdev);
+ return NULL;
+}
+
static struct input_dev *imon_init_idev(struct imon_context *ictx)
{
struct input_dev *idev;
- struct ir_dev_props *props;
- struct ir_input_dev *ir;
int ret, i;
idev = input_allocate_device();
if (!idev) {
- dev_err(ictx->dev, "remote input dev allocation failed\n");
- goto idev_alloc_failed;
- }
-
- props = kzalloc(sizeof(struct ir_dev_props), GFP_KERNEL);
- if (!props) {
- dev_err(ictx->dev, "remote ir dev props allocation failed\n");
- goto props_alloc_failed;
- }
-
- ir = kzalloc(sizeof(struct ir_input_dev), GFP_KERNEL);
- if (!ir) {
- dev_err(ictx->dev, "remote ir input dev allocation failed\n");
- goto ir_dev_alloc_failed;
+ dev_err(ictx->dev, "input dev allocation failed\n");
+ goto out;
}
snprintf(ictx->name_idev, sizeof(ictx->name_idev),
- "iMON Remote (%04x:%04x)", ictx->vendor, ictx->product);
+ "iMON Panel, Knob and Mouse(%04x:%04x)",
+ ictx->vendor, ictx->product);
idev->name = ictx->name_idev;
usb_make_path(ictx->usbdev_intf0, ictx->phys_idev,
sizeof(ictx->phys_idev));
- strlcat(ictx->phys_idev, "/input0", sizeof(ictx->phys_idev));
+ strlcat(ictx->phys_idev, "/input1", sizeof(ictx->phys_idev));
idev->phys = ictx->phys_idev;
idev->evbit[0] = BIT_MASK(EV_KEY) | BIT_MASK(EV_REP) | BIT_MASK(EV_REL);
@@ -1698,37 +1895,20 @@ static struct input_dev *imon_init_idev(struct imon_context *ictx)
__set_bit(kc, idev->keybit);
}
- props->priv = ictx;
- props->driver_type = RC_DRIVER_SCANCODE;
- /* IR_TYPE_OTHER maps to iMON PAD remote, IR_TYPE_RC6 to MCE remote */
- props->allowed_protos = IR_TYPE_OTHER | IR_TYPE_RC6;
- props->change_protocol = imon_ir_change_protocol;
- ictx->props = props;
-
- ictx->ir = ir;
- memcpy(&ir->dev, ictx->dev, sizeof(struct device));
-
usb_to_input_id(ictx->usbdev_intf0, &idev->id);
idev->dev.parent = ictx->dev;
+ input_set_drvdata(idev, ictx);
- input_set_drvdata(idev, ir);
-
- ret = ir_input_register(idev, RC_MAP_IMON_PAD, props, MOD_NAME);
+ ret = input_register_device(idev);
if (ret < 0) {
- dev_err(ictx->dev, "remote input dev register failed\n");
- goto idev_register_failed;
+ dev_err(ictx->dev, "input dev register failed\n");
+ goto out;
}
return idev;
-idev_register_failed:
- kfree(ir);
-ir_dev_alloc_failed:
- kfree(props);
-props_alloc_failed:
+out:
input_free_device(idev);
-idev_alloc_failed:
-
return NULL;
}
@@ -1750,7 +1930,7 @@ static struct input_dev *imon_init_touch(struct imon_context *ictx)
usb_make_path(ictx->usbdev_intf1, ictx->phys_touch,
sizeof(ictx->phys_touch));
- strlcat(ictx->phys_touch, "/input1", sizeof(ictx->phys_touch));
+ strlcat(ictx->phys_touch, "/input2", sizeof(ictx->phys_touch));
touch->phys = ictx->phys_touch;
touch->evbit[0] =
@@ -1790,9 +1970,9 @@ static bool imon_find_endpoints(struct imon_context *ictx,
int ifnum = iface_desc->desc.bInterfaceNumber;
int num_endpts = iface_desc->desc.bNumEndpoints;
int i, ep_dir, ep_type;
- bool ir_ep_found = 0;
- bool display_ep_found = 0;
- bool tx_control = 0;
+ bool ir_ep_found = false;
+ bool display_ep_found = false;
+ bool tx_control = false;
/*
* Scan the endpoint list and set:
@@ -1808,13 +1988,13 @@ static bool imon_find_endpoints(struct imon_context *ictx,
ep_type == USB_ENDPOINT_XFER_INT) {
rx_endpoint = ep;
- ir_ep_found = 1;
+ ir_ep_found = true;
dev_dbg(ictx->dev, "%s: found IR endpoint\n", __func__);
} else if (!display_ep_found && ep_dir == USB_DIR_OUT &&
ep_type == USB_ENDPOINT_XFER_INT) {
tx_endpoint = ep;
- display_ep_found = 1;
+ display_ep_found = true;
dev_dbg(ictx->dev, "%s: found display endpoint\n", __func__);
}
}
@@ -1835,8 +2015,8 @@ static bool imon_find_endpoints(struct imon_context *ictx,
* newer iMON devices that use control urb instead of interrupt
*/
if (!display_ep_found) {
- tx_control = 1;
- display_ep_found = 1;
+ tx_control = true;
+ display_ep_found = true;
dev_dbg(ictx->dev, "%s: device uses control endpoint, not "
"interface OUT endpoint\n", __func__);
}
@@ -1847,7 +2027,7 @@ static bool imon_find_endpoints(struct imon_context *ictx,
* and without... :\
*/
if (ictx->display_type == IMON_DISPLAY_TYPE_NONE) {
- display_ep_found = 0;
+ display_ep_found = false;
dev_dbg(ictx->dev, "%s: device has no display\n", __func__);
}
@@ -1856,13 +2036,13 @@ static bool imon_find_endpoints(struct imon_context *ictx,
* that refers to e.g. /dev/lcd0 (a character device LCD or VFD).
*/
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA) {
- display_ep_found = 0;
+ display_ep_found = false;
dev_dbg(ictx->dev, "%s: iMON Touch device found\n", __func__);
}
/* Input endpoint is mandatory */
if (!ir_ep_found)
- err("%s: no valid input (IR) endpoint found.", __func__);
+ pr_err("no valid input (IR) endpoint found\n");
ictx->tx_control = tx_control;
@@ -1900,14 +2080,16 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
}
mutex_init(&ictx->lock);
+ spin_lock_init(&ictx->kc_lock);
mutex_lock(&ictx->lock);
ictx->dev = dev;
ictx->usbdev_intf0 = usb_get_dev(interface_to_usbdev(intf));
- ictx->dev_present_intf0 = 1;
+ ictx->dev_present_intf0 = true;
ictx->rx_urb_intf0 = rx_urb;
ictx->tx_urb = tx_urb;
+ ictx->rf_device = false;
ictx->vendor = le16_to_cpu(ictx->usbdev_intf0->descriptor.idVendor);
ictx->product = le16_to_cpu(ictx->usbdev_intf0->descriptor.idProduct);
@@ -1918,12 +2100,6 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
goto find_endpoint_failed;
}
- ictx->idev = imon_init_idev(ictx);
- if (!ictx->idev) {
- dev_err(dev, "%s: input device setup failed\n", __func__);
- goto idev_setup_failed;
- }
-
usb_fill_int_urb(ictx->rx_urb_intf0, ictx->usbdev_intf0,
usb_rcvintpipe(ictx->usbdev_intf0,
ictx->rx_endpoint_intf0->bEndpointAddress),
@@ -1933,17 +2109,29 @@ static struct imon_context *imon_init_intf0(struct usb_interface *intf)
ret = usb_submit_urb(ictx->rx_urb_intf0, GFP_KERNEL);
if (ret) {
- err("%s: usb_submit_urb failed for intf0 (%d)",
- __func__, ret);
+ pr_err("usb_submit_urb failed for intf0 (%d)\n", ret);
goto urb_submit_failed;
}
+ ictx->idev = imon_init_idev(ictx);
+ if (!ictx->idev) {
+ dev_err(dev, "%s: input device setup failed\n", __func__);
+ goto idev_setup_failed;
+ }
+
+ ictx->rdev = imon_init_rdev(ictx);
+ if (!ictx->rdev) {
+ dev_err(dev, "%s: rc device setup failed\n", __func__);
+ goto rdev_setup_failed;
+ }
+
return ictx;
-urb_submit_failed:
+rdev_setup_failed:
input_unregister_device(ictx->idev);
- input_free_device(ictx->idev);
idev_setup_failed:
+ usb_kill_urb(ictx->rx_urb_intf0);
+urb_submit_failed:
find_endpoint_failed:
mutex_unlock(&ictx->lock);
usb_free_urb(tx_urb);
@@ -1966,7 +2154,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
rx_urb = usb_alloc_urb(0, GFP_KERNEL);
if (!rx_urb) {
- err("%s: usb_alloc_urb failed for IR urb", __func__);
+ pr_err("usb_alloc_urb failed for IR urb\n");
goto rx_urb_alloc_failed;
}
@@ -1979,7 +2167,7 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
}
ictx->usbdev_intf1 = usb_get_dev(interface_to_usbdev(intf));
- ictx->dev_present_intf1 = 1;
+ ictx->dev_present_intf1 = true;
ictx->rx_urb_intf1 = rx_urb;
ret = -ENODEV;
@@ -2004,18 +2192,15 @@ static struct imon_context *imon_init_intf1(struct usb_interface *intf,
ret = usb_submit_urb(ictx->rx_urb_intf1, GFP_KERNEL);
if (ret) {
- err("%s: usb_submit_urb failed for intf1 (%d)",
- __func__, ret);
+ pr_err("usb_submit_urb failed for intf1 (%d)\n", ret);
goto urb_submit_failed;
}
return ictx;
urb_submit_failed:
- if (ictx->touch) {
+ if (ictx->touch)
input_unregister_device(ictx->touch);
- input_free_device(ictx->touch);
- }
touch_setup_failed:
find_endpoint_failed:
mutex_unlock(&ictx->lock);
@@ -2026,109 +2211,6 @@ rx_urb_alloc_failed:
return NULL;
}
-/*
- * The 0x15c2:0xffdc device ID was used for umpteen different imon
- * devices, and all of them constantly spew interrupts, even when there
- * is no actual data to report. However, byte 6 of this buffer looks like
- * its unique across device variants, so we're trying to key off that to
- * figure out which display type (if any) and what IR protocol the device
- * actually supports. These devices have their IR protocol hard-coded into
- * their firmware, they can't be changed on the fly like the newer hardware.
- */
-static void imon_get_ffdc_type(struct imon_context *ictx)
-{
- u8 ffdc_cfg_byte = ictx->usb_rx_buf[6];
- u8 detected_display_type = IMON_DISPLAY_TYPE_NONE;
- u64 allowed_protos = IR_TYPE_OTHER;
-
- switch (ffdc_cfg_byte) {
- /* iMON Knob, no display, iMON IR + vol knob */
- case 0x21:
- dev_info(ictx->dev, "0xffdc iMON Knob, iMON IR");
- ictx->display_supported = false;
- break;
- /* iMON VFD, no IR (does have vol knob tho) */
- case 0x35:
- dev_info(ictx->dev, "0xffdc iMON VFD + knob, no IR");
- detected_display_type = IMON_DISPLAY_TYPE_VFD;
- break;
- /* iMON VFD, iMON IR */
- case 0x24:
- case 0x85:
- dev_info(ictx->dev, "0xffdc iMON VFD, iMON IR");
- detected_display_type = IMON_DISPLAY_TYPE_VFD;
- break;
- /* iMON LCD, MCE IR */
- case 0x9f:
- dev_info(ictx->dev, "0xffdc iMON LCD, MCE IR");
- detected_display_type = IMON_DISPLAY_TYPE_LCD;
- allowed_protos = IR_TYPE_RC6;
- break;
- default:
- dev_info(ictx->dev, "Unknown 0xffdc device, "
- "defaulting to VFD and iMON IR");
- detected_display_type = IMON_DISPLAY_TYPE_VFD;
- break;
- }
-
- printk(KERN_CONT " (id 0x%02x)\n", ffdc_cfg_byte);
-
- ictx->display_type = detected_display_type;
- ictx->props->allowed_protos = allowed_protos;
- ictx->ir_type = allowed_protos;
-}
-
-static void imon_set_display_type(struct imon_context *ictx,
- struct usb_interface *intf)
-{
- u8 configured_display_type = IMON_DISPLAY_TYPE_VFD;
-
- /*
- * Try to auto-detect the type of display if the user hasn't set
- * it by hand via the display_type modparam. Default is VFD.
- */
-
- if (display_type == IMON_DISPLAY_TYPE_AUTO) {
- switch (ictx->product) {
- case 0xffdc:
- /* set in imon_get_ffdc_type() */
- configured_display_type = ictx->display_type;
- break;
- case 0x0034:
- case 0x0035:
- configured_display_type = IMON_DISPLAY_TYPE_VGA;
- break;
- case 0x0038:
- case 0x0039:
- case 0x0045:
- configured_display_type = IMON_DISPLAY_TYPE_LCD;
- break;
- case 0x003c:
- case 0x0041:
- case 0x0042:
- case 0x0043:
- configured_display_type = IMON_DISPLAY_TYPE_NONE;
- ictx->display_supported = false;
- break;
- case 0x0036:
- case 0x0044:
- default:
- configured_display_type = IMON_DISPLAY_TYPE_VFD;
- break;
- }
- } else {
- configured_display_type = display_type;
- if (display_type == IMON_DISPLAY_TYPE_NONE)
- ictx->display_supported = false;
- else
- ictx->display_supported = true;
- dev_info(ictx->dev, "%s: overriding display type to %d via "
- "modparam\n", __func__, display_type);
- }
-
- ictx->display_type = configured_display_type;
-}
-
static void imon_init_display(struct imon_context *ictx,
struct usb_interface *intf)
{
@@ -2137,8 +2219,7 @@ static void imon_init_display(struct imon_context *ictx,
dev_dbg(ictx->dev, "Registering iMON display with sysfs\n");
/* set up sysfs entry for built-in clock */
- ret = sysfs_create_group(&intf->dev.kobj,
- &imon_display_attribute_group);
+ ret = sysfs_create_group(&intf->dev.kobj, &imon_display_attr_group);
if (ret)
dev_err(ictx->dev, "Could not create display sysfs "
"entries(%d)", ret);
@@ -2169,8 +2250,6 @@ static int __devinit imon_probe(struct usb_interface *interface,
struct imon_context *ictx = NULL;
struct imon_context *first_if_ctx = NULL;
u16 vendor, product;
- const unsigned char fp_packet[] = { 0x40, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x88 };
code_length = BUF_CHUNK_SIZE * 8;
@@ -2187,30 +2266,21 @@ static int __devinit imon_probe(struct usb_interface *interface,
mutex_lock(&driver_lock);
first_if = usb_ifnum_to_if(usbdev, 0);
- first_if_ctx = (struct imon_context *)usb_get_intfdata(first_if);
+ first_if_ctx = usb_get_intfdata(first_if);
if (ifnum == 0) {
ictx = imon_init_intf0(interface);
if (!ictx) {
- err("%s: failed to initialize context!\n", __func__);
+ pr_err("failed to initialize context!\n");
ret = -ENODEV;
goto fail;
}
- if (product == 0xffdc) {
- /* RF products *also* use 0xffdc... sigh... */
- sysfs_err = sysfs_create_group(&interface->dev.kobj,
- &imon_rf_attribute_group);
- if (sysfs_err)
- err("%s: Could not create RF sysfs entries(%d)",
- __func__, sysfs_err);
- }
-
} else {
/* this is the secondary interface on the device */
ictx = imon_init_intf1(interface, first_if_ctx);
if (!ictx) {
- err("%s: failed to attach to context!\n", __func__);
+ pr_err("failed to attach to context!\n");
ret = -ENODEV;
goto fail;
}
@@ -2220,31 +2290,18 @@ static int __devinit imon_probe(struct usb_interface *interface,
usb_set_intfdata(interface, ictx);
if (ifnum == 0) {
- /* Enable front-panel buttons and/or knobs */
- memcpy(ictx->usb_tx_buf, &fp_packet, sizeof(fp_packet));
- ret = send_packet(ictx);
- /* Not fatal, but warn about it */
- if (ret)
- dev_info(dev, "failed to enable panel buttons "
- "and/or knobs\n");
-
- if (product == 0xffdc)
- imon_get_ffdc_type(ictx);
-
- imon_set_display_type(ictx, interface);
+ if (product == 0xffdc && ictx->rf_device) {
+ sysfs_err = sysfs_create_group(&interface->dev.kobj,
+ &imon_rf_attr_group);
+ if (sysfs_err)
+ pr_err("Could not create RF sysfs entries(%d)\n",
+ sysfs_err);
+ }
if (ictx->display_supported)
imon_init_display(ictx, interface);
}
- /* set IR protocol/remote type */
- ret = imon_ir_change_protocol(ictx, ictx->ir_type);
- if (ret) {
- dev_warn(dev, "%s: failed to set IR protocol, falling back "
- "to standard iMON protocol mode\n", __func__);
- ictx->ir_type = IR_TYPE_OTHER;
- }
-
dev_info(dev, "iMON device (%04x:%04x, intf%d) on "
"usb<%d:%d> initialized\n", vendor, product, ifnum,
usbdev->bus->busnum, usbdev->devnum);
@@ -2283,10 +2340,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
* sysfs_remove_group is safe to call even if sysfs_create_group
* hasn't been called
*/
- sysfs_remove_group(&interface->dev.kobj,
- &imon_display_attribute_group);
- sysfs_remove_group(&interface->dev.kobj,
- &imon_rf_attribute_group);
+ sysfs_remove_group(&interface->dev.kobj, &imon_display_attr_group);
+ sysfs_remove_group(&interface->dev.kobj, &imon_rf_attr_group);
usb_set_intfdata(interface, NULL);
@@ -2297,9 +2352,10 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
}
if (ifnum == 0) {
- ictx->dev_present_intf0 = 0;
+ ictx->dev_present_intf0 = false;
usb_kill_urb(ictx->rx_urb_intf0);
input_unregister_device(ictx->idev);
+ rc_unregister_device(ictx->rdev);
if (ictx->display_supported) {
if (ictx->display_type == IMON_DISPLAY_TYPE_LCD)
usb_deregister_dev(interface, &imon_lcd_class);
@@ -2307,7 +2363,7 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
usb_deregister_dev(interface, &imon_vfd_class);
}
} else {
- ictx->dev_present_intf1 = 0;
+ ictx->dev_present_intf1 = false;
usb_kill_urb(ictx->rx_urb_intf1);
if (ictx->display_type == IMON_DISPLAY_TYPE_VGA)
input_unregister_device(ictx->touch);
@@ -2319,11 +2375,8 @@ static void __devexit imon_disconnect(struct usb_interface *interface)
mutex_unlock(&ictx->lock);
if (!ictx->display_isopen)
free_imon_context(ictx);
- } else {
- if (ictx->ir_type == IR_TYPE_RC6)
- del_timer_sync(&ictx->itimer);
+ } else
mutex_unlock(&ictx->lock);
- }
mutex_unlock(&driver_lock);
@@ -2380,7 +2433,7 @@ static int __init imon_init(void)
rc = usb_register(&imon_driver);
if (rc) {
- err("%s: usb register failed(%d)", __func__, rc);
+ pr_err("usb register failed(%d)\n", rc);
rc = -ENODEV;
}
diff --git a/drivers/media/IR/ir-jvc-decoder.c b/drivers/media/rc/ir-jvc-decoder.c
index 0b804944cbb0..624449afaa61 100644
--- a/drivers/media/IR/ir-jvc-decoder.c
+++ b/drivers/media/rc/ir-jvc-decoder.c
@@ -13,7 +13,7 @@
*/
#include <linux/bitrev.h>
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define JVC_NBITS 16 /* dev(8) + func(8) */
#define JVC_UNIT 525000 /* ns */
@@ -25,10 +25,6 @@
#define JVC_TRAILER_PULSE (1 * JVC_UNIT)
#define JVC_TRAILER_SPACE (35 * JVC_UNIT)
-/* Used to register jvc_decoder clients */
-static LIST_HEAD(decoder_list);
-DEFINE_SPINLOCK(decoder_lock);
-
enum jvc_state {
STATE_INACTIVE,
STATE_HEADER_SPACE,
@@ -36,110 +32,26 @@ enum jvc_state {
STATE_BIT_SPACE,
STATE_TRAILER_PULSE,
STATE_TRAILER_SPACE,
-};
-
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum jvc_state state;
- u16 jvc_bits;
- u16 jvc_old_bits;
- unsigned count;
- bool first;
- bool toggle;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
-{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "jvc_decoder",
- .attrs = decoder_attributes,
+ STATE_CHECK_REPEAT,
};
/**
* ir_jvc_decode() - Decode one JVC pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @duration: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_jvc_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
+ struct jvc_dec *data = &dev->raw->jvc;
- if (!data->enabled)
+ if (!(dev->raw->enabled_protocols & RC_TYPE_JVC))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
@@ -149,6 +61,7 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
IR_dprintk(2, "JVC decode started at state %d (%uus %s)\n",
data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+again:
switch (data->state) {
case STATE_INACTIVE:
@@ -188,9 +101,9 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (ev.pulse)
break;
- data->jvc_bits <<= 1;
+ data->bits <<= 1;
if (eq_margin(ev.duration, JVC_BIT_1_SPACE, JVC_UNIT / 2)) {
- data->jvc_bits |= 1;
+ data->bits |= 1;
decrease_duration(&ev, JVC_BIT_1_SPACE);
} else if (eq_margin(ev.duration, JVC_BIT_0_SPACE, JVC_UNIT / 2))
decrease_duration(&ev, JVC_BIT_0_SPACE);
@@ -223,23 +136,33 @@ static int ir_jvc_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (data->first) {
u32 scancode;
- scancode = (bitrev8((data->jvc_bits >> 8) & 0xff) << 8) |
- (bitrev8((data->jvc_bits >> 0) & 0xff) << 0);
+ scancode = (bitrev8((data->bits >> 8) & 0xff) << 8) |
+ (bitrev8((data->bits >> 0) & 0xff) << 0);
IR_dprintk(1, "JVC scancode 0x%04x\n", scancode);
- ir_keydown(input_dev, scancode, data->toggle);
+ rc_keydown(dev, scancode, data->toggle);
data->first = false;
- data->jvc_old_bits = data->jvc_bits;
- } else if (data->jvc_bits == data->jvc_old_bits) {
+ data->old_bits = data->bits;
+ } else if (data->bits == data->old_bits) {
IR_dprintk(1, "JVC repeat\n");
- ir_repeat(input_dev);
+ rc_repeat(dev);
} else {
IR_dprintk(1, "JVC invalid repeat msg\n");
break;
}
data->count = 0;
- data->state = STATE_BIT_PULSE;
+ data->state = STATE_CHECK_REPEAT;
return 0;
+
+ case STATE_CHECK_REPEAT:
+ if (!ev.pulse)
+ break;
+
+ if (eq_margin(ev.duration, JVC_HEADER_PULSE, JVC_UNIT / 2))
+ data->state = STATE_INACTIVE;
+ else
+ data->state = STATE_BIT_PULSE;
+ goto again;
}
out:
@@ -249,54 +172,9 @@ out:
return -EINVAL;
}
-static int ir_jvc_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_jvc_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler jvc_handler = {
+ .protocols = RC_TYPE_JVC,
.decode = ir_jvc_decode,
- .raw_register = ir_jvc_register,
- .raw_unregister = ir_jvc_unregister,
};
static int __init ir_jvc_decode_init(void)
diff --git a/drivers/media/rc/ir-lirc-codec.c b/drivers/media/rc/ir-lirc-codec.c
new file mode 100644
index 000000000000..f011c5d9dea1
--- /dev/null
+++ b/drivers/media/rc/ir-lirc-codec.c
@@ -0,0 +1,402 @@
+/* ir-lirc-codec.c - ir-core to classic lirc interface bridge
+ *
+ * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/sched.h>
+#include <linux/wait.h>
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+#include <media/rc-core.h>
+#include "rc-core-priv.h"
+
+#define LIRCBUF_SIZE 256
+
+/**
+ * ir_lirc_decode() - Send raw IR data to lirc_dev to be relayed to the
+ * lircd userspace daemon for decoding.
+ * @input_dev: the struct rc_dev descriptor of the device
+ * @duration: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the lirc interfaces aren't wired up.
+ */
+static int ir_lirc_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+ struct lirc_codec *lirc = &dev->raw->lirc;
+ int sample;
+
+ if (!(dev->raw->enabled_protocols & RC_TYPE_LIRC))
+ return 0;
+
+ if (!dev->raw->lirc.drv || !dev->raw->lirc.drv->rbuf)
+ return -EINVAL;
+
+ /* Packet start */
+ if (ev.reset)
+ return 0;
+
+ /* Carrier reports */
+ if (ev.carrier_report) {
+ sample = LIRC_FREQUENCY(ev.carrier);
+
+ /* Packet end */
+ } else if (ev.timeout) {
+
+ if (lirc->gap)
+ return 0;
+
+ lirc->gap_start = ktime_get();
+ lirc->gap = true;
+ lirc->gap_duration = ev.duration;
+
+ if (!lirc->send_timeout_reports)
+ return 0;
+
+ sample = LIRC_TIMEOUT(ev.duration / 1000);
+
+ /* Normal sample */
+ } else {
+
+ if (lirc->gap) {
+ int gap_sample;
+
+ lirc->gap_duration += ktime_to_ns(ktime_sub(ktime_get(),
+ lirc->gap_start));
+
+ /* Convert to ms and cap by LIRC_VALUE_MASK */
+ do_div(lirc->gap_duration, 1000);
+ lirc->gap_duration = min(lirc->gap_duration,
+ (u64)LIRC_VALUE_MASK);
+
+ gap_sample = LIRC_SPACE(lirc->gap_duration);
+ lirc_buffer_write(dev->raw->lirc.drv->rbuf,
+ (unsigned char *) &gap_sample);
+ lirc->gap = false;
+ }
+
+ sample = ev.pulse ? LIRC_PULSE(ev.duration / 1000) :
+ LIRC_SPACE(ev.duration / 1000);
+ }
+
+ lirc_buffer_write(dev->raw->lirc.drv->rbuf,
+ (unsigned char *) &sample);
+ wake_up(&dev->raw->lirc.drv->rbuf->wait_poll);
+
+ return 0;
+}
+
+static ssize_t ir_lirc_transmit_ir(struct file *file, const char *buf,
+ size_t n, loff_t *ppos)
+{
+ struct lirc_codec *lirc;
+ struct rc_dev *dev;
+ int *txbuf; /* buffer with values to transmit */
+ int ret = 0;
+ size_t count;
+
+ lirc = lirc_get_pdata(file);
+ if (!lirc)
+ return -EFAULT;
+
+ if (n % sizeof(int))
+ return -EINVAL;
+
+ count = n / sizeof(int);
+ if (count > LIRCBUF_SIZE || count % 2 == 0 || n % sizeof(int) != 0)
+ return -EINVAL;
+
+ txbuf = memdup_user(buf, n);
+ if (IS_ERR(txbuf))
+ return PTR_ERR(txbuf);
+
+ dev = lirc->dev;
+ if (!dev) {
+ ret = -EFAULT;
+ goto out;
+ }
+
+ if (dev->tx_ir)
+ ret = dev->tx_ir(dev, txbuf, (u32)n);
+
+out:
+ kfree(txbuf);
+ return ret;
+}
+
+static long ir_lirc_ioctl(struct file *filep, unsigned int cmd,
+ unsigned long __user arg)
+{
+ struct lirc_codec *lirc;
+ struct rc_dev *dev;
+ int ret = 0;
+ __u32 val = 0, tmp;
+
+ lirc = lirc_get_pdata(filep);
+ if (!lirc)
+ return -EFAULT;
+
+ dev = lirc->dev;
+ if (!dev)
+ return -EFAULT;
+
+ if (_IOC_DIR(cmd) & _IOC_WRITE) {
+ ret = get_user(val, (__u32 *)arg);
+ if (ret)
+ return ret;
+ }
+
+ switch (cmd) {
+
+ /* legacy support */
+ case LIRC_GET_SEND_MODE:
+ val = LIRC_CAN_SEND_PULSE & LIRC_CAN_SEND_MASK;
+ break;
+
+ case LIRC_SET_SEND_MODE:
+ if (val != (LIRC_MODE_PULSE & LIRC_CAN_SEND_MASK))
+ return -EINVAL;
+ return 0;
+
+ /* TX settings */
+ case LIRC_SET_TRANSMITTER_MASK:
+ if (!dev->s_tx_mask)
+ return -EINVAL;
+
+ return dev->s_tx_mask(dev, val);
+
+ case LIRC_SET_SEND_CARRIER:
+ if (!dev->s_tx_carrier)
+ return -EINVAL;
+
+ return dev->s_tx_carrier(dev, val);
+
+ case LIRC_SET_SEND_DUTY_CYCLE:
+ if (!dev->s_tx_duty_cycle)
+ return -ENOSYS;
+
+ if (val <= 0 || val >= 100)
+ return -EINVAL;
+
+ return dev->s_tx_duty_cycle(dev, val);
+
+ /* RX settings */
+ case LIRC_SET_REC_CARRIER:
+ if (!dev->s_rx_carrier_range)
+ return -ENOSYS;
+
+ if (val <= 0)
+ return -EINVAL;
+
+ return dev->s_rx_carrier_range(dev,
+ dev->raw->lirc.carrier_low,
+ val);
+
+ case LIRC_SET_REC_CARRIER_RANGE:
+ if (val <= 0)
+ return -EINVAL;
+
+ dev->raw->lirc.carrier_low = val;
+ return 0;
+
+ case LIRC_GET_REC_RESOLUTION:
+ val = dev->rx_resolution;
+ break;
+
+ case LIRC_SET_WIDEBAND_RECEIVER:
+ if (!dev->s_learning_mode)
+ return -ENOSYS;
+
+ return dev->s_learning_mode(dev, !!val);
+
+ case LIRC_SET_MEASURE_CARRIER_MODE:
+ if (!dev->s_carrier_report)
+ return -ENOSYS;
+
+ return dev->s_carrier_report(dev, !!val);
+
+ /* Generic timeout support */
+ case LIRC_GET_MIN_TIMEOUT:
+ if (!dev->max_timeout)
+ return -ENOSYS;
+ val = dev->min_timeout / 1000;
+ break;
+
+ case LIRC_GET_MAX_TIMEOUT:
+ if (!dev->max_timeout)
+ return -ENOSYS;
+ val = dev->max_timeout / 1000;
+ break;
+
+ case LIRC_SET_REC_TIMEOUT:
+ if (!dev->max_timeout)
+ return -ENOSYS;
+
+ tmp = val * 1000;
+
+ if (tmp < dev->min_timeout ||
+ tmp > dev->max_timeout)
+ return -EINVAL;
+
+ dev->timeout = tmp;
+ break;
+
+ case LIRC_SET_REC_TIMEOUT_REPORTS:
+ lirc->send_timeout_reports = !!val;
+ break;
+
+ default:
+ return lirc_dev_fop_ioctl(filep, cmd, arg);
+ }
+
+ if (_IOC_DIR(cmd) & _IOC_READ)
+ ret = put_user(val, (__u32 *)arg);
+
+ return ret;
+}
+
+static int ir_lirc_open(void *data)
+{
+ return 0;
+}
+
+static void ir_lirc_close(void *data)
+{
+ return;
+}
+
+static struct file_operations lirc_fops = {
+ .owner = THIS_MODULE,
+ .write = ir_lirc_transmit_ir,
+ .unlocked_ioctl = ir_lirc_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = ir_lirc_ioctl,
+#endif
+ .read = lirc_dev_fop_read,
+ .poll = lirc_dev_fop_poll,
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+ .llseek = no_llseek,
+};
+
+static int ir_lirc_register(struct rc_dev *dev)
+{
+ struct lirc_driver *drv;
+ struct lirc_buffer *rbuf;
+ int rc = -ENOMEM;
+ unsigned long features;
+
+ drv = kzalloc(sizeof(struct lirc_driver), GFP_KERNEL);
+ if (!drv)
+ return rc;
+
+ rbuf = kzalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!rbuf)
+ goto rbuf_alloc_failed;
+
+ rc = lirc_buffer_init(rbuf, sizeof(int), LIRCBUF_SIZE);
+ if (rc)
+ goto rbuf_init_failed;
+
+ features = LIRC_CAN_REC_MODE2;
+ if (dev->tx_ir) {
+ features |= LIRC_CAN_SEND_PULSE;
+ if (dev->s_tx_mask)
+ features |= LIRC_CAN_SET_TRANSMITTER_MASK;
+ if (dev->s_tx_carrier)
+ features |= LIRC_CAN_SET_SEND_CARRIER;
+ if (dev->s_tx_duty_cycle)
+ features |= LIRC_CAN_SET_SEND_DUTY_CYCLE;
+ }
+
+ if (dev->s_rx_carrier_range)
+ features |= LIRC_CAN_SET_REC_CARRIER |
+ LIRC_CAN_SET_REC_CARRIER_RANGE;
+
+ if (dev->s_learning_mode)
+ features |= LIRC_CAN_USE_WIDEBAND_RECEIVER;
+
+ if (dev->s_carrier_report)
+ features |= LIRC_CAN_MEASURE_CARRIER;
+
+ if (dev->max_timeout)
+ features |= LIRC_CAN_SET_REC_TIMEOUT;
+
+ snprintf(drv->name, sizeof(drv->name), "ir-lirc-codec (%s)",
+ dev->driver_name);
+ drv->minor = -1;
+ drv->features = features;
+ drv->data = &dev->raw->lirc;
+ drv->rbuf = rbuf;
+ drv->set_use_inc = &ir_lirc_open;
+ drv->set_use_dec = &ir_lirc_close;
+ drv->code_length = sizeof(struct ir_raw_event) * 8;
+ drv->fops = &lirc_fops;
+ drv->dev = &dev->dev;
+ drv->owner = THIS_MODULE;
+
+ drv->minor = lirc_register_driver(drv);
+ if (drv->minor < 0) {
+ rc = -ENODEV;
+ goto lirc_register_failed;
+ }
+
+ dev->raw->lirc.drv = drv;
+ dev->raw->lirc.dev = dev;
+ return 0;
+
+lirc_register_failed:
+rbuf_init_failed:
+ kfree(rbuf);
+rbuf_alloc_failed:
+ kfree(drv);
+
+ return rc;
+}
+
+static int ir_lirc_unregister(struct rc_dev *dev)
+{
+ struct lirc_codec *lirc = &dev->raw->lirc;
+
+ lirc_unregister_driver(lirc->drv->minor);
+ lirc_buffer_free(lirc->drv->rbuf);
+ kfree(lirc->drv);
+
+ return 0;
+}
+
+static struct ir_raw_handler lirc_handler = {
+ .protocols = RC_TYPE_LIRC,
+ .decode = ir_lirc_decode,
+ .raw_register = ir_lirc_register,
+ .raw_unregister = ir_lirc_unregister,
+};
+
+static int __init ir_lirc_codec_init(void)
+{
+ ir_raw_handler_register(&lirc_handler);
+
+ printk(KERN_INFO "IR LIRC bridge handler initialized\n");
+ return 0;
+}
+
+static void __exit ir_lirc_codec_exit(void)
+{
+ ir_raw_handler_unregister(&lirc_handler);
+}
+
+module_init(ir_lirc_codec_init);
+module_exit(ir_lirc_codec_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("LIRC IR handler bridge");
diff --git a/drivers/media/IR/ir-nec-decoder.c b/drivers/media/rc/ir-nec-decoder.c
index ba79233112ef..7b58b4a1729b 100644
--- a/drivers/media/IR/ir-nec-decoder.c
+++ b/drivers/media/rc/ir-nec-decoder.c
@@ -13,23 +13,20 @@
*/
#include <linux/bitrev.h>
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define NEC_NBITS 32
#define NEC_UNIT 562500 /* ns */
#define NEC_HEADER_PULSE (16 * NEC_UNIT)
#define NECX_HEADER_PULSE (8 * NEC_UNIT) /* Less common NEC variant */
#define NEC_HEADER_SPACE (8 * NEC_UNIT)
-#define NEC_REPEAT_SPACE (8 * NEC_UNIT)
+#define NEC_REPEAT_SPACE (4 * NEC_UNIT)
#define NEC_BIT_PULSE (1 * NEC_UNIT)
#define NEC_BIT_0_SPACE (1 * NEC_UNIT)
#define NEC_BIT_1_SPACE (3 * NEC_UNIT)
#define NEC_TRAILER_PULSE (1 * NEC_UNIT)
#define NEC_TRAILER_SPACE (10 * NEC_UNIT) /* even longer in reality */
-
-/* Used to register nec_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
+#define NECX_REPEAT_BITS 1
enum nec_state {
STATE_INACTIVE,
@@ -40,107 +37,25 @@ enum nec_state {
STATE_TRAILER_SPACE,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum nec_state state;
- u32 nec_bits;
- unsigned count;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
-{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "nec_decoder",
- .attrs = decoder_attributes,
-};
-
/**
* ir_nec_decode() - Decode one NEC pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @duration: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_nec_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct nec_dec *data = &dev->raw->nec;
u32 scancode;
u8 address, not_address, command, not_command;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
-
- if (!data->enabled)
+ if (!(dev->raw->enabled_protocols & RC_TYPE_NEC))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
@@ -153,8 +68,12 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!ev.pulse)
break;
- if (!eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2) &&
- !eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
+ if (eq_margin(ev.duration, NEC_HEADER_PULSE, NEC_UNIT / 2)) {
+ data->is_nec_x = false;
+ data->necx_repeat = false;
+ } else if (eq_margin(ev.duration, NECX_HEADER_PULSE, NEC_UNIT / 2))
+ data->is_nec_x = true;
+ else
break;
data->count = 0;
@@ -169,9 +88,13 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
data->state = STATE_BIT_PULSE;
return 0;
} else if (eq_margin(ev.duration, NEC_REPEAT_SPACE, NEC_UNIT / 2)) {
- ir_repeat(input_dev);
- IR_dprintk(1, "Repeat last key\n");
- data->state = STATE_TRAILER_PULSE;
+ if (!dev->keypressed) {
+ IR_dprintk(1, "Discarding last key repeat: event after key up\n");
+ } else {
+ rc_repeat(dev);
+ IR_dprintk(1, "Repeat last key\n");
+ data->state = STATE_TRAILER_PULSE;
+ }
return 0;
}
@@ -191,9 +114,20 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (ev.pulse)
break;
- data->nec_bits <<= 1;
+ if (data->necx_repeat && data->count == NECX_REPEAT_BITS &&
+ geq_margin(ev.duration,
+ NEC_TRAILER_SPACE, NEC_UNIT / 2)) {
+ IR_dprintk(1, "Repeat last key\n");
+ rc_repeat(dev);
+ data->state = STATE_INACTIVE;
+ return 0;
+
+ } else if (data->count > NECX_REPEAT_BITS)
+ data->necx_repeat = false;
+
+ data->bits <<= 1;
if (eq_margin(ev.duration, NEC_BIT_1_SPACE, NEC_UNIT / 2))
- data->nec_bits |= 1;
+ data->bits |= 1;
else if (!eq_margin(ev.duration, NEC_BIT_0_SPACE, NEC_UNIT / 2))
break;
data->count++;
@@ -222,14 +156,14 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!geq_margin(ev.duration, NEC_TRAILER_SPACE, NEC_UNIT / 2))
break;
- address = bitrev8((data->nec_bits >> 24) & 0xff);
- not_address = bitrev8((data->nec_bits >> 16) & 0xff);
- command = bitrev8((data->nec_bits >> 8) & 0xff);
- not_command = bitrev8((data->nec_bits >> 0) & 0xff);
+ address = bitrev8((data->bits >> 24) & 0xff);
+ not_address = bitrev8((data->bits >> 16) & 0xff);
+ command = bitrev8((data->bits >> 8) & 0xff);
+ not_command = bitrev8((data->bits >> 0) & 0xff);
if ((command ^ not_command) != 0xff) {
IR_dprintk(1, "NEC checksum error: received 0x%08x\n",
- data->nec_bits);
+ data->bits);
break;
}
@@ -245,7 +179,10 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
IR_dprintk(1, "NEC scancode 0x%04x\n", scancode);
}
- ir_keydown(input_dev, scancode, 0);
+ if (data->is_nec_x)
+ data->necx_repeat = true;
+
+ rc_keydown(dev, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
@@ -256,54 +193,9 @@ static int ir_nec_decode(struct input_dev *input_dev, struct ir_raw_event ev)
return -EINVAL;
}
-static int ir_nec_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_nec_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler nec_handler = {
+ .protocols = RC_TYPE_NEC,
.decode = ir_nec_decode,
- .raw_register = ir_nec_register,
- .raw_unregister = ir_nec_unregister,
};
static int __init ir_nec_decode_init(void)
diff --git a/drivers/media/rc/ir-raw.c b/drivers/media/rc/ir-raw.c
new file mode 100644
index 000000000000..73230ff93b8a
--- /dev/null
+++ b/drivers/media/rc/ir-raw.c
@@ -0,0 +1,371 @@
+/* ir-raw.c - handle IR pulse/space events
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kthread.h>
+#include <linux/mutex.h>
+#include <linux/sched.h>
+#include <linux/freezer.h>
+#include "rc-core-priv.h"
+
+/* Define the max number of pulse/space transitions to buffer */
+#define MAX_IR_EVENT_SIZE 512
+
+/* Used to keep track of IR raw clients, protected by ir_raw_handler_lock */
+static LIST_HEAD(ir_raw_client_list);
+
+/* Used to handle IR raw handler extensions */
+static DEFINE_MUTEX(ir_raw_handler_lock);
+static LIST_HEAD(ir_raw_handler_list);
+static u64 available_protocols;
+
+#ifdef MODULE
+/* Used to load the decoders */
+static struct work_struct wq_load;
+#endif
+
+static int ir_raw_event_thread(void *data)
+{
+ struct ir_raw_event ev;
+ struct ir_raw_handler *handler;
+ struct ir_raw_event_ctrl *raw = (struct ir_raw_event_ctrl *)data;
+ int retval;
+
+ while (!kthread_should_stop()) {
+
+ spin_lock_irq(&raw->lock);
+ retval = kfifo_out(&raw->kfifo, &ev, sizeof(ev));
+
+ if (!retval) {
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (kthread_should_stop())
+ set_current_state(TASK_RUNNING);
+
+ spin_unlock_irq(&raw->lock);
+ schedule();
+ continue;
+ }
+
+ spin_unlock_irq(&raw->lock);
+
+
+ BUG_ON(retval != sizeof(ev));
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ handler->decode(raw->dev, ev);
+ raw->prev_ev = ev;
+ mutex_unlock(&ir_raw_handler_lock);
+ }
+
+ return 0;
+}
+
+/**
+ * ir_raw_event_store() - pass a pulse/space duration to the raw ir decoders
+ * @dev: the struct rc_dev device descriptor
+ * @ev: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This routine (which may be called from an interrupt context) stores a
+ * pulse/space duration for the raw ir decoding state machines. Pulses are
+ * signalled as positive values and spaces as negative values. A zero value
+ * will reset the decoding state machines.
+ */
+int ir_raw_event_store(struct rc_dev *dev, struct ir_raw_event *ev)
+{
+ if (!dev->raw)
+ return -EINVAL;
+
+ IR_dprintk(2, "sample: (%05dus %s)\n",
+ TO_US(ev->duration), TO_STR(ev->pulse));
+
+ if (kfifo_in(&dev->raw->kfifo, ev, sizeof(*ev)) != sizeof(*ev))
+ return -ENOMEM;
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store);
+
+/**
+ * ir_raw_event_store_edge() - notify raw ir decoders of the start of a pulse/space
+ * @dev: the struct rc_dev device descriptor
+ * @type: the type of the event that has occurred
+ *
+ * This routine (which may be called from an interrupt context) is used to
+ * store the beginning of an ir pulse or space (or the start/end of ir
+ * reception) for the raw ir decoding state machines. This is used by
+ * hardware which does not provide durations directly but only interrupts
+ * (or similar events) on state change.
+ */
+int ir_raw_event_store_edge(struct rc_dev *dev, enum raw_event_type type)
+{
+ ktime_t now;
+ s64 delta; /* ns */
+ struct ir_raw_event ev;
+ int rc = 0;
+
+ if (!dev->raw)
+ return -EINVAL;
+
+ now = ktime_get();
+ delta = ktime_to_ns(ktime_sub(now, dev->raw->last_event));
+
+ /* Check for a long duration since last event or if we're
+ * being called for the first time, note that delta can't
+ * possibly be negative.
+ */
+ ev.duration = 0;
+ if (delta > IR_MAX_DURATION || !dev->raw->last_type)
+ type |= IR_START_EVENT;
+ else
+ ev.duration = delta;
+
+ if (type & IR_START_EVENT)
+ ir_raw_event_reset(dev);
+ else if (dev->raw->last_type & IR_SPACE) {
+ ev.pulse = false;
+ rc = ir_raw_event_store(dev, &ev);
+ } else if (dev->raw->last_type & IR_PULSE) {
+ ev.pulse = true;
+ rc = ir_raw_event_store(dev, &ev);
+ } else
+ return 0;
+
+ dev->raw->last_event = now;
+ dev->raw->last_type = type;
+ return rc;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store_edge);
+
+/**
+ * ir_raw_event_store_with_filter() - pass next pulse/space to decoders with some processing
+ * @dev: the struct rc_dev device descriptor
+ * @type: the type of the event that has occurred
+ *
+ * This routine (which may be called from an interrupt context) works
+ * in similiar manner to ir_raw_event_store_edge.
+ * This routine is intended for devices with limited internal buffer
+ * It automerges samples of same type, and handles timeouts
+ */
+int ir_raw_event_store_with_filter(struct rc_dev *dev, struct ir_raw_event *ev)
+{
+ if (!dev->raw)
+ return -EINVAL;
+
+ /* Ignore spaces in idle mode */
+ if (dev->idle && !ev->pulse)
+ return 0;
+ else if (dev->idle)
+ ir_raw_event_set_idle(dev, false);
+
+ if (!dev->raw->this_ev.duration)
+ dev->raw->this_ev = *ev;
+ else if (ev->pulse == dev->raw->this_ev.pulse)
+ dev->raw->this_ev.duration += ev->duration;
+ else {
+ ir_raw_event_store(dev, &dev->raw->this_ev);
+ dev->raw->this_ev = *ev;
+ }
+
+ /* Enter idle mode if nessesary */
+ if (!ev->pulse && dev->timeout &&
+ dev->raw->this_ev.duration >= dev->timeout)
+ ir_raw_event_set_idle(dev, true);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_store_with_filter);
+
+/**
+ * ir_raw_event_set_idle() - provide hint to rc-core when the device is idle or not
+ * @dev: the struct rc_dev device descriptor
+ * @idle: whether the device is idle or not
+ */
+void ir_raw_event_set_idle(struct rc_dev *dev, bool idle)
+{
+ if (!dev->raw)
+ return;
+
+ IR_dprintk(2, "%s idle mode\n", idle ? "enter" : "leave");
+
+ if (idle) {
+ dev->raw->this_ev.timeout = true;
+ ir_raw_event_store(dev, &dev->raw->this_ev);
+ init_ir_raw_event(&dev->raw->this_ev);
+ }
+
+ if (dev->s_idle)
+ dev->s_idle(dev, idle);
+
+ dev->idle = idle;
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_set_idle);
+
+/**
+ * ir_raw_event_handle() - schedules the decoding of stored ir data
+ * @dev: the struct rc_dev device descriptor
+ *
+ * This routine will tell rc-core to start decoding stored ir data.
+ */
+void ir_raw_event_handle(struct rc_dev *dev)
+{
+ unsigned long flags;
+
+ if (!dev->raw)
+ return;
+
+ spin_lock_irqsave(&dev->raw->lock, flags);
+ wake_up_process(dev->raw->thread);
+ spin_unlock_irqrestore(&dev->raw->lock, flags);
+}
+EXPORT_SYMBOL_GPL(ir_raw_event_handle);
+
+/* used internally by the sysfs interface */
+u64
+ir_raw_get_allowed_protocols(void)
+{
+ u64 protocols;
+ mutex_lock(&ir_raw_handler_lock);
+ protocols = available_protocols;
+ mutex_unlock(&ir_raw_handler_lock);
+ return protocols;
+}
+
+/*
+ * Used to (un)register raw event clients
+ */
+int ir_raw_event_register(struct rc_dev *dev)
+{
+ int rc;
+ struct ir_raw_handler *handler;
+
+ if (!dev)
+ return -EINVAL;
+
+ dev->raw = kzalloc(sizeof(*dev->raw), GFP_KERNEL);
+ if (!dev->raw)
+ return -ENOMEM;
+
+ dev->raw->dev = dev;
+ dev->raw->enabled_protocols = ~0;
+ rc = kfifo_alloc(&dev->raw->kfifo,
+ sizeof(struct ir_raw_event) * MAX_IR_EVENT_SIZE,
+ GFP_KERNEL);
+ if (rc < 0)
+ goto out;
+
+ spin_lock_init(&dev->raw->lock);
+ dev->raw->thread = kthread_run(ir_raw_event_thread, dev->raw,
+ "rc%ld", dev->devno);
+
+ if (IS_ERR(dev->raw->thread)) {
+ rc = PTR_ERR(dev->raw->thread);
+ goto out;
+ }
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_add_tail(&dev->raw->list, &ir_raw_client_list);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ if (handler->raw_register)
+ handler->raw_register(dev);
+ mutex_unlock(&ir_raw_handler_lock);
+
+ return 0;
+
+out:
+ kfree(dev->raw);
+ dev->raw = NULL;
+ return rc;
+}
+
+void ir_raw_event_unregister(struct rc_dev *dev)
+{
+ struct ir_raw_handler *handler;
+
+ if (!dev || !dev->raw)
+ return;
+
+ kthread_stop(dev->raw->thread);
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_del(&dev->raw->list);
+ list_for_each_entry(handler, &ir_raw_handler_list, list)
+ if (handler->raw_unregister)
+ handler->raw_unregister(dev);
+ mutex_unlock(&ir_raw_handler_lock);
+
+ kfifo_free(&dev->raw->kfifo);
+ kfree(dev->raw);
+ dev->raw = NULL;
+}
+
+/*
+ * Extension interface - used to register the IR decoders
+ */
+
+int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler)
+{
+ struct ir_raw_event_ctrl *raw;
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_add_tail(&ir_raw_handler->list, &ir_raw_handler_list);
+ if (ir_raw_handler->raw_register)
+ list_for_each_entry(raw, &ir_raw_client_list, list)
+ ir_raw_handler->raw_register(raw->dev);
+ available_protocols |= ir_raw_handler->protocols;
+ mutex_unlock(&ir_raw_handler_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(ir_raw_handler_register);
+
+void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler)
+{
+ struct ir_raw_event_ctrl *raw;
+
+ mutex_lock(&ir_raw_handler_lock);
+ list_del(&ir_raw_handler->list);
+ if (ir_raw_handler->raw_unregister)
+ list_for_each_entry(raw, &ir_raw_client_list, list)
+ ir_raw_handler->raw_unregister(raw->dev);
+ available_protocols &= ~ir_raw_handler->protocols;
+ mutex_unlock(&ir_raw_handler_lock);
+}
+EXPORT_SYMBOL(ir_raw_handler_unregister);
+
+#ifdef MODULE
+static void init_decoders(struct work_struct *work)
+{
+ /* Load the decoder modules */
+
+ load_nec_decode();
+ load_rc5_decode();
+ load_rc6_decode();
+ load_jvc_decode();
+ load_sony_decode();
+ load_lirc_codec();
+
+ /* If needed, we may later add some init code. In this case,
+ it is needed to change the CONFIG_MODULE test at rc-core.h
+ */
+}
+#endif
+
+void ir_raw_init(void)
+{
+#ifdef MODULE
+ INIT_WORK(&wq_load, init_decoders);
+ schedule_work(&wq_load);
+#endif
+}
diff --git a/drivers/media/IR/ir-rc5-decoder.c b/drivers/media/rc/ir-rc5-decoder.c
index 23cdb1b1a3bc..ebdba5539916 100644
--- a/drivers/media/IR/ir-rc5-decoder.c
+++ b/drivers/media/rc/ir-rc5-decoder.c
@@ -20,7 +20,7 @@
* the first two bits are start bits, and a third one is a filing bit
*/
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define RC5_NBITS 14
#define RC5X_NBITS 20
@@ -30,10 +30,6 @@
#define RC5_BIT_END (1 * RC5_UNIT)
#define RC5X_SPACE (4 * RC5_UNIT)
-/* Used to register rc5_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
enum rc5_state {
STATE_INACTIVE,
STATE_BIT_START,
@@ -42,110 +38,25 @@ enum rc5_state {
STATE_FINISHED,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum rc5_state state;
- u32 rc5_bits;
- struct ir_raw_event prev_ev;
- unsigned count;
- unsigned wanted_bits;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
-{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "rc5_decoder",
- .attrs = decoder_attributes,
-};
-
/**
* ir_rc5_decode() - Decode one RC-5 pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_rc5_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_rc5_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct rc5_dec *data = &dev->raw->rc5;
u8 toggle;
u32 scancode;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
+ if (!(dev->raw->enabled_protocols & RC_TYPE_RC5))
+ return 0;
- if (!data->enabled)
- return 0;
-
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
@@ -176,16 +87,15 @@ again:
if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
break;
- data->rc5_bits <<= 1;
+ data->bits <<= 1;
if (!ev.pulse)
- data->rc5_bits |= 1;
+ data->bits |= 1;
data->count++;
- data->prev_ev = ev;
data->state = STATE_BIT_END;
return 0;
case STATE_BIT_END:
- if (!is_transition(&ev, &data->prev_ev))
+ if (!is_transition(&ev, &dev->raw->prev_ev))
break;
if (data->count == data->wanted_bits)
@@ -217,11 +127,11 @@ again:
if (data->wanted_bits == RC5X_NBITS) {
/* RC5X */
u8 xdata, command, system;
- xdata = (data->rc5_bits & 0x0003F) >> 0;
- command = (data->rc5_bits & 0x00FC0) >> 6;
- system = (data->rc5_bits & 0x1F000) >> 12;
- toggle = (data->rc5_bits & 0x20000) ? 1 : 0;
- command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+ xdata = (data->bits & 0x0003F) >> 0;
+ command = (data->bits & 0x00FC0) >> 6;
+ system = (data->bits & 0x1F000) >> 12;
+ toggle = (data->bits & 0x20000) ? 1 : 0;
+ command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 16 | command << 8 | xdata;
IR_dprintk(1, "RC5X scancode 0x%06x (toggle: %u)\n",
@@ -230,17 +140,17 @@ again:
} else {
/* RC5 */
u8 command, system;
- command = (data->rc5_bits & 0x0003F) >> 0;
- system = (data->rc5_bits & 0x007C0) >> 6;
- toggle = (data->rc5_bits & 0x00800) ? 1 : 0;
- command += (data->rc5_bits & 0x01000) ? 0 : 0x40;
+ command = (data->bits & 0x0003F) >> 0;
+ system = (data->bits & 0x007C0) >> 6;
+ toggle = (data->bits & 0x00800) ? 1 : 0;
+ command += (data->bits & 0x01000) ? 0 : 0x40;
scancode = system << 8 | command;
IR_dprintk(1, "RC5 scancode 0x%04x (toggle: %u)\n",
scancode, toggle);
}
- ir_keydown(input_dev, scancode, toggle);
+ rc_keydown(dev, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
@@ -252,54 +162,9 @@ out:
return -EINVAL;
}
-static int ir_rc5_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_rc5_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler rc5_handler = {
+ .protocols = RC_TYPE_RC5,
.decode = ir_rc5_decode,
- .raw_register = ir_rc5_register,
- .raw_unregister = ir_rc5_unregister,
};
static int __init ir_rc5_decode_init(void)
diff --git a/drivers/media/rc/ir-rc5-sz-decoder.c b/drivers/media/rc/ir-rc5-sz-decoder.c
new file mode 100644
index 000000000000..90aa8868629a
--- /dev/null
+++ b/drivers/media/rc/ir-rc5-sz-decoder.c
@@ -0,0 +1,153 @@
+/* ir-rc5-sz-decoder.c - handle RC5 Streamzap IR Pulse/Space protocol
+ *
+ * Copyright (C) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (C) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * 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.
+ */
+
+/*
+ * This code handles the 15 bit RC5-ish protocol used by the Streamzap
+ * PC Remote.
+ * It considers a carrier of 36 kHz, with a total of 15 bits, where
+ * the first two bits are start bits, and a third one is a filing bit
+ */
+
+#include "rc-core-priv.h"
+
+#define RC5_SZ_NBITS 15
+#define RC5_UNIT 888888 /* ns */
+#define RC5_BIT_START (1 * RC5_UNIT)
+#define RC5_BIT_END (1 * RC5_UNIT)
+
+enum rc5_sz_state {
+ STATE_INACTIVE,
+ STATE_BIT_START,
+ STATE_BIT_END,
+ STATE_FINISHED,
+};
+
+/**
+ * ir_rc5_sz_decode() - Decode one RC-5 Streamzap pulse or space
+ * @dev: the struct rc_dev descriptor of the device
+ * @ev: the struct ir_raw_event descriptor of the pulse/space
+ *
+ * This function returns -EINVAL if the pulse violates the state machine
+ */
+static int ir_rc5_sz_decode(struct rc_dev *dev, struct ir_raw_event ev)
+{
+ struct rc5_sz_dec *data = &dev->raw->rc5_sz;
+ u8 toggle, command, system;
+ u32 scancode;
+
+ if (!(dev->raw->enabled_protocols & RC_TYPE_RC5_SZ))
+ return 0;
+
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+
+ if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+ goto out;
+
+again:
+ IR_dprintk(2, "RC5-sz decode started at state %i (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+
+ if (!geq_margin(ev.duration, RC5_UNIT, RC5_UNIT / 2))
+ return 0;
+
+ switch (data->state) {
+
+ case STATE_INACTIVE:
+ if (!ev.pulse)
+ break;
+
+ data->state = STATE_BIT_START;
+ data->count = 1;
+ data->wanted_bits = RC5_SZ_NBITS;
+ decrease_duration(&ev, RC5_BIT_START);
+ goto again;
+
+ case STATE_BIT_START:
+ if (!eq_margin(ev.duration, RC5_BIT_START, RC5_UNIT / 2))
+ break;
+
+ data->bits <<= 1;
+ if (!ev.pulse)
+ data->bits |= 1;
+ data->count++;
+ data->state = STATE_BIT_END;
+ return 0;
+
+ case STATE_BIT_END:
+ if (!is_transition(&ev, &dev->raw->prev_ev))
+ break;
+
+ if (data->count == data->wanted_bits)
+ data->state = STATE_FINISHED;
+ else
+ data->state = STATE_BIT_START;
+
+ decrease_duration(&ev, RC5_BIT_END);
+ goto again;
+
+ case STATE_FINISHED:
+ if (ev.pulse)
+ break;
+
+ /* RC5-sz */
+ command = (data->bits & 0x0003F) >> 0;
+ system = (data->bits & 0x02FC0) >> 6;
+ toggle = (data->bits & 0x01000) ? 1 : 0;
+ scancode = system << 6 | command;
+
+ IR_dprintk(1, "RC5-sz scancode 0x%04x (toggle: %u)\n",
+ scancode, toggle);
+
+ rc_keydown(dev, scancode, toggle);
+ data->state = STATE_INACTIVE;
+ return 0;
+ }
+
+out:
+ IR_dprintk(1, "RC5-sz decode failed at state %i (%uus %s)\n",
+ data->state, TO_US(ev.duration), TO_STR(ev.pulse));
+ data->state = STATE_INACTIVE;
+ return -EINVAL;
+}
+
+static struct ir_raw_handler rc5_sz_handler = {
+ .protocols = RC_TYPE_RC5_SZ,
+ .decode = ir_rc5_sz_decode,
+};
+
+static int __init ir_rc5_sz_decode_init(void)
+{
+ ir_raw_handler_register(&rc5_sz_handler);
+
+ printk(KERN_INFO "IR RC5 (streamzap) protocol handler initialized\n");
+ return 0;
+}
+
+static void __exit ir_rc5_sz_decode_exit(void)
+{
+ ir_raw_handler_unregister(&rc5_sz_handler);
+}
+
+module_init(ir_rc5_sz_decode_init);
+module_exit(ir_rc5_sz_decode_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_AUTHOR("Red Hat Inc. (http://www.redhat.com)");
+MODULE_DESCRIPTION("RC5 (streamzap) IR protocol decoder");
diff --git a/drivers/media/IR/ir-rc6-decoder.c b/drivers/media/rc/ir-rc6-decoder.c
index 2bf479f4f1bc..755dafa3871b 100644
--- a/drivers/media/IR/ir-rc6-decoder.c
+++ b/drivers/media/rc/ir-rc6-decoder.c
@@ -12,7 +12,7 @@
* GNU General Public License for more details.
*/
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
/*
* This decoder currently supports:
@@ -36,10 +36,6 @@
#define RC6_STARTBIT_MASK 0x08 /* for the header bits */
#define RC6_6A_MCE_TOGGLE_MASK 0x8000 /* for the body bits */
-/* Used to register rc6_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
enum rc6_mode {
RC6_MODE_0,
RC6_MODE_6A,
@@ -58,89 +54,8 @@ enum rc6_state {
STATE_FINISHED,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum rc6_state state;
- u8 header;
- u32 body;
- struct ir_raw_event prev_ev;
- bool toggle;
- unsigned count;
- unsigned wanted_bits;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
+static enum rc6_mode rc6_mode(struct rc6_dec *data)
{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "rc6_decoder",
- .attrs = decoder_attributes,
-};
-
-static enum rc6_mode rc6_mode(struct decoder_data *data) {
switch (data->header & RC6_MODE_MASK) {
case 0:
return RC6_MODE_0;
@@ -155,27 +70,23 @@ static enum rc6_mode rc6_mode(struct decoder_data *data) {
/**
* ir_rc6_decode() - Decode one RC6 pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_rc6_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_rc6_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct rc6_dec *data = &dev->raw->rc6;
u32 scancode;
u8 toggle;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
-
- if (!data->enabled)
+ if (!(dev->raw->enabled_protocols & RC_TYPE_RC6))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
@@ -223,12 +134,11 @@ again:
if (ev.pulse)
data->header |= 1;
data->count++;
- data->prev_ev = ev;
data->state = STATE_HEADER_BIT_END;
return 0;
case STATE_HEADER_BIT_END:
- if (!is_transition(&ev, &data->prev_ev))
+ if (!is_transition(&ev, &dev->raw->prev_ev))
break;
if (data->count == RC6_HEADER_NBITS)
@@ -244,12 +154,11 @@ again:
break;
data->toggle = ev.pulse;
- data->prev_ev = ev;
data->state = STATE_TOGGLE_END;
return 0;
case STATE_TOGGLE_END:
- if (!is_transition(&ev, &data->prev_ev) ||
+ if (!is_transition(&ev, &dev->raw->prev_ev) ||
!geq_margin(ev.duration, RC6_TOGGLE_END, RC6_UNIT / 2))
break;
@@ -259,7 +168,6 @@ again:
}
data->state = STATE_BODY_BIT_START;
- data->prev_ev = ev;
decrease_duration(&ev, RC6_TOGGLE_END);
data->count = 0;
@@ -291,13 +199,11 @@ again:
if (ev.pulse)
data->body |= 1;
data->count++;
- data->prev_ev = ev;
-
data->state = STATE_BODY_BIT_END;
return 0;
case STATE_BODY_BIT_END:
- if (!is_transition(&ev, &data->prev_ev))
+ if (!is_transition(&ev, &dev->raw->prev_ev))
break;
if (data->count == data->wanted_bits)
@@ -336,7 +242,7 @@ again:
goto out;
}
- ir_keydown(input_dev, scancode, toggle);
+ rc_keydown(dev, scancode, toggle);
data->state = STATE_INACTIVE;
return 0;
}
@@ -348,54 +254,9 @@ out:
return -EINVAL;
}
-static int ir_rc6_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_rc6_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler rc6_handler = {
+ .protocols = RC_TYPE_RC6,
.decode = ir_rc6_decode,
- .raw_register = ir_rc6_register,
- .raw_unregister = ir_rc6_unregister,
};
static int __init ir_rc6_decode_init(void)
diff --git a/drivers/media/IR/ir-sony-decoder.c b/drivers/media/rc/ir-sony-decoder.c
index 9f440c5c060d..a92de80c48db 100644
--- a/drivers/media/IR/ir-sony-decoder.c
+++ b/drivers/media/rc/ir-sony-decoder.c
@@ -13,7 +13,7 @@
*/
#include <linux/bitrev.h>
-#include "ir-core-priv.h"
+#include "rc-core-priv.h"
#define SONY_UNIT 600000 /* ns */
#define SONY_HEADER_PULSE (4 * SONY_UNIT)
@@ -23,10 +23,6 @@
#define SONY_BIT_SPACE (1 * SONY_UNIT)
#define SONY_TRAILER_SPACE (10 * SONY_UNIT) /* minimum */
-/* Used to register sony_decoder clients */
-static LIST_HEAD(decoder_list);
-static DEFINE_SPINLOCK(decoder_lock);
-
enum sony_state {
STATE_INACTIVE,
STATE_HEADER_SPACE,
@@ -35,107 +31,25 @@ enum sony_state {
STATE_FINISHED,
};
-struct decoder_data {
- struct list_head list;
- struct ir_input_dev *ir_dev;
- int enabled:1;
-
- /* State machine control */
- enum sony_state state;
- u32 sony_bits;
- unsigned count;
-};
-
-
-/**
- * get_decoder_data() - gets decoder data
- * @input_dev: input device
- *
- * Returns the struct decoder_data that corresponds to a device
- */
-static struct decoder_data *get_decoder_data(struct ir_input_dev *ir_dev)
-{
- struct decoder_data *data = NULL;
-
- spin_lock(&decoder_lock);
- list_for_each_entry(data, &decoder_list, list) {
- if (data->ir_dev == ir_dev)
- break;
- }
- spin_unlock(&decoder_lock);
- return data;
-}
-
-static ssize_t store_enabled(struct device *d,
- struct device_attribute *mattr,
- const char *buf,
- size_t len)
-{
- unsigned long value;
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (strict_strtoul(buf, 10, &value) || value > 1)
- return -EINVAL;
-
- data->enabled = value;
-
- return len;
-}
-
-static ssize_t show_enabled(struct device *d,
- struct device_attribute *mattr, char *buf)
-{
- struct ir_input_dev *ir_dev = dev_get_drvdata(d);
- struct decoder_data *data = get_decoder_data(ir_dev);
-
- if (!data)
- return -EINVAL;
-
- if (data->enabled)
- return sprintf(buf, "1\n");
- else
- return sprintf(buf, "0\n");
-}
-
-static DEVICE_ATTR(enabled, S_IRUGO | S_IWUSR, show_enabled, store_enabled);
-
-static struct attribute *decoder_attributes[] = {
- &dev_attr_enabled.attr,
- NULL
-};
-
-static struct attribute_group decoder_attribute_group = {
- .name = "sony_decoder",
- .attrs = decoder_attributes,
-};
-
/**
* ir_sony_decode() - Decode one Sony pulse or space
- * @input_dev: the struct input_dev descriptor of the device
+ * @dev: the struct rc_dev descriptor of the device
* @ev: the struct ir_raw_event descriptor of the pulse/space
*
* This function returns -EINVAL if the pulse violates the state machine
*/
-static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
+static int ir_sony_decode(struct rc_dev *dev, struct ir_raw_event ev)
{
- struct decoder_data *data;
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
+ struct sony_dec *data = &dev->raw->sony;
u32 scancode;
u8 device, subdevice, function;
- data = get_decoder_data(ir_dev);
- if (!data)
- return -EINVAL;
-
- if (!data->enabled)
+ if (!(dev->raw->enabled_protocols & RC_TYPE_SONY))
return 0;
- if (IS_RESET(ev)) {
- data->state = STATE_INACTIVE;
+ if (!is_timing_event(ev)) {
+ if (ev.reset)
+ data->state = STATE_INACTIVE;
return 0;
}
@@ -172,9 +86,9 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
if (!ev.pulse)
break;
- data->sony_bits <<= 1;
+ data->bits <<= 1;
if (eq_margin(ev.duration, SONY_BIT_1_PULSE, SONY_UNIT / 2))
- data->sony_bits |= 1;
+ data->bits |= 1;
else if (!eq_margin(ev.duration, SONY_BIT_0_PULSE, SONY_UNIT / 2))
break;
@@ -208,19 +122,19 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
switch (data->count) {
case 12:
- device = bitrev8((data->sony_bits << 3) & 0xF8);
+ device = bitrev8((data->bits << 3) & 0xF8);
subdevice = 0;
- function = bitrev8((data->sony_bits >> 4) & 0xFE);
+ function = bitrev8((data->bits >> 4) & 0xFE);
break;
case 15:
- device = bitrev8((data->sony_bits >> 0) & 0xFF);
+ device = bitrev8((data->bits >> 0) & 0xFF);
subdevice = 0;
- function = bitrev8((data->sony_bits >> 7) & 0xFD);
+ function = bitrev8((data->bits >> 7) & 0xFD);
break;
case 20:
- device = bitrev8((data->sony_bits >> 5) & 0xF8);
- subdevice = bitrev8((data->sony_bits >> 0) & 0xFF);
- function = bitrev8((data->sony_bits >> 12) & 0xFE);
+ device = bitrev8((data->bits >> 5) & 0xF8);
+ subdevice = bitrev8((data->bits >> 0) & 0xFF);
+ function = bitrev8((data->bits >> 12) & 0xFE);
break;
default:
IR_dprintk(1, "Sony invalid bitcount %u\n", data->count);
@@ -229,7 +143,7 @@ static int ir_sony_decode(struct input_dev *input_dev, struct ir_raw_event ev)
scancode = device << 16 | subdevice << 8 | function;
IR_dprintk(1, "Sony(%u) scancode 0x%05x\n", data->count, scancode);
- ir_keydown(input_dev, scancode, 0);
+ rc_keydown(dev, scancode, 0);
data->state = STATE_INACTIVE;
return 0;
}
@@ -241,54 +155,9 @@ out:
return -EINVAL;
}
-static int ir_sony_register(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- struct decoder_data *data;
- int rc;
-
- rc = sysfs_create_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- if (rc < 0)
- return rc;
-
- data = kzalloc(sizeof(*data), GFP_KERNEL);
- if (!data) {
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
- return -ENOMEM;
- }
-
- data->ir_dev = ir_dev;
- data->enabled = 1;
-
- spin_lock(&decoder_lock);
- list_add_tail(&data->list, &decoder_list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
-static int ir_sony_unregister(struct input_dev *input_dev)
-{
- struct ir_input_dev *ir_dev = input_get_drvdata(input_dev);
- static struct decoder_data *data;
-
- data = get_decoder_data(ir_dev);
- if (!data)
- return 0;
-
- sysfs_remove_group(&ir_dev->dev.kobj, &decoder_attribute_group);
-
- spin_lock(&decoder_lock);
- list_del(&data->list);
- spin_unlock(&decoder_lock);
-
- return 0;
-}
-
static struct ir_raw_handler sony_handler = {
+ .protocols = RC_TYPE_SONY,
.decode = ir_sony_decode,
- .raw_register = ir_sony_register,
- .raw_unregister = ir_sony_unregister,
};
static int __init ir_sony_decode_init(void)
diff --git a/drivers/media/IR/keymaps/Kconfig b/drivers/media/rc/keymaps/Kconfig
index 14b22f58f823..8e615fd55852 100644
--- a/drivers/media/IR/keymaps/Kconfig
+++ b/drivers/media/rc/keymaps/Kconfig
@@ -1,6 +1,6 @@
config RC_MAP
tristate "Compile Remote Controller keymap modules"
- depends on IR_CORE
+ depends on RC_CORE
default y
---help---
diff --git a/drivers/media/IR/keymaps/Makefile b/drivers/media/rc/keymaps/Makefile
index ec25258a955f..0659e9f50144 100644
--- a/drivers/media/IR/keymaps/Makefile
+++ b/drivers/media/rc/keymaps/Makefile
@@ -1,4 +1,6 @@
obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
+ rc-alink-dtu-m.o \
+ rc-anysee.o \
rc-apac-viewcomp.o \
rc-asus-pc39.o \
rc-ati-tv-wonder-hd-600.o \
@@ -6,17 +8,23 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-avermedia.o \
rc-avermedia-cardbus.o \
rc-avermedia-dvbt.o \
- rc-avermedia-m135a-rm-jx.o \
+ rc-avermedia-m135a.o \
+ rc-avermedia-m733a-rm-k6.o \
+ rc-avermedia-rm-ks.o \
rc-avertv-303.o \
+ rc-azurewave-ad-tu700.o \
rc-behold.o \
rc-behold-columbus.o \
rc-budget-ci-old.o \
rc-cinergy-1400.o \
rc-cinergy.o \
+ rc-dib0700-nec.o \
+ rc-dib0700-rc5.o \
+ rc-digitalnow-tinytwin.o \
+ rc-digittrade.o \
rc-dm1105-nec.o \
rc-dntv-live-dvb-t.o \
rc-dntv-live-dvbt-pro.o \
- rc-empty.o \
rc-em-terratec.o \
rc-encore-enltv2.o \
rc-encore-enltv.o \
@@ -36,7 +44,12 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-kaiomy.o \
rc-kworld-315u.o \
rc-kworld-plus-tv-analog.o \
+ rc-leadtek-y04g0051.o \
+ rc-lirc.o \
+ rc-lme2510.o \
rc-manli.o \
+ rc-msi-digivox-ii.o \
+ rc-msi-digivox-iii.o \
rc-msi-tvanywhere.o \
rc-msi-tvanywhere-plus.o \
rc-nebula.o \
@@ -49,6 +62,7 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-pinnacle-pctv-hd.o \
rc-pixelview.o \
rc-pixelview-mk12.o \
+ rc-pixelview-002t.o \
rc-pixelview-new.o \
rc-powercolor-real-angel.o \
rc-proteus-2309.o \
@@ -56,11 +70,18 @@ obj-$(CONFIG_RC_MAP) += rc-adstech-dvb-t-pci.o \
rc-pv951.o \
rc-rc5-hauppauge-new.o \
rc-rc5-tv.o \
+ rc-rc6-mce.o \
rc-real-audio-220-32-keys.o \
+ rc-streamzap.o \
rc-tbs-nec.o \
rc-terratec-cinergy-xs.o \
+ rc-terratec-slim.o \
rc-tevii-nec.o \
+ rc-total-media-in-hand.o \
+ rc-trekstor.o \
rc-tt-1500.o \
+ rc-twinhan1027.o \
+ rc-videomate-m1f.o \
rc-videomate-s350.o \
rc-videomate-tv-pvr.o \
rc-winfast.o \
diff --git a/drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
index b17283176ecd..136d3952dedc 100644
--- a/drivers/media/IR/keymaps/rc-adstech-dvb-t-pci.c
+++ b/drivers/media/rc/keymaps/rc-adstech-dvb-t-pci.c
@@ -14,7 +14,7 @@
/* ADS Tech Instant TV DVB-T PCI Remote */
-static struct ir_scancode adstech_dvb_t_pci[] = {
+static struct rc_map_table adstech_dvb_t_pci[] = {
/* Keys 0 to 9 */
{ 0x4d, KEY_0 },
{ 0x57, KEY_1 },
@@ -63,23 +63,23 @@ static struct ir_scancode adstech_dvb_t_pci[] = {
{ 0x1c, KEY_VOLUMEDOWN },
};
-static struct rc_keymap adstech_dvb_t_pci_map = {
+static struct rc_map_list adstech_dvb_t_pci_map = {
.map = {
.scan = adstech_dvb_t_pci,
.size = ARRAY_SIZE(adstech_dvb_t_pci),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ADSTECH_DVB_T_PCI,
}
};
static int __init init_rc_map_adstech_dvb_t_pci(void)
{
- return ir_register_map(&adstech_dvb_t_pci_map);
+ return rc_map_register(&adstech_dvb_t_pci_map);
}
static void __exit exit_rc_map_adstech_dvb_t_pci(void)
{
- ir_unregister_map(&adstech_dvb_t_pci_map);
+ rc_map_unregister(&adstech_dvb_t_pci_map);
}
module_init(init_rc_map_adstech_dvb_t_pci)
diff --git a/drivers/media/rc/keymaps/rc-alink-dtu-m.c b/drivers/media/rc/keymaps/rc-alink-dtu-m.c
new file mode 100644
index 000000000000..fe652e928dc0
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-alink-dtu-m.c
@@ -0,0 +1,68 @@
+/*
+ * A-Link DTU(m) remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* A-Link DTU(m) slim remote, 6 rows, 3 columns. */
+static struct rc_map_table alink_dtu_m[] = {
+ { 0x0800, KEY_VOLUMEUP },
+ { 0x0801, KEY_1 },
+ { 0x0802, KEY_3 },
+ { 0x0803, KEY_7 },
+ { 0x0804, KEY_9 },
+ { 0x0805, KEY_NEW }, /* symbol: PIP */
+ { 0x0806, KEY_0 },
+ { 0x0807, KEY_CHANNEL }, /* JUMP */
+ { 0x080d, KEY_5 },
+ { 0x080f, KEY_2 },
+ { 0x0812, KEY_POWER2 },
+ { 0x0814, KEY_CHANNELUP },
+ { 0x0816, KEY_VOLUMEDOWN },
+ { 0x0818, KEY_6 },
+ { 0x081a, KEY_MUTE },
+ { 0x081b, KEY_8 },
+ { 0x081c, KEY_4 },
+ { 0x081d, KEY_CHANNELDOWN },
+};
+
+static struct rc_map_list alink_dtu_m_map = {
+ .map = {
+ .scan = alink_dtu_m,
+ .size = ARRAY_SIZE(alink_dtu_m),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_ALINK_DTU_M,
+ }
+};
+
+static int __init init_rc_map_alink_dtu_m(void)
+{
+ return rc_map_register(&alink_dtu_m_map);
+}
+
+static void __exit exit_rc_map_alink_dtu_m(void)
+{
+ rc_map_unregister(&alink_dtu_m_map);
+}
+
+module_init(init_rc_map_alink_dtu_m)
+module_exit(exit_rc_map_alink_dtu_m)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-anysee.c b/drivers/media/rc/keymaps/rc-anysee.c
new file mode 100644
index 000000000000..884f1b51a8ee
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-anysee.c
@@ -0,0 +1,93 @@
+/*
+ * Anysee remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table anysee[] = {
+ { 0x0800, KEY_0 },
+ { 0x0801, KEY_1 },
+ { 0x0802, KEY_2 },
+ { 0x0803, KEY_3 },
+ { 0x0804, KEY_4 },
+ { 0x0805, KEY_5 },
+ { 0x0806, KEY_6 },
+ { 0x0807, KEY_7 },
+ { 0x0808, KEY_8 },
+ { 0x0809, KEY_9 },
+ { 0x080a, KEY_POWER2 }, /* [red power button] */
+ { 0x080b, KEY_VIDEO }, /* [*] MODE */
+ { 0x080c, KEY_CHANNEL }, /* [symbol counterclockwise arrow] */
+ { 0x080d, KEY_NEXT }, /* [>>|] */
+ { 0x080e, KEY_MENU }, /* MENU */
+ { 0x080f, KEY_EPG }, /* [EPG] */
+ { 0x0810, KEY_CLEAR }, /* EXIT */
+ { 0x0811, KEY_CHANNELUP },
+ { 0x0812, KEY_VOLUMEDOWN },
+ { 0x0813, KEY_VOLUMEUP },
+ { 0x0814, KEY_CHANNELDOWN },
+ { 0x0815, KEY_OK },
+ { 0x0816, KEY_RADIO }, /* [symbol TV/radio] */
+ { 0x0817, KEY_INFO }, /* [i] */
+ { 0x0818, KEY_PREVIOUS }, /* [|<<] */
+ { 0x0819, KEY_FAVORITES }, /* FAV. */
+ { 0x081a, KEY_SUBTITLE }, /* Subtitle */
+ { 0x081b, KEY_CAMERA }, /* [symbol camera] */
+ { 0x081c, KEY_YELLOW },
+ { 0x081d, KEY_RED },
+ { 0x081e, KEY_LANGUAGE }, /* [symbol Second Audio Program] */
+ { 0x081f, KEY_GREEN },
+ { 0x0820, KEY_SLEEP }, /* Sleep */
+ { 0x0821, KEY_SCREEN }, /* 16:9 / 4:3 */
+ { 0x0822, KEY_ZOOM }, /* SIZE */
+ { 0x0824, KEY_FN }, /* [F1] */
+ { 0x0825, KEY_FN }, /* [F2] */
+ { 0x0842, KEY_MUTE }, /* symbol mute */
+ { 0x0844, KEY_BLUE },
+ { 0x0847, KEY_TEXT }, /* TEXT */
+ { 0x0848, KEY_STOP },
+ { 0x0849, KEY_RECORD },
+ { 0x0850, KEY_PLAY },
+ { 0x0851, KEY_PAUSE },
+};
+
+static struct rc_map_list anysee_map = {
+ .map = {
+ .scan = anysee,
+ .size = ARRAY_SIZE(anysee),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_ANYSEE,
+ }
+};
+
+static int __init init_rc_map_anysee(void)
+{
+ return rc_map_register(&anysee_map);
+}
+
+static void __exit exit_rc_map_anysee(void)
+{
+ rc_map_unregister(&anysee_map);
+}
+
+module_init(init_rc_map_anysee)
+module_exit(exit_rc_map_anysee)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-apac-viewcomp.c b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
index 0ef2b562baf0..7af188209ff9 100644
--- a/drivers/media/IR/keymaps/rc-apac-viewcomp.c
+++ b/drivers/media/rc/keymaps/rc-apac-viewcomp.c
@@ -14,7 +14,7 @@
/* Attila Kondoros <attila.kondoros@chello.hu> */
-static struct ir_scancode apac_viewcomp[] = {
+static struct rc_map_table apac_viewcomp[] = {
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -54,23 +54,23 @@ static struct ir_scancode apac_viewcomp[] = {
{ 0x18, KEY_KPMINUS }, /* fine tune <<<< */
};
-static struct rc_keymap apac_viewcomp_map = {
+static struct rc_map_list apac_viewcomp_map = {
.map = {
.scan = apac_viewcomp,
.size = ARRAY_SIZE(apac_viewcomp),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_APAC_VIEWCOMP,
}
};
static int __init init_rc_map_apac_viewcomp(void)
{
- return ir_register_map(&apac_viewcomp_map);
+ return rc_map_register(&apac_viewcomp_map);
}
static void __exit exit_rc_map_apac_viewcomp(void)
{
- ir_unregister_map(&apac_viewcomp_map);
+ rc_map_unregister(&apac_viewcomp_map);
}
module_init(init_rc_map_apac_viewcomp)
diff --git a/drivers/media/rc/keymaps/rc-asus-pc39.c b/drivers/media/rc/keymaps/rc-asus-pc39.c
new file mode 100644
index 000000000000..b2481154491b
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-asus-pc39.c
@@ -0,0 +1,91 @@
+/* asus-pc39.h - Keytable for asus_pc39 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Marc Fargas <telenieko@telenieko.com>
+ * this is the remote control that comes with the asus p7131
+ * which has a label saying is "Model PC-39"
+ */
+
+static struct rc_map_table asus_pc39[] = {
+ /* Keys 0 to 9 */
+ { 0x082a, KEY_0 },
+ { 0x0816, KEY_1 },
+ { 0x0812, KEY_2 },
+ { 0x0814, KEY_3 },
+ { 0x0836, KEY_4 },
+ { 0x0832, KEY_5 },
+ { 0x0834, KEY_6 },
+ { 0x080e, KEY_7 },
+ { 0x080a, KEY_8 },
+ { 0x080c, KEY_9 },
+
+ { 0x0801, KEY_RADIO }, /* radio */
+ { 0x083c, KEY_MENU }, /* dvd/menu */
+ { 0x0815, KEY_VOLUMEUP },
+ { 0x0826, KEY_VOLUMEDOWN },
+ { 0x0808, KEY_UP },
+ { 0x0804, KEY_DOWN },
+ { 0x0818, KEY_LEFT },
+ { 0x0810, KEY_RIGHT },
+ { 0x081a, KEY_VIDEO }, /* video */
+ { 0x0806, KEY_AUDIO }, /* music */
+
+ { 0x081e, KEY_TV }, /* tv */
+ { 0x0822, KEY_EXIT }, /* back */
+ { 0x0835, KEY_CHANNELUP }, /* channel / program + */
+ { 0x0824, KEY_CHANNELDOWN }, /* channel / program - */
+ { 0x0825, KEY_ENTER }, /* enter */
+
+ { 0x0839, KEY_PAUSE }, /* play/pause */
+ { 0x0821, KEY_PREVIOUS }, /* rew */
+ { 0x0819, KEY_NEXT }, /* forward */
+ { 0x0831, KEY_REWIND }, /* backward << */
+ { 0x0805, KEY_FASTFORWARD }, /* forward >> */
+ { 0x0809, KEY_STOP },
+ { 0x0811, KEY_RECORD }, /* recording */
+ { 0x0829, KEY_POWER }, /* the button that reads "close" */
+
+ { 0x082e, KEY_ZOOM }, /* full screen */
+ { 0x082c, KEY_MACRO }, /* recall */
+ { 0x081c, KEY_HOME }, /* home */
+ { 0x083a, KEY_PVR }, /* picture */
+ { 0x0802, KEY_MUTE }, /* mute */
+ { 0x083e, KEY_DVD }, /* dvd */
+};
+
+static struct rc_map_list asus_pc39_map = {
+ .map = {
+ .scan = asus_pc39,
+ .size = ARRAY_SIZE(asus_pc39),
+ .rc_type = RC_TYPE_RC5,
+ .name = RC_MAP_ASUS_PC39,
+ }
+};
+
+static int __init init_rc_map_asus_pc39(void)
+{
+ return rc_map_register(&asus_pc39_map);
+}
+
+static void __exit exit_rc_map_asus_pc39(void)
+{
+ rc_map_unregister(&asus_pc39_map);
+}
+
+module_init(init_rc_map_asus_pc39)
+module_exit(exit_rc_map_asus_pc39)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
index 8edfd293d010..f766b24b0158 100644
--- a/drivers/media/IR/keymaps/rc-ati-tv-wonder-hd-600.c
+++ b/drivers/media/rc/keymaps/rc-ati-tv-wonder-hd-600.c
@@ -16,7 +16,7 @@
Devin Heitmueller <devin.heitmueller@gmail.com>
*/
-static struct ir_scancode ati_tv_wonder_hd_600[] = {
+static struct rc_map_table ati_tv_wonder_hd_600[] = {
{ 0x00, KEY_RECORD}, /* Row 1 */
{ 0x01, KEY_PLAYPAUSE},
{ 0x02, KEY_STOP},
@@ -43,23 +43,23 @@ static struct ir_scancode ati_tv_wonder_hd_600[] = {
{ 0x17, KEY_VOLUMEDOWN},
};
-static struct rc_keymap ati_tv_wonder_hd_600_map = {
+static struct rc_map_list ati_tv_wonder_hd_600_map = {
.map = {
.scan = ati_tv_wonder_hd_600,
.size = ARRAY_SIZE(ati_tv_wonder_hd_600),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ATI_TV_WONDER_HD_600,
}
};
static int __init init_rc_map_ati_tv_wonder_hd_600(void)
{
- return ir_register_map(&ati_tv_wonder_hd_600_map);
+ return rc_map_register(&ati_tv_wonder_hd_600_map);
}
static void __exit exit_rc_map_ati_tv_wonder_hd_600(void)
{
- ir_unregister_map(&ati_tv_wonder_hd_600_map);
+ rc_map_unregister(&ati_tv_wonder_hd_600_map);
}
module_init(init_rc_map_ati_tv_wonder_hd_600)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-a16d.c b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
index 12f043587f2e..ec9beeebd410 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-a16d.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-a16d.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode avermedia_a16d[] = {
+static struct rc_map_table avermedia_a16d[] = {
{ 0x20, KEY_LIST},
{ 0x00, KEY_POWER},
{ 0x28, KEY_1},
@@ -49,23 +49,23 @@ static struct ir_scancode avermedia_a16d[] = {
{ 0x2a, KEY_MENU},
};
-static struct rc_keymap avermedia_a16d_map = {
+static struct rc_map_list avermedia_a16d_map = {
.map = {
.scan = avermedia_a16d,
.size = ARRAY_SIZE(avermedia_a16d),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERMEDIA_A16D,
}
};
static int __init init_rc_map_avermedia_a16d(void)
{
- return ir_register_map(&avermedia_a16d_map);
+ return rc_map_register(&avermedia_a16d_map);
}
static void __exit exit_rc_map_avermedia_a16d(void)
{
- ir_unregister_map(&avermedia_a16d_map);
+ rc_map_unregister(&avermedia_a16d_map);
}
module_init(init_rc_map_avermedia_a16d)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-cardbus.c b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
index 2a945b02e8ca..bdf97b74cf90 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-cardbus.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-cardbus.c
@@ -14,7 +14,7 @@
/* Oldrich Jedlicka <oldium.pro@seznam.cz> */
-static struct ir_scancode avermedia_cardbus[] = {
+static struct rc_map_table avermedia_cardbus[] = {
{ 0x00, KEY_POWER },
{ 0x01, KEY_TUNER }, /* TV/FM */
{ 0x03, KEY_TEXT }, /* Teletext */
@@ -71,23 +71,23 @@ static struct ir_scancode avermedia_cardbus[] = {
{ 0x43, KEY_CHANNELUP }, /* Channel up */
};
-static struct rc_keymap avermedia_cardbus_map = {
+static struct rc_map_list avermedia_cardbus_map = {
.map = {
.scan = avermedia_cardbus,
.size = ARRAY_SIZE(avermedia_cardbus),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERMEDIA_CARDBUS,
}
};
static int __init init_rc_map_avermedia_cardbus(void)
{
- return ir_register_map(&avermedia_cardbus_map);
+ return rc_map_register(&avermedia_cardbus_map);
}
static void __exit exit_rc_map_avermedia_cardbus(void)
{
- ir_unregister_map(&avermedia_cardbus_map);
+ rc_map_unregister(&avermedia_cardbus_map);
}
module_init(init_rc_map_avermedia_cardbus)
diff --git a/drivers/media/IR/keymaps/rc-avermedia-dvbt.c b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
index 39dde6222875..3ddb41bc075e 100644
--- a/drivers/media/IR/keymaps/rc-avermedia-dvbt.c
+++ b/drivers/media/rc/keymaps/rc-avermedia-dvbt.c
@@ -14,7 +14,7 @@
/* Matt Jesson <dvb@jesson.eclipse.co.uk */
-static struct ir_scancode avermedia_dvbt[] = {
+static struct rc_map_table avermedia_dvbt[] = {
{ 0x28, KEY_0 }, /* '0' / 'enter' */
{ 0x22, KEY_1 }, /* '1' */
{ 0x12, KEY_2 }, /* '2' / 'up arrow' */
@@ -52,23 +52,23 @@ static struct ir_scancode avermedia_dvbt[] = {
{ 0x3e, KEY_VOLUMEUP }, /* 'volume +' */
};
-static struct rc_keymap avermedia_dvbt_map = {
+static struct rc_map_list avermedia_dvbt_map = {
.map = {
.scan = avermedia_dvbt,
.size = ARRAY_SIZE(avermedia_dvbt),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERMEDIA_DVBT,
}
};
static int __init init_rc_map_avermedia_dvbt(void)
{
- return ir_register_map(&avermedia_dvbt_map);
+ return rc_map_register(&avermedia_dvbt_map);
}
static void __exit exit_rc_map_avermedia_dvbt(void)
{
- ir_unregister_map(&avermedia_dvbt_map);
+ rc_map_unregister(&avermedia_dvbt_map);
}
module_init(init_rc_map_avermedia_dvbt)
diff --git a/drivers/media/rc/keymaps/rc-avermedia-m135a.c b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
new file mode 100644
index 000000000000..357fea58a46e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-m135a.c
@@ -0,0 +1,147 @@
+/* avermedia-m135a.c - Keytable for Avermedia M135A Remote Controllers
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Avermedia M135A with RM-JX and RM-K6 remote controls
+ *
+ * On Avermedia M135A with IR model RM-JX, the same codes exist on both
+ * Positivo (BR) and original IR, initial version and remote control codes
+ * added by Mauro Carvalho Chehab <mchehab@infradead.org>
+ *
+ * Positivo also ships Avermedia M135A with model RM-K6, extra control
+ * codes added by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ */
+
+static struct rc_map_table avermedia_m135a[] = {
+ /* RM-JX */
+ { 0x0200, KEY_POWER2 },
+ { 0x022e, KEY_DOT }, /* '.' */
+ { 0x0201, KEY_MODE }, /* TV/FM or SOURCE */
+
+ { 0x0205, KEY_1 },
+ { 0x0206, KEY_2 },
+ { 0x0207, KEY_3 },
+ { 0x0209, KEY_4 },
+ { 0x020a, KEY_5 },
+ { 0x020b, KEY_6 },
+ { 0x020d, KEY_7 },
+ { 0x020e, KEY_8 },
+ { 0x020f, KEY_9 },
+ { 0x0211, KEY_0 },
+
+ { 0x0213, KEY_RIGHT }, /* -> or L */
+ { 0x0212, KEY_LEFT }, /* <- or R */
+
+ { 0x0217, KEY_SLEEP }, /* Capturar Imagem or Snapshot */
+ { 0x0210, KEY_SHUFFLE }, /* Amostra or 16 chan prev */
+
+ { 0x0303, KEY_CHANNELUP },
+ { 0x0302, KEY_CHANNELDOWN },
+ { 0x021f, KEY_VOLUMEUP },
+ { 0x021e, KEY_VOLUMEDOWN },
+ { 0x020c, KEY_ENTER }, /* Full Screen */
+
+ { 0x0214, KEY_MUTE },
+ { 0x0208, KEY_AUDIO },
+
+ { 0x0203, KEY_TEXT }, /* Teletext */
+ { 0x0204, KEY_EPG },
+ { 0x022b, KEY_TV2 }, /* TV2 or PIP */
+
+ { 0x021d, KEY_RED },
+ { 0x021c, KEY_YELLOW },
+ { 0x0301, KEY_GREEN },
+ { 0x0300, KEY_BLUE },
+
+ { 0x021a, KEY_PLAYPAUSE },
+ { 0x0219, KEY_RECORD },
+ { 0x0218, KEY_PLAY },
+ { 0x021b, KEY_STOP },
+
+ /* RM-K6 */
+ { 0x0401, KEY_POWER2 },
+ { 0x0406, KEY_MUTE },
+ { 0x0408, KEY_MODE }, /* TV/FM */
+
+ { 0x0409, KEY_1 },
+ { 0x040a, KEY_2 },
+ { 0x040b, KEY_3 },
+ { 0x040c, KEY_4 },
+ { 0x040d, KEY_5 },
+ { 0x040e, KEY_6 },
+ { 0x040f, KEY_7 },
+ { 0x0410, KEY_8 },
+ { 0x0411, KEY_9 },
+ { 0x044c, KEY_DOT }, /* '.' */
+ { 0x0412, KEY_0 },
+ { 0x0407, KEY_REFRESH }, /* Refresh/Reload */
+
+ { 0x0413, KEY_AUDIO },
+ { 0x0440, KEY_SCREEN }, /* Full Screen toggle */
+ { 0x0441, KEY_HOME },
+ { 0x0442, KEY_BACK },
+ { 0x0447, KEY_UP },
+ { 0x0448, KEY_DOWN },
+ { 0x0449, KEY_LEFT },
+ { 0x044a, KEY_RIGHT },
+ { 0x044b, KEY_OK },
+ { 0x0404, KEY_VOLUMEUP },
+ { 0x0405, KEY_VOLUMEDOWN },
+ { 0x0402, KEY_CHANNELUP },
+ { 0x0403, KEY_CHANNELDOWN },
+
+ { 0x0443, KEY_RED },
+ { 0x0444, KEY_GREEN },
+ { 0x0445, KEY_YELLOW },
+ { 0x0446, KEY_BLUE },
+
+ { 0x0414, KEY_TEXT },
+ { 0x0415, KEY_EPG },
+ { 0x041a, KEY_TV2 }, /* PIP */
+ { 0x041b, KEY_MHP }, /* Snapshot */
+
+ { 0x0417, KEY_RECORD },
+ { 0x0416, KEY_PLAYPAUSE },
+ { 0x0418, KEY_STOP },
+ { 0x0419, KEY_PAUSE },
+
+ { 0x041f, KEY_PREVIOUS },
+ { 0x041c, KEY_REWIND },
+ { 0x041d, KEY_FORWARD },
+ { 0x041e, KEY_NEXT },
+};
+
+static struct rc_map_list avermedia_m135a_map = {
+ .map = {
+ .scan = avermedia_m135a,
+ .size = ARRAY_SIZE(avermedia_m135a),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_AVERMEDIA_M135A,
+ }
+};
+
+static int __init init_rc_map_avermedia_m135a(void)
+{
+ return rc_map_register(&avermedia_m135a_map);
+}
+
+static void __exit exit_rc_map_avermedia_m135a(void)
+{
+ rc_map_unregister(&avermedia_m135a_map);
+}
+
+module_init(init_rc_map_avermedia_m135a)
+module_exit(exit_rc_map_avermedia_m135a)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
new file mode 100644
index 000000000000..e694e6eac37e
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-m733a-rm-k6.c
@@ -0,0 +1,95 @@
+/* avermedia-m733a-rm-k6.h - Keytable for avermedia_m733a_rm_k6 Remote Controller
+ *
+ * Copyright (c) 2010 by Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Avermedia M733A with IR model RM-K6
+ * This is the stock remote controller used with Positivo machines with M733A
+ * Herton Ronaldo Krzesinski <herton@mandriva.com.br>
+ */
+
+static struct rc_map_table avermedia_m733a_rm_k6[] = {
+ { 0x0401, KEY_POWER2 },
+ { 0x0406, KEY_MUTE },
+ { 0x0408, KEY_MODE }, /* TV/FM */
+
+ { 0x0409, KEY_1 },
+ { 0x040a, KEY_2 },
+ { 0x040b, KEY_3 },
+ { 0x040c, KEY_4 },
+ { 0x040d, KEY_5 },
+ { 0x040e, KEY_6 },
+ { 0x040f, KEY_7 },
+ { 0x0410, KEY_8 },
+ { 0x0411, KEY_9 },
+ { 0x044c, KEY_DOT }, /* '.' */
+ { 0x0412, KEY_0 },
+ { 0x0407, KEY_REFRESH }, /* Refresh/Reload */
+
+ { 0x0413, KEY_AUDIO },
+ { 0x0440, KEY_SCREEN }, /* Full Screen toggle */
+ { 0x0441, KEY_HOME },
+ { 0x0442, KEY_BACK },
+ { 0x0447, KEY_UP },
+ { 0x0448, KEY_DOWN },
+ { 0x0449, KEY_LEFT },
+ { 0x044a, KEY_RIGHT },
+ { 0x044b, KEY_OK },
+ { 0x0404, KEY_VOLUMEUP },
+ { 0x0405, KEY_VOLUMEDOWN },
+ { 0x0402, KEY_CHANNELUP },
+ { 0x0403, KEY_CHANNELDOWN },
+
+ { 0x0443, KEY_RED },
+ { 0x0444, KEY_GREEN },
+ { 0x0445, KEY_YELLOW },
+ { 0x0446, KEY_BLUE },
+
+ { 0x0414, KEY_TEXT },
+ { 0x0415, KEY_EPG },
+ { 0x041a, KEY_TV2 }, /* PIP */
+ { 0x041b, KEY_MHP }, /* Snapshot */
+
+ { 0x0417, KEY_RECORD },
+ { 0x0416, KEY_PLAYPAUSE },
+ { 0x0418, KEY_STOP },
+ { 0x0419, KEY_PAUSE },
+
+ { 0x041f, KEY_PREVIOUS },
+ { 0x041c, KEY_REWIND },
+ { 0x041d, KEY_FORWARD },
+ { 0x041e, KEY_NEXT },
+};
+
+static struct rc_map_list avermedia_m733a_rm_k6_map = {
+ .map = {
+ .scan = avermedia_m733a_rm_k6,
+ .size = ARRAY_SIZE(avermedia_m733a_rm_k6),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_AVERMEDIA_M733A_RM_K6,
+ }
+};
+
+static int __init init_rc_map_avermedia_m733a_rm_k6(void)
+{
+ return rc_map_register(&avermedia_m733a_rm_k6_map);
+}
+
+static void __exit exit_rc_map_avermedia_m733a_rm_k6(void)
+{
+ rc_map_unregister(&avermedia_m733a_rm_k6_map);
+}
+
+module_init(init_rc_map_avermedia_m733a_rm_k6)
+module_exit(exit_rc_map_avermedia_m733a_rm_k6)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
new file mode 100644
index 000000000000..f4ca1fff455d
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-avermedia-rm-ks.c
@@ -0,0 +1,79 @@
+/*
+ * AverMedia RM-KS remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* Initial keytable is from Jose Alberto Reguero <jareguero@telefonica.net>
+ and Felipe Morales Moreno <felipe.morales.moreno@gmail.com> */
+/* FIXME: mappings are not 100% correct? */
+static struct rc_map_table avermedia_rm_ks[] = {
+ { 0x0501, KEY_POWER2 },
+ { 0x0502, KEY_CHANNELUP },
+ { 0x0503, KEY_CHANNELDOWN },
+ { 0x0504, KEY_VOLUMEUP },
+ { 0x0505, KEY_VOLUMEDOWN },
+ { 0x0506, KEY_MUTE },
+ { 0x0507, KEY_RIGHT },
+ { 0x0508, KEY_PROG1 },
+ { 0x0509, KEY_1 },
+ { 0x050a, KEY_2 },
+ { 0x050b, KEY_3 },
+ { 0x050c, KEY_4 },
+ { 0x050d, KEY_5 },
+ { 0x050e, KEY_6 },
+ { 0x050f, KEY_7 },
+ { 0x0510, KEY_8 },
+ { 0x0511, KEY_9 },
+ { 0x0512, KEY_0 },
+ { 0x0513, KEY_AUDIO },
+ { 0x0515, KEY_EPG },
+ { 0x0516, KEY_PLAY },
+ { 0x0517, KEY_RECORD },
+ { 0x0518, KEY_STOP },
+ { 0x051c, KEY_BACK },
+ { 0x051d, KEY_FORWARD },
+ { 0x054d, KEY_LEFT },
+ { 0x0556, KEY_ZOOM },
+};
+
+static struct rc_map_list avermedia_rm_ks_map = {
+ .map = {
+ .scan = avermedia_rm_ks,
+ .size = ARRAY_SIZE(avermedia_rm_ks),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_AVERMEDIA_RM_KS,
+ }
+};
+
+static int __init init_rc_map_avermedia_rm_ks(void)
+{
+ return rc_map_register(&avermedia_rm_ks_map);
+}
+
+static void __exit exit_rc_map_avermedia_rm_ks(void)
+{
+ rc_map_unregister(&avermedia_rm_ks_map);
+}
+
+module_init(init_rc_map_avermedia_rm_ks)
+module_exit(exit_rc_map_avermedia_rm_ks)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-avermedia.c b/drivers/media/rc/keymaps/rc-avermedia.c
index 21effd5bfb0d..edfa71506d3e 100644
--- a/drivers/media/IR/keymaps/rc-avermedia.c
+++ b/drivers/media/rc/keymaps/rc-avermedia.c
@@ -14,7 +14,7 @@
/* Alex Hermann <gaaf@gmx.net> */
-static struct ir_scancode avermedia[] = {
+static struct rc_map_table avermedia[] = {
{ 0x28, KEY_1 },
{ 0x18, KEY_2 },
{ 0x38, KEY_3 },
@@ -60,23 +60,23 @@ static struct ir_scancode avermedia[] = {
{ 0x31, KEY_CHANNELUP } /* CHANNEL/PAGE+ */
};
-static struct rc_keymap avermedia_map = {
+static struct rc_map_list avermedia_map = {
.map = {
.scan = avermedia,
.size = ARRAY_SIZE(avermedia),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERMEDIA,
}
};
static int __init init_rc_map_avermedia(void)
{
- return ir_register_map(&avermedia_map);
+ return rc_map_register(&avermedia_map);
}
static void __exit exit_rc_map_avermedia(void)
{
- ir_unregister_map(&avermedia_map);
+ rc_map_unregister(&avermedia_map);
}
module_init(init_rc_map_avermedia)
diff --git a/drivers/media/IR/keymaps/rc-avertv-303.c b/drivers/media/rc/keymaps/rc-avertv-303.c
index 971c59d6f9d6..32e94988dc94 100644
--- a/drivers/media/IR/keymaps/rc-avertv-303.c
+++ b/drivers/media/rc/keymaps/rc-avertv-303.c
@@ -14,7 +14,7 @@
/* AVERTV STUDIO 303 Remote */
-static struct ir_scancode avertv_303[] = {
+static struct rc_map_table avertv_303[] = {
{ 0x2a, KEY_1 },
{ 0x32, KEY_2 },
{ 0x3a, KEY_3 },
@@ -59,23 +59,23 @@ static struct ir_scancode avertv_303[] = {
{ 0x1b, KEY_UP },
};
-static struct rc_keymap avertv_303_map = {
+static struct rc_map_list avertv_303_map = {
.map = {
.scan = avertv_303,
.size = ARRAY_SIZE(avertv_303),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_AVERTV_303,
}
};
static int __init init_rc_map_avertv_303(void)
{
- return ir_register_map(&avertv_303_map);
+ return rc_map_register(&avertv_303_map);
}
static void __exit exit_rc_map_avertv_303(void)
{
- ir_unregister_map(&avertv_303_map);
+ rc_map_unregister(&avertv_303_map);
}
module_init(init_rc_map_avertv_303)
diff --git a/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
new file mode 100644
index 000000000000..c3f6d62ac892
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-azurewave-ad-tu700.c
@@ -0,0 +1,102 @@
+/*
+ * TwinHan AzureWave AD-TU700(704J) remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table azurewave_ad_tu700[] = {
+ { 0x0000, KEY_TAB }, /* Tab */
+ { 0x0001, KEY_2 },
+ { 0x0002, KEY_CHANNELDOWN },
+ { 0x0003, KEY_1 },
+ { 0x0004, KEY_MENU }, /* Record List */
+ { 0x0005, KEY_CHANNELUP },
+ { 0x0006, KEY_3 },
+ { 0x0007, KEY_SLEEP }, /* Hibernate */
+ { 0x0008, KEY_VIDEO }, /* A/V */
+ { 0x0009, KEY_4 },
+ { 0x000a, KEY_VOLUMEDOWN },
+ { 0x000c, KEY_CANCEL }, /* Cancel */
+ { 0x000d, KEY_7 },
+ { 0x000e, KEY_AGAIN }, /* Recall */
+ { 0x000f, KEY_TEXT }, /* Teletext */
+ { 0x0010, KEY_MUTE },
+ { 0x0011, KEY_RECORD },
+ { 0x0012, KEY_FASTFORWARD }, /* FF >> */
+ { 0x0013, KEY_BACK }, /* Back */
+ { 0x0014, KEY_PLAY },
+ { 0x0015, KEY_0 },
+ { 0x0016, KEY_POWER2 }, /* [red power button] */
+ { 0x0017, KEY_FAVORITES }, /* Favorite List */
+ { 0x0018, KEY_RED },
+ { 0x0019, KEY_8 },
+ { 0x001a, KEY_STOP },
+ { 0x001b, KEY_9 },
+ { 0x001c, KEY_EPG }, /* Info/EPG */
+ { 0x001d, KEY_5 },
+ { 0x001e, KEY_VOLUMEUP },
+ { 0x001f, KEY_6 },
+ { 0x0040, KEY_REWIND }, /* FR << */
+ { 0x0041, KEY_PREVIOUS }, /* Replay */
+ { 0x0042, KEY_NEXT }, /* Skip */
+ { 0x0043, KEY_SUBTITLE }, /* Subtitle / CC */
+ { 0x0045, KEY_KPPLUS }, /* Zoom+ */
+ { 0x0046, KEY_KPMINUS }, /* Zoom- */
+ { 0x0047, KEY_NEW }, /* PIP */
+ { 0x0048, KEY_INFO }, /* Preview */
+ { 0x0049, KEY_MODE }, /* L/R */
+ { 0x004a, KEY_CLEAR }, /* Clear */
+ { 0x004b, KEY_UP }, /* up arrow */
+ { 0x004c, KEY_PAUSE },
+ { 0x004d, KEY_ZOOM }, /* Full Screen */
+ { 0x004e, KEY_LEFT }, /* left arrow */
+ { 0x004f, KEY_OK }, /* Enter / ok */
+ { 0x0050, KEY_LANGUAGE }, /* SAP */
+ { 0x0051, KEY_DOWN }, /* down arrow */
+ { 0x0052, KEY_RIGHT }, /* right arrow */
+ { 0x0053, KEY_GREEN },
+ { 0x0054, KEY_CAMERA }, /* Capture */
+ { 0x005e, KEY_YELLOW },
+ { 0x005f, KEY_BLUE },
+};
+
+static struct rc_map_list azurewave_ad_tu700_map = {
+ .map = {
+ .scan = azurewave_ad_tu700,
+ .size = ARRAY_SIZE(azurewave_ad_tu700),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_AZUREWAVE_AD_TU700,
+ }
+};
+
+static int __init init_rc_map_azurewave_ad_tu700(void)
+{
+ return rc_map_register(&azurewave_ad_tu700_map);
+}
+
+static void __exit exit_rc_map_azurewave_ad_tu700(void)
+{
+ rc_map_unregister(&azurewave_ad_tu700_map);
+}
+
+module_init(init_rc_map_azurewave_ad_tu700)
+module_exit(exit_rc_map_azurewave_ad_tu700)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-behold-columbus.c b/drivers/media/rc/keymaps/rc-behold-columbus.c
index 9f56c98fef5b..4b787fa94f08 100644
--- a/drivers/media/IR/keymaps/rc-behold-columbus.c
+++ b/drivers/media/rc/keymaps/rc-behold-columbus.c
@@ -21,7 +21,7 @@
* helps to descide which keycodes to assign to the buttons.
*/
-static struct ir_scancode behold_columbus[] = {
+static struct rc_map_table behold_columbus[] = {
/* 0x13 0x11 0x1C 0x12 *
* Mute Source TV/FM Power *
@@ -82,23 +82,23 @@ static struct ir_scancode behold_columbus[] = {
};
-static struct rc_keymap behold_columbus_map = {
+static struct rc_map_list behold_columbus_map = {
.map = {
.scan = behold_columbus,
.size = ARRAY_SIZE(behold_columbus),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_BEHOLD_COLUMBUS,
}
};
static int __init init_rc_map_behold_columbus(void)
{
- return ir_register_map(&behold_columbus_map);
+ return rc_map_register(&behold_columbus_map);
}
static void __exit exit_rc_map_behold_columbus(void)
{
- ir_unregister_map(&behold_columbus_map);
+ rc_map_unregister(&behold_columbus_map);
}
module_init(init_rc_map_behold_columbus)
diff --git a/drivers/media/IR/keymaps/rc-behold.c b/drivers/media/rc/keymaps/rc-behold.c
index abc140b2098b..0ee1f149364c 100644
--- a/drivers/media/IR/keymaps/rc-behold.c
+++ b/drivers/media/rc/keymaps/rc-behold.c
@@ -24,13 +24,13 @@
* helps to descide which keycodes to assign to the buttons.
*/
-static struct ir_scancode behold[] = {
+static struct rc_map_table behold[] = {
/* 0x1c 0x12 *
* TV/FM POWER *
* */
- { 0x1c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */
- { 0x12, KEY_POWER },
+ { 0x6b861c, KEY_TUNER }, /* XXX KEY_TV / KEY_RADIO */
+ { 0x6b8612, KEY_POWER },
/* 0x01 0x02 0x03 *
* 1 2 3 *
@@ -41,28 +41,28 @@ static struct ir_scancode behold[] = {
* 0x07 0x08 0x09 *
* 7 8 9 *
* */
- { 0x01, KEY_1 },
- { 0x02, KEY_2 },
- { 0x03, KEY_3 },
- { 0x04, KEY_4 },
- { 0x05, KEY_5 },
- { 0x06, KEY_6 },
- { 0x07, KEY_7 },
- { 0x08, KEY_8 },
- { 0x09, KEY_9 },
+ { 0x6b8601, KEY_1 },
+ { 0x6b8602, KEY_2 },
+ { 0x6b8603, KEY_3 },
+ { 0x6b8604, KEY_4 },
+ { 0x6b8605, KEY_5 },
+ { 0x6b8606, KEY_6 },
+ { 0x6b8607, KEY_7 },
+ { 0x6b8608, KEY_8 },
+ { 0x6b8609, KEY_9 },
/* 0x0a 0x00 0x17 *
* RECALL 0 MODE *
* */
- { 0x0a, KEY_AGAIN },
- { 0x00, KEY_0 },
- { 0x17, KEY_MODE },
+ { 0x6b860a, KEY_AGAIN },
+ { 0x6b8600, KEY_0 },
+ { 0x6b8617, KEY_MODE },
/* 0x14 0x10 *
* ASPECT FULLSCREEN *
* */
- { 0x14, KEY_SCREEN },
- { 0x10, KEY_ZOOM },
+ { 0x6b8614, KEY_SCREEN },
+ { 0x6b8610, KEY_ZOOM },
/* 0x0b *
* Up *
@@ -73,17 +73,17 @@ static struct ir_scancode behold[] = {
* 0x015 *
* Down *
* */
- { 0x0b, KEY_CHANNELUP },
- { 0x18, KEY_VOLUMEDOWN },
- { 0x16, KEY_OK }, /* XXX KEY_ENTER */
- { 0x0c, KEY_VOLUMEUP },
- { 0x15, KEY_CHANNELDOWN },
+ { 0x6b860b, KEY_CHANNELUP },
+ { 0x6b8618, KEY_VOLUMEDOWN },
+ { 0x6b8616, KEY_OK }, /* XXX KEY_ENTER */
+ { 0x6b860c, KEY_VOLUMEUP },
+ { 0x6b8615, KEY_CHANNELDOWN },
/* 0x11 0x0d *
* MUTE INFO *
* */
- { 0x11, KEY_MUTE },
- { 0x0d, KEY_INFO },
+ { 0x6b8611, KEY_MUTE },
+ { 0x6b860d, KEY_INFO },
/* 0x0f 0x1b 0x1a *
* RECORD PLAY/PAUSE STOP *
@@ -92,46 +92,46 @@ static struct ir_scancode behold[] = {
*TELETEXT AUDIO SOURCE *
* RED YELLOW *
* */
- { 0x0f, KEY_RECORD },
- { 0x1b, KEY_PLAYPAUSE },
- { 0x1a, KEY_STOP },
- { 0x0e, KEY_TEXT },
- { 0x1f, KEY_RED }, /*XXX KEY_AUDIO */
- { 0x1e, KEY_YELLOW }, /*XXX KEY_SOURCE */
+ { 0x6b860f, KEY_RECORD },
+ { 0x6b861b, KEY_PLAYPAUSE },
+ { 0x6b861a, KEY_STOP },
+ { 0x6b860e, KEY_TEXT },
+ { 0x6b861f, KEY_RED }, /*XXX KEY_AUDIO */
+ { 0x6b861e, KEY_YELLOW }, /*XXX KEY_SOURCE */
/* 0x1d 0x13 0x19 *
* SLEEP PREVIEW DVB *
* GREEN BLUE *
* */
- { 0x1d, KEY_SLEEP },
- { 0x13, KEY_GREEN },
- { 0x19, KEY_BLUE }, /* XXX KEY_SAT */
+ { 0x6b861d, KEY_SLEEP },
+ { 0x6b8613, KEY_GREEN },
+ { 0x6b8619, KEY_BLUE }, /* XXX KEY_SAT */
/* 0x58 0x5c *
* FREEZE SNAPSHOT *
* */
- { 0x58, KEY_SLOW },
- { 0x5c, KEY_CAMERA },
+ { 0x6b8658, KEY_SLOW },
+ { 0x6b865c, KEY_CAMERA },
};
-static struct rc_keymap behold_map = {
+static struct rc_map_list behold_map = {
.map = {
.scan = behold,
.size = ARRAY_SIZE(behold),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_BEHOLD,
}
};
static int __init init_rc_map_behold(void)
{
- return ir_register_map(&behold_map);
+ return rc_map_register(&behold_map);
}
static void __exit exit_rc_map_behold(void)
{
- ir_unregister_map(&behold_map);
+ rc_map_unregister(&behold_map);
}
module_init(init_rc_map_behold)
diff --git a/drivers/media/IR/keymaps/rc-budget-ci-old.c b/drivers/media/rc/keymaps/rc-budget-ci-old.c
index 64c2ac913338..97fc3862f608 100644
--- a/drivers/media/IR/keymaps/rc-budget-ci-old.c
+++ b/drivers/media/rc/keymaps/rc-budget-ci-old.c
@@ -18,7 +18,7 @@
* This is a "middle of the road" approach, differences are noted
*/
-static struct ir_scancode budget_ci_old[] = {
+static struct rc_map_table budget_ci_old[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -66,23 +66,23 @@ static struct ir_scancode budget_ci_old[] = {
{ 0x3e, KEY_TUNER },
};
-static struct rc_keymap budget_ci_old_map = {
+static struct rc_map_list budget_ci_old_map = {
.map = {
.scan = budget_ci_old,
.size = ARRAY_SIZE(budget_ci_old),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_BUDGET_CI_OLD,
}
};
static int __init init_rc_map_budget_ci_old(void)
{
- return ir_register_map(&budget_ci_old_map);
+ return rc_map_register(&budget_ci_old_map);
}
static void __exit exit_rc_map_budget_ci_old(void)
{
- ir_unregister_map(&budget_ci_old_map);
+ rc_map_unregister(&budget_ci_old_map);
}
module_init(init_rc_map_budget_ci_old)
diff --git a/drivers/media/IR/keymaps/rc-cinergy-1400.c b/drivers/media/rc/keymaps/rc-cinergy-1400.c
index 074f2c2c2c61..284534b67e7d 100644
--- a/drivers/media/IR/keymaps/rc-cinergy-1400.c
+++ b/drivers/media/rc/keymaps/rc-cinergy-1400.c
@@ -14,7 +14,7 @@
/* Cinergy 1400 DVB-T */
-static struct ir_scancode cinergy_1400[] = {
+static struct rc_map_table cinergy_1400[] = {
{ 0x01, KEY_POWER },
{ 0x02, KEY_1 },
{ 0x03, KEY_2 },
@@ -58,23 +58,23 @@ static struct ir_scancode cinergy_1400[] = {
{ 0x5c, KEY_NEXT },
};
-static struct rc_keymap cinergy_1400_map = {
+static struct rc_map_list cinergy_1400_map = {
.map = {
.scan = cinergy_1400,
.size = ARRAY_SIZE(cinergy_1400),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_CINERGY_1400,
}
};
static int __init init_rc_map_cinergy_1400(void)
{
- return ir_register_map(&cinergy_1400_map);
+ return rc_map_register(&cinergy_1400_map);
}
static void __exit exit_rc_map_cinergy_1400(void)
{
- ir_unregister_map(&cinergy_1400_map);
+ rc_map_unregister(&cinergy_1400_map);
}
module_init(init_rc_map_cinergy_1400)
diff --git a/drivers/media/IR/keymaps/rc-cinergy.c b/drivers/media/rc/keymaps/rc-cinergy.c
index cf84c3dba742..99520ff65b61 100644
--- a/drivers/media/IR/keymaps/rc-cinergy.c
+++ b/drivers/media/rc/keymaps/rc-cinergy.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode cinergy[] = {
+static struct rc_map_table cinergy[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -52,23 +52,23 @@ static struct ir_scancode cinergy[] = {
{ 0x23, KEY_STOP },
};
-static struct rc_keymap cinergy_map = {
+static struct rc_map_list cinergy_map = {
.map = {
.scan = cinergy,
.size = ARRAY_SIZE(cinergy),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_CINERGY,
}
};
static int __init init_rc_map_cinergy(void)
{
- return ir_register_map(&cinergy_map);
+ return rc_map_register(&cinergy_map);
}
static void __exit exit_rc_map_cinergy(void)
{
- ir_unregister_map(&cinergy_map);
+ rc_map_unregister(&cinergy_map);
}
module_init(init_rc_map_cinergy)
diff --git a/drivers/media/rc/keymaps/rc-dib0700-nec.c b/drivers/media/rc/keymaps/rc-dib0700-nec.c
new file mode 100644
index 000000000000..7a5f5300caf9
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dib0700-nec.c
@@ -0,0 +1,124 @@
+/* rc-dvb0700-big.c - Keytable for devices in dvb0700
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * TODO: This table is a real mess, as it merges RC codes from several
+ * devices into a big table. It also has both RC-5 and NEC codes inside.
+ * It should be broken into small tables, and the protocols should properly
+ * be indentificated.
+ *
+ * The table were imported from dib0700_devices.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table dib0700_nec_table[] = {
+ /* Key codes for the Pixelview SBTVD remote */
+ { 0x866b13, KEY_MUTE },
+ { 0x866b12, KEY_POWER },
+ { 0x866b01, KEY_1 },
+ { 0x866b02, KEY_2 },
+ { 0x866b03, KEY_3 },
+ { 0x866b04, KEY_4 },
+ { 0x866b05, KEY_5 },
+ { 0x866b06, KEY_6 },
+ { 0x866b07, KEY_7 },
+ { 0x866b08, KEY_8 },
+ { 0x866b09, KEY_9 },
+ { 0x866b00, KEY_0 },
+ { 0x866b0d, KEY_CHANNELUP },
+ { 0x866b19, KEY_CHANNELDOWN },
+ { 0x866b10, KEY_VOLUMEUP },
+ { 0x866b0c, KEY_VOLUMEDOWN },
+
+ { 0x866b0a, KEY_CAMERA },
+ { 0x866b0b, KEY_ZOOM },
+ { 0x866b1b, KEY_BACKSPACE },
+ { 0x866b15, KEY_ENTER },
+
+ { 0x866b1d, KEY_UP },
+ { 0x866b1e, KEY_DOWN },
+ { 0x866b0e, KEY_LEFT },
+ { 0x866b0f, KEY_RIGHT },
+
+ { 0x866b18, KEY_RECORD },
+ { 0x866b1a, KEY_STOP },
+
+ /* Key codes for the EvolutePC TVWay+ remote */
+ { 0x7a00, KEY_MENU },
+ { 0x7a01, KEY_RECORD },
+ { 0x7a02, KEY_PLAY },
+ { 0x7a03, KEY_STOP },
+ { 0x7a10, KEY_CHANNELUP },
+ { 0x7a11, KEY_CHANNELDOWN },
+ { 0x7a12, KEY_VOLUMEUP },
+ { 0x7a13, KEY_VOLUMEDOWN },
+ { 0x7a40, KEY_POWER },
+ { 0x7a41, KEY_MUTE },
+
+ /* Key codes for the Elgato EyeTV Diversity silver remote */
+ { 0x4501, KEY_POWER },
+ { 0x4502, KEY_MUTE },
+ { 0x4503, KEY_1 },
+ { 0x4504, KEY_2 },
+ { 0x4505, KEY_3 },
+ { 0x4506, KEY_4 },
+ { 0x4507, KEY_5 },
+ { 0x4508, KEY_6 },
+ { 0x4509, KEY_7 },
+ { 0x450a, KEY_8 },
+ { 0x450b, KEY_9 },
+ { 0x450c, KEY_LAST },
+ { 0x450d, KEY_0 },
+ { 0x450e, KEY_ENTER },
+ { 0x450f, KEY_RED },
+ { 0x4510, KEY_CHANNELUP },
+ { 0x4511, KEY_GREEN },
+ { 0x4512, KEY_VOLUMEDOWN },
+ { 0x4513, KEY_OK },
+ { 0x4514, KEY_VOLUMEUP },
+ { 0x4515, KEY_YELLOW },
+ { 0x4516, KEY_CHANNELDOWN },
+ { 0x4517, KEY_BLUE },
+ { 0x4518, KEY_LEFT }, /* Skip backwards */
+ { 0x4519, KEY_PLAYPAUSE },
+ { 0x451a, KEY_RIGHT }, /* Skip forward */
+ { 0x451b, KEY_REWIND },
+ { 0x451c, KEY_L }, /* Live */
+ { 0x451d, KEY_FASTFORWARD },
+ { 0x451e, KEY_STOP }, /* 'Reveal' for Teletext */
+ { 0x451f, KEY_MENU }, /* KEY_TEXT for Teletext */
+ { 0x4540, KEY_RECORD }, /* Font 'Size' for Teletext */
+ { 0x4541, KEY_SCREEN }, /* Full screen toggle, 'Hold' for Teletext */
+ { 0x4542, KEY_SELECT }, /* Select video input, 'Select' for Teletext */
+};
+
+static struct rc_map_list dib0700_nec_map = {
+ .map = {
+ .scan = dib0700_nec_table,
+ .size = ARRAY_SIZE(dib0700_nec_table),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_DIB0700_NEC_TABLE,
+ }
+};
+
+static int __init init_rc_map(void)
+{
+ return rc_map_register(&dib0700_nec_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+ rc_map_unregister(&dib0700_nec_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-dib0700-rc5.c b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
new file mode 100644
index 000000000000..4af12e45dfba
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-dib0700-rc5.c
@@ -0,0 +1,235 @@
+/* rc-dvb0700-big.c - Keytable for devices in dvb0700
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * TODO: This table is a real mess, as it merges RC codes from several
+ * devices into a big table. It also has both RC-5 and NEC codes inside.
+ * It should be broken into small tables, and the protocols should properly
+ * be indentificated.
+ *
+ * The table were imported from dib0700_devices.c.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table dib0700_rc5_table[] = {
+ /* Key codes for the tiny Pinnacle remote*/
+ { 0x0700, KEY_MUTE },
+ { 0x0701, KEY_MENU }, /* Pinnacle logo */
+ { 0x0739, KEY_POWER },
+ { 0x0703, KEY_VOLUMEUP },
+ { 0x0709, KEY_VOLUMEDOWN },
+ { 0x0706, KEY_CHANNELUP },
+ { 0x070c, KEY_CHANNELDOWN },
+ { 0x070f, KEY_1 },
+ { 0x0715, KEY_2 },
+ { 0x0710, KEY_3 },
+ { 0x0718, KEY_4 },
+ { 0x071b, KEY_5 },
+ { 0x071e, KEY_6 },
+ { 0x0711, KEY_7 },
+ { 0x0721, KEY_8 },
+ { 0x0712, KEY_9 },
+ { 0x0727, KEY_0 },
+ { 0x0724, KEY_SCREEN }, /* 'Square' key */
+ { 0x072a, KEY_TEXT }, /* 'T' key */
+ { 0x072d, KEY_REWIND },
+ { 0x0730, KEY_PLAY },
+ { 0x0733, KEY_FASTFORWARD },
+ { 0x0736, KEY_RECORD },
+ { 0x073c, KEY_STOP },
+ { 0x073f, KEY_CANCEL }, /* '?' key */
+
+ /* Key codes for the Terratec Cinergy DT XS Diversity, similar to cinergyT2.c */
+ { 0xeb01, KEY_POWER },
+ { 0xeb02, KEY_1 },
+ { 0xeb03, KEY_2 },
+ { 0xeb04, KEY_3 },
+ { 0xeb05, KEY_4 },
+ { 0xeb06, KEY_5 },
+ { 0xeb07, KEY_6 },
+ { 0xeb08, KEY_7 },
+ { 0xeb09, KEY_8 },
+ { 0xeb0a, KEY_9 },
+ { 0xeb0b, KEY_VIDEO },
+ { 0xeb0c, KEY_0 },
+ { 0xeb0d, KEY_REFRESH },
+ { 0xeb0f, KEY_EPG },
+ { 0xeb10, KEY_UP },
+ { 0xeb11, KEY_LEFT },
+ { 0xeb12, KEY_OK },
+ { 0xeb13, KEY_RIGHT },
+ { 0xeb14, KEY_DOWN },
+ { 0xeb16, KEY_INFO },
+ { 0xeb17, KEY_RED },
+ { 0xeb18, KEY_GREEN },
+ { 0xeb19, KEY_YELLOW },
+ { 0xeb1a, KEY_BLUE },
+ { 0xeb1b, KEY_CHANNELUP },
+ { 0xeb1c, KEY_VOLUMEUP },
+ { 0xeb1d, KEY_MUTE },
+ { 0xeb1e, KEY_VOLUMEDOWN },
+ { 0xeb1f, KEY_CHANNELDOWN },
+ { 0xeb40, KEY_PAUSE },
+ { 0xeb41, KEY_HOME },
+ { 0xeb42, KEY_MENU }, /* DVD Menu */
+ { 0xeb43, KEY_SUBTITLE },
+ { 0xeb44, KEY_TEXT }, /* Teletext */
+ { 0xeb45, KEY_DELETE },
+ { 0xeb46, KEY_TV },
+ { 0xeb47, KEY_DVD },
+ { 0xeb48, KEY_STOP },
+ { 0xeb49, KEY_VIDEO },
+ { 0xeb4a, KEY_AUDIO }, /* Music */
+ { 0xeb4b, KEY_SCREEN }, /* Pic */
+ { 0xeb4c, KEY_PLAY },
+ { 0xeb4d, KEY_BACK },
+ { 0xeb4e, KEY_REWIND },
+ { 0xeb4f, KEY_FASTFORWARD },
+ { 0xeb54, KEY_PREVIOUS },
+ { 0xeb58, KEY_RECORD },
+ { 0xeb5c, KEY_NEXT },
+
+ /* Key codes for the Haupauge WinTV Nova-TD, copied from nova-t-usb2.c (Nova-T USB2) */
+ { 0x1e00, KEY_0 },
+ { 0x1e01, KEY_1 },
+ { 0x1e02, KEY_2 },
+ { 0x1e03, KEY_3 },
+ { 0x1e04, KEY_4 },
+ { 0x1e05, KEY_5 },
+ { 0x1e06, KEY_6 },
+ { 0x1e07, KEY_7 },
+ { 0x1e08, KEY_8 },
+ { 0x1e09, KEY_9 },
+ { 0x1e0a, KEY_KPASTERISK },
+ { 0x1e0b, KEY_RED },
+ { 0x1e0c, KEY_RADIO },
+ { 0x1e0d, KEY_MENU },
+ { 0x1e0e, KEY_GRAVE }, /* # */
+ { 0x1e0f, KEY_MUTE },
+ { 0x1e10, KEY_VOLUMEUP },
+ { 0x1e11, KEY_VOLUMEDOWN },
+ { 0x1e12, KEY_CHANNEL },
+ { 0x1e14, KEY_UP },
+ { 0x1e15, KEY_DOWN },
+ { 0x1e16, KEY_LEFT },
+ { 0x1e17, KEY_RIGHT },
+ { 0x1e18, KEY_VIDEO },
+ { 0x1e19, KEY_AUDIO },
+ { 0x1e1a, KEY_MEDIA },
+ { 0x1e1b, KEY_EPG },
+ { 0x1e1c, KEY_TV },
+ { 0x1e1e, KEY_NEXT },
+ { 0x1e1f, KEY_BACK },
+ { 0x1e20, KEY_CHANNELUP },
+ { 0x1e21, KEY_CHANNELDOWN },
+ { 0x1e24, KEY_LAST }, /* Skip backwards */
+ { 0x1e25, KEY_OK },
+ { 0x1e29, KEY_BLUE},
+ { 0x1e2e, KEY_GREEN },
+ { 0x1e30, KEY_PAUSE },
+ { 0x1e32, KEY_REWIND },
+ { 0x1e34, KEY_FASTFORWARD },
+ { 0x1e35, KEY_PLAY },
+ { 0x1e36, KEY_STOP },
+ { 0x1e37, KEY_RECORD },
+ { 0x1e38, KEY_YELLOW },
+ { 0x1e3b, KEY_GOTO },
+ { 0x1e3d, KEY_POWER },
+
+ /* Key codes for the Leadtek Winfast DTV Dongle */
+ { 0x0042, KEY_POWER },
+ { 0x077c, KEY_TUNER },
+ { 0x0f4e, KEY_PRINT }, /* PREVIEW */
+ { 0x0840, KEY_SCREEN }, /* full screen toggle*/
+ { 0x0f71, KEY_DOT }, /* frequency */
+ { 0x0743, KEY_0 },
+ { 0x0c41, KEY_1 },
+ { 0x0443, KEY_2 },
+ { 0x0b7f, KEY_3 },
+ { 0x0e41, KEY_4 },
+ { 0x0643, KEY_5 },
+ { 0x097f, KEY_6 },
+ { 0x0d7e, KEY_7 },
+ { 0x057c, KEY_8 },
+ { 0x0a40, KEY_9 },
+ { 0x0e4e, KEY_CLEAR },
+ { 0x047c, KEY_CHANNEL }, /* show channel number */
+ { 0x0f41, KEY_LAST }, /* recall */
+ { 0x0342, KEY_MUTE },
+ { 0x064c, KEY_RESERVED }, /* PIP button*/
+ { 0x0172, KEY_SHUFFLE }, /* SNAPSHOT */
+ { 0x0c4e, KEY_PLAYPAUSE }, /* TIMESHIFT */
+ { 0x0b70, KEY_RECORD },
+ { 0x037d, KEY_VOLUMEUP },
+ { 0x017d, KEY_VOLUMEDOWN },
+ { 0x0242, KEY_CHANNELUP },
+ { 0x007d, KEY_CHANNELDOWN },
+
+ /* Key codes for Nova-TD "credit card" remote control. */
+ { 0x1d00, KEY_0 },
+ { 0x1d01, KEY_1 },
+ { 0x1d02, KEY_2 },
+ { 0x1d03, KEY_3 },
+ { 0x1d04, KEY_4 },
+ { 0x1d05, KEY_5 },
+ { 0x1d06, KEY_6 },
+ { 0x1d07, KEY_7 },
+ { 0x1d08, KEY_8 },
+ { 0x1d09, KEY_9 },
+ { 0x1d0a, KEY_TEXT },
+ { 0x1d0d, KEY_MENU },
+ { 0x1d0f, KEY_MUTE },
+ { 0x1d10, KEY_VOLUMEUP },
+ { 0x1d11, KEY_VOLUMEDOWN },
+ { 0x1d12, KEY_CHANNEL },
+ { 0x1d14, KEY_UP },
+ { 0x1d15, KEY_DOWN },
+ { 0x1d16, KEY_LEFT },
+ { 0x1d17, KEY_RIGHT },
+ { 0x1d1c, KEY_TV },
+ { 0x1d1e, KEY_NEXT },
+ { 0x1d1f, KEY_BACK },
+ { 0x1d20, KEY_CHANNELUP },
+ { 0x1d21, KEY_CHANNELDOWN },
+ { 0x1d24, KEY_LAST },
+ { 0x1d25, KEY_OK },
+ { 0x1d30, KEY_PAUSE },
+ { 0x1d32, KEY_REWIND },
+ { 0x1d34, KEY_FASTFORWARD },
+ { 0x1d35, KEY_PLAY },
+ { 0x1d36, KEY_STOP },
+ { 0x1d37, KEY_RECORD },
+ { 0x1d3b, KEY_GOTO },
+ { 0x1d3d, KEY_POWER },
+};
+
+static struct rc_map_list dib0700_rc5_map = {
+ .map = {
+ .scan = dib0700_rc5_table,
+ .size = ARRAY_SIZE(dib0700_rc5_table),
+ .rc_type = RC_TYPE_RC5,
+ .name = RC_MAP_DIB0700_RC5_TABLE,
+ }
+};
+
+static int __init init_rc_map(void)
+{
+ return rc_map_register(&dib0700_rc5_map);
+}
+
+static void __exit exit_rc_map(void)
+{
+ rc_map_unregister(&dib0700_rc5_map);
+}
+
+module_init(init_rc_map)
+module_exit(exit_rc_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
new file mode 100644
index 000000000000..f68b450f5593
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-digitalnow-tinytwin.c
@@ -0,0 +1,98 @@
+/*
+ * DigitalNow TinyTwin remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table digitalnow_tinytwin[] = {
+ { 0x0000, KEY_MUTE }, /* [symbol speaker] */
+ { 0x0001, KEY_VOLUMEUP },
+ { 0x0002, KEY_POWER2 }, /* TV [power button] */
+ { 0x0003, KEY_2 },
+ { 0x0004, KEY_3 },
+ { 0x0005, KEY_4 },
+ { 0x0006, KEY_6 },
+ { 0x0007, KEY_7 },
+ { 0x0008, KEY_8 },
+ { 0x0009, KEY_NUMERIC_STAR }, /* [*] */
+ { 0x000a, KEY_0 },
+ { 0x000b, KEY_NUMERIC_POUND }, /* [#] */
+ { 0x000c, KEY_RIGHT }, /* [right arrow] */
+ { 0x000d, KEY_HOMEPAGE }, /* [symbol home] Start */
+ { 0x000e, KEY_RED }, /* [red] Videos */
+ { 0x0010, KEY_POWER }, /* PC [power button] */
+ { 0x0011, KEY_YELLOW }, /* [yellow] Pictures */
+ { 0x0012, KEY_DOWN }, /* [down arrow] */
+ { 0x0013, KEY_GREEN }, /* [green] Music */
+ { 0x0014, KEY_CYCLEWINDOWS }, /* BACK */
+ { 0x0015, KEY_FAVORITES }, /* MORE */
+ { 0x0016, KEY_UP }, /* [up arrow] */
+ { 0x0017, KEY_LEFT }, /* [left arrow] */
+ { 0x0018, KEY_OK }, /* OK */
+ { 0x0019, KEY_BLUE }, /* [blue] MyTV */
+ { 0x001a, KEY_REWIND }, /* REW [<<] */
+ { 0x001b, KEY_PLAY }, /* PLAY */
+ { 0x001c, KEY_5 },
+ { 0x001d, KEY_9 },
+ { 0x001e, KEY_VOLUMEDOWN },
+ { 0x001f, KEY_1 },
+ { 0x0040, KEY_STOP }, /* STOP */
+ { 0x0042, KEY_PAUSE }, /* PAUSE */
+ { 0x0043, KEY_SCREEN }, /* Aspect */
+ { 0x0044, KEY_FORWARD }, /* FWD [>>] */
+ { 0x0045, KEY_NEXT }, /* SKIP */
+ { 0x0048, KEY_RECORD }, /* RECORD */
+ { 0x0049, KEY_VIDEO }, /* RTV */
+ { 0x004a, KEY_EPG }, /* Guide */
+ { 0x004b, KEY_CHANNELUP },
+ { 0x004c, KEY_HELP }, /* Help */
+ { 0x004d, KEY_RADIO }, /* Radio */
+ { 0x004f, KEY_CHANNELDOWN },
+ { 0x0050, KEY_DVD }, /* DVD */
+ { 0x0051, KEY_AUDIO }, /* Audio */
+ { 0x0052, KEY_TITLE }, /* Title */
+ { 0x0053, KEY_NEW }, /* [symbol PIP?] */
+ { 0x0057, KEY_MENU }, /* Mouse */
+ { 0x005a, KEY_PREVIOUS }, /* REPLAY */
+};
+
+static struct rc_map_list digitalnow_tinytwin_map = {
+ .map = {
+ .scan = digitalnow_tinytwin,
+ .size = ARRAY_SIZE(digitalnow_tinytwin),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_DIGITALNOW_TINYTWIN,
+ }
+};
+
+static int __init init_rc_map_digitalnow_tinytwin(void)
+{
+ return rc_map_register(&digitalnow_tinytwin_map);
+}
+
+static void __exit exit_rc_map_digitalnow_tinytwin(void)
+{
+ rc_map_unregister(&digitalnow_tinytwin_map);
+}
+
+module_init(init_rc_map_digitalnow_tinytwin)
+module_exit(exit_rc_map_digitalnow_tinytwin)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-digittrade.c b/drivers/media/rc/keymaps/rc-digittrade.c
new file mode 100644
index 000000000000..21d49871f2a3
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-digittrade.c
@@ -0,0 +1,82 @@
+/*
+ * Digittrade DVB-T USB Stick remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* Digittrade DVB-T USB Stick remote controller. */
+/* Imported from af9015.h.
+ Initial keytable was from Alain Kalker <miki@dds.nl> */
+
+/* Digittrade DVB-T USB Stick */
+static struct rc_map_table digittrade[] = {
+ { 0x0000, KEY_9 },
+ { 0x0001, KEY_EPG }, /* EPG */
+ { 0x0002, KEY_VOLUMEDOWN }, /* Vol Dn */
+ { 0x0003, KEY_TEXT }, /* TELETEXT */
+ { 0x0004, KEY_8 },
+ { 0x0005, KEY_MUTE }, /* MUTE */
+ { 0x0006, KEY_POWER2 }, /* POWER */
+ { 0x0009, KEY_ZOOM }, /* FULLSCREEN */
+ { 0x000a, KEY_RECORD }, /* RECORD */
+ { 0x000d, KEY_SUBTITLE }, /* SUBTITLE */
+ { 0x000e, KEY_STOP }, /* STOP */
+ { 0x0010, KEY_OK }, /* RETURN */
+ { 0x0011, KEY_2 },
+ { 0x0012, KEY_4 },
+ { 0x0015, KEY_3 },
+ { 0x0016, KEY_5 },
+ { 0x0017, KEY_CHANNELDOWN }, /* Ch Dn */
+ { 0x0019, KEY_CHANNELUP }, /* CH Up */
+ { 0x001a, KEY_PAUSE }, /* PAUSE */
+ { 0x001b, KEY_1 },
+ { 0x001d, KEY_AUDIO }, /* DUAL SOUND */
+ { 0x001e, KEY_PLAY }, /* PLAY */
+ { 0x001f, KEY_CAMERA }, /* SNAPSHOT */
+ { 0x0040, KEY_VOLUMEUP }, /* Vol Up */
+ { 0x0048, KEY_7 },
+ { 0x004c, KEY_6 },
+ { 0x004d, KEY_PLAYPAUSE }, /* TIMESHIFT */
+ { 0x0054, KEY_0 },
+};
+
+static struct rc_map_list digittrade_map = {
+ .map = {
+ .scan = digittrade,
+ .size = ARRAY_SIZE(digittrade),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_DIGITTRADE,
+ }
+};
+
+static int __init init_rc_map_digittrade(void)
+{
+ return rc_map_register(&digittrade_map);
+}
+
+static void __exit exit_rc_map_digittrade(void)
+{
+ rc_map_unregister(&digittrade_map);
+}
+
+module_init(init_rc_map_digittrade)
+module_exit(exit_rc_map_digittrade)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-dm1105-nec.c b/drivers/media/rc/keymaps/rc-dm1105-nec.c
index 90684d0efea3..d024fbf88bc4 100644
--- a/drivers/media/IR/keymaps/rc-dm1105-nec.c
+++ b/drivers/media/rc/keymaps/rc-dm1105-nec.c
@@ -16,7 +16,7 @@
Igor M. Liplianin <liplianin@me.by>
*/
-static struct ir_scancode dm1105_nec[] = {
+static struct rc_map_table dm1105_nec[] = {
{ 0x0a, KEY_POWER2}, /* power */
{ 0x0c, KEY_MUTE}, /* mute */
{ 0x11, KEY_1},
@@ -50,23 +50,23 @@ static struct ir_scancode dm1105_nec[] = {
{ 0x1b, KEY_B}, /* recall */
};
-static struct rc_keymap dm1105_nec_map = {
+static struct rc_map_list dm1105_nec_map = {
.map = {
.scan = dm1105_nec,
.size = ARRAY_SIZE(dm1105_nec),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_DM1105_NEC,
}
};
static int __init init_rc_map_dm1105_nec(void)
{
- return ir_register_map(&dm1105_nec_map);
+ return rc_map_register(&dm1105_nec_map);
}
static void __exit exit_rc_map_dm1105_nec(void)
{
- ir_unregister_map(&dm1105_nec_map);
+ rc_map_unregister(&dm1105_nec_map);
}
module_init(init_rc_map_dm1105_nec)
diff --git a/drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
index 8a4027af964a..43912bd02a9e 100644
--- a/drivers/media/IR/keymaps/rc-dntv-live-dvb-t.c
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvb-t.c
@@ -14,7 +14,7 @@
/* DigitalNow DNTV Live DVB-T Remote */
-static struct ir_scancode dntv_live_dvb_t[] = {
+static struct rc_map_table dntv_live_dvb_t[] = {
{ 0x00, KEY_ESC }, /* 'go up a level?' */
/* Keys 0 to 9 */
{ 0x0a, KEY_0 },
@@ -52,23 +52,23 @@ static struct ir_scancode dntv_live_dvb_t[] = {
{ 0x1f, KEY_VOLUMEDOWN },
};
-static struct rc_keymap dntv_live_dvb_t_map = {
+static struct rc_map_list dntv_live_dvb_t_map = {
.map = {
.scan = dntv_live_dvb_t,
.size = ARRAY_SIZE(dntv_live_dvb_t),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_DNTV_LIVE_DVB_T,
}
};
static int __init init_rc_map_dntv_live_dvb_t(void)
{
- return ir_register_map(&dntv_live_dvb_t_map);
+ return rc_map_register(&dntv_live_dvb_t_map);
}
static void __exit exit_rc_map_dntv_live_dvb_t(void)
{
- ir_unregister_map(&dntv_live_dvb_t_map);
+ rc_map_unregister(&dntv_live_dvb_t_map);
}
module_init(init_rc_map_dntv_live_dvb_t)
diff --git a/drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
index 6f4d60764d59..015e99de06de 100644
--- a/drivers/media/IR/keymaps/rc-dntv-live-dvbt-pro.c
+++ b/drivers/media/rc/keymaps/rc-dntv-live-dvbt-pro.c
@@ -14,7 +14,7 @@
/* DigitalNow DNTV Live! DVB-T Pro Remote */
-static struct ir_scancode dntv_live_dvbt_pro[] = {
+static struct rc_map_table dntv_live_dvbt_pro[] = {
{ 0x16, KEY_POWER },
{ 0x5b, KEY_HOME },
@@ -71,23 +71,23 @@ static struct ir_scancode dntv_live_dvbt_pro[] = {
{ 0x5d, KEY_BLUE },
};
-static struct rc_keymap dntv_live_dvbt_pro_map = {
+static struct rc_map_list dntv_live_dvbt_pro_map = {
.map = {
.scan = dntv_live_dvbt_pro,
.size = ARRAY_SIZE(dntv_live_dvbt_pro),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_DNTV_LIVE_DVBT_PRO,
}
};
static int __init init_rc_map_dntv_live_dvbt_pro(void)
{
- return ir_register_map(&dntv_live_dvbt_pro_map);
+ return rc_map_register(&dntv_live_dvbt_pro_map);
}
static void __exit exit_rc_map_dntv_live_dvbt_pro(void)
{
- ir_unregister_map(&dntv_live_dvbt_pro_map);
+ rc_map_unregister(&dntv_live_dvbt_pro_map);
}
module_init(init_rc_map_dntv_live_dvbt_pro)
diff --git a/drivers/media/IR/keymaps/rc-em-terratec.c b/drivers/media/rc/keymaps/rc-em-terratec.c
index 3130c9c29e6b..269d4299da34 100644
--- a/drivers/media/IR/keymaps/rc-em-terratec.c
+++ b/drivers/media/rc/keymaps/rc-em-terratec.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode em_terratec[] = {
+static struct rc_map_table em_terratec[] = {
{ 0x01, KEY_CHANNEL },
{ 0x02, KEY_SELECT },
{ 0x03, KEY_MUTE },
@@ -43,23 +43,23 @@ static struct ir_scancode em_terratec[] = {
{ 0x40, KEY_ZOOM },
};
-static struct rc_keymap em_terratec_map = {
+static struct rc_map_list em_terratec_map = {
.map = {
.scan = em_terratec,
.size = ARRAY_SIZE(em_terratec),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_EM_TERRATEC,
}
};
static int __init init_rc_map_em_terratec(void)
{
- return ir_register_map(&em_terratec_map);
+ return rc_map_register(&em_terratec_map);
}
static void __exit exit_rc_map_em_terratec(void)
{
- ir_unregister_map(&em_terratec_map);
+ rc_map_unregister(&em_terratec_map);
}
module_init(init_rc_map_em_terratec)
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv-fm53.c b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
index 4b816967877e..e388698a0697 100644
--- a/drivers/media/IR/keymaps/rc-encore-enltv-fm53.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv-fm53.c
@@ -16,7 +16,7 @@
Mauro Carvalho Chehab <mchehab@infradead.org>
*/
-static struct ir_scancode encore_enltv_fm53[] = {
+static struct rc_map_table encore_enltv_fm53[] = {
{ 0x10, KEY_POWER2},
{ 0x06, KEY_MUTE},
@@ -55,23 +55,23 @@ static struct ir_scancode encore_enltv_fm53[] = {
{ 0x47, KEY_SLEEP}, /* shutdown */
};
-static struct rc_keymap encore_enltv_fm53_map = {
+static struct rc_map_list encore_enltv_fm53_map = {
.map = {
.scan = encore_enltv_fm53,
.size = ARRAY_SIZE(encore_enltv_fm53),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ENCORE_ENLTV_FM53,
}
};
static int __init init_rc_map_encore_enltv_fm53(void)
{
- return ir_register_map(&encore_enltv_fm53_map);
+ return rc_map_register(&encore_enltv_fm53_map);
}
static void __exit exit_rc_map_encore_enltv_fm53(void)
{
- ir_unregister_map(&encore_enltv_fm53_map);
+ rc_map_unregister(&encore_enltv_fm53_map);
}
module_init(init_rc_map_encore_enltv_fm53)
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv.c b/drivers/media/rc/keymaps/rc-encore-enltv.c
index 9fabffd28cc9..afa4e92284ef 100644
--- a/drivers/media/IR/keymaps/rc-encore-enltv.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv.c
@@ -15,7 +15,7 @@
/* Encore ENLTV-FM - black plastic, white front cover with white glowing buttons
Juan Pablo Sormani <sorman@gmail.com> */
-static struct ir_scancode encore_enltv[] = {
+static struct rc_map_table encore_enltv[] = {
/* Power button does nothing, neither in Windows app,
although it sends data (used for BIOS wakeup?) */
@@ -86,23 +86,23 @@ static struct ir_scancode encore_enltv[] = {
{ 0x57, KEY_BLUE }, /* AP4 */
};
-static struct rc_keymap encore_enltv_map = {
+static struct rc_map_list encore_enltv_map = {
.map = {
.scan = encore_enltv,
.size = ARRAY_SIZE(encore_enltv),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ENCORE_ENLTV,
}
};
static int __init init_rc_map_encore_enltv(void)
{
- return ir_register_map(&encore_enltv_map);
+ return rc_map_register(&encore_enltv_map);
}
static void __exit exit_rc_map_encore_enltv(void)
{
- ir_unregister_map(&encore_enltv_map);
+ rc_map_unregister(&encore_enltv_map);
}
module_init(init_rc_map_encore_enltv)
diff --git a/drivers/media/IR/keymaps/rc-encore-enltv2.c b/drivers/media/rc/keymaps/rc-encore-enltv2.c
index efefd5166618..7d5b00ed4ff2 100644
--- a/drivers/media/IR/keymaps/rc-encore-enltv2.c
+++ b/drivers/media/rc/keymaps/rc-encore-enltv2.c
@@ -15,7 +15,7 @@
/* Encore ENLTV2-FM - silver plastic - "Wand Media" written at the botton
Mauro Carvalho Chehab <mchehab@infradead.org> */
-static struct ir_scancode encore_enltv2[] = {
+static struct rc_map_table encore_enltv2[] = {
{ 0x4c, KEY_POWER2 },
{ 0x4a, KEY_TUNER },
{ 0x40, KEY_1 },
@@ -64,23 +64,23 @@ static struct ir_scancode encore_enltv2[] = {
{ 0x79, KEY_STOP },
};
-static struct rc_keymap encore_enltv2_map = {
+static struct rc_map_list encore_enltv2_map = {
.map = {
.scan = encore_enltv2,
.size = ARRAY_SIZE(encore_enltv2),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_ENCORE_ENLTV2,
}
};
static int __init init_rc_map_encore_enltv2(void)
{
- return ir_register_map(&encore_enltv2_map);
+ return rc_map_register(&encore_enltv2_map);
}
static void __exit exit_rc_map_encore_enltv2(void)
{
- ir_unregister_map(&encore_enltv2_map);
+ rc_map_unregister(&encore_enltv2_map);
}
module_init(init_rc_map_encore_enltv2)
diff --git a/drivers/media/IR/keymaps/rc-evga-indtube.c b/drivers/media/rc/keymaps/rc-evga-indtube.c
index 3f3fb13813b3..a2bf24f6dfbb 100644
--- a/drivers/media/IR/keymaps/rc-evga-indtube.c
+++ b/drivers/media/rc/keymaps/rc-evga-indtube.c
@@ -16,7 +16,7 @@
Devin Heitmueller <devin.heitmueller@gmail.com>
*/
-static struct ir_scancode evga_indtube[] = {
+static struct rc_map_table evga_indtube[] = {
{ 0x12, KEY_POWER},
{ 0x02, KEY_MODE}, /* TV */
{ 0x14, KEY_MUTE},
@@ -35,23 +35,23 @@ static struct ir_scancode evga_indtube[] = {
{ 0x13, KEY_CAMERA},
};
-static struct rc_keymap evga_indtube_map = {
+static struct rc_map_list evga_indtube_map = {
.map = {
.scan = evga_indtube,
.size = ARRAY_SIZE(evga_indtube),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_EVGA_INDTUBE,
}
};
static int __init init_rc_map_evga_indtube(void)
{
- return ir_register_map(&evga_indtube_map);
+ return rc_map_register(&evga_indtube_map);
}
static void __exit exit_rc_map_evga_indtube(void)
{
- ir_unregister_map(&evga_indtube_map);
+ rc_map_unregister(&evga_indtube_map);
}
module_init(init_rc_map_evga_indtube)
diff --git a/drivers/media/IR/keymaps/rc-eztv.c b/drivers/media/rc/keymaps/rc-eztv.c
index 660907a78db9..1e8e5b2d6e36 100644
--- a/drivers/media/IR/keymaps/rc-eztv.c
+++ b/drivers/media/rc/keymaps/rc-eztv.c
@@ -15,7 +15,7 @@
/* Alfons Geser <a.geser@cox.net>
* updates from Job D. R. Borges <jobdrb@ig.com.br> */
-static struct ir_scancode eztv[] = {
+static struct rc_map_table eztv[] = {
{ 0x12, KEY_POWER },
{ 0x01, KEY_TV }, /* DVR */
{ 0x15, KEY_DVD }, /* DVD */
@@ -70,23 +70,23 @@ static struct ir_scancode eztv[] = {
{ 0x21, KEY_DOT }, /* . (decimal dot) */
};
-static struct rc_keymap eztv_map = {
+static struct rc_map_list eztv_map = {
.map = {
.scan = eztv,
.size = ARRAY_SIZE(eztv),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_EZTV,
}
};
static int __init init_rc_map_eztv(void)
{
- return ir_register_map(&eztv_map);
+ return rc_map_register(&eztv_map);
}
static void __exit exit_rc_map_eztv(void)
{
- ir_unregister_map(&eztv_map);
+ rc_map_unregister(&eztv_map);
}
module_init(init_rc_map_eztv)
diff --git a/drivers/media/IR/keymaps/rc-flydvb.c b/drivers/media/rc/keymaps/rc-flydvb.c
index a173c81035f4..aea2f4acf7d8 100644
--- a/drivers/media/IR/keymaps/rc-flydvb.c
+++ b/drivers/media/rc/keymaps/rc-flydvb.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode flydvb[] = {
+static struct rc_map_table flydvb[] = {
{ 0x01, KEY_ZOOM }, /* Full Screen */
{ 0x00, KEY_POWER }, /* Power */
@@ -51,23 +51,23 @@ static struct ir_scancode flydvb[] = {
{ 0x0e, KEY_NEXT }, /* End >>| */
};
-static struct rc_keymap flydvb_map = {
+static struct rc_map_list flydvb_map = {
.map = {
.scan = flydvb,
.size = ARRAY_SIZE(flydvb),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_FLYDVB,
}
};
static int __init init_rc_map_flydvb(void)
{
- return ir_register_map(&flydvb_map);
+ return rc_map_register(&flydvb_map);
}
static void __exit exit_rc_map_flydvb(void)
{
- ir_unregister_map(&flydvb_map);
+ rc_map_unregister(&flydvb_map);
}
module_init(init_rc_map_flydvb)
diff --git a/drivers/media/IR/keymaps/rc-flyvideo.c b/drivers/media/rc/keymaps/rc-flyvideo.c
index 9c73043cbdba..5bbe68371756 100644
--- a/drivers/media/IR/keymaps/rc-flyvideo.c
+++ b/drivers/media/rc/keymaps/rc-flyvideo.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode flyvideo[] = {
+static struct rc_map_table flyvideo[] = {
{ 0x0f, KEY_0 },
{ 0x03, KEY_1 },
{ 0x04, KEY_2 },
@@ -44,23 +44,23 @@ static struct ir_scancode flyvideo[] = {
{ 0x0a, KEY_ANGLE }, /* no label, may be used as the PAUSE button */
};
-static struct rc_keymap flyvideo_map = {
+static struct rc_map_list flyvideo_map = {
.map = {
.scan = flyvideo,
.size = ARRAY_SIZE(flyvideo),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_FLYVIDEO,
}
};
static int __init init_rc_map_flyvideo(void)
{
- return ir_register_map(&flyvideo_map);
+ return rc_map_register(&flyvideo_map);
}
static void __exit exit_rc_map_flyvideo(void)
{
- ir_unregister_map(&flyvideo_map);
+ rc_map_unregister(&flyvideo_map);
}
module_init(init_rc_map_flyvideo)
diff --git a/drivers/media/IR/keymaps/rc-fusionhdtv-mce.c b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
index cdb10389b10e..c80b25c65b57 100644
--- a/drivers/media/IR/keymaps/rc-fusionhdtv-mce.c
+++ b/drivers/media/rc/keymaps/rc-fusionhdtv-mce.c
@@ -14,7 +14,7 @@
/* DViCO FUSION HDTV MCE remote */
-static struct ir_scancode fusionhdtv_mce[] = {
+static struct rc_map_table fusionhdtv_mce[] = {
{ 0x0b, KEY_1 },
{ 0x17, KEY_2 },
@@ -72,23 +72,23 @@ static struct ir_scancode fusionhdtv_mce[] = {
{ 0x4e, KEY_POWER },
};
-static struct rc_keymap fusionhdtv_mce_map = {
+static struct rc_map_list fusionhdtv_mce_map = {
.map = {
.scan = fusionhdtv_mce,
.size = ARRAY_SIZE(fusionhdtv_mce),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_FUSIONHDTV_MCE,
}
};
static int __init init_rc_map_fusionhdtv_mce(void)
{
- return ir_register_map(&fusionhdtv_mce_map);
+ return rc_map_register(&fusionhdtv_mce_map);
}
static void __exit exit_rc_map_fusionhdtv_mce(void)
{
- ir_unregister_map(&fusionhdtv_mce_map);
+ rc_map_unregister(&fusionhdtv_mce_map);
}
module_init(init_rc_map_fusionhdtv_mce)
diff --git a/drivers/media/IR/keymaps/rc-gadmei-rm008z.c b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
index c16c0d1263ac..068c9ead98dd 100644
--- a/drivers/media/IR/keymaps/rc-gadmei-rm008z.c
+++ b/drivers/media/rc/keymaps/rc-gadmei-rm008z.c
@@ -16,7 +16,7 @@
Shine Liu <shinel@foxmail.com>
*/
-static struct ir_scancode gadmei_rm008z[] = {
+static struct rc_map_table gadmei_rm008z[] = {
{ 0x14, KEY_POWER2}, /* POWER OFF */
{ 0x0c, KEY_MUTE}, /* MUTE */
@@ -55,23 +55,23 @@ static struct ir_scancode gadmei_rm008z[] = {
{ 0x15, KEY_ENTER}, /* OK */
};
-static struct rc_keymap gadmei_rm008z_map = {
+static struct rc_map_list gadmei_rm008z_map = {
.map = {
.scan = gadmei_rm008z,
.size = ARRAY_SIZE(gadmei_rm008z),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_GADMEI_RM008Z,
}
};
static int __init init_rc_map_gadmei_rm008z(void)
{
- return ir_register_map(&gadmei_rm008z_map);
+ return rc_map_register(&gadmei_rm008z_map);
}
static void __exit exit_rc_map_gadmei_rm008z(void)
{
- ir_unregister_map(&gadmei_rm008z_map);
+ rc_map_unregister(&gadmei_rm008z_map);
}
module_init(init_rc_map_gadmei_rm008z)
diff --git a/drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
index 89f8e384e52a..cdbbed467926 100644
--- a/drivers/media/IR/keymaps/rc-genius-tvgo-a11mce.c
+++ b/drivers/media/rc/keymaps/rc-genius-tvgo-a11mce.c
@@ -17,7 +17,7 @@
* Adrian Pardini <pardo.bsso@gmail.com>
*/
-static struct ir_scancode genius_tvgo_a11mce[] = {
+static struct rc_map_table genius_tvgo_a11mce[] = {
/* Keys 0 to 9 */
{ 0x48, KEY_0 },
{ 0x09, KEY_1 },
@@ -58,23 +58,23 @@ static struct ir_scancode genius_tvgo_a11mce[] = {
{ 0x50, KEY_BLUE },
};
-static struct rc_keymap genius_tvgo_a11mce_map = {
+static struct rc_map_list genius_tvgo_a11mce_map = {
.map = {
.scan = genius_tvgo_a11mce,
.size = ARRAY_SIZE(genius_tvgo_a11mce),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_GENIUS_TVGO_A11MCE,
}
};
static int __init init_rc_map_genius_tvgo_a11mce(void)
{
- return ir_register_map(&genius_tvgo_a11mce_map);
+ return rc_map_register(&genius_tvgo_a11mce_map);
}
static void __exit exit_rc_map_genius_tvgo_a11mce(void)
{
- ir_unregister_map(&genius_tvgo_a11mce_map);
+ rc_map_unregister(&genius_tvgo_a11mce_map);
}
module_init(init_rc_map_genius_tvgo_a11mce)
diff --git a/drivers/media/IR/keymaps/rc-gotview7135.c b/drivers/media/rc/keymaps/rc-gotview7135.c
index 52f025bb35f6..a38bdde8c140 100644
--- a/drivers/media/IR/keymaps/rc-gotview7135.c
+++ b/drivers/media/rc/keymaps/rc-gotview7135.c
@@ -14,7 +14,7 @@
/* Mike Baikov <mike@baikov.com> */
-static struct ir_scancode gotview7135[] = {
+static struct rc_map_table gotview7135[] = {
{ 0x11, KEY_POWER },
{ 0x35, KEY_TV },
@@ -53,23 +53,23 @@ static struct ir_scancode gotview7135[] = {
{ 0x38, KEY_F24 }, /* NORMAL TIMESHIFT */
};
-static struct rc_keymap gotview7135_map = {
+static struct rc_map_list gotview7135_map = {
.map = {
.scan = gotview7135,
.size = ARRAY_SIZE(gotview7135),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_GOTVIEW7135,
}
};
static int __init init_rc_map_gotview7135(void)
{
- return ir_register_map(&gotview7135_map);
+ return rc_map_register(&gotview7135_map);
}
static void __exit exit_rc_map_gotview7135(void)
{
- ir_unregister_map(&gotview7135_map);
+ rc_map_unregister(&gotview7135_map);
}
module_init(init_rc_map_gotview7135)
diff --git a/drivers/media/IR/keymaps/rc-hauppauge-new.c b/drivers/media/rc/keymaps/rc-hauppauge-new.c
index c6f8cd7c5186..bd11da46e56a 100644
--- a/drivers/media/IR/keymaps/rc-hauppauge-new.c
+++ b/drivers/media/rc/keymaps/rc-hauppauge-new.c
@@ -16,7 +16,7 @@
* slightly different versions), shipped with cx88+ivtv cards.
* almost rc5 coding, but some non-standard keys */
-static struct ir_scancode hauppauge_new[] = {
+static struct rc_map_table hauppauge_new[] = {
/* Keys 0 to 9 */
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@@ -74,23 +74,23 @@ static struct ir_scancode hauppauge_new[] = {
{ 0x3d, KEY_POWER }, /* system power (green button) */
};
-static struct rc_keymap hauppauge_new_map = {
+static struct rc_map_list hauppauge_new_map = {
.map = {
.scan = hauppauge_new,
.size = ARRAY_SIZE(hauppauge_new),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_HAUPPAUGE_NEW,
}
};
static int __init init_rc_map_hauppauge_new(void)
{
- return ir_register_map(&hauppauge_new_map);
+ return rc_map_register(&hauppauge_new_map);
}
static void __exit exit_rc_map_hauppauge_new(void)
{
- ir_unregister_map(&hauppauge_new_map);
+ rc_map_unregister(&hauppauge_new_map);
}
module_init(init_rc_map_hauppauge_new)
diff --git a/drivers/media/IR/keymaps/rc-imon-mce.c b/drivers/media/rc/keymaps/rc-imon-mce.c
index e49f350e3a0d..cb67184e015c 100644
--- a/drivers/media/IR/keymaps/rc-imon-mce.c
+++ b/drivers/media/rc/keymaps/rc-imon-mce.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
/* mce-mode imon mce remote key table */
-static struct ir_scancode imon_mce[] = {
+static struct rc_map_table imon_mce[] = {
/* keys sorted mostly by frequency of use to optimize lookups */
{ 0x800ff415, KEY_REWIND },
{ 0x800ff414, KEY_FASTFORWARD },
@@ -115,24 +115,24 @@ static struct ir_scancode imon_mce[] = {
};
-static struct rc_keymap imon_mce_map = {
+static struct rc_map_list imon_mce_map = {
.map = {
.scan = imon_mce,
.size = ARRAY_SIZE(imon_mce),
/* its RC6, but w/a hardware decoder */
- .ir_type = IR_TYPE_RC6,
+ .rc_type = RC_TYPE_RC6,
.name = RC_MAP_IMON_MCE,
}
};
static int __init init_rc_map_imon_mce(void)
{
- return ir_register_map(&imon_mce_map);
+ return rc_map_register(&imon_mce_map);
}
static void __exit exit_rc_map_imon_mce(void)
{
- ir_unregister_map(&imon_mce_map);
+ rc_map_unregister(&imon_mce_map);
}
module_init(init_rc_map_imon_mce)
diff --git a/drivers/media/IR/keymaps/rc-imon-pad.c b/drivers/media/rc/keymaps/rc-imon-pad.c
index bc4db72f02e6..eef46b73ca7b 100644
--- a/drivers/media/IR/keymaps/rc-imon-pad.c
+++ b/drivers/media/rc/keymaps/rc-imon-pad.c
@@ -17,7 +17,7 @@
* same remote to different hex codes, and the silkscreened names
* vary a bit between the SoundGraph and Antec remotes... ugh.
*/
-static struct ir_scancode imon_pad[] = {
+static struct rc_map_table imon_pad[] = {
/* keys sorted mostly by frequency of use to optimize lookups */
{ 0x2a8195b7, KEY_REWIND },
{ 0x298315b7, KEY_REWIND },
@@ -129,24 +129,24 @@ static struct ir_scancode imon_pad[] = {
{ 0x29b715b7, KEY_DASHBOARD }, /* AppLauncher */
};
-static struct rc_keymap imon_pad_map = {
+static struct rc_map_list imon_pad_map = {
.map = {
.scan = imon_pad,
.size = ARRAY_SIZE(imon_pad),
/* actual protocol details unknown, hardware decoder */
- .ir_type = IR_TYPE_OTHER,
+ .rc_type = RC_TYPE_OTHER,
.name = RC_MAP_IMON_PAD,
}
};
static int __init init_rc_map_imon_pad(void)
{
- return ir_register_map(&imon_pad_map);
+ return rc_map_register(&imon_pad_map);
}
static void __exit exit_rc_map_imon_pad(void)
{
- ir_unregister_map(&imon_pad_map);
+ rc_map_unregister(&imon_pad_map);
}
module_init(init_rc_map_imon_pad)
diff --git a/drivers/media/IR/keymaps/rc-iodata-bctv7e.c b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
index ef6600259fc0..1f59e163f75d 100644
--- a/drivers/media/IR/keymaps/rc-iodata-bctv7e.c
+++ b/drivers/media/rc/keymaps/rc-iodata-bctv7e.c
@@ -14,7 +14,7 @@
/* IO-DATA BCTV7E Remote */
-static struct ir_scancode iodata_bctv7e[] = {
+static struct rc_map_table iodata_bctv7e[] = {
{ 0x40, KEY_TV },
{ 0x20, KEY_RADIO }, /* FM */
{ 0x60, KEY_EPG },
@@ -62,23 +62,23 @@ static struct ir_scancode iodata_bctv7e[] = {
{ 0x01, KEY_NEXT }, /* skip >| */
};
-static struct rc_keymap iodata_bctv7e_map = {
+static struct rc_map_list iodata_bctv7e_map = {
.map = {
.scan = iodata_bctv7e,
.size = ARRAY_SIZE(iodata_bctv7e),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_IODATA_BCTV7E,
}
};
static int __init init_rc_map_iodata_bctv7e(void)
{
- return ir_register_map(&iodata_bctv7e_map);
+ return rc_map_register(&iodata_bctv7e_map);
}
static void __exit exit_rc_map_iodata_bctv7e(void)
{
- ir_unregister_map(&iodata_bctv7e_map);
+ rc_map_unregister(&iodata_bctv7e_map);
}
module_init(init_rc_map_iodata_bctv7e)
diff --git a/drivers/media/IR/keymaps/rc-kaiomy.c b/drivers/media/rc/keymaps/rc-kaiomy.c
index 4c7883ba0f15..f31dc5c1ad9c 100644
--- a/drivers/media/IR/keymaps/rc-kaiomy.c
+++ b/drivers/media/rc/keymaps/rc-kaiomy.c
@@ -16,7 +16,7 @@
Mauro Carvalho Chehab <mchehab@infradead.org>
*/
-static struct ir_scancode kaiomy[] = {
+static struct rc_map_table kaiomy[] = {
{ 0x43, KEY_POWER2},
{ 0x01, KEY_LIST},
{ 0x0b, KEY_ZOOM},
@@ -61,23 +61,23 @@ static struct ir_scancode kaiomy[] = {
{ 0x1f, KEY_BLUE},
};
-static struct rc_keymap kaiomy_map = {
+static struct rc_map_list kaiomy_map = {
.map = {
.scan = kaiomy,
.size = ARRAY_SIZE(kaiomy),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_KAIOMY,
}
};
static int __init init_rc_map_kaiomy(void)
{
- return ir_register_map(&kaiomy_map);
+ return rc_map_register(&kaiomy_map);
}
static void __exit exit_rc_map_kaiomy(void)
{
- ir_unregister_map(&kaiomy_map);
+ rc_map_unregister(&kaiomy_map);
}
module_init(init_rc_map_kaiomy)
diff --git a/drivers/media/IR/keymaps/rc-kworld-315u.c b/drivers/media/rc/keymaps/rc-kworld-315u.c
index 618c817374e6..3ce6ef79fc34 100644
--- a/drivers/media/IR/keymaps/rc-kworld-315u.c
+++ b/drivers/media/rc/keymaps/rc-kworld-315u.c
@@ -15,7 +15,7 @@
/* Kworld 315U
*/
-static struct ir_scancode kworld_315u[] = {
+static struct rc_map_table kworld_315u[] = {
{ 0x6143, KEY_POWER },
{ 0x6101, KEY_TUNER }, /* source */
{ 0x610b, KEY_ZOOM },
@@ -57,23 +57,23 @@ static struct ir_scancode kworld_315u[] = {
{ 0x611f, KEY_BLUE },
};
-static struct rc_keymap kworld_315u_map = {
+static struct rc_map_list kworld_315u_map = {
.map = {
.scan = kworld_315u,
.size = ARRAY_SIZE(kworld_315u),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_KWORLD_315U,
}
};
static int __init init_rc_map_kworld_315u(void)
{
- return ir_register_map(&kworld_315u_map);
+ return rc_map_register(&kworld_315u_map);
}
static void __exit exit_rc_map_kworld_315u(void)
{
- ir_unregister_map(&kworld_315u_map);
+ rc_map_unregister(&kworld_315u_map);
}
module_init(init_rc_map_kworld_315u)
diff --git a/drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
index 366732f1f7b7..e45f0b8759d0 100644
--- a/drivers/media/IR/keymaps/rc-kworld-plus-tv-analog.c
+++ b/drivers/media/rc/keymaps/rc-kworld-plus-tv-analog.c
@@ -16,7 +16,7 @@
Mauro Carvalho Chehab <mchehab@infradead.org>
*/
-static struct ir_scancode kworld_plus_tv_analog[] = {
+static struct rc_map_table kworld_plus_tv_analog[] = {
{ 0x0c, KEY_PROG1 }, /* Kworld key */
{ 0x16, KEY_CLOSECD }, /* -> ) */
{ 0x1d, KEY_POWER2 },
@@ -73,23 +73,23 @@ static struct ir_scancode kworld_plus_tv_analog[] = {
{ 0x23, KEY_GREEN}, /* C */
};
-static struct rc_keymap kworld_plus_tv_analog_map = {
+static struct rc_map_list kworld_plus_tv_analog_map = {
.map = {
.scan = kworld_plus_tv_analog,
.size = ARRAY_SIZE(kworld_plus_tv_analog),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_KWORLD_PLUS_TV_ANALOG,
}
};
static int __init init_rc_map_kworld_plus_tv_analog(void)
{
- return ir_register_map(&kworld_plus_tv_analog_map);
+ return rc_map_register(&kworld_plus_tv_analog_map);
}
static void __exit exit_rc_map_kworld_plus_tv_analog(void)
{
- ir_unregister_map(&kworld_plus_tv_analog_map);
+ rc_map_unregister(&kworld_plus_tv_analog_map);
}
module_init(init_rc_map_kworld_plus_tv_analog)
diff --git a/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
new file mode 100644
index 000000000000..8faa54ff16e6
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-leadtek-y04g0051.c
@@ -0,0 +1,99 @@
+/*
+ * LeadTek Y04G0051 remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table leadtek_y04g0051[] = {
+ { 0x0300, KEY_POWER2 },
+ { 0x0303, KEY_SCREEN },
+ { 0x0304, KEY_RIGHT },
+ { 0x0305, KEY_1 },
+ { 0x0306, KEY_2 },
+ { 0x0307, KEY_3 },
+ { 0x0308, KEY_LEFT },
+ { 0x0309, KEY_4 },
+ { 0x030a, KEY_5 },
+ { 0x030b, KEY_6 },
+ { 0x030c, KEY_UP },
+ { 0x030d, KEY_7 },
+ { 0x030e, KEY_8 },
+ { 0x030f, KEY_9 },
+ { 0x0310, KEY_DOWN },
+ { 0x0311, KEY_AGAIN },
+ { 0x0312, KEY_0 },
+ { 0x0313, KEY_OK }, /* 1st ok */
+ { 0x0314, KEY_MUTE },
+ { 0x0316, KEY_OK }, /* 2nd ok */
+ { 0x031e, KEY_VIDEO }, /* 2nd video */
+ { 0x031b, KEY_AUDIO },
+ { 0x031f, KEY_TEXT },
+ { 0x0340, KEY_SLEEP },
+ { 0x0341, KEY_DOT },
+ { 0x0342, KEY_REWIND },
+ { 0x0343, KEY_PLAY },
+ { 0x0344, KEY_FASTFORWARD },
+ { 0x0345, KEY_TIME },
+ { 0x0346, KEY_STOP }, /* 2nd stop */
+ { 0x0347, KEY_RECORD },
+ { 0x0348, KEY_CAMERA },
+ { 0x0349, KEY_ESC },
+ { 0x034a, KEY_NEW },
+ { 0x034b, KEY_RED },
+ { 0x034c, KEY_GREEN },
+ { 0x034d, KEY_YELLOW },
+ { 0x034e, KEY_BLUE },
+ { 0x034f, KEY_MENU },
+ { 0x0350, KEY_STOP }, /* 1st stop */
+ { 0x0351, KEY_CHANNEL },
+ { 0x0352, KEY_VIDEO }, /* 1st video */
+ { 0x0353, KEY_EPG },
+ { 0x0354, KEY_PREVIOUS },
+ { 0x0355, KEY_NEXT },
+ { 0x0356, KEY_TV },
+ { 0x035a, KEY_VOLUMEDOWN },
+ { 0x035b, KEY_CHANNELUP },
+ { 0x035e, KEY_VOLUMEUP },
+ { 0x035f, KEY_CHANNELDOWN },
+};
+
+static struct rc_map_list leadtek_y04g0051_map = {
+ .map = {
+ .scan = leadtek_y04g0051,
+ .size = ARRAY_SIZE(leadtek_y04g0051),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_LEADTEK_Y04G0051,
+ }
+};
+
+static int __init init_rc_map_leadtek_y04g0051(void)
+{
+ return rc_map_register(&leadtek_y04g0051_map);
+}
+
+static void __exit exit_rc_map_leadtek_y04g0051(void)
+{
+ rc_map_unregister(&leadtek_y04g0051_map);
+}
+
+module_init(init_rc_map_leadtek_y04g0051)
+module_exit(exit_rc_map_leadtek_y04g0051)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-lirc.c b/drivers/media/rc/keymaps/rc-lirc.c
new file mode 100644
index 000000000000..e8e23e233c39
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-lirc.c
@@ -0,0 +1,41 @@
+/* rc-lirc.c - Empty dummy keytable, for use when its preferred to pass
+ * all raw IR data to the lirc userspace decoder.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-core.h>
+
+static struct rc_map_table lirc[] = {
+ { },
+};
+
+static struct rc_map_list lirc_map = {
+ .map = {
+ .scan = lirc,
+ .size = ARRAY_SIZE(lirc),
+ .rc_type = RC_TYPE_LIRC,
+ .name = RC_MAP_LIRC,
+ }
+};
+
+static int __init init_rc_map_lirc(void)
+{
+ return rc_map_register(&lirc_map);
+}
+
+static void __exit exit_rc_map_lirc(void)
+{
+ rc_map_unregister(&lirc_map);
+}
+
+module_init(init_rc_map_lirc)
+module_exit(exit_rc_map_lirc)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-lme2510.c b/drivers/media/rc/keymaps/rc-lme2510.c
new file mode 100644
index 000000000000..875cd81477c7
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-lme2510.c
@@ -0,0 +1,68 @@
+/* LME2510 remote control
+ *
+ *
+ * Copyright (C) 2010 Malcolm Priestley (tvboxspy@gmail.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+
+static struct rc_map_table lme2510_rc[] = {
+ { 0xba45, KEY_0 },
+ { 0xa05f, KEY_1 },
+ { 0xaf50, KEY_2 },
+ { 0xa25d, KEY_3 },
+ { 0xbe41, KEY_4 },
+ { 0xf50a, KEY_5 },
+ { 0xbd42, KEY_6 },
+ { 0xb847, KEY_7 },
+ { 0xb649, KEY_8 },
+ { 0xfa05, KEY_9 },
+ { 0xbc43, KEY_POWER },
+ { 0xb946, KEY_SUBTITLE },
+ { 0xf906, KEY_PAUSE },
+ { 0xfc03, KEY_MEDIA_REPEAT},
+ { 0xfd02, KEY_PAUSE },
+ { 0xa15e, KEY_VOLUMEUP },
+ { 0xa35c, KEY_VOLUMEDOWN },
+ { 0xf609, KEY_CHANNELUP },
+ { 0xe51a, KEY_CHANNELDOWN },
+ { 0xe11e, KEY_PLAY },
+ { 0xe41b, KEY_ZOOM },
+ { 0xa659, KEY_MUTE },
+ { 0xa55a, KEY_TV },
+ { 0xe718, KEY_RECORD },
+ { 0xf807, KEY_EPG },
+ { 0xfe01, KEY_STOP },
+
+};
+
+static struct rc_map_list lme2510_map = {
+ .map = {
+ .scan = lme2510_rc,
+ .size = ARRAY_SIZE(lme2510_rc),
+ .rc_type = RC_TYPE_UNKNOWN,
+ .name = RC_MAP_LME2510,
+ }
+};
+
+static int __init init_rc_lme2510_map(void)
+{
+ return rc_map_register(&lme2510_map);
+}
+
+static void __exit exit_rc_lme2510_map(void)
+{
+ rc_map_unregister(&lme2510_map);
+}
+
+module_init(init_rc_lme2510_map)
+module_exit(exit_rc_lme2510_map)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Malcolm Priestley tvboxspy@gmail.com");
diff --git a/drivers/media/IR/keymaps/rc-manli.c b/drivers/media/rc/keymaps/rc-manli.c
index 1e9fbfa90a1e..23b2d04e7a9f 100644
--- a/drivers/media/IR/keymaps/rc-manli.c
+++ b/drivers/media/rc/keymaps/rc-manli.c
@@ -13,7 +13,6 @@
#include <media/rc-map.h>
/* Michael Tokarev <mjt@tls.msk.ru>
- http://www.corpit.ru/mjt/beholdTV/remote_control.jpg
keytable is used by MANLI MTV00[0x0c] and BeholdTV 40[13] at
least, and probably other cards too.
The "ascii-art picture" below (in comments, first row
@@ -22,7 +21,7 @@
helps to descide which keycodes to assign to the buttons.
*/
-static struct ir_scancode manli[] = {
+static struct rc_map_table manli[] = {
/* 0x1c 0x12 *
* FUNCTION POWER *
@@ -109,23 +108,23 @@ static struct ir_scancode manli[] = {
/* 0x1d unused ? */
};
-static struct rc_keymap manli_map = {
+static struct rc_map_list manli_map = {
.map = {
.scan = manli,
.size = ARRAY_SIZE(manli),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_MANLI,
}
};
static int __init init_rc_map_manli(void)
{
- return ir_register_map(&manli_map);
+ return rc_map_register(&manli_map);
}
static void __exit exit_rc_map_manli(void)
{
- ir_unregister_map(&manli_map);
+ rc_map_unregister(&manli_map);
}
module_init(init_rc_map_manli)
diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-ii.c b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
new file mode 100644
index 000000000000..7b9a01b6e4cf
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-ii.c
@@ -0,0 +1,67 @@
+/*
+ * MSI DIGIVOX mini II remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table msi_digivox_ii[] = {
+ { 0x0002, KEY_2 },
+ { 0x0003, KEY_UP }, /* up */
+ { 0x0004, KEY_3 },
+ { 0x0005, KEY_CHANNELDOWN },
+ { 0x0008, KEY_5 },
+ { 0x0009, KEY_0 },
+ { 0x000b, KEY_8 },
+ { 0x000d, KEY_DOWN }, /* down */
+ { 0x0010, KEY_9 },
+ { 0x0011, KEY_7 },
+ { 0x0014, KEY_VOLUMEUP },
+ { 0x0015, KEY_CHANNELUP },
+ { 0x0016, KEY_OK },
+ { 0x0017, KEY_POWER2 },
+ { 0x001a, KEY_1 },
+ { 0x001c, KEY_4 },
+ { 0x001d, KEY_6 },
+ { 0x001f, KEY_VOLUMEDOWN },
+};
+
+static struct rc_map_list msi_digivox_ii_map = {
+ .map = {
+ .scan = msi_digivox_ii,
+ .size = ARRAY_SIZE(msi_digivox_ii),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_MSI_DIGIVOX_II,
+ }
+};
+
+static int __init init_rc_map_msi_digivox_ii(void)
+{
+ return rc_map_register(&msi_digivox_ii_map);
+}
+
+static void __exit exit_rc_map_msi_digivox_ii(void)
+{
+ rc_map_unregister(&msi_digivox_ii_map);
+}
+
+module_init(init_rc_map_msi_digivox_ii)
+module_exit(exit_rc_map_msi_digivox_ii)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-msi-digivox-iii.c b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
new file mode 100644
index 000000000000..ae9d06b39157
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-msi-digivox-iii.c
@@ -0,0 +1,85 @@
+/*
+ * MSI DIGIVOX mini III remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* MSI DIGIVOX mini III */
+/* Uses NEC extended 0x61d6. */
+/* This remote seems to be same as rc-kworld-315u.c. Anyhow, add new remote
+ since rc-kworld-315u.c lacks NEC extended address byte. */
+static struct rc_map_table msi_digivox_iii[] = {
+ { 0x61d601, KEY_VIDEO }, /* Source */
+ { 0x61d602, KEY_3 },
+ { 0x61d603, KEY_POWER }, /* ShutDown */
+ { 0x61d604, KEY_1 },
+ { 0x61d605, KEY_5 },
+ { 0x61d606, KEY_6 },
+ { 0x61d607, KEY_CHANNELDOWN }, /* CH- */
+ { 0x61d608, KEY_2 },
+ { 0x61d609, KEY_CHANNELUP }, /* CH+ */
+ { 0x61d60a, KEY_9 },
+ { 0x61d60b, KEY_ZOOM }, /* Zoom */
+ { 0x61d60c, KEY_7 },
+ { 0x61d60d, KEY_8 },
+ { 0x61d60e, KEY_VOLUMEUP }, /* Vol+ */
+ { 0x61d60f, KEY_4 },
+ { 0x61d610, KEY_ESC }, /* [back up arrow] */
+ { 0x61d611, KEY_0 },
+ { 0x61d612, KEY_OK }, /* [enter arrow] */
+ { 0x61d613, KEY_VOLUMEDOWN }, /* Vol- */
+ { 0x61d614, KEY_RECORD }, /* Rec */
+ { 0x61d615, KEY_STOP }, /* Stop */
+ { 0x61d616, KEY_PLAY }, /* Play */
+ { 0x61d617, KEY_MUTE }, /* Mute */
+ { 0x61d618, KEY_UP },
+ { 0x61d619, KEY_DOWN },
+ { 0x61d61a, KEY_LEFT },
+ { 0x61d61b, KEY_RIGHT },
+ { 0x61d61c, KEY_RED },
+ { 0x61d61d, KEY_GREEN },
+ { 0x61d61e, KEY_YELLOW },
+ { 0x61d61f, KEY_BLUE },
+ { 0x61d643, KEY_POWER2 }, /* [red power button] */
+};
+
+static struct rc_map_list msi_digivox_iii_map = {
+ .map = {
+ .scan = msi_digivox_iii,
+ .size = ARRAY_SIZE(msi_digivox_iii),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_MSI_DIGIVOX_III,
+ }
+};
+
+static int __init init_rc_map_msi_digivox_iii(void)
+{
+ return rc_map_register(&msi_digivox_iii_map);
+}
+
+static void __exit exit_rc_map_msi_digivox_iii(void)
+{
+ rc_map_unregister(&msi_digivox_iii_map);
+}
+
+module_init(init_rc_map_msi_digivox_iii)
+module_exit(exit_rc_map_msi_digivox_iii)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
index eb8e42c18ff9..fa8fd0ab94c7 100644
--- a/drivers/media/IR/keymaps/rc-msi-tvanywhere-plus.c
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere-plus.c
@@ -26,7 +26,7 @@
Some changes to formatting and keycodes by Mark Schultz <n9xmj@yahoo.com>
*/
-static struct ir_scancode msi_tvanywhere_plus[] = {
+static struct rc_map_table msi_tvanywhere_plus[] = {
/* ---- Remote Button Layout ----
@@ -97,23 +97,23 @@ static struct ir_scancode msi_tvanywhere_plus[] = {
{ 0x1d, KEY_RESTART }, /* Reset */
};
-static struct rc_keymap msi_tvanywhere_plus_map = {
+static struct rc_map_list msi_tvanywhere_plus_map = {
.map = {
.scan = msi_tvanywhere_plus,
.size = ARRAY_SIZE(msi_tvanywhere_plus),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_MSI_TVANYWHERE_PLUS,
}
};
static int __init init_rc_map_msi_tvanywhere_plus(void)
{
- return ir_register_map(&msi_tvanywhere_plus_map);
+ return rc_map_register(&msi_tvanywhere_plus_map);
}
static void __exit exit_rc_map_msi_tvanywhere_plus(void)
{
- ir_unregister_map(&msi_tvanywhere_plus_map);
+ rc_map_unregister(&msi_tvanywhere_plus_map);
}
module_init(init_rc_map_msi_tvanywhere_plus)
diff --git a/drivers/media/IR/keymaps/rc-msi-tvanywhere.c b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
index ef411854f067..18b37facb0dd 100644
--- a/drivers/media/IR/keymaps/rc-msi-tvanywhere.c
+++ b/drivers/media/rc/keymaps/rc-msi-tvanywhere.c
@@ -14,7 +14,7 @@
/* MSI TV@nywhere MASTER remote */
-static struct ir_scancode msi_tvanywhere[] = {
+static struct rc_map_table msi_tvanywhere[] = {
/* Keys 0 to 9 */
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@@ -43,23 +43,23 @@ static struct ir_scancode msi_tvanywhere[] = {
{ 0x1f, KEY_VOLUMEDOWN },
};
-static struct rc_keymap msi_tvanywhere_map = {
+static struct rc_map_list msi_tvanywhere_map = {
.map = {
.scan = msi_tvanywhere,
.size = ARRAY_SIZE(msi_tvanywhere),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_MSI_TVANYWHERE,
}
};
static int __init init_rc_map_msi_tvanywhere(void)
{
- return ir_register_map(&msi_tvanywhere_map);
+ return rc_map_register(&msi_tvanywhere_map);
}
static void __exit exit_rc_map_msi_tvanywhere(void)
{
- ir_unregister_map(&msi_tvanywhere_map);
+ rc_map_unregister(&msi_tvanywhere_map);
}
module_init(init_rc_map_msi_tvanywhere)
diff --git a/drivers/media/IR/keymaps/rc-nebula.c b/drivers/media/rc/keymaps/rc-nebula.c
index ccc50eb402ec..3e6f077eb700 100644
--- a/drivers/media/IR/keymaps/rc-nebula.c
+++ b/drivers/media/rc/keymaps/rc-nebula.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode nebula[] = {
+static struct rc_map_table nebula[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -70,23 +70,23 @@ static struct ir_scancode nebula[] = {
{ 0x36, KEY_PC },
};
-static struct rc_keymap nebula_map = {
+static struct rc_map_list nebula_map = {
.map = {
.scan = nebula,
.size = ARRAY_SIZE(nebula),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_NEBULA,
}
};
static int __init init_rc_map_nebula(void)
{
- return ir_register_map(&nebula_map);
+ return rc_map_register(&nebula_map);
}
static void __exit exit_rc_map_nebula(void)
{
- ir_unregister_map(&nebula_map);
+ rc_map_unregister(&nebula_map);
}
module_init(init_rc_map_nebula)
diff --git a/drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
index e1b54d20db60..26f114c5c0de 100644
--- a/drivers/media/IR/keymaps/rc-nec-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-nec-terratec-cinergy-xs.c
@@ -16,7 +16,7 @@
Mauro Carvalho Chehab <mchehab@redhat.com>
*/
-static struct ir_scancode nec_terratec_cinergy_xs[] = {
+static struct rc_map_table nec_terratec_cinergy_xs[] = {
{ 0x1441, KEY_HOME},
{ 0x1401, KEY_POWER2},
@@ -79,23 +79,23 @@ static struct ir_scancode nec_terratec_cinergy_xs[] = {
{ 0x145c, KEY_NEXT},
};
-static struct rc_keymap nec_terratec_cinergy_xs_map = {
+static struct rc_map_list nec_terratec_cinergy_xs_map = {
.map = {
.scan = nec_terratec_cinergy_xs,
.size = ARRAY_SIZE(nec_terratec_cinergy_xs),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_NEC_TERRATEC_CINERGY_XS,
}
};
static int __init init_rc_map_nec_terratec_cinergy_xs(void)
{
- return ir_register_map(&nec_terratec_cinergy_xs_map);
+ return rc_map_register(&nec_terratec_cinergy_xs_map);
}
static void __exit exit_rc_map_nec_terratec_cinergy_xs(void)
{
- ir_unregister_map(&nec_terratec_cinergy_xs_map);
+ rc_map_unregister(&nec_terratec_cinergy_xs_map);
}
module_init(init_rc_map_nec_terratec_cinergy_xs)
diff --git a/drivers/media/IR/keymaps/rc-norwood.c b/drivers/media/rc/keymaps/rc-norwood.c
index e5849a6b3f05..629ee9d84537 100644
--- a/drivers/media/IR/keymaps/rc-norwood.c
+++ b/drivers/media/rc/keymaps/rc-norwood.c
@@ -16,7 +16,7 @@
By Peter Naulls <peter@chocky.org>
Key comments are the functions given in the manual */
-static struct ir_scancode norwood[] = {
+static struct rc_map_table norwood[] = {
/* Keys 0 to 9 */
{ 0x20, KEY_0 },
{ 0x21, KEY_1 },
@@ -59,23 +59,23 @@ static struct ir_scancode norwood[] = {
{ 0x65, KEY_POWER }, /* Computer power */
};
-static struct rc_keymap norwood_map = {
+static struct rc_map_list norwood_map = {
.map = {
.scan = norwood,
.size = ARRAY_SIZE(norwood),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_NORWOOD,
}
};
static int __init init_rc_map_norwood(void)
{
- return ir_register_map(&norwood_map);
+ return rc_map_register(&norwood_map);
}
static void __exit exit_rc_map_norwood(void)
{
- ir_unregister_map(&norwood_map);
+ rc_map_unregister(&norwood_map);
}
module_init(init_rc_map_norwood)
diff --git a/drivers/media/IR/keymaps/rc-npgtech.c b/drivers/media/rc/keymaps/rc-npgtech.c
index b9ece1e90296..4aa588bf6d69 100644
--- a/drivers/media/IR/keymaps/rc-npgtech.c
+++ b/drivers/media/rc/keymaps/rc-npgtech.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode npgtech[] = {
+static struct rc_map_table npgtech[] = {
{ 0x1d, KEY_SWITCHVIDEOMODE }, /* switch inputs */
{ 0x2a, KEY_FRONT },
@@ -54,23 +54,23 @@ static struct ir_scancode npgtech[] = {
};
-static struct rc_keymap npgtech_map = {
+static struct rc_map_list npgtech_map = {
.map = {
.scan = npgtech,
.size = ARRAY_SIZE(npgtech),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_NPGTECH,
}
};
static int __init init_rc_map_npgtech(void)
{
- return ir_register_map(&npgtech_map);
+ return rc_map_register(&npgtech_map);
}
static void __exit exit_rc_map_npgtech(void)
{
- ir_unregister_map(&npgtech_map);
+ rc_map_unregister(&npgtech_map);
}
module_init(init_rc_map_npgtech)
diff --git a/drivers/media/IR/keymaps/rc-pctv-sedna.c b/drivers/media/rc/keymaps/rc-pctv-sedna.c
index 4129bb44a25b..fa5ae5981eb8 100644
--- a/drivers/media/IR/keymaps/rc-pctv-sedna.c
+++ b/drivers/media/rc/keymaps/rc-pctv-sedna.c
@@ -17,7 +17,7 @@
Pavel Mihaylov <bin@bash.info>
Also for the remote bundled with Kozumi KTV-01C card */
-static struct ir_scancode pctv_sedna[] = {
+static struct rc_map_table pctv_sedna[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -54,23 +54,23 @@ static struct ir_scancode pctv_sedna[] = {
{ 0x1f, KEY_PLAY }, /* Play */
};
-static struct rc_keymap pctv_sedna_map = {
+static struct rc_map_list pctv_sedna_map = {
.map = {
.scan = pctv_sedna,
.size = ARRAY_SIZE(pctv_sedna),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PCTV_SEDNA,
}
};
static int __init init_rc_map_pctv_sedna(void)
{
- return ir_register_map(&pctv_sedna_map);
+ return rc_map_register(&pctv_sedna_map);
}
static void __exit exit_rc_map_pctv_sedna(void)
{
- ir_unregister_map(&pctv_sedna_map);
+ rc_map_unregister(&pctv_sedna_map);
}
module_init(init_rc_map_pctv_sedna)
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-color.c b/drivers/media/rc/keymaps/rc-pinnacle-color.c
index 326e023ce126..23b8c505c6aa 100644
--- a/drivers/media/IR/keymaps/rc-pinnacle-color.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-color.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode pinnacle_color[] = {
+static struct rc_map_table pinnacle_color[] = {
{ 0x59, KEY_MUTE },
{ 0x4a, KEY_POWER },
@@ -68,23 +68,23 @@ static struct ir_scancode pinnacle_color[] = {
{ 0x0a, KEY_BACKSPACE },
};
-static struct rc_keymap pinnacle_color_map = {
+static struct rc_map_list pinnacle_color_map = {
.map = {
.scan = pinnacle_color,
.size = ARRAY_SIZE(pinnacle_color),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PINNACLE_COLOR,
}
};
static int __init init_rc_map_pinnacle_color(void)
{
- return ir_register_map(&pinnacle_color_map);
+ return rc_map_register(&pinnacle_color_map);
}
static void __exit exit_rc_map_pinnacle_color(void)
{
- ir_unregister_map(&pinnacle_color_map);
+ rc_map_unregister(&pinnacle_color_map);
}
module_init(init_rc_map_pinnacle_color)
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-grey.c b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
index 14cb772515c6..6ba8c368d10a 100644
--- a/drivers/media/IR/keymaps/rc-pinnacle-grey.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-grey.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode pinnacle_grey[] = {
+static struct rc_map_table pinnacle_grey[] = {
{ 0x3a, KEY_0 },
{ 0x31, KEY_1 },
{ 0x32, KEY_2 },
@@ -63,23 +63,23 @@ static struct ir_scancode pinnacle_grey[] = {
{ 0x18, KEY_EPG },
};
-static struct rc_keymap pinnacle_grey_map = {
+static struct rc_map_list pinnacle_grey_map = {
.map = {
.scan = pinnacle_grey,
.size = ARRAY_SIZE(pinnacle_grey),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PINNACLE_GREY,
}
};
static int __init init_rc_map_pinnacle_grey(void)
{
- return ir_register_map(&pinnacle_grey_map);
+ return rc_map_register(&pinnacle_grey_map);
}
static void __exit exit_rc_map_pinnacle_grey(void)
{
- ir_unregister_map(&pinnacle_grey_map);
+ rc_map_unregister(&pinnacle_grey_map);
}
module_init(init_rc_map_pinnacle_grey)
diff --git a/drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
index 835bf4ef8de7..bb10ffe086b4 100644
--- a/drivers/media/IR/keymaps/rc-pinnacle-pctv-hd.c
+++ b/drivers/media/rc/keymaps/rc-pinnacle-pctv-hd.c
@@ -14,7 +14,7 @@
/* Pinnacle PCTV HD 800i mini remote */
-static struct ir_scancode pinnacle_pctv_hd[] = {
+static struct rc_map_table pinnacle_pctv_hd[] = {
{ 0x0f, KEY_1 },
{ 0x15, KEY_2 },
@@ -47,23 +47,23 @@ static struct ir_scancode pinnacle_pctv_hd[] = {
{ 0x3f, KEY_EPG }, /* Labeled "?" */
};
-static struct rc_keymap pinnacle_pctv_hd_map = {
+static struct rc_map_list pinnacle_pctv_hd_map = {
.map = {
.scan = pinnacle_pctv_hd,
.size = ARRAY_SIZE(pinnacle_pctv_hd),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PINNACLE_PCTV_HD,
}
};
static int __init init_rc_map_pinnacle_pctv_hd(void)
{
- return ir_register_map(&pinnacle_pctv_hd_map);
+ return rc_map_register(&pinnacle_pctv_hd_map);
}
static void __exit exit_rc_map_pinnacle_pctv_hd(void)
{
- ir_unregister_map(&pinnacle_pctv_hd_map);
+ rc_map_unregister(&pinnacle_pctv_hd_map);
}
module_init(init_rc_map_pinnacle_pctv_hd)
diff --git a/drivers/media/rc/keymaps/rc-pixelview-002t.c b/drivers/media/rc/keymaps/rc-pixelview-002t.c
new file mode 100644
index 000000000000..e5ab071f635a
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-pixelview-002t.c
@@ -0,0 +1,77 @@
+/* rc-pixelview-mk12.h - Keytable for pixelview Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/*
+ * Keytable for 002-T IR remote provided together with Pixelview
+ * SBTVD Hybrid Remote Controller. Uses NEC extended format.
+ */
+static struct rc_map_table pixelview_002t[] = {
+ { 0x866b13, KEY_MUTE },
+ { 0x866b12, KEY_POWER2 }, /* power */
+
+ { 0x866b01, KEY_1 },
+ { 0x866b02, KEY_2 },
+ { 0x866b03, KEY_3 },
+ { 0x866b04, KEY_4 },
+ { 0x866b05, KEY_5 },
+ { 0x866b06, KEY_6 },
+ { 0x866b07, KEY_7 },
+ { 0x866b08, KEY_8 },
+ { 0x866b09, KEY_9 },
+ { 0x866b00, KEY_0 },
+
+ { 0x866b0d, KEY_CHANNELUP },
+ { 0x866b19, KEY_CHANNELDOWN },
+ { 0x866b10, KEY_VOLUMEUP }, /* vol + */
+ { 0x866b0c, KEY_VOLUMEDOWN }, /* vol - */
+
+ { 0x866b0a, KEY_CAMERA }, /* snapshot */
+ { 0x866b0b, KEY_ZOOM }, /* zoom */
+
+ { 0x866b1b, KEY_BACKSPACE },
+ { 0x866b15, KEY_ENTER },
+
+ { 0x866b1d, KEY_UP },
+ { 0x866b1e, KEY_DOWN },
+ { 0x866b0e, KEY_LEFT },
+ { 0x866b0f, KEY_RIGHT },
+
+ { 0x866b18, KEY_RECORD },
+ { 0x866b1a, KEY_STOP },
+};
+
+static struct rc_map_list pixelview_map = {
+ .map = {
+ .scan = pixelview_002t,
+ .size = ARRAY_SIZE(pixelview_002t),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_PIXELVIEW_002T,
+ }
+};
+
+static int __init init_rc_map_pixelview(void)
+{
+ return rc_map_register(&pixelview_map);
+}
+
+static void __exit exit_rc_map_pixelview(void)
+{
+ rc_map_unregister(&pixelview_map);
+}
+
+module_init(init_rc_map_pixelview)
+module_exit(exit_rc_map_pixelview)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-pixelview-mk12.c b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
index 5a735d569a8b..8d9f664e0a2d 100644
--- a/drivers/media/IR/keymaps/rc-pixelview-mk12.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-mk12.c
@@ -16,7 +16,7 @@
* Keytable for MK-F12 IR remote provided together with Pixelview
* Ultra Pro Remote Controller. Uses NEC extended format.
*/
-static struct ir_scancode pixelview_mk12[] = {
+static struct rc_map_table pixelview_mk12[] = {
{ 0x866b03, KEY_TUNER }, /* Timeshift */
{ 0x866b1e, KEY_POWER2 }, /* power */
@@ -57,23 +57,23 @@ static struct ir_scancode pixelview_mk12[] = {
{ 0x866b07, KEY_RADIO }, /* FM */
};
-static struct rc_keymap pixelview_map = {
+static struct rc_map_list pixelview_map = {
.map = {
.scan = pixelview_mk12,
.size = ARRAY_SIZE(pixelview_mk12),
- .ir_type = IR_TYPE_NEC,
+ .rc_type = RC_TYPE_NEC,
.name = RC_MAP_PIXELVIEW_MK12,
}
};
static int __init init_rc_map_pixelview(void)
{
- return ir_register_map(&pixelview_map);
+ return rc_map_register(&pixelview_map);
}
static void __exit exit_rc_map_pixelview(void)
{
- ir_unregister_map(&pixelview_map);
+ rc_map_unregister(&pixelview_map);
}
module_init(init_rc_map_pixelview)
diff --git a/drivers/media/IR/keymaps/rc-pixelview-new.c b/drivers/media/rc/keymaps/rc-pixelview-new.c
index 7bbbbf5735e6..777a70076be2 100644
--- a/drivers/media/IR/keymaps/rc-pixelview-new.c
+++ b/drivers/media/rc/keymaps/rc-pixelview-new.c
@@ -17,7 +17,7 @@
present on PV MPEG 8000GT
*/
-static struct ir_scancode pixelview_new[] = {
+static struct rc_map_table pixelview_new[] = {
{ 0x3c, KEY_TIME }, /* Timeshift */
{ 0x12, KEY_POWER },
@@ -57,23 +57,23 @@ static struct ir_scancode pixelview_new[] = {
{ 0x34, KEY_RADIO },
};
-static struct rc_keymap pixelview_new_map = {
+static struct rc_map_list pixelview_new_map = {
.map = {
.scan = pixelview_new,
.size = ARRAY_SIZE(pixelview_new),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PIXELVIEW_NEW,
}
};
static int __init init_rc_map_pixelview_new(void)
{
- return ir_register_map(&pixelview_new_map);
+ return rc_map_register(&pixelview_new_map);
}
static void __exit exit_rc_map_pixelview_new(void)
{
- ir_unregister_map(&pixelview_new_map);
+ rc_map_unregister(&pixelview_new_map);
}
module_init(init_rc_map_pixelview_new)
diff --git a/drivers/media/IR/keymaps/rc-pixelview.c b/drivers/media/rc/keymaps/rc-pixelview.c
index 82ff12e182a0..0ec5988916b9 100644
--- a/drivers/media/IR/keymaps/rc-pixelview.c
+++ b/drivers/media/rc/keymaps/rc-pixelview.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode pixelview[] = {
+static struct rc_map_table pixelview[] = {
{ 0x1e, KEY_POWER }, /* power */
{ 0x07, KEY_MEDIA }, /* source */
@@ -56,23 +56,23 @@ static struct ir_scancode pixelview[] = {
{ 0x18, KEY_MUTE }, /* mute/unmute */
};
-static struct rc_keymap pixelview_map = {
+static struct rc_map_list pixelview_map = {
.map = {
.scan = pixelview,
.size = ARRAY_SIZE(pixelview),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PIXELVIEW,
}
};
static int __init init_rc_map_pixelview(void)
{
- return ir_register_map(&pixelview_map);
+ return rc_map_register(&pixelview_map);
}
static void __exit exit_rc_map_pixelview(void)
{
- ir_unregister_map(&pixelview_map);
+ rc_map_unregister(&pixelview_map);
}
module_init(init_rc_map_pixelview)
diff --git a/drivers/media/IR/keymaps/rc-powercolor-real-angel.c b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
index 7cef8190a224..5f9d546a86c4 100644
--- a/drivers/media/IR/keymaps/rc-powercolor-real-angel.c
+++ b/drivers/media/rc/keymaps/rc-powercolor-real-angel.c
@@ -17,7 +17,7 @@
* Daniel Fraga <fragabr@gmail.com>
*/
-static struct ir_scancode powercolor_real_angel[] = {
+static struct rc_map_table powercolor_real_angel[] = {
{ 0x38, KEY_SWITCHVIDEOMODE }, /* switch inputs */
{ 0x0c, KEY_MEDIA }, /* Turn ON/OFF App */
{ 0x00, KEY_0 },
@@ -55,23 +55,23 @@ static struct ir_scancode powercolor_real_angel[] = {
{ 0x25, KEY_POWER }, /* power */
};
-static struct rc_keymap powercolor_real_angel_map = {
+static struct rc_map_list powercolor_real_angel_map = {
.map = {
.scan = powercolor_real_angel,
.size = ARRAY_SIZE(powercolor_real_angel),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_POWERCOLOR_REAL_ANGEL,
}
};
static int __init init_rc_map_powercolor_real_angel(void)
{
- return ir_register_map(&powercolor_real_angel_map);
+ return rc_map_register(&powercolor_real_angel_map);
}
static void __exit exit_rc_map_powercolor_real_angel(void)
{
- ir_unregister_map(&powercolor_real_angel_map);
+ rc_map_unregister(&powercolor_real_angel_map);
}
module_init(init_rc_map_powercolor_real_angel)
diff --git a/drivers/media/IR/keymaps/rc-proteus-2309.c b/drivers/media/rc/keymaps/rc-proteus-2309.c
index 22e92d39dee5..8a3a643879d4 100644
--- a/drivers/media/IR/keymaps/rc-proteus-2309.c
+++ b/drivers/media/rc/keymaps/rc-proteus-2309.c
@@ -14,7 +14,7 @@
/* Michal Majchrowicz <mmajchrowicz@gmail.com> */
-static struct ir_scancode proteus_2309[] = {
+static struct rc_map_table proteus_2309[] = {
/* numeric */
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@@ -43,23 +43,23 @@ static struct ir_scancode proteus_2309[] = {
{ 0x14, KEY_F1 },
};
-static struct rc_keymap proteus_2309_map = {
+static struct rc_map_list proteus_2309_map = {
.map = {
.scan = proteus_2309,
.size = ARRAY_SIZE(proteus_2309),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PROTEUS_2309,
}
};
static int __init init_rc_map_proteus_2309(void)
{
- return ir_register_map(&proteus_2309_map);
+ return rc_map_register(&proteus_2309_map);
}
static void __exit exit_rc_map_proteus_2309(void)
{
- ir_unregister_map(&proteus_2309_map);
+ rc_map_unregister(&proteus_2309_map);
}
module_init(init_rc_map_proteus_2309)
diff --git a/drivers/media/IR/keymaps/rc-purpletv.c b/drivers/media/rc/keymaps/rc-purpletv.c
index 4e20fc2269f7..ef90296bfd68 100644
--- a/drivers/media/IR/keymaps/rc-purpletv.c
+++ b/drivers/media/rc/keymaps/rc-purpletv.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode purpletv[] = {
+static struct rc_map_table purpletv[] = {
{ 0x03, KEY_POWER },
{ 0x6f, KEY_MUTE },
{ 0x10, KEY_BACKSPACE }, /* Recall */
@@ -55,23 +55,23 @@ static struct ir_scancode purpletv[] = {
};
-static struct rc_keymap purpletv_map = {
+static struct rc_map_list purpletv_map = {
.map = {
.scan = purpletv,
.size = ARRAY_SIZE(purpletv),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PURPLETV,
}
};
static int __init init_rc_map_purpletv(void)
{
- return ir_register_map(&purpletv_map);
+ return rc_map_register(&purpletv_map);
}
static void __exit exit_rc_map_purpletv(void)
{
- ir_unregister_map(&purpletv_map);
+ rc_map_unregister(&purpletv_map);
}
module_init(init_rc_map_purpletv)
diff --git a/drivers/media/IR/keymaps/rc-pv951.c b/drivers/media/rc/keymaps/rc-pv951.c
index 36679e706cf3..83a418de12c6 100644
--- a/drivers/media/IR/keymaps/rc-pv951.c
+++ b/drivers/media/rc/keymaps/rc-pv951.c
@@ -14,7 +14,7 @@
/* Mark Phalan <phalanm@o2.ie> */
-static struct ir_scancode pv951[] = {
+static struct rc_map_table pv951[] = {
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
{ 0x02, KEY_2 },
@@ -52,23 +52,23 @@ static struct ir_scancode pv951[] = {
{ 0x1c, KEY_MEDIA }, /* PC/TV */
};
-static struct rc_keymap pv951_map = {
+static struct rc_map_list pv951_map = {
.map = {
.scan = pv951,
.size = ARRAY_SIZE(pv951),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_PV951,
}
};
static int __init init_rc_map_pv951(void)
{
- return ir_register_map(&pv951_map);
+ return rc_map_register(&pv951_map);
}
static void __exit exit_rc_map_pv951(void)
{
- ir_unregister_map(&pv951_map);
+ rc_map_unregister(&pv951_map);
}
module_init(init_rc_map_pv951)
diff --git a/drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c
index cc6b8f548747..dfc9b15f43a9 100644
--- a/drivers/media/IR/keymaps/rc-rc5-hauppauge-new.c
+++ b/drivers/media/rc/keymaps/rc-rc5-hauppauge-new.c
@@ -19,7 +19,7 @@
* This table contains the complete RC5 code, instead of just the data part
*/
-static struct ir_scancode rc5_hauppauge_new[] = {
+static struct rc_map_table rc5_hauppauge_new[] = {
/* Keys 0 to 9 */
{ 0x1e00, KEY_0 },
{ 0x1e01, KEY_1 },
@@ -75,25 +75,63 @@ static struct ir_scancode rc5_hauppauge_new[] = {
{ 0x1e3b, KEY_SELECT }, /* top right button */
{ 0x1e3c, KEY_ZOOM }, /* full */
{ 0x1e3d, KEY_POWER }, /* system power (green button) */
+
+ /* Keycodes for DSR-0112 remote bundled with Haupauge MiniStick */
+ { 0x1d00, KEY_0 },
+ { 0x1d01, KEY_1 },
+ { 0x1d02, KEY_2 },
+ { 0x1d03, KEY_3 },
+ { 0x1d04, KEY_4 },
+ { 0x1d05, KEY_5 },
+ { 0x1d06, KEY_6 },
+ { 0x1d07, KEY_7 },
+ { 0x1d08, KEY_8 },
+ { 0x1d09, KEY_9 },
+ { 0x1d0a, KEY_TEXT },
+ { 0x1d0d, KEY_MENU },
+ { 0x1d0f, KEY_MUTE },
+ { 0x1d10, KEY_VOLUMEUP },
+ { 0x1d11, KEY_VOLUMEDOWN },
+ { 0x1d12, KEY_PREVIOUS }, /* Prev.Ch .. ??? */
+ { 0x1d14, KEY_UP },
+ { 0x1d15, KEY_DOWN },
+ { 0x1d16, KEY_LEFT },
+ { 0x1d17, KEY_RIGHT },
+ { 0x1d1c, KEY_TV },
+ { 0x1d1e, KEY_NEXT }, /* >| */
+ { 0x1d1f, KEY_EXIT },
+ { 0x1d20, KEY_CHANNELUP },
+ { 0x1d21, KEY_CHANNELDOWN },
+ { 0x1d24, KEY_LAST }, /* <| */
+ { 0x1d25, KEY_OK },
+ { 0x1d30, KEY_PAUSE },
+ { 0x1d32, KEY_REWIND },
+ { 0x1d34, KEY_FASTFORWARD },
+ { 0x1d35, KEY_PLAY },
+ { 0x1d36, KEY_STOP },
+ { 0x1d37, KEY_RECORD },
+ { 0x1d3b, KEY_GOTO },
+ { 0x1d3d, KEY_POWER },
+ { 0x1d3f, KEY_HOME },
};
-static struct rc_keymap rc5_hauppauge_new_map = {
+static struct rc_map_list rc5_hauppauge_new_map = {
.map = {
.scan = rc5_hauppauge_new,
.size = ARRAY_SIZE(rc5_hauppauge_new),
- .ir_type = IR_TYPE_RC5,
+ .rc_type = RC_TYPE_RC5,
.name = RC_MAP_RC5_HAUPPAUGE_NEW,
}
};
static int __init init_rc_map_rc5_hauppauge_new(void)
{
- return ir_register_map(&rc5_hauppauge_new_map);
+ return rc_map_register(&rc5_hauppauge_new_map);
}
static void __exit exit_rc_map_rc5_hauppauge_new(void)
{
- ir_unregister_map(&rc5_hauppauge_new_map);
+ rc_map_unregister(&rc5_hauppauge_new_map);
}
module_init(init_rc_map_rc5_hauppauge_new)
diff --git a/drivers/media/IR/keymaps/rc-rc5-tv.c b/drivers/media/rc/keymaps/rc-rc5-tv.c
index 73cce2f8ddfb..4fcef9f1f721 100644
--- a/drivers/media/IR/keymaps/rc-rc5-tv.c
+++ b/drivers/media/rc/keymaps/rc-rc5-tv.c
@@ -16,7 +16,7 @@
/* see http://users.pandora.be/nenya/electronics/rc5/codes00.htm */
/* used by old (black) Hauppauge remotes */
-static struct ir_scancode rc5_tv[] = {
+static struct rc_map_table rc5_tv[] = {
/* Keys 0 to 9 */
{ 0x00, KEY_0 },
{ 0x01, KEY_1 },
@@ -55,23 +55,23 @@ static struct ir_scancode rc5_tv[] = {
};
-static struct rc_keymap rc5_tv_map = {
+static struct rc_map_list rc5_tv_map = {
.map = {
.scan = rc5_tv,
.size = ARRAY_SIZE(rc5_tv),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_RC5_TV,
}
};
static int __init init_rc_map_rc5_tv(void)
{
- return ir_register_map(&rc5_tv_map);
+ return rc_map_register(&rc5_tv_map);
}
static void __exit exit_rc_map_rc5_tv(void)
{
- ir_unregister_map(&rc5_tv_map);
+ rc_map_unregister(&rc5_tv_map);
}
module_init(init_rc_map_rc5_tv)
diff --git a/drivers/media/rc/keymaps/rc-rc6-mce.c b/drivers/media/rc/keymaps/rc-rc6-mce.c
new file mode 100644
index 000000000000..3bf3337875d1
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-rc6-mce.c
@@ -0,0 +1,113 @@
+/* rc-rc6-mce.c - Keytable for Windows Media Center RC-6 remotes for use
+ * with the Media Center Edition eHome Infrared Transceiver.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table rc6_mce[] = {
+
+ { 0x800f0400, KEY_NUMERIC_0 },
+ { 0x800f0401, KEY_NUMERIC_1 },
+ { 0x800f0402, KEY_NUMERIC_2 },
+ { 0x800f0403, KEY_NUMERIC_3 },
+ { 0x800f0404, KEY_NUMERIC_4 },
+ { 0x800f0405, KEY_NUMERIC_5 },
+ { 0x800f0406, KEY_NUMERIC_6 },
+ { 0x800f0407, KEY_NUMERIC_7 },
+ { 0x800f0408, KEY_NUMERIC_8 },
+ { 0x800f0409, KEY_NUMERIC_9 },
+
+ { 0x800f040a, KEY_DELETE },
+ { 0x800f040b, KEY_ENTER },
+ { 0x800f040c, KEY_POWER }, /* PC Power */
+ { 0x800f040d, KEY_PROG1 }, /* Windows MCE button */
+ { 0x800f040e, KEY_MUTE },
+ { 0x800f040f, KEY_INFO },
+
+ { 0x800f0410, KEY_VOLUMEUP },
+ { 0x800f0411, KEY_VOLUMEDOWN },
+ { 0x800f0412, KEY_CHANNELUP },
+ { 0x800f0413, KEY_CHANNELDOWN },
+
+ { 0x800f0414, KEY_FASTFORWARD },
+ { 0x800f0415, KEY_REWIND },
+ { 0x800f0416, KEY_PLAY },
+ { 0x800f0417, KEY_RECORD },
+ { 0x800f0418, KEY_PAUSE },
+ { 0x800f046e, KEY_PLAYPAUSE },
+ { 0x800f0419, KEY_STOP },
+ { 0x800f041a, KEY_NEXT },
+ { 0x800f041b, KEY_PREVIOUS },
+ { 0x800f041c, KEY_NUMERIC_POUND },
+ { 0x800f041d, KEY_NUMERIC_STAR },
+
+ { 0x800f041e, KEY_UP },
+ { 0x800f041f, KEY_DOWN },
+ { 0x800f0420, KEY_LEFT },
+ { 0x800f0421, KEY_RIGHT },
+
+ { 0x800f0422, KEY_OK },
+ { 0x800f0423, KEY_EXIT },
+ { 0x800f0424, KEY_DVD },
+ { 0x800f0425, KEY_TUNER }, /* LiveTV */
+ { 0x800f0426, KEY_EPG }, /* Guide */
+ { 0x800f0427, KEY_ZOOM }, /* Aspect */
+
+ { 0x800f043a, KEY_BRIGHTNESSUP },
+
+ { 0x800f0446, KEY_TV },
+ { 0x800f0447, KEY_AUDIO }, /* My Music */
+ { 0x800f0448, KEY_PVR }, /* RecordedTV */
+ { 0x800f0449, KEY_CAMERA },
+ { 0x800f044a, KEY_VIDEO },
+ { 0x800f044c, KEY_LANGUAGE },
+ { 0x800f044d, KEY_TITLE },
+ { 0x800f044e, KEY_PRINT }, /* Print - HP OEM version of remote */
+
+ { 0x800f0450, KEY_RADIO },
+
+ { 0x800f045a, KEY_SUBTITLE }, /* Caption/Teletext */
+ { 0x800f045b, KEY_RED },
+ { 0x800f045c, KEY_GREEN },
+ { 0x800f045d, KEY_YELLOW },
+ { 0x800f045e, KEY_BLUE },
+
+ { 0x800f0465, KEY_POWER2 }, /* TV Power */
+ { 0x800f046e, KEY_PLAYPAUSE },
+ { 0x800f046f, KEY_MEDIA }, /* Start media application (NEW) */
+
+ { 0x800f0480, KEY_BRIGHTNESSDOWN },
+ { 0x800f0481, KEY_PLAYPAUSE },
+};
+
+static struct rc_map_list rc6_mce_map = {
+ .map = {
+ .scan = rc6_mce,
+ .size = ARRAY_SIZE(rc6_mce),
+ .rc_type = RC_TYPE_RC6,
+ .name = RC_MAP_RC6_MCE,
+ }
+};
+
+static int __init init_rc_map_rc6_mce(void)
+{
+ return rc_map_register(&rc6_mce_map);
+}
+
+static void __exit exit_rc_map_rc6_mce(void)
+{
+ rc_map_unregister(&rc6_mce_map);
+}
+
+module_init(init_rc_map_rc6_mce)
+module_exit(exit_rc_map_rc6_mce)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
index ab1a6d2baf72..2d14598592d8 100644
--- a/drivers/media/IR/keymaps/rc-real-audio-220-32-keys.c
+++ b/drivers/media/rc/keymaps/rc-real-audio-220-32-keys.c
@@ -14,7 +14,7 @@
/* Zogis Real Audio 220 - 32 keys IR */
-static struct ir_scancode real_audio_220_32_keys[] = {
+static struct rc_map_table real_audio_220_32_keys[] = {
{ 0x1c, KEY_RADIO},
{ 0x12, KEY_POWER2},
@@ -52,23 +52,23 @@ static struct ir_scancode real_audio_220_32_keys[] = {
};
-static struct rc_keymap real_audio_220_32_keys_map = {
+static struct rc_map_list real_audio_220_32_keys_map = {
.map = {
.scan = real_audio_220_32_keys,
.size = ARRAY_SIZE(real_audio_220_32_keys),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_REAL_AUDIO_220_32_KEYS,
}
};
static int __init init_rc_map_real_audio_220_32_keys(void)
{
- return ir_register_map(&real_audio_220_32_keys_map);
+ return rc_map_register(&real_audio_220_32_keys_map);
}
static void __exit exit_rc_map_real_audio_220_32_keys(void)
{
- ir_unregister_map(&real_audio_220_32_keys_map);
+ rc_map_unregister(&real_audio_220_32_keys_map);
}
module_init(init_rc_map_real_audio_220_32_keys)
diff --git a/drivers/media/rc/keymaps/rc-streamzap.c b/drivers/media/rc/keymaps/rc-streamzap.c
new file mode 100644
index 000000000000..92cc10d2f9cd
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-streamzap.c
@@ -0,0 +1,82 @@
+/* rc-streamzap.c - Keytable for Streamzap PC Remote, for use
+ * with the Streamzap PC Remote IR Receiver.
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table streamzap[] = {
+/*
+ * The Streamzap remote is almost, but not quite, RC-5, as it has an extra
+ * bit in it, which throws the in-kernel RC-5 decoder for a loop. Currently,
+ * an additional RC-5-sz decoder is being deployed to support it, but it
+ * may be possible to merge it back with the standard RC-5 decoder.
+ */
+ { 0x28c0, KEY_NUMERIC_0 },
+ { 0x28c1, KEY_NUMERIC_1 },
+ { 0x28c2, KEY_NUMERIC_2 },
+ { 0x28c3, KEY_NUMERIC_3 },
+ { 0x28c4, KEY_NUMERIC_4 },
+ { 0x28c5, KEY_NUMERIC_5 },
+ { 0x28c6, KEY_NUMERIC_6 },
+ { 0x28c7, KEY_NUMERIC_7 },
+ { 0x28c8, KEY_NUMERIC_8 },
+ { 0x28c9, KEY_NUMERIC_9 },
+ { 0x28ca, KEY_POWER },
+ { 0x28cb, KEY_MUTE },
+ { 0x28cc, KEY_CHANNELUP },
+ { 0x28cd, KEY_VOLUMEUP },
+ { 0x28ce, KEY_CHANNELDOWN },
+ { 0x28cf, KEY_VOLUMEDOWN },
+ { 0x28d0, KEY_UP },
+ { 0x28d1, KEY_LEFT },
+ { 0x28d2, KEY_OK },
+ { 0x28d3, KEY_RIGHT },
+ { 0x28d4, KEY_DOWN },
+ { 0x28d5, KEY_MENU },
+ { 0x28d6, KEY_EXIT },
+ { 0x28d7, KEY_PLAY },
+ { 0x28d8, KEY_PAUSE },
+ { 0x28d9, KEY_STOP },
+ { 0x28da, KEY_BACK },
+ { 0x28db, KEY_FORWARD },
+ { 0x28dc, KEY_RECORD },
+ { 0x28dd, KEY_REWIND },
+ { 0x28de, KEY_FASTFORWARD },
+ { 0x28e0, KEY_RED },
+ { 0x28e1, KEY_GREEN },
+ { 0x28e2, KEY_YELLOW },
+ { 0x28e3, KEY_BLUE },
+
+};
+
+static struct rc_map_list streamzap_map = {
+ .map = {
+ .scan = streamzap,
+ .size = ARRAY_SIZE(streamzap),
+ .rc_type = RC_TYPE_RC5_SZ,
+ .name = RC_MAP_STREAMZAP,
+ }
+};
+
+static int __init init_rc_map_streamzap(void)
+{
+ return rc_map_register(&streamzap_map);
+}
+
+static void __exit exit_rc_map_streamzap(void)
+{
+ rc_map_unregister(&streamzap_map);
+}
+
+module_init(init_rc_map_streamzap)
+module_exit(exit_rc_map_streamzap)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-tbs-nec.c b/drivers/media/rc/keymaps/rc-tbs-nec.c
new file mode 100644
index 000000000000..7242ee66f6e0
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-tbs-nec.c
@@ -0,0 +1,75 @@
+/* tbs-nec.h - Keytable for tbs_nec Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table tbs_nec[] = {
+ { 0x84, KEY_POWER2}, /* power */
+ { 0x94, KEY_MUTE}, /* mute */
+ { 0x87, KEY_1},
+ { 0x86, KEY_2},
+ { 0x85, KEY_3},
+ { 0x8b, KEY_4},
+ { 0x8a, KEY_5},
+ { 0x89, KEY_6},
+ { 0x8f, KEY_7},
+ { 0x8e, KEY_8},
+ { 0x8d, KEY_9},
+ { 0x92, KEY_0},
+ { 0xc0, KEY_10CHANNELSUP}, /* 10+ */
+ { 0xd0, KEY_10CHANNELSDOWN}, /* 10- */
+ { 0x96, KEY_CHANNELUP}, /* ch+ */
+ { 0x91, KEY_CHANNELDOWN}, /* ch- */
+ { 0x93, KEY_VOLUMEUP}, /* vol+ */
+ { 0x8c, KEY_VOLUMEDOWN}, /* vol- */
+ { 0x83, KEY_RECORD}, /* rec */
+ { 0x98, KEY_PAUSE}, /* pause, yellow */
+ { 0x99, KEY_OK}, /* ok */
+ { 0x9a, KEY_CAMERA}, /* snapshot */
+ { 0x81, KEY_UP},
+ { 0x90, KEY_LEFT},
+ { 0x82, KEY_RIGHT},
+ { 0x88, KEY_DOWN},
+ { 0x95, KEY_FAVORITES}, /* blue */
+ { 0x97, KEY_SUBTITLE}, /* green */
+ { 0x9d, KEY_ZOOM},
+ { 0x9f, KEY_EXIT},
+ { 0x9e, KEY_MENU},
+ { 0x9c, KEY_EPG},
+ { 0x80, KEY_PREVIOUS}, /* red */
+ { 0x9b, KEY_MODE},
+};
+
+static struct rc_map_list tbs_nec_map = {
+ .map = {
+ .scan = tbs_nec,
+ .size = ARRAY_SIZE(tbs_nec),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_TBS_NEC,
+ }
+};
+
+static int __init init_rc_map_tbs_nec(void)
+{
+ return rc_map_register(&tbs_nec_map);
+}
+
+static void __exit exit_rc_map_tbs_nec(void)
+{
+ rc_map_unregister(&tbs_nec_map);
+}
+
+module_init(init_rc_map_tbs_nec)
+module_exit(exit_rc_map_tbs_nec)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
index 5326a0b444c1..bc38e34b9fda 100644
--- a/drivers/media/IR/keymaps/rc-terratec-cinergy-xs.c
+++ b/drivers/media/rc/keymaps/rc-terratec-cinergy-xs.c
@@ -16,7 +16,7 @@
Devin Heitmueller <dheitmueller@linuxtv.org>
*/
-static struct ir_scancode terratec_cinergy_xs[] = {
+static struct rc_map_table terratec_cinergy_xs[] = {
{ 0x41, KEY_HOME},
{ 0x01, KEY_POWER},
{ 0x42, KEY_MENU},
@@ -66,23 +66,23 @@ static struct ir_scancode terratec_cinergy_xs[] = {
{ 0x5c, KEY_NEXT},
};
-static struct rc_keymap terratec_cinergy_xs_map = {
+static struct rc_map_list terratec_cinergy_xs_map = {
.map = {
.scan = terratec_cinergy_xs,
.size = ARRAY_SIZE(terratec_cinergy_xs),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_TERRATEC_CINERGY_XS,
}
};
static int __init init_rc_map_terratec_cinergy_xs(void)
{
- return ir_register_map(&terratec_cinergy_xs_map);
+ return rc_map_register(&terratec_cinergy_xs_map);
}
static void __exit exit_rc_map_terratec_cinergy_xs(void)
{
- ir_unregister_map(&terratec_cinergy_xs_map);
+ rc_map_unregister(&terratec_cinergy_xs_map);
}
module_init(init_rc_map_terratec_cinergy_xs)
diff --git a/drivers/media/rc/keymaps/rc-terratec-slim.c b/drivers/media/rc/keymaps/rc-terratec-slim.c
new file mode 100644
index 000000000000..1abafa5fd303
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-terratec-slim.c
@@ -0,0 +1,79 @@
+/*
+ * TerraTec remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* TerraTec slim remote, 7 rows, 4 columns. */
+/* Uses NEC extended 0x02bd. */
+static struct rc_map_table terratec_slim[] = {
+ { 0x02bd00, KEY_1 },
+ { 0x02bd01, KEY_2 },
+ { 0x02bd02, KEY_3 },
+ { 0x02bd03, KEY_4 },
+ { 0x02bd04, KEY_5 },
+ { 0x02bd05, KEY_6 },
+ { 0x02bd06, KEY_7 },
+ { 0x02bd07, KEY_8 },
+ { 0x02bd08, KEY_9 },
+ { 0x02bd09, KEY_0 },
+ { 0x02bd0a, KEY_MUTE },
+ { 0x02bd0b, KEY_NEW }, /* symbol: PIP */
+ { 0x02bd0e, KEY_VOLUMEDOWN },
+ { 0x02bd0f, KEY_PLAYPAUSE },
+ { 0x02bd10, KEY_RIGHT },
+ { 0x02bd11, KEY_LEFT },
+ { 0x02bd12, KEY_UP },
+ { 0x02bd13, KEY_DOWN },
+ { 0x02bd15, KEY_OK },
+ { 0x02bd16, KEY_STOP },
+ { 0x02bd17, KEY_CAMERA }, /* snapshot */
+ { 0x02bd18, KEY_CHANNELUP },
+ { 0x02bd19, KEY_RECORD },
+ { 0x02bd1a, KEY_CHANNELDOWN },
+ { 0x02bd1c, KEY_ESC },
+ { 0x02bd1f, KEY_VOLUMEUP },
+ { 0x02bd44, KEY_EPG },
+ { 0x02bd45, KEY_POWER2 }, /* [red power button] */
+};
+
+static struct rc_map_list terratec_slim_map = {
+ .map = {
+ .scan = terratec_slim,
+ .size = ARRAY_SIZE(terratec_slim),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_TERRATEC_SLIM,
+ }
+};
+
+static int __init init_rc_map_terratec_slim(void)
+{
+ return rc_map_register(&terratec_slim_map);
+}
+
+static void __exit exit_rc_map_terratec_slim(void)
+{
+ rc_map_unregister(&terratec_slim_map);
+}
+
+module_init(init_rc_map_terratec_slim)
+module_exit(exit_rc_map_terratec_slim)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/IR/keymaps/rc-tevii-nec.c b/drivers/media/rc/keymaps/rc-tevii-nec.c
index e30d411c07bb..ef5ba3f32735 100644
--- a/drivers/media/IR/keymaps/rc-tevii-nec.c
+++ b/drivers/media/rc/keymaps/rc-tevii-nec.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode tevii_nec[] = {
+static struct rc_map_table tevii_nec[] = {
{ 0x0a, KEY_POWER2},
{ 0x0c, KEY_MUTE},
{ 0x11, KEY_1},
@@ -62,23 +62,23 @@ static struct ir_scancode tevii_nec[] = {
{ 0x58, KEY_SWITCHVIDEOMODE},
};
-static struct rc_keymap tevii_nec_map = {
+static struct rc_map_list tevii_nec_map = {
.map = {
.scan = tevii_nec,
.size = ARRAY_SIZE(tevii_nec),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_TEVII_NEC,
}
};
static int __init init_rc_map_tevii_nec(void)
{
- return ir_register_map(&tevii_nec_map);
+ return rc_map_register(&tevii_nec_map);
}
static void __exit exit_rc_map_tevii_nec(void)
{
- ir_unregister_map(&tevii_nec_map);
+ rc_map_unregister(&tevii_nec_map);
}
module_init(init_rc_map_tevii_nec)
diff --git a/drivers/media/rc/keymaps/rc-total-media-in-hand.c b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
new file mode 100644
index 000000000000..20ac4e19fb3f
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-total-media-in-hand.c
@@ -0,0 +1,85 @@
+/*
+ * Total Media In Hand remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* Uses NEC extended 0x02bd */
+static struct rc_map_table total_media_in_hand[] = {
+ { 0x02bd00, KEY_1 },
+ { 0x02bd01, KEY_2 },
+ { 0x02bd02, KEY_3 },
+ { 0x02bd03, KEY_4 },
+ { 0x02bd04, KEY_5 },
+ { 0x02bd05, KEY_6 },
+ { 0x02bd06, KEY_7 },
+ { 0x02bd07, KEY_8 },
+ { 0x02bd08, KEY_9 },
+ { 0x02bd09, KEY_0 },
+ { 0x02bd0a, KEY_MUTE },
+ { 0x02bd0b, KEY_CYCLEWINDOWS }, /* yellow, [min / max] */
+ { 0x02bd0c, KEY_VIDEO }, /* TV / AV */
+ { 0x02bd0e, KEY_VOLUMEDOWN },
+ { 0x02bd0f, KEY_TIME }, /* TimeShift */
+ { 0x02bd10, KEY_RIGHT }, /* right arrow */
+ { 0x02bd11, KEY_LEFT }, /* left arrow */
+ { 0x02bd12, KEY_UP }, /* up arrow */
+ { 0x02bd13, KEY_DOWN }, /* down arrow */
+ { 0x02bd14, KEY_POWER2 }, /* [red] */
+ { 0x02bd15, KEY_OK }, /* OK */
+ { 0x02bd16, KEY_STOP },
+ { 0x02bd17, KEY_CAMERA }, /* Snapshot */
+ { 0x02bd18, KEY_CHANNELUP },
+ { 0x02bd19, KEY_RECORD },
+ { 0x02bd1a, KEY_CHANNELDOWN },
+ { 0x02bd1c, KEY_ESC }, /* Esc */
+ { 0x02bd1e, KEY_PLAY },
+ { 0x02bd1f, KEY_VOLUMEUP },
+ { 0x02bd40, KEY_PAUSE },
+ { 0x02bd41, KEY_FASTFORWARD }, /* FF >> */
+ { 0x02bd42, KEY_REWIND }, /* FR << */
+ { 0x02bd43, KEY_ZOOM }, /* [window + mouse pointer] */
+ { 0x02bd44, KEY_SHUFFLE }, /* Shuffle */
+ { 0x02bd45, KEY_INFO }, /* [red (I)] */
+};
+
+static struct rc_map_list total_media_in_hand_map = {
+ .map = {
+ .scan = total_media_in_hand,
+ .size = ARRAY_SIZE(total_media_in_hand),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_TOTAL_MEDIA_IN_HAND,
+ }
+};
+
+static int __init init_rc_map_total_media_in_hand(void)
+{
+ return rc_map_register(&total_media_in_hand_map);
+}
+
+static void __exit exit_rc_map_total_media_in_hand(void)
+{
+ rc_map_unregister(&total_media_in_hand_map);
+}
+
+module_init(init_rc_map_total_media_in_hand)
+module_exit(exit_rc_map_total_media_in_hand)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-trekstor.c b/drivers/media/rc/keymaps/rc-trekstor.c
new file mode 100644
index 000000000000..f8190ead2e32
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-trekstor.c
@@ -0,0 +1,80 @@
+/*
+ * TrekStor remote controller keytable
+ *
+ * Copyright (C) 2010 Antti Palosaari <crope@iki.fi>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ */
+
+#include <media/rc-map.h>
+
+/* TrekStor DVB-T USB Stick remote controller. */
+/* Imported from af9015.h.
+ Initial keytable was from Marc Schneider <macke@macke.org> */
+static struct rc_map_table trekstor[] = {
+ { 0x0084, KEY_0 },
+ { 0x0085, KEY_MUTE }, /* Mute */
+ { 0x0086, KEY_HOMEPAGE }, /* Home */
+ { 0x0087, KEY_UP }, /* Up */
+ { 0x0088, KEY_OK }, /* OK */
+ { 0x0089, KEY_RIGHT }, /* Right */
+ { 0x008a, KEY_FASTFORWARD }, /* Fast forward */
+ { 0x008b, KEY_VOLUMEUP }, /* Volume + */
+ { 0x008c, KEY_DOWN }, /* Down */
+ { 0x008d, KEY_PLAY }, /* Play/Pause */
+ { 0x008e, KEY_STOP }, /* Stop */
+ { 0x008f, KEY_EPG }, /* Info/EPG */
+ { 0x0090, KEY_7 },
+ { 0x0091, KEY_4 },
+ { 0x0092, KEY_1 },
+ { 0x0093, KEY_CHANNELDOWN }, /* Channel - */
+ { 0x0094, KEY_8 },
+ { 0x0095, KEY_5 },
+ { 0x0096, KEY_2 },
+ { 0x0097, KEY_CHANNELUP }, /* Channel + */
+ { 0x0098, KEY_9 },
+ { 0x0099, KEY_6 },
+ { 0x009a, KEY_3 },
+ { 0x009b, KEY_VOLUMEDOWN }, /* Volume - */
+ { 0x009c, KEY_TV }, /* TV */
+ { 0x009d, KEY_RECORD }, /* Record */
+ { 0x009e, KEY_REWIND }, /* Rewind */
+ { 0x009f, KEY_LEFT }, /* Left */
+};
+
+static struct rc_map_list trekstor_map = {
+ .map = {
+ .scan = trekstor,
+ .size = ARRAY_SIZE(trekstor),
+ .rc_type = RC_TYPE_NEC,
+ .name = RC_MAP_TREKSTOR,
+ }
+};
+
+static int __init init_rc_map_trekstor(void)
+{
+ return rc_map_register(&trekstor_map);
+}
+
+static void __exit exit_rc_map_trekstor(void)
+{
+ rc_map_unregister(&trekstor_map);
+}
+
+module_init(init_rc_map_trekstor)
+module_exit(exit_rc_map_trekstor)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Antti Palosaari <crope@iki.fi>");
diff --git a/drivers/media/rc/keymaps/rc-tt-1500.c b/drivers/media/rc/keymaps/rc-tt-1500.c
new file mode 100644
index 000000000000..295f3738e301
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-tt-1500.c
@@ -0,0 +1,82 @@
+/* tt-1500.h - Keytable for tt_1500 Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+/* for the Technotrend 1500 bundled remotes (grey and black): */
+
+static struct rc_map_table tt_1500[] = {
+ { 0x1501, KEY_POWER },
+ { 0x1502, KEY_SHUFFLE }, /* ? double-arrow key */
+ { 0x1503, KEY_1 },
+ { 0x1504, KEY_2 },
+ { 0x1505, KEY_3 },
+ { 0x1506, KEY_4 },
+ { 0x1507, KEY_5 },
+ { 0x1508, KEY_6 },
+ { 0x1509, KEY_7 },
+ { 0x150a, KEY_8 },
+ { 0x150b, KEY_9 },
+ { 0x150c, KEY_0 },
+ { 0x150d, KEY_UP },
+ { 0x150e, KEY_LEFT },
+ { 0x150f, KEY_OK },
+ { 0x1510, KEY_RIGHT },
+ { 0x1511, KEY_DOWN },
+ { 0x1512, KEY_INFO },
+ { 0x1513, KEY_EXIT },
+ { 0x1514, KEY_RED },
+ { 0x1515, KEY_GREEN },
+ { 0x1516, KEY_YELLOW },
+ { 0x1517, KEY_BLUE },
+ { 0x1518, KEY_MUTE },
+ { 0x1519, KEY_TEXT },
+ { 0x151a, KEY_MODE }, /* ? TV/Radio */
+ { 0x1521, KEY_OPTION },
+ { 0x1522, KEY_EPG },
+ { 0x1523, KEY_CHANNELUP },
+ { 0x1524, KEY_CHANNELDOWN },
+ { 0x1525, KEY_VOLUMEUP },
+ { 0x1526, KEY_VOLUMEDOWN },
+ { 0x1527, KEY_SETUP },
+ { 0x153a, KEY_RECORD }, /* these keys are only in the black remote */
+ { 0x153b, KEY_PLAY },
+ { 0x153c, KEY_STOP },
+ { 0x153d, KEY_REWIND },
+ { 0x153e, KEY_PAUSE },
+ { 0x153f, KEY_FORWARD },
+};
+
+static struct rc_map_list tt_1500_map = {
+ .map = {
+ .scan = tt_1500,
+ .size = ARRAY_SIZE(tt_1500),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_TT_1500,
+ }
+};
+
+static int __init init_rc_map_tt_1500(void)
+{
+ return rc_map_register(&tt_1500_map);
+}
+
+static void __exit exit_rc_map_tt_1500(void)
+{
+ rc_map_unregister(&tt_1500_map);
+}
+
+module_init(init_rc_map_tt_1500)
+module_exit(exit_rc_map_tt_1500)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
diff --git a/drivers/media/rc/keymaps/rc-twinhan1027.c b/drivers/media/rc/keymaps/rc-twinhan1027.c
new file mode 100644
index 000000000000..8bf8df64b081
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-twinhan1027.c
@@ -0,0 +1,87 @@
+#include <media/rc-map.h>
+
+static struct rc_map_table twinhan_vp1027[] = {
+ { 0x16, KEY_POWER2 },
+ { 0x17, KEY_FAVORITES },
+ { 0x0f, KEY_TEXT },
+ { 0x48, KEY_INFO},
+ { 0x1c, KEY_EPG },
+ { 0x04, KEY_LIST },
+
+ { 0x03, KEY_1 },
+ { 0x01, KEY_2 },
+ { 0x06, KEY_3 },
+ { 0x09, KEY_4 },
+ { 0x1d, KEY_5 },
+ { 0x1f, KEY_6 },
+ { 0x0d, KEY_7 },
+ { 0x19, KEY_8 },
+ { 0x1b, KEY_9 },
+ { 0x15, KEY_0 },
+
+ { 0x0c, KEY_CANCEL },
+ { 0x4a, KEY_CLEAR },
+ { 0x13, KEY_BACKSPACE },
+ { 0x00, KEY_TAB },
+
+ { 0x4b, KEY_UP },
+ { 0x51, KEY_DOWN },
+ { 0x4e, KEY_LEFT },
+ { 0x52, KEY_RIGHT },
+ { 0x4f, KEY_ENTER },
+
+ { 0x1e, KEY_VOLUMEUP },
+ { 0x0a, KEY_VOLUMEDOWN },
+ { 0x02, KEY_CHANNELDOWN },
+ { 0x05, KEY_CHANNELUP },
+ { 0x11, KEY_RECORD },
+
+ { 0x14, KEY_PLAY },
+ { 0x4c, KEY_PAUSE },
+ { 0x1a, KEY_STOP },
+ { 0x40, KEY_REWIND },
+ { 0x12, KEY_FASTFORWARD },
+ { 0x41, KEY_PREVIOUSSONG },
+ { 0x42, KEY_NEXTSONG },
+ { 0x54, KEY_SAVE },
+ { 0x50, KEY_LANGUAGE },
+ { 0x47, KEY_MEDIA },
+ { 0x4d, KEY_SCREEN },
+ { 0x43, KEY_SUBTITLE },
+ { 0x10, KEY_MUTE },
+ { 0x49, KEY_AUDIO },
+ { 0x07, KEY_SLEEP },
+ { 0x08, KEY_VIDEO },
+ { 0x0e, KEY_AGAIN },
+ { 0x45, KEY_EQUAL },
+ { 0x46, KEY_MINUS },
+ { 0x18, KEY_RED },
+ { 0x53, KEY_GREEN },
+ { 0x5e, KEY_YELLOW },
+ { 0x5f, KEY_BLUE },
+};
+
+static struct rc_map_list twinhan_vp1027_map = {
+ .map = {
+ .scan = twinhan_vp1027,
+ .size = ARRAY_SIZE(twinhan_vp1027),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_TWINHAN_VP1027_DVBS,
+ }
+};
+
+static int __init init_rc_map_twinhan_vp1027(void)
+{
+ return rc_map_register(&twinhan_vp1027_map);
+}
+
+static void __exit exit_rc_map_twinhan_vp1027(void)
+{
+ rc_map_unregister(&twinhan_vp1027_map);
+}
+
+module_init(init_rc_map_twinhan_vp1027)
+module_exit(exit_rc_map_twinhan_vp1027)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Sergey Ivanov <123kash@gmail.com>");
diff --git a/drivers/media/rc/keymaps/rc-videomate-m1f.c b/drivers/media/rc/keymaps/rc-videomate-m1f.c
new file mode 100644
index 000000000000..4994d405c0a1
--- /dev/null
+++ b/drivers/media/rc/keymaps/rc-videomate-m1f.c
@@ -0,0 +1,92 @@
+/* videomate-m1f.h - Keytable for videomate_m1f Remote Controller
+ *
+ * keymap imported from ir-keymaps.c
+ *
+ * Copyright (c) 2010 by Pavel Osnova <pvosnova@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <media/rc-map.h>
+
+static struct rc_map_table videomate_m1f[] = {
+ { 0x01, KEY_POWER },
+ { 0x31, KEY_TUNER },
+ { 0x33, KEY_VIDEO },
+ { 0x2f, KEY_RADIO },
+ { 0x30, KEY_CAMERA },
+ { 0x2d, KEY_NEW }, /* TV record button */
+ { 0x17, KEY_CYCLEWINDOWS },
+ { 0x2c, KEY_ANGLE },
+ { 0x2b, KEY_LANGUAGE },
+ { 0x32, KEY_SEARCH }, /* '...' button */
+ { 0x11, KEY_UP },
+ { 0x13, KEY_LEFT },
+ { 0x15, KEY_OK },
+ { 0x14, KEY_RIGHT },
+ { 0x12, KEY_DOWN },
+ { 0x16, KEY_BACKSPACE },
+ { 0x02, KEY_ZOOM }, /* WIN key */
+ { 0x04, KEY_INFO },
+ { 0x05, KEY_VOLUMEUP },
+ { 0x03, KEY_MUTE },
+ { 0x07, KEY_CHANNELUP },
+ { 0x06, KEY_VOLUMEDOWN },
+ { 0x08, KEY_CHANNELDOWN },
+ { 0x0c, KEY_RECORD },
+ { 0x0e, KEY_STOP },
+ { 0x0a, KEY_BACK },
+ { 0x0b, KEY_PLAY },
+ { 0x09, KEY_FORWARD },
+ { 0x10, KEY_PREVIOUS },
+ { 0x0d, KEY_PAUSE },
+ { 0x0f, KEY_NEXT },
+ { 0x1e, KEY_1 },
+ { 0x1f, KEY_2 },
+ { 0x20, KEY_3 },
+ { 0x21, KEY_4 },
+ { 0x22, KEY_5 },
+ { 0x23, KEY_6 },
+ { 0x24, KEY_7 },
+ { 0x25, KEY_8 },
+ { 0x26, KEY_9 },
+ { 0x2a, KEY_NUMERIC_STAR }, /* * key */
+ { 0x1d, KEY_0 },
+ { 0x29, KEY_SUBTITLE }, /* # key */
+ { 0x27, KEY_CLEAR },
+ { 0x34, KEY_SCREEN },
+ { 0x28, KEY_ENTER },
+ { 0x19, KEY_RED },
+ { 0x1a, KEY_GREEN },
+ { 0x1b, KEY_YELLOW },
+ { 0x1c, KEY_BLUE },
+ { 0x18, KEY_TEXT },
+};
+
+static struct rc_map_list videomate_m1f_map = {
+ .map = {
+ .scan = videomate_m1f,
+ .size = ARRAY_SIZE(videomate_m1f),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_VIDEOMATE_M1F,
+ }
+};
+
+static int __init init_rc_map_videomate_m1f(void)
+{
+ return rc_map_register(&videomate_m1f_map);
+}
+
+static void __exit exit_rc_map_videomate_m1f(void)
+{
+ rc_map_unregister(&videomate_m1f_map);
+}
+
+module_init(init_rc_map_videomate_m1f)
+module_exit(exit_rc_map_videomate_m1f)
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Pavel Osnova <pvosnova@gmail.com>");
diff --git a/drivers/media/IR/keymaps/rc-videomate-s350.c b/drivers/media/rc/keymaps/rc-videomate-s350.c
index 4df7fcd1d2fc..9e474a6024e5 100644
--- a/drivers/media/IR/keymaps/rc-videomate-s350.c
+++ b/drivers/media/rc/keymaps/rc-videomate-s350.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode videomate_s350[] = {
+static struct rc_map_table videomate_s350[] = {
{ 0x00, KEY_TV},
{ 0x01, KEY_DVD},
{ 0x04, KEY_RECORD},
@@ -59,23 +59,23 @@ static struct ir_scancode videomate_s350[] = {
{ 0x20, KEY_TEXT},
};
-static struct rc_keymap videomate_s350_map = {
+static struct rc_map_list videomate_s350_map = {
.map = {
.scan = videomate_s350,
.size = ARRAY_SIZE(videomate_s350),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_VIDEOMATE_S350,
}
};
static int __init init_rc_map_videomate_s350(void)
{
- return ir_register_map(&videomate_s350_map);
+ return rc_map_register(&videomate_s350_map);
}
static void __exit exit_rc_map_videomate_s350(void)
{
- ir_unregister_map(&videomate_s350_map);
+ rc_map_unregister(&videomate_s350_map);
}
module_init(init_rc_map_videomate_s350)
diff --git a/drivers/media/IR/keymaps/rc-videomate-tv-pvr.c b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
index 776b0a638d87..5f2a46e1f8f6 100644
--- a/drivers/media/IR/keymaps/rc-videomate-tv-pvr.c
+++ b/drivers/media/rc/keymaps/rc-videomate-tv-pvr.c
@@ -12,7 +12,7 @@
#include <media/rc-map.h>
-static struct ir_scancode videomate_tv_pvr[] = {
+static struct rc_map_table videomate_tv_pvr[] = {
{ 0x14, KEY_MUTE },
{ 0x24, KEY_ZOOM },
@@ -61,23 +61,23 @@ static struct ir_scancode videomate_tv_pvr[] = {
{ 0x21, KEY_SLEEP },
};
-static struct rc_keymap videomate_tv_pvr_map = {
+static struct rc_map_list videomate_tv_pvr_map = {
.map = {
.scan = videomate_tv_pvr,
.size = ARRAY_SIZE(videomate_tv_pvr),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_VIDEOMATE_TV_PVR,
}
};
static int __init init_rc_map_videomate_tv_pvr(void)
{
- return ir_register_map(&videomate_tv_pvr_map);
+ return rc_map_register(&videomate_tv_pvr_map);
}
static void __exit exit_rc_map_videomate_tv_pvr(void)
{
- ir_unregister_map(&videomate_tv_pvr_map);
+ rc_map_unregister(&videomate_tv_pvr_map);
}
module_init(init_rc_map_videomate_tv_pvr)
diff --git a/drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
index 9d2d550aaa90..bd8d021f40aa 100644
--- a/drivers/media/IR/keymaps/rc-winfast-usbii-deluxe.c
+++ b/drivers/media/rc/keymaps/rc-winfast-usbii-deluxe.c
@@ -16,7 +16,7 @@
Magnus Alm <magnus.alm@gmail.com>
*/
-static struct ir_scancode winfast_usbii_deluxe[] = {
+static struct rc_map_table winfast_usbii_deluxe[] = {
{ 0x62, KEY_0},
{ 0x75, KEY_1},
{ 0x76, KEY_2},
@@ -56,23 +56,23 @@ static struct ir_scancode winfast_usbii_deluxe[] = {
};
-static struct rc_keymap winfast_usbii_deluxe_map = {
+static struct rc_map_list winfast_usbii_deluxe_map = {
.map = {
.scan = winfast_usbii_deluxe,
.size = ARRAY_SIZE(winfast_usbii_deluxe),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_WINFAST_USBII_DELUXE,
}
};
static int __init init_rc_map_winfast_usbii_deluxe(void)
{
- return ir_register_map(&winfast_usbii_deluxe_map);
+ return rc_map_register(&winfast_usbii_deluxe_map);
}
static void __exit exit_rc_map_winfast_usbii_deluxe(void)
{
- ir_unregister_map(&winfast_usbii_deluxe_map);
+ rc_map_unregister(&winfast_usbii_deluxe_map);
}
module_init(init_rc_map_winfast_usbii_deluxe)
diff --git a/drivers/media/IR/keymaps/rc-winfast.c b/drivers/media/rc/keymaps/rc-winfast.c
index 0e90a3bd9499..2747db43b70c 100644
--- a/drivers/media/IR/keymaps/rc-winfast.c
+++ b/drivers/media/rc/keymaps/rc-winfast.c
@@ -14,7 +14,7 @@
/* Table for Leadtek Winfast Remote Controls - used by both bttv and cx88 */
-static struct ir_scancode winfast[] = {
+static struct rc_map_table winfast[] = {
/* Keys 0 to 9 */
{ 0x12, KEY_0 },
{ 0x05, KEY_1 },
@@ -76,23 +76,23 @@ static struct ir_scancode winfast[] = {
{ 0x3f, KEY_F24 } /* MCE -CH, on Y04G0033 */
};
-static struct rc_keymap winfast_map = {
+static struct rc_map_list winfast_map = {
.map = {
.scan = winfast,
.size = ARRAY_SIZE(winfast),
- .ir_type = IR_TYPE_UNKNOWN, /* Legacy IR type */
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
.name = RC_MAP_WINFAST,
}
};
static int __init init_rc_map_winfast(void)
{
- return ir_register_map(&winfast_map);
+ return rc_map_register(&winfast_map);
}
static void __exit exit_rc_map_winfast(void)
{
- ir_unregister_map(&winfast_map);
+ rc_map_unregister(&winfast_map);
}
module_init(init_rc_map_winfast)
diff --git a/drivers/media/rc/lirc_dev.c b/drivers/media/rc/lirc_dev.c
new file mode 100644
index 000000000000..fd237ab120bb
--- /dev/null
+++ b/drivers/media/rc/lirc_dev.c
@@ -0,0 +1,816 @@
+/*
+ * LIRC base driver
+ *
+ * by Artur Lipowski <alipowski@interia.pl>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/ioctl.h>
+#include <linux/fs.h>
+#include <linux/poll.h>
+#include <linux/completion.h>
+#include <linux/mutex.h>
+#include <linux/wait.h>
+#include <linux/unistd.h>
+#include <linux/kthread.h>
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/cdev.h>
+
+#include <media/lirc.h>
+#include <media/lirc_dev.h>
+
+static int debug;
+
+#define IRCTL_DEV_NAME "BaseRemoteCtl"
+#define NOPLUG -1
+#define LOGHEAD "lirc_dev (%s[%d]): "
+
+static dev_t lirc_base_dev;
+
+struct irctl {
+ struct lirc_driver d;
+ int attached;
+ int open;
+
+ struct mutex irctl_lock;
+ struct lirc_buffer *buf;
+ unsigned int chunk_size;
+
+ struct task_struct *task;
+ long jiffies_to_wait;
+};
+
+static DEFINE_MUTEX(lirc_dev_lock);
+
+static struct irctl *irctls[MAX_IRCTL_DEVICES];
+static struct cdev cdevs[MAX_IRCTL_DEVICES];
+
+/* Only used for sysfs but defined to void otherwise */
+static struct class *lirc_class;
+
+/* helper function
+ * initializes the irctl structure
+ */
+static void lirc_irctl_init(struct irctl *ir)
+{
+ mutex_init(&ir->irctl_lock);
+ ir->d.minor = NOPLUG;
+}
+
+static void lirc_irctl_cleanup(struct irctl *ir)
+{
+ dev_dbg(ir->d.dev, LOGHEAD "cleaning up\n", ir->d.name, ir->d.minor);
+
+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+
+ if (ir->buf != ir->d.rbuf) {
+ lirc_buffer_free(ir->buf);
+ kfree(ir->buf);
+ }
+ ir->buf = NULL;
+}
+
+/* helper function
+ * reads key codes from driver and puts them into buffer
+ * returns 0 on success
+ */
+static int lirc_add_to_buf(struct irctl *ir)
+{
+ if (ir->d.add_to_buf) {
+ int res = -ENODATA;
+ int got_data = 0;
+
+ /*
+ * service the device as long as it is returning
+ * data and we have space
+ */
+get_data:
+ res = ir->d.add_to_buf(ir->d.data, ir->buf);
+ if (res == 0) {
+ got_data++;
+ goto get_data;
+ }
+
+ if (res == -ENODEV)
+ kthread_stop(ir->task);
+
+ return got_data ? 0 : res;
+ }
+
+ return 0;
+}
+
+/* main function of the polling thread
+ */
+static int lirc_thread(void *irctl)
+{
+ struct irctl *ir = irctl;
+
+ dev_dbg(ir->d.dev, LOGHEAD "poll thread started\n",
+ ir->d.name, ir->d.minor);
+
+ do {
+ if (ir->open) {
+ if (ir->jiffies_to_wait) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(ir->jiffies_to_wait);
+ }
+ if (kthread_should_stop())
+ break;
+ if (!lirc_add_to_buf(ir))
+ wake_up_interruptible(&ir->buf->wait_poll);
+ } else {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }
+ } while (!kthread_should_stop());
+
+ dev_dbg(ir->d.dev, LOGHEAD "poll thread ended\n",
+ ir->d.name, ir->d.minor);
+
+ return 0;
+}
+
+
+static struct file_operations lirc_dev_fops = {
+ .owner = THIS_MODULE,
+ .read = lirc_dev_fop_read,
+ .write = lirc_dev_fop_write,
+ .poll = lirc_dev_fop_poll,
+ .unlocked_ioctl = lirc_dev_fop_ioctl,
+#ifdef CONFIG_COMPAT
+ .compat_ioctl = lirc_dev_fop_ioctl,
+#endif
+ .open = lirc_dev_fop_open,
+ .release = lirc_dev_fop_close,
+ .llseek = noop_llseek,
+};
+
+static int lirc_cdev_add(struct irctl *ir)
+{
+ int retval;
+ struct lirc_driver *d = &ir->d;
+ struct cdev *cdev = &cdevs[d->minor];
+
+ if (d->fops) {
+ cdev_init(cdev, d->fops);
+ cdev->owner = d->owner;
+ } else {
+ cdev_init(cdev, &lirc_dev_fops);
+ cdev->owner = THIS_MODULE;
+ }
+ retval = kobject_set_name(&cdev->kobj, "lirc%d", d->minor);
+ if (retval)
+ return retval;
+
+ retval = cdev_add(cdev, MKDEV(MAJOR(lirc_base_dev), d->minor), 1);
+ if (retval)
+ kobject_put(&cdev->kobj);
+
+ return retval;
+}
+
+int lirc_register_driver(struct lirc_driver *d)
+{
+ struct irctl *ir;
+ int minor;
+ int bytes_in_key;
+ unsigned int chunk_size;
+ unsigned int buffer_size;
+ int err;
+
+ if (!d) {
+ printk(KERN_ERR "lirc_dev: lirc_register_driver: "
+ "driver pointer must be not NULL!\n");
+ err = -EBADRQC;
+ goto out;
+ }
+
+ if (!d->dev) {
+ printk(KERN_ERR "%s: dev pointer not filled in!\n", __func__);
+ err = -EINVAL;
+ goto out;
+ }
+
+ if (MAX_IRCTL_DEVICES <= d->minor) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "\"minor\" must be between 0 and %d (%d)!\n",
+ MAX_IRCTL_DEVICES-1, d->minor);
+ err = -EBADRQC;
+ goto out;
+ }
+
+ if (1 > d->code_length || (BUFLEN * 8) < d->code_length) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "code length in bits for minor (%d) "
+ "must be less than %d!\n",
+ d->minor, BUFLEN * 8);
+ err = -EBADRQC;
+ goto out;
+ }
+
+ dev_dbg(d->dev, "lirc_dev: lirc_register_driver: sample_rate: %d\n",
+ d->sample_rate);
+ if (d->sample_rate) {
+ if (2 > d->sample_rate || HZ < d->sample_rate) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "sample_rate must be between 2 and %d!\n", HZ);
+ err = -EBADRQC;
+ goto out;
+ }
+ if (!d->add_to_buf) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "add_to_buf cannot be NULL when "
+ "sample_rate is set\n");
+ err = -EBADRQC;
+ goto out;
+ }
+ } else if (!(d->fops && d->fops->read) && !d->rbuf) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "fops->read and rbuf cannot all be NULL!\n");
+ err = -EBADRQC;
+ goto out;
+ } else if (!d->rbuf) {
+ if (!(d->fops && d->fops->read && d->fops->poll &&
+ d->fops->unlocked_ioctl)) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "neither read, poll nor unlocked_ioctl can be NULL!\n");
+ err = -EBADRQC;
+ goto out;
+ }
+ }
+
+ mutex_lock(&lirc_dev_lock);
+
+ minor = d->minor;
+
+ if (minor < 0) {
+ /* find first free slot for driver */
+ for (minor = 0; minor < MAX_IRCTL_DEVICES; minor++)
+ if (!irctls[minor])
+ break;
+ if (MAX_IRCTL_DEVICES == minor) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "no free slots for drivers!\n");
+ err = -ENOMEM;
+ goto out_lock;
+ }
+ } else if (irctls[minor]) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "minor (%d) just registered!\n", minor);
+ err = -EBUSY;
+ goto out_lock;
+ }
+
+ ir = kzalloc(sizeof(struct irctl), GFP_KERNEL);
+ if (!ir) {
+ err = -ENOMEM;
+ goto out_lock;
+ }
+ lirc_irctl_init(ir);
+ irctls[minor] = ir;
+ d->minor = minor;
+
+ if (d->sample_rate) {
+ ir->jiffies_to_wait = HZ / d->sample_rate;
+ } else {
+ /* it means - wait for external event in task queue */
+ ir->jiffies_to_wait = 0;
+ }
+
+ /* some safety check 8-) */
+ d->name[sizeof(d->name)-1] = '\0';
+
+ bytes_in_key = BITS_TO_LONGS(d->code_length) +
+ (d->code_length % 8 ? 1 : 0);
+ buffer_size = d->buffer_size ? d->buffer_size : BUFLEN / bytes_in_key;
+ chunk_size = d->chunk_size ? d->chunk_size : bytes_in_key;
+
+ if (d->rbuf) {
+ ir->buf = d->rbuf;
+ } else {
+ ir->buf = kmalloc(sizeof(struct lirc_buffer), GFP_KERNEL);
+ if (!ir->buf) {
+ err = -ENOMEM;
+ goto out_lock;
+ }
+ err = lirc_buffer_init(ir->buf, chunk_size, buffer_size);
+ if (err) {
+ kfree(ir->buf);
+ goto out_lock;
+ }
+ }
+ ir->chunk_size = ir->buf->chunk_size;
+
+ if (d->features == 0)
+ d->features = LIRC_CAN_REC_LIRCCODE;
+
+ ir->d = *d;
+
+ device_create(lirc_class, ir->d.dev,
+ MKDEV(MAJOR(lirc_base_dev), ir->d.minor), NULL,
+ "lirc%u", ir->d.minor);
+
+ if (d->sample_rate) {
+ /* try to fire up polling thread */
+ ir->task = kthread_run(lirc_thread, (void *)ir, "lirc_dev");
+ if (IS_ERR(ir->task)) {
+ dev_err(d->dev, "lirc_dev: lirc_register_driver: "
+ "cannot run poll thread for minor = %d\n",
+ d->minor);
+ err = -ECHILD;
+ goto out_sysfs;
+ }
+ }
+
+ err = lirc_cdev_add(ir);
+ if (err)
+ goto out_sysfs;
+
+ ir->attached = 1;
+ mutex_unlock(&lirc_dev_lock);
+
+ dev_info(ir->d.dev, "lirc_dev: driver %s registered at minor = %d\n",
+ ir->d.name, ir->d.minor);
+ return minor;
+
+out_sysfs:
+ device_destroy(lirc_class, MKDEV(MAJOR(lirc_base_dev), ir->d.minor));
+out_lock:
+ mutex_unlock(&lirc_dev_lock);
+out:
+ return err;
+}
+EXPORT_SYMBOL(lirc_register_driver);
+
+int lirc_unregister_driver(int minor)
+{
+ struct irctl *ir;
+ struct cdev *cdev;
+
+ if (minor < 0 || minor >= MAX_IRCTL_DEVICES) {
+ printk(KERN_ERR "lirc_dev: %s: minor (%d) must be between "
+ "0 and %d!\n", __func__, minor, MAX_IRCTL_DEVICES-1);
+ return -EBADRQC;
+ }
+
+ ir = irctls[minor];
+ if (!ir) {
+ printk(KERN_ERR "lirc_dev: %s: failed to get irctl struct "
+ "for minor %d!\n", __func__, minor);
+ return -ENOENT;
+ }
+
+ cdev = &cdevs[minor];
+
+ mutex_lock(&lirc_dev_lock);
+
+ if (ir->d.minor != minor) {
+ printk(KERN_ERR "lirc_dev: %s: minor (%d) device not "
+ "registered!\n", __func__, minor);
+ mutex_unlock(&lirc_dev_lock);
+ return -ENOENT;
+ }
+
+ /* end up polling thread */
+ if (ir->task)
+ kthread_stop(ir->task);
+
+ dev_dbg(ir->d.dev, "lirc_dev: driver %s unregistered from minor = %d\n",
+ ir->d.name, ir->d.minor);
+
+ ir->attached = 0;
+ if (ir->open) {
+ dev_dbg(ir->d.dev, LOGHEAD "releasing opened driver\n",
+ ir->d.name, ir->d.minor);
+ wake_up_interruptible(&ir->buf->wait_poll);
+ mutex_lock(&ir->irctl_lock);
+ ir->d.set_use_dec(ir->d.data);
+ module_put(cdev->owner);
+ mutex_unlock(&ir->irctl_lock);
+ } else {
+ lirc_irctl_cleanup(ir);
+ cdev_del(cdev);
+ kfree(ir);
+ irctls[minor] = NULL;
+ }
+
+ mutex_unlock(&lirc_dev_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(lirc_unregister_driver);
+
+int lirc_dev_fop_open(struct inode *inode, struct file *file)
+{
+ struct irctl *ir;
+ struct cdev *cdev;
+ int retval = 0;
+
+ if (iminor(inode) >= MAX_IRCTL_DEVICES) {
+ printk(KERN_WARNING "lirc_dev [%d]: open result = -ENODEV\n",
+ iminor(inode));
+ return -ENODEV;
+ }
+
+ if (mutex_lock_interruptible(&lirc_dev_lock))
+ return -ERESTARTSYS;
+
+ ir = irctls[iminor(inode)];
+ if (!ir) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ dev_dbg(ir->d.dev, LOGHEAD "open called\n", ir->d.name, ir->d.minor);
+
+ if (ir->d.minor == NOPLUG) {
+ retval = -ENODEV;
+ goto error;
+ }
+
+ if (ir->open) {
+ retval = -EBUSY;
+ goto error;
+ }
+
+ cdev = &cdevs[iminor(inode)];
+ if (try_module_get(cdev->owner)) {
+ ir->open++;
+ retval = ir->d.set_use_inc(ir->d.data);
+
+ if (retval) {
+ module_put(cdev->owner);
+ ir->open--;
+ } else {
+ lirc_buffer_clear(ir->buf);
+ }
+ if (ir->task)
+ wake_up_process(ir->task);
+ }
+
+error:
+ if (ir)
+ dev_dbg(ir->d.dev, LOGHEAD "open result = %d\n",
+ ir->d.name, ir->d.minor, retval);
+
+ mutex_unlock(&lirc_dev_lock);
+
+ nonseekable_open(inode, file);
+
+ return retval;
+}
+EXPORT_SYMBOL(lirc_dev_fop_open);
+
+int lirc_dev_fop_close(struct inode *inode, struct file *file)
+{
+ struct irctl *ir = irctls[iminor(inode)];
+ struct cdev *cdev = &cdevs[iminor(inode)];
+
+ if (!ir) {
+ printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ return -EINVAL;
+ }
+
+ dev_dbg(ir->d.dev, LOGHEAD "close called\n", ir->d.name, ir->d.minor);
+
+ WARN_ON(mutex_lock_killable(&lirc_dev_lock));
+
+ ir->open--;
+ if (ir->attached) {
+ ir->d.set_use_dec(ir->d.data);
+ module_put(cdev->owner);
+ } else {
+ lirc_irctl_cleanup(ir);
+ cdev_del(cdev);
+ irctls[ir->d.minor] = NULL;
+ kfree(ir);
+ }
+
+ mutex_unlock(&lirc_dev_lock);
+
+ return 0;
+}
+EXPORT_SYMBOL(lirc_dev_fop_close);
+
+unsigned int lirc_dev_fop_poll(struct file *file, poll_table *wait)
+{
+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+ unsigned int ret;
+
+ if (!ir) {
+ printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ return POLLERR;
+ }
+
+ dev_dbg(ir->d.dev, LOGHEAD "poll called\n", ir->d.name, ir->d.minor);
+
+ if (!ir->attached)
+ return POLLERR;
+
+ poll_wait(file, &ir->buf->wait_poll, wait);
+
+ if (ir->buf)
+ if (lirc_buffer_empty(ir->buf))
+ ret = 0;
+ else
+ ret = POLLIN | POLLRDNORM;
+ else
+ ret = POLLERR;
+
+ dev_dbg(ir->d.dev, LOGHEAD "poll result = %d\n",
+ ir->d.name, ir->d.minor, ret);
+
+ return ret;
+}
+EXPORT_SYMBOL(lirc_dev_fop_poll);
+
+long lirc_dev_fop_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
+{
+ __u32 mode;
+ int result = 0;
+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+
+ if (!ir) {
+ printk(KERN_ERR "lirc_dev: %s: no irctl found!\n", __func__);
+ return -ENODEV;
+ }
+
+ dev_dbg(ir->d.dev, LOGHEAD "ioctl called (0x%x)\n",
+ ir->d.name, ir->d.minor, cmd);
+
+ if (ir->d.minor == NOPLUG || !ir->attached) {
+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = -ENODEV\n",
+ ir->d.name, ir->d.minor);
+ return -ENODEV;
+ }
+
+ mutex_lock(&ir->irctl_lock);
+
+ switch (cmd) {
+ case LIRC_GET_FEATURES:
+ result = put_user(ir->d.features, (__u32 *)arg);
+ break;
+ case LIRC_GET_REC_MODE:
+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
+ result = -ENOSYS;
+ break;
+ }
+
+ result = put_user(LIRC_REC2MODE
+ (ir->d.features & LIRC_CAN_REC_MASK),
+ (__u32 *)arg);
+ break;
+ case LIRC_SET_REC_MODE:
+ if (!(ir->d.features & LIRC_CAN_REC_MASK)) {
+ result = -ENOSYS;
+ break;
+ }
+
+ result = get_user(mode, (__u32 *)arg);
+ if (!result && !(LIRC_MODE2REC(mode) & ir->d.features))
+ result = -EINVAL;
+ /*
+ * FIXME: We should actually set the mode somehow but
+ * for now, lirc_serial doesn't support mode changing either
+ */
+ break;
+ case LIRC_GET_LENGTH:
+ result = put_user(ir->d.code_length, (__u32 *)arg);
+ break;
+ case LIRC_GET_MIN_TIMEOUT:
+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
+ ir->d.min_timeout == 0) {
+ result = -ENOSYS;
+ break;
+ }
+
+ result = put_user(ir->d.min_timeout, (__u32 *)arg);
+ break;
+ case LIRC_GET_MAX_TIMEOUT:
+ if (!(ir->d.features & LIRC_CAN_SET_REC_TIMEOUT) ||
+ ir->d.max_timeout == 0) {
+ result = -ENOSYS;
+ break;
+ }
+
+ result = put_user(ir->d.max_timeout, (__u32 *)arg);
+ break;
+ default:
+ result = -EINVAL;
+ }
+
+ dev_dbg(ir->d.dev, LOGHEAD "ioctl result = %d\n",
+ ir->d.name, ir->d.minor, result);
+
+ mutex_unlock(&ir->irctl_lock);
+
+ return result;
+}
+EXPORT_SYMBOL(lirc_dev_fop_ioctl);
+
+ssize_t lirc_dev_fop_read(struct file *file,
+ char __user *buffer,
+ size_t length,
+ loff_t *ppos)
+{
+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+ unsigned char *buf;
+ int ret = 0, written = 0;
+ DECLARE_WAITQUEUE(wait, current);
+
+ if (!ir) {
+ printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ return -ENODEV;
+ }
+
+ dev_dbg(ir->d.dev, LOGHEAD "read called\n", ir->d.name, ir->d.minor);
+
+ buf = kzalloc(ir->chunk_size, GFP_KERNEL);
+ if (!buf)
+ return -ENOMEM;
+
+ if (mutex_lock_interruptible(&ir->irctl_lock)) {
+ ret = -ERESTARTSYS;
+ goto out_unlocked;
+ }
+ if (!ir->attached) {
+ ret = -ENODEV;
+ goto out_locked;
+ }
+
+ if (length % ir->chunk_size) {
+ ret = -EINVAL;
+ goto out_locked;
+ }
+
+ /*
+ * we add ourselves to the task queue before buffer check
+ * to avoid losing scan code (in case when queue is awaken somewhere
+ * between while condition checking and scheduling)
+ */
+ add_wait_queue(&ir->buf->wait_poll, &wait);
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ /*
+ * while we didn't provide 'length' bytes, device is opened in blocking
+ * mode and 'copy_to_user' is happy, wait for data.
+ */
+ while (written < length && ret == 0) {
+ if (lirc_buffer_empty(ir->buf)) {
+ /* According to the read(2) man page, 'written' can be
+ * returned as less than 'length', instead of blocking
+ * again, returning -EWOULDBLOCK, or returning
+ * -ERESTARTSYS */
+ if (written)
+ break;
+ if (file->f_flags & O_NONBLOCK) {
+ ret = -EWOULDBLOCK;
+ break;
+ }
+ if (signal_pending(current)) {
+ ret = -ERESTARTSYS;
+ break;
+ }
+
+ mutex_unlock(&ir->irctl_lock);
+ schedule();
+ set_current_state(TASK_INTERRUPTIBLE);
+
+ if (mutex_lock_interruptible(&ir->irctl_lock)) {
+ ret = -ERESTARTSYS;
+ remove_wait_queue(&ir->buf->wait_poll, &wait);
+ set_current_state(TASK_RUNNING);
+ goto out_unlocked;
+ }
+
+ if (!ir->attached) {
+ ret = -ENODEV;
+ break;
+ }
+ } else {
+ lirc_buffer_read(ir->buf, buf);
+ ret = copy_to_user((void *)buffer+written, buf,
+ ir->buf->chunk_size);
+ if (!ret)
+ written += ir->buf->chunk_size;
+ else
+ ret = -EFAULT;
+ }
+ }
+
+ remove_wait_queue(&ir->buf->wait_poll, &wait);
+ set_current_state(TASK_RUNNING);
+
+out_locked:
+ mutex_unlock(&ir->irctl_lock);
+
+out_unlocked:
+ kfree(buf);
+ dev_dbg(ir->d.dev, LOGHEAD "read result = %s (%d)\n",
+ ir->d.name, ir->d.minor, ret ? "<fail>" : "<ok>", ret);
+
+ return ret ? ret : written;
+}
+EXPORT_SYMBOL(lirc_dev_fop_read);
+
+void *lirc_get_pdata(struct file *file)
+{
+ void *data = NULL;
+
+ if (file && file->f_dentry && file->f_dentry->d_inode &&
+ file->f_dentry->d_inode->i_rdev) {
+ struct irctl *ir;
+ ir = irctls[iminor(file->f_dentry->d_inode)];
+ data = ir->d.data;
+ }
+
+ return data;
+}
+EXPORT_SYMBOL(lirc_get_pdata);
+
+
+ssize_t lirc_dev_fop_write(struct file *file, const char __user *buffer,
+ size_t length, loff_t *ppos)
+{
+ struct irctl *ir = irctls[iminor(file->f_dentry->d_inode)];
+
+ if (!ir) {
+ printk(KERN_ERR "%s: called with invalid irctl\n", __func__);
+ return -ENODEV;
+ }
+
+ dev_dbg(ir->d.dev, LOGHEAD "write called\n", ir->d.name, ir->d.minor);
+
+ if (!ir->attached)
+ return -ENODEV;
+
+ return -EINVAL;
+}
+EXPORT_SYMBOL(lirc_dev_fop_write);
+
+
+static int __init lirc_dev_init(void)
+{
+ int retval;
+
+ lirc_class = class_create(THIS_MODULE, "lirc");
+ if (IS_ERR(lirc_class)) {
+ retval = PTR_ERR(lirc_class);
+ printk(KERN_ERR "lirc_dev: class_create failed\n");
+ goto error;
+ }
+
+ retval = alloc_chrdev_region(&lirc_base_dev, 0, MAX_IRCTL_DEVICES,
+ IRCTL_DEV_NAME);
+ if (retval) {
+ class_destroy(lirc_class);
+ printk(KERN_ERR "lirc_dev: alloc_chrdev_region failed\n");
+ goto error;
+ }
+
+
+ printk(KERN_INFO "lirc_dev: IR Remote Control driver registered, "
+ "major %d \n", MAJOR(lirc_base_dev));
+
+error:
+ return retval;
+}
+
+
+
+static void __exit lirc_dev_exit(void)
+{
+ class_destroy(lirc_class);
+ unregister_chrdev_region(lirc_base_dev, MAX_IRCTL_DEVICES);
+ printk(KERN_INFO "lirc_dev: module unloaded\n");
+}
+
+module_init(lirc_dev_init);
+module_exit(lirc_dev_exit);
+
+MODULE_DESCRIPTION("LIRC base driver module");
+MODULE_AUTHOR("Artur Lipowski");
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/media/rc/mceusb.c b/drivers/media/rc/mceusb.c
new file mode 100644
index 000000000000..079353e5d558
--- /dev/null
+++ b/drivers/media/rc/mceusb.c
@@ -0,0 +1,1312 @@
+/*
+ * Driver for USB Windows Media Center Ed. eHome Infrared Transceivers
+ *
+ * Copyright (c) 2010 by Jarod Wilson <jarod@redhat.com>
+ *
+ * Based on the original lirc_mceusb and lirc_mceusb2 drivers, by Dan
+ * Conti, Martin Blatter and Daniel Melander, the latter of which was
+ * in turn also based on the lirc_atiusb driver by Paul Miller. The
+ * two mce drivers were merged into one by Jarod Wilson, with transmit
+ * support for the 1st-gen device added primarily by Patrick Calhoun,
+ * with a bit of tweaks by Jarod. Debugging improvements and proper
+ * support for what appears to be 3rd-gen hardware added by Jarod.
+ * Initial port from lirc driver to ir-core drivery by Jarod, based
+ * partially on a port to an earlier proposed IR infrastructure by
+ * Jon Smirl, which included enhancements and simplifications to the
+ * incoming IR buffer parsing routines.
+ *
+ *
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#define DRIVER_VERSION "1.91"
+#define DRIVER_AUTHOR "Jarod Wilson <jarod@wilsonet.com>"
+#define DRIVER_DESC "Windows Media Center Ed. eHome Infrared Transceiver " \
+ "device driver"
+#define DRIVER_NAME "mceusb"
+
+#define USB_BUFLEN 32 /* USB reception buffer length */
+#define USB_CTRL_MSG_SZ 2 /* Size of usb ctrl msg on gen1 hw */
+#define MCE_G1_INIT_MSGS 40 /* Init messages on gen1 hw to throw out */
+
+/* MCE constants */
+#define MCE_CMDBUF_SIZE 384 /* MCE Command buffer length */
+#define MCE_TIME_UNIT 50 /* Approx 50us resolution */
+#define MCE_CODE_LENGTH 5 /* Normal length of packet (with header) */
+#define MCE_PACKET_SIZE 4 /* Normal length of packet (without header) */
+#define MCE_IRDATA_HEADER 0x84 /* Actual header format is 0x80 + num_bytes */
+#define MCE_IRDATA_TRAILER 0x80 /* End of IR data */
+#define MCE_TX_HEADER_LENGTH 3 /* # of bytes in the initializing tx header */
+#define MCE_MAX_CHANNELS 2 /* Two transmitters, hardware dependent? */
+#define MCE_DEFAULT_TX_MASK 0x03 /* Vals: TX1=0x01, TX2=0x02, ALL=0x03 */
+#define MCE_PULSE_BIT 0x80 /* Pulse bit, MSB set == PULSE else SPACE */
+#define MCE_PULSE_MASK 0x7f /* Pulse mask */
+#define MCE_MAX_PULSE_LENGTH 0x7f /* Longest transmittable pulse symbol */
+
+#define MCE_HW_CMD_HEADER 0xff /* MCE hardware command header */
+#define MCE_COMMAND_HEADER 0x9f /* MCE command header */
+#define MCE_COMMAND_MASK 0xe0 /* Mask out command bits */
+#define MCE_COMMAND_NULL 0x00 /* These show up various places... */
+/* if buf[i] & MCE_COMMAND_MASK == 0x80 and buf[i] != MCE_COMMAND_HEADER,
+ * then we're looking at a raw IR data sample */
+#define MCE_COMMAND_IRDATA 0x80
+#define MCE_PACKET_LENGTH_MASK 0x1f /* Packet length mask */
+
+/* Sub-commands, which follow MCE_COMMAND_HEADER or MCE_HW_CMD_HEADER */
+#define MCE_CMD_SIG_END 0x01 /* End of signal */
+#define MCE_CMD_PING 0x03 /* Ping device */
+#define MCE_CMD_UNKNOWN 0x04 /* Unknown */
+#define MCE_CMD_UNKNOWN2 0x05 /* Unknown */
+#define MCE_CMD_S_CARRIER 0x06 /* Set TX carrier frequency */
+#define MCE_CMD_G_CARRIER 0x07 /* Get TX carrier frequency */
+#define MCE_CMD_S_TXMASK 0x08 /* Set TX port bitmask */
+#define MCE_CMD_UNKNOWN3 0x09 /* Unknown */
+#define MCE_CMD_UNKNOWN4 0x0a /* Unknown */
+#define MCE_CMD_G_REVISION 0x0b /* Get hw/sw revision */
+#define MCE_CMD_S_TIMEOUT 0x0c /* Set RX timeout value */
+#define MCE_CMD_G_TIMEOUT 0x0d /* Get RX timeout value */
+#define MCE_CMD_UNKNOWN5 0x0e /* Unknown */
+#define MCE_CMD_UNKNOWN6 0x0f /* Unknown */
+#define MCE_CMD_G_RXPORTSTS 0x11 /* Get RX port status */
+#define MCE_CMD_G_TXMASK 0x13 /* Set TX port bitmask */
+#define MCE_CMD_S_RXSENSOR 0x14 /* Set RX sensor (std/learning) */
+#define MCE_CMD_G_RXSENSOR 0x15 /* Get RX sensor (std/learning) */
+#define MCE_RSP_PULSE_COUNT 0x15 /* RX pulse count (only if learning) */
+#define MCE_CMD_TX_PORTS 0x16 /* Get number of TX ports */
+#define MCE_CMD_G_WAKESRC 0x17 /* Get wake source */
+#define MCE_CMD_UNKNOWN7 0x18 /* Unknown */
+#define MCE_CMD_UNKNOWN8 0x19 /* Unknown */
+#define MCE_CMD_UNKNOWN9 0x1b /* Unknown */
+#define MCE_CMD_DEVICE_RESET 0xaa /* Reset the hardware */
+#define MCE_RSP_CMD_INVALID 0xfe /* Invalid command issued */
+
+
+/* module parameters */
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+/* general constants */
+#define SEND_FLAG_IN_PROGRESS 1
+#define SEND_FLAG_COMPLETE 2
+#define RECV_FLAG_IN_PROGRESS 3
+#define RECV_FLAG_COMPLETE 4
+
+#define MCEUSB_RX 1
+#define MCEUSB_TX 2
+
+#define VENDOR_PHILIPS 0x0471
+#define VENDOR_SMK 0x0609
+#define VENDOR_TATUNG 0x1460
+#define VENDOR_GATEWAY 0x107b
+#define VENDOR_SHUTTLE 0x1308
+#define VENDOR_SHUTTLE2 0x051c
+#define VENDOR_MITSUMI 0x03ee
+#define VENDOR_TOPSEED 0x1784
+#define VENDOR_RICAVISION 0x179d
+#define VENDOR_ITRON 0x195d
+#define VENDOR_FIC 0x1509
+#define VENDOR_LG 0x043e
+#define VENDOR_MICROSOFT 0x045e
+#define VENDOR_FORMOSA 0x147a
+#define VENDOR_FINTEK 0x1934
+#define VENDOR_PINNACLE 0x2304
+#define VENDOR_ECS 0x1019
+#define VENDOR_WISTRON 0x0fb8
+#define VENDOR_COMPRO 0x185b
+#define VENDOR_NORTHSTAR 0x04eb
+#define VENDOR_REALTEK 0x0bda
+#define VENDOR_TIVO 0x105a
+#define VENDOR_CONEXANT 0x0572
+
+enum mceusb_model_type {
+ MCE_GEN2 = 0, /* Most boards */
+ MCE_GEN1,
+ MCE_GEN3,
+ MCE_GEN2_TX_INV,
+ POLARIS_EVK,
+ CX_HYBRID_TV,
+};
+
+struct mceusb_model {
+ u32 mce_gen1:1;
+ u32 mce_gen2:1;
+ u32 mce_gen3:1;
+ u32 tx_mask_normal:1;
+ u32 is_polaris:1;
+ u32 no_tx:1;
+
+ const char *rc_map; /* Allow specify a per-board map */
+ const char *name; /* per-board name */
+};
+
+static const struct mceusb_model mceusb_model[] = {
+ [MCE_GEN1] = {
+ .mce_gen1 = 1,
+ .tx_mask_normal = 1,
+ },
+ [MCE_GEN2] = {
+ .mce_gen2 = 1,
+ },
+ [MCE_GEN2_TX_INV] = {
+ .mce_gen2 = 1,
+ .tx_mask_normal = 1,
+ },
+ [MCE_GEN3] = {
+ .mce_gen3 = 1,
+ .tx_mask_normal = 1,
+ },
+ [POLARIS_EVK] = {
+ .is_polaris = 1,
+ /*
+ * In fact, the EVK is shipped without
+ * remotes, but we should have something handy,
+ * to allow testing it
+ */
+ .rc_map = RC_MAP_RC5_HAUPPAUGE_NEW,
+ .name = "Conexant Hybrid TV (cx231xx) MCE IR",
+ },
+ [CX_HYBRID_TV] = {
+ .is_polaris = 1,
+ .no_tx = 1, /* tx isn't wired up at all */
+ .name = "Conexant Hybrid TV (cx231xx) MCE IR",
+ },
+};
+
+static struct usb_device_id mceusb_dev_table[] = {
+ /* Original Microsoft MCE IR Transceiver (often HP-branded) */
+ { USB_DEVICE(VENDOR_MICROSOFT, 0x006d),
+ .driver_info = MCE_GEN1 },
+ /* Philips Infrared Transceiver - Sahara branded */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x0608) },
+ /* Philips Infrared Transceiver - HP branded */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x060c),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* Philips SRM5100 */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x060d) },
+ /* Philips Infrared Transceiver - Omaura */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x060f) },
+ /* Philips Infrared Transceiver - Spinel plus */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x0613) },
+ /* Philips eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x0815) },
+ /* Philips/Spinel plus IR transceiver for ASUS */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x206c) },
+ /* Philips/Spinel plus IR transceiver for ASUS */
+ { USB_DEVICE(VENDOR_PHILIPS, 0x2088) },
+ /* Realtek MCE IR Receiver */
+ { USB_DEVICE(VENDOR_REALTEK, 0x0161) },
+ /* SMK/Toshiba G83C0004D410 */
+ { USB_DEVICE(VENDOR_SMK, 0x031d),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* SMK eHome Infrared Transceiver (Sony VAIO) */
+ { USB_DEVICE(VENDOR_SMK, 0x0322),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* bundled with Hauppauge PVR-150 */
+ { USB_DEVICE(VENDOR_SMK, 0x0334),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* SMK eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_SMK, 0x0338) },
+ /* Tatung eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TATUNG, 0x9150) },
+ /* Shuttle eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_SHUTTLE, 0xc001) },
+ /* Shuttle eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_SHUTTLE2, 0xc001) },
+ /* Gateway eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_GATEWAY, 0x3009) },
+ /* Mitsumi */
+ { USB_DEVICE(VENDOR_MITSUMI, 0x2501) },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0001),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* Topseed HP eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0006),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0007),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0008),
+ .driver_info = MCE_GEN3 },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x000a),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* Topseed eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_TOPSEED, 0x0011),
+ .driver_info = MCE_GEN2_TX_INV },
+ /* Ricavision internal Infrared Transceiver */
+ { USB_DEVICE(VENDOR_RICAVISION, 0x0010) },
+ /* Itron ione Libra Q-11 */
+ { USB_DEVICE(VENDOR_ITRON, 0x7002) },
+ /* FIC eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_FIC, 0x9242) },
+ /* LG eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_LG, 0x9803) },
+ /* Microsoft MCE Infrared Transceiver */
+ { USB_DEVICE(VENDOR_MICROSOFT, 0x00a0) },
+ /* Formosa eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe015) },
+ /* Formosa21 / eHome Infrared Receiver */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe016) },
+ /* Formosa aim / Trust MCE Infrared Receiver */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe017) },
+ /* Formosa Industrial Computing / Beanbag Emulation Device */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe018) },
+ /* Formosa21 / eHome Infrared Receiver */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03a) },
+ /* Formosa Industrial Computing AIM IR605/A */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03c) },
+ /* Formosa Industrial Computing */
+ { USB_DEVICE(VENDOR_FORMOSA, 0xe03e) },
+ /* Fintek eHome Infrared Transceiver (HP branded) */
+ { USB_DEVICE(VENDOR_FINTEK, 0x5168) },
+ /* Fintek eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_FINTEK, 0x0602) },
+ /* Fintek eHome Infrared Transceiver (in the AOpen MP45) */
+ { USB_DEVICE(VENDOR_FINTEK, 0x0702) },
+ /* Pinnacle Remote Kit */
+ { USB_DEVICE(VENDOR_PINNACLE, 0x0225),
+ .driver_info = MCE_GEN3 },
+ /* Elitegroup Computer Systems IR */
+ { USB_DEVICE(VENDOR_ECS, 0x0f38) },
+ /* Wistron Corp. eHome Infrared Receiver */
+ { USB_DEVICE(VENDOR_WISTRON, 0x0002) },
+ /* Compro K100 */
+ { USB_DEVICE(VENDOR_COMPRO, 0x3020) },
+ /* Compro K100 v2 */
+ { USB_DEVICE(VENDOR_COMPRO, 0x3082) },
+ /* Northstar Systems, Inc. eHome Infrared Transceiver */
+ { USB_DEVICE(VENDOR_NORTHSTAR, 0xe004) },
+ /* TiVo PC IR Receiver */
+ { USB_DEVICE(VENDOR_TIVO, 0x2000) },
+ /* Conexant Hybrid TV "Shelby" Polaris SDK */
+ { USB_DEVICE(VENDOR_CONEXANT, 0x58a1),
+ .driver_info = POLARIS_EVK },
+ /* Conexant Hybrid TV RDU253S Polaris */
+ { USB_DEVICE(VENDOR_CONEXANT, 0x58a5),
+ .driver_info = CX_HYBRID_TV },
+ /* Terminating entry */
+ { }
+};
+
+/* data structure for each usb transceiver */
+struct mceusb_dev {
+ /* ir-core bits */
+ struct rc_dev *rc;
+
+ /* optional features we can enable */
+ bool carrier_report_enabled;
+ bool learning_enabled;
+
+ /* core device bits */
+ struct device *dev;
+
+ /* usb */
+ struct usb_device *usbdev;
+ struct urb *urb_in;
+ struct usb_endpoint_descriptor *usb_ep_in;
+ struct usb_endpoint_descriptor *usb_ep_out;
+
+ /* buffers and dma */
+ unsigned char *buf_in;
+ unsigned int len_in;
+ dma_addr_t dma_in;
+ dma_addr_t dma_out;
+
+ enum {
+ CMD_HEADER = 0,
+ SUBCMD,
+ CMD_DATA,
+ PARSE_IRDATA,
+ } parser_state;
+
+ u8 cmd, rem; /* Remaining IR data bytes in packet */
+
+ struct {
+ u32 connected:1;
+ u32 tx_mask_normal:1;
+ u32 microsoft_gen1:1;
+ u32 no_tx:1;
+ } flags;
+
+ /* transmit support */
+ int send_flags;
+ u32 carrier;
+ unsigned char tx_mask;
+
+ char name[128];
+ char phys[64];
+ enum mceusb_model_type model;
+};
+
+/*
+ * MCE Device Command Strings
+ * Device command responses vary from device to device...
+ * - DEVICE_RESET resets the hardware to its default state
+ * - GET_REVISION fetches the hardware/software revision, common
+ * replies are ff 0b 45 ff 1b 08 and ff 0b 50 ff 1b 42
+ * - GET_CARRIER_FREQ gets the carrier mode and frequency of the
+ * device, with replies in the form of 9f 06 MM FF, where MM is 0-3,
+ * meaning clk of 10000000, 2500000, 625000 or 156250, and FF is
+ * ((clk / frequency) - 1)
+ * - GET_RX_TIMEOUT fetches the receiver timeout in units of 50us,
+ * response in the form of 9f 0c msb lsb
+ * - GET_TX_BITMASK fetches the transmitter bitmask, replies in
+ * the form of 9f 08 bm, where bm is the bitmask
+ * - GET_RX_SENSOR fetches the RX sensor setting -- long-range
+ * general use one or short-range learning one, in the form of
+ * 9f 14 ss, where ss is either 01 for long-range or 02 for short
+ * - SET_CARRIER_FREQ sets a new carrier mode and frequency
+ * - SET_TX_BITMASK sets the transmitter bitmask
+ * - SET_RX_TIMEOUT sets the receiver timeout
+ * - SET_RX_SENSOR sets which receiver sensor to use
+ */
+static char DEVICE_RESET[] = {MCE_COMMAND_NULL, MCE_HW_CMD_HEADER,
+ MCE_CMD_DEVICE_RESET};
+static char GET_REVISION[] = {MCE_HW_CMD_HEADER, MCE_CMD_G_REVISION};
+static char GET_UNKNOWN[] = {MCE_HW_CMD_HEADER, MCE_CMD_UNKNOWN7};
+static char GET_UNKNOWN2[] = {MCE_COMMAND_HEADER, MCE_CMD_UNKNOWN2};
+static char GET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER, MCE_CMD_G_CARRIER};
+static char GET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TIMEOUT};
+static char GET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_G_TXMASK};
+static char GET_RX_SENSOR[] = {MCE_COMMAND_HEADER, MCE_CMD_G_RXSENSOR};
+/* sub in desired values in lower byte or bytes for full command */
+/* FIXME: make use of these for transmit.
+static char SET_CARRIER_FREQ[] = {MCE_COMMAND_HEADER,
+ MCE_CMD_S_CARRIER, 0x00, 0x00};
+static char SET_TX_BITMASK[] = {MCE_COMMAND_HEADER, MCE_CMD_S_TXMASK, 0x00};
+static char SET_RX_TIMEOUT[] = {MCE_COMMAND_HEADER,
+ MCE_CMD_S_TIMEOUT, 0x00, 0x00};
+static char SET_RX_SENSOR[] = {MCE_COMMAND_HEADER,
+ MCE_CMD_S_RXSENSOR, 0x00};
+*/
+
+static int mceusb_cmdsize(u8 cmd, u8 subcmd)
+{
+ int datasize = 0;
+
+ switch (cmd) {
+ case MCE_COMMAND_NULL:
+ if (subcmd == MCE_HW_CMD_HEADER)
+ datasize = 1;
+ break;
+ case MCE_HW_CMD_HEADER:
+ switch (subcmd) {
+ case MCE_CMD_G_REVISION:
+ datasize = 2;
+ break;
+ }
+ case MCE_COMMAND_HEADER:
+ switch (subcmd) {
+ case MCE_CMD_UNKNOWN:
+ case MCE_CMD_S_CARRIER:
+ case MCE_CMD_S_TIMEOUT:
+ case MCE_RSP_PULSE_COUNT:
+ datasize = 2;
+ break;
+ case MCE_CMD_SIG_END:
+ case MCE_CMD_S_TXMASK:
+ case MCE_CMD_S_RXSENSOR:
+ datasize = 1;
+ break;
+ }
+ }
+ return datasize;
+}
+
+static void mceusb_dev_printdata(struct mceusb_dev *ir, char *buf,
+ int offset, int len, bool out)
+{
+ char codes[USB_BUFLEN * 3 + 1];
+ char inout[9];
+ u8 cmd, subcmd, data1, data2;
+ struct device *dev = ir->dev;
+ int i, start, skip = 0;
+
+ if (!debug)
+ return;
+
+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
+ if (ir->flags.microsoft_gen1 && !out && !offset)
+ skip = 2;
+
+ if (len <= skip)
+ return;
+
+ for (i = 0; i < len && i < USB_BUFLEN; i++)
+ snprintf(codes + i * 3, 4, "%02x ", buf[i + offset] & 0xff);
+
+ dev_info(dev, "%sx data: %s(length=%d)\n",
+ (out ? "t" : "r"), codes, len);
+
+ if (out)
+ strcpy(inout, "Request\0");
+ else
+ strcpy(inout, "Got\0");
+
+ start = offset + skip;
+ cmd = buf[start] & 0xff;
+ subcmd = buf[start + 1] & 0xff;
+ data1 = buf[start + 2] & 0xff;
+ data2 = buf[start + 3] & 0xff;
+
+ switch (cmd) {
+ case MCE_COMMAND_NULL:
+ if ((subcmd == MCE_HW_CMD_HEADER) &&
+ (data1 == MCE_CMD_DEVICE_RESET))
+ dev_info(dev, "Device reset requested\n");
+ else
+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ cmd, subcmd);
+ break;
+ case MCE_HW_CMD_HEADER:
+ switch (subcmd) {
+ case MCE_CMD_G_REVISION:
+ if (len == 2)
+ dev_info(dev, "Get hw/sw rev?\n");
+ else
+ dev_info(dev, "hw/sw rev 0x%02x 0x%02x "
+ "0x%02x 0x%02x\n", data1, data2,
+ buf[start + 4], buf[start + 5]);
+ break;
+ case MCE_CMD_DEVICE_RESET:
+ dev_info(dev, "Device reset requested\n");
+ break;
+ case MCE_RSP_CMD_INVALID:
+ dev_info(dev, "Previous command not supported\n");
+ break;
+ case MCE_CMD_UNKNOWN7:
+ case MCE_CMD_UNKNOWN9:
+ default:
+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ cmd, subcmd);
+ break;
+ }
+ break;
+ case MCE_COMMAND_HEADER:
+ switch (subcmd) {
+ case MCE_CMD_SIG_END:
+ dev_info(dev, "End of signal\n");
+ break;
+ case MCE_CMD_PING:
+ dev_info(dev, "Ping\n");
+ break;
+ case MCE_CMD_UNKNOWN:
+ dev_info(dev, "Resp to 9f 05 of 0x%02x 0x%02x\n",
+ data1, data2);
+ break;
+ case MCE_CMD_S_CARRIER:
+ dev_info(dev, "%s carrier mode and freq of "
+ "0x%02x 0x%02x\n", inout, data1, data2);
+ break;
+ case MCE_CMD_G_CARRIER:
+ dev_info(dev, "Get carrier mode and freq\n");
+ break;
+ case MCE_CMD_S_TXMASK:
+ dev_info(dev, "%s transmit blaster mask of 0x%02x\n",
+ inout, data1);
+ break;
+ case MCE_CMD_S_TIMEOUT:
+ /* value is in units of 50us, so x*50/100 or x/2 ms */
+ dev_info(dev, "%s receive timeout of %d ms\n",
+ inout, ((data1 << 8) | data2) / 2);
+ break;
+ case MCE_CMD_G_TIMEOUT:
+ dev_info(dev, "Get receive timeout\n");
+ break;
+ case MCE_CMD_G_TXMASK:
+ dev_info(dev, "Get transmit blaster mask\n");
+ break;
+ case MCE_CMD_S_RXSENSOR:
+ dev_info(dev, "%s %s-range receive sensor in use\n",
+ inout, data1 == 0x02 ? "short" : "long");
+ break;
+ case MCE_CMD_G_RXSENSOR:
+ /* aka MCE_RSP_PULSE_COUNT */
+ if (out)
+ dev_info(dev, "Get receive sensor\n");
+ else if (ir->learning_enabled)
+ dev_info(dev, "RX pulse count: %d\n",
+ ((data1 << 8) | data2));
+ break;
+ case MCE_RSP_CMD_INVALID:
+ dev_info(dev, "Error! Hardware is likely wedged...\n");
+ break;
+ case MCE_CMD_UNKNOWN2:
+ case MCE_CMD_UNKNOWN3:
+ case MCE_CMD_UNKNOWN5:
+ default:
+ dev_info(dev, "Unknown command 0x%02x 0x%02x\n",
+ cmd, subcmd);
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ if (cmd == MCE_IRDATA_TRAILER)
+ dev_info(dev, "End of raw IR data\n");
+ else if ((cmd != MCE_COMMAND_HEADER) &&
+ ((cmd & MCE_COMMAND_MASK) == MCE_COMMAND_IRDATA))
+ dev_info(dev, "Raw IR data, %d pulse/space samples\n", ir->rem);
+}
+
+static void mce_async_callback(struct urb *urb, struct pt_regs *regs)
+{
+ struct mceusb_dev *ir;
+ int len;
+
+ if (!urb)
+ return;
+
+ ir = urb->context;
+ if (ir) {
+ len = urb->actual_length;
+
+ dev_dbg(ir->dev, "callback called (status=%d len=%d)\n",
+ urb->status, len);
+
+ mceusb_dev_printdata(ir, urb->transfer_buffer, 0, len, true);
+ }
+
+}
+
+/* request incoming or send outgoing usb packet - used to initialize remote */
+static void mce_request_packet(struct mceusb_dev *ir,
+ struct usb_endpoint_descriptor *ep,
+ unsigned char *data, int size, int urb_type)
+{
+ int res;
+ struct urb *async_urb;
+ struct device *dev = ir->dev;
+ unsigned char *async_buf;
+
+ if (urb_type == MCEUSB_TX) {
+ async_urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (unlikely(!async_urb)) {
+ dev_err(dev, "Error, couldn't allocate urb!\n");
+ return;
+ }
+
+ async_buf = kzalloc(size, GFP_KERNEL);
+ if (!async_buf) {
+ dev_err(dev, "Error, couldn't allocate buf!\n");
+ usb_free_urb(async_urb);
+ return;
+ }
+
+ /* outbound data */
+ usb_fill_int_urb(async_urb, ir->usbdev,
+ usb_sndintpipe(ir->usbdev, ep->bEndpointAddress),
+ async_buf, size, (usb_complete_t)mce_async_callback,
+ ir, ep->bInterval);
+ memcpy(async_buf, data, size);
+
+ } else if (urb_type == MCEUSB_RX) {
+ /* standard request */
+ async_urb = ir->urb_in;
+ ir->send_flags = RECV_FLAG_IN_PROGRESS;
+
+ } else {
+ dev_err(dev, "Error! Unknown urb type %d\n", urb_type);
+ return;
+ }
+
+ dev_dbg(dev, "receive request called (size=%#x)\n", size);
+
+ async_urb->transfer_buffer_length = size;
+ async_urb->dev = ir->usbdev;
+
+ res = usb_submit_urb(async_urb, GFP_ATOMIC);
+ if (res) {
+ dev_dbg(dev, "receive request FAILED! (res=%d)\n", res);
+ return;
+ }
+ dev_dbg(dev, "receive request complete (res=%d)\n", res);
+}
+
+static void mce_async_out(struct mceusb_dev *ir, unsigned char *data, int size)
+{
+ mce_request_packet(ir, ir->usb_ep_out, data, size, MCEUSB_TX);
+}
+
+static void mce_sync_in(struct mceusb_dev *ir, unsigned char *data, int size)
+{
+ mce_request_packet(ir, ir->usb_ep_in, data, size, MCEUSB_RX);
+}
+
+/* Send data out the IR blaster port(s) */
+static int mceusb_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+{
+ struct mceusb_dev *ir = dev->priv;
+ int i, ret = 0;
+ int count, cmdcount = 0;
+ unsigned char *cmdbuf; /* MCE command buffer */
+ long signal_duration = 0; /* Singnal length in us */
+ struct timeval start_time, end_time;
+
+ do_gettimeofday(&start_time);
+
+ count = n / sizeof(int);
+
+ cmdbuf = kzalloc(sizeof(int) * MCE_CMDBUF_SIZE, GFP_KERNEL);
+ if (!cmdbuf)
+ return -ENOMEM;
+
+ /* MCE tx init header */
+ cmdbuf[cmdcount++] = MCE_COMMAND_HEADER;
+ cmdbuf[cmdcount++] = MCE_CMD_S_TXMASK;
+ cmdbuf[cmdcount++] = ir->tx_mask;
+
+ /* Generate mce packet data */
+ for (i = 0; (i < count) && (cmdcount < MCE_CMDBUF_SIZE); i++) {
+ signal_duration += txbuf[i];
+ txbuf[i] = txbuf[i] / MCE_TIME_UNIT;
+
+ do { /* loop to support long pulses/spaces > 127*50us=6.35ms */
+
+ /* Insert mce packet header every 4th entry */
+ if ((cmdcount < MCE_CMDBUF_SIZE) &&
+ (cmdcount - MCE_TX_HEADER_LENGTH) %
+ MCE_CODE_LENGTH == 0)
+ cmdbuf[cmdcount++] = MCE_IRDATA_HEADER;
+
+ /* Insert mce packet data */
+ if (cmdcount < MCE_CMDBUF_SIZE)
+ cmdbuf[cmdcount++] =
+ (txbuf[i] < MCE_PULSE_BIT ?
+ txbuf[i] : MCE_MAX_PULSE_LENGTH) |
+ (i & 1 ? 0x00 : MCE_PULSE_BIT);
+ else {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ } while ((txbuf[i] > MCE_MAX_PULSE_LENGTH) &&
+ (txbuf[i] -= MCE_MAX_PULSE_LENGTH));
+ }
+
+ /* Fix packet length in last header */
+ cmdbuf[cmdcount - (cmdcount - MCE_TX_HEADER_LENGTH) % MCE_CODE_LENGTH] =
+ MCE_COMMAND_IRDATA + (cmdcount - MCE_TX_HEADER_LENGTH) %
+ MCE_CODE_LENGTH - 1;
+
+ /* Check if we have room for the empty packet at the end */
+ if (cmdcount >= MCE_CMDBUF_SIZE) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ /* All mce commands end with an empty packet (0x80) */
+ cmdbuf[cmdcount++] = MCE_IRDATA_TRAILER;
+
+ /* Transmit the command to the mce device */
+ mce_async_out(ir, cmdbuf, cmdcount);
+
+ /*
+ * The lircd gap calculation expects the write function to
+ * wait the time it takes for the ircommand to be sent before
+ * it returns.
+ */
+ do_gettimeofday(&end_time);
+ signal_duration -= (end_time.tv_usec - start_time.tv_usec) +
+ (end_time.tv_sec - start_time.tv_sec) * 1000000;
+
+ /* delay with the closest number of ticks */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(signal_duration));
+
+out:
+ kfree(cmdbuf);
+ return ret ? ret : n;
+}
+
+/* Sets active IR outputs -- mce devices typically have two */
+static int mceusb_set_tx_mask(struct rc_dev *dev, u32 mask)
+{
+ struct mceusb_dev *ir = dev->priv;
+
+ if (ir->flags.tx_mask_normal)
+ ir->tx_mask = mask;
+ else
+ ir->tx_mask = (mask != MCE_DEFAULT_TX_MASK ?
+ mask ^ MCE_DEFAULT_TX_MASK : mask) << 1;
+
+ return 0;
+}
+
+/* Sets the send carrier frequency and mode */
+static int mceusb_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+{
+ struct mceusb_dev *ir = dev->priv;
+ int clk = 10000000;
+ int prescaler = 0, divisor = 0;
+ unsigned char cmdbuf[4] = { MCE_COMMAND_HEADER,
+ MCE_CMD_S_CARRIER, 0x00, 0x00 };
+
+ /* Carrier has changed */
+ if (ir->carrier != carrier) {
+
+ if (carrier == 0) {
+ ir->carrier = carrier;
+ cmdbuf[2] = MCE_CMD_SIG_END;
+ cmdbuf[3] = MCE_IRDATA_TRAILER;
+ dev_dbg(ir->dev, "%s: disabling carrier "
+ "modulation\n", __func__);
+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+ return carrier;
+ }
+
+ for (prescaler = 0; prescaler < 4; ++prescaler) {
+ divisor = (clk >> (2 * prescaler)) / carrier;
+ if (divisor <= 0xff) {
+ ir->carrier = carrier;
+ cmdbuf[2] = prescaler;
+ cmdbuf[3] = divisor;
+ dev_dbg(ir->dev, "%s: requesting %u HZ "
+ "carrier\n", __func__, carrier);
+
+ /* Transmit new carrier to mce device */
+ mce_async_out(ir, cmdbuf, sizeof(cmdbuf));
+ return carrier;
+ }
+ }
+
+ return -EINVAL;
+
+ }
+
+ return carrier;
+}
+
+/*
+ * We don't do anything but print debug spew for many of the command bits
+ * we receive from the hardware, but some of them are useful information
+ * we want to store so that we can use them.
+ */
+static void mceusb_handle_command(struct mceusb_dev *ir, int index)
+{
+ u8 hi = ir->buf_in[index + 1] & 0xff;
+ u8 lo = ir->buf_in[index + 2] & 0xff;
+
+ switch (ir->buf_in[index]) {
+ /* 2-byte return value commands */
+ case MCE_CMD_S_TIMEOUT:
+ ir->rc->timeout = MS_TO_NS((hi << 8 | lo) / 2);
+ break;
+
+ /* 1-byte return value commands */
+ case MCE_CMD_S_TXMASK:
+ ir->tx_mask = hi;
+ break;
+ case MCE_CMD_S_RXSENSOR:
+ ir->learning_enabled = (hi == 0x02);
+ break;
+ default:
+ break;
+ }
+}
+
+static void mceusb_process_ir_data(struct mceusb_dev *ir, int buf_len)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+ int i = 0;
+
+ /* skip meaningless 0xb1 0x60 header bytes on orig receiver */
+ if (ir->flags.microsoft_gen1)
+ i = 2;
+
+ /* if there's no data, just return now */
+ if (buf_len <= i)
+ return;
+
+ for (; i < buf_len; i++) {
+ switch (ir->parser_state) {
+ case SUBCMD:
+ ir->rem = mceusb_cmdsize(ir->cmd, ir->buf_in[i]);
+ mceusb_dev_printdata(ir, ir->buf_in, i - 1,
+ ir->rem + 2, false);
+ mceusb_handle_command(ir, i);
+ ir->parser_state = CMD_DATA;
+ break;
+ case PARSE_IRDATA:
+ ir->rem--;
+ rawir.pulse = ((ir->buf_in[i] & MCE_PULSE_BIT) != 0);
+ rawir.duration = (ir->buf_in[i] & MCE_PULSE_MASK)
+ * MS_TO_US(MCE_TIME_UNIT);
+
+ dev_dbg(ir->dev, "Storing %s with duration %d\n",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+
+ ir_raw_event_store_with_filter(ir->rc, &rawir);
+ break;
+ case CMD_DATA:
+ ir->rem--;
+ break;
+ case CMD_HEADER:
+ /* decode mce packets of the form (84),AA,BB,CC,DD */
+ /* IR data packets can span USB messages - rem */
+ ir->cmd = ir->buf_in[i];
+ if ((ir->cmd == MCE_COMMAND_HEADER) ||
+ ((ir->cmd & MCE_COMMAND_MASK) !=
+ MCE_COMMAND_IRDATA)) {
+ ir->parser_state = SUBCMD;
+ continue;
+ }
+ ir->rem = (ir->cmd & MCE_PACKET_LENGTH_MASK);
+ mceusb_dev_printdata(ir, ir->buf_in,
+ i, ir->rem + 1, false);
+ if (ir->rem)
+ ir->parser_state = PARSE_IRDATA;
+ break;
+ }
+
+ if (ir->parser_state != CMD_HEADER && !ir->rem)
+ ir->parser_state = CMD_HEADER;
+ }
+ dev_dbg(ir->dev, "processed IR data, calling ir_raw_event_handle\n");
+ ir_raw_event_handle(ir->rc);
+}
+
+static void mceusb_dev_recv(struct urb *urb, struct pt_regs *regs)
+{
+ struct mceusb_dev *ir;
+ int buf_len;
+
+ if (!urb)
+ return;
+
+ ir = urb->context;
+ if (!ir) {
+ usb_unlink_urb(urb);
+ return;
+ }
+
+ buf_len = urb->actual_length;
+
+ if (ir->send_flags == RECV_FLAG_IN_PROGRESS) {
+ ir->send_flags = SEND_FLAG_COMPLETE;
+ dev_dbg(ir->dev, "setup answer received %d bytes\n",
+ buf_len);
+ }
+
+ switch (urb->status) {
+ /* success */
+ case 0:
+ mceusb_process_ir_data(ir, buf_len);
+ break;
+
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ usb_unlink_urb(urb);
+ return;
+
+ case -EPIPE:
+ default:
+ dev_dbg(ir->dev, "Error: urb status = %d\n", urb->status);
+ break;
+ }
+
+ usb_submit_urb(urb, GFP_ATOMIC);
+}
+
+static void mceusb_gen1_init(struct mceusb_dev *ir)
+{
+ int ret;
+ int maxp = ir->len_in;
+ struct device *dev = ir->dev;
+ char *data;
+
+ data = kzalloc(USB_CTRL_MSG_SZ, GFP_KERNEL);
+ if (!data) {
+ dev_err(dev, "%s: memory allocation failed!\n", __func__);
+ return;
+ }
+
+ /*
+ * This is a strange one. Windows issues a set address to the device
+ * on the receive control pipe and expect a certain value pair back
+ */
+ ret = usb_control_msg(ir->usbdev, usb_rcvctrlpipe(ir->usbdev, 0),
+ USB_REQ_SET_ADDRESS, USB_TYPE_VENDOR, 0, 0,
+ data, USB_CTRL_MSG_SZ, HZ * 3);
+ dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+ dev_dbg(dev, "%s - data[0] = %d, data[1] = %d\n",
+ __func__, data[0], data[1]);
+
+ /* set feature: bit rate 38400 bps */
+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+ USB_REQ_SET_FEATURE, USB_TYPE_VENDOR,
+ 0xc04e, 0x0000, NULL, 0, HZ * 3);
+
+ dev_dbg(dev, "%s - ret = %d\n", __func__, ret);
+
+ /* bRequest 4: set char length to 8 bits */
+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+ 4, USB_TYPE_VENDOR,
+ 0x0808, 0x0000, NULL, 0, HZ * 3);
+ dev_dbg(dev, "%s - retB = %d\n", __func__, ret);
+
+ /* bRequest 2: set handshaking to use DTR/DSR */
+ ret = usb_control_msg(ir->usbdev, usb_sndctrlpipe(ir->usbdev, 0),
+ 2, USB_TYPE_VENDOR,
+ 0x0000, 0x0100, NULL, 0, HZ * 3);
+ dev_dbg(dev, "%s - retC = %d\n", __func__, ret);
+
+ /* device reset */
+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* get hw/sw revision? */
+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
+ mce_sync_in(ir, NULL, maxp);
+
+ kfree(data);
+};
+
+static void mceusb_gen2_init(struct mceusb_dev *ir)
+{
+ int maxp = ir->len_in;
+
+ /* device reset */
+ mce_async_out(ir, DEVICE_RESET, sizeof(DEVICE_RESET));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* get hw/sw revision? */
+ mce_async_out(ir, GET_REVISION, sizeof(GET_REVISION));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* unknown what the next two actually return... */
+ mce_async_out(ir, GET_UNKNOWN, sizeof(GET_UNKNOWN));
+ mce_sync_in(ir, NULL, maxp);
+ mce_async_out(ir, GET_UNKNOWN2, sizeof(GET_UNKNOWN2));
+ mce_sync_in(ir, NULL, maxp);
+}
+
+static void mceusb_get_parameters(struct mceusb_dev *ir)
+{
+ int maxp = ir->len_in;
+
+ /* get the carrier and frequency */
+ mce_async_out(ir, GET_CARRIER_FREQ, sizeof(GET_CARRIER_FREQ));
+ mce_sync_in(ir, NULL, maxp);
+
+ if (!ir->flags.no_tx) {
+ /* get the transmitter bitmask */
+ mce_async_out(ir, GET_TX_BITMASK, sizeof(GET_TX_BITMASK));
+ mce_sync_in(ir, NULL, maxp);
+ }
+
+ /* get receiver timeout value */
+ mce_async_out(ir, GET_RX_TIMEOUT, sizeof(GET_RX_TIMEOUT));
+ mce_sync_in(ir, NULL, maxp);
+
+ /* get receiver sensor setting */
+ mce_async_out(ir, GET_RX_SENSOR, sizeof(GET_RX_SENSOR));
+ mce_sync_in(ir, NULL, maxp);
+}
+
+static struct rc_dev *mceusb_init_rc_dev(struct mceusb_dev *ir)
+{
+ struct device *dev = ir->dev;
+ struct rc_dev *rc;
+ int ret;
+
+ rc = rc_allocate_device();
+ if (!rc) {
+ dev_err(dev, "remote dev allocation failed\n");
+ goto out;
+ }
+
+ snprintf(ir->name, sizeof(ir->name), "%s (%04x:%04x)",
+ mceusb_model[ir->model].name ?
+ mceusb_model[ir->model].name :
+ "Media Center Ed. eHome Infrared Remote Transceiver",
+ le16_to_cpu(ir->usbdev->descriptor.idVendor),
+ le16_to_cpu(ir->usbdev->descriptor.idProduct));
+
+ usb_make_path(ir->usbdev, ir->phys, sizeof(ir->phys));
+
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ usb_to_input_id(ir->usbdev, &rc->input_id);
+ rc->dev.parent = dev;
+ rc->priv = ir;
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->allowed_protos = RC_TYPE_ALL;
+ rc->timeout = MS_TO_NS(1000);
+ if (!ir->flags.no_tx) {
+ rc->s_tx_mask = mceusb_set_tx_mask;
+ rc->s_tx_carrier = mceusb_set_tx_carrier;
+ rc->tx_ir = mceusb_tx_ir;
+ }
+ rc->driver_name = DRIVER_NAME;
+ rc->map_name = mceusb_model[ir->model].rc_map ?
+ mceusb_model[ir->model].rc_map : RC_MAP_RC6_MCE;
+
+ ret = rc_register_device(rc);
+ if (ret < 0) {
+ dev_err(dev, "remote dev registration failed\n");
+ goto out;
+ }
+
+ return rc;
+
+out:
+ rc_free_device(rc);
+ return NULL;
+}
+
+static int __devinit mceusb_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct usb_host_interface *idesc;
+ struct usb_endpoint_descriptor *ep = NULL;
+ struct usb_endpoint_descriptor *ep_in = NULL;
+ struct usb_endpoint_descriptor *ep_out = NULL;
+ struct mceusb_dev *ir = NULL;
+ int pipe, maxp, i;
+ char buf[63], name[128] = "";
+ enum mceusb_model_type model = id->driver_info;
+ bool is_gen3;
+ bool is_microsoft_gen1;
+ bool tx_mask_normal;
+ bool is_polaris;
+
+ dev_dbg(&intf->dev, "%s called\n", __func__);
+
+ idesc = intf->cur_altsetting;
+
+ is_gen3 = mceusb_model[model].mce_gen3;
+ is_microsoft_gen1 = mceusb_model[model].mce_gen1;
+ tx_mask_normal = mceusb_model[model].tx_mask_normal;
+ is_polaris = mceusb_model[model].is_polaris;
+
+ if (is_polaris) {
+ /* Interface 0 is IR */
+ if (idesc->desc.bInterfaceNumber)
+ return -ENODEV;
+ }
+
+ /* step through the endpoints to find first bulk in and out endpoint */
+ for (i = 0; i < idesc->desc.bNumEndpoints; ++i) {
+ ep = &idesc->endpoint[i].desc;
+
+ if ((ep_in == NULL)
+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_IN)
+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK)
+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT))) {
+
+ ep_in = ep;
+ ep_in->bmAttributes = USB_ENDPOINT_XFER_INT;
+ ep_in->bInterval = 1;
+ dev_dbg(&intf->dev, "acceptable inbound endpoint "
+ "found\n");
+ }
+
+ if ((ep_out == NULL)
+ && ((ep->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ == USB_DIR_OUT)
+ && (((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_BULK)
+ || ((ep->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ == USB_ENDPOINT_XFER_INT))) {
+
+ ep_out = ep;
+ ep_out->bmAttributes = USB_ENDPOINT_XFER_INT;
+ ep_out->bInterval = 1;
+ dev_dbg(&intf->dev, "acceptable outbound endpoint "
+ "found\n");
+ }
+ }
+ if (ep_in == NULL) {
+ dev_dbg(&intf->dev, "inbound and/or endpoint not found\n");
+ return -ENODEV;
+ }
+
+ pipe = usb_rcvintpipe(dev, ep_in->bEndpointAddress);
+ maxp = usb_maxpacket(dev, pipe, usb_pipeout(pipe));
+
+ ir = kzalloc(sizeof(struct mceusb_dev), GFP_KERNEL);
+ if (!ir)
+ goto mem_alloc_fail;
+
+ ir->buf_in = usb_alloc_coherent(dev, maxp, GFP_ATOMIC, &ir->dma_in);
+ if (!ir->buf_in)
+ goto buf_in_alloc_fail;
+
+ ir->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+ if (!ir->urb_in)
+ goto urb_in_alloc_fail;
+
+ ir->usbdev = dev;
+ ir->dev = &intf->dev;
+ ir->len_in = maxp;
+ ir->flags.microsoft_gen1 = is_microsoft_gen1;
+ ir->flags.tx_mask_normal = tx_mask_normal;
+ ir->flags.no_tx = mceusb_model[model].no_tx;
+ ir->model = model;
+
+ /* Saving usb interface data for use by the transmitter routine */
+ ir->usb_ep_in = ep_in;
+ ir->usb_ep_out = ep_out;
+
+ if (dev->descriptor.iManufacturer
+ && usb_string(dev, dev->descriptor.iManufacturer,
+ buf, sizeof(buf)) > 0)
+ strlcpy(name, buf, sizeof(name));
+ if (dev->descriptor.iProduct
+ && usb_string(dev, dev->descriptor.iProduct,
+ buf, sizeof(buf)) > 0)
+ snprintf(name + strlen(name), sizeof(name) - strlen(name),
+ " %s", buf);
+
+ ir->rc = mceusb_init_rc_dev(ir);
+ if (!ir->rc)
+ goto rc_dev_fail;
+
+ /* flush buffers on the device */
+ mce_sync_in(ir, NULL, maxp);
+ mce_sync_in(ir, NULL, maxp);
+
+ /* wire up inbound data handler */
+ usb_fill_int_urb(ir->urb_in, dev, pipe, ir->buf_in,
+ maxp, (usb_complete_t) mceusb_dev_recv, ir, ep_in->bInterval);
+ ir->urb_in->transfer_dma = ir->dma_in;
+ ir->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ /* initialize device */
+ if (ir->flags.microsoft_gen1)
+ mceusb_gen1_init(ir);
+ else if (!is_gen3)
+ mceusb_gen2_init(ir);
+
+ mceusb_get_parameters(ir);
+
+ if (!ir->flags.no_tx)
+ mceusb_set_tx_mask(ir->rc, MCE_DEFAULT_TX_MASK);
+
+ usb_set_intfdata(intf, ir);
+
+ dev_info(&intf->dev, "Registered %s on usb%d:%d\n", name,
+ dev->bus->busnum, dev->devnum);
+
+ return 0;
+
+ /* Error-handling path */
+rc_dev_fail:
+ usb_free_urb(ir->urb_in);
+urb_in_alloc_fail:
+ usb_free_coherent(dev, maxp, ir->buf_in, ir->dma_in);
+buf_in_alloc_fail:
+ kfree(ir);
+mem_alloc_fail:
+ dev_err(&intf->dev, "%s: device setup failed!\n", __func__);
+
+ return -ENOMEM;
+}
+
+
+static void __devexit mceusb_dev_disconnect(struct usb_interface *intf)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+ struct mceusb_dev *ir = usb_get_intfdata(intf);
+
+ usb_set_intfdata(intf, NULL);
+
+ if (!ir)
+ return;
+
+ ir->usbdev = NULL;
+ rc_unregister_device(ir->rc);
+ usb_kill_urb(ir->urb_in);
+ usb_free_urb(ir->urb_in);
+ usb_free_coherent(dev, ir->len_in, ir->buf_in, ir->dma_in);
+
+ kfree(ir);
+}
+
+static int mceusb_dev_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct mceusb_dev *ir = usb_get_intfdata(intf);
+ dev_info(ir->dev, "suspend\n");
+ usb_kill_urb(ir->urb_in);
+ return 0;
+}
+
+static int mceusb_dev_resume(struct usb_interface *intf)
+{
+ struct mceusb_dev *ir = usb_get_intfdata(intf);
+ dev_info(ir->dev, "resume\n");
+ if (usb_submit_urb(ir->urb_in, GFP_ATOMIC))
+ return -EIO;
+ return 0;
+}
+
+static struct usb_driver mceusb_dev_driver = {
+ .name = DRIVER_NAME,
+ .probe = mceusb_dev_probe,
+ .disconnect = mceusb_dev_disconnect,
+ .suspend = mceusb_dev_suspend,
+ .resume = mceusb_dev_resume,
+ .reset_resume = mceusb_dev_resume,
+ .id_table = mceusb_dev_table
+};
+
+static int __init mceusb_dev_init(void)
+{
+ int ret;
+
+ ret = usb_register(&mceusb_dev_driver);
+ if (ret < 0)
+ printk(KERN_ERR DRIVER_NAME
+ ": usb register failed, result = %d\n", ret);
+
+ return ret;
+}
+
+static void __exit mceusb_dev_exit(void)
+{
+ usb_deregister(&mceusb_dev_driver);
+}
+
+module_init(mceusb_dev_init);
+module_exit(mceusb_dev_exit);
+
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_AUTHOR(DRIVER_AUTHOR);
+MODULE_LICENSE("GPL");
+MODULE_DEVICE_TABLE(usb, mceusb_dev_table);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Debug enabled or not");
diff --git a/drivers/media/rc/nuvoton-cir.c b/drivers/media/rc/nuvoton-cir.c
new file mode 100644
index 000000000000..dd4caf8ef80b
--- /dev/null
+++ b/drivers/media/rc/nuvoton-cir.c
@@ -0,0 +1,1244 @@
+/*
+ * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
+ *
+ * Copyright (C) 2010 Jarod Wilson <jarod@redhat.com>
+ * Copyright (C) 2009 Nuvoton PS Team
+ *
+ * Special thanks to Nuvoton for providing hardware, spec sheets and
+ * sample code upon which portions of this driver are based. Indirect
+ * thanks also to Maxim Levitsky, whose ene_ir driver this driver is
+ * modeled after.
+ *
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/pnp.h>
+#include <linux/io.h>
+#include <linux/interrupt.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <media/rc-core.h>
+#include <linux/pci_ids.h>
+
+#include "nuvoton-cir.h"
+
+static char *chip_id = "w836x7hg";
+
+/* write val to config reg */
+static inline void nvt_cr_write(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+ outb(reg, nvt->cr_efir);
+ outb(val, nvt->cr_efdr);
+}
+
+/* read val from config reg */
+static inline u8 nvt_cr_read(struct nvt_dev *nvt, u8 reg)
+{
+ outb(reg, nvt->cr_efir);
+ return inb(nvt->cr_efdr);
+}
+
+/* update config register bit without changing other bits */
+static inline void nvt_set_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+ u8 tmp = nvt_cr_read(nvt, reg) | val;
+ nvt_cr_write(nvt, tmp, reg);
+}
+
+/* clear config register bit without changing other bits */
+static inline void nvt_clear_reg_bit(struct nvt_dev *nvt, u8 val, u8 reg)
+{
+ u8 tmp = nvt_cr_read(nvt, reg) & ~val;
+ nvt_cr_write(nvt, tmp, reg);
+}
+
+/* enter extended function mode */
+static inline void nvt_efm_enable(struct nvt_dev *nvt)
+{
+ /* Enabling Extended Function Mode explicitly requires writing 2x */
+ outb(EFER_EFM_ENABLE, nvt->cr_efir);
+ outb(EFER_EFM_ENABLE, nvt->cr_efir);
+}
+
+/* exit extended function mode */
+static inline void nvt_efm_disable(struct nvt_dev *nvt)
+{
+ outb(EFER_EFM_DISABLE, nvt->cr_efir);
+}
+
+/*
+ * When you want to address a specific logical device, write its logical
+ * device number to CR_LOGICAL_DEV_SEL, then enable/disable by writing
+ * 0x1/0x0 respectively to CR_LOGICAL_DEV_EN.
+ */
+static inline void nvt_select_logical_dev(struct nvt_dev *nvt, u8 ldev)
+{
+ outb(CR_LOGICAL_DEV_SEL, nvt->cr_efir);
+ outb(ldev, nvt->cr_efdr);
+}
+
+/* write val to cir config register */
+static inline void nvt_cir_reg_write(struct nvt_dev *nvt, u8 val, u8 offset)
+{
+ outb(val, nvt->cir_addr + offset);
+}
+
+/* read val from cir config register */
+static u8 nvt_cir_reg_read(struct nvt_dev *nvt, u8 offset)
+{
+ u8 val;
+
+ val = inb(nvt->cir_addr + offset);
+
+ return val;
+}
+
+/* write val to cir wake register */
+static inline void nvt_cir_wake_reg_write(struct nvt_dev *nvt,
+ u8 val, u8 offset)
+{
+ outb(val, nvt->cir_wake_addr + offset);
+}
+
+/* read val from cir wake config register */
+static u8 nvt_cir_wake_reg_read(struct nvt_dev *nvt, u8 offset)
+{
+ u8 val;
+
+ val = inb(nvt->cir_wake_addr + offset);
+
+ return val;
+}
+
+#define pr_reg(text, ...) \
+ printk(KERN_INFO KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+/* dump current cir register contents */
+static void cir_dump_regs(struct nvt_dev *nvt)
+{
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+
+ pr_reg("%s: Dump CIR logical device registers:\n", NVT_DRIVER_NAME);
+ pr_reg(" * CR CIR ACTIVE : 0x%x\n",
+ nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
+ pr_reg(" * CR CIR BASE ADDR: 0x%x\n",
+ (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
+ nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
+ pr_reg(" * CR CIR IRQ NUM: 0x%x\n",
+ nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
+
+ nvt_efm_disable(nvt);
+
+ pr_reg("%s: Dump CIR registers:\n", NVT_DRIVER_NAME);
+ pr_reg(" * IRCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRCON));
+ pr_reg(" * IRSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRSTS));
+ pr_reg(" * IREN: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IREN));
+ pr_reg(" * RXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_RXFCONT));
+ pr_reg(" * CP: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CP));
+ pr_reg(" * CC: 0x%x\n", nvt_cir_reg_read(nvt, CIR_CC));
+ pr_reg(" * SLCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCH));
+ pr_reg(" * SLCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SLCL));
+ pr_reg(" * FIFOCON: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FIFOCON));
+ pr_reg(" * IRFIFOSTS: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFIFOSTS));
+ pr_reg(" * SRXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_SRXFIFO));
+ pr_reg(" * TXFCONT: 0x%x\n", nvt_cir_reg_read(nvt, CIR_TXFCONT));
+ pr_reg(" * STXFIFO: 0x%x\n", nvt_cir_reg_read(nvt, CIR_STXFIFO));
+ pr_reg(" * FCCH: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCH));
+ pr_reg(" * FCCL: 0x%x\n", nvt_cir_reg_read(nvt, CIR_FCCL));
+ pr_reg(" * IRFSM: 0x%x\n", nvt_cir_reg_read(nvt, CIR_IRFSM));
+}
+
+/* dump current cir wake register contents */
+static void cir_wake_dump_regs(struct nvt_dev *nvt)
+{
+ u8 i, fifo_len;
+
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+
+ pr_reg("%s: Dump CIR WAKE logical device registers:\n",
+ NVT_DRIVER_NAME);
+ pr_reg(" * CR CIR WAKE ACTIVE : 0x%x\n",
+ nvt_cr_read(nvt, CR_LOGICAL_DEV_EN));
+ pr_reg(" * CR CIR WAKE BASE ADDR: 0x%x\n",
+ (nvt_cr_read(nvt, CR_CIR_BASE_ADDR_HI) << 8) |
+ nvt_cr_read(nvt, CR_CIR_BASE_ADDR_LO));
+ pr_reg(" * CR CIR WAKE IRQ NUM: 0x%x\n",
+ nvt_cr_read(nvt, CR_CIR_IRQ_RSRC));
+
+ nvt_efm_disable(nvt);
+
+ pr_reg("%s: Dump CIR WAKE registers\n", NVT_DRIVER_NAME);
+ pr_reg(" * IRCON: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRCON));
+ pr_reg(" * IRSTS: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS));
+ pr_reg(" * IREN: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN));
+ pr_reg(" * FIFO CMP DEEP: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_DEEP));
+ pr_reg(" * FIFO CMP TOL: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_CMP_TOL));
+ pr_reg(" * FIFO COUNT: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT));
+ pr_reg(" * SLCH: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCH));
+ pr_reg(" * SLCL: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_SLCL));
+ pr_reg(" * FIFOCON: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON));
+ pr_reg(" * SRXFSTS: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_SRXFSTS));
+ pr_reg(" * SAMPLE RX FIFO: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_SAMPLE_RX_FIFO));
+ pr_reg(" * WR FIFO DATA: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_WR_FIFO_DATA));
+ pr_reg(" * RD FIFO ONLY: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
+ pr_reg(" * RD FIFO ONLY IDX: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX));
+ pr_reg(" * FIFO IGNORE: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_IGNORE));
+ pr_reg(" * IRFSM: 0x%x\n",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRFSM));
+
+ fifo_len = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFO_COUNT);
+ pr_reg("%s: Dump CIR WAKE FIFO (len %d)\n", NVT_DRIVER_NAME, fifo_len);
+ pr_reg("* Contents = ");
+ for (i = 0; i < fifo_len; i++)
+ printk(KERN_CONT "%02x ",
+ nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY));
+ printk(KERN_CONT "\n");
+}
+
+/* detect hardware features */
+static int nvt_hw_detect(struct nvt_dev *nvt)
+{
+ unsigned long flags;
+ u8 chip_major, chip_minor;
+ int ret = 0;
+
+ nvt_efm_enable(nvt);
+
+ /* Check if we're wired for the alternate EFER setup */
+ chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+ if (chip_major == 0xff) {
+ nvt->cr_efir = CR_EFIR2;
+ nvt->cr_efdr = CR_EFDR2;
+ nvt_efm_enable(nvt);
+ chip_major = nvt_cr_read(nvt, CR_CHIP_ID_HI);
+ }
+
+ chip_minor = nvt_cr_read(nvt, CR_CHIP_ID_LO);
+ nvt_dbg("%s: chip id: 0x%02x 0x%02x", chip_id, chip_major, chip_minor);
+
+ if (chip_major != CHIP_ID_HIGH ||
+ (chip_minor != CHIP_ID_LOW && chip_minor != CHIP_ID_LOW2)) {
+ nvt_pr(KERN_ERR, "%s: unsupported chip, id: 0x%02x 0x%02x",
+ chip_id, chip_major, chip_minor);
+ ret = -ENODEV;
+ }
+
+ nvt_efm_disable(nvt);
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->chip_major = chip_major;
+ nvt->chip_minor = chip_minor;
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ return ret;
+}
+
+static void nvt_cir_ldev_init(struct nvt_dev *nvt)
+{
+ u8 val;
+
+ /* output pin selection (Pin95=CIRRX, Pin96=CIRTX1, WB enabled */
+ val = nvt_cr_read(nvt, CR_OUTPUT_PIN_SEL);
+ val &= OUTPUT_PIN_SEL_MASK;
+ val |= (OUTPUT_ENABLE_CIR | OUTPUT_ENABLE_CIRWB);
+ nvt_cr_write(nvt, val, CR_OUTPUT_PIN_SEL);
+
+ /* Select CIR logical device and enable */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_cr_write(nvt, nvt->cir_addr >> 8, CR_CIR_BASE_ADDR_HI);
+ nvt_cr_write(nvt, nvt->cir_addr & 0xff, CR_CIR_BASE_ADDR_LO);
+
+ nvt_cr_write(nvt, nvt->cir_irq, CR_CIR_IRQ_RSRC);
+
+ nvt_dbg("CIR initialized, base io port address: 0x%lx, irq: %d",
+ nvt->cir_addr, nvt->cir_irq);
+}
+
+static void nvt_cir_wake_ldev_init(struct nvt_dev *nvt)
+{
+ /* Select ACPI logical device, enable it and CIR Wake */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ /* Enable CIR Wake via PSOUT# (Pin60) */
+ nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
+
+ /* enable cir interrupt of mouse/keyboard IRQ event */
+ nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
+
+ /* enable pme interrupt of cir wakeup event */
+ nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
+
+ /* Select CIR Wake logical device and enable */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_cr_write(nvt, nvt->cir_wake_addr >> 8, CR_CIR_BASE_ADDR_HI);
+ nvt_cr_write(nvt, nvt->cir_wake_addr & 0xff, CR_CIR_BASE_ADDR_LO);
+
+ nvt_cr_write(nvt, nvt->cir_wake_irq, CR_CIR_IRQ_RSRC);
+
+ nvt_dbg("CIR Wake initialized, base io port address: 0x%lx, irq: %d",
+ nvt->cir_wake_addr, nvt->cir_wake_irq);
+}
+
+/* clear out the hardware's cir rx fifo */
+static void nvt_clear_cir_fifo(struct nvt_dev *nvt)
+{
+ u8 val;
+
+ val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
+ nvt_cir_reg_write(nvt, val | CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
+}
+
+/* clear out the hardware's cir wake rx fifo */
+static void nvt_clear_cir_wake_fifo(struct nvt_dev *nvt)
+{
+ u8 val;
+
+ val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_FIFOCON);
+ nvt_cir_wake_reg_write(nvt, val | CIR_WAKE_FIFOCON_RXFIFOCLR,
+ CIR_WAKE_FIFOCON);
+}
+
+/* clear out the hardware's cir tx fifo */
+static void nvt_clear_tx_fifo(struct nvt_dev *nvt)
+{
+ u8 val;
+
+ val = nvt_cir_reg_read(nvt, CIR_FIFOCON);
+ nvt_cir_reg_write(nvt, val | CIR_FIFOCON_TXFIFOCLR, CIR_FIFOCON);
+}
+
+/* enable RX Trigger Level Reach and Packet End interrupts */
+static void nvt_set_cir_iren(struct nvt_dev *nvt)
+{
+ u8 iren;
+
+ iren = CIR_IREN_RTR | CIR_IREN_PE;
+ nvt_cir_reg_write(nvt, iren, CIR_IREN);
+}
+
+static void nvt_cir_regs_init(struct nvt_dev *nvt)
+{
+ /* set sample limit count (PE interrupt raised when reached) */
+ nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_SLCH);
+ nvt_cir_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_SLCL);
+
+ /* set fifo irq trigger levels */
+ nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV |
+ CIR_FIFOCON_RX_TRIGGER_LEV, CIR_FIFOCON);
+
+ /*
+ * Enable TX and RX, specify carrier on = low, off = high, and set
+ * sample period (currently 50us)
+ */
+ nvt_cir_reg_write(nvt,
+ CIR_IRCON_TXEN | CIR_IRCON_RXEN |
+ CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_IRCON);
+
+ /* clear hardware rx and tx fifos */
+ nvt_clear_cir_fifo(nvt);
+ nvt_clear_tx_fifo(nvt);
+
+ /* clear any and all stray interrupts */
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+ /* and finally, enable interrupts */
+ nvt_set_cir_iren(nvt);
+}
+
+static void nvt_cir_wake_regs_init(struct nvt_dev *nvt)
+{
+ /* set number of bytes needed for wake key comparison (default 67) */
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFO_LEN, CIR_WAKE_FIFO_CMP_DEEP);
+
+ /* set tolerance/variance allowed per byte during wake compare */
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_CMP_TOLERANCE,
+ CIR_WAKE_FIFO_CMP_TOL);
+
+ /* set sample limit count (PE interrupt raised when reached) */
+ nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT >> 8, CIR_WAKE_SLCH);
+ nvt_cir_wake_reg_write(nvt, CIR_RX_LIMIT_COUNT & 0xff, CIR_WAKE_SLCL);
+
+ /* set cir wake fifo rx trigger level (currently 67) */
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_FIFOCON_RX_TRIGGER_LEV,
+ CIR_WAKE_FIFOCON);
+
+ /*
+ * Enable TX and RX, specific carrier on = low, off = high, and set
+ * sample period (currently 50us)
+ */
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
+ CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
+ CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_WAKE_IRCON);
+
+ /* clear cir wake rx fifo */
+ nvt_clear_cir_wake_fifo(nvt);
+
+ /* clear any and all stray interrupts */
+ nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
+}
+
+static void nvt_enable_wake(struct nvt_dev *nvt)
+{
+ nvt_efm_enable(nvt);
+
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_ACPI);
+ nvt_set_reg_bit(nvt, CIR_WAKE_ENABLE_BIT, CR_ACPI_CIR_WAKE);
+ nvt_set_reg_bit(nvt, CIR_INTR_MOUSE_IRQ_BIT, CR_ACPI_IRQ_EVENTS);
+ nvt_set_reg_bit(nvt, PME_INTR_CIR_PASS_BIT, CR_ACPI_IRQ_EVENTS2);
+
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR_WAKE);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+
+ nvt_cir_wake_reg_write(nvt, CIR_WAKE_IRCON_MODE0 | CIR_WAKE_IRCON_RXEN |
+ CIR_WAKE_IRCON_R | CIR_WAKE_IRCON_RXINV |
+ CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_WAKE_IRCON);
+ nvt_cir_wake_reg_write(nvt, 0xff, CIR_WAKE_IRSTS);
+ nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
+}
+
+/* rx carrier detect only works in learning mode, must be called w/nvt_lock */
+static u32 nvt_rx_carrier_detect(struct nvt_dev *nvt)
+{
+ u32 count, carrier, duration = 0;
+ int i;
+
+ count = nvt_cir_reg_read(nvt, CIR_FCCL) |
+ nvt_cir_reg_read(nvt, CIR_FCCH) << 8;
+
+ for (i = 0; i < nvt->pkts; i++) {
+ if (nvt->buf[i] & BUF_PULSE_BIT)
+ duration += nvt->buf[i] & BUF_LEN_MASK;
+ }
+
+ duration *= SAMPLE_PERIOD;
+
+ if (!count || !duration) {
+ nvt_pr(KERN_NOTICE, "Unable to determine carrier! (c:%u, d:%u)",
+ count, duration);
+ return 0;
+ }
+
+ carrier = (count * 1000000) / duration;
+
+ if ((carrier > MAX_CARRIER) || (carrier < MIN_CARRIER))
+ nvt_dbg("WTF? Carrier frequency out of range!");
+
+ nvt_dbg("Carrier frequency: %u (count %u, duration %u)",
+ carrier, count, duration);
+
+ return carrier;
+}
+
+/*
+ * set carrier frequency
+ *
+ * set carrier on 2 registers: CP & CC
+ * always set CP as 0x81
+ * set CC by SPEC, CC = 3MHz/carrier - 1
+ */
+static int nvt_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+{
+ struct nvt_dev *nvt = dev->priv;
+ u16 val;
+
+ nvt_cir_reg_write(nvt, 1, CIR_CP);
+ val = 3000000 / (carrier) - 1;
+ nvt_cir_reg_write(nvt, val & 0xff, CIR_CC);
+
+ nvt_dbg("cp: 0x%x cc: 0x%x\n",
+ nvt_cir_reg_read(nvt, CIR_CP), nvt_cir_reg_read(nvt, CIR_CC));
+
+ return 0;
+}
+
+/*
+ * nvt_tx_ir
+ *
+ * 1) clean TX fifo first (handled by AP)
+ * 2) copy data from user space
+ * 3) disable RX interrupts, enable TX interrupts: TTR & TFU
+ * 4) send 9 packets to TX FIFO to open TTR
+ * in interrupt_handler:
+ * 5) send all data out
+ * go back to write():
+ * 6) disable TX interrupts, re-enable RX interupts
+ *
+ * The key problem of this function is user space data may larger than
+ * driver's data buf length. So nvt_tx_ir() will only copy TX_BUF_LEN data to
+ * buf, and keep current copied data buf num in cur_buf_num. But driver's buf
+ * number may larger than TXFCONT (0xff). So in interrupt_handler, it has to
+ * set TXFCONT as 0xff, until buf_count less than 0xff.
+ */
+static int nvt_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+{
+ struct nvt_dev *nvt = dev->priv;
+ unsigned long flags;
+ size_t cur_count;
+ unsigned int i;
+ u8 iren;
+ int ret;
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+
+ if (n >= TX_BUF_LEN) {
+ nvt->tx.buf_count = cur_count = TX_BUF_LEN;
+ ret = TX_BUF_LEN;
+ } else {
+ nvt->tx.buf_count = cur_count = n;
+ ret = n;
+ }
+
+ memcpy(nvt->tx.buf, txbuf, nvt->tx.buf_count);
+
+ nvt->tx.cur_buf_num = 0;
+
+ /* save currently enabled interrupts */
+ iren = nvt_cir_reg_read(nvt, CIR_IREN);
+
+ /* now disable all interrupts, save TFU & TTR */
+ nvt_cir_reg_write(nvt, CIR_IREN_TFU | CIR_IREN_TTR, CIR_IREN);
+
+ nvt->tx.tx_state = ST_TX_REPLY;
+
+ nvt_cir_reg_write(nvt, CIR_FIFOCON_TX_TRIGGER_LEV_8 |
+ CIR_FIFOCON_RXFIFOCLR, CIR_FIFOCON);
+
+ /* trigger TTR interrupt by writing out ones, (yes, it's ugly) */
+ for (i = 0; i < 9; i++)
+ nvt_cir_reg_write(nvt, 0x01, CIR_STXFIFO);
+
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ wait_event(nvt->tx.queue, nvt->tx.tx_state == ST_TX_REQUEST);
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+ nvt->tx.tx_state = ST_TX_NONE;
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ /* restore enabled interrupts to prior state */
+ nvt_cir_reg_write(nvt, iren, CIR_IREN);
+
+ return ret;
+}
+
+/* dump contents of the last rx buffer we got from the hw rx fifo */
+static void nvt_dump_rx_buf(struct nvt_dev *nvt)
+{
+ int i;
+
+ printk(KERN_DEBUG "%s (len %d): ", __func__, nvt->pkts);
+ for (i = 0; (i < nvt->pkts) && (i < RX_BUF_LEN); i++)
+ printk(KERN_CONT "0x%02x ", nvt->buf[i]);
+ printk(KERN_CONT "\n");
+}
+
+/*
+ * Process raw data in rx driver buffer, store it in raw IR event kfifo,
+ * trigger decode when appropriate.
+ *
+ * We get IR data samples one byte at a time. If the msb is set, its a pulse,
+ * otherwise its a space. The lower 7 bits are the count of SAMPLE_PERIOD
+ * (default 50us) intervals for that pulse/space. A discrete signal is
+ * followed by a series of 0x7f packets, then either 0x7<something> or 0x80
+ * to signal more IR coming (repeats) or end of IR, respectively. We store
+ * sample data in the raw event kfifo until we see 0x7<something> (except f)
+ * or 0x80, at which time, we trigger a decode operation.
+ */
+static void nvt_process_rx_ir_data(struct nvt_dev *nvt)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+ unsigned int count;
+ u32 carrier;
+ u8 sample;
+ int i;
+
+ nvt_dbg_verbose("%s firing", __func__);
+
+ if (debug)
+ nvt_dump_rx_buf(nvt);
+
+ if (nvt->carrier_detect_enabled)
+ carrier = nvt_rx_carrier_detect(nvt);
+
+ count = nvt->pkts;
+ nvt_dbg_verbose("Processing buffer of len %d", count);
+
+ init_ir_raw_event(&rawir);
+
+ for (i = 0; i < count; i++) {
+ nvt->pkts--;
+ sample = nvt->buf[i];
+
+ rawir.pulse = ((sample & BUF_PULSE_BIT) != 0);
+ rawir.duration = (sample & BUF_LEN_MASK)
+ * SAMPLE_PERIOD * 1000;
+
+ if ((sample & BUF_LEN_MASK) == BUF_LEN_MASK) {
+ if (nvt->rawir.pulse == rawir.pulse)
+ nvt->rawir.duration += rawir.duration;
+ else {
+ nvt->rawir.duration = rawir.duration;
+ nvt->rawir.pulse = rawir.pulse;
+ }
+ continue;
+ }
+
+ rawir.duration += nvt->rawir.duration;
+
+ init_ir_raw_event(&nvt->rawir);
+ nvt->rawir.duration = 0;
+ nvt->rawir.pulse = rawir.pulse;
+
+ if (sample == BUF_PULSE_BIT)
+ rawir.pulse = false;
+
+ if (rawir.duration) {
+ nvt_dbg("Storing %s with duration %d",
+ rawir.pulse ? "pulse" : "space",
+ rawir.duration);
+
+ ir_raw_event_store(nvt->rdev, &rawir);
+ }
+
+ /*
+ * BUF_PULSE_BIT indicates end of IR data, BUF_REPEAT_BYTE
+ * indicates end of IR signal, but new data incoming. In both
+ * cases, it means we're ready to call ir_raw_event_handle
+ */
+ if ((sample == BUF_PULSE_BIT) && nvt->pkts) {
+ nvt_dbg("Calling ir_raw_event_handle (signal end)\n");
+ ir_raw_event_handle(nvt->rdev);
+ }
+ }
+
+ nvt_dbg("Calling ir_raw_event_handle (buffer empty)\n");
+ ir_raw_event_handle(nvt->rdev);
+
+ if (nvt->pkts) {
+ nvt_dbg("Odd, pkts should be 0 now... (its %u)", nvt->pkts);
+ nvt->pkts = 0;
+ }
+
+ nvt_dbg_verbose("%s done", __func__);
+}
+
+static void nvt_handle_rx_fifo_overrun(struct nvt_dev *nvt)
+{
+ nvt_pr(KERN_WARNING, "RX FIFO overrun detected, flushing data!");
+
+ nvt->pkts = 0;
+ nvt_clear_cir_fifo(nvt);
+ ir_raw_event_reset(nvt->rdev);
+}
+
+/* copy data from hardware rx fifo into driver buffer */
+static void nvt_get_rx_ir_data(struct nvt_dev *nvt)
+{
+ unsigned long flags;
+ u8 fifocount, val;
+ unsigned int b_idx;
+ bool overrun = false;
+ int i;
+
+ /* Get count of how many bytes to read from RX FIFO */
+ fifocount = nvt_cir_reg_read(nvt, CIR_RXFCONT);
+ /* if we get 0xff, probably means the logical dev is disabled */
+ if (fifocount == 0xff)
+ return;
+ /* watch out for a fifo overrun condition */
+ else if (fifocount > RX_BUF_LEN) {
+ overrun = true;
+ fifocount = RX_BUF_LEN;
+ }
+
+ nvt_dbg("attempting to fetch %u bytes from hw rx fifo", fifocount);
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+ b_idx = nvt->pkts;
+
+ /* This should never happen, but lets check anyway... */
+ if (b_idx + fifocount > RX_BUF_LEN) {
+ nvt_process_rx_ir_data(nvt);
+ b_idx = 0;
+ }
+
+ /* Read fifocount bytes from CIR Sample RX FIFO register */
+ for (i = 0; i < fifocount; i++) {
+ val = nvt_cir_reg_read(nvt, CIR_SRXFIFO);
+ nvt->buf[b_idx + i] = val;
+ }
+
+ nvt->pkts += fifocount;
+ nvt_dbg("%s: pkts now %d", __func__, nvt->pkts);
+
+ nvt_process_rx_ir_data(nvt);
+
+ if (overrun)
+ nvt_handle_rx_fifo_overrun(nvt);
+
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+}
+
+static void nvt_cir_log_irqs(u8 status, u8 iren)
+{
+ nvt_pr(KERN_INFO, "IRQ 0x%02x (IREN 0x%02x) :%s%s%s%s%s%s%s%s%s",
+ status, iren,
+ status & CIR_IRSTS_RDR ? " RDR" : "",
+ status & CIR_IRSTS_RTR ? " RTR" : "",
+ status & CIR_IRSTS_PE ? " PE" : "",
+ status & CIR_IRSTS_RFO ? " RFO" : "",
+ status & CIR_IRSTS_TE ? " TE" : "",
+ status & CIR_IRSTS_TTR ? " TTR" : "",
+ status & CIR_IRSTS_TFU ? " TFU" : "",
+ status & CIR_IRSTS_GH ? " GH" : "",
+ status & ~(CIR_IRSTS_RDR | CIR_IRSTS_RTR | CIR_IRSTS_PE |
+ CIR_IRSTS_RFO | CIR_IRSTS_TE | CIR_IRSTS_TTR |
+ CIR_IRSTS_TFU | CIR_IRSTS_GH) ? " ?" : "");
+}
+
+static bool nvt_cir_tx_inactive(struct nvt_dev *nvt)
+{
+ unsigned long flags;
+ bool tx_inactive;
+ u8 tx_state;
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+ tx_state = nvt->tx.tx_state;
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ tx_inactive = (tx_state == ST_TX_NONE);
+
+ return tx_inactive;
+}
+
+/* interrupt service routine for incoming and outgoing CIR data */
+static irqreturn_t nvt_cir_isr(int irq, void *data)
+{
+ struct nvt_dev *nvt = data;
+ u8 status, iren, cur_state;
+ unsigned long flags;
+
+ nvt_dbg_verbose("%s firing", __func__);
+
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_efm_disable(nvt);
+
+ /*
+ * Get IR Status register contents. Write 1 to ack/clear
+ *
+ * bit: reg name - description
+ * 7: CIR_IRSTS_RDR - RX Data Ready
+ * 6: CIR_IRSTS_RTR - RX FIFO Trigger Level Reach
+ * 5: CIR_IRSTS_PE - Packet End
+ * 4: CIR_IRSTS_RFO - RX FIFO Overrun (RDR will also be set)
+ * 3: CIR_IRSTS_TE - TX FIFO Empty
+ * 2: CIR_IRSTS_TTR - TX FIFO Trigger Level Reach
+ * 1: CIR_IRSTS_TFU - TX FIFO Underrun
+ * 0: CIR_IRSTS_GH - Min Length Detected
+ */
+ status = nvt_cir_reg_read(nvt, CIR_IRSTS);
+ if (!status) {
+ nvt_dbg_verbose("%s exiting, IRSTS 0x0", __func__);
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+ return IRQ_RETVAL(IRQ_NONE);
+ }
+
+ /* ack/clear all irq flags we've got */
+ nvt_cir_reg_write(nvt, status, CIR_IRSTS);
+ nvt_cir_reg_write(nvt, 0, CIR_IRSTS);
+
+ /* Interrupt may be shared with CIR Wake, bail if CIR not enabled */
+ iren = nvt_cir_reg_read(nvt, CIR_IREN);
+ if (!iren) {
+ nvt_dbg_verbose("%s exiting, CIR not enabled", __func__);
+ return IRQ_RETVAL(IRQ_NONE);
+ }
+
+ if (debug)
+ nvt_cir_log_irqs(status, iren);
+
+ if (status & CIR_IRSTS_RTR) {
+ /* FIXME: add code for study/learn mode */
+ /* We only do rx if not tx'ing */
+ if (nvt_cir_tx_inactive(nvt))
+ nvt_get_rx_ir_data(nvt);
+ }
+
+ if (status & CIR_IRSTS_PE) {
+ if (nvt_cir_tx_inactive(nvt))
+ nvt_get_rx_ir_data(nvt);
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+
+ cur_state = nvt->study_state;
+
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ if (cur_state == ST_STUDY_NONE)
+ nvt_clear_cir_fifo(nvt);
+ }
+
+ if (status & CIR_IRSTS_TE)
+ nvt_clear_tx_fifo(nvt);
+
+ if (status & CIR_IRSTS_TTR) {
+ unsigned int pos, count;
+ u8 tmp;
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+
+ pos = nvt->tx.cur_buf_num;
+ count = nvt->tx.buf_count;
+
+ /* Write data into the hardware tx fifo while pos < count */
+ if (pos < count) {
+ nvt_cir_reg_write(nvt, nvt->tx.buf[pos], CIR_STXFIFO);
+ nvt->tx.cur_buf_num++;
+ /* Disable TX FIFO Trigger Level Reach (TTR) interrupt */
+ } else {
+ tmp = nvt_cir_reg_read(nvt, CIR_IREN);
+ nvt_cir_reg_write(nvt, tmp & ~CIR_IREN_TTR, CIR_IREN);
+ }
+
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ }
+
+ if (status & CIR_IRSTS_TFU) {
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+ if (nvt->tx.tx_state == ST_TX_REPLY) {
+ nvt->tx.tx_state = ST_TX_REQUEST;
+ wake_up(&nvt->tx.queue);
+ }
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+ }
+
+ nvt_dbg_verbose("%s done", __func__);
+ return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+/* Interrupt service routine for CIR Wake */
+static irqreturn_t nvt_cir_wake_isr(int irq, void *data)
+{
+ u8 status, iren, val;
+ struct nvt_dev *nvt = data;
+ unsigned long flags;
+
+ nvt_dbg_wake("%s firing", __func__);
+
+ status = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IRSTS);
+ if (!status)
+ return IRQ_RETVAL(IRQ_NONE);
+
+ if (status & CIR_WAKE_IRSTS_IR_PENDING)
+ nvt_clear_cir_wake_fifo(nvt);
+
+ nvt_cir_wake_reg_write(nvt, status, CIR_WAKE_IRSTS);
+ nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IRSTS);
+
+ /* Interrupt may be shared with CIR, bail if Wake not enabled */
+ iren = nvt_cir_wake_reg_read(nvt, CIR_WAKE_IREN);
+ if (!iren) {
+ nvt_dbg_wake("%s exiting, wake not enabled", __func__);
+ return IRQ_RETVAL(IRQ_HANDLED);
+ }
+
+ if ((status & CIR_WAKE_IRSTS_PE) &&
+ (nvt->wake_state == ST_WAKE_START)) {
+ while (nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY_IDX)) {
+ val = nvt_cir_wake_reg_read(nvt, CIR_WAKE_RD_FIFO_ONLY);
+ nvt_dbg("setting wake up key: 0x%x", val);
+ }
+
+ nvt_cir_wake_reg_write(nvt, 0, CIR_WAKE_IREN);
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->wake_state = ST_WAKE_FINISH;
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+ }
+
+ nvt_dbg_wake("%s done", __func__);
+ return IRQ_RETVAL(IRQ_HANDLED);
+}
+
+static void nvt_enable_cir(struct nvt_dev *nvt)
+{
+ /* set function enable flags */
+ nvt_cir_reg_write(nvt, CIR_IRCON_TXEN | CIR_IRCON_RXEN |
+ CIR_IRCON_RXINV | CIR_IRCON_SAMPLE_PERIOD_SEL,
+ CIR_IRCON);
+
+ nvt_efm_enable(nvt);
+
+ /* enable the CIR logical device */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+
+ /* clear all pending interrupts */
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+ /* enable interrupts */
+ nvt_set_cir_iren(nvt);
+}
+
+static void nvt_disable_cir(struct nvt_dev *nvt)
+{
+ /* disable CIR interrupts */
+ nvt_cir_reg_write(nvt, 0, CIR_IREN);
+
+ /* clear any and all pending interrupts */
+ nvt_cir_reg_write(nvt, 0xff, CIR_IRSTS);
+
+ /* clear all function enable flags */
+ nvt_cir_reg_write(nvt, 0, CIR_IRCON);
+
+ /* clear hardware rx and tx fifos */
+ nvt_clear_cir_fifo(nvt);
+ nvt_clear_tx_fifo(nvt);
+
+ nvt_efm_enable(nvt);
+
+ /* disable the CIR logical device */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+}
+
+static int nvt_open(struct rc_dev *dev)
+{
+ struct nvt_dev *nvt = dev->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->in_use = true;
+ nvt_enable_cir(nvt);
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ return 0;
+}
+
+static void nvt_close(struct rc_dev *dev)
+{
+ struct nvt_dev *nvt = dev->priv;
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->in_use = false;
+ nvt_disable_cir(nvt);
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+}
+
+/* Allocate memory, probe hardware, and initialize everything */
+static int nvt_probe(struct pnp_dev *pdev, const struct pnp_device_id *dev_id)
+{
+ struct nvt_dev *nvt;
+ struct rc_dev *rdev;
+ int ret = -ENOMEM;
+
+ nvt = kzalloc(sizeof(struct nvt_dev), GFP_KERNEL);
+ if (!nvt)
+ return ret;
+
+ /* input device for IR remote (and tx) */
+ rdev = rc_allocate_device();
+ if (!rdev)
+ goto failure;
+
+ ret = -ENODEV;
+ /* validate pnp resources */
+ if (!pnp_port_valid(pdev, 0) ||
+ pnp_port_len(pdev, 0) < CIR_IOREG_LENGTH) {
+ dev_err(&pdev->dev, "IR PNP Port not valid!\n");
+ goto failure;
+ }
+
+ if (!pnp_irq_valid(pdev, 0)) {
+ dev_err(&pdev->dev, "PNP IRQ not valid!\n");
+ goto failure;
+ }
+
+ if (!pnp_port_valid(pdev, 1) ||
+ pnp_port_len(pdev, 1) < CIR_IOREG_LENGTH) {
+ dev_err(&pdev->dev, "Wake PNP Port not valid!\n");
+ goto failure;
+ }
+
+ nvt->cir_addr = pnp_port_start(pdev, 0);
+ nvt->cir_irq = pnp_irq(pdev, 0);
+
+ nvt->cir_wake_addr = pnp_port_start(pdev, 1);
+ /* irq is always shared between cir and cir wake */
+ nvt->cir_wake_irq = nvt->cir_irq;
+
+ nvt->cr_efir = CR_EFIR;
+ nvt->cr_efdr = CR_EFDR;
+
+ spin_lock_init(&nvt->nvt_lock);
+ spin_lock_init(&nvt->tx.lock);
+ init_ir_raw_event(&nvt->rawir);
+
+ ret = -EBUSY;
+ /* now claim resources */
+ if (!request_region(nvt->cir_addr,
+ CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
+ goto failure;
+
+ if (request_irq(nvt->cir_irq, nvt_cir_isr, IRQF_SHARED,
+ NVT_DRIVER_NAME, (void *)nvt))
+ goto failure;
+
+ if (!request_region(nvt->cir_wake_addr,
+ CIR_IOREG_LENGTH, NVT_DRIVER_NAME))
+ goto failure;
+
+ if (request_irq(nvt->cir_wake_irq, nvt_cir_wake_isr, IRQF_SHARED,
+ NVT_DRIVER_NAME, (void *)nvt))
+ goto failure;
+
+ pnp_set_drvdata(pdev, nvt);
+ nvt->pdev = pdev;
+
+ init_waitqueue_head(&nvt->tx.queue);
+
+ ret = nvt_hw_detect(nvt);
+ if (ret)
+ goto failure;
+
+ /* Initialize CIR & CIR Wake Logical Devices */
+ nvt_efm_enable(nvt);
+ nvt_cir_ldev_init(nvt);
+ nvt_cir_wake_ldev_init(nvt);
+ nvt_efm_disable(nvt);
+
+ /* Initialize CIR & CIR Wake Config Registers */
+ nvt_cir_regs_init(nvt);
+ nvt_cir_wake_regs_init(nvt);
+
+ /* Set up the rc device */
+ rdev->priv = nvt;
+ rdev->driver_type = RC_DRIVER_IR_RAW;
+ rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->open = nvt_open;
+ rdev->close = nvt_close;
+ rdev->tx_ir = nvt_tx_ir;
+ rdev->s_tx_carrier = nvt_set_tx_carrier;
+ rdev->input_name = "Nuvoton w836x7hg Infrared Remote Transceiver";
+ rdev->input_id.bustype = BUS_HOST;
+ rdev->input_id.vendor = PCI_VENDOR_ID_WINBOND2;
+ rdev->input_id.product = nvt->chip_major;
+ rdev->input_id.version = nvt->chip_minor;
+ rdev->driver_name = NVT_DRIVER_NAME;
+ rdev->map_name = RC_MAP_RC6_MCE;
+#if 0
+ rdev->min_timeout = XYZ;
+ rdev->max_timeout = XYZ;
+ rdev->timeout = XYZ;
+ /* rx resolution is hardwired to 50us atm, 1, 25, 100 also possible */
+ rdev->rx_resolution = XYZ;
+ /* tx bits */
+ rdev->tx_resolution = XYZ;
+#endif
+
+ ret = rc_register_device(rdev);
+ if (ret)
+ goto failure;
+
+ device_set_wakeup_capable(&pdev->dev, 1);
+ device_set_wakeup_enable(&pdev->dev, 1);
+ nvt->rdev = rdev;
+ nvt_pr(KERN_NOTICE, "driver has been successfully loaded\n");
+ if (debug) {
+ cir_dump_regs(nvt);
+ cir_wake_dump_regs(nvt);
+ }
+
+ return 0;
+
+failure:
+ if (nvt->cir_irq)
+ free_irq(nvt->cir_irq, nvt);
+ if (nvt->cir_addr)
+ release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
+
+ if (nvt->cir_wake_irq)
+ free_irq(nvt->cir_wake_irq, nvt);
+ if (nvt->cir_wake_addr)
+ release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
+
+ rc_free_device(rdev);
+ kfree(nvt);
+
+ return ret;
+}
+
+static void __devexit nvt_remove(struct pnp_dev *pdev)
+{
+ struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+ unsigned long flags;
+
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ /* disable CIR */
+ nvt_cir_reg_write(nvt, 0, CIR_IREN);
+ nvt_disable_cir(nvt);
+ /* enable CIR Wake (for IR power-on) */
+ nvt_enable_wake(nvt);
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ /* free resources */
+ free_irq(nvt->cir_irq, nvt);
+ free_irq(nvt->cir_wake_irq, nvt);
+ release_region(nvt->cir_addr, CIR_IOREG_LENGTH);
+ release_region(nvt->cir_wake_addr, CIR_IOREG_LENGTH);
+
+ rc_unregister_device(nvt->rdev);
+
+ kfree(nvt);
+}
+
+static int nvt_suspend(struct pnp_dev *pdev, pm_message_t state)
+{
+ struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+ unsigned long flags;
+
+ nvt_dbg("%s called", __func__);
+
+ /* zero out misc state tracking */
+ spin_lock_irqsave(&nvt->nvt_lock, flags);
+ nvt->study_state = ST_STUDY_NONE;
+ nvt->wake_state = ST_WAKE_NONE;
+ spin_unlock_irqrestore(&nvt->nvt_lock, flags);
+
+ spin_lock_irqsave(&nvt->tx.lock, flags);
+ nvt->tx.tx_state = ST_TX_NONE;
+ spin_unlock_irqrestore(&nvt->tx.lock, flags);
+
+ /* disable all CIR interrupts */
+ nvt_cir_reg_write(nvt, 0, CIR_IREN);
+
+ nvt_efm_enable(nvt);
+
+ /* disable cir logical dev */
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_DISABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+
+ /* make sure wake is enabled */
+ nvt_enable_wake(nvt);
+
+ return 0;
+}
+
+static int nvt_resume(struct pnp_dev *pdev)
+{
+ int ret = 0;
+ struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+
+ nvt_dbg("%s called", __func__);
+
+ /* open interrupt */
+ nvt_set_cir_iren(nvt);
+
+ /* Enable CIR logical device */
+ nvt_efm_enable(nvt);
+ nvt_select_logical_dev(nvt, LOGICAL_DEV_CIR);
+ nvt_cr_write(nvt, LOGICAL_DEV_ENABLE, CR_LOGICAL_DEV_EN);
+
+ nvt_efm_disable(nvt);
+
+ nvt_cir_regs_init(nvt);
+ nvt_cir_wake_regs_init(nvt);
+
+ return ret;
+}
+
+static void nvt_shutdown(struct pnp_dev *pdev)
+{
+ struct nvt_dev *nvt = pnp_get_drvdata(pdev);
+ nvt_enable_wake(nvt);
+}
+
+static const struct pnp_device_id nvt_ids[] = {
+ { "WEC0530", 0 }, /* CIR */
+ { "NTN0530", 0 }, /* CIR for new chip's pnp id*/
+ { "", 0 },
+};
+
+static struct pnp_driver nvt_driver = {
+ .name = NVT_DRIVER_NAME,
+ .id_table = nvt_ids,
+ .flags = PNP_DRIVER_RES_DO_NOT_CHANGE,
+ .probe = nvt_probe,
+ .remove = __devexit_p(nvt_remove),
+ .suspend = nvt_suspend,
+ .resume = nvt_resume,
+ .shutdown = nvt_shutdown,
+};
+
+int nvt_init(void)
+{
+ return pnp_register_driver(&nvt_driver);
+}
+
+void nvt_exit(void)
+{
+ pnp_unregister_driver(&nvt_driver);
+}
+
+module_param(debug, int, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging output");
+
+MODULE_DEVICE_TABLE(pnp, nvt_ids);
+MODULE_DESCRIPTION("Nuvoton W83667HG-A & W83677HG-I CIR driver");
+
+MODULE_AUTHOR("Jarod Wilson <jarod@redhat.com>");
+MODULE_LICENSE("GPL");
+
+module_init(nvt_init);
+module_exit(nvt_exit);
diff --git a/drivers/media/rc/nuvoton-cir.h b/drivers/media/rc/nuvoton-cir.h
new file mode 100644
index 000000000000..1df82351cb03
--- /dev/null
+++ b/drivers/media/rc/nuvoton-cir.h
@@ -0,0 +1,407 @@
+/*
+ * Driver for Nuvoton Technology Corporation w83667hg/w83677hg-i CIR
+ *
+ * Copyright (C) 2010 Jarod Wilson <jarod@redhat.com>
+ * Copyright (C) 2009 Nuvoton PS Team
+ *
+ * Special thanks to Nuvoton for providing hardware, spec sheets and
+ * sample code upon which portions of this driver are based. Indirect
+ * thanks also to Maxim Levitsky, whose ene_ir driver this driver is
+ * modeled after.
+ *
+ * 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/spinlock.h>
+#include <linux/ioctl.h>
+
+/* platform driver name to register */
+#define NVT_DRIVER_NAME "nuvoton-cir"
+
+/* debugging module parameter */
+static int debug;
+
+
+#define nvt_pr(level, text, ...) \
+ printk(level KBUILD_MODNAME ": " text, ## __VA_ARGS__)
+
+#define nvt_dbg(text, ...) \
+ if (debug) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define nvt_dbg_verbose(text, ...) \
+ if (debug > 1) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+#define nvt_dbg_wake(text, ...) \
+ if (debug > 2) \
+ printk(KERN_DEBUG \
+ KBUILD_MODNAME ": " text "\n" , ## __VA_ARGS__)
+
+
+/*
+ * Original lirc driver said min value of 76, and recommended value of 256
+ * for the buffer length, but then used 2048. Never mind that the size of the
+ * RX FIFO is 32 bytes... So I'm using 32 for RX and 256 for TX atm, but I'm
+ * not sure if maybe that TX value is off by a factor of 8 (bits vs. bytes),
+ * and I don't have TX-capable hardware to test/debug on...
+ */
+#define TX_BUF_LEN 256
+#define RX_BUF_LEN 32
+
+struct nvt_dev {
+ struct pnp_dev *pdev;
+ struct rc_dev *rdev;
+ struct ir_raw_event rawir;
+
+ spinlock_t nvt_lock;
+ bool in_use;
+
+ /* for rx */
+ u8 buf[RX_BUF_LEN];
+ unsigned int pkts;
+
+ struct {
+ spinlock_t lock;
+ u8 buf[TX_BUF_LEN];
+ unsigned int buf_count;
+ unsigned int cur_buf_num;
+ wait_queue_head_t queue;
+ u8 tx_state;
+ } tx;
+
+ /* EFER Config register index/data pair */
+ u8 cr_efir;
+ u8 cr_efdr;
+
+ /* hardware I/O settings */
+ unsigned long cir_addr;
+ unsigned long cir_wake_addr;
+ int cir_irq;
+ int cir_wake_irq;
+
+ /* hardware id */
+ u8 chip_major;
+ u8 chip_minor;
+
+ /* hardware features */
+ bool hw_learning_capable;
+ bool hw_tx_capable;
+
+ /* rx settings */
+ bool learning_enabled;
+ bool carrier_detect_enabled;
+
+ /* track cir wake state */
+ u8 wake_state;
+ /* for study */
+ u8 study_state;
+ /* carrier period = 1 / frequency */
+ u32 carrier;
+};
+
+/* study states */
+#define ST_STUDY_NONE 0x0
+#define ST_STUDY_START 0x1
+#define ST_STUDY_CARRIER 0x2
+#define ST_STUDY_ALL_RECV 0x4
+
+/* wake states */
+#define ST_WAKE_NONE 0x0
+#define ST_WAKE_START 0x1
+#define ST_WAKE_FINISH 0x2
+
+/* receive states */
+#define ST_RX_WAIT_7F 0x1
+#define ST_RX_WAIT_HEAD 0x2
+#define ST_RX_WAIT_SILENT_END 0x4
+
+/* send states */
+#define ST_TX_NONE 0x0
+#define ST_TX_REQUEST 0x2
+#define ST_TX_REPLY 0x4
+
+/* buffer packet constants */
+#define BUF_PULSE_BIT 0x80
+#define BUF_LEN_MASK 0x7f
+#define BUF_REPEAT_BYTE 0x70
+#define BUF_REPEAT_MASK 0xf0
+
+/* CIR settings */
+
+/* total length of CIR and CIR WAKE */
+#define CIR_IOREG_LENGTH 0x0f
+
+/* RX limit length, 8 high bits for SLCH, 8 low bits for SLCL (0x7d0 = 2000) */
+#define CIR_RX_LIMIT_COUNT 0x7d0
+
+/* CIR Regs */
+#define CIR_IRCON 0x00
+#define CIR_IRSTS 0x01
+#define CIR_IREN 0x02
+#define CIR_RXFCONT 0x03
+#define CIR_CP 0x04
+#define CIR_CC 0x05
+#define CIR_SLCH 0x06
+#define CIR_SLCL 0x07
+#define CIR_FIFOCON 0x08
+#define CIR_IRFIFOSTS 0x09
+#define CIR_SRXFIFO 0x0a
+#define CIR_TXFCONT 0x0b
+#define CIR_STXFIFO 0x0c
+#define CIR_FCCH 0x0d
+#define CIR_FCCL 0x0e
+#define CIR_IRFSM 0x0f
+
+/* CIR IRCON settings */
+#define CIR_IRCON_RECV 0x80
+#define CIR_IRCON_WIREN 0x40
+#define CIR_IRCON_TXEN 0x20
+#define CIR_IRCON_RXEN 0x10
+#define CIR_IRCON_WRXINV 0x08
+#define CIR_IRCON_RXINV 0x04
+
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_1 0x00
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_25 0x01
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_50 0x02
+#define CIR_IRCON_SAMPLE_PERIOD_SEL_100 0x03
+
+/* FIXME: make this a runtime option */
+/* select sample period as 50us */
+#define CIR_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50
+
+/* CIR IRSTS settings */
+#define CIR_IRSTS_RDR 0x80
+#define CIR_IRSTS_RTR 0x40
+#define CIR_IRSTS_PE 0x20
+#define CIR_IRSTS_RFO 0x10
+#define CIR_IRSTS_TE 0x08
+#define CIR_IRSTS_TTR 0x04
+#define CIR_IRSTS_TFU 0x02
+#define CIR_IRSTS_GH 0x01
+
+/* CIR IREN settings */
+#define CIR_IREN_RDR 0x80
+#define CIR_IREN_RTR 0x40
+#define CIR_IREN_PE 0x20
+#define CIR_IREN_RFO 0x10
+#define CIR_IREN_TE 0x08
+#define CIR_IREN_TTR 0x04
+#define CIR_IREN_TFU 0x02
+#define CIR_IREN_GH 0x01
+
+/* CIR FIFOCON settings */
+#define CIR_FIFOCON_TXFIFOCLR 0x80
+
+#define CIR_FIFOCON_TX_TRIGGER_LEV_31 0x00
+#define CIR_FIFOCON_TX_TRIGGER_LEV_24 0x10
+#define CIR_FIFOCON_TX_TRIGGER_LEV_16 0x20
+#define CIR_FIFOCON_TX_TRIGGER_LEV_8 0x30
+
+/* FIXME: make this a runtime option */
+/* select TX trigger level as 16 */
+#define CIR_FIFOCON_TX_TRIGGER_LEV CIR_FIFOCON_TX_TRIGGER_LEV_16
+
+#define CIR_FIFOCON_RXFIFOCLR 0x08
+
+#define CIR_FIFOCON_RX_TRIGGER_LEV_1 0x00
+#define CIR_FIFOCON_RX_TRIGGER_LEV_8 0x01
+#define CIR_FIFOCON_RX_TRIGGER_LEV_16 0x02
+#define CIR_FIFOCON_RX_TRIGGER_LEV_24 0x03
+
+/* FIXME: make this a runtime option */
+/* select RX trigger level as 24 */
+#define CIR_FIFOCON_RX_TRIGGER_LEV CIR_FIFOCON_RX_TRIGGER_LEV_24
+
+/* CIR IRFIFOSTS settings */
+#define CIR_IRFIFOSTS_IR_PENDING 0x80
+#define CIR_IRFIFOSTS_RX_GS 0x40
+#define CIR_IRFIFOSTS_RX_FTA 0x20
+#define CIR_IRFIFOSTS_RX_EMPTY 0x10
+#define CIR_IRFIFOSTS_RX_FULL 0x08
+#define CIR_IRFIFOSTS_TX_FTA 0x04
+#define CIR_IRFIFOSTS_TX_EMPTY 0x02
+#define CIR_IRFIFOSTS_TX_FULL 0x01
+
+
+/* CIR WAKE UP Regs */
+#define CIR_WAKE_IRCON 0x00
+#define CIR_WAKE_IRSTS 0x01
+#define CIR_WAKE_IREN 0x02
+#define CIR_WAKE_FIFO_CMP_DEEP 0x03
+#define CIR_WAKE_FIFO_CMP_TOL 0x04
+#define CIR_WAKE_FIFO_COUNT 0x05
+#define CIR_WAKE_SLCH 0x06
+#define CIR_WAKE_SLCL 0x07
+#define CIR_WAKE_FIFOCON 0x08
+#define CIR_WAKE_SRXFSTS 0x09
+#define CIR_WAKE_SAMPLE_RX_FIFO 0x0a
+#define CIR_WAKE_WR_FIFO_DATA 0x0b
+#define CIR_WAKE_RD_FIFO_ONLY 0x0c
+#define CIR_WAKE_RD_FIFO_ONLY_IDX 0x0d
+#define CIR_WAKE_FIFO_IGNORE 0x0e
+#define CIR_WAKE_IRFSM 0x0f
+
+/* CIR WAKE UP IRCON settings */
+#define CIR_WAKE_IRCON_DEC_RST 0x80
+#define CIR_WAKE_IRCON_MODE1 0x40
+#define CIR_WAKE_IRCON_MODE0 0x20
+#define CIR_WAKE_IRCON_RXEN 0x10
+#define CIR_WAKE_IRCON_R 0x08
+#define CIR_WAKE_IRCON_RXINV 0x04
+
+/* FIXME/jarod: make this a runtime option */
+/* select a same sample period like cir register */
+#define CIR_WAKE_IRCON_SAMPLE_PERIOD_SEL CIR_IRCON_SAMPLE_PERIOD_SEL_50
+
+/* CIR WAKE IRSTS Bits */
+#define CIR_WAKE_IRSTS_RDR 0x80
+#define CIR_WAKE_IRSTS_RTR 0x40
+#define CIR_WAKE_IRSTS_PE 0x20
+#define CIR_WAKE_IRSTS_RFO 0x10
+#define CIR_WAKE_IRSTS_GH 0x08
+#define CIR_WAKE_IRSTS_IR_PENDING 0x01
+
+/* CIR WAKE UP IREN Bits */
+#define CIR_WAKE_IREN_RDR 0x80
+#define CIR_WAKE_IREN_RTR 0x40
+#define CIR_WAKE_IREN_PE 0x20
+#define CIR_WAKE_IREN_RFO 0x10
+#define CIR_WAKE_IREN_TE 0x08
+#define CIR_WAKE_IREN_TTR 0x04
+#define CIR_WAKE_IREN_TFU 0x02
+#define CIR_WAKE_IREN_GH 0x01
+
+/* CIR WAKE FIFOCON settings */
+#define CIR_WAKE_FIFOCON_RXFIFOCLR 0x08
+
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67 0x00
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_66 0x01
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_65 0x02
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_64 0x03
+
+/* FIXME: make this a runtime option */
+/* select WAKE UP RX trigger level as 67 */
+#define CIR_WAKE_FIFOCON_RX_TRIGGER_LEV CIR_WAKE_FIFOCON_RX_TRIGGER_LEV_67
+
+/* CIR WAKE SRXFSTS settings */
+#define CIR_WAKE_IRFIFOSTS_RX_GS 0x80
+#define CIR_WAKE_IRFIFOSTS_RX_FTA 0x40
+#define CIR_WAKE_IRFIFOSTS_RX_EMPTY 0x20
+#define CIR_WAKE_IRFIFOSTS_RX_FULL 0x10
+
+/* CIR Wake FIFO buffer is 67 bytes long */
+#define CIR_WAKE_FIFO_LEN 67
+/* CIR Wake byte comparison tolerance */
+#define CIR_WAKE_CMP_TOLERANCE 5
+
+/*
+ * Extended Function Enable Registers:
+ * Extended Function Index Register
+ * Extended Function Data Register
+ */
+#define CR_EFIR 0x2e
+#define CR_EFDR 0x2f
+
+/* Possible alternate EFER values, depends on how the chip is wired */
+#define CR_EFIR2 0x4e
+#define CR_EFDR2 0x4f
+
+/* Extended Function Mode enable/disable magic values */
+#define EFER_EFM_ENABLE 0x87
+#define EFER_EFM_DISABLE 0xaa
+
+/* Chip IDs found in CR_CHIP_ID_{HI,LO} */
+#define CHIP_ID_HIGH 0xb4
+#define CHIP_ID_LOW 0x72
+#define CHIP_ID_LOW2 0x73
+
+/* Config regs we need to care about */
+#define CR_SOFTWARE_RESET 0x02
+#define CR_LOGICAL_DEV_SEL 0x07
+#define CR_CHIP_ID_HI 0x20
+#define CR_CHIP_ID_LO 0x21
+#define CR_DEV_POWER_DOWN 0x22 /* bit 2 is CIR power, default power on */
+#define CR_OUTPUT_PIN_SEL 0x27
+#define CR_LOGICAL_DEV_EN 0x30 /* valid for all logical devices */
+/* next three regs valid for both the CIR and CIR_WAKE logical devices */
+#define CR_CIR_BASE_ADDR_HI 0x60
+#define CR_CIR_BASE_ADDR_LO 0x61
+#define CR_CIR_IRQ_RSRC 0x70
+/* next three regs valid only for ACPI logical dev */
+#define CR_ACPI_CIR_WAKE 0xe0
+#define CR_ACPI_IRQ_EVENTS 0xf6
+#define CR_ACPI_IRQ_EVENTS2 0xf7
+
+/* Logical devices that we need to care about */
+#define LOGICAL_DEV_LPT 0x01
+#define LOGICAL_DEV_CIR 0x06
+#define LOGICAL_DEV_ACPI 0x0a
+#define LOGICAL_DEV_CIR_WAKE 0x0e
+
+#define LOGICAL_DEV_DISABLE 0x00
+#define LOGICAL_DEV_ENABLE 0x01
+
+#define CIR_WAKE_ENABLE_BIT 0x08
+#define CIR_INTR_MOUSE_IRQ_BIT 0x80
+#define PME_INTR_CIR_PASS_BIT 0x08
+
+#define OUTPUT_PIN_SEL_MASK 0xbc
+#define OUTPUT_ENABLE_CIR 0x01 /* Pin95=CIRRX, Pin96=CIRTX1 */
+#define OUTPUT_ENABLE_CIRWB 0x40 /* enable wide-band sensor */
+
+/* MCE CIR signal length, related on sample period */
+
+/* MCE CIR controller signal length: about 43ms
+ * 43ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define CONTROLLER_BUF_LEN_MIN 830
+
+/* MCE CIR keyboard signal length: about 26ms
+ * 26ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define KEYBOARD_BUF_LEN_MAX 650
+#define KEYBOARD_BUF_LEN_MIN 610
+
+/* MCE CIR mouse signal length: about 24ms
+ * 24ms / 50us (sample period) * 0.85 (inaccuracy)
+ */
+#define MOUSE_BUF_LEN_MIN 565
+
+#define CIR_SAMPLE_PERIOD 50
+#define CIR_SAMPLE_LOW_INACCURACY 0.85
+
+/* MAX silence time that driver will sent to lirc */
+#define MAX_SILENCE_TIME 60000
+
+#if CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_100
+#define SAMPLE_PERIOD 100
+
+#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_50
+#define SAMPLE_PERIOD 50
+
+#elif CIR_IRCON_SAMPLE_PERIOD_SEL == CIR_IRCON_SAMPLE_PERIOD_SEL_25
+#define SAMPLE_PERIOD 25
+
+#else
+#define SAMPLE_PERIOD 1
+#endif
+
+/* as VISTA MCE definition, valid carrier value */
+#define MAX_CARRIER 60000
+#define MIN_CARRIER 30000
diff --git a/drivers/media/IR/ir-core-priv.h b/drivers/media/rc/rc-core-priv.h
index 9a5e65a471a5..873b38789751 100644
--- a/drivers/media/IR/ir-core-priv.h
+++ b/drivers/media/rc/rc-core-priv.h
@@ -13,26 +13,88 @@
* GNU General Public License for more details.
*/
-#ifndef _IR_RAW_EVENT
-#define _IR_RAW_EVENT
+#ifndef _RC_CORE_PRIV
+#define _RC_CORE_PRIV
#include <linux/slab.h>
-#include <media/ir-core.h>
+#include <linux/spinlock.h>
+#include <media/rc-core.h>
struct ir_raw_handler {
struct list_head list;
- int (*decode)(struct input_dev *input_dev, struct ir_raw_event event);
- int (*raw_register)(struct input_dev *input_dev);
- int (*raw_unregister)(struct input_dev *input_dev);
+ u64 protocols; /* which are handled by this handler */
+ int (*decode)(struct rc_dev *dev, struct ir_raw_event event);
+
+ /* These two should only be used by the lirc decoder */
+ int (*raw_register)(struct rc_dev *dev);
+ int (*raw_unregister)(struct rc_dev *dev);
};
struct ir_raw_event_ctrl {
- struct work_struct rx_work; /* for the rx decoding workqueue */
+ struct list_head list; /* to keep track of raw clients */
+ struct task_struct *thread;
+ spinlock_t lock;
struct kfifo kfifo; /* fifo for the pulse/space durations */
ktime_t last_event; /* when last event occurred */
enum raw_event_type last_type; /* last event type */
- struct input_dev *input_dev; /* pointer to the parent input_dev */
+ struct rc_dev *dev; /* pointer to the parent rc_dev */
+ u64 enabled_protocols; /* enabled raw protocol decoders */
+
+ /* raw decoder state follows */
+ struct ir_raw_event prev_ev;
+ struct ir_raw_event this_ev;
+ struct nec_dec {
+ int state;
+ unsigned count;
+ u32 bits;
+ bool is_nec_x;
+ bool necx_repeat;
+ } nec;
+ struct rc5_dec {
+ int state;
+ u32 bits;
+ unsigned count;
+ unsigned wanted_bits;
+ } rc5;
+ struct rc6_dec {
+ int state;
+ u8 header;
+ u32 body;
+ bool toggle;
+ unsigned count;
+ unsigned wanted_bits;
+ } rc6;
+ struct sony_dec {
+ int state;
+ u32 bits;
+ unsigned count;
+ } sony;
+ struct jvc_dec {
+ int state;
+ u16 bits;
+ u16 old_bits;
+ unsigned count;
+ bool first;
+ bool toggle;
+ } jvc;
+ struct rc5_sz_dec {
+ int state;
+ u32 bits;
+ unsigned count;
+ unsigned wanted_bits;
+ } rc5_sz;
+ struct lirc_codec {
+ struct rc_dev *dev;
+ struct lirc_driver *drv;
+ int carrier_low;
+
+ ktime_t gap_start;
+ u64 gap_duration;
+ bool gap;
+ bool send_timeout_reports;
+
+ } lirc;
};
/* macros for IR decoders */
@@ -59,28 +121,25 @@ static inline void decrease_duration(struct ir_raw_event *ev, unsigned duration)
ev->duration -= duration;
}
-#define TO_US(duration) (((duration) + 500) / 1000)
-#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
-#define IS_RESET(ev) (ev.duration == 0)
-
-/*
- * Routines from ir-sysfs.c - Meant to be called only internally inside
- * ir-core
- */
+/* Returns true if event is normal pulse/space event */
+static inline bool is_timing_event(struct ir_raw_event ev)
+{
+ return !ev.carrier_report && !ev.reset;
+}
-int ir_register_class(struct input_dev *input_dev);
-void ir_unregister_class(struct input_dev *input_dev);
+#define TO_US(duration) DIV_ROUND_CLOSEST((duration), 1000)
+#define TO_STR(is_pulse) ((is_pulse) ? "pulse" : "space")
/*
- * Routines from ir-raw-event.c to be used internally and by decoders
+ * Routines from rc-raw.c to be used internally and by decoders
*/
-int ir_raw_event_register(struct input_dev *input_dev);
-void ir_raw_event_unregister(struct input_dev *input_dev);
+u64 ir_raw_get_allowed_protocols(void);
+int ir_raw_event_register(struct rc_dev *dev);
+void ir_raw_event_unregister(struct rc_dev *dev);
int ir_raw_handler_register(struct ir_raw_handler *ir_raw_handler);
void ir_raw_handler_unregister(struct ir_raw_handler *ir_raw_handler);
void ir_raw_init(void);
-
/*
* Decoder initialization code
*
@@ -123,4 +182,12 @@ void ir_raw_init(void);
#define load_sony_decode() 0
#endif
-#endif /* _IR_RAW_EVENT */
+/* from ir-lirc-codec.c */
+#ifdef CONFIG_IR_LIRC_CODEC_MODULE
+#define load_lirc_codec() request_module("ir-lirc-codec")
+#else
+#define load_lirc_codec() 0
+#endif
+
+
+#endif /* _RC_CORE_PRIV */
diff --git a/drivers/media/rc/rc-loopback.c b/drivers/media/rc/rc-loopback.c
new file mode 100644
index 000000000000..49cee61d79c6
--- /dev/null
+++ b/drivers/media/rc/rc-loopback.c
@@ -0,0 +1,260 @@
+/*
+ * Loopback driver for rc-core,
+ *
+ * Copyright (c) 2010 David Härdeman <david@hardeman.nu>
+ *
+ * This driver receives TX data and passes it back as RX data,
+ * which is useful for (scripted) debugging of rc-core without
+ * having to use actual hardware.
+ *
+ * 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/device.h>
+#include <linux/module.h>
+#include <linux/sched.h>
+#include <media/rc-core.h>
+
+#define DRIVER_NAME "rc-loopback"
+#define dprintk(x...) if (debug) printk(KERN_INFO DRIVER_NAME ": " x)
+#define RXMASK_REGULAR 0x1
+#define RXMASK_LEARNING 0x2
+
+static bool debug;
+
+struct loopback_dev {
+ struct rc_dev *dev;
+ u32 txmask;
+ u32 txcarrier;
+ u32 txduty;
+ bool idle;
+ bool learning;
+ bool carrierreport;
+ u32 rxcarriermin;
+ u32 rxcarriermax;
+};
+
+static struct loopback_dev loopdev;
+
+static int loop_set_tx_mask(struct rc_dev *dev, u32 mask)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if ((mask & (RXMASK_REGULAR | RXMASK_LEARNING)) != mask) {
+ dprintk("invalid tx mask: %u\n", mask);
+ return -EINVAL;
+ }
+
+ dprintk("setting tx mask: %u\n", mask);
+ lodev->txmask = mask;
+ return 0;
+}
+
+static int loop_set_tx_carrier(struct rc_dev *dev, u32 carrier)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ dprintk("setting tx carrier: %u\n", carrier);
+ lodev->txcarrier = carrier;
+ return 0;
+}
+
+static int loop_set_tx_duty_cycle(struct rc_dev *dev, u32 duty_cycle)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (duty_cycle < 1 || duty_cycle > 99) {
+ dprintk("invalid duty cycle: %u\n", duty_cycle);
+ return -EINVAL;
+ }
+
+ dprintk("setting duty cycle: %u\n", duty_cycle);
+ lodev->txduty = duty_cycle;
+ return 0;
+}
+
+static int loop_set_rx_carrier_range(struct rc_dev *dev, u32 min, u32 max)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (min < 1 || min > max) {
+ dprintk("invalid rx carrier range %u to %u\n", min, max);
+ return -EINVAL;
+ }
+
+ dprintk("setting rx carrier range %u to %u\n", min, max);
+ lodev->rxcarriermin = min;
+ lodev->rxcarriermax = max;
+ return 0;
+}
+
+static int loop_tx_ir(struct rc_dev *dev, int *txbuf, u32 n)
+{
+ struct loopback_dev *lodev = dev->priv;
+ u32 rxmask;
+ unsigned count;
+ unsigned total_duration = 0;
+ unsigned i;
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ if (n == 0 || n % sizeof(int)) {
+ dprintk("invalid tx buffer size\n");
+ return -EINVAL;
+ }
+
+ count = n / sizeof(int);
+ for (i = 0; i < count; i++)
+ total_duration += abs(txbuf[i]);
+
+ if (total_duration == 0) {
+ dprintk("invalid tx data, total duration zero\n");
+ return -EINVAL;
+ }
+
+ if (lodev->txcarrier < lodev->rxcarriermin ||
+ lodev->txcarrier > lodev->rxcarriermax) {
+ dprintk("ignoring tx, carrier out of range\n");
+ goto out;
+ }
+
+ if (lodev->learning)
+ rxmask = RXMASK_LEARNING;
+ else
+ rxmask = RXMASK_REGULAR;
+
+ if (!(rxmask & lodev->txmask)) {
+ dprintk("ignoring tx, rx mask mismatch\n");
+ goto out;
+ }
+
+ for (i = 0; i < count; i++) {
+ rawir.pulse = i % 2 ? false : true;
+ rawir.duration = abs(txbuf[i]) * 1000;
+ if (rawir.duration)
+ ir_raw_event_store_with_filter(dev, &rawir);
+ }
+ ir_raw_event_handle(dev);
+
+out:
+ /* Lirc expects this function to take as long as the total duration */
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(usecs_to_jiffies(total_duration));
+ return n;
+}
+
+static void loop_set_idle(struct rc_dev *dev, bool enable)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (lodev->idle != enable) {
+ dprintk("%sing idle mode\n", enable ? "enter" : "exit");
+ lodev->idle = enable;
+ }
+}
+
+static int loop_set_learning_mode(struct rc_dev *dev, int enable)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (lodev->learning != enable) {
+ dprintk("%sing learning mode\n", enable ? "enter" : "exit");
+ lodev->learning = !!enable;
+ }
+
+ return 0;
+}
+
+static int loop_set_carrier_report(struct rc_dev *dev, int enable)
+{
+ struct loopback_dev *lodev = dev->priv;
+
+ if (lodev->carrierreport != enable) {
+ dprintk("%sabling carrier reports\n", enable ? "en" : "dis");
+ lodev->carrierreport = !!enable;
+ }
+
+ return 0;
+}
+
+static int __init loop_init(void)
+{
+ struct rc_dev *rc;
+ int ret;
+
+ rc = rc_allocate_device();
+ if (!rc) {
+ printk(KERN_ERR DRIVER_NAME ": rc_dev allocation failed\n");
+ return -ENOMEM;
+ }
+
+ rc->input_name = "rc-core loopback device";
+ rc->input_phys = "rc-core/virtual";
+ rc->input_id.bustype = BUS_VIRTUAL;
+ rc->input_id.version = 1;
+ rc->driver_name = DRIVER_NAME;
+ rc->map_name = RC_MAP_EMPTY;
+ rc->priv = &loopdev;
+ rc->driver_type = RC_DRIVER_IR_RAW;
+ rc->allowed_protos = RC_TYPE_ALL;
+ rc->timeout = 100 * 1000 * 1000; /* 100 ms */
+ rc->min_timeout = 1;
+ rc->max_timeout = UINT_MAX;
+ rc->rx_resolution = 1000;
+ rc->tx_resolution = 1000;
+ rc->s_tx_mask = loop_set_tx_mask;
+ rc->s_tx_carrier = loop_set_tx_carrier;
+ rc->s_tx_duty_cycle = loop_set_tx_duty_cycle;
+ rc->s_rx_carrier_range = loop_set_rx_carrier_range;
+ rc->tx_ir = loop_tx_ir;
+ rc->s_idle = loop_set_idle;
+ rc->s_learning_mode = loop_set_learning_mode;
+ rc->s_carrier_report = loop_set_carrier_report;
+ rc->priv = &loopdev;
+
+ loopdev.txmask = RXMASK_REGULAR;
+ loopdev.txcarrier = 36000;
+ loopdev.txduty = 50;
+ loopdev.rxcarriermin = 1;
+ loopdev.rxcarriermax = ~0;
+ loopdev.idle = true;
+ loopdev.learning = false;
+ loopdev.carrierreport = false;
+
+ ret = rc_register_device(rc);
+ if (ret < 0) {
+ printk(KERN_ERR DRIVER_NAME ": rc_dev registration failed\n");
+ rc_free_device(rc);
+ return ret;
+ }
+
+ loopdev.dev = rc;
+ return 0;
+}
+
+static void __exit loop_exit(void)
+{
+ rc_unregister_device(loopdev.dev);
+}
+
+module_init(loop_init);
+module_exit(loop_exit);
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debug messages");
+
+MODULE_DESCRIPTION("Loopback device for rc-core debugging");
+MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/rc-main.c b/drivers/media/rc/rc-main.c
new file mode 100644
index 000000000000..72be8a02118c
--- /dev/null
+++ b/drivers/media/rc/rc-main.c
@@ -0,0 +1,1135 @@
+/* rc-main.c - Remote Controller core module
+ *
+ * Copyright (C) 2009-2010 by Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <media/rc-core.h>
+#include <linux/spinlock.h>
+#include <linux/delay.h>
+#include <linux/input.h>
+#include <linux/slab.h>
+#include <linux/device.h>
+#include "rc-core-priv.h"
+
+/* Sizes are in bytes, 256 bytes allows for 32 entries on x64 */
+#define IR_TAB_MIN_SIZE 256
+#define IR_TAB_MAX_SIZE 8192
+
+/* FIXME: IR_KEYPRESS_TIMEOUT should be protocol specific */
+#define IR_KEYPRESS_TIMEOUT 250
+
+/* Used to keep track of known keymaps */
+static LIST_HEAD(rc_map_list);
+static DEFINE_SPINLOCK(rc_map_lock);
+
+static struct rc_map_list *seek_rc_map(const char *name)
+{
+ struct rc_map_list *map = NULL;
+
+ spin_lock(&rc_map_lock);
+ list_for_each_entry(map, &rc_map_list, list) {
+ if (!strcmp(name, map->map.name)) {
+ spin_unlock(&rc_map_lock);
+ return map;
+ }
+ }
+ spin_unlock(&rc_map_lock);
+
+ return NULL;
+}
+
+struct rc_map *rc_map_get(const char *name)
+{
+
+ struct rc_map_list *map;
+
+ map = seek_rc_map(name);
+#ifdef MODULE
+ if (!map) {
+ int rc = request_module(name);
+ if (rc < 0) {
+ printk(KERN_ERR "Couldn't load IR keymap %s\n", name);
+ return NULL;
+ }
+ msleep(20); /* Give some time for IR to register */
+
+ map = seek_rc_map(name);
+ }
+#endif
+ if (!map) {
+ printk(KERN_ERR "IR keymap %s not found\n", name);
+ return NULL;
+ }
+
+ printk(KERN_INFO "Registered IR keymap %s\n", map->map.name);
+
+ return &map->map;
+}
+EXPORT_SYMBOL_GPL(rc_map_get);
+
+int rc_map_register(struct rc_map_list *map)
+{
+ spin_lock(&rc_map_lock);
+ list_add_tail(&map->list, &rc_map_list);
+ spin_unlock(&rc_map_lock);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(rc_map_register);
+
+void rc_map_unregister(struct rc_map_list *map)
+{
+ spin_lock(&rc_map_lock);
+ list_del(&map->list);
+ spin_unlock(&rc_map_lock);
+}
+EXPORT_SYMBOL_GPL(rc_map_unregister);
+
+
+static struct rc_map_table empty[] = {
+ { 0x2a, KEY_COFFEE },
+};
+
+static struct rc_map_list empty_map = {
+ .map = {
+ .scan = empty,
+ .size = ARRAY_SIZE(empty),
+ .rc_type = RC_TYPE_UNKNOWN, /* Legacy IR type */
+ .name = RC_MAP_EMPTY,
+ }
+};
+
+/**
+ * ir_create_table() - initializes a scancode table
+ * @rc_map: the rc_map to initialize
+ * @name: name to assign to the table
+ * @rc_type: ir type to assign to the new table
+ * @size: initial size of the table
+ * @return: zero on success or a negative error code
+ *
+ * This routine will initialize the rc_map and will allocate
+ * memory to hold at least the specified number of elements.
+ */
+static int ir_create_table(struct rc_map *rc_map,
+ const char *name, u64 rc_type, size_t size)
+{
+ rc_map->name = name;
+ rc_map->rc_type = rc_type;
+ rc_map->alloc = roundup_pow_of_two(size * sizeof(struct rc_map_table));
+ rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
+ rc_map->scan = kmalloc(rc_map->alloc, GFP_KERNEL);
+ if (!rc_map->scan)
+ return -ENOMEM;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_map->size, rc_map->alloc);
+ return 0;
+}
+
+/**
+ * ir_free_table() - frees memory allocated by a scancode table
+ * @rc_map: the table whose mappings need to be freed
+ *
+ * This routine will free memory alloctaed for key mappings used by given
+ * scancode table.
+ */
+static void ir_free_table(struct rc_map *rc_map)
+{
+ rc_map->size = 0;
+ kfree(rc_map->scan);
+ rc_map->scan = NULL;
+}
+
+/**
+ * ir_resize_table() - resizes a scancode table if necessary
+ * @rc_map: the rc_map to resize
+ * @gfp_flags: gfp flags to use when allocating memory
+ * @return: zero on success or a negative error code
+ *
+ * This routine will shrink the rc_map if it has lots of
+ * unused entries and grow it if it is full.
+ */
+static int ir_resize_table(struct rc_map *rc_map, gfp_t gfp_flags)
+{
+ unsigned int oldalloc = rc_map->alloc;
+ unsigned int newalloc = oldalloc;
+ struct rc_map_table *oldscan = rc_map->scan;
+ struct rc_map_table *newscan;
+
+ if (rc_map->size == rc_map->len) {
+ /* All entries in use -> grow keytable */
+ if (rc_map->alloc >= IR_TAB_MAX_SIZE)
+ return -ENOMEM;
+
+ newalloc *= 2;
+ IR_dprintk(1, "Growing table to %u bytes\n", newalloc);
+ }
+
+ if ((rc_map->len * 3 < rc_map->size) && (oldalloc > IR_TAB_MIN_SIZE)) {
+ /* Less than 1/3 of entries in use -> shrink keytable */
+ newalloc /= 2;
+ IR_dprintk(1, "Shrinking table to %u bytes\n", newalloc);
+ }
+
+ if (newalloc == oldalloc)
+ return 0;
+
+ newscan = kmalloc(newalloc, gfp_flags);
+ if (!newscan) {
+ IR_dprintk(1, "Failed to kmalloc %u bytes\n", newalloc);
+ return -ENOMEM;
+ }
+
+ memcpy(newscan, rc_map->scan, rc_map->len * sizeof(struct rc_map_table));
+ rc_map->scan = newscan;
+ rc_map->alloc = newalloc;
+ rc_map->size = rc_map->alloc / sizeof(struct rc_map_table);
+ kfree(oldscan);
+ return 0;
+}
+
+/**
+ * ir_update_mapping() - set a keycode in the scancode->keycode table
+ * @dev: the struct rc_dev device descriptor
+ * @rc_map: scancode table to be adjusted
+ * @index: index of the mapping that needs to be updated
+ * @keycode: the desired keycode
+ * @return: previous keycode assigned to the mapping
+ *
+ * This routine is used to update scancode->keycode mapping at given
+ * position.
+ */
+static unsigned int ir_update_mapping(struct rc_dev *dev,
+ struct rc_map *rc_map,
+ unsigned int index,
+ unsigned int new_keycode)
+{
+ int old_keycode = rc_map->scan[index].keycode;
+ int i;
+
+ /* Did the user wish to remove the mapping? */
+ if (new_keycode == KEY_RESERVED || new_keycode == KEY_UNKNOWN) {
+ IR_dprintk(1, "#%d: Deleting scan 0x%04x\n",
+ index, rc_map->scan[index].scancode);
+ rc_map->len--;
+ memmove(&rc_map->scan[index], &rc_map->scan[index+ 1],
+ (rc_map->len - index) * sizeof(struct rc_map_table));
+ } else {
+ IR_dprintk(1, "#%d: %s scan 0x%04x with key 0x%04x\n",
+ index,
+ old_keycode == KEY_RESERVED ? "New" : "Replacing",
+ rc_map->scan[index].scancode, new_keycode);
+ rc_map->scan[index].keycode = new_keycode;
+ __set_bit(new_keycode, dev->input_dev->keybit);
+ }
+
+ if (old_keycode != KEY_RESERVED) {
+ /* A previous mapping was updated... */
+ __clear_bit(old_keycode, dev->input_dev->keybit);
+ /* ... but another scancode might use the same keycode */
+ for (i = 0; i < rc_map->len; i++) {
+ if (rc_map->scan[i].keycode == old_keycode) {
+ __set_bit(old_keycode, dev->input_dev->keybit);
+ break;
+ }
+ }
+
+ /* Possibly shrink the keytable, failure is not a problem */
+ ir_resize_table(rc_map, GFP_ATOMIC);
+ }
+
+ return old_keycode;
+}
+
+/**
+ * ir_establish_scancode() - set a keycode in the scancode->keycode table
+ * @dev: the struct rc_dev device descriptor
+ * @rc_map: scancode table to be searched
+ * @scancode: the desired scancode
+ * @resize: controls whether we allowed to resize the table to
+ * accomodate not yet present scancodes
+ * @return: index of the mapping containing scancode in question
+ * or -1U in case of failure.
+ *
+ * This routine is used to locate given scancode in rc_map.
+ * If scancode is not yet present the routine will allocate a new slot
+ * for it.
+ */
+static unsigned int ir_establish_scancode(struct rc_dev *dev,
+ struct rc_map *rc_map,
+ unsigned int scancode,
+ bool resize)
+{
+ unsigned int i;
+
+ /*
+ * Unfortunately, some hardware-based IR decoders don't provide
+ * all bits for the complete IR code. In general, they provide only
+ * the command part of the IR code. Yet, as it is possible to replace
+ * the provided IR with another one, it is needed to allow loading
+ * IR tables from other remotes. So, we support specifying a mask to
+ * indicate the valid bits of the scancodes.
+ */
+ if (dev->scanmask)
+ scancode &= dev->scanmask;
+
+ /* First check if we already have a mapping for this ir command */
+ for (i = 0; i < rc_map->len; i++) {
+ if (rc_map->scan[i].scancode == scancode)
+ return i;
+
+ /* Keytable is sorted from lowest to highest scancode */
+ if (rc_map->scan[i].scancode >= scancode)
+ break;
+ }
+
+ /* No previous mapping found, we might need to grow the table */
+ if (rc_map->size == rc_map->len) {
+ if (!resize || ir_resize_table(rc_map, GFP_ATOMIC))
+ return -1U;
+ }
+
+ /* i is the proper index to insert our new keycode */
+ if (i < rc_map->len)
+ memmove(&rc_map->scan[i + 1], &rc_map->scan[i],
+ (rc_map->len - i) * sizeof(struct rc_map_table));
+ rc_map->scan[i].scancode = scancode;
+ rc_map->scan[i].keycode = KEY_RESERVED;
+ rc_map->len++;
+
+ return i;
+}
+
+/**
+ * ir_setkeycode() - set a keycode in the scancode->keycode table
+ * @idev: the struct input_dev device descriptor
+ * @scancode: the desired scancode
+ * @keycode: result
+ * @return: -EINVAL if the keycode could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle evdev EVIOCSKEY ioctl.
+ */
+static int ir_setkeycode(struct input_dev *idev,
+ const struct input_keymap_entry *ke,
+ unsigned int *old_keycode)
+{
+ struct rc_dev *rdev = input_get_drvdata(idev);
+ struct rc_map *rc_map = &rdev->rc_map;
+ unsigned int index;
+ unsigned int scancode;
+ int retval = 0;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ if (index >= rc_map->len) {
+ retval = -EINVAL;
+ goto out;
+ }
+ } else {
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ index = ir_establish_scancode(rdev, rc_map, scancode, true);
+ if (index >= rc_map->len) {
+ retval = -ENOMEM;
+ goto out;
+ }
+ }
+
+ *old_keycode = ir_update_mapping(rdev, rc_map, index, ke->keycode);
+
+out:
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+ return retval;
+}
+
+/**
+ * ir_setkeytable() - sets several entries in the scancode->keycode table
+ * @dev: the struct rc_dev device descriptor
+ * @to: the struct rc_map to copy entries to
+ * @from: the struct rc_map to copy entries from
+ * @return: -ENOMEM if all keycodes could not be inserted, otherwise zero.
+ *
+ * This routine is used to handle table initialization.
+ */
+static int ir_setkeytable(struct rc_dev *dev,
+ const struct rc_map *from)
+{
+ struct rc_map *rc_map = &dev->rc_map;
+ unsigned int i, index;
+ int rc;
+
+ rc = ir_create_table(rc_map, from->name,
+ from->rc_type, from->size);
+ if (rc)
+ return rc;
+
+ IR_dprintk(1, "Allocated space for %u keycode entries (%u bytes)\n",
+ rc_map->size, rc_map->alloc);
+
+ for (i = 0; i < from->size; i++) {
+ index = ir_establish_scancode(dev, rc_map,
+ from->scan[i].scancode, false);
+ if (index >= rc_map->len) {
+ rc = -ENOMEM;
+ break;
+ }
+
+ ir_update_mapping(dev, rc_map, index,
+ from->scan[i].keycode);
+ }
+
+ if (rc)
+ ir_free_table(rc_map);
+
+ return rc;
+}
+
+/**
+ * ir_lookup_by_scancode() - locate mapping by scancode
+ * @rc_map: the struct rc_map to search
+ * @scancode: scancode to look for in the table
+ * @return: index in the table, -1U if not found
+ *
+ * This routine performs binary search in RC keykeymap table for
+ * given scancode.
+ */
+static unsigned int ir_lookup_by_scancode(const struct rc_map *rc_map,
+ unsigned int scancode)
+{
+ int start = 0;
+ int end = rc_map->len - 1;
+ int mid;
+
+ while (start <= end) {
+ mid = (start + end) / 2;
+ if (rc_map->scan[mid].scancode < scancode)
+ start = mid + 1;
+ else if (rc_map->scan[mid].scancode > scancode)
+ end = mid - 1;
+ else
+ return mid;
+ }
+
+ return -1U;
+}
+
+/**
+ * ir_getkeycode() - get a keycode from the scancode->keycode table
+ * @idev: the struct input_dev device descriptor
+ * @scancode: the desired scancode
+ * @keycode: used to return the keycode, if found, or KEY_RESERVED
+ * @return: always returns zero.
+ *
+ * This routine is used to handle evdev EVIOCGKEY ioctl.
+ */
+static int ir_getkeycode(struct input_dev *idev,
+ struct input_keymap_entry *ke)
+{
+ struct rc_dev *rdev = input_get_drvdata(idev);
+ struct rc_map *rc_map = &rdev->rc_map;
+ struct rc_map_table *entry;
+ unsigned long flags;
+ unsigned int index;
+ unsigned int scancode;
+ int retval;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ if (ke->flags & INPUT_KEYMAP_BY_INDEX) {
+ index = ke->index;
+ } else {
+ retval = input_scancode_to_scalar(ke, &scancode);
+ if (retval)
+ goto out;
+
+ index = ir_lookup_by_scancode(rc_map, scancode);
+ }
+
+ if (index >= rc_map->len) {
+ if (!(ke->flags & INPUT_KEYMAP_BY_INDEX))
+ IR_dprintk(1, "unknown key for scancode 0x%04x\n",
+ scancode);
+ retval = -EINVAL;
+ goto out;
+ }
+
+ entry = &rc_map->scan[index];
+
+ ke->index = index;
+ ke->keycode = entry->keycode;
+ ke->len = sizeof(entry->scancode);
+ memcpy(ke->scancode, &entry->scancode, sizeof(entry->scancode));
+
+ retval = 0;
+
+out:
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+ return retval;
+}
+
+/**
+ * rc_g_keycode_from_table() - gets the keycode that corresponds to a scancode
+ * @dev: the struct rc_dev descriptor of the device
+ * @scancode: the scancode to look for
+ * @return: the corresponding keycode, or KEY_RESERVED
+ *
+ * This routine is used by drivers which need to convert a scancode to a
+ * keycode. Normally it should not be used since drivers should have no
+ * interest in keycodes.
+ */
+u32 rc_g_keycode_from_table(struct rc_dev *dev, u32 scancode)
+{
+ struct rc_map *rc_map = &dev->rc_map;
+ unsigned int keycode;
+ unsigned int index;
+ unsigned long flags;
+
+ spin_lock_irqsave(&rc_map->lock, flags);
+
+ index = ir_lookup_by_scancode(rc_map, scancode);
+ keycode = index < rc_map->len ?
+ rc_map->scan[index].keycode : KEY_RESERVED;
+
+ spin_unlock_irqrestore(&rc_map->lock, flags);
+
+ if (keycode != KEY_RESERVED)
+ IR_dprintk(1, "%s: scancode 0x%04x keycode 0x%02x\n",
+ dev->input_name, scancode, keycode);
+
+ return keycode;
+}
+EXPORT_SYMBOL_GPL(rc_g_keycode_from_table);
+
+/**
+ * ir_do_keyup() - internal function to signal the release of a keypress
+ * @dev: the struct rc_dev descriptor of the device
+ *
+ * This function is used internally to release a keypress, it must be
+ * called with keylock held.
+ */
+static void ir_do_keyup(struct rc_dev *dev)
+{
+ if (!dev->keypressed)
+ return;
+
+ IR_dprintk(1, "keyup key 0x%04x\n", dev->last_keycode);
+ input_report_key(dev->input_dev, dev->last_keycode, 0);
+ input_sync(dev->input_dev);
+ dev->keypressed = false;
+}
+
+/**
+ * rc_keyup() - signals the release of a keypress
+ * @dev: the struct rc_dev descriptor of the device
+ *
+ * This routine is used to signal that a key has been released on the
+ * remote control.
+ */
+void rc_keyup(struct rc_dev *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->keylock, flags);
+ ir_do_keyup(dev);
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keyup);
+
+/**
+ * ir_timer_keyup() - generates a keyup event after a timeout
+ * @cookie: a pointer to the struct rc_dev for the device
+ *
+ * This routine will generate a keyup event some time after a keydown event
+ * is generated when no further activity has been detected.
+ */
+static void ir_timer_keyup(unsigned long cookie)
+{
+ struct rc_dev *dev = (struct rc_dev *)cookie;
+ unsigned long flags;
+
+ /*
+ * ir->keyup_jiffies is used to prevent a race condition if a
+ * hardware interrupt occurs at this point and the keyup timer
+ * event is moved further into the future as a result.
+ *
+ * The timer will then be reactivated and this function called
+ * again in the future. We need to exit gracefully in that case
+ * to allow the input subsystem to do its auto-repeat magic or
+ * a keyup event might follow immediately after the keydown.
+ */
+ spin_lock_irqsave(&dev->keylock, flags);
+ if (time_is_before_eq_jiffies(dev->keyup_jiffies))
+ ir_do_keyup(dev);
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+
+/**
+ * rc_repeat() - signals that a key is still pressed
+ * @dev: the struct rc_dev descriptor of the device
+ *
+ * This routine is used by IR decoders when a repeat message which does
+ * not include the necessary bits to reproduce the scancode has been
+ * received.
+ */
+void rc_repeat(struct rc_dev *dev)
+{
+ unsigned long flags;
+
+ spin_lock_irqsave(&dev->keylock, flags);
+
+ input_event(dev->input_dev, EV_MSC, MSC_SCAN, dev->last_scancode);
+
+ if (!dev->keypressed)
+ goto out;
+
+ dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+ mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
+
+out:
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_repeat);
+
+/**
+ * ir_do_keydown() - internal function to process a keypress
+ * @dev: the struct rc_dev descriptor of the device
+ * @scancode: the scancode of the keypress
+ * @keycode: the keycode of the keypress
+ * @toggle: the toggle value of the keypress
+ *
+ * This function is used internally to register a keypress, it must be
+ * called with keylock held.
+ */
+static void ir_do_keydown(struct rc_dev *dev, int scancode,
+ u32 keycode, u8 toggle)
+{
+ input_event(dev->input_dev, EV_MSC, MSC_SCAN, scancode);
+
+ /* Repeat event? */
+ if (dev->keypressed &&
+ dev->last_scancode == scancode &&
+ dev->last_toggle == toggle)
+ return;
+
+ /* Release old keypress */
+ ir_do_keyup(dev);
+
+ dev->last_scancode = scancode;
+ dev->last_toggle = toggle;
+ dev->last_keycode = keycode;
+
+ if (keycode == KEY_RESERVED)
+ return;
+
+ /* Register a keypress */
+ dev->keypressed = true;
+ IR_dprintk(1, "%s: key down event, key 0x%04x, scancode 0x%04x\n",
+ dev->input_name, keycode, scancode);
+ input_report_key(dev->input_dev, dev->last_keycode, 1);
+ input_sync(dev->input_dev);
+}
+
+/**
+ * rc_keydown() - generates input event for a key press
+ * @dev: the struct rc_dev descriptor of the device
+ * @scancode: the scancode that we're seeking
+ * @toggle: the toggle value (protocol dependent, if the protocol doesn't
+ * support toggle values, this should be set to zero)
+ *
+ * This routine is used to signal that a key has been pressed on the
+ * remote control.
+ */
+void rc_keydown(struct rc_dev *dev, int scancode, u8 toggle)
+{
+ unsigned long flags;
+ u32 keycode = rc_g_keycode_from_table(dev, scancode);
+
+ spin_lock_irqsave(&dev->keylock, flags);
+ ir_do_keydown(dev, scancode, keycode, toggle);
+
+ if (dev->keypressed) {
+ dev->keyup_jiffies = jiffies + msecs_to_jiffies(IR_KEYPRESS_TIMEOUT);
+ mod_timer(&dev->timer_keyup, dev->keyup_jiffies);
+ }
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keydown);
+
+/**
+ * rc_keydown_notimeout() - generates input event for a key press without
+ * an automatic keyup event at a later time
+ * @dev: the struct rc_dev descriptor of the device
+ * @scancode: the scancode that we're seeking
+ * @toggle: the toggle value (protocol dependent, if the protocol doesn't
+ * support toggle values, this should be set to zero)
+ *
+ * This routine is used to signal that a key has been pressed on the
+ * remote control. The driver must manually call rc_keyup() at a later stage.
+ */
+void rc_keydown_notimeout(struct rc_dev *dev, int scancode, u8 toggle)
+{
+ unsigned long flags;
+ u32 keycode = rc_g_keycode_from_table(dev, scancode);
+
+ spin_lock_irqsave(&dev->keylock, flags);
+ ir_do_keydown(dev, scancode, keycode, toggle);
+ spin_unlock_irqrestore(&dev->keylock, flags);
+}
+EXPORT_SYMBOL_GPL(rc_keydown_notimeout);
+
+static int ir_open(struct input_dev *idev)
+{
+ struct rc_dev *rdev = input_get_drvdata(idev);
+
+ return rdev->open(rdev);
+}
+
+static void ir_close(struct input_dev *idev)
+{
+ struct rc_dev *rdev = input_get_drvdata(idev);
+
+ rdev->close(rdev);
+}
+
+/* class for /sys/class/rc */
+static char *ir_devnode(struct device *dev, mode_t *mode)
+{
+ return kasprintf(GFP_KERNEL, "rc/%s", dev_name(dev));
+}
+
+static struct class ir_input_class = {
+ .name = "rc",
+ .devnode = ir_devnode,
+};
+
+static struct {
+ u64 type;
+ char *name;
+} proto_names[] = {
+ { RC_TYPE_UNKNOWN, "unknown" },
+ { RC_TYPE_RC5, "rc-5" },
+ { RC_TYPE_NEC, "nec" },
+ { RC_TYPE_RC6, "rc-6" },
+ { RC_TYPE_JVC, "jvc" },
+ { RC_TYPE_SONY, "sony" },
+ { RC_TYPE_RC5_SZ, "rc-5-sz" },
+ { RC_TYPE_LIRC, "lirc" },
+};
+
+#define PROTO_NONE "none"
+
+/**
+ * show_protocols() - shows the current IR protocol(s)
+ * @device: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the output buffer
+ *
+ * This routine is a callback routine for input read the IR protocol type(s).
+ * it is trigged by reading /sys/class/rc/rc?/protocols.
+ * It returns the protocol names of supported protocols.
+ * Enabled protocols are printed in brackets.
+ */
+static ssize_t show_protocols(struct device *device,
+ struct device_attribute *mattr, char *buf)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ u64 allowed, enabled;
+ char *tmp = buf;
+ int i;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ if (dev->driver_type == RC_DRIVER_SCANCODE) {
+ enabled = dev->rc_map.rc_type;
+ allowed = dev->allowed_protos;
+ } else {
+ enabled = dev->raw->enabled_protocols;
+ allowed = ir_raw_get_allowed_protocols();
+ }
+
+ IR_dprintk(1, "allowed - 0x%llx, enabled - 0x%llx\n",
+ (long long)allowed,
+ (long long)enabled);
+
+ for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+ if (allowed & enabled & proto_names[i].type)
+ tmp += sprintf(tmp, "[%s] ", proto_names[i].name);
+ else if (allowed & proto_names[i].type)
+ tmp += sprintf(tmp, "%s ", proto_names[i].name);
+ }
+
+ if (tmp != buf)
+ tmp--;
+ *tmp = '\n';
+ return tmp + 1 - buf;
+}
+
+/**
+ * store_protocols() - changes the current IR protocol(s)
+ * @device: the device descriptor
+ * @mattr: the device attribute struct (unused)
+ * @buf: a pointer to the input buffer
+ * @len: length of the input buffer
+ *
+ * This routine is for changing the IR protocol type.
+ * It is trigged by writing to /sys/class/rc/rc?/protocols.
+ * Writing "+proto" will add a protocol to the list of enabled protocols.
+ * Writing "-proto" will remove a protocol from the list of enabled protocols.
+ * Writing "proto" will enable only "proto".
+ * Writing "none" will disable all protocols.
+ * Returns -EINVAL if an invalid protocol combination or unknown protocol name
+ * is used, otherwise @len.
+ */
+static ssize_t store_protocols(struct device *device,
+ struct device_attribute *mattr,
+ const char *data,
+ size_t len)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+ bool enable, disable;
+ const char *tmp;
+ u64 type;
+ u64 mask;
+ int rc, i, count = 0;
+ unsigned long flags;
+
+ /* Device is being removed */
+ if (!dev)
+ return -EINVAL;
+
+ if (dev->driver_type == RC_DRIVER_SCANCODE)
+ type = dev->rc_map.rc_type;
+ else if (dev->raw)
+ type = dev->raw->enabled_protocols;
+ else {
+ IR_dprintk(1, "Protocol switching not supported\n");
+ return -EINVAL;
+ }
+
+ while ((tmp = strsep((char **) &data, " \n")) != NULL) {
+ if (!*tmp)
+ break;
+
+ if (*tmp == '+') {
+ enable = true;
+ disable = false;
+ tmp++;
+ } else if (*tmp == '-') {
+ enable = false;
+ disable = true;
+ tmp++;
+ } else {
+ enable = false;
+ disable = false;
+ }
+
+ if (!enable && !disable && !strncasecmp(tmp, PROTO_NONE, sizeof(PROTO_NONE))) {
+ tmp += sizeof(PROTO_NONE);
+ mask = 0;
+ count++;
+ } else {
+ for (i = 0; i < ARRAY_SIZE(proto_names); i++) {
+ if (!strncasecmp(tmp, proto_names[i].name, strlen(proto_names[i].name))) {
+ tmp += strlen(proto_names[i].name);
+ mask = proto_names[i].type;
+ break;
+ }
+ }
+ if (i == ARRAY_SIZE(proto_names)) {
+ IR_dprintk(1, "Unknown protocol: '%s'\n", tmp);
+ return -EINVAL;
+ }
+ count++;
+ }
+
+ if (enable)
+ type |= mask;
+ else if (disable)
+ type &= ~mask;
+ else
+ type = mask;
+ }
+
+ if (!count) {
+ IR_dprintk(1, "Protocol not specified\n");
+ return -EINVAL;
+ }
+
+ if (dev->change_protocol) {
+ rc = dev->change_protocol(dev, type);
+ if (rc < 0) {
+ IR_dprintk(1, "Error setting protocols to 0x%llx\n",
+ (long long)type);
+ return -EINVAL;
+ }
+ }
+
+ if (dev->driver_type == RC_DRIVER_SCANCODE) {
+ spin_lock_irqsave(&dev->rc_map.lock, flags);
+ dev->rc_map.rc_type = type;
+ spin_unlock_irqrestore(&dev->rc_map.lock, flags);
+ } else {
+ dev->raw->enabled_protocols = type;
+ }
+
+ IR_dprintk(1, "Current protocol(s): 0x%llx\n",
+ (long long)type);
+
+ return len;
+}
+
+static void rc_dev_release(struct device *device)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+
+ kfree(dev);
+ module_put(THIS_MODULE);
+}
+
+#define ADD_HOTPLUG_VAR(fmt, val...) \
+ do { \
+ int err = add_uevent_var(env, fmt, val); \
+ if (err) \
+ return err; \
+ } while (0)
+
+static int rc_dev_uevent(struct device *device, struct kobj_uevent_env *env)
+{
+ struct rc_dev *dev = to_rc_dev(device);
+
+ if (dev->rc_map.name)
+ ADD_HOTPLUG_VAR("NAME=%s", dev->rc_map.name);
+ if (dev->driver_name)
+ ADD_HOTPLUG_VAR("DRV_NAME=%s", dev->driver_name);
+
+ return 0;
+}
+
+/*
+ * Static device attribute struct with the sysfs attributes for IR's
+ */
+static DEVICE_ATTR(protocols, S_IRUGO | S_IWUSR,
+ show_protocols, store_protocols);
+
+static struct attribute *rc_dev_attrs[] = {
+ &dev_attr_protocols.attr,
+ NULL,
+};
+
+static struct attribute_group rc_dev_attr_grp = {
+ .attrs = rc_dev_attrs,
+};
+
+static const struct attribute_group *rc_dev_attr_groups[] = {
+ &rc_dev_attr_grp,
+ NULL
+};
+
+static struct device_type rc_dev_type = {
+ .groups = rc_dev_attr_groups,
+ .release = rc_dev_release,
+ .uevent = rc_dev_uevent,
+};
+
+struct rc_dev *rc_allocate_device(void)
+{
+ struct rc_dev *dev;
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (!dev)
+ return NULL;
+
+ dev->input_dev = input_allocate_device();
+ if (!dev->input_dev) {
+ kfree(dev);
+ return NULL;
+ }
+
+ dev->input_dev->getkeycode_new = ir_getkeycode;
+ dev->input_dev->setkeycode_new = ir_setkeycode;
+ input_set_drvdata(dev->input_dev, dev);
+
+ spin_lock_init(&dev->rc_map.lock);
+ spin_lock_init(&dev->keylock);
+ setup_timer(&dev->timer_keyup, ir_timer_keyup, (unsigned long)dev);
+
+ dev->dev.type = &rc_dev_type;
+ dev->dev.class = &ir_input_class;
+ device_initialize(&dev->dev);
+
+ __module_get(THIS_MODULE);
+ return dev;
+}
+EXPORT_SYMBOL_GPL(rc_allocate_device);
+
+void rc_free_device(struct rc_dev *dev)
+{
+ if (dev) {
+ input_free_device(dev->input_dev);
+ put_device(&dev->dev);
+ }
+}
+EXPORT_SYMBOL_GPL(rc_free_device);
+
+int rc_register_device(struct rc_dev *dev)
+{
+ static atomic_t devno = ATOMIC_INIT(0);
+ struct rc_map *rc_map;
+ const char *path;
+ int rc;
+
+ if (!dev || !dev->map_name)
+ return -EINVAL;
+
+ rc_map = rc_map_get(dev->map_name);
+ if (!rc_map)
+ rc_map = rc_map_get(RC_MAP_EMPTY);
+ if (!rc_map || !rc_map->scan || rc_map->size == 0)
+ return -EINVAL;
+
+ set_bit(EV_KEY, dev->input_dev->evbit);
+ set_bit(EV_REP, dev->input_dev->evbit);
+ set_bit(EV_MSC, dev->input_dev->evbit);
+ set_bit(MSC_SCAN, dev->input_dev->mscbit);
+ if (dev->open)
+ dev->input_dev->open = ir_open;
+ if (dev->close)
+ dev->input_dev->close = ir_close;
+
+ dev->devno = (unsigned long)(atomic_inc_return(&devno) - 1);
+ dev_set_name(&dev->dev, "rc%ld", dev->devno);
+ dev_set_drvdata(&dev->dev, dev);
+ rc = device_add(&dev->dev);
+ if (rc)
+ return rc;
+
+ rc = ir_setkeytable(dev, rc_map);
+ if (rc)
+ goto out_dev;
+
+ dev->input_dev->dev.parent = &dev->dev;
+ memcpy(&dev->input_dev->id, &dev->input_id, sizeof(dev->input_id));
+ dev->input_dev->phys = dev->input_phys;
+ dev->input_dev->name = dev->input_name;
+ rc = input_register_device(dev->input_dev);
+ if (rc)
+ goto out_table;
+
+ /*
+ * Default delay of 250ms is too short for some protocols, expecially
+ * since the timeout is currently set to 250ms. Increase it to 500ms,
+ * to avoid wrong repetition of the keycodes. Note that this must be
+ * set after the call to input_register_device().
+ */
+ dev->input_dev->rep[REP_DELAY] = 500;
+
+ path = kobject_get_path(&dev->dev.kobj, GFP_KERNEL);
+ printk(KERN_INFO "%s: %s as %s\n",
+ dev_name(&dev->dev),
+ dev->input_name ? dev->input_name : "Unspecified device",
+ path ? path : "N/A");
+ kfree(path);
+
+ if (dev->driver_type == RC_DRIVER_IR_RAW) {
+ rc = ir_raw_event_register(dev);
+ if (rc < 0)
+ goto out_input;
+ }
+
+ if (dev->change_protocol) {
+ rc = dev->change_protocol(dev, rc_map->rc_type);
+ if (rc < 0)
+ goto out_raw;
+ }
+
+ IR_dprintk(1, "Registered rc%ld (driver: %s, remote: %s, mode %s)\n",
+ dev->devno,
+ dev->driver_name ? dev->driver_name : "unknown",
+ rc_map->name ? rc_map->name : "unknown",
+ dev->driver_type == RC_DRIVER_IR_RAW ? "raw" : "cooked");
+
+ return 0;
+
+out_raw:
+ if (dev->driver_type == RC_DRIVER_IR_RAW)
+ ir_raw_event_unregister(dev);
+out_input:
+ input_unregister_device(dev->input_dev);
+ dev->input_dev = NULL;
+out_table:
+ ir_free_table(&dev->rc_map);
+out_dev:
+ device_del(&dev->dev);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(rc_register_device);
+
+void rc_unregister_device(struct rc_dev *dev)
+{
+ if (!dev)
+ return;
+
+ del_timer_sync(&dev->timer_keyup);
+
+ if (dev->driver_type == RC_DRIVER_IR_RAW)
+ ir_raw_event_unregister(dev);
+
+ input_unregister_device(dev->input_dev);
+ dev->input_dev = NULL;
+
+ ir_free_table(&dev->rc_map);
+ IR_dprintk(1, "Freed keycode table\n");
+
+ device_unregister(&dev->dev);
+}
+EXPORT_SYMBOL_GPL(rc_unregister_device);
+
+/*
+ * Init/exit code for the module. Basically, creates/removes /sys/class/rc
+ */
+
+static int __init rc_core_init(void)
+{
+ int rc = class_register(&ir_input_class);
+ if (rc) {
+ printk(KERN_ERR "rc_core: unable to register rc class\n");
+ return rc;
+ }
+
+ /* Initialize/load the decoders/keymap code that will be used */
+ ir_raw_init();
+ rc_map_register(&empty_map);
+
+ return 0;
+}
+
+static void __exit rc_core_exit(void)
+{
+ class_unregister(&ir_input_class);
+ rc_map_unregister(&empty_map);
+}
+
+module_init(rc_core_init);
+module_exit(rc_core_exit);
+
+int rc_core_debug; /* ir_debug level (0,1,2) */
+EXPORT_SYMBOL_GPL(rc_core_debug);
+module_param_named(debug, rc_core_debug, int, 0644);
+
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/rc/streamzap.c b/drivers/media/rc/streamzap.c
new file mode 100644
index 000000000000..6e2911c2abfb
--- /dev/null
+++ b/drivers/media/rc/streamzap.c
@@ -0,0 +1,557 @@
+/*
+ * Streamzap Remote Control driver
+ *
+ * Copyright (c) 2005 Christoph Bartelmus <lirc@bartelmus.de>
+ * Copyright (c) 2010 Jarod Wilson <jarod@wilsonet.com>
+ *
+ * This driver was based on the work of Greg Wickham and Adrian
+ * Dewhurst. It was substantially rewritten to support correct signal
+ * gaps and now maintains a delay buffer, which is used to present
+ * consistent timing behaviour to user space applications. Without the
+ * delay buffer an ugly hack would be required in lircd, which can
+ * cause sluggish signal decoding in certain situations.
+ *
+ * Ported to in-kernel ir-core interface by Jarod Wilson
+ *
+ * This driver is based on the USB skeleton driver packaged with the
+ * kernel; copyright (C) 2001-2003 Greg Kroah-Hartman (greg@kroah.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#include <linux/device.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/usb.h>
+#include <linux/usb/input.h>
+#include <media/rc-core.h>
+
+#define DRIVER_VERSION "1.61"
+#define DRIVER_NAME "streamzap"
+#define DRIVER_DESC "Streamzap Remote Control driver"
+
+#ifdef CONFIG_USB_DEBUG
+static int debug = 1;
+#else
+static int debug;
+#endif
+
+#define USB_STREAMZAP_VENDOR_ID 0x0e9c
+#define USB_STREAMZAP_PRODUCT_ID 0x0000
+
+/* table of devices that work with this driver */
+static struct usb_device_id streamzap_table[] = {
+ /* Streamzap Remote Control */
+ { USB_DEVICE(USB_STREAMZAP_VENDOR_ID, USB_STREAMZAP_PRODUCT_ID) },
+ /* Terminating entry */
+ { }
+};
+
+MODULE_DEVICE_TABLE(usb, streamzap_table);
+
+#define SZ_PULSE_MASK 0xf0
+#define SZ_SPACE_MASK 0x0f
+#define SZ_TIMEOUT 0xff
+#define SZ_RESOLUTION 256
+
+/* number of samples buffered */
+#define SZ_BUF_LEN 128
+
+/* from ir-rc5-sz-decoder.c */
+#ifdef CONFIG_IR_RC5_SZ_DECODER_MODULE
+#define load_rc5_sz_decode() request_module("ir-rc5-sz-decoder")
+#else
+#define load_rc5_sz_decode() {}
+#endif
+
+enum StreamzapDecoderState {
+ PulseSpace,
+ FullPulse,
+ FullSpace,
+ IgnorePulse
+};
+
+/* structure to hold our device specific stuff */
+struct streamzap_ir {
+ /* ir-core */
+ struct rc_dev *rdev;
+
+ /* core device info */
+ struct device *dev;
+
+ /* usb */
+ struct usb_device *usbdev;
+ struct usb_interface *interface;
+ struct usb_endpoint_descriptor *endpoint;
+ struct urb *urb_in;
+
+ /* buffer & dma */
+ unsigned char *buf_in;
+ dma_addr_t dma_in;
+ unsigned int buf_in_len;
+
+ /* track what state we're in */
+ enum StreamzapDecoderState decoder_state;
+ /* tracks whether we are currently receiving some signal */
+ bool idle;
+ /* sum of signal lengths received since signal start */
+ unsigned long sum;
+ /* start time of signal; necessary for gap tracking */
+ struct timeval signal_last;
+ struct timeval signal_start;
+ bool timeout_enabled;
+
+ char name[128];
+ char phys[64];
+};
+
+
+/* local function prototypes */
+static int streamzap_probe(struct usb_interface *interface,
+ const struct usb_device_id *id);
+static void streamzap_disconnect(struct usb_interface *interface);
+static void streamzap_callback(struct urb *urb);
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message);
+static int streamzap_resume(struct usb_interface *intf);
+
+/* usb specific object needed to register this driver with the usb subsystem */
+static struct usb_driver streamzap_driver = {
+ .name = DRIVER_NAME,
+ .probe = streamzap_probe,
+ .disconnect = streamzap_disconnect,
+ .suspend = streamzap_suspend,
+ .resume = streamzap_resume,
+ .id_table = streamzap_table,
+};
+
+static void sz_push(struct streamzap_ir *sz, struct ir_raw_event rawir)
+{
+ dev_dbg(sz->dev, "Storing %s with duration %u us\n",
+ (rawir.pulse ? "pulse" : "space"), rawir.duration);
+ ir_raw_event_store_with_filter(sz->rdev, &rawir);
+}
+
+static void sz_push_full_pulse(struct streamzap_ir *sz,
+ unsigned char value)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ if (sz->idle) {
+ long deltv;
+
+ sz->signal_last = sz->signal_start;
+ do_gettimeofday(&sz->signal_start);
+
+ deltv = sz->signal_start.tv_sec - sz->signal_last.tv_sec;
+ rawir.pulse = false;
+ if (deltv > 15) {
+ /* really long time */
+ rawir.duration = IR_MAX_DURATION;
+ } else {
+ rawir.duration = (int)(deltv * 1000000 +
+ sz->signal_start.tv_usec -
+ sz->signal_last.tv_usec);
+ rawir.duration -= sz->sum;
+ rawir.duration *= 1000;
+ rawir.duration &= IR_MAX_DURATION;
+ }
+ sz_push(sz, rawir);
+
+ sz->idle = false;
+ sz->sum = 0;
+ }
+
+ rawir.pulse = true;
+ rawir.duration = ((int) value) * SZ_RESOLUTION;
+ rawir.duration += SZ_RESOLUTION / 2;
+ sz->sum += rawir.duration;
+ rawir.duration *= 1000;
+ rawir.duration &= IR_MAX_DURATION;
+ sz_push(sz, rawir);
+}
+
+static void sz_push_half_pulse(struct streamzap_ir *sz,
+ unsigned char value)
+{
+ sz_push_full_pulse(sz, (value & SZ_PULSE_MASK) >> 4);
+}
+
+static void sz_push_full_space(struct streamzap_ir *sz,
+ unsigned char value)
+{
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ rawir.pulse = false;
+ rawir.duration = ((int) value) * SZ_RESOLUTION;
+ rawir.duration += SZ_RESOLUTION / 2;
+ sz->sum += rawir.duration;
+ rawir.duration *= 1000;
+ sz_push(sz, rawir);
+}
+
+static void sz_push_half_space(struct streamzap_ir *sz,
+ unsigned long value)
+{
+ sz_push_full_space(sz, value & SZ_SPACE_MASK);
+}
+
+/**
+ * streamzap_callback - usb IRQ handler callback
+ *
+ * This procedure is invoked on reception of data from
+ * the usb remote.
+ */
+static void streamzap_callback(struct urb *urb)
+{
+ struct streamzap_ir *sz;
+ unsigned int i;
+ int len;
+
+ if (!urb)
+ return;
+
+ sz = urb->context;
+ len = urb->actual_length;
+
+ switch (urb->status) {
+ case -ECONNRESET:
+ case -ENOENT:
+ case -ESHUTDOWN:
+ /*
+ * this urb is terminated, clean up.
+ * sz might already be invalid at this point
+ */
+ dev_err(sz->dev, "urb terminated, status: %d\n", urb->status);
+ return;
+ default:
+ break;
+ }
+
+ dev_dbg(sz->dev, "%s: received urb, len %d\n", __func__, len);
+ for (i = 0; i < len; i++) {
+ dev_dbg(sz->dev, "sz->buf_in[%d]: %x\n",
+ i, (unsigned char)sz->buf_in[i]);
+ switch (sz->decoder_state) {
+ case PulseSpace:
+ if ((sz->buf_in[i] & SZ_PULSE_MASK) ==
+ SZ_PULSE_MASK) {
+ sz->decoder_state = FullPulse;
+ continue;
+ } else if ((sz->buf_in[i] & SZ_SPACE_MASK)
+ == SZ_SPACE_MASK) {
+ sz_push_half_pulse(sz, sz->buf_in[i]);
+ sz->decoder_state = FullSpace;
+ continue;
+ } else {
+ sz_push_half_pulse(sz, sz->buf_in[i]);
+ sz_push_half_space(sz, sz->buf_in[i]);
+ }
+ break;
+ case FullPulse:
+ sz_push_full_pulse(sz, sz->buf_in[i]);
+ sz->decoder_state = IgnorePulse;
+ break;
+ case FullSpace:
+ if (sz->buf_in[i] == SZ_TIMEOUT) {
+ DEFINE_IR_RAW_EVENT(rawir);
+
+ rawir.pulse = false;
+ rawir.duration = sz->rdev->timeout;
+ sz->idle = true;
+ if (sz->timeout_enabled)
+ sz_push(sz, rawir);
+ ir_raw_event_handle(sz->rdev);
+ } else {
+ sz_push_full_space(sz, sz->buf_in[i]);
+ }
+ sz->decoder_state = PulseSpace;
+ break;
+ case IgnorePulse:
+ if ((sz->buf_in[i] & SZ_SPACE_MASK) ==
+ SZ_SPACE_MASK) {
+ sz->decoder_state = FullSpace;
+ continue;
+ }
+ sz_push_half_space(sz, sz->buf_in[i]);
+ sz->decoder_state = PulseSpace;
+ break;
+ }
+ }
+
+ usb_submit_urb(urb, GFP_ATOMIC);
+
+ return;
+}
+
+static struct rc_dev *streamzap_init_rc_dev(struct streamzap_ir *sz)
+{
+ struct rc_dev *rdev;
+ struct device *dev = sz->dev;
+ int ret;
+
+ rdev = rc_allocate_device();
+ if (!rdev) {
+ dev_err(dev, "remote dev allocation failed\n");
+ goto out;
+ }
+
+ snprintf(sz->name, sizeof(sz->name), "Streamzap PC Remote Infrared "
+ "Receiver (%04x:%04x)",
+ le16_to_cpu(sz->usbdev->descriptor.idVendor),
+ le16_to_cpu(sz->usbdev->descriptor.idProduct));
+ usb_make_path(sz->usbdev, sz->phys, sizeof(sz->phys));
+ strlcat(sz->phys, "/input0", sizeof(sz->phys));
+
+ rdev->input_name = sz->name;
+ rdev->input_phys = sz->phys;
+ usb_to_input_id(sz->usbdev, &rdev->input_id);
+ rdev->dev.parent = dev;
+ rdev->priv = sz;
+ rdev->driver_type = RC_DRIVER_IR_RAW;
+ rdev->allowed_protos = RC_TYPE_ALL;
+ rdev->driver_name = DRIVER_NAME;
+ rdev->map_name = RC_MAP_STREAMZAP;
+
+ ret = rc_register_device(rdev);
+ if (ret < 0) {
+ dev_err(dev, "remote input device register failed\n");
+ goto out;
+ }
+
+ return rdev;
+
+out:
+ rc_free_device(rdev);
+ return NULL;
+}
+
+/**
+ * streamzap_probe
+ *
+ * Called by usb-core to associated with a candidate device
+ * On any failure the return value is the ERROR
+ * On success return 0
+ */
+static int __devinit streamzap_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct usb_device *usbdev = interface_to_usbdev(intf);
+ struct usb_host_interface *iface_host;
+ struct streamzap_ir *sz = NULL;
+ char buf[63], name[128] = "";
+ int retval = -ENOMEM;
+ int pipe, maxp;
+
+ /* Allocate space for device driver specific data */
+ sz = kzalloc(sizeof(struct streamzap_ir), GFP_KERNEL);
+ if (!sz)
+ return -ENOMEM;
+
+ sz->usbdev = usbdev;
+ sz->interface = intf;
+
+ /* Check to ensure endpoint information matches requirements */
+ iface_host = intf->cur_altsetting;
+
+ if (iface_host->desc.bNumEndpoints != 1) {
+ dev_err(&intf->dev, "%s: Unexpected desc.bNumEndpoints (%d)\n",
+ __func__, iface_host->desc.bNumEndpoints);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+ sz->endpoint = &(iface_host->endpoint[0].desc);
+ if ((sz->endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK)
+ != USB_DIR_IN) {
+ dev_err(&intf->dev, "%s: endpoint doesn't match input device "
+ "02%02x\n", __func__, sz->endpoint->bEndpointAddress);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+ if ((sz->endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK)
+ != USB_ENDPOINT_XFER_INT) {
+ dev_err(&intf->dev, "%s: endpoint attributes don't match xfer "
+ "02%02x\n", __func__, sz->endpoint->bmAttributes);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+ pipe = usb_rcvintpipe(usbdev, sz->endpoint->bEndpointAddress);
+ maxp = usb_maxpacket(usbdev, pipe, usb_pipeout(pipe));
+
+ if (maxp == 0) {
+ dev_err(&intf->dev, "%s: endpoint Max Packet Size is 0!?!\n",
+ __func__);
+ retval = -ENODEV;
+ goto free_sz;
+ }
+
+ /* Allocate the USB buffer and IRQ URB */
+ sz->buf_in = usb_alloc_coherent(usbdev, maxp, GFP_ATOMIC, &sz->dma_in);
+ if (!sz->buf_in)
+ goto free_sz;
+
+ sz->urb_in = usb_alloc_urb(0, GFP_KERNEL);
+ if (!sz->urb_in)
+ goto free_buf_in;
+
+ sz->dev = &intf->dev;
+ sz->buf_in_len = maxp;
+
+ if (usbdev->descriptor.iManufacturer
+ && usb_string(usbdev, usbdev->descriptor.iManufacturer,
+ buf, sizeof(buf)) > 0)
+ strlcpy(name, buf, sizeof(name));
+
+ if (usbdev->descriptor.iProduct
+ && usb_string(usbdev, usbdev->descriptor.iProduct,
+ buf, sizeof(buf)) > 0)
+ snprintf(name + strlen(name), sizeof(name) - strlen(name),
+ " %s", buf);
+
+ sz->rdev = streamzap_init_rc_dev(sz);
+ if (!sz->rdev)
+ goto rc_dev_fail;
+
+ sz->idle = true;
+ sz->decoder_state = PulseSpace;
+ /* FIXME: don't yet have a way to set this */
+ sz->timeout_enabled = true;
+ sz->rdev->timeout = (((SZ_TIMEOUT * SZ_RESOLUTION * 1000) &
+ IR_MAX_DURATION) | 0x03000000);
+ #if 0
+ /* not yet supported, depends on patches from maxim */
+ /* see also: LIRC_GET_REC_RESOLUTION and LIRC_SET_REC_TIMEOUT */
+ sz->min_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
+ sz->max_timeout = SZ_TIMEOUT * SZ_RESOLUTION * 1000;
+ #endif
+
+ do_gettimeofday(&sz->signal_start);
+
+ /* Complete final initialisations */
+ usb_fill_int_urb(sz->urb_in, usbdev, pipe, sz->buf_in,
+ maxp, (usb_complete_t)streamzap_callback,
+ sz, sz->endpoint->bInterval);
+ sz->urb_in->transfer_dma = sz->dma_in;
+ sz->urb_in->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
+
+ usb_set_intfdata(intf, sz);
+
+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC))
+ dev_err(sz->dev, "urb submit failed\n");
+
+ dev_info(sz->dev, "Registered %s on usb%d:%d\n", name,
+ usbdev->bus->busnum, usbdev->devnum);
+
+ /* Load the streamzap not-quite-rc5 decoder too */
+ load_rc5_sz_decode();
+
+ return 0;
+
+rc_dev_fail:
+ usb_free_urb(sz->urb_in);
+free_buf_in:
+ usb_free_coherent(usbdev, maxp, sz->buf_in, sz->dma_in);
+free_sz:
+ kfree(sz);
+
+ return retval;
+}
+
+/**
+ * streamzap_disconnect
+ *
+ * Called by the usb core when the device is removed from the system.
+ *
+ * This routine guarantees that the driver will not submit any more urbs
+ * by clearing dev->usbdev. It is also supposed to terminate any currently
+ * active urbs. Unfortunately, usb_bulk_msg(), used in streamzap_read(),
+ * does not provide any way to do this.
+ */
+static void streamzap_disconnect(struct usb_interface *interface)
+{
+ struct streamzap_ir *sz = usb_get_intfdata(interface);
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+
+ usb_set_intfdata(interface, NULL);
+
+ if (!sz)
+ return;
+
+ sz->usbdev = NULL;
+ rc_unregister_device(sz->rdev);
+ usb_kill_urb(sz->urb_in);
+ usb_free_urb(sz->urb_in);
+ usb_free_coherent(usbdev, sz->buf_in_len, sz->buf_in, sz->dma_in);
+
+ kfree(sz);
+}
+
+static int streamzap_suspend(struct usb_interface *intf, pm_message_t message)
+{
+ struct streamzap_ir *sz = usb_get_intfdata(intf);
+
+ usb_kill_urb(sz->urb_in);
+
+ return 0;
+}
+
+static int streamzap_resume(struct usb_interface *intf)
+{
+ struct streamzap_ir *sz = usb_get_intfdata(intf);
+
+ if (usb_submit_urb(sz->urb_in, GFP_ATOMIC)) {
+ dev_err(sz->dev, "Error sumbiting urb\n");
+ return -EIO;
+ }
+
+ return 0;
+}
+
+/**
+ * streamzap_init
+ */
+static int __init streamzap_init(void)
+{
+ int ret;
+
+ /* register this driver with the USB subsystem */
+ ret = usb_register(&streamzap_driver);
+ if (ret < 0)
+ printk(KERN_ERR DRIVER_NAME ": usb register failed, "
+ "result = %d\n", ret);
+
+ return ret;
+}
+
+/**
+ * streamzap_exit
+ */
+static void __exit streamzap_exit(void)
+{
+ usb_deregister(&streamzap_driver);
+}
+
+
+module_init(streamzap_init);
+module_exit(streamzap_exit);
+
+MODULE_AUTHOR("Jarod Wilson <jarod@wilsonet.com>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
+
+module_param(debug, bool, S_IRUGO | S_IWUSR);
+MODULE_PARM_DESC(debug, "Enable debugging messages");
diff --git a/drivers/media/rc/winbond-cir.c b/drivers/media/rc/winbond-cir.c
new file mode 100644
index 000000000000..186de5522001
--- /dev/null
+++ b/drivers/media/rc/winbond-cir.c
@@ -0,0 +1,932 @@
+/*
+ * winbond-cir.c - Driver for the Consumer IR functionality of Winbond
+ * SuperI/O chips.
+ *
+ * Currently supports the Winbond WPCD376i chip (PNP id WEC1022), but
+ * could probably support others (Winbond WEC102X, NatSemi, etc)
+ * with minor modifications.
+ *
+ * Original Author: David Härdeman <david@hardeman.nu>
+ * Copyright (C) 2009 - 2010 David Härdeman <david@hardeman.nu>
+ *
+ * Dedicated to my daughter Matilda, without whose loving attention this
+ * driver would have been finished in half the time and with a fraction
+ * of the bugs.
+ *
+ * Written using:
+ * o Winbond WPCD376I datasheet helpfully provided by Jesse Barnes at Intel
+ * o NatSemi PC87338/PC97338 datasheet (for the serial port stuff)
+ * o DSDT dumps
+ *
+ * Supported features:
+ * o Wake-On-CIR functionality
+ *
+ * To do:
+ * o Learning
+ * o IR Transmit
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/pnp.h>
+#include <linux/interrupt.h>
+#include <linux/timer.h>
+#include <linux/leds.h>
+#include <linux/spinlock.h>
+#include <linux/pci_ids.h>
+#include <linux/io.h>
+#include <linux/bitrev.h>
+#include <linux/slab.h>
+#include <media/rc-core.h>
+
+#define DRVNAME "winbond-cir"
+
+/* CEIR Wake-Up Registers, relative to data->wbase */
+#define WBCIR_REG_WCEIR_CTL 0x03 /* CEIR Receiver Control */
+#define WBCIR_REG_WCEIR_STS 0x04 /* CEIR Receiver Status */
+#define WBCIR_REG_WCEIR_EV_EN 0x05 /* CEIR Receiver Event Enable */
+#define WBCIR_REG_WCEIR_CNTL 0x06 /* CEIR Receiver Counter Low */
+#define WBCIR_REG_WCEIR_CNTH 0x07 /* CEIR Receiver Counter High */
+#define WBCIR_REG_WCEIR_INDEX 0x08 /* CEIR Receiver Index */
+#define WBCIR_REG_WCEIR_DATA 0x09 /* CEIR Receiver Data */
+#define WBCIR_REG_WCEIR_CSL 0x0A /* CEIR Re. Compare Strlen */
+#define WBCIR_REG_WCEIR_CFG1 0x0B /* CEIR Re. Configuration 1 */
+#define WBCIR_REG_WCEIR_CFG2 0x0C /* CEIR Re. Configuration 2 */
+
+/* CEIR Enhanced Functionality Registers, relative to data->ebase */
+#define WBCIR_REG_ECEIR_CTS 0x00 /* Enhanced IR Control Status */
+#define WBCIR_REG_ECEIR_CCTL 0x01 /* Infrared Counter Control */
+#define WBCIR_REG_ECEIR_CNT_LO 0x02 /* Infrared Counter LSB */
+#define WBCIR_REG_ECEIR_CNT_HI 0x03 /* Infrared Counter MSB */
+#define WBCIR_REG_ECEIR_IREM 0x04 /* Infrared Emitter Status */
+
+/* SP3 Banked Registers, relative to data->sbase */
+#define WBCIR_REG_SP3_BSR 0x03 /* Bank Select, all banks */
+ /* Bank 0 */
+#define WBCIR_REG_SP3_RXDATA 0x00 /* FIFO RX data (r) */
+#define WBCIR_REG_SP3_TXDATA 0x00 /* FIFO TX data (w) */
+#define WBCIR_REG_SP3_IER 0x01 /* Interrupt Enable */
+#define WBCIR_REG_SP3_EIR 0x02 /* Event Identification (r) */
+#define WBCIR_REG_SP3_FCR 0x02 /* FIFO Control (w) */
+#define WBCIR_REG_SP3_MCR 0x04 /* Mode Control */
+#define WBCIR_REG_SP3_LSR 0x05 /* Link Status */
+#define WBCIR_REG_SP3_MSR 0x06 /* Modem Status */
+#define WBCIR_REG_SP3_ASCR 0x07 /* Aux Status and Control */
+ /* Bank 2 */
+#define WBCIR_REG_SP3_BGDL 0x00 /* Baud Divisor LSB */
+#define WBCIR_REG_SP3_BGDH 0x01 /* Baud Divisor MSB */
+#define WBCIR_REG_SP3_EXCR1 0x02 /* Extended Control 1 */
+#define WBCIR_REG_SP3_EXCR2 0x04 /* Extended Control 2 */
+#define WBCIR_REG_SP3_TXFLV 0x06 /* TX FIFO Level */
+#define WBCIR_REG_SP3_RXFLV 0x07 /* RX FIFO Level */
+ /* Bank 3 */
+#define WBCIR_REG_SP3_MRID 0x00 /* Module Identification */
+#define WBCIR_REG_SP3_SH_LCR 0x01 /* LCR Shadow */
+#define WBCIR_REG_SP3_SH_FCR 0x02 /* FCR Shadow */
+ /* Bank 4 */
+#define WBCIR_REG_SP3_IRCR1 0x02 /* Infrared Control 1 */
+ /* Bank 5 */
+#define WBCIR_REG_SP3_IRCR2 0x04 /* Infrared Control 2 */
+ /* Bank 6 */
+#define WBCIR_REG_SP3_IRCR3 0x00 /* Infrared Control 3 */
+#define WBCIR_REG_SP3_SIR_PW 0x02 /* SIR Pulse Width */
+ /* Bank 7 */
+#define WBCIR_REG_SP3_IRRXDC 0x00 /* IR RX Demod Control */
+#define WBCIR_REG_SP3_IRTXMC 0x01 /* IR TX Mod Control */
+#define WBCIR_REG_SP3_RCCFG 0x02 /* CEIR Config */
+#define WBCIR_REG_SP3_IRCFG1 0x04 /* Infrared Config 1 */
+#define WBCIR_REG_SP3_IRCFG4 0x07 /* Infrared Config 4 */
+
+/*
+ * Magic values follow
+ */
+
+/* No interrupts for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
+#define WBCIR_IRQ_NONE 0x00
+/* RX data bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
+#define WBCIR_IRQ_RX 0x01
+/* Over/Under-flow bit for WBCIR_REG_SP3_IER and WBCIR_REG_SP3_EIR */
+#define WBCIR_IRQ_ERR 0x04
+/* Led enable/disable bit for WBCIR_REG_ECEIR_CTS */
+#define WBCIR_LED_ENABLE 0x80
+/* RX data available bit for WBCIR_REG_SP3_LSR */
+#define WBCIR_RX_AVAIL 0x01
+/* RX disable bit for WBCIR_REG_SP3_ASCR */
+#define WBCIR_RX_DISABLE 0x20
+/* Extended mode enable bit for WBCIR_REG_SP3_EXCR1 */
+#define WBCIR_EXT_ENABLE 0x01
+/* Select compare register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */
+#define WBCIR_REGSEL_COMPARE 0x10
+/* Select mask register in WBCIR_REG_WCEIR_INDEX (bits 5 & 6) */
+#define WBCIR_REGSEL_MASK 0x20
+/* Starting address of selected register in WBCIR_REG_WCEIR_INDEX */
+#define WBCIR_REG_ADDR0 0x00
+
+/* Valid banks for the SP3 UART */
+enum wbcir_bank {
+ WBCIR_BANK_0 = 0x00,
+ WBCIR_BANK_1 = 0x80,
+ WBCIR_BANK_2 = 0xE0,
+ WBCIR_BANK_3 = 0xE4,
+ WBCIR_BANK_4 = 0xE8,
+ WBCIR_BANK_5 = 0xEC,
+ WBCIR_BANK_6 = 0xF0,
+ WBCIR_BANK_7 = 0xF4,
+};
+
+/* Supported power-on IR Protocols */
+enum wbcir_protocol {
+ IR_PROTOCOL_RC5 = 0x0,
+ IR_PROTOCOL_NEC = 0x1,
+ IR_PROTOCOL_RC6 = 0x2,
+};
+
+/* Misc */
+#define WBCIR_NAME "Winbond CIR"
+#define WBCIR_ID_FAMILY 0xF1 /* Family ID for the WPCD376I */
+#define WBCIR_ID_CHIP 0x04 /* Chip ID for the WPCD376I */
+#define INVALID_SCANCODE 0x7FFFFFFF /* Invalid with all protos */
+#define WAKEUP_IOMEM_LEN 0x10 /* Wake-Up I/O Reg Len */
+#define EHFUNC_IOMEM_LEN 0x10 /* Enhanced Func I/O Reg Len */
+#define SP_IOMEM_LEN 0x08 /* Serial Port 3 (IR) Reg Len */
+
+/* Per-device data */
+struct wbcir_data {
+ spinlock_t spinlock;
+
+ unsigned long wbase; /* Wake-Up Baseaddr */
+ unsigned long ebase; /* Enhanced Func. Baseaddr */
+ unsigned long sbase; /* Serial Port Baseaddr */
+ unsigned int irq; /* Serial Port IRQ */
+
+ struct rc_dev *dev;
+
+ struct led_trigger *rxtrigger;
+ struct led_trigger *txtrigger;
+ struct led_classdev led;
+
+ /* RX irdata state */
+ bool irdata_active;
+ bool irdata_error;
+ struct ir_raw_event ev;
+};
+
+static enum wbcir_protocol protocol = IR_PROTOCOL_RC6;
+module_param(protocol, uint, 0444);
+MODULE_PARM_DESC(protocol, "IR protocol to use for the power-on command "
+ "(0 = RC5, 1 = NEC, 2 = RC6A, default)");
+
+static int invert; /* default = 0 */
+module_param(invert, bool, 0444);
+MODULE_PARM_DESC(invert, "Invert the signal from the IR receiver");
+
+static unsigned int wake_sc = 0x800F040C;
+module_param(wake_sc, uint, 0644);
+MODULE_PARM_DESC(wake_sc, "Scancode of the power-on IR command");
+
+static unsigned int wake_rc6mode = 6;
+module_param(wake_rc6mode, uint, 0644);
+MODULE_PARM_DESC(wake_rc6mode, "RC6 mode for the power-on command "
+ "(0 = 0, 6 = 6A, default)");
+
+
+
+/*****************************************************************************
+ *
+ * UTILITY FUNCTIONS
+ *
+ *****************************************************************************/
+
+/* Caller needs to hold wbcir_lock */
+static void
+wbcir_set_bits(unsigned long addr, u8 bits, u8 mask)
+{
+ u8 val;
+
+ val = inb(addr);
+ val = ((val & ~mask) | (bits & mask));
+ outb(val, addr);
+}
+
+/* Selects the register bank for the serial port */
+static inline void
+wbcir_select_bank(struct wbcir_data *data, enum wbcir_bank bank)
+{
+ outb(bank, data->sbase + WBCIR_REG_SP3_BSR);
+}
+
+static enum led_brightness
+wbcir_led_brightness_get(struct led_classdev *led_cdev)
+{
+ struct wbcir_data *data = container_of(led_cdev,
+ struct wbcir_data,
+ led);
+
+ if (inb(data->ebase + WBCIR_REG_ECEIR_CTS) & WBCIR_LED_ENABLE)
+ return LED_FULL;
+ else
+ return LED_OFF;
+}
+
+static void
+wbcir_led_brightness_set(struct led_classdev *led_cdev,
+ enum led_brightness brightness)
+{
+ struct wbcir_data *data = container_of(led_cdev,
+ struct wbcir_data,
+ led);
+
+ wbcir_set_bits(data->ebase + WBCIR_REG_ECEIR_CTS,
+ brightness == LED_OFF ? 0x00 : WBCIR_LED_ENABLE,
+ WBCIR_LED_ENABLE);
+}
+
+/* Manchester encodes bits to RC6 message cells (see wbcir_shutdown) */
+static u8
+wbcir_to_rc6cells(u8 val)
+{
+ u8 coded = 0x00;
+ int i;
+
+ val &= 0x0F;
+ for (i = 0; i < 4; i++) {
+ if (val & 0x01)
+ coded |= 0x02 << (i * 2);
+ else
+ coded |= 0x01 << (i * 2);
+ val >>= 1;
+ }
+
+ return coded;
+}
+
+/*****************************************************************************
+ *
+ * INTERRUPT FUNCTIONS
+ *
+ *****************************************************************************/
+
+static irqreturn_t
+wbcir_irq_handler(int irqno, void *cookie)
+{
+ struct pnp_dev *device = cookie;
+ struct wbcir_data *data = pnp_get_drvdata(device);
+ unsigned long flags;
+ u8 irdata[8];
+ u8 disable = true;
+ u8 status;
+ int i;
+
+ spin_lock_irqsave(&data->spinlock, flags);
+
+ wbcir_select_bank(data, WBCIR_BANK_0);
+
+ status = inb(data->sbase + WBCIR_REG_SP3_EIR);
+
+ if (!(status & (WBCIR_IRQ_RX | WBCIR_IRQ_ERR))) {
+ spin_unlock_irqrestore(&data->spinlock, flags);
+ return IRQ_NONE;
+ }
+
+ /* Check for e.g. buffer overflow */
+ if (status & WBCIR_IRQ_ERR) {
+ data->irdata_error = true;
+ ir_raw_event_reset(data->dev);
+ }
+
+ if (!(status & WBCIR_IRQ_RX))
+ goto out;
+
+ if (!data->irdata_active) {
+ data->irdata_active = true;
+ led_trigger_event(data->rxtrigger, LED_FULL);
+ }
+
+ /* Since RXHDLEV is set, at least 8 bytes are in the FIFO */
+ insb(data->sbase + WBCIR_REG_SP3_RXDATA, &irdata[0], 8);
+
+ for (i = 0; i < 8; i++) {
+ u8 pulse;
+ u32 duration;
+
+ if (irdata[i] != 0xFF && irdata[i] != 0x00)
+ disable = false;
+
+ if (data->irdata_error)
+ continue;
+
+ pulse = irdata[i] & 0x80 ? false : true;
+ duration = (irdata[i] & 0x7F) * 10000; /* ns */
+
+ if (data->ev.pulse != pulse) {
+ if (data->ev.duration != 0) {
+ ir_raw_event_store(data->dev, &data->ev);
+ data->ev.duration = 0;
+ }
+
+ data->ev.pulse = pulse;
+ }
+
+ data->ev.duration += duration;
+ }
+
+ if (disable) {
+ if (data->ev.duration != 0 && !data->irdata_error) {
+ ir_raw_event_store(data->dev, &data->ev);
+ data->ev.duration = 0;
+ }
+
+ /* Set RXINACTIVE */
+ outb(WBCIR_RX_DISABLE, data->sbase + WBCIR_REG_SP3_ASCR);
+
+ /* Drain the FIFO */
+ while (inb(data->sbase + WBCIR_REG_SP3_LSR) & WBCIR_RX_AVAIL)
+ inb(data->sbase + WBCIR_REG_SP3_RXDATA);
+
+ ir_raw_event_reset(data->dev);
+ data->irdata_error = false;
+ data->irdata_active = false;
+ led_trigger_event(data->rxtrigger, LED_OFF);
+ }
+
+ ir_raw_event_handle(data->dev);
+
+out:
+ spin_unlock_irqrestore(&data->spinlock, flags);
+ return IRQ_HANDLED;
+}
+
+
+
+/*****************************************************************************
+ *
+ * SETUP/INIT/SUSPEND/RESUME FUNCTIONS
+ *
+ *****************************************************************************/
+
+static void
+wbcir_shutdown(struct pnp_dev *device)
+{
+ struct device *dev = &device->dev;
+ struct wbcir_data *data = pnp_get_drvdata(device);
+ int do_wake = 1;
+ u8 match[11];
+ u8 mask[11];
+ u8 rc6_csl = 0;
+ int i;
+
+ memset(match, 0, sizeof(match));
+ memset(mask, 0, sizeof(mask));
+
+ if (wake_sc == INVALID_SCANCODE || !device_may_wakeup(dev)) {
+ do_wake = 0;
+ goto finish;
+ }
+
+ switch (protocol) {
+ case IR_PROTOCOL_RC5:
+ if (wake_sc > 0xFFF) {
+ do_wake = 0;
+ dev_err(dev, "RC5 - Invalid wake scancode\n");
+ break;
+ }
+
+ /* Mask = 13 bits, ex toggle */
+ mask[0] = 0xFF;
+ mask[1] = 0x17;
+
+ match[0] = (wake_sc & 0x003F); /* 6 command bits */
+ match[0] |= (wake_sc & 0x0180) >> 1; /* 2 address bits */
+ match[1] = (wake_sc & 0x0E00) >> 9; /* 3 address bits */
+ if (!(wake_sc & 0x0040)) /* 2nd start bit */
+ match[1] |= 0x10;
+
+ break;
+
+ case IR_PROTOCOL_NEC:
+ if (wake_sc > 0xFFFFFF) {
+ do_wake = 0;
+ dev_err(dev, "NEC - Invalid wake scancode\n");
+ break;
+ }
+
+ mask[0] = mask[1] = mask[2] = mask[3] = 0xFF;
+
+ match[1] = bitrev8((wake_sc & 0xFF));
+ match[0] = ~match[1];
+
+ match[3] = bitrev8((wake_sc & 0xFF00) >> 8);
+ if (wake_sc > 0xFFFF)
+ match[2] = bitrev8((wake_sc & 0xFF0000) >> 16);
+ else
+ match[2] = ~match[3];
+
+ break;
+
+ case IR_PROTOCOL_RC6:
+
+ if (wake_rc6mode == 0) {
+ if (wake_sc > 0xFFFF) {
+ do_wake = 0;
+ dev_err(dev, "RC6 - Invalid wake scancode\n");
+ break;
+ }
+
+ /* Command */
+ match[0] = wbcir_to_rc6cells(wake_sc >> 0);
+ mask[0] = 0xFF;
+ match[1] = wbcir_to_rc6cells(wake_sc >> 4);
+ mask[1] = 0xFF;
+
+ /* Address */
+ match[2] = wbcir_to_rc6cells(wake_sc >> 8);
+ mask[2] = 0xFF;
+ match[3] = wbcir_to_rc6cells(wake_sc >> 12);
+ mask[3] = 0xFF;
+
+ /* Header */
+ match[4] = 0x50; /* mode1 = mode0 = 0, ignore toggle */
+ mask[4] = 0xF0;
+ match[5] = 0x09; /* start bit = 1, mode2 = 0 */
+ mask[5] = 0x0F;
+
+ rc6_csl = 44;
+
+ } else if (wake_rc6mode == 6) {
+ i = 0;
+
+ /* Command */
+ match[i] = wbcir_to_rc6cells(wake_sc >> 0);
+ mask[i++] = 0xFF;
+ match[i] = wbcir_to_rc6cells(wake_sc >> 4);
+ mask[i++] = 0xFF;
+
+ /* Address + Toggle */
+ match[i] = wbcir_to_rc6cells(wake_sc >> 8);
+ mask[i++] = 0xFF;
+ match[i] = wbcir_to_rc6cells(wake_sc >> 12);
+ mask[i++] = 0x3F;
+
+ /* Customer bits 7 - 0 */
+ match[i] = wbcir_to_rc6cells(wake_sc >> 16);
+ mask[i++] = 0xFF;
+ match[i] = wbcir_to_rc6cells(wake_sc >> 20);
+ mask[i++] = 0xFF;
+
+ if (wake_sc & 0x80000000) {
+ /* Customer range bit and bits 15 - 8 */
+ match[i] = wbcir_to_rc6cells(wake_sc >> 24);
+ mask[i++] = 0xFF;
+ match[i] = wbcir_to_rc6cells(wake_sc >> 28);
+ mask[i++] = 0xFF;
+ rc6_csl = 76;
+ } else if (wake_sc <= 0x007FFFFF) {
+ rc6_csl = 60;
+ } else {
+ do_wake = 0;
+ dev_err(dev, "RC6 - Invalid wake scancode\n");
+ break;
+ }
+
+ /* Header */
+ match[i] = 0x93; /* mode1 = mode0 = 1, submode = 0 */
+ mask[i++] = 0xFF;
+ match[i] = 0x0A; /* start bit = 1, mode2 = 1 */
+ mask[i++] = 0x0F;
+
+ } else {
+ do_wake = 0;
+ dev_err(dev, "RC6 - Invalid wake mode\n");
+ }
+
+ break;
+
+ default:
+ do_wake = 0;
+ break;
+ }
+
+finish:
+ if (do_wake) {
+ /* Set compare and compare mask */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX,
+ WBCIR_REGSEL_COMPARE | WBCIR_REG_ADDR0,
+ 0x3F);
+ outsb(data->wbase + WBCIR_REG_WCEIR_DATA, match, 11);
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_INDEX,
+ WBCIR_REGSEL_MASK | WBCIR_REG_ADDR0,
+ 0x3F);
+ outsb(data->wbase + WBCIR_REG_WCEIR_DATA, mask, 11);
+
+ /* RC6 Compare String Len */
+ outb(rc6_csl, data->wbase + WBCIR_REG_WCEIR_CSL);
+
+ /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17);
+
+ /* Clear BUFF_EN, Clear END_EN, Set MATCH_EN */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x01, 0x07);
+
+ /* Set CEIR_EN */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x01, 0x01);
+
+ } else {
+ /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
+
+ /* Clear CEIR_EN */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
+ }
+
+ /* Disable interrupts */
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
+ /* Disable LED */
+ data->irdata_active = false;
+ led_trigger_event(data->rxtrigger, LED_OFF);
+
+ /*
+ * ACPI will set the HW disable bit for SP3 which means that the
+ * output signals are left in an undefined state which may cause
+ * spurious interrupts which we need to ignore until the hardware
+ * is reinitialized.
+ */
+ disable_irq(data->irq);
+}
+
+static int
+wbcir_suspend(struct pnp_dev *device, pm_message_t state)
+{
+ wbcir_shutdown(device);
+ return 0;
+}
+
+static void
+wbcir_init_hw(struct wbcir_data *data)
+{
+ u8 tmp;
+
+ /* Disable interrupts */
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
+ /* Set PROT_SEL, RX_INV, Clear CEIR_EN (needed for the led) */
+ tmp = protocol << 4;
+ if (invert)
+ tmp |= 0x08;
+ outb(tmp, data->wbase + WBCIR_REG_WCEIR_CTL);
+
+ /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17);
+
+ /* Clear BUFF_EN, Clear END_EN, Clear MATCH_EN */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
+
+ /* Set RC5 cell time to correspond to 36 kHz */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CFG1, 0x4A, 0x7F);
+
+ /* Set IRTX_INV */
+ if (invert)
+ outb(0x04, data->ebase + WBCIR_REG_ECEIR_CCTL);
+ else
+ outb(0x00, data->ebase + WBCIR_REG_ECEIR_CCTL);
+
+ /*
+ * Clear IR LED, set SP3 clock to 24Mhz
+ * set SP3_IRRX_SW to binary 01, helpfully not documented
+ */
+ outb(0x10, data->ebase + WBCIR_REG_ECEIR_CTS);
+
+ /* Enable extended mode */
+ wbcir_select_bank(data, WBCIR_BANK_2);
+ outb(WBCIR_EXT_ENABLE, data->sbase + WBCIR_REG_SP3_EXCR1);
+
+ /*
+ * Configure baud generator, IR data will be sampled at
+ * a bitrate of: (24Mhz * prescaler) / (divisor * 16).
+ *
+ * The ECIR registers include a flag to change the
+ * 24Mhz clock freq to 48Mhz.
+ *
+ * It's not documented in the specs, but fifo levels
+ * other than 16 seems to be unsupported.
+ */
+
+ /* prescaler 1.0, tx/rx fifo lvl 16 */
+ outb(0x30, data->sbase + WBCIR_REG_SP3_EXCR2);
+
+ /* Set baud divisor to generate one byte per bit/cell */
+ switch (protocol) {
+ case IR_PROTOCOL_RC5:
+ outb(0xA7, data->sbase + WBCIR_REG_SP3_BGDL);
+ break;
+ case IR_PROTOCOL_RC6:
+ outb(0x53, data->sbase + WBCIR_REG_SP3_BGDL);
+ break;
+ case IR_PROTOCOL_NEC:
+ outb(0x69, data->sbase + WBCIR_REG_SP3_BGDL);
+ break;
+ }
+ outb(0x00, data->sbase + WBCIR_REG_SP3_BGDH);
+
+ /* Set CEIR mode */
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(0xC0, data->sbase + WBCIR_REG_SP3_MCR);
+ inb(data->sbase + WBCIR_REG_SP3_LSR); /* Clear LSR */
+ inb(data->sbase + WBCIR_REG_SP3_MSR); /* Clear MSR */
+
+ /* Disable RX demod, run-length encoding/decoding, set freq span */
+ wbcir_select_bank(data, WBCIR_BANK_7);
+ outb(0x10, data->sbase + WBCIR_REG_SP3_RCCFG);
+
+ /* Disable timer */
+ wbcir_select_bank(data, WBCIR_BANK_4);
+ outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR1);
+
+ /* Enable MSR interrupt, Clear AUX_IRX */
+ wbcir_select_bank(data, WBCIR_BANK_5);
+ outb(0x00, data->sbase + WBCIR_REG_SP3_IRCR2);
+
+ /* Disable CRC */
+ wbcir_select_bank(data, WBCIR_BANK_6);
+ outb(0x20, data->sbase + WBCIR_REG_SP3_IRCR3);
+
+ /* Set RX/TX (de)modulation freq, not really used */
+ wbcir_select_bank(data, WBCIR_BANK_7);
+ outb(0xF2, data->sbase + WBCIR_REG_SP3_IRRXDC);
+ outb(0x69, data->sbase + WBCIR_REG_SP3_IRTXMC);
+
+ /* Set invert and pin direction */
+ if (invert)
+ outb(0x10, data->sbase + WBCIR_REG_SP3_IRCFG4);
+ else
+ outb(0x00, data->sbase + WBCIR_REG_SP3_IRCFG4);
+
+ /* Set FIFO thresholds (RX = 8, TX = 3), reset RX/TX */
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(0x97, data->sbase + WBCIR_REG_SP3_FCR);
+
+ /* Clear AUX status bits */
+ outb(0xE0, data->sbase + WBCIR_REG_SP3_ASCR);
+
+ /* Clear IR decoding state */
+ data->irdata_active = false;
+ led_trigger_event(data->rxtrigger, LED_OFF);
+ data->irdata_error = false;
+ data->ev.duration = 0;
+ ir_raw_event_reset(data->dev);
+ ir_raw_event_handle(data->dev);
+
+ /* Enable interrupts */
+ outb(WBCIR_IRQ_RX | WBCIR_IRQ_ERR, data->sbase + WBCIR_REG_SP3_IER);
+}
+
+static int
+wbcir_resume(struct pnp_dev *device)
+{
+ struct wbcir_data *data = pnp_get_drvdata(device);
+
+ wbcir_init_hw(data);
+ enable_irq(data->irq);
+
+ return 0;
+}
+
+static int __devinit
+wbcir_probe(struct pnp_dev *device, const struct pnp_device_id *dev_id)
+{
+ struct device *dev = &device->dev;
+ struct wbcir_data *data;
+ int err;
+
+ if (!(pnp_port_len(device, 0) == EHFUNC_IOMEM_LEN &&
+ pnp_port_len(device, 1) == WAKEUP_IOMEM_LEN &&
+ pnp_port_len(device, 2) == SP_IOMEM_LEN)) {
+ dev_err(dev, "Invalid resources\n");
+ return -ENODEV;
+ }
+
+ data = kzalloc(sizeof(*data), GFP_KERNEL);
+ if (!data) {
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pnp_set_drvdata(device, data);
+
+ spin_lock_init(&data->spinlock);
+ data->ebase = pnp_port_start(device, 0);
+ data->wbase = pnp_port_start(device, 1);
+ data->sbase = pnp_port_start(device, 2);
+ data->irq = pnp_irq(device, 0);
+
+ if (data->wbase == 0 || data->ebase == 0 ||
+ data->sbase == 0 || data->irq == 0) {
+ err = -ENODEV;
+ dev_err(dev, "Invalid resources\n");
+ goto exit_free_data;
+ }
+
+ dev_dbg(&device->dev, "Found device "
+ "(w: 0x%lX, e: 0x%lX, s: 0x%lX, i: %u)\n",
+ data->wbase, data->ebase, data->sbase, data->irq);
+
+ if (!request_region(data->wbase, WAKEUP_IOMEM_LEN, DRVNAME)) {
+ dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
+ data->wbase, data->wbase + WAKEUP_IOMEM_LEN - 1);
+ err = -EBUSY;
+ goto exit_free_data;
+ }
+
+ if (!request_region(data->ebase, EHFUNC_IOMEM_LEN, DRVNAME)) {
+ dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
+ data->ebase, data->ebase + EHFUNC_IOMEM_LEN - 1);
+ err = -EBUSY;
+ goto exit_release_wbase;
+ }
+
+ if (!request_region(data->sbase, SP_IOMEM_LEN, DRVNAME)) {
+ dev_err(dev, "Region 0x%lx-0x%lx already in use!\n",
+ data->sbase, data->sbase + SP_IOMEM_LEN - 1);
+ err = -EBUSY;
+ goto exit_release_ebase;
+ }
+
+ err = request_irq(data->irq, wbcir_irq_handler,
+ IRQF_DISABLED, DRVNAME, device);
+ if (err) {
+ dev_err(dev, "Failed to claim IRQ %u\n", data->irq);
+ err = -EBUSY;
+ goto exit_release_sbase;
+ }
+
+ led_trigger_register_simple("cir-tx", &data->txtrigger);
+ if (!data->txtrigger) {
+ err = -ENOMEM;
+ goto exit_free_irq;
+ }
+
+ led_trigger_register_simple("cir-rx", &data->rxtrigger);
+ if (!data->rxtrigger) {
+ err = -ENOMEM;
+ goto exit_unregister_txtrigger;
+ }
+
+ data->led.name = "cir::activity";
+ data->led.default_trigger = "cir-rx";
+ data->led.brightness_set = wbcir_led_brightness_set;
+ data->led.brightness_get = wbcir_led_brightness_get;
+ err = led_classdev_register(&device->dev, &data->led);
+ if (err)
+ goto exit_unregister_rxtrigger;
+
+ data->dev = rc_allocate_device();
+ if (!data->dev) {
+ err = -ENOMEM;
+ goto exit_unregister_led;
+ }
+
+ data->dev->driver_name = WBCIR_NAME;
+ data->dev->input_name = WBCIR_NAME;
+ data->dev->input_phys = "wbcir/cir0";
+ data->dev->input_id.bustype = BUS_HOST;
+ data->dev->input_id.vendor = PCI_VENDOR_ID_WINBOND;
+ data->dev->input_id.product = WBCIR_ID_FAMILY;
+ data->dev->input_id.version = WBCIR_ID_CHIP;
+ data->dev->priv = data;
+ data->dev->dev.parent = &device->dev;
+
+ err = rc_register_device(data->dev);
+ if (err)
+ goto exit_free_rc;
+
+ device_init_wakeup(&device->dev, 1);
+
+ wbcir_init_hw(data);
+
+ return 0;
+
+exit_free_rc:
+ rc_free_device(data->dev);
+exit_unregister_led:
+ led_classdev_unregister(&data->led);
+exit_unregister_rxtrigger:
+ led_trigger_unregister_simple(data->rxtrigger);
+exit_unregister_txtrigger:
+ led_trigger_unregister_simple(data->txtrigger);
+exit_free_irq:
+ free_irq(data->irq, device);
+exit_release_sbase:
+ release_region(data->sbase, SP_IOMEM_LEN);
+exit_release_ebase:
+ release_region(data->ebase, EHFUNC_IOMEM_LEN);
+exit_release_wbase:
+ release_region(data->wbase, WAKEUP_IOMEM_LEN);
+exit_free_data:
+ kfree(data);
+ pnp_set_drvdata(device, NULL);
+exit:
+ return err;
+}
+
+static void __devexit
+wbcir_remove(struct pnp_dev *device)
+{
+ struct wbcir_data *data = pnp_get_drvdata(device);
+
+ /* Disable interrupts */
+ wbcir_select_bank(data, WBCIR_BANK_0);
+ outb(WBCIR_IRQ_NONE, data->sbase + WBCIR_REG_SP3_IER);
+
+ free_irq(data->irq, device);
+
+ /* Clear status bits NEC_REP, BUFF, MSG_END, MATCH */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_STS, 0x17, 0x17);
+
+ /* Clear CEIR_EN */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_CTL, 0x00, 0x01);
+
+ /* Clear BUFF_EN, END_EN, MATCH_EN */
+ wbcir_set_bits(data->wbase + WBCIR_REG_WCEIR_EV_EN, 0x00, 0x07);
+
+ rc_unregister_device(data->dev);
+
+ led_trigger_unregister_simple(data->rxtrigger);
+ led_trigger_unregister_simple(data->txtrigger);
+ led_classdev_unregister(&data->led);
+
+ /* This is ok since &data->led isn't actually used */
+ wbcir_led_brightness_set(&data->led, LED_OFF);
+
+ release_region(data->wbase, WAKEUP_IOMEM_LEN);
+ release_region(data->ebase, EHFUNC_IOMEM_LEN);
+ release_region(data->sbase, SP_IOMEM_LEN);
+
+ kfree(data);
+
+ pnp_set_drvdata(device, NULL);
+}
+
+static const struct pnp_device_id wbcir_ids[] = {
+ { "WEC1022", 0 },
+ { "", 0 }
+};
+MODULE_DEVICE_TABLE(pnp, wbcir_ids);
+
+static struct pnp_driver wbcir_driver = {
+ .name = WBCIR_NAME,
+ .id_table = wbcir_ids,
+ .probe = wbcir_probe,
+ .remove = __devexit_p(wbcir_remove),
+ .suspend = wbcir_suspend,
+ .resume = wbcir_resume,
+ .shutdown = wbcir_shutdown
+};
+
+static int __init
+wbcir_init(void)
+{
+ int ret;
+
+ switch (protocol) {
+ case IR_PROTOCOL_RC5:
+ case IR_PROTOCOL_NEC:
+ case IR_PROTOCOL_RC6:
+ break;
+ default:
+ printk(KERN_ERR DRVNAME ": Invalid power-on protocol\n");
+ }
+
+ ret = pnp_register_driver(&wbcir_driver);
+ if (ret)
+ printk(KERN_ERR DRVNAME ": Unable to register driver\n");
+
+ return ret;
+}
+
+static void __exit
+wbcir_exit(void)
+{
+ pnp_unregister_driver(&wbcir_driver);
+}
+
+module_init(wbcir_init);
+module_exit(wbcir_exit);
+
+MODULE_AUTHOR("David Härdeman <david@hardeman.nu>");
+MODULE_DESCRIPTION("Winbond SuperI/O Consumer IR Driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index ad9e6f9c22e9..aa021600e9df 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -7,11 +7,6 @@ config VIDEO_V4L2
depends on VIDEO_DEV && VIDEO_V4L2_COMMON
default VIDEO_DEV && VIDEO_V4L2_COMMON
-config VIDEO_V4L1
- tristate
- depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
- default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
-
config VIDEOBUF_GEN
tristate
@@ -83,7 +78,7 @@ config VIDEO_FIXED_MINOR_RANGES
config VIDEO_HELPER_CHIPS_AUTO
bool "Autoselect pertinent encoders/decoders and other helper chips"
- default y
+ default y if !EXPERT
---help---
Most video cards may require additional modules to encode or
decode audio/video standards. This option will autoselect
@@ -96,7 +91,7 @@ config VIDEO_HELPER_CHIPS_AUTO
config VIDEO_IR_I2C
tristate "I2C module for IR" if !VIDEO_HELPER_CHIPS_AUTO
- depends on I2C && VIDEO_IR
+ depends on I2C && RC_CORE
default y
---help---
Most boards have an IR chip directly connected via GPIO. However,
@@ -112,7 +107,7 @@ config VIDEO_IR_I2C
#
menu "Encoders/decoders and other helper chips"
- depends on !VIDEO_HELPER_CHIPS_AUTO
+ visible if !VIDEO_HELPER_CHIPS_AUTO
comment "Audio decoders"
@@ -146,15 +141,6 @@ config VIDEO_TDA9840
To compile this driver as a module, choose M here: the
module will be called tda9840.
-config VIDEO_TDA9875
- tristate "Philips TDA9875 audio processor"
- depends on VIDEO_V4L2 && I2C
- ---help---
- Support for tda9875 audio decoder chip found on some bt8xx boards.
-
- To compile this driver as a module, choose M here: the
- module will be called tda9875.
-
config VIDEO_TEA6415C
tristate "Philips TEA6415C audio processor"
depends on I2C
@@ -517,19 +503,6 @@ config VIDEO_UPD64083
endmenu # encoder / decoder chips
-config DISPLAY_DAVINCI_DM646X_EVM
- tristate "DM646x EVM Video Display"
- depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
- select VIDEOBUF_DMA_CONTIG
- select VIDEO_DAVINCI_VPIF
- select VIDEO_ADV7343
- select VIDEO_THS7303
- help
- Support for DM6467 based display device.
-
- To compile this driver as a module, choose M here: the
- module will be called vpif_display.
-
config VIDEO_SH_VOU
tristate "SuperH VOU video output driver"
depends on VIDEO_DEV && ARCH_SHMOBILE
@@ -537,29 +510,22 @@ config VIDEO_SH_VOU
help
Support for the Video Output Unit (VOU) on SuperH SoCs.
-config CAPTURE_DAVINCI_DM646X_EVM
- tristate "DM646x EVM Video Capture"
- depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+config VIDEO_VIU
+ tristate "Freescale VIU Video Driver"
+ depends on VIDEO_V4L2 && PPC_MPC512x
select VIDEOBUF_DMA_CONTIG
- select VIDEO_DAVINCI_VPIF
- help
- Support for DM6467 based capture device.
-
- To compile this driver as a module, choose M here: the
- module will be called vpif_capture.
-
-config VIDEO_DAVINCI_VPIF
- tristate "DaVinci VPIF Driver"
- depends on DISPLAY_DAVINCI_DM646X_EVM
- help
- Support for DaVinci VPIF Driver.
+ default y
+ ---help---
+ Support for Freescale VIU video driver. This device captures
+ video data, or overlays video on DIU frame buffer.
- To compile this driver as a module, choose M here: the
- module will be called vpif.
+ Say Y here if you want to enable VIU device on MPC5121e Rev2+.
+ In doubt, say N.
config VIDEO_VIVI
tristate "Virtual Video Driver"
- depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64 && FONTS
+ depends on VIDEO_DEV && VIDEO_V4L2 && !SPARC32 && !SPARC64
+ depends on FRAMEBUFFER_CONSOLE || STI_CONSOLE
select FONT_8x16
select VIDEOBUF_VMALLOC
default n
@@ -570,66 +536,7 @@ config VIDEO_VIVI
Say Y here if you want to test video apps or debug V4L devices.
In doubt, say N.
-config VIDEO_VPSS_SYSTEM
- tristate "VPSS System module driver"
- depends on ARCH_DAVINCI
- help
- Support for vpss system module for video driver
-
-config VIDEO_VPFE_CAPTURE
- tristate "VPFE Video Capture Driver"
- depends on VIDEO_V4L2 && ARCH_DAVINCI
- select VIDEOBUF_DMA_CONTIG
- help
- Support for DMXXXX VPFE based frame grabber. This is the
- common V4L2 module for following DMXXX SoCs from Texas
- Instruments:- DM6446 & DM355.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe-capture.
-
-config VIDEO_DM6446_CCDC
- tristate "DM6446 CCDC HW module"
- depends on ARCH_DAVINCI_DM644x && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
- with decoder modules such as TVP5146 over BT656 or
- sensor module such as MT9T001 over a raw interface. This
- module configures the interface and CCDC/ISIF to do
- video frame capture from slave decoders.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
-
-config VIDEO_DM355_CCDC
- tristate "DM355 CCDC HW module"
- depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables DM355 CCD hw module. DM355 CCDC hw interfaces
- with decoder modules such as TVP5146 over BT656 or
- sensor module such as MT9T001 over a raw interface. This
- module configures the interface and CCDC/ISIF to do
- video frame capture from a slave decoders
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
-
-config VIDEO_ISIF
- tristate "ISIF HW module"
- depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
- select VIDEO_VPSS_SYSTEM
- default y
- help
- Enables ISIF hw module. This is the hardware module for
- configuring ISIF in VPFE to capture Raw Bayer RGB data from
- a image sensor or YUV data from a YUV source.
-
- To compile this driver as a module, choose M here: the
- module will be called vpfe.
+source "drivers/media/video/davinci/Kconfig"
source "drivers/media/video/omap/Kconfig"
@@ -646,7 +553,7 @@ config VIDEO_PMS
config VIDEO_BWQCAM
tristate "Quickcam BW Video For Linux"
- depends on PARPORT && VIDEO_V4L1
+ depends on PARPORT && VIDEO_V4L2
help
Say Y have if you the black and white version of the QuickCam
camera. See the next option for the color version.
@@ -656,7 +563,7 @@ config VIDEO_BWQCAM
config VIDEO_CQCAM
tristate "QuickCam Colour Video For Linux (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PARPORT && VIDEO_V4L1
+ depends on EXPERIMENTAL && PARPORT && VIDEO_V4L2
help
This is the video4linux driver for the colour version of the
Connectix QuickCam. If you have one of these cameras, say Y here,
@@ -678,68 +585,8 @@ config VIDEO_W9966
Check out <file:Documentation/video4linux/w9966.txt> for more
information.
-config VIDEO_CPIA
- tristate "CPiA Video For Linux (DEPRECATED)"
- depends on VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca cpia1 module
- instead. Note that you need atleast version 0.6.4 of libv4l for
- the cpia1 gspca module.
-
- This is the video4linux driver for cameras based on Vision's CPiA
- (Colour Processor Interface ASIC), such as the Creative Labs Video
- Blaster Webcam II. If you have one of these cameras, say Y here
- and select parallel port and/or USB lowlevel support below,
- otherwise say N. This will not work with the Creative Webcam III.
-
- Please read <file:Documentation/video4linux/README.cpia> for more
- information.
-
- This driver is also available as a module (cpia).
-
-config VIDEO_CPIA_PP
- tristate "CPiA Parallel Port Lowlevel Support"
- depends on PARPORT_1284 && VIDEO_CPIA && PARPORT
- help
- This is the lowlevel parallel port support for cameras based on
- Vision's CPiA (Colour Processor Interface ASIC), such as the
- Creative Webcam II. If you have the parallel port version of one
- of these cameras, say Y here, otherwise say N. It is also available
- as a module (cpia_pp).
-
-config VIDEO_CPIA_USB
- tristate "CPiA USB Lowlevel Support"
- depends on VIDEO_CPIA && USB
- help
- This is the lowlevel USB support for cameras based on Vision's CPiA
- (Colour Processor Interface ASIC), such as the Creative Webcam II.
- If you have the USB version of one of these cameras, say Y here,
- otherwise say N. This will not work with the Creative Webcam III.
- It is also available as a module (cpia_usb).
-
source "drivers/media/video/cpia2/Kconfig"
-config VIDEO_SAA5246A
- tristate "SAA5246A, SAA5281 Teletext processor"
- depends on I2C && VIDEO_V4L2
- help
- Support for I2C bus based teletext using the SAA5246A or SAA5281
- chip. Useful only if you live in Europe.
-
- To compile this driver as a module, choose M here: the
- module will be called saa5246a.
-
-config VIDEO_SAA5249
- tristate "SAA5249 Teletext processor"
- depends on I2C && VIDEO_V4L2
- help
- Support for I2C bus based teletext using the SAA5249 chip. At the
- moment this is only useful on some European WinTV cards.
-
- To compile this driver as a module, choose M here: the
- module will be called saa5249.
-
config VIDEO_VINO
tristate "SGI Vino Video For Linux (EXPERIMENTAL)"
depends on I2C && SGI_IP22 && EXPERIMENTAL && VIDEO_V4L2
@@ -748,14 +595,6 @@ config VIDEO_VINO
Say Y here to build in support for the Vino video input system found
on SGI Indy machines.
-config VIDEO_STRADIS
- tristate "Stradis 4:2:2 MPEG-2 video driver (EXPERIMENTAL)"
- depends on EXPERIMENTAL && PCI && VIDEO_V4L1 && VIRT_TO_BUS
- help
- Say Y here to enable support for the Stradis 4:2:2 MPEG-2 video
- driver for PCI. There is a product page at
- <http://www.stradis.com/>.
-
source "drivers/media/video/zoran/Kconfig"
config VIDEO_MEYE
@@ -813,6 +652,16 @@ config VIDEO_HEXIUM_GEMINI
To compile this driver as a module, choose M here: the
module will be called hexium_gemini.
+config VIDEO_TIMBERDALE
+ tristate "Support for timberdale Video In/LogiWIN"
+ depends on VIDEO_V4L2 && I2C
+ select DMA_ENGINE
+ select TIMB_DMA
+ select VIDEO_ADV7180
+ select VIDEOBUF_DMA_CONTIG
+ ---help---
+ Add support for the Video In peripherial of the timberdale FPGA.
+
source "drivers/media/video/cx88/Kconfig"
source "drivers/media/video/cx23885/Kconfig"
@@ -853,6 +702,22 @@ config VIDEO_CAFE_CCIC
CMOS camera controller. This is the controller found on first-
generation OLPC systems.
+config VIDEO_SR030PC30
+ tristate "SR030PC30 VGA camera sensor support"
+ depends on I2C && VIDEO_V4L2
+ ---help---
+ This driver supports SR030PC30 VGA camera from Siliconfile
+
+config VIDEO_VIA_CAMERA
+ tristate "VIAFB camera controller support"
+ depends on FB_VIA
+ select VIDEOBUF_DMA_SG
+ select VIDEO_OV7670
+ help
+ Driver support for the integrated camera controller in VIA
+ Chrome9 chipsets. Currently only tested on OLPC xo-1.5 systems
+ with ov7670 sensors.
+
config SOC_CAMERA
tristate "SoC camera support"
depends on VIDEO_V4L2 && HAS_DMA && I2C
@@ -862,6 +727,12 @@ config SOC_CAMERA
over a bus like PCI or USB. For example some i2c camera connected
directly to the data bus of an SoC.
+config SOC_CAMERA_IMX074
+ tristate "imx074 support"
+ depends on SOC_CAMERA && I2C
+ help
+ This driver supports IMX074 cameras from Sony
+
config SOC_CAMERA_MT9M001
tristate "mt9m001 support"
depends on SOC_CAMERA && I2C
@@ -871,10 +742,11 @@ config SOC_CAMERA_MT9M001
and colour models.
config SOC_CAMERA_MT9M111
- tristate "mt9m111 and mt9m112 support"
+ tristate "mt9m111, mt9m112 and mt9m131 support"
depends on SOC_CAMERA && I2C
help
- This driver supports MT9M111 and MT9M112 cameras from Micron
+ This driver supports MT9M111, MT9M112 and MT9M131 cameras from
+ Micron/Aptina
config SOC_CAMERA_MT9T031
tristate "mt9t031 support"
@@ -913,6 +785,18 @@ config SOC_CAMERA_PLATFORM
help
This is a generic SoC camera platform driver, useful for testing
+config SOC_CAMERA_OV2640
+ tristate "ov2640 camera support"
+ depends on SOC_CAMERA && I2C
+ help
+ This is a ov2640 camera driver
+
+config SOC_CAMERA_OV6650
+ tristate "ov6650 sensor support"
+ depends on SOC_CAMERA && I2C
+ ---help---
+ This is a V4L2 SoC camera driver for the OmniVision OV6650 sensor
+
config SOC_CAMERA_OV772X
tristate "ov772x camera support"
depends on SOC_CAMERA && I2C
@@ -955,6 +839,12 @@ config VIDEO_PXA27x
---help---
This is a v4l2 driver for the PXA27x Quick Capture Interface
+config VIDEO_SH_MOBILE_CSI2
+ tristate "SuperH Mobile MIPI CSI-2 Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA && HAVE_CLK
+ ---help---
+ This is a v4l2 driver for the SuperH MIPI CSI-2 Interface
+
config VIDEO_SH_MOBILE_CEU
tristate "SuperH Mobile CEU Interface driver"
depends on VIDEO_DEV && SOC_CAMERA && HAS_DMA && HAVE_CLK
@@ -962,6 +852,14 @@ config VIDEO_SH_MOBILE_CEU
---help---
This is a v4l2 driver for the SuperH Mobile CEU Interface
+config VIDEO_OMAP1
+ tristate "OMAP1 Camera Interface driver"
+ depends on VIDEO_DEV && ARCH_OMAP1 && SOC_CAMERA
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEOBUF_DMA_SG
+ ---help---
+ This is a v4l2 driver for the TI OMAP1 camera interface
+
config VIDEO_OMAP2
tristate "OMAP2 Camera Capture Interface driver"
depends on VIDEO_DEV && ARCH_OMAP2
@@ -969,6 +867,19 @@ config VIDEO_OMAP2
---help---
This is a v4l2 driver for the TI OMAP2 camera capture interface
+config VIDEO_MX2_HOSTSUPPORT
+ bool
+
+config VIDEO_MX2
+ tristate "i.MX27/i.MX25 Camera Sensor Interface driver"
+ depends on VIDEO_DEV && SOC_CAMERA && (MACH_MX27 || ARCH_MX25)
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEO_MX2_HOSTSUPPORT
+ ---help---
+ This is a v4l2 driver for the i.MX27 and the i.MX25 Camera Sensor
+ Interface
+
+
#
# USB Multimedia device configuration
#
@@ -996,97 +907,10 @@ source "drivers/media/video/cx231xx/Kconfig"
source "drivers/media/video/usbvision/Kconfig"
-source "drivers/media/video/usbvideo/Kconfig"
-
source "drivers/media/video/et61x251/Kconfig"
-config VIDEO_OVCAMCHIP
- tristate "OmniVision Camera Chip support (DEPRECATED)"
- depends on I2C && VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca ov519 module
- instead. Note that for the ov511 / ov518 support of the gspca module
- you need atleast version 0.6.0 of libv4l and for the w9968cf
- atleast version 0.6.3 of libv4l.
-
- Support for the OmniVision OV6xxx and OV7xxx series of camera chips.
- This driver is intended to be used with the ov511 and w9968cf USB
- camera drivers.
-
- To compile this driver as a module, choose M here: the
- module will be called ovcamchip.
-
-config USB_W9968CF
- tristate "USB W996[87]CF JPEG Dual Mode Camera support (DEPRECATED)"
- depends on VIDEO_V4L1 && I2C && VIDEO_OVCAMCHIP
- default n
- ---help---
- This driver is DEPRECATED please use the gspca ov519 module
- instead. Note that for the w9968cf support of the gspca module
- you need atleast version 0.6.3 of libv4l.
-
- Say Y here if you want support for cameras based on OV681 or
- Winbond W9967CF/W9968CF JPEG USB Dual Mode Camera Chips.
-
- This driver has an optional plugin, which is distributed as a
- separate module only (released under GPL). It allows to use higher
- resolutions and framerates, but cannot be included in the official
- Linux kernel for performance purposes.
-
- See <file:Documentation/video4linux/w9968cf.txt> for more info.
-
- To compile this driver as a module, choose M here: the
- module will be called w9968cf.
-
-config USB_OV511
- tristate "USB OV511 Camera support (DEPRECATED)"
- depends on VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca ov519 module
- instead. Note that for the ov511 / ov518 support of the gspca module
- you need atleast version 0.6.0 of libv4l.
-
- Say Y here if you want to connect this type of camera to your
- computer's USB port. See <file:Documentation/video4linux/ov511.txt>
- for more information and for a list of supported cameras.
-
- To compile this driver as a module, choose M here: the
- module will be called ov511.
-
-config USB_SE401
- tristate "USB SE401 Camera support"
- depends on VIDEO_V4L1
- ---help---
- Say Y here if you want to connect this type of camera to your
- computer's USB port. See <file:Documentation/video4linux/se401.txt>
- for more information and for a list of supported cameras.
-
- To compile this driver as a module, choose M here: the
- module will be called se401.
-
source "drivers/media/video/sn9c102/Kconfig"
-config USB_STV680
- tristate "USB STV680 (Pencam) Camera support (DEPRECATED)"
- depends on VIDEO_V4L1
- default n
- ---help---
- This driver is DEPRECATED please use the gspca stv0680 module
- instead. Note that for the gspca stv0680 module you need
- atleast version 0.6.3 of libv4l.
-
- Say Y here if you want to connect this type of camera to your
- computer's USB port. This includes the Pencam line of cameras.
- See <file:Documentation/video4linux/stv680.txt> for more information
- and for a list of supported cameras.
-
- To compile this driver as a module, choose M here: the
- module will be called stv680.
-
-source "drivers/media/video/zc0301/Kconfig"
-
source "drivers/media/video/pwc/Kconfig"
config USB_ZR364XX
@@ -1111,7 +935,7 @@ config USB_STKWEBCAM
Supported devices are typically found in some Asus laptops,
with USB id 174f:a311 and 05e1:0501. Other Syntek cameras
may be supported by the stk11xx driver, from which this is
- derived, see http://stk11xx.sourceforge.net
+ derived, see <http://sourceforge.net/projects/syntekdriver/>
To compile this driver as a module, choose M here: the
module will be called stkwebcam.
@@ -1150,4 +974,13 @@ config VIDEO_MEM2MEM_TESTDEV
This is a virtual test device for the memory-to-memory driver
framework.
+config VIDEO_SAMSUNG_S5P_FIMC
+ tristate "Samsung S5P FIMC (video postprocessor) driver"
+ depends on VIDEO_DEV && VIDEO_V4L2 && PLAT_S5P
+ select VIDEOBUF_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ help
+ This is a v4l2 driver for the S5P camera interface
+ (video postprocessor)
+
endif # V4L_MEM2MEM_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index cc93859d3164..a509d317e258 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -11,7 +11,7 @@ stkwebcam-objs := stk-webcam.o stk-sensor.o
omap2cam-objs := omap24xxcam.o omap24xxcam-dma.o
videodev-objs := v4l2-dev.o v4l2-ioctl.o v4l2-device.o v4l2-fh.o \
- v4l2-event.o
+ v4l2-event.o v4l2-ctrls.o
# V4L2 core modules
@@ -22,19 +22,12 @@ endif
obj-$(CONFIG_VIDEO_V4L2_COMMON) += v4l2-common.o
-ifeq ($(CONFIG_VIDEO_V4L1_COMPAT),y)
- obj-$(CONFIG_VIDEO_DEV) += v4l1-compat.o
-endif
-
# All i2c modules must come first:
obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_VIDEO_TVAUDIO) += tvaudio.o
obj-$(CONFIG_VIDEO_TDA7432) += tda7432.o
-obj-$(CONFIG_VIDEO_TDA9875) += tda9875.o
obj-$(CONFIG_VIDEO_SAA6588) += saa6588.o
-obj-$(CONFIG_VIDEO_SAA5246A) += saa5246a.o
-obj-$(CONFIG_VIDEO_SAA5249) += saa5249.o
obj-$(CONFIG_VIDEO_TDA9840) += tda9840.o
obj-$(CONFIG_VIDEO_TEA6415C) += tea6415c.o
obj-$(CONFIG_VIDEO_TEA6420) += tea6420.o
@@ -73,12 +66,16 @@ obj-$(CONFIG_VIDEO_OV7670) += ov7670.o
obj-$(CONFIG_VIDEO_TCM825X) += tcm825x.o
obj-$(CONFIG_VIDEO_TVEEPROM) += tveeprom.o
obj-$(CONFIG_VIDEO_MT9V011) += mt9v011.o
+obj-$(CONFIG_VIDEO_SR030PC30) += sr030pc30.o
+obj-$(CONFIG_SOC_CAMERA_IMX074) += imx074.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_MT9T112) += mt9t112.o
obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
+obj-$(CONFIG_SOC_CAMERA_OV2640) += ov2640.o
+obj-$(CONFIG_SOC_CAMERA_OV6650) += ov6650.o
obj-$(CONFIG_SOC_CAMERA_OV772X) += ov772x.o
obj-$(CONFIG_SOC_CAMERA_OV9640) += ov9640.o
obj-$(CONFIG_SOC_CAMERA_RJ54N1) += rj54n1cb0c.o
@@ -93,10 +90,6 @@ obj-$(CONFIG_VIDEO_BWQCAM) += bw-qcam.o
obj-$(CONFIG_VIDEO_W9966) += w9966.o
obj-$(CONFIG_VIDEO_PMS) += pms.o
obj-$(CONFIG_VIDEO_VINO) += vino.o
-obj-$(CONFIG_VIDEO_STRADIS) += stradis.o
-obj-$(CONFIG_VIDEO_CPIA) += cpia.o
-obj-$(CONFIG_VIDEO_CPIA_PP) += cpia_pp.o
-obj-$(CONFIG_VIDEO_CPIA_USB) += cpia_usb.o
obj-$(CONFIG_VIDEO_MEYE) += meye.o
obj-$(CONFIG_VIDEO_SAA7134) += saa7134/
obj-$(CONFIG_VIDEO_CX88) += cx88/
@@ -105,11 +98,11 @@ obj-$(CONFIG_VIDEO_TLG2300) += tlg2300/
obj-$(CONFIG_VIDEO_CX231XX) += cx231xx/
obj-$(CONFIG_VIDEO_USBVISION) += usbvision/
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2/
-obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip/
obj-$(CONFIG_VIDEO_CPIA2) += cpia2/
obj-$(CONFIG_VIDEO_MXB) += mxb.o
obj-$(CONFIG_VIDEO_HEXIUM_ORION) += hexium_orion.o
obj-$(CONFIG_VIDEO_HEXIUM_GEMINI) += hexium_gemini.o
+obj-$(CONFIG_VIDEO_TIMBERDALE) += timblogiw.o
obj-$(CONFIG_VIDEOBUF_GEN) += videobuf-core.o
obj-$(CONFIG_VIDEOBUF_DMA_SG) += videobuf-dma-sg.o
@@ -126,31 +119,24 @@ obj-$(CONFIG_VIDEO_CX2341X) += cx2341x.o
obj-$(CONFIG_VIDEO_CAFE_CCIC) += cafe_ccic.o
-obj-$(CONFIG_USB_DABUSB) += dabusb.o
-obj-$(CONFIG_USB_OV511) += ov511.o
-obj-$(CONFIG_USB_SE401) += se401.o
-obj-$(CONFIG_USB_STV680) += stv680.o
-obj-$(CONFIG_USB_W9968CF) += w9968cf.o
+obj-$(CONFIG_VIDEO_VIA_CAMERA) += via-camera.o
+
obj-$(CONFIG_USB_ZR364XX) += zr364xx.o
obj-$(CONFIG_USB_STKWEBCAM) += stkwebcam.o
obj-$(CONFIG_USB_SN9C102) += sn9c102/
obj-$(CONFIG_USB_ET61X251) += et61x251/
obj-$(CONFIG_USB_PWC) += pwc/
-obj-$(CONFIG_USB_ZC0301) += zc0301/
obj-$(CONFIG_USB_GSPCA) += gspca/
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr/
-obj-$(CONFIG_USB_IBMCAM) += usbvideo/
-obj-$(CONFIG_USB_KONICAWC) += usbvideo/
-obj-$(CONFIG_USB_VICAM) += usbvideo/
-obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += usbvideo/
obj-$(CONFIG_USB_S2255) += s2255drv.o
obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_CX18) += cx18/
+obj-$(CONFIG_VIDEO_VIU) += fsl-viu.o
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_MEM2MEM_TESTDEV) += mem2mem_testdev.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
@@ -162,9 +148,13 @@ obj-$(CONFIG_SOC_CAMERA) += soc_camera.o soc_mediabus.o
obj-$(CONFIG_SOC_CAMERA_PLATFORM) += soc_camera_platform.o
# soc-camera host drivers have to be linked after camera drivers
obj-$(CONFIG_VIDEO_MX1) += mx1_camera.o
+obj-$(CONFIG_VIDEO_MX2) += mx2_camera.o
obj-$(CONFIG_VIDEO_MX3) += mx3_camera.o
obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
+obj-$(CONFIG_VIDEO_SH_MOBILE_CSI2) += sh_mobile_csi2.o
obj-$(CONFIG_VIDEO_SH_MOBILE_CEU) += sh_mobile_ceu_camera.o
+obj-$(CONFIG_VIDEO_OMAP1) += omap1_camera.o
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) += s5p-fimc/
obj-$(CONFIG_ARCH_DAVINCI) += davinci/
@@ -177,7 +167,7 @@ obj-$(CONFIG_VIDEO_SAA7164) += saa7164/
obj-$(CONFIG_VIDEO_IR_I2C) += ir-kbd-i2c.o
-obj-$(CONFIG_ARCH_DAVINCI) += davinci/
+obj-y += davinci/
obj-$(CONFIG_ARCH_OMAP) += omap/
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index 48e89fbf391b..23ba5c37c3e4 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -34,11 +34,9 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("Analog Devices ADV7170 video encoder driver");
MODULE_AUTHOR("Maxim Yevtyushkin");
@@ -337,9 +335,25 @@ static const struct i2c_device_id adv7170_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adv7170_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "adv7170",
- .probe = adv7170_probe,
- .remove = adv7170_remove,
- .id_table = adv7170_id,
+static struct i2c_driver adv7170_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "adv7170",
+ },
+ .probe = adv7170_probe,
+ .remove = adv7170_remove,
+ .id_table = adv7170_id,
};
+
+static __init int init_adv7170(void)
+{
+ return i2c_add_driver(&adv7170_driver);
+}
+
+static __exit void exit_adv7170(void)
+{
+ i2c_del_driver(&adv7170_driver);
+}
+
+module_init(init_adv7170);
+module_exit(exit_adv7170);
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index f1ba0d742c65..d2327dbb473f 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -30,11 +30,9 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("Analog Devices ADV7175 video encoder driver");
MODULE_AUTHOR("Dave Perks");
@@ -305,11 +303,22 @@ static int adv7175_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ide
return v4l2_chip_ident_i2c_client(client, chip, V4L2_IDENT_ADV7175, 0);
}
+static int adv7175_s_power(struct v4l2_subdev *sd, int on)
+{
+ if (on)
+ adv7175_write(sd, 0x01, 0x00);
+ else
+ adv7175_write(sd, 0x01, 0x78);
+
+ return 0;
+}
+
/* ----------------------------------------------------------------------- */
static const struct v4l2_subdev_core_ops adv7175_core_ops = {
.g_chip_ident = adv7175_g_chip_ident,
.init = adv7175_init,
+ .s_power = adv7175_s_power,
};
static const struct v4l2_subdev_video_ops adv7175_video_ops = {
@@ -376,9 +385,25 @@ static const struct i2c_device_id adv7175_id[] = {
};
MODULE_DEVICE_TABLE(i2c, adv7175_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "adv7175",
- .probe = adv7175_probe,
- .remove = adv7175_remove,
- .id_table = adv7175_id,
+static struct i2c_driver adv7175_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "adv7175",
+ },
+ .probe = adv7175_probe,
+ .remove = adv7175_remove,
+ .id_table = adv7175_id,
};
+
+static __init int init_adv7175(void)
+{
+ return i2c_add_driver(&adv7175_driver);
+}
+
+static __exit void exit_adv7175(void)
+{
+ i2c_del_driver(&adv7175_driver);
+}
+
+module_init(init_adv7175);
+module_exit(exit_adv7175);
diff --git a/drivers/media/video/adv7180.c b/drivers/media/video/adv7180.c
index 23e610f62736..d2138d06bcad 100644
--- a/drivers/media/video/adv7180.c
+++ b/drivers/media/video/adv7180.c
@@ -22,7 +22,6 @@
#include <linux/kernel.h>
#include <linux/interrupt.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/slab.h>
#include <media/v4l2-ioctl.h>
#include <linux/videodev2.h>
diff --git a/drivers/media/video/ak881x.c b/drivers/media/video/ak881x.c
index 35390d4717b9..b388654d48cd 100644
--- a/drivers/media/video/ak881x.c
+++ b/drivers/media/video/ak881x.c
@@ -11,6 +11,7 @@
#include <linux/i2c.h>
#include <linux/init.h>
#include <linux/platform_device.h>
+#include <linux/slab.h>
#include <linux/videodev2.h>
#include <media/ak881x.h>
@@ -125,7 +126,7 @@ static int ak881x_try_g_mbus_fmt(struct v4l2_subdev *sd,
v4l_bound_align_image(&mf->width, 0, 720, 2,
&mf->height, 0, ak881x->lines, 1, 0);
mf->field = V4L2_FIELD_INTERLACED;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+ mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
mf->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
@@ -135,19 +136,19 @@ static int ak881x_s_mbus_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
if (mf->field != V4L2_FIELD_INTERLACED ||
- mf->code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ mf->code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EINVAL;
return ak881x_try_g_mbus_fmt(sd, mf);
}
-static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, int index,
+static int ak881x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV8_2X8_LE;
+ *code = V4L2_MBUS_FMT_YUYV8_2X8;
return 0;
}
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index 31e7a123d19a..f989f2820d88 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -712,7 +712,7 @@ static int ar_initialize(struct ar *ar)
static const struct v4l2_file_operations ar_fops = {
.owner = THIS_MODULE,
.read = ar_read,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops ar_ioctl_ops = {
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
index 4d2623158188..5c7f2f7d9805 100644
--- a/drivers/media/video/au0828/Makefile
+++ b/drivers/media/video/au0828/Makefile
@@ -1,4 +1,4 @@
-au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o
+au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o au0828-video.o au0828-vbi.o
obj-$(CONFIG_VIDEO_AU0828) += au0828.o
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
index 57dd9195daf5..01be89fa5c78 100644
--- a/drivers/media/video/au0828/au0828-cards.c
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -212,7 +212,7 @@ void au0828_card_setup(struct au0828_dev *dev)
be abstracted out if we ever need to support a different
demod) */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "au8522", "au8522", 0x8e >> 1, NULL);
+ "au8522", 0x8e >> 1, NULL);
if (sd == NULL)
printk(KERN_ERR "analog subdev registration failed\n");
}
@@ -221,7 +221,7 @@ void au0828_card_setup(struct au0828_dev *dev)
if (dev->board.tuner_type != TUNER_ABSENT) {
/* Load the tuner module, which does the attach */
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->board.tuner_addr, NULL);
+ "tuner", dev->board.tuner_addr, NULL);
if (sd == NULL)
printk(KERN_ERR "tuner subdev registration fail\n");
diff --git a/drivers/media/video/au0828/au0828-vbi.c b/drivers/media/video/au0828/au0828-vbi.c
new file mode 100644
index 000000000000..63f593070ee8
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-vbi.c
@@ -0,0 +1,138 @@
+/*
+ au0828-vbi.c - VBI driver for au0828
+
+ Copyright (C) 2010 Devin Heitmueller <dheitmueller@kernellabs.com>
+
+ This work was sponsored by GetWellNetwork Inc.
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License, or
+ (at your option) any later version.
+
+ This program is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU General Public License for more details.
+
+ You should have received a copy of the GNU General Public License
+ along with this program; if not, write to the Free Software
+ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ 02110-1301, USA.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+
+#include "au0828.h"
+
+static unsigned int vbibufs = 5;
+module_param(vbibufs, int, 0644);
+MODULE_PARM_DESC(vbibufs, "number of vbi buffers, range 2-32");
+
+/* ------------------------------------------------------------------ */
+
+static void
+free_buffer(struct videobuf_queue *vq, struct au0828_buffer *buf)
+{
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.vbi_buf == buf)
+ dev->isoc_ctl.vbi_buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+vbi_setup(struct videobuf_queue *q, unsigned int *count, unsigned int *size)
+{
+ struct au0828_fh *fh = q->priv_data;
+ struct au0828_dev *dev = fh->dev;
+
+ *size = dev->vbi_width * dev->vbi_height * 2;
+
+ if (0 == *count)
+ *count = vbibufs;
+ if (*count < 2)
+ *count = 2;
+ if (*count > 32)
+ *count = 32;
+ return 0;
+}
+
+static int
+vbi_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct au0828_fh *fh = q->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+ int rc = 0;
+
+ buf->vb.size = dev->vbi_width * dev->vbi_height * 2;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->vbi_width;
+ buf->vb.height = dev->vbi_height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(q, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(q, buf);
+ return rc;
+}
+
+static void
+vbi_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct au0828_buffer *buf = container_of(vb,
+ struct au0828_buffer,
+ vb);
+ struct au0828_fh *fh = vq->priv_data;
+ struct au0828_dev *dev = fh->dev;
+ struct au0828_dmaqueue *vbiq = &dev->vbiq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vbiq->active);
+}
+
+static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
+{
+ struct au0828_buffer *buf = container_of(vb, struct au0828_buffer, vb);
+ free_buffer(q, buf);
+}
+
+struct videobuf_queue_ops au0828_vbi_qops = {
+ .buf_setup = vbi_setup,
+ .buf_prepare = vbi_prepare,
+ .buf_queue = vbi_queue,
+ .buf_release = vbi_release,
+};
diff --git a/drivers/media/video/au0828/au0828-video.c b/drivers/media/video/au0828/au0828-video.c
index 52f25aabb6dc..e41e4ad5cc40 100644
--- a/drivers/media/video/au0828/au0828-video.c
+++ b/drivers/media/video/au0828/au0828-video.c
@@ -122,6 +122,7 @@ static void au0828_irq_callback(struct urb *urb)
{
struct au0828_dmaqueue *dma_q = urb->context;
struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vidq);
+ unsigned long flags = 0;
int rc, i;
switch (urb->status) {
@@ -139,9 +140,9 @@ static void au0828_irq_callback(struct urb *urb)
}
/* Copy data from URB */
- spin_lock(&dev->slock);
+ spin_lock_irqsave(&dev->slock, flags);
rc = dev->isoc_ctl.isoc_copy(dev, urb);
- spin_unlock(&dev->slock);
+ spin_unlock_irqrestore(&dev->slock, flags);
/* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
@@ -314,6 +315,23 @@ static inline void buffer_filled(struct au0828_dev *dev,
wake_up(&buf->vb.done);
}
+static inline void vbi_buffer_filled(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ au0828_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+
+ dev->isoc_ctl.vbi_buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
/*
* Identify the buffer header type and properly handles
*/
@@ -327,6 +345,9 @@ static void au0828_copy_video(struct au0828_dev *dev,
int linesdone, currlinedone, offset, lencopy, remain;
int bytesperline = dev->width << 1; /* Assumes 16-bit depth @@@@ */
+ if (len == 0)
+ return;
+
if (dma_q->pos + len > buf->vb.size)
len = buf->vb.size - dma_q->pos;
@@ -414,17 +435,98 @@ static inline void get_next_buf(struct au0828_dmaqueue *dma_q,
return;
}
+static void au0828_copy_vbi(struct au0828_dev *dev,
+ struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ unsigned char *startwrite, *startread;
+ int bytesperline;
+ int i, j = 0;
+
+ if (dev == NULL) {
+ au0828_isocdbg("dev is null\n");
+ return;
+ }
+
+ if (dma_q == NULL) {
+ au0828_isocdbg("dma_q is null\n");
+ return;
+ }
+ if (buf == NULL)
+ return;
+ if (p == NULL) {
+ au0828_isocdbg("p is null\n");
+ return;
+ }
+ if (outp == NULL) {
+ au0828_isocdbg("outp is null\n");
+ return;
+ }
+
+ bytesperline = dev->vbi_width;
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ startread = p;
+ startwrite = outp + (dma_q->pos / 2);
+
+ /* Make sure the bottom field populates the second half of the frame */
+ if (buf->top_field == 0)
+ startwrite += bytesperline * dev->vbi_height;
+
+ for (i = 0; i < len; i += 2)
+ startwrite[j++] = startread[i+1];
+
+ dma_q->pos += len;
+}
+
+
+/*
+ * video-buf generic routine to get the next available VBI buffer
+ */
+static inline void vbi_get_next_buf(struct au0828_dmaqueue *dma_q,
+ struct au0828_buffer **buf)
+{
+ struct au0828_dev *dev = container_of(dma_q, struct au0828_dev, vbiq);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ au0828_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.vbi_buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct au0828_buffer, vb.queue);
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0x00, (*buf)->vb.size);
+
+ dev->isoc_ctl.vbi_buf = *buf;
+
+ return;
+}
+
/*
* Controls the isoc copy of each urb packet
*/
static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
{
struct au0828_buffer *buf;
+ struct au0828_buffer *vbi_buf;
struct au0828_dmaqueue *dma_q = urb->context;
+ struct au0828_dmaqueue *vbi_dma_q = &dev->vbiq;
unsigned char *outp = NULL;
+ unsigned char *vbioutp = NULL;
int i, len = 0, rc = 1;
unsigned char *p;
unsigned char fbyte;
+ unsigned int vbi_field_size;
+ unsigned int remain, lencopy;
if (!dev)
return 0;
@@ -443,6 +545,10 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
if (buf != NULL)
outp = videobuf_to_vmalloc(&buf->vb);
+ vbi_buf = dev->isoc_ctl.vbi_buf;
+ if (vbi_buf != NULL)
+ vbioutp = videobuf_to_vmalloc(&vbi_buf->vb);
+
for (i = 0; i < urb->number_of_packets; i++) {
int status = urb->iso_frame_desc[i].status;
@@ -471,7 +577,20 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
p += 4;
au0828_isocdbg("Video frame %s\n",
(fbyte & 0x40) ? "odd" : "even");
- if (!(fbyte & 0x40)) {
+ if (fbyte & 0x40) {
+ /* VBI */
+ if (vbi_buf != NULL)
+ vbi_buffer_filled(dev,
+ vbi_dma_q,
+ vbi_buf);
+ vbi_get_next_buf(vbi_dma_q, &vbi_buf);
+ if (vbi_buf == NULL)
+ vbioutp = NULL;
+ else
+ vbioutp = videobuf_to_vmalloc(
+ &vbi_buf->vb);
+
+ /* Video */
if (buf != NULL)
buffer_filled(dev, dma_q, buf);
get_next_buf(dma_q, &buf);
@@ -479,6 +598,15 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
outp = NULL;
else
outp = videobuf_to_vmalloc(&buf->vb);
+
+ /* As long as isoc traffic is arriving, keep
+ resetting the timer */
+ if (dev->vid_timeout_running)
+ mod_timer(&dev->vid_timeout,
+ jiffies + (HZ / 10));
+ if (dev->vbi_timeout_running)
+ mod_timer(&dev->vbi_timeout,
+ jiffies + (HZ / 10));
}
if (buf != NULL) {
@@ -488,9 +616,36 @@ static inline int au0828_isoc_copy(struct au0828_dev *dev, struct urb *urb)
buf->top_field = 0;
}
+ if (vbi_buf != NULL) {
+ if (fbyte & 0x40)
+ vbi_buf->top_field = 1;
+ else
+ vbi_buf->top_field = 0;
+ }
+
+ dev->vbi_read = 0;
+ vbi_dma_q->pos = 0;
dma_q->pos = 0;
}
- if (buf != NULL)
+
+ vbi_field_size = dev->vbi_width * dev->vbi_height * 2;
+ if (dev->vbi_read < vbi_field_size) {
+ remain = vbi_field_size - dev->vbi_read;
+ if (len < remain)
+ lencopy = len;
+ else
+ lencopy = remain;
+
+ if (vbi_buf != NULL)
+ au0828_copy_vbi(dev, vbi_dma_q, vbi_buf, p,
+ vbioutp, len);
+
+ len -= lencopy;
+ p += lencopy;
+ dev->vbi_read += lencopy;
+ }
+
+ if (dev->vbi_read >= vbi_field_size && buf != NULL)
au0828_copy_video(dev, dma_q, buf, p, outp, len);
}
return rc;
@@ -642,7 +797,7 @@ int au0828_analog_stream_enable(struct au0828_dev *d)
au0828_writereg(d, 0x114, 0xa0);
au0828_writereg(d, 0x115, 0x05);
/* set y position */
- au0828_writereg(d, 0x112, 0x02);
+ au0828_writereg(d, 0x112, 0x00);
au0828_writereg(d, 0x113, 0x00);
au0828_writereg(d, 0x116, 0xf2);
au0828_writereg(d, 0x117, 0x00);
@@ -703,47 +858,134 @@ void au0828_analog_unregister(struct au0828_dev *dev)
/* Usage lock check functions */
-static int res_get(struct au0828_fh *fh)
+static int res_get(struct au0828_fh *fh, unsigned int bit)
{
- struct au0828_dev *dev = fh->dev;
- int rc = 0;
+ struct au0828_dev *dev = fh->dev;
- /* This instance already has stream_on */
- if (fh->stream_on)
- return rc;
+ if (fh->resources & bit)
+ /* have it already allocated */
+ return 1;
- if (dev->stream_on)
- return -EBUSY;
+ /* is it free? */
+ mutex_lock(&dev->lock);
+ if (dev->resources & bit) {
+ /* no, someone else uses it */
+ mutex_unlock(&dev->lock);
+ return 0;
+ }
+ /* it's free, grab it */
+ fh->resources |= bit;
+ dev->resources |= bit;
+ dprintk(1, "res: get %d\n", bit);
+ mutex_unlock(&dev->lock);
+ return 1;
+}
- dev->stream_on = 1;
- fh->stream_on = 1;
- return rc;
+static int res_check(struct au0828_fh *fh, unsigned int bit)
+{
+ return fh->resources & bit;
}
-static int res_check(struct au0828_fh *fh)
+static int res_locked(struct au0828_dev *dev, unsigned int bit)
{
- return fh->stream_on;
+ return dev->resources & bit;
}
-static void res_free(struct au0828_fh *fh)
+static void res_free(struct au0828_fh *fh, unsigned int bits)
{
- struct au0828_dev *dev = fh->dev;
+ struct au0828_dev *dev = fh->dev;
+
+ BUG_ON((fh->resources & bits) != bits);
+
+ mutex_lock(&dev->lock);
+ fh->resources &= ~bits;
+ dev->resources &= ~bits;
+ dprintk(1, "res: put %d\n", bits);
+ mutex_unlock(&dev->lock);
+}
+
+static int get_ressource(struct au0828_fh *fh)
+{
+ switch (fh->type) {
+ case V4L2_BUF_TYPE_VIDEO_CAPTURE:
+ return AU0828_RESOURCE_VIDEO;
+ case V4L2_BUF_TYPE_VBI_CAPTURE:
+ return AU0828_RESOURCE_VBI;
+ default:
+ BUG();
+ return 0;
+ }
+}
+
+/* This function ensures that video frames continue to be delivered even if
+ the ITU-656 input isn't receiving any data (thereby preventing applications
+ such as tvtime from hanging) */
+void au0828_vid_buffer_timeout(unsigned long data)
+{
+ struct au0828_dev *dev = (struct au0828_dev *) data;
+ struct au0828_dmaqueue *dma_q = &dev->vidq;
+ struct au0828_buffer *buf;
+ unsigned char *vid_data;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&dev->slock, flags);
+
+ buf = dev->isoc_ctl.buf;
+ if (buf != NULL) {
+ vid_data = videobuf_to_vmalloc(&buf->vb);
+ memset(vid_data, 0x00, buf->vb.size); /* Blank green frame */
+ buffer_filled(dev, dma_q, buf);
+ }
+ get_next_buf(dma_q, &buf);
+
+ if (dev->vid_timeout_running == 1)
+ mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
- fh->stream_on = 0;
- dev->stream_on = 0;
+ spin_unlock_irqrestore(&dev->slock, flags);
}
+void au0828_vbi_buffer_timeout(unsigned long data)
+{
+ struct au0828_dev *dev = (struct au0828_dev *) data;
+ struct au0828_dmaqueue *dma_q = &dev->vbiq;
+ struct au0828_buffer *buf;
+ unsigned char *vbi_data;
+ unsigned long flags = 0;
+
+ spin_lock_irqsave(&dev->slock, flags);
+
+ buf = dev->isoc_ctl.vbi_buf;
+ if (buf != NULL) {
+ vbi_data = videobuf_to_vmalloc(&buf->vb);
+ memset(vbi_data, 0x00, buf->vb.size);
+ vbi_buffer_filled(dev, dma_q, buf);
+ }
+ vbi_get_next_buf(dma_q, &buf);
+
+ if (dev->vbi_timeout_running == 1)
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ spin_unlock_irqrestore(&dev->slock, flags);
+}
+
+
static int au0828_v4l2_open(struct file *filp)
{
int ret = 0;
+ struct video_device *vdev = video_devdata(filp);
struct au0828_dev *dev = video_drvdata(filp);
struct au0828_fh *fh;
- int type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ int type;
-#ifdef VBI_IS_WORKING
- if (video_devdata(filp)->vfl_type == VFL_TYPE_GRABBER)
+ switch (vdev->vfl_type) {
+ case VFL_TYPE_GRABBER:
+ type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ break;
+ case VFL_TYPE_VBI:
type = V4L2_BUF_TYPE_VBI_CAPTURE;
-#endif
+ break;
+ default:
+ return -EINVAL;
+ }
fh = kzalloc(sizeof(struct au0828_fh), GFP_KERNEL);
if (NULL == fh) {
@@ -781,9 +1023,19 @@ static int au0828_v4l2_open(struct file *filp)
dev->users++;
videobuf_queue_vmalloc_init(&fh->vb_vidq, &au0828_video_qops,
- NULL, &dev->slock, fh->type,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
- sizeof(struct au0828_buffer), fh);
+ sizeof(struct au0828_buffer), fh, NULL);
+
+ /* VBI Setup */
+ dev->vbi_width = 720;
+ dev->vbi_height = 1;
+ videobuf_queue_vmalloc_init(&fh->vb_vbiq, &au0828_vbi_qops,
+ NULL, &dev->slock,
+ V4L2_BUF_TYPE_VBI_CAPTURE,
+ V4L2_FIELD_SEQ_TB,
+ sizeof(struct au0828_buffer), fh, NULL);
return ret;
}
@@ -794,17 +1046,27 @@ static int au0828_v4l2_close(struct file *filp)
struct au0828_fh *fh = filp->private_data;
struct au0828_dev *dev = fh->dev;
- mutex_lock(&dev->lock);
- if (res_check(fh))
- res_free(fh);
+ if (res_check(fh, AU0828_RESOURCE_VIDEO)) {
+ /* Cancel timeout thread in case they didn't call streamoff */
+ dev->vid_timeout_running = 0;
+ del_timer_sync(&dev->vid_timeout);
- if (dev->users == 1) {
videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
+ res_free(fh, AU0828_RESOURCE_VIDEO);
+ }
+ if (res_check(fh, AU0828_RESOURCE_VBI)) {
+ /* Cancel timeout thread in case they didn't call streamoff */
+ dev->vbi_timeout_running = 0;
+ del_timer_sync(&dev->vbi_timeout);
+
+ videobuf_stop(&fh->vb_vbiq);
+ res_free(fh, AU0828_RESOURCE_VBI);
+ }
+
+ if (dev->users == 1) {
if (dev->dev_state & DEV_DISCONNECTED) {
au0828_analog_unregister(dev);
- mutex_unlock(&dev->lock);
kfree(dev);
return 0;
}
@@ -823,10 +1085,11 @@ static int au0828_v4l2_close(struct file *filp)
printk(KERN_INFO "Au0828 can't set alternate to 0!\n");
}
+ videobuf_mmap_free(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vbiq);
kfree(fh);
dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -842,16 +1105,28 @@ static ssize_t au0828_v4l2_read(struct file *filp, char __user *buf,
return rc;
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- mutex_lock(&dev->lock);
- rc = res_get(fh);
- mutex_unlock(&dev->lock);
-
- if (unlikely(rc < 0))
- return rc;
+ if (res_locked(dev, AU0828_RESOURCE_VIDEO))
+ return -EBUSY;
return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
filp->f_flags & O_NONBLOCK);
}
+
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VBI))
+ return -EBUSY;
+
+ if (dev->vbi_timeout_running == 0) {
+ /* Handle case where caller tries to read without
+ calling streamon first */
+ dev->vbi_timeout_running = 1;
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ }
+
+ return videobuf_read_stream(&fh->vb_vbiq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ }
+
return 0;
}
@@ -865,17 +1140,17 @@ static unsigned int au0828_v4l2_poll(struct file *filp, poll_table *wait)
if (rc < 0)
return rc;
- 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)
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VIDEO))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ if (!res_get(fh, AU0828_RESOURCE_VBI))
+ return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vbiq, wait);
+ } else {
return POLLERR;
-
- return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
+ }
}
static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
@@ -888,14 +1163,10 @@ static int au0828_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
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);
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+ else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)
+ rc = videobuf_mmap_mapper(&fh->vb_vbiq, vma);
return rc;
}
@@ -911,14 +1182,6 @@ static int au0828_set_format(struct au0828_dev *dev, unsigned int cmd,
maxwidth = 720;
maxheight = 480;
-#ifdef VBI_IS_WORKING
- if (format->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- dprintk(1, "VBI format set: to be supported!\n");
- return 0;
- }
- if (format->type == V4L2_BUF_TYPE_VBI_CAPTURE)
- return 0;
-#endif
if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -999,9 +1262,7 @@ static int vidioc_querycap(struct file *file, void *priv,
/*set the device capabilities */
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
-#ifdef VBI_IS_WORKING
V4L2_CAP_VBI_CAPTURE |
-#endif
V4L2_CAP_AUDIO |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING |
@@ -1056,20 +1317,21 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct au0828_dev *dev = fh->dev;
int rc;
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
+
+ mutex_lock(&dev->lock);
+
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
printk(KERN_INFO "%s queue busy\n", __func__);
rc = -EBUSY;
goto out;
}
- if (dev->stream_on && !fh->stream_on) {
- printk(KERN_INFO "%s device in use by another fh\n", __func__);
- rc = -EBUSY;
- goto out;
- }
-
- return au0828_set_format(dev, VIDIOC_S_FMT, f);
+ rc = au0828_set_format(dev, VIDIOC_S_FMT, f);
out:
+ mutex_unlock(&dev->lock);
return rc;
}
@@ -1300,6 +1562,29 @@ static int vidioc_s_frequency(struct file *file, void *priv,
return 0;
}
+
+/* RAW VBI ioctls */
+
+static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+
+ format->fmt.vbi.samples_per_line = dev->vbi_width;
+ format->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ format->fmt.vbi.offset = 0;
+ format->fmt.vbi.flags = 0;
+ format->fmt.vbi.sampling_rate = 6750000 * 4 / 2;
+
+ format->fmt.vbi.count[0] = dev->vbi_height;
+ format->fmt.vbi.count[1] = dev->vbi_height;
+ format->fmt.vbi.start[0] = 21;
+ format->fmt.vbi.start[1] = 284;
+
+ return 0;
+}
+
static int vidioc_g_chip_ident(struct file *file, void *priv,
struct v4l2_dbg_chip_ident *chip)
{
@@ -1345,25 +1630,37 @@ static int vidioc_cropcap(struct file *file, void *priv,
static int vidioc_streamon(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int rc;
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc = -EINVAL;
rc = check_dev(dev);
if (rc < 0)
return rc;
+ if (unlikely(type != fh->type))
+ return -EINVAL;
+
+ dprintk(1, "vidioc_streamon fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
+
+ if (unlikely(!res_get(fh, get_ressource(fh))))
+ return -EBUSY;
+
if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
au0828_analog_stream_enable(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 1);
}
- mutex_lock(&dev->lock);
- rc = res_get(fh);
-
- if (likely(rc >= 0))
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
rc = videobuf_streamon(&fh->vb_vidq);
- mutex_unlock(&dev->lock);
+ dev->vid_timeout_running = 1;
+ mod_timer(&dev->vid_timeout, jiffies + (HZ / 10));
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ rc = videobuf_streamon(&fh->vb_vbiq);
+ dev->vbi_timeout_running = 1;
+ mod_timer(&dev->vbi_timeout, jiffies + (HZ / 10));
+ }
return rc;
}
@@ -1371,38 +1668,48 @@ static int vidioc_streamon(struct file *file, void *priv,
static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type type)
{
- struct au0828_fh *fh = priv;
- struct au0828_dev *dev = fh->dev;
- int i;
- int ret;
- int rc;
+ struct au0828_fh *fh = priv;
+ struct au0828_dev *dev = fh->dev;
+ int rc;
+ int i;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
+ fh->type != V4L2_BUF_TYPE_VBI_CAPTURE)
return -EINVAL;
if (type != fh->type)
return -EINVAL;
- if (type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dprintk(1, "vidioc_streamoff fh=%p t=%d fh->res=%d dev->res=%d\n",
+ fh, type, fh->resources, dev->resources);
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev->vid_timeout_running = 0;
+ del_timer_sync(&dev->vid_timeout);
+
v4l2_device_call_all(&dev->v4l2_dev, 0, video, s_stream, 0);
- ret = au0828_stream_interrupt(dev);
- if (ret != 0)
- return ret;
- }
+ rc = au0828_stream_interrupt(dev);
+ if (rc != 0)
+ return rc;
- for (i = 0; i < AU0828_MAX_INPUT; i++) {
- if (AUVI_INPUT(i).audio_setup == NULL)
- continue;
- (AUVI_INPUT(i).audio_setup)(dev, 0);
- }
+ for (i = 0; i < AU0828_MAX_INPUT; i++) {
+ if (AUVI_INPUT(i).audio_setup == NULL)
+ continue;
+ (AUVI_INPUT(i).audio_setup)(dev, 0);
+ }
- mutex_lock(&dev->lock);
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh);
- mutex_unlock(&dev->lock);
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh, AU0828_RESOURCE_VIDEO);
+ } else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ dev->vbi_timeout_running = 0;
+ del_timer_sync(&dev->vbi_timeout);
+
+ videobuf_streamoff(&fh->vb_vbiq);
+ res_free(fh, AU0828_RESOURCE_VBI);
+ }
return 0;
}
@@ -1502,15 +1809,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct au0828_fh *fh = priv;
-
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
static struct v4l2_file_operations au0828_v4l_fops = {
.owner = THIS_MODULE,
.open = au0828_v4l2_open,
@@ -1527,19 +1825,11 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
.vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
.vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
-#ifdef VBI_IS_WORKING
.vidioc_g_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
- .vidioc_try_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
- .vidioc_s_fmt_vbi_cap = vidioc_s_fmt_vbi_cap,
-#endif
+ .vidioc_s_fmt_vbi_cap = vidioc_g_fmt_vbi_cap,
.vidioc_g_audio = vidioc_g_audio,
.vidioc_s_audio = vidioc_s_audio,
.vidioc_cropcap = vidioc_cropcap,
-#ifdef VBI_IS_WORKING
- .vidioc_g_fmt_sliced_vbi_cap = vidioc_g_fmt_sliced_vbi_cap,
- .vidioc_try_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
- .vidioc_s_fmt_sliced_vbi_cap = vidioc_try_set_sliced_vbi_cap,
-#endif
.vidioc_reqbufs = vidioc_reqbufs,
.vidioc_querybuf = vidioc_querybuf,
.vidioc_qbuf = vidioc_qbuf,
@@ -1562,9 +1852,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
#endif
.vidioc_g_chip_ident = vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static const struct video_device au0828_video_template = {
@@ -1621,8 +1908,19 @@ int au0828_analog_register(struct au0828_dev *dev,
spin_lock_init(&dev->slock);
mutex_init(&dev->lock);
+ /* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
INIT_LIST_HEAD(&dev->vidq.queued);
+ INIT_LIST_HEAD(&dev->vbiq.active);
+ INIT_LIST_HEAD(&dev->vbiq.queued);
+
+ dev->vid_timeout.function = au0828_vid_buffer_timeout;
+ dev->vid_timeout.data = (unsigned long) dev;
+ init_timer(&dev->vid_timeout);
+
+ dev->vbi_timeout.function = au0828_vbi_buffer_timeout;
+ dev->vbi_timeout.data = (unsigned long) dev;
+ init_timer(&dev->vbi_timeout);
dev->width = NTSC_STD_W;
dev->height = NTSC_STD_H;
@@ -1638,26 +1936,23 @@ int au0828_analog_register(struct au0828_dev *dev,
return -ENOMEM;
}
-#ifdef VBI_IS_WORKING
+ /* allocate the VBI struct */
dev->vbi_dev = video_device_alloc();
if (NULL == dev->vbi_dev) {
dprintk(1, "Can't allocate vbi_device.\n");
kfree(dev->vdev);
return -ENOMEM;
}
-#endif
/* Fill the video capture device struct */
*dev->vdev = au0828_video_template;
dev->vdev->parent = &dev->usbdev->dev;
strcpy(dev->vdev->name, "au0828a video");
-#ifdef VBI_IS_WORKING
/* Setup the VBI device */
*dev->vbi_dev = au0828_video_template;
dev->vbi_dev->parent = &dev->usbdev->dev;
strcpy(dev->vbi_dev->name, "au0828a vbi");
-#endif
/* Register the v4l2 device */
video_set_drvdata(dev->vdev, dev);
@@ -1669,7 +1964,6 @@ int au0828_analog_register(struct au0828_dev *dev,
return -ENODEV;
}
-#ifdef VBI_IS_WORKING
/* Register the vbi device */
video_set_drvdata(dev->vbi_dev, dev);
retval = video_register_device(dev->vbi_dev, VFL_TYPE_VBI, -1);
@@ -1680,7 +1974,6 @@ int au0828_analog_register(struct au0828_dev *dev,
video_device_release(dev->vdev);
return -ENODEV;
}
-#endif
dprintk(1, "%s completed!\n", __func__);
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
index 207f32dec6a6..9cde35321824 100644
--- a/drivers/media/video/au0828/au0828.h
+++ b/drivers/media/video/au0828/au0828.h
@@ -53,13 +53,17 @@
/* Defination for AU0828 USB transfer */
#define AU0828_MAX_ISO_BUFS 12 /* maybe resize this value in the future */
-#define AU0828_ISO_PACKETS_PER_URB 10
+#define AU0828_ISO_PACKETS_PER_URB 128
#define AU0828_MIN_BUF 4
#define AU0828_DEF_BUF 8
#define AU0828_MAX_INPUT 4
+/* au0828 resource types (used for res_get/res_lock etc */
+#define AU0828_RESOURCE_VIDEO 0x01
+#define AU0828_RESOURCE_VBI 0x02
+
enum au0828_itype {
AU0828_VMUX_UNDEFINED = 0,
AU0828_VMUX_COMPOSITE,
@@ -115,8 +119,10 @@ enum au0828_dev_state {
struct au0828_fh {
struct au0828_dev *dev;
- unsigned int stream_on:1; /* Locks streams */
+ unsigned int resources;
+
struct videobuf_queue vb_vidq;
+ struct videobuf_queue vb_vbiq;
enum v4l2_buf_type type;
};
@@ -145,7 +151,8 @@ struct au0828_usb_isoc_ctl {
int tmp_buf_len;
/* Stores already requested buffers */
- struct au0828_buffer *buf;
+ struct au0828_buffer *buf;
+ struct au0828_buffer *vbi_buf;
/* Stores the number of received fields */
int nfields;
@@ -194,11 +201,18 @@ struct au0828_dev {
/* Analog */
struct v4l2_device v4l2_dev;
int users;
- unsigned int stream_on:1; /* Locks streams */
+ unsigned int resources; /* resources in use */
struct video_device *vdev;
struct video_device *vbi_dev;
+ struct timer_list vid_timeout;
+ int vid_timeout_running;
+ struct timer_list vbi_timeout;
+ int vbi_timeout_running;
int width;
int height;
+ int vbi_width;
+ int vbi_height;
+ u32 vbi_read;
u32 field_size;
u32 frame_size;
u32 bytesperline;
@@ -219,6 +233,7 @@ struct au0828_dev {
/* Isoc control struct */
struct au0828_dmaqueue vidq;
+ struct au0828_dmaqueue vbiq;
struct au0828_usb_isoc_ctl isoc_ctl;
spinlock_t slock;
@@ -278,6 +293,9 @@ void au0828_analog_unregister(struct au0828_dev *dev);
extern int au0828_dvb_register(struct au0828_dev *dev);
extern void au0828_dvb_unregister(struct au0828_dev *dev);
+/* au0828-vbi.c */
+extern struct videobuf_queue_ops au0828_vbi_qops;
+
#define dprintk(level, fmt, arg...)\
do { if (au0828_debug & level)\
printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index 770cb9accf81..c38300fc0b1d 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -33,12 +33,10 @@
#include <linux/ioctl.h>
#include <linux/delay.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/bt819.h>
MODULE_DESCRIPTION("Brooktree-819 video decoder driver");
@@ -537,9 +535,25 @@ static const struct i2c_device_id bt819_id[] = {
};
MODULE_DEVICE_TABLE(i2c, bt819_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "bt819",
- .probe = bt819_probe,
- .remove = bt819_remove,
- .id_table = bt819_id,
+static struct i2c_driver bt819_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bt819",
+ },
+ .probe = bt819_probe,
+ .remove = bt819_remove,
+ .id_table = bt819_id,
};
+
+static __init int init_bt819(void)
+{
+ return i2c_add_driver(&bt819_driver);
+}
+
+static __exit void exit_bt819(void)
+{
+ i2c_del_driver(&bt819_driver);
+}
+
+module_init(init_bt819);
+module_exit(exit_bt819);
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index ae3337392505..a43059d4c799 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -34,11 +34,9 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("Brooktree-856A video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -262,9 +260,25 @@ static const struct i2c_device_id bt856_id[] = {
};
MODULE_DEVICE_TABLE(i2c, bt856_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "bt856",
- .probe = bt856_probe,
- .remove = bt856_remove,
- .id_table = bt856_id,
+static struct i2c_driver bt856_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bt856",
+ },
+ .probe = bt856_probe,
+ .remove = bt856_remove,
+ .id_table = bt856_id,
};
+
+static __init int init_bt856(void)
+{
+ return i2c_add_driver(&bt856_driver);
+}
+
+static __exit void exit_bt856(void)
+{
+ i2c_del_driver(&bt856_driver);
+}
+
+module_init(init_bt856);
+module_exit(exit_bt856);
diff --git a/drivers/media/video/bt866.c b/drivers/media/video/bt866.c
index 62ac422bb159..4e5dcea0501d 100644
--- a/drivers/media/video/bt866.c
+++ b/drivers/media/video/bt866.c
@@ -34,11 +34,9 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("Brooktree-866 video encoder driver");
MODULE_AUTHOR("Mike Bernson & Dave Perks");
@@ -232,9 +230,25 @@ static const struct i2c_device_id bt866_id[] = {
};
MODULE_DEVICE_TABLE(i2c, bt866_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "bt866",
- .probe = bt866_probe,
- .remove = bt866_remove,
- .id_table = bt866_id,
+static struct i2c_driver bt866_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "bt866",
+ },
+ .probe = bt866_probe,
+ .remove = bt866_remove,
+ .id_table = bt866_id,
};
+
+static __init int init_bt866(void)
+{
+ return i2c_add_driver(&bt866_driver);
+}
+
+static __exit void exit_bt866(void)
+{
+ i2c_del_driver(&bt866_driver);
+}
+
+module_init(init_bt866);
+module_exit(exit_bt866);
diff --git a/drivers/media/video/bt8xx/Kconfig b/drivers/media/video/bt8xx/Kconfig
index 3077c45015f5..7da5c2e1fc12 100644
--- a/drivers/media/video/bt8xx/Kconfig
+++ b/drivers/media/video/bt8xx/Kconfig
@@ -1,10 +1,10 @@
config VIDEO_BT848
tristate "BT848 Video For Linux"
- depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2 && INPUT
+ depends on VIDEO_DEV && PCI && I2C && VIDEO_V4L2
select I2C_ALGOBIT
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
- select VIDEO_IR
+ depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 7af56cde0c79..7f58756d72c8 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -1373,7 +1373,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x1800,
.audio_mode_gpio= fv2000s_audio,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
@@ -1511,7 +1510,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomute = 0x09,
.needs_tvaudio = 1,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.pll = PLL_28,
.tuner_type = TUNER_PHILIPS_PAL,
.tuner_addr = ADDR_UNSET,
@@ -1550,7 +1548,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomask2 = 0x07ff,
.muxsel = MUXSEL(3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.muxsel_hook = rv605_muxsel,
@@ -1686,7 +1683,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY1x0_848] = {
@@ -1699,7 +1695,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
@@ -1714,7 +1709,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY1x1] = {
@@ -1727,7 +1721,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY1x1_SVID] = {
@@ -1740,7 +1733,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY2xx] = {
@@ -1753,7 +1745,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
@@ -1768,7 +1759,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY2x0] = {
@@ -1781,7 +1771,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY500] = {
@@ -1794,7 +1783,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
[BTTV_BOARD_OSPREY540] = {
@@ -1805,7 +1793,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
@@ -1820,7 +1807,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1, /* must avoid, conflicts with the bt860 */
},
[BTTV_BOARD_IDS_EAGLE] = {
@@ -1835,7 +1821,6 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2, 2, 2, 2),
.muxsel_hook = eagle_muxsel,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.pll = PLL_28,
},
[BTTV_BOARD_PINNACLESAT] = {
@@ -1846,7 +1831,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.muxsel = MUXSEL(3, 1),
.pll = PLL_28,
@@ -1897,7 +1881,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = 2,
.gpiomask = 0,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.muxsel = MUXSEL(2, 0, 1),
.pll = PLL_28,
@@ -1970,7 +1953,6 @@ struct tvcard bttv_tvcards[] = {
/* Tuner, CVid, SVid, CVid over SVid connector */
.muxsel = MUXSEL(2, 3, 1, 1),
.gpiomask = 0,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_PHILIPS_PAL_I,
.tuner_addr = ADDR_UNSET,
@@ -2017,7 +1999,6 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2,2,2,2, 3,3,3,3, 1,1,1,1, 0,0,0,0),
.muxsel_hook = xguard_muxsel,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
},
@@ -2029,7 +2010,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = NO_SVHS,
.muxsel = MUXSEL(2, 3, 1, 0),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.tuner_type = TUNER_ABSENT,
@@ -2134,7 +2114,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = NO_SVHS, /* card has no svhs */
.needs_tvaudio = 0,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.gpiomask = 0x00,
.muxsel = MUXSEL(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0),
@@ -2156,7 +2135,6 @@ struct tvcard bttv_tvcards[] = {
[BTTV_BOARD_TWINHAN_DST] = {
.name = "Twinhan DST + clones",
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
@@ -2171,7 +2149,6 @@ struct tvcard bttv_tvcards[] = {
/* Vid In, SVid In, Vid over SVid in connector */
.muxsel = MUXSEL(3, 1, 1, 3),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
@@ -2226,7 +2203,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = NO_SVHS,
.muxsel = MUXSEL(2, 3, 1, 0),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.needs_tvaudio = 0,
.tuner_type = TUNER_ABSENT,
@@ -2278,7 +2254,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomask = 0,
.gpiomask2 = 0x3C<<16,/*Set the GPIO[18]->GPIO[21] as output pin.==> drive the video inputs through analog multiplexers*/
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
/*878A input is always MUX0, see above.*/
.muxsel = MUXSEL(2, 2, 2, 2),
@@ -2302,7 +2277,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_TEMIC_PAL,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
},
[BTTV_BOARD_AVDVBT_771] = {
/* Wolfram Joost <wojo@frokaschwei.de> */
@@ -2313,7 +2287,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.muxsel = MUXSEL(3, 3),
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.has_dvb = 1,
@@ -2329,7 +2302,6 @@ struct tvcard bttv_tvcards[] = {
.svhs = 1,
.muxsel = MUXSEL(3, 1, 2, 0), /* Comp0, S-Video, ?, ? */
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.tuner_type = TUNER_ABSENT,
@@ -2393,7 +2365,6 @@ struct tvcard bttv_tvcards[] = {
/* Chris Pascoe <c.pascoe@itee.uq.edu.au> */
.name = "DViCO FusionHDTV DVB-T Lite",
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.no_video = 1,
@@ -2440,7 +2411,6 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2),
.pll = PLL_28,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
@@ -2478,7 +2448,6 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda7432 = 1,
- .no_tda9875 = 1,
.muxsel_hook = kodicom4400r_muxsel,
},
[BTTV_BOARD_KODICOM_4400R_SL] = {
@@ -2500,7 +2469,6 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda7432 = 1,
- .no_tda9875 = 1,
.muxsel_hook = kodicom4400r_muxsel,
},
/* ---- card 0x86---------------------------------- */
@@ -2530,7 +2498,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x00400005, 0, 0x00000001, 0 },
.gpiomute = 0x00c00007,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.has_dvb = 1,
},
@@ -2630,7 +2597,6 @@ struct tvcard bttv_tvcards[] = {
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
/* ---- card 0x8d ---------------------------------- */
@@ -2658,7 +2624,6 @@ struct tvcard bttv_tvcards[] = {
.muxsel = MUXSEL(2, 3, 1, 1),
.gpiomux = { 100000, 100002, 100002, 100000 },
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.pll = PLL_28,
.tuner_type = TUNER_TNF_5335MF,
@@ -2674,7 +2639,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomask = 0x0f, /* old: 7 */
.muxsel = MUXSEL(0, 1, 3, 2), /* Composite 0-3 */
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
.tuner_type = TUNER_ABSENT,
.tuner_addr = ADDR_UNSET,
@@ -2732,7 +2696,6 @@ struct tvcard bttv_tvcards[] = {
.gpiomux = { 0x00400005, 0, 0x00000001, 0 },
.gpiomute = 0x00c00007,
.no_msp34xx = 1,
- .no_tda9875 = 1,
.no_tda7432 = 1,
},
/* ---- card 0x95---------------------------------- */
@@ -2874,7 +2837,6 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda7432 = 1,
- .no_tda9875 = 1,
.muxsel_hook = gv800s_muxsel,
},
[BTTV_BOARD_GEOVISION_GV800S_SL] = {
@@ -2899,7 +2861,6 @@ struct tvcard bttv_tvcards[] = {
.pll = PLL_28,
.no_msp34xx = 1,
.no_tda7432 = 1,
- .no_tda9875 = 1,
.muxsel_hook = gv800s_muxsel,
},
[BTTV_BOARD_PV183] = {
@@ -3529,7 +3490,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "saa6588", "saa6588", 0, addrs);
+ &btv->c.i2c_adap, "saa6588", 0, addrs);
btv->has_saa6588 = (sd != NULL);
}
@@ -3554,7 +3515,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400", 0, addrs);
+ &btv->c.i2c_adap, "msp3400", 0, addrs);
if (btv->sd_msp34xx)
return;
goto no_audio;
@@ -3568,7 +3529,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
+ &btv->c.i2c_adap, "tda7432", 0, addrs))
return;
goto no_audio;
}
@@ -3576,7 +3537,7 @@ void __devinit bttv_init_card2(struct bttv *btv)
case 3: {
/* The user specified that we should probe for tvaudio */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
goto no_audio;
@@ -3596,11 +3557,11 @@ void __devinit bttv_init_card2(struct bttv *btv)
found is really something else (e.g. a tea6300). */
if (!bttv_tvcards[btv->c.type].no_msp34xx) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400",
+ &btv->c.i2c_adap, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400 >> 1));
} else if (bttv_tvcards[btv->c.type].msp34xx_alt) {
btv->sd_msp34xx = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "msp3400", "msp3400",
+ &btv->c.i2c_adap, "msp3400",
0, I2C_ADDRS(I2C_ADDR_MSP3400_ALT >> 1));
}
@@ -3616,13 +3577,13 @@ void __devinit bttv_init_card2(struct bttv *btv)
};
if (v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tda7432", "tda7432", 0, addrs))
+ &btv->c.i2c_adap, "tda7432", 0, addrs))
return;
}
/* Now see if we can find one of the tvaudio devices. */
btv->sd_tvaudio = v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tvaudio", "tvaudio", 0, tvaudio_addrs());
+ &btv->c.i2c_adap, "tvaudio", 0, tvaudio_addrs());
if (btv->sd_tvaudio)
return;
@@ -3646,13 +3607,13 @@ void __devinit bttv_init_tuner(struct bttv *btv)
/* Load tuner module before issuing tuner config call! */
if (bttv_tvcards[btv->c.type].has_radio)
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
v4l2_i2c_new_subdev(&btv->c.v4l2_dev,
- &btv->c.i2c_adap, "tuner", "tuner",
+ &btv->c.i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_TV_WITH_DEMOD));
tun_setup.mode_mask = T_ANALOG_TV | T_DIGITAL_TV;
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index 38c7f78ad9cf..91399c94cd18 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -42,7 +42,6 @@
#include <linux/fs.h>
#include <linux/kernel.h>
#include <linux/sched.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/kdev_t.h>
#include "bttvp.h"
@@ -56,7 +55,7 @@
#include <asm/io.h>
#include <asm/byteorder.h>
-#include <media/rds.h>
+#include <media/saa6588.h>
unsigned int bttv_num; /* number of Bt848s in use */
@@ -190,8 +189,14 @@ static void request_modules(struct bttv *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct bttv *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
@@ -842,7 +847,7 @@ static const struct v4l2_queryctrl *ctrl_by_id(int id)
RESOURCE_OVERLAY)
static
-int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
+int check_alloc_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bit)
{
int xbits; /* mutual exclusive resources */
@@ -855,7 +860,6 @@ int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
xbits |= RESOURCE_VIDEO_READ | RESOURCE_VIDEO_STREAM;
/* is it free? */
- mutex_lock(&btv->lock);
if (btv->resources & xbits) {
/* no, someone else uses it */
goto fail;
@@ -885,11 +889,9 @@ int check_alloc_btres(struct bttv *btv, struct bttv_fh *fh, int bit)
/* it's free, grab it */
fh->resources |= bit;
btv->resources |= bit;
- mutex_unlock(&btv->lock);
return 1;
fail:
- mutex_unlock(&btv->lock);
return 0;
}
@@ -935,13 +937,12 @@ disclaim_video_lines(struct bttv *btv)
}
static
-void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
+void free_btres_lock(struct bttv *btv, struct bttv_fh *fh, int bits)
{
if ((fh->resources & bits) != bits) {
/* trying to free ressources not allocated by us ... */
printk("bttv: BUG! (btres)\n");
}
- mutex_lock(&btv->lock);
fh->resources &= ~bits;
btv->resources &= ~bits;
@@ -952,8 +953,6 @@ void free_btres(struct bttv *btv, struct bttv_fh *fh, int bits)
if (0 == (bits & VBI_RESOURCES))
disclaim_vbi_lines(btv);
-
- mutex_unlock(&btv->lock);
}
/* ----------------------------------------------------------------------- */
@@ -1682,7 +1681,7 @@ bttv_switch_overlay(struct bttv *btv, struct bttv_fh *fh,
kfree(old);
}
if (NULL == new)
- free_btres(btv,fh,RESOURCE_OVERLAY);
+ free_btres_lock(btv,fh,RESOURCE_OVERLAY);
dprintk("switch_overlay: done\n");
return retval;
}
@@ -1714,28 +1713,20 @@ static int bttv_prepare_buffer(struct videobuf_queue *q,struct bttv *btv,
/* Make sure tvnorm and vbi_end remain consistent
until we're done. */
- mutex_lock(&btv->lock);
norm = btv->tvnorm;
/* In this mode capturing always starts at defrect.top
(default VDELAY), ignoring cropping parameters. */
if (btv->vbi_end > bttv_tvnorms[norm].cropcap.defrect.top) {
- mutex_unlock(&btv->lock);
return -EINVAL;
}
- mutex_unlock(&btv->lock);
-
c.rect = bttv_tvnorms[norm].cropcap.defrect;
} else {
- mutex_lock(&btv->lock);
-
norm = btv->tvnorm;
c = btv->crop[!!fh->do_crop];
- mutex_unlock(&btv->lock);
-
if (width < c.min_scaled_width ||
width > c.max_scaled_width ||
height < c.min_scaled_height)
@@ -1860,20 +1851,22 @@ static int bttv_s_std(struct file *file, void *priv, v4l2_std_id *id)
int err;
err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
+ if (err)
+ goto err;
for (i = 0; i < BTTV_TVNORMS; i++)
if (*id & bttv_tvnorms[i].v4l2_id)
break;
- if (i == BTTV_TVNORMS)
- return -EINVAL;
+ if (i == BTTV_TVNORMS) {
+ err = -EINVAL;
+ goto err;
+ }
- mutex_lock(&btv->lock);
set_tvnorm(btv, i);
- mutex_unlock(&btv->lock);
- return 0;
+err:
+
+ return err;
}
static int bttv_querystd(struct file *file, void *f, v4l2_std_id *id)
@@ -1893,10 +1886,12 @@ static int bttv_enum_input(struct file *file, void *priv,
{
struct bttv_fh *fh = priv;
struct bttv *btv = fh->btv;
- int n;
+ int rc = 0;
- if (i->index >= bttv_tvcards[btv->c.type].video_inputs)
- return -EINVAL;
+ if (i->index >= bttv_tvcards[btv->c.type].video_inputs) {
+ rc = -EINVAL;
+ goto err;
+ }
i->type = V4L2_INPUT_TYPE_CAMERA;
i->audioset = 1;
@@ -1919,10 +1914,11 @@ static int bttv_enum_input(struct file *file, void *priv,
i->status |= V4L2_IN_ST_NO_H_LOCK;
}
- for (n = 0; n < BTTV_TVNORMS; n++)
- i->std |= bttv_tvnorms[n].v4l2_id;
+ i->std = BTTV_NORMS;
- return 0;
+err:
+
+ return rc;
}
static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
@@ -1931,6 +1927,7 @@ static int bttv_g_input(struct file *file, void *priv, unsigned int *i)
struct bttv *btv = fh->btv;
*i = btv->input;
+
return 0;
}
@@ -1942,15 +1939,17 @@ static int bttv_s_input(struct file *file, void *priv, unsigned int i)
int err;
err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
+ if (unlikely(err))
+ goto err;
- if (i > bttv_tvcards[btv->c.type].video_inputs)
- return -EINVAL;
+ if (i > bttv_tvcards[btv->c.type].video_inputs) {
+ err = -EINVAL;
+ goto err;
+ }
- mutex_lock(&btv->lock);
set_input(btv, i, btv->tvnorm);
- mutex_unlock(&btv->lock);
+
+err:
return 0;
}
@@ -1961,23 +1960,24 @@ static int bttv_s_tuner(struct file *file, void *priv,
struct bttv *btv = fh->btv;
int err;
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
-
- if (btv->tuner_type == TUNER_ABSENT)
+ if (unlikely(0 != t->index))
return -EINVAL;
- if (0 != t->index)
- return -EINVAL;
+ if (unlikely(btv->tuner_type == TUNER_ABSENT)) {
+ err = -EINVAL;
+ goto err;
+ }
+
+ err = v4l2_prio_check(&btv->prio, fh->prio);
+ if (unlikely(err))
+ goto err;
- mutex_lock(&btv->lock);
bttv_call_all(btv, tuner, s_tuner, t);
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 1);
- mutex_unlock(&btv->lock);
+err:
return 0;
}
@@ -2001,21 +2001,24 @@ static int bttv_s_frequency(struct file *file, void *priv,
struct bttv *btv = fh->btv;
int err;
- err = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != err)
- return err;
-
if (unlikely(f->tuner != 0))
return -EINVAL;
+
+ err = v4l2_prio_check(&btv->prio, fh->prio);
+ if (unlikely(err))
+ goto err;
+
if (unlikely(f->type != (btv->radio_user
- ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV)))
- return -EINVAL;
- mutex_lock(&btv->lock);
+ ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV))) {
+ err = -EINVAL;
+ goto err;
+ }
btv->freq = f->frequency;
bttv_call_all(btv, tuner, s_frequency, f);
if (btv->has_matchbox && btv->radio_user)
tea5757_set_freq(btv, btv->freq);
- mutex_unlock(&btv->lock);
+err:
+
return 0;
}
@@ -2124,7 +2127,7 @@ bttv_crop_adjust (struct bttv_crop * c,
also adjust the current cropping parameters to get closer to the
desired image size. */
static int
-limit_scaled_size (struct bttv_fh * fh,
+limit_scaled_size_lock (struct bttv_fh * fh,
__s32 * width,
__s32 * height,
enum v4l2_field field,
@@ -2147,7 +2150,6 @@ limit_scaled_size (struct bttv_fh * fh,
/* Make sure tvnorm, vbi_end and the current cropping parameters
remain consistent until we're done. */
- mutex_lock(&btv->lock);
b = &bttv_tvnorms[btv->tvnorm].cropcap.bounds;
@@ -2225,7 +2227,6 @@ limit_scaled_size (struct bttv_fh * fh,
rc = 0; /* success */
fail:
- mutex_unlock(&btv->lock);
return rc;
}
@@ -2238,7 +2239,7 @@ limit_scaled_size (struct bttv_fh * fh,
may also adjust the current cropping parameters to get closer
to the desired window size. */
static int
-verify_window (struct bttv_fh * fh,
+verify_window_lock (struct bttv_fh * fh,
struct v4l2_window * win,
int adjust_size,
int adjust_crop)
@@ -2292,7 +2293,7 @@ verify_window (struct bttv_fh * fh,
win->w.width -= win->w.left & ~width_mask;
win->w.left = (win->w.left - width_mask - 1) & width_mask;
- rc = limit_scaled_size(fh, &win->w.width, &win->w.height,
+ rc = limit_scaled_size_lock(fh, &win->w.width, &win->w.height,
field, width_mask,
/* width_bias: round down */ 0,
adjust_size, adjust_crop);
@@ -2303,7 +2304,7 @@ verify_window (struct bttv_fh * fh,
return 0;
}
-static int setup_window(struct bttv_fh *fh, struct bttv *btv,
+static int setup_window_lock(struct bttv_fh *fh, struct bttv *btv,
struct v4l2_window *win, int fixup)
{
struct v4l2_clip *clips = NULL;
@@ -2313,7 +2314,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
return -EINVAL;
if (!(fh->ovfmt->flags & FORMAT_FLAGS_PACKED))
return -EINVAL;
- retval = verify_window(fh, win,
+ retval = verify_window_lock(fh, win,
/* adjust_size */ fixup,
/* adjust_crop */ fixup);
if (0 != retval)
@@ -2332,6 +2333,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
return -EFAULT;
}
}
+
/* clip against screen */
if (NULL != btv->fbuf.base)
n = btcx_screen_clips(btv->fbuf.fmt.width, btv->fbuf.fmt.height,
@@ -2354,7 +2356,6 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
BUG();
}
- mutex_lock(&fh->cap.vb_lock);
kfree(fh->ov.clips);
fh->ov.clips = clips;
fh->ov.nclips = n;
@@ -2362,6 +2363,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
fh->ov.w = win->w;
fh->ov.field = win->field;
fh->ov.setup_ok = 1;
+
btv->init.ov.w.width = win->w.width;
btv->init.ov.w.height = win->w.height;
btv->init.ov.field = win->field;
@@ -2376,7 +2378,6 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
}
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2516,7 +2517,7 @@ static int bttv_try_fmt_vid_cap(struct file *file, void *priv,
width = f->fmt.pix.width;
height = f->fmt.pix.height;
- rc = limit_scaled_size(fh, &width, &height, field,
+ rc = limit_scaled_size_lock(fh, &width, &height, field,
/* width_mask: 4 pixels */ ~3,
/* width_bias: nearest */ 2,
/* adjust_size */ 1,
@@ -2536,7 +2537,7 @@ static int bttv_try_fmt_vid_overlay(struct file *file, void *priv,
{
struct bttv_fh *fh = priv;
- return verify_window(fh, &f->fmt.win,
+ return verify_window_lock(fh, &f->fmt.win,
/* adjust_size */ 1,
/* adjust_crop */ 0);
}
@@ -2563,7 +2564,7 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
height = f->fmt.pix.height;
field = f->fmt.pix.field;
- retval = limit_scaled_size(fh, &width, &height, f->fmt.pix.field,
+ retval = limit_scaled_size_lock(fh, &width, &height, f->fmt.pix.field,
/* width_mask: 4 pixels */ ~3,
/* width_bias: nearest */ 2,
/* adjust_size */ 1,
@@ -2576,7 +2577,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
/* update our state informations */
- mutex_lock(&fh->cap.vb_lock);
fh->fmt = fmt;
fh->cap.field = f->fmt.pix.field;
fh->cap.last = V4L2_FIELD_NONE;
@@ -2585,7 +2585,6 @@ static int bttv_s_fmt_vid_cap(struct file *file, void *priv,
btv->init.fmt = fmt;
btv->init.width = f->fmt.pix.width;
btv->init.height = f->fmt.pix.height;
- mutex_unlock(&fh->cap.vb_lock);
return 0;
}
@@ -2601,36 +2600,8 @@ static int bttv_s_fmt_vid_overlay(struct file *file, void *priv,
return -EINVAL;
}
- return setup_window(fh, btv, &f->fmt.win, 1);
-}
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- int retval;
- unsigned int i;
- struct bttv_fh *fh = priv;
-
- mutex_lock(&fh->cap.vb_lock);
- retval = __videobuf_mmap_setup(&fh->cap, gbuffers, gbufsize,
- V4L2_MEMORY_MMAP);
- if (retval < 0) {
- mutex_unlock(&fh->cap.vb_lock);
- return retval;
- }
-
- gbuffers = retval;
- memset(mbuf, 0, sizeof(*mbuf));
- mbuf->frames = gbuffers;
- mbuf->size = gbuffers * gbufsize;
-
- for (i = 0; i < gbuffers; i++)
- mbuf->offsets[i] = i * gbufsize;
-
- mutex_unlock(&fh->cap.vb_lock);
- return 0;
+ return setup_window_lock(fh, btv, &f->fmt.win, 1);
}
-#endif
static int bttv_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
@@ -2651,11 +2622,15 @@ static int bttv_querycap(struct file *file, void *priv,
V4L2_CAP_VBI_CAPTURE |
V4L2_CAP_READWRITE |
V4L2_CAP_STREAMING;
- if (btv->has_saa6588)
- cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (no_overlay <= 0)
cap->capabilities |= V4L2_CAP_VIDEO_OVERLAY;
+ /*
+ * No need to lock here: those vars are initialized during board
+ * probe and remains untouched during the rest of the driver lifecycle
+ */
+ if (btv->has_saa6588)
+ cap->capabilities |= V4L2_CAP_RDS_CAPTURE;
if (btv->tuner_type != TUNER_ABSENT)
cap->capabilities |= V4L2_CAP_TUNER;
return 0;
@@ -2730,22 +2705,24 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
struct bttv_buffer *new;
- int retval;
+ int retval = 0;
if (on) {
/* verify args */
- if (NULL == btv->fbuf.base)
+ if (unlikely(!btv->fbuf.base)) {
return -EINVAL;
- if (!fh->ov.setup_ok) {
+ }
+ if (unlikely(!fh->ov.setup_ok)) {
dprintk("bttv%d: overlay: !setup_ok\n", btv->c.nr);
- return -EINVAL;
+ retval = -EINVAL;
}
+ if (retval)
+ return retval;
}
- if (!check_alloc_btres(btv, fh, RESOURCE_OVERLAY))
+ if (!check_alloc_btres_lock(btv, fh, RESOURCE_OVERLAY))
return -EBUSY;
- mutex_lock(&fh->cap.vb_lock);
if (on) {
fh->ov.tvnorm = btv->tvnorm;
new = videobuf_sg_alloc(sizeof(*new));
@@ -2757,7 +2734,6 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
/* switch over */
retval = bttv_switch_overlay(btv, fh, new);
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2785,7 +2761,7 @@ static int bttv_s_fbuf(struct file *file, void *f,
__s32 width = fb->fmt.width;
__s32 height = fb->fmt.height;
- retval = limit_scaled_size(fh, &width, &height,
+ retval = limit_scaled_size_lock(fh, &width, &height,
V4L2_FIELD_INTERLACED,
/* width_mask */ ~3,
/* width_bias */ 2,
@@ -2796,7 +2772,6 @@ static int bttv_s_fbuf(struct file *file, void *f,
}
/* ok, accept it */
- mutex_lock(&fh->cap.vb_lock);
btv->fbuf.base = fb->base;
btv->fbuf.fmt.width = fb->fmt.width;
btv->fbuf.fmt.height = fb->fmt.height;
@@ -2828,7 +2803,6 @@ static int bttv_s_fbuf(struct file *file, void *f,
retval = bttv_switch_overlay(btv, fh, new);
}
}
- mutex_unlock(&fh->cap.vb_lock);
return retval;
}
@@ -2852,7 +2826,7 @@ static int bttv_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
struct bttv *btv = fh->btv;
int res = bttv_resource(fh);
- if (!check_alloc_btres(btv, fh, res))
+ if (!check_alloc_btres_lock(btv, fh, res))
return -EBUSY;
return videobuf_qbuf(bttv_queue(fh), b);
@@ -2872,7 +2846,7 @@ static int bttv_streamon(struct file *file, void *priv,
struct bttv *btv = fh->btv;
int res = bttv_resource(fh);
- if (!check_alloc_btres(btv, fh, res))
+ if (!check_alloc_btres_lock(btv, fh, res))
return -EBUSY;
return videobuf_streamon(bttv_queue(fh));
}
@@ -2890,7 +2864,7 @@ static int bttv_streamoff(struct file *file, void *priv,
retval = videobuf_streamoff(bttv_queue(fh));
if (retval < 0)
return retval;
- free_btres(btv, fh, res);
+ free_btres_lock(btv, fh, res);
return 0;
}
@@ -2926,6 +2900,7 @@ static int bttv_g_parm(struct file *file, void *f,
v4l2_video_std_frame_period(bttv_tvnorms[btv->tvnorm].v4l2_id,
&parm->parm.capture.timeperframe);
+
return 0;
}
@@ -2940,7 +2915,6 @@ static int bttv_g_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- mutex_lock(&btv->lock);
t->rxsubchans = V4L2_TUNER_SUB_MONO;
bttv_call_all(btv, tuner, g_tuner, t);
strcpy(t->name, "Television");
@@ -2952,7 +2926,6 @@ static int bttv_g_tuner(struct file *file, void *priv,
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 0);
- mutex_unlock(&btv->lock);
return 0;
}
@@ -2971,8 +2944,11 @@ static int bttv_s_priority(struct file *file, void *f,
{
struct bttv_fh *fh = f;
struct bttv *btv = fh->btv;
+ int rc;
- return v4l2_prio_change(&btv->prio, &fh->prio, prio);
+ rc = v4l2_prio_change(&btv->prio, &fh->prio, prio);
+
+ return rc;
}
static int bttv_cropcap(struct file *file, void *priv,
@@ -3024,19 +3000,17 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
crop->type != V4L2_BUF_TYPE_VIDEO_OVERLAY)
return -EINVAL;
- retval = v4l2_prio_check(&btv->prio, fh->prio);
- if (0 != retval)
- return retval;
-
/* Make sure tvnorm, vbi_end and the current cropping
parameters remain consistent until we're done. Note
- read() may change vbi_end in check_alloc_btres(). */
- mutex_lock(&btv->lock);
+ read() may change vbi_end in check_alloc_btres_lock(). */
+ retval = v4l2_prio_check(&btv->prio, fh->prio);
+ if (0 != retval) {
+ return retval;
+ }
retval = -EBUSY;
if (locked_btres(fh->btv, VIDEO_RESOURCES)) {
- mutex_unlock(&btv->lock);
return retval;
}
@@ -3048,7 +3022,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
b_top = max(b->top, btv->vbi_end);
if (b_top + 32 >= b_bottom) {
- mutex_unlock(&btv->lock);
return retval;
}
@@ -3071,12 +3044,8 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
btv->crop[1] = c;
- mutex_unlock(&btv->lock);
-
fh->do_crop = 1;
- mutex_lock(&fh->cap.vb_lock);
-
if (fh->width < c.min_scaled_width) {
fh->width = c.min_scaled_width;
btv->init.width = c.min_scaled_width;
@@ -3093,8 +3062,6 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
btv->init.height = c.max_scaled_height;
}
- mutex_unlock(&fh->cap.vb_lock);
-
return 0;
}
@@ -3128,17 +3095,17 @@ static ssize_t bttv_read(struct file *file, char __user *data,
switch (fh->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- if (!check_alloc_btres(fh->btv, fh, RESOURCE_VIDEO_READ)) {
+ if (!check_alloc_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ)) {
/* VIDEO_READ in use by another fh,
or VIDEO_STREAM by any fh. */
return -EBUSY;
}
retval = videobuf_read_one(&fh->cap, data, count, ppos,
file->f_flags & O_NONBLOCK);
- free_btres(fh->btv, fh, RESOURCE_VIDEO_READ);
+ free_btres_lock(fh->btv, fh, RESOURCE_VIDEO_READ);
break;
case V4L2_BUF_TYPE_VBI_CAPTURE:
- if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+ if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
return -EBUSY;
retval = videobuf_read_stream(&fh->vbi, data, count, ppos, 1,
file->f_flags & O_NONBLOCK);
@@ -3157,20 +3124,18 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
unsigned int rc = POLLERR;
if (V4L2_BUF_TYPE_VBI_CAPTURE == fh->type) {
- if (!check_alloc_btres(fh->btv,fh,RESOURCE_VBI))
+ if (!check_alloc_btres_lock(fh->btv,fh,RESOURCE_VBI))
return POLLERR;
return videobuf_poll_stream(file, &fh->vbi, wait);
}
if (check_btres(fh,RESOURCE_VIDEO_STREAM)) {
- mutex_lock(&fh->cap.vb_lock);
/* streaming capture */
if (list_empty(&fh->cap.stream))
goto err;
buf = list_entry(fh->cap.stream.next,struct bttv_buffer,vb.stream);
} else {
/* read() capture */
- mutex_lock(&fh->cap.vb_lock);
if (NULL == fh->cap.read_buf) {
/* need to capture a new frame */
if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
@@ -3188,7 +3153,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
fh->cap.ops->buf_queue(&fh->cap,fh->cap.read_buf);
fh->cap.read_off = 0;
}
- mutex_unlock(&fh->cap.vb_lock);
buf = (struct bttv_buffer*)fh->cap.read_buf;
}
@@ -3199,7 +3163,6 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
else
rc = 0;
err:
- mutex_unlock(&fh->cap.vb_lock);
return rc;
}
@@ -3221,21 +3184,20 @@ static int bttv_open(struct file *file)
return -ENODEV;
}
- lock_kernel();
-
dprintk(KERN_DEBUG "bttv%d: open called (type=%s)\n",
btv->c.nr,v4l2_type_names[type]);
/* allocate per filehandle data */
- fh = kmalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh) {
- unlock_kernel();
+ fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+ if (unlikely(!fh))
return -ENOMEM;
- }
file->private_data = fh;
+
*fh = btv->init;
+
fh->type = type;
fh->ov.setup_ok = 0;
+
v4l2_prio_open(&btv->prio, &fh->prio);
videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
@@ -3243,13 +3205,13 @@ static int bttv_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer),
- fh);
+ fh, &btv->lock);
videobuf_queue_sg_init(&fh->vbi, &bttv_vbi_qops,
&btv->c.pci->dev, &btv->s_lock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct bttv_buffer),
- fh);
+ fh, &btv->lock);
set_tvnorm(btv,btv->tvnorm);
set_input(btv, btv->input, btv->tvnorm);
@@ -3272,7 +3234,6 @@ static int bttv_open(struct file *file)
bttv_vbi_fmt_reset(&fh->vbi_fmt, btv->tvnorm);
bttv_field_count(btv);
- unlock_kernel();
return 0;
}
@@ -3288,23 +3249,24 @@ static int bttv_release(struct file *file)
/* stop video capture */
if (check_btres(fh, RESOURCE_VIDEO_STREAM)) {
videobuf_streamoff(&fh->cap);
- free_btres(btv,fh,RESOURCE_VIDEO_STREAM);
+ free_btres_lock(btv,fh,RESOURCE_VIDEO_STREAM);
}
if (fh->cap.read_buf) {
buffer_release(&fh->cap,fh->cap.read_buf);
kfree(fh->cap.read_buf);
}
if (check_btres(fh, RESOURCE_VIDEO_READ)) {
- free_btres(btv, fh, RESOURCE_VIDEO_READ);
+ free_btres_lock(btv, fh, RESOURCE_VIDEO_READ);
}
/* stop vbi capture */
if (check_btres(fh, RESOURCE_VBI)) {
videobuf_stop(&fh->vbi);
- free_btres(btv,fh,RESOURCE_VBI);
+ free_btres_lock(btv,fh,RESOURCE_VBI);
}
/* free stuff */
+
videobuf_mmap_free(&fh->cap);
videobuf_mmap_free(&fh->vbi);
v4l2_prio_close(&btv->prio, fh->prio);
@@ -3333,13 +3295,13 @@ bttv_mmap(struct file *file, struct vm_area_struct *vma)
static const struct v4l2_file_operations bttv_fops =
{
- .owner = THIS_MODULE,
- .open = bttv_open,
- .release = bttv_release,
- .ioctl = video_ioctl2,
- .read = bttv_read,
- .mmap = bttv_mmap,
- .poll = bttv_poll,
+ .owner = THIS_MODULE,
+ .open = bttv_open,
+ .release = bttv_release,
+ .unlocked_ioctl = video_ioctl2,
+ .read = bttv_read,
+ .mmap = bttv_mmap,
+ .poll = bttv_poll,
};
static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
@@ -3373,9 +3335,6 @@ static const struct v4l2_ioctl_ops bttv_ioctl_ops = {
.vidioc_streamoff = bttv_streamoff,
.vidioc_g_tuner = bttv_g_tuner,
.vidioc_s_tuner = bttv_s_tuner,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
.vidioc_g_crop = bttv_g_crop,
.vidioc_s_crop = bttv_s_crop,
.vidioc_g_fbuf = bttv_g_fbuf,
@@ -3412,29 +3371,22 @@ static int radio_open(struct file *file)
dprintk("bttv: open dev=%s\n", video_device_node_name(vdev));
- lock_kernel();
-
dprintk("bttv%d: open called (radio)\n",btv->c.nr);
/* allocate per filehandle data */
fh = kmalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh) {
- unlock_kernel();
+ if (unlikely(!fh))
return -ENOMEM;
- }
file->private_data = fh;
*fh = btv->init;
- v4l2_prio_open(&btv->prio, &fh->prio);
- mutex_lock(&btv->lock);
+ v4l2_prio_open(&btv->prio, &fh->prio);
btv->radio_user++;
bttv_call_all(btv, tuner, s_radio);
audio_input(btv,TVAUDIO_INPUT_RADIO);
- mutex_unlock(&btv->lock);
- unlock_kernel();
return 0;
}
@@ -3442,7 +3394,7 @@ static int radio_release(struct file *file)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- struct rds_command cmd;
+ struct saa6588_command cmd;
v4l2_prio_close(&btv->prio, fh->prio);
file->private_data = NULL;
@@ -3450,7 +3402,7 @@ static int radio_release(struct file *file)
btv->radio_user--;
- bttv_call_all(btv, core, ioctl, RDS_CMD_CLOSE, &cmd);
+ bttv_call_all(btv, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
return 0;
}
@@ -3479,7 +3431,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
return -EINVAL;
if (0 != t->index)
return -EINVAL;
- mutex_lock(&btv->lock);
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
@@ -3488,8 +3439,6 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (btv->audio_mode_gpio)
btv->audio_mode_gpio(btv, t, 0);
- mutex_unlock(&btv->lock);
-
return 0;
}
@@ -3580,13 +3529,13 @@ static ssize_t radio_read(struct file *file, char __user *data,
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- struct rds_command cmd;
+ struct saa6588_command cmd;
cmd.block_count = count/3;
cmd.buffer = data;
cmd.instance = file;
cmd.result = -ENODEV;
- bttv_call_all(btv, core, ioctl, RDS_CMD_READ, &cmd);
+ bttv_call_all(btv, core, ioctl, SAA6588_CMD_READ, &cmd);
return cmd.result;
}
@@ -3595,11 +3544,11 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
{
struct bttv_fh *fh = file->private_data;
struct bttv *btv = fh->btv;
- struct rds_command cmd;
+ struct saa6588_command cmd;
cmd.instance = file;
cmd.event_list = wait;
cmd.result = -ENODEV;
- bttv_call_all(btv, core, ioctl, RDS_CMD_POLL, &cmd);
+ bttv_call_all(btv, core, ioctl, SAA6588_CMD_POLL, &cmd);
return cmd.result;
}
@@ -3610,7 +3559,7 @@ static const struct v4l2_file_operations radio_fops =
.open = radio_open,
.read = radio_read,
.release = radio_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = radio_poll,
};
@@ -4070,9 +4019,6 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
btv=(struct bttv *)dev_id;
- if (btv->custom_irq)
- handled = btv->custom_irq(btv);
-
count=0;
while (1) {
/* get/clear interrupt status bits */
@@ -4108,7 +4054,6 @@ static irqreturn_t bttv_irq(int irq, void *dev_id)
btv->field_count++;
if ((astat & BT848_INT_GPINT) && btv->remote) {
- wake_up(&btv->gpioq);
bttv_input_irq(btv);
}
@@ -4313,7 +4258,6 @@ static int __devinit bttv_probe(struct pci_dev *dev,
mutex_init(&btv->lock);
spin_lock_init(&btv->s_lock);
spin_lock_init(&btv->gpio_lock);
- init_waitqueue_head(&btv->gpioq);
init_waitqueue_head(&btv->i2c_queue);
INIT_LIST_HEAD(&btv->c.subs);
INIT_LIST_HEAD(&btv->capture);
@@ -4491,6 +4435,9 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
if (bttv_verbose)
printk("bttv%d: unloading\n",btv->c.nr);
+ if (bttv_tvcards[btv->c.type].has_dvb)
+ flush_request_modules(btv);
+
/* shutdown everything (DMA+IRQs) */
btand(~15, BT848_GPIO_DMA_CTL);
btwrite(0, BT848_INT_MASK);
@@ -4501,7 +4448,6 @@ static void __devexit bttv_remove(struct pci_dev *pci_dev)
/* tell gpio modules we are leaving ... */
btv->shutdown=1;
- wake_up(&btv->gpioq);
bttv_input_fini(btv);
bttv_sub_del_devices(&btv->c);
diff --git a/drivers/media/video/bt8xx/bttv-i2c.c b/drivers/media/video/bt8xx/bttv-i2c.c
index 407fa61e4cda..d49b675045fe 100644
--- a/drivers/media/video/bt8xx/bttv-i2c.c
+++ b/drivers/media/video/bt8xx/bttv-i2c.c
@@ -121,9 +121,8 @@ bttv_i2c_wait_done(struct bttv *btv)
/* timeout */
if (wait_event_interruptible_timeout(btv->i2c_queue,
- btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
-
- rc = -EIO;
+ btv->i2c_done, msecs_to_jiffies(85)) == -ERESTARTSYS)
+ rc = -EIO;
if (btv->i2c_done & BT848_INT_RACK)
rc = 1;
@@ -390,41 +389,3 @@ int __devinit init_bttv_i2c(struct bttv *btv)
return btv->i2c_rc;
}
-
-/* Instantiate the I2C IR receiver device, if present */
-void __devinit init_bttv_i2c_ir(struct bttv *btv)
-{
- if (0 == btv->i2c_rc) {
- struct i2c_board_info info;
- /* The external IR receiver is at i2c address 0x34 (0x35 for
- reads). Future Hauppauge cards will have an internal
- receiver at 0x30 (0x31 for reads). In theory, both can be
- fitted, and Hauppauge suggest an external overrides an
- internal.
-
- That's why we probe 0x1a (~0x34) first. CB
- */
- const unsigned short addr_list[] = {
- 0x1a, 0x18, 0x4b, 0x64, 0x30, 0x71,
- I2C_CLIENT_END
- };
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list);
- }
-}
-
-int __devexit fini_bttv_i2c(struct bttv *btv)
-{
- if (0 != btv->i2c_rc)
- return 0;
-
- return i2c_del_adapter(&btv->c.i2c_adap);
-}
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index f68717a4bdec..e8b64bca9db2 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -31,15 +31,9 @@
static int ir_debug;
module_param(ir_debug, int, 0644);
-static int repeat_delay = 500;
-module_param(repeat_delay, int, 0644);
-static int repeat_period = 33;
-module_param(repeat_period, int, 0644);
static int ir_rc5_remote_gap = 885;
module_param(ir_rc5_remote_gap, int, 0644);
-static int ir_rc5_key_timeout = 200;
-module_param(ir_rc5_key_timeout, int, 0644);
#undef dprintk
#define dprintk(arg...) do { \
@@ -55,7 +49,7 @@ module_param(ir_rc5_key_timeout, int, 0644);
static void ir_handle_key(struct bttv *btv)
{
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
u32 gpio,data;
/* read gpio value */
@@ -74,23 +68,22 @@ static void ir_handle_key(struct bttv *btv)
(gpio & ir->mask_keydown) ? " down" : "",
(gpio & ir->mask_keyup) ? " up" : "");
- if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
- (ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- ir_input_keydown(ir->dev, &ir->ir, data);
+ if ((ir->mask_keydown && (gpio & ir->mask_keydown)) ||
+ (ir->mask_keyup && !(gpio & ir->mask_keyup))) {
+ rc_keydown_notimeout(ir->dev, data, 0);
} else {
/* HACK: Probably, ir->mask_keydown is missing
for this board */
if (btv->c.type == BTTV_BOARD_WINFAST2000)
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
- ir_input_nokey(ir->dev,&ir->ir);
+ rc_keyup(ir->dev);
}
-
}
static void ir_enltv_handle_key(struct bttv *btv)
{
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
u32 gpio, data, keyup;
/* read gpio value */
@@ -107,9 +100,9 @@ static void ir_enltv_handle_key(struct bttv *btv)
gpio, data,
(gpio & ir->mask_keyup) ? " up" : "up/down");
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
if (keyup)
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keyup(ir->dev);
} else {
if ((ir->last_gpio & 1 << 31) == keyup)
return;
@@ -119,26 +112,30 @@ static void ir_enltv_handle_key(struct bttv *btv)
(gpio & ir->mask_keyup) ? " up" : "down");
if (keyup)
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keyup(ir->dev);
else
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
}
ir->last_gpio = data | keyup;
}
+static int bttv_rc5_irq(struct bttv *btv);
+
void bttv_input_irq(struct bttv *btv)
{
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
- if (!ir->polling)
+ if (ir->rc5_gpio)
+ bttv_rc5_irq(btv);
+ else if (!ir->polling)
ir_handle_key(btv);
}
static void bttv_input_timer(unsigned long data)
{
struct bttv *btv = (struct bttv*)data;
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
if (btv->c.type == BTTV_BOARD_ENLTV_FM_2)
ir_enltv_handle_key(btv);
@@ -147,11 +144,109 @@ static void bttv_input_timer(unsigned long data)
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
-/* ---------------------------------------------------------------*/
+/*
+ * FIXME: Nebula digi uses the legacy way to decode RC5, instead of relying
+ * on the rc-core way. As we need to be sure that both IRQ transitions are
+ * properly triggered, Better to touch it only with this hardware for
+ * testing.
+ */
+
+#define RC5_START(x) (((x) >> 12) & 3)
+#define RC5_TOGGLE(x) (((x) >> 11) & 1)
+#define RC5_ADDR(x) (((x) >> 6) & 31)
+#define RC5_INSTR(x) ((x) & 63)
+
+/* decode raw bit pattern to RC5 code */
+static u32 bttv_rc5_decode(unsigned int code)
+{
+ unsigned int org_code = code;
+ unsigned int pair;
+ unsigned int rc5 = 0;
+ int i;
+
+ for (i = 0; i < 14; ++i) {
+ pair = code & 0x3;
+ code >>= 2;
+
+ rc5 <<= 1;
+ switch (pair) {
+ case 0:
+ case 2:
+ break;
+ case 1:
+ rc5 |= 1;
+ break;
+ case 3:
+ dprintk(KERN_INFO DEVNAME ":rc5_decode(%x) bad code\n",
+ org_code);
+ return 0;
+ }
+ }
+ dprintk(KERN_INFO DEVNAME ":"
+ "code=%x, rc5=%x, start=%x, toggle=%x, address=%x, "
+ "instr=%x\n", rc5, org_code, RC5_START(rc5),
+ RC5_TOGGLE(rc5), RC5_ADDR(rc5), RC5_INSTR(rc5));
+ return rc5;
+}
+
+static void bttv_rc5_timer_end(unsigned long data)
+{
+ struct bttv_ir *ir = (struct bttv_ir *)data;
+ struct timeval tv;
+ unsigned long current_jiffies;
+ u32 gap;
+ u32 rc5 = 0;
+
+ /* get time */
+ current_jiffies = jiffies;
+ do_gettimeofday(&tv);
+
+ /* avoid overflow with gap >1s */
+ if (tv.tv_sec - ir->base_time.tv_sec > 1) {
+ gap = 200000;
+ } else {
+ gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
+ tv.tv_usec - ir->base_time.tv_usec;
+ }
+
+ /* signal we're ready to start a new code */
+ ir->active = false;
+
+ /* Allow some timer jitter (RC5 is ~24ms anyway so this is ok) */
+ if (gap < 28000) {
+ dprintk(KERN_INFO DEVNAME ": spurious timer_end\n");
+ return;
+ }
+
+ if (ir->last_bit < 20) {
+ /* ignore spurious codes (caused by light/other remotes) */
+ dprintk(KERN_INFO DEVNAME ": short code: %x\n", ir->code);
+ } else {
+ ir->code = (ir->code << ir->shift_by) | 1;
+ rc5 = bttv_rc5_decode(ir->code);
+
+ /* two start bits? */
+ if (RC5_START(rc5) != ir->start) {
+ printk(KERN_INFO DEVNAME ":"
+ " rc5 start bits invalid: %u\n", RC5_START(rc5));
+
+ /* right address? */
+ } else if (RC5_ADDR(rc5) == ir->addr) {
+ u32 toggle = RC5_TOGGLE(rc5);
+ u32 instr = RC5_INSTR(rc5);
+
+ /* Good code */
+ rc_keydown(ir->dev, instr, toggle);
+ dprintk(KERN_INFO DEVNAME ":"
+ " instruction %x, toggle %x\n",
+ instr, toggle);
+ }
+ }
+}
static int bttv_rc5_irq(struct bttv *btv)
{
- struct card_ir *ir = btv->remote;
+ struct bttv_ir *ir = btv->remote;
struct timeval tv;
u32 gpio;
u32 gap;
@@ -160,10 +255,6 @@ static int bttv_rc5_irq(struct bttv *btv)
/* read gpio port */
gpio = bttv_gpio_read(&btv->c);
- /* remote IRQ? */
- if (!(gpio & 0x20))
- return 0;
-
/* get time of bit */
current_jiffies = jiffies;
do_gettimeofday(&tv);
@@ -176,6 +267,13 @@ static int bttv_rc5_irq(struct bttv *btv)
tv.tv_usec - ir->base_time.tv_usec;
}
+ dprintk(KERN_INFO DEVNAME ": RC5 IRQ: gap %d us for %s\n",
+ gap, (gpio & 0x20) ? "mark" : "space");
+
+ /* remote IRQ? */
+ if (!(gpio & 0x20))
+ return 0;
+
/* active code => add bit */
if (ir->active) {
/* only if in the code (otherwise spurious IRQ or timer
@@ -187,13 +285,12 @@ static int bttv_rc5_irq(struct bttv *btv)
}
/* starting new code */
} else {
- ir->active = 1;
+ ir->active = true;
ir->code = 0;
ir->base_time = tv;
ir->last_bit = 0;
- mod_timer(&ir->timer_end,
- current_jiffies + msecs_to_jiffies(30));
+ mod_timer(&ir->timer, current_jiffies + msecs_to_jiffies(30));
}
/* toggle GPIO pin 4 to reset the irq */
@@ -204,7 +301,7 @@ static int bttv_rc5_irq(struct bttv *btv)
/* ---------------------------------------------------------------------- */
-static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
+static void bttv_ir_start(struct bttv *btv, struct bttv_ir *ir)
{
if (ir->polling) {
setup_timer(&ir->timer, bttv_input_timer, (unsigned long)btv);
@@ -212,53 +309,130 @@ static void bttv_ir_start(struct bttv *btv, struct card_ir *ir)
add_timer(&ir->timer);
} else if (ir->rc5_gpio) {
/* set timer_end for code completion */
- init_timer(&ir->timer_end);
- ir->timer_end.function = ir_rc5_timer_end;
- ir->timer_end.data = (unsigned long)ir;
-
- init_timer(&ir->timer_keyup);
- ir->timer_keyup.function = ir_rc5_timer_keyup;
- ir->timer_keyup.data = (unsigned long)ir;
+ setup_timer(&ir->timer, bttv_rc5_timer_end, (unsigned long)ir);
ir->shift_by = 1;
ir->start = 3;
ir->addr = 0x0;
- ir->rc5_key_timeout = ir_rc5_key_timeout;
ir->rc5_remote_gap = ir_rc5_remote_gap;
}
}
static void bttv_ir_stop(struct bttv *btv)
{
- if (btv->remote->polling) {
+ if (btv->remote->polling)
del_timer_sync(&btv->remote->timer);
- flush_scheduled_work();
- }
if (btv->remote->rc5_gpio) {
u32 gpio;
- del_timer_sync(&btv->remote->timer_end);
- flush_scheduled_work();
+ del_timer_sync(&btv->remote->timer);
gpio = bttv_gpio_read(&btv->c);
bttv_gpio_write(&btv->c, gpio & ~(1 << 4));
}
}
+/*
+ * Get_key functions used by I2C remotes
+ */
+
+static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char b;
+
+ /* poll IR chip */
+ if (1 != i2c_master_recv(ir->c, &b, 1)) {
+ dprintk(KERN_INFO DEVNAME ": read error\n");
+ return -EIO;
+ }
+
+ /* ignore 0xaa */
+ if (b==0xaa)
+ return 0;
+ dprintk(KERN_INFO DEVNAME ": key %02x\n", b);
+
+ /*
+ * NOTE:
+ * lirc_i2c maps the pv951 code as:
+ * addr = 0x61D6
+ * cmd = bit_reverse (b)
+ * So, it seems that this device uses NEC extended
+ * I decided to not fix the table, due to two reasons:
+ * 1) Without the actual device, this is only a guess;
+ * 2) As the addr is not reported via I2C, nor can be changed,
+ * the device is bound to the vendor-provided RC.
+ */
+
+ *ir_key = b;
+ *ir_raw = b;
+ return 1;
+}
+
+/* Instantiate the I2C IR receiver device, if present */
+void __devinit init_bttv_i2c_ir(struct bttv *btv)
+{
+ const unsigned short addr_list[] = {
+ 0x1a, 0x18, 0x64, 0x30, 0x71,
+ I2C_CLIENT_END
+ };
+ struct i2c_board_info info;
+
+ if (0 != btv->i2c_rc)
+ return;
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&btv->init_data, 0, sizeof(btv->init_data));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+
+ switch (btv->c.type) {
+ case BTTV_BOARD_PV951:
+ btv->init_data.name = "PV951";
+ btv->init_data.get_key = get_key_pv951;
+ btv->init_data.ir_codes = RC_MAP_PV951;
+ info.addr = 0x4b;
+ break;
+ default:
+ /*
+ * The external IR receiver is at i2c address 0x34 (0x35 for
+ * reads). Future Hauppauge cards will have an internal
+ * receiver at 0x30 (0x31 for reads). In theory, both can be
+ * fitted, and Hauppauge suggest an external overrides an
+ * internal.
+ * That's why we probe 0x1a (~0x34) first. CB
+ */
+
+ i2c_new_probed_device(&btv->c.i2c_adap, &info, addr_list, NULL);
+ return;
+ }
+
+ if (btv->init_data.name)
+ info.platform_data = &btv->init_data;
+ i2c_new_device(&btv->c.i2c_adap, &info);
+
+ return;
+}
+
+int __devexit fini_bttv_i2c(struct bttv *btv)
+{
+ if (0 != btv->i2c_rc)
+ return 0;
+
+ return i2c_del_adapter(&btv->c.i2c_adap);
+}
+
int bttv_input_init(struct bttv *btv)
{
- struct card_ir *ir;
+ struct bttv_ir *ir;
char *ir_codes = NULL;
- struct input_dev *input_dev;
- u64 ir_type = IR_TYPE_OTHER;
+ struct rc_dev *rc;
int err = -ENOMEM;
if (!btv->has_remote)
return -ENODEV;
ir = kzalloc(sizeof(*ir),GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
+ rc = rc_allocate_device();
+ if (!ir || !rc)
goto err_out_free;
/* detect & configure */
@@ -321,8 +495,7 @@ int bttv_input_init(struct bttv *btv)
break;
case BTTV_BOARD_NEBULA_DIGITV:
ir_codes = RC_MAP_NEBULA;
- btv->custom_irq = bttv_rc5_irq;
- ir->rc5_gpio = 1;
+ ir->rc5_gpio = true;
break;
case BTTV_BOARD_MACHTV_MAGICTV:
ir_codes = RC_MAP_APAC_VIEWCOMP;
@@ -364,48 +537,43 @@ int bttv_input_init(struct bttv *btv)
}
/* init input device */
- ir->dev = input_dev;
+ ir->dev = rc;
snprintf(ir->name, sizeof(ir->name), "bttv IR (card=%d)",
btv->c.type);
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
pci_name(btv->c.pci));
- err = ir_input_init(input_dev, &ir->ir, ir_type);
- if (err < 0)
- goto err_out_free;
-
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
if (btv->c.pci->subsystem_vendor) {
- input_dev->id.vendor = btv->c.pci->subsystem_vendor;
- input_dev->id.product = btv->c.pci->subsystem_device;
+ rc->input_id.vendor = btv->c.pci->subsystem_vendor;
+ rc->input_id.product = btv->c.pci->subsystem_device;
} else {
- input_dev->id.vendor = btv->c.pci->vendor;
- input_dev->id.product = btv->c.pci->device;
+ rc->input_id.vendor = btv->c.pci->vendor;
+ rc->input_id.product = btv->c.pci->device;
}
- input_dev->dev.parent = &btv->c.pci->dev;
+ rc->dev.parent = &btv->c.pci->dev;
+ rc->map_name = ir_codes;
+ rc->driver_name = MODULE_NAME;
btv->remote = ir;
bttv_ir_start(btv, ir);
/* all done */
- err = ir_input_register(btv->remote->dev, ir_codes, NULL, MODULE_NAME);
+ err = rc_register_device(rc);
if (err)
goto err_out_stop;
- /* the remote isn't as bouncy as a keyboard */
- ir->dev->rep[REP_DELAY] = repeat_delay;
- ir->dev->rep[REP_PERIOD] = repeat_period;
-
return 0;
err_out_stop:
bttv_ir_stop(btv);
btv->remote = NULL;
err_out_free:
+ rc_free_device(rc);
kfree(ir);
return err;
}
@@ -416,14 +584,7 @@ void bttv_input_fini(struct bttv *btv)
return;
bttv_ir_stop(btv);
- ir_input_unregister(btv->remote->dev);
+ rc_unregister_device(btv->remote->dev);
kfree(btv->remote);
btv->remote = NULL;
}
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/bt8xx/bttv-risc.c b/drivers/media/video/bt8xx/bttv-risc.c
index c24b1c100e13..9b57d091da48 100644
--- a/drivers/media/video/bt8xx/bttv-risc.c
+++ b/drivers/media/video/bt8xx/bttv-risc.c
@@ -582,8 +582,8 @@ bttv_dma_free(struct videobuf_queue *q,struct bttv *btv, struct bttv_buffer *buf
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(btv->c.pci,&buf->bottom);
btcx_riscmem_free(btv->c.pci,&buf->top);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index 3ec2402c6b4a..c6333595c6b9 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -17,8 +17,6 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
-#include <media/ir-common.h>
-#include <media/ir-kbd-i2c.h>
#include <media/i2c-addr.h>
#include <media/tuner.h>
@@ -236,7 +234,6 @@ struct tvcard {
/* i2c audio flags */
unsigned int no_msp34xx:1;
- unsigned int no_tda9875:1;
unsigned int no_tda7432:1;
unsigned int needs_tvaudio:1;
unsigned int msp34xx_alt:1;
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 6cccc2a17eee..9b776faf0741 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -41,8 +41,8 @@
#include <linux/device.h>
#include <media/videobuf-dma-sg.h>
#include <media/tveeprom.h>
-#include <media/ir-common.h>
-
+#include <media/rc-core.h>
+#include <media/ir-kbd-i2c.h>
#include "bt848.h"
#include "bttv.h"
@@ -120,6 +120,33 @@ struct bttv_format {
int hshift,vshift; /* for planar modes */
};
+struct bttv_ir {
+ struct rc_dev *dev;
+ struct timer_list timer;
+
+ char name[32];
+ char phys[32];
+
+ /* Usual gpio signalling */
+ u32 mask_keycode;
+ u32 mask_keydown;
+ u32 mask_keyup;
+ u32 polling;
+ u32 last_gpio;
+ int shift_by;
+ int start; // What should RC5_START() be
+ int addr; // What RC5_ADDR() should be.
+ int rc5_remote_gap;
+
+ /* RC5 gpio */
+ bool rc5_gpio; /* Is RC5 legacy GPIO enabled? */
+ u32 last_bit; /* last raw bit seen */
+ u32 code; /* raw code under construction */
+ struct timeval base_time; /* time of last seen code */
+ bool active; /* building raw code */
+};
+
+
/* ---------------------------------------------------------- */
struct bttv_geometry {
@@ -271,6 +298,12 @@ int bttv_sub_del_devices(struct bttv_core *core);
extern int no_overlay;
/* ---------------------------------------------------------- */
+/* bttv-input.c */
+
+extern void init_bttv_i2c_ir(struct bttv *btv);
+extern int fini_bttv_i2c(struct bttv *btv);
+
+/* ---------------------------------------------------------- */
/* bttv-driver.c */
/* insmod options */
@@ -279,8 +312,6 @@ extern unsigned int bttv_debug;
extern unsigned int bttv_gpio;
extern void bttv_gpio_tracking(struct bttv *btv, char *comment);
extern int init_bttv_i2c(struct bttv *btv);
-extern void init_bttv_i2c_ir(struct bttv *btv);
-extern int fini_bttv_i2c(struct bttv *btv);
#define bttv_printk if (bttv_verbose) printk
#define dprintk if (bttv_debug >= 1) printk
@@ -301,7 +332,6 @@ struct bttv_pll_info {
/* for gpio-connected remote control */
struct bttv_input {
struct input_dev *dev;
- struct ir_input_state ir;
char name[32];
char phys[32];
u32 mask_keycode;
@@ -334,12 +364,10 @@ struct bttv {
struct bttv_pll_info pll;
int triton1;
int gpioirq;
- int (*custom_irq)(struct bttv *btv);
int use_i2c_hw;
/* old gpio interface */
- wait_queue_head_t gpioq;
int shutdown;
void (*volume_gpio)(struct bttv *btv, __u16 volume);
@@ -364,7 +392,10 @@ struct bttv {
/* infrared remote */
int has_remote;
- struct card_ir *remote;
+ struct bttv_ir *remote;
+
+ /* I2C remote data */
+ struct IR_i2c_init_data init_data;
/* locking */
spinlock_t s_lock;
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 3c9e754d73a0..c1193506131c 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -66,19 +66,58 @@ OTHER DEALINGS IN THE SOFTWARE.
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/fs.h>
-#include <linux/init.h>
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/mm.h>
#include <linux/parport.h>
#include <linux/sched.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
+#include <linux/version.h>
+#include <linux/videodev2.h>
#include <linux/mutex.h>
#include <asm/uaccess.h>
-
-#include "bw-qcam.h"
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+
+/* One from column A... */
+#define QC_NOTSET 0
+#define QC_UNIDIR 1
+#define QC_BIDIR 2
+#define QC_SERIAL 3
+
+/* ... and one from column B */
+#define QC_ANY 0x00
+#define QC_FORCE_UNIDIR 0x10
+#define QC_FORCE_BIDIR 0x20
+#define QC_FORCE_SERIAL 0x30
+/* in the port_mode member */
+
+#define QC_MODE_MASK 0x07
+#define QC_FORCE_MASK 0x70
+
+#define MAX_HEIGHT 243
+#define MAX_WIDTH 336
+
+/* Bit fields for status flags */
+#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */
+
+struct qcam {
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct pardevice *pdev;
+ struct parport *pport;
+ struct mutex lock;
+ int width, height;
+ int bpp;
+ int mode;
+ int contrast, brightness, whitebal;
+ int port_mode;
+ int transfer_scale;
+ int top, left;
+ int status;
+ unsigned int saved_bits;
+ unsigned long in_use;
+};
static unsigned int maxpoll = 250; /* Maximum busy-loop count for qcam I/O */
static unsigned int yieldlines = 4; /* Yield after this many during capture */
@@ -93,22 +132,26 @@ module_param(video_nr, int, 0);
* immediately attempt to initialize qcam */
module_param(force_init, int, 0);
-static inline int read_lpstatus(struct qcam_device *q)
+#define MAX_CAMS 4
+static struct qcam *qcams[MAX_CAMS];
+static unsigned int num_cams;
+
+static inline int read_lpstatus(struct qcam *q)
{
return parport_read_status(q->pport);
}
-static inline int read_lpdata(struct qcam_device *q)
+static inline int read_lpdata(struct qcam *q)
{
return parport_read_data(q->pport);
}
-static inline void write_lpdata(struct qcam_device *q, int d)
+static inline void write_lpdata(struct qcam *q, int d)
{
parport_write_data(q->pport, d);
}
-static inline void write_lpcontrol(struct qcam_device *q, int d)
+static void write_lpcontrol(struct qcam *q, int d)
{
if (d & 0x20) {
/* Set bidirectional mode to reverse (data in) */
@@ -124,126 +167,11 @@ static inline void write_lpcontrol(struct qcam_device *q, int d)
parport_write_control(q->pport, d);
}
-static int qc_waithand(struct qcam_device *q, int val);
-static int qc_command(struct qcam_device *q, int command);
-static int qc_readparam(struct qcam_device *q);
-static int qc_setscanmode(struct qcam_device *q);
-static int qc_readbytes(struct qcam_device *q, char buffer[]);
-
-static struct video_device qcam_template;
-
-static int qc_calibrate(struct qcam_device *q)
-{
- /*
- * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
- * The white balance is an individiual value for each
- * quickcam.
- */
-
- int value;
- int count = 0;
-
- qc_command(q, 27); /* AutoAdjustOffset */
- qc_command(q, 0); /* Dummy Parameter, ignored by the camera */
-
- /* GetOffset (33) will read 255 until autocalibration */
- /* is finished. After that, a value of 1-254 will be */
- /* returned. */
-
- do {
- qc_command(q, 33);
- value = qc_readparam(q);
- mdelay(1);
- schedule();
- count++;
- } while (value == 0xff && count < 2048);
-
- q->whitebal = value;
- return value;
-}
-
-/* Initialize the QuickCam driver control structure. This is where
- * defaults are set for people who don't have a config file.*/
-
-static struct qcam_device *qcam_init(struct parport *port)
-{
- struct qcam_device *q;
-
- q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
- if (q == NULL)
- return NULL;
-
- q->pport = port;
- q->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
- NULL, 0, NULL);
- if (q->pdev == NULL) {
- printk(KERN_ERR "bw-qcam: couldn't register for %s.\n",
- port->name);
- kfree(q);
- return NULL;
- }
-
- memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
-
- mutex_init(&q->lock);
-
- q->port_mode = (QC_ANY | QC_NOTSET);
- q->width = 320;
- q->height = 240;
- q->bpp = 4;
- q->transfer_scale = 2;
- q->contrast = 192;
- q->brightness = 180;
- q->whitebal = 105;
- q->top = 1;
- q->left = 14;
- q->mode = -1;
- q->status = QC_PARAM_CHANGE;
- return q;
-}
-
-
-/* qc_command is probably a bit of a misnomer -- it's used to send
- * bytes *to* the camera. Generally, these bytes are either commands
- * or arguments to commands, so the name fits, but it still bugs me a
- * bit. See the documentation for a list of commands. */
-
-static int qc_command(struct qcam_device *q, int command)
-{
- int n1, n2;
- int cmd;
-
- write_lpdata(q, command);
- write_lpcontrol(q, 6);
-
- n1 = qc_waithand(q, 1);
-
- write_lpcontrol(q, 0xe);
- n2 = qc_waithand(q, 0);
-
- cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
- return cmd;
-}
-
-static int qc_readparam(struct qcam_device *q)
-{
- int n1, n2;
- int cmd;
-
- write_lpcontrol(q, 6);
- n1 = qc_waithand(q, 1);
-
- write_lpcontrol(q, 0xe);
- n2 = qc_waithand(q, 0);
-
- cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
- return cmd;
-}
/* qc_waithand busy-waits for a handshake signal from the QuickCam.
* Almost all communication with the camera requires handshaking. */
-static int qc_waithand(struct qcam_device *q, int val)
+static int qc_waithand(struct qcam *q, int val)
{
int status;
int runs = 0;
@@ -286,7 +214,7 @@ static int qc_waithand(struct qcam_device *q, int val)
* (bit 3 of status register). It also returns the last value read,
* since this data is useful. */
-static unsigned int qc_waithand2(struct qcam_device *q, int val)
+static unsigned int qc_waithand2(struct qcam *q, int val)
{
unsigned int status;
int runs = 0;
@@ -309,6 +237,43 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
return status;
}
+/* qc_command is probably a bit of a misnomer -- it's used to send
+ * bytes *to* the camera. Generally, these bytes are either commands
+ * or arguments to commands, so the name fits, but it still bugs me a
+ * bit. See the documentation for a list of commands. */
+
+static int qc_command(struct qcam *q, int command)
+{
+ int n1, n2;
+ int cmd;
+
+ write_lpdata(q, command);
+ write_lpcontrol(q, 6);
+
+ n1 = qc_waithand(q, 1);
+
+ write_lpcontrol(q, 0xe);
+ n2 = qc_waithand(q, 0);
+
+ cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+ return cmd;
+}
+
+static int qc_readparam(struct qcam *q)
+{
+ int n1, n2;
+ int cmd;
+
+ write_lpcontrol(q, 6);
+ n1 = qc_waithand(q, 1);
+
+ write_lpcontrol(q, 0xe);
+ n2 = qc_waithand(q, 0);
+
+ cmd = (n1 & 0xf0) | ((n2 & 0xf0) >> 4);
+ return cmd;
+}
+
/* Try to detect a QuickCam. It appears to flash the upper 4 bits of
the status register at 5-10 Hz. This is only used in the autoprobe
@@ -317,7 +282,7 @@ static unsigned int qc_waithand2(struct qcam_device *q, int val)
almost completely safe, while their method screws up my printer if
I plug it in before the camera. */
-static int qc_detect(struct qcam_device *q)
+static int qc_detect(struct qcam *q)
{
int reg, lastreg;
int count = 0;
@@ -358,41 +323,6 @@ static int qc_detect(struct qcam_device *q)
}
}
-
-/* Reset the QuickCam. This uses the same sequence the Windows
- * QuickPic program uses. Someone with a bi-directional port should
- * check that bi-directional mode is detected right, and then
- * implement bi-directional mode in qc_readbyte(). */
-
-static void qc_reset(struct qcam_device *q)
-{
- switch (q->port_mode & QC_FORCE_MASK) {
- case QC_FORCE_UNIDIR:
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
- break;
-
- case QC_FORCE_BIDIR:
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
- break;
-
- case QC_ANY:
- write_lpcontrol(q, 0x20);
- write_lpdata(q, 0x75);
-
- if (read_lpdata(q) != 0x75)
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
- else
- q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
- break;
- }
-
- write_lpcontrol(q, 0xb);
- udelay(250);
- write_lpcontrol(q, 0xe);
- qc_setscanmode(q); /* in case port_mode changed */
-}
-
-
/* Decide which scan mode to use. There's no real requirement that
* the scanmode match the resolution in q->height and q-> width -- the
* camera takes the picture at the resolution specified in the
@@ -402,7 +332,7 @@ static void qc_reset(struct qcam_device *q)
* returned. If the scan is smaller, then the rest of the image
* returned contains garbage. */
-static int qc_setscanmode(struct qcam_device *q)
+static int qc_setscanmode(struct qcam *q)
{
int old_mode = q->mode;
@@ -442,10 +372,45 @@ static int qc_setscanmode(struct qcam_device *q)
}
+/* Reset the QuickCam. This uses the same sequence the Windows
+ * QuickPic program uses. Someone with a bi-directional port should
+ * check that bi-directional mode is detected right, and then
+ * implement bi-directional mode in qc_readbyte(). */
+
+static void qc_reset(struct qcam *q)
+{
+ switch (q->port_mode & QC_FORCE_MASK) {
+ case QC_FORCE_UNIDIR:
+ q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+ break;
+
+ case QC_FORCE_BIDIR:
+ q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+ break;
+
+ case QC_ANY:
+ write_lpcontrol(q, 0x20);
+ write_lpdata(q, 0x75);
+
+ if (read_lpdata(q) != 0x75)
+ q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_BIDIR;
+ else
+ q->port_mode = (q->port_mode & ~QC_MODE_MASK) | QC_UNIDIR;
+ break;
+ }
+
+ write_lpcontrol(q, 0xb);
+ udelay(250);
+ write_lpcontrol(q, 0xe);
+ qc_setscanmode(q); /* in case port_mode changed */
+}
+
+
+
/* Reset the QuickCam and program for brightness, contrast,
* white-balance, and resolution. */
-static void qc_set(struct qcam_device *q)
+static void qc_set(struct qcam *q)
{
int val;
int val2;
@@ -499,7 +464,7 @@ static void qc_set(struct qcam_device *q)
the supplied buffer. It returns the number of bytes read,
or -1 on error. */
-static inline int qc_readbytes(struct qcam_device *q, char buffer[])
+static inline int qc_readbytes(struct qcam *q, char buffer[])
{
int ret = 1;
unsigned int hi, lo;
@@ -590,7 +555,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
* n=2^(bit depth)-1. Ask me for more details if you don't understand
* this. */
-static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam *q, char __user *buf, unsigned long len)
{
int i, j, k, yield;
int bytes;
@@ -674,171 +639,206 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
* Video4linux interfacing
*/
-static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int qcam_querycap(struct file *file, void *priv,
+ struct v4l2_capability *vcap)
{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
- strcpy(b->name, "Quickcam");
- b->type = VID_TYPE_CAPTURE|VID_TYPE_SCALES|VID_TYPE_MONOCHROME;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = 320;
- b->maxheight = 240;
- b->minwidth = 80;
- b->minheight = 60;
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- /* Good question.. its composite or SVHS so.. */
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Camera");
- return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGTUNER:
- {
- struct video_tuner *v = arg;
- if (v->tuner)
- return -EINVAL;
- strcpy(v->name, "Format");
- v->rangelow = 0;
- v->rangehigh = 0;
- v->flags = 0;
- v->mode = VIDEO_MODE_AUTO;
- return 0;
- }
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
- if (v->tuner)
- return -EINVAL;
- if (v->mode != VIDEO_MODE_AUTO)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
- p->colour = 0x8000;
- p->hue = 0x8000;
- p->brightness = qcam->brightness << 8;
- p->contrast = qcam->contrast << 8;
- p->whiteness = qcam->whitebal << 8;
- p->depth = qcam->bpp;
- p->palette = VIDEO_PALETTE_GREY;
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
- if (p->palette != VIDEO_PALETTE_GREY)
- return -EINVAL;
- if (p->depth != 4 && p->depth != 6)
- return -EINVAL;
-
- /*
- * Now load the camera.
- */
-
- qcam->brightness = p->brightness >> 8;
- qcam->contrast = p->contrast >> 8;
- qcam->whitebal = p->whiteness >> 8;
- qcam->bpp = p->depth;
-
- mutex_lock(&qcam->lock);
- qc_setscanmode(qcam);
- mutex_unlock(&qcam->lock);
- qcam->status |= QC_PARAM_CHANGE;
+ struct qcam *qcam = video_drvdata(file);
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->height < 60 || vw->height > 240)
- return -EINVAL;
- if (vw->width < 80 || vw->width > 320)
- return -EINVAL;
-
- qcam->width = 320;
- qcam->height = 240;
- qcam->transfer_scale = 4;
-
- if (vw->width >= 160 && vw->height >= 120)
- qcam->transfer_scale = 2;
- if (vw->width >= 320 && vw->height >= 240) {
- qcam->width = 320;
- qcam->height = 240;
- qcam->transfer_scale = 1;
- }
- mutex_lock(&qcam->lock);
- qc_setscanmode(qcam);
- mutex_unlock(&qcam->lock);
+ strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
+ strlcpy(vcap->card, "B&W Quickcam", sizeof(vcap->card));
+ strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+ vcap->version = KERNEL_VERSION(0, 0, 2);
+ vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ return 0;
+}
- /* We must update the camera before we grab. We could
- just have changed the grab size */
- qcam->status |= QC_PARAM_CHANGE;
+static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+ if (vin->index > 0)
+ return -EINVAL;
+ strlcpy(vin->name, "Camera", sizeof(vin->name));
+ vin->type = V4L2_INPUT_TYPE_CAMERA;
+ vin->audioset = 0;
+ vin->tuner = 0;
+ vin->std = 0;
+ vin->status = 0;
+ return 0;
+}
- /* Ok we figured out what to use from our wide choice */
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
+static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+ *inp = 0;
+ return 0;
+}
- memset(vw, 0, sizeof(*vw));
- vw->width = qcam->width / qcam->transfer_scale;
- vw->height = qcam->height / qcam->transfer_scale;
- return 0;
- }
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
+static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+ return (inp > 0) ? -EINVAL : 0;
+}
+
+static int qcam_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 180);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
+ case V4L2_CID_GAMMA:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 105);
+ }
+ return -EINVAL;
+}
+
+static int qcam_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct qcam *qcam = video_drvdata(file);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = qcam->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = qcam->contrast;
+ break;
+ case V4L2_CID_GAMMA:
+ ctrl->value = qcam->whitebal;
+ break;
default:
- return -ENOIOCTLCMD;
+ ret = -EINVAL;
+ break;
}
+ return ret;
+}
+
+static int qcam_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct qcam *qcam = video_drvdata(file);
+ int ret = 0;
+
+ mutex_lock(&qcam->lock);
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ qcam->brightness = ctrl->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ qcam->contrast = ctrl->value;
+ break;
+ case V4L2_CID_GAMMA:
+ qcam->whitebal = ctrl->value;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
+ }
+ if (ret == 0) {
+ qc_setscanmode(qcam);
+ qcam->status |= QC_PARAM_CHANGE;
+ }
+ mutex_unlock(&qcam->lock);
+ return ret;
+}
+
+static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct qcam *qcam = video_drvdata(file);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ pix->width = qcam->width / qcam->transfer_scale;
+ pix->height = qcam->height / qcam->transfer_scale;
+ pix->pixelformat = (qcam->bpp == 4) ? V4L2_PIX_FMT_Y4 : V4L2_PIX_FMT_Y6;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = qcam->width;
+ pix->sizeimage = qcam->width * qcam->height;
+ /* Just a guess */
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ if (pix->height <= 60 || pix->width <= 80) {
+ pix->height = 60;
+ pix->width = 80;
+ } else if (pix->height <= 120 || pix->width <= 160) {
+ pix->height = 120;
+ pix->width = 160;
+ } else {
+ pix->height = 240;
+ pix->width = 320;
+ }
+ if (pix->pixelformat != V4L2_PIX_FMT_Y4 &&
+ pix->pixelformat != V4L2_PIX_FMT_Y6)
+ pix->pixelformat = V4L2_PIX_FMT_Y4;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = pix->width;
+ pix->sizeimage = pix->width * pix->height;
+ /* Just a guess */
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct qcam *qcam = video_drvdata(file);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
+
+ if (ret)
+ return ret;
+ qcam->width = 320;
+ qcam->height = 240;
+ if (pix->height == 60)
+ qcam->transfer_scale = 4;
+ else if (pix->height == 120)
+ qcam->transfer_scale = 2;
+ else
+ qcam->transfer_scale = 1;
+ if (pix->pixelformat == V4L2_PIX_FMT_Y6)
+ qcam->bpp = 6;
+ else
+ qcam->bpp = 4;
+
+ mutex_lock(&qcam->lock);
+ qc_setscanmode(qcam);
+ /* We must update the camera before we grab. We could
+ just have changed the grab size */
+ qcam->status |= QC_PARAM_CHANGE;
+ mutex_unlock(&qcam->lock);
return 0;
}
-static long qcam_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
+static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
{
- return video_usercopy(file, cmd, arg, qcam_do_ioctl);
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "4-Bit Monochrome", V4L2_PIX_FMT_Y4,
+ { 0, 0, 0, 0 }
+ },
+ { 0, 0, 0,
+ "6-Bit Monochrome", V4L2_PIX_FMT_Y6,
+ { 0, 0, 0, 0 }
+ },
+ };
+ enum v4l2_buf_type type = fmt->type;
+
+ if (fmt->index > 1)
+ return -EINVAL;
+
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+ return 0;
}
static ssize_t qcam_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct video_device *v = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)v;
+ struct qcam *qcam = video_drvdata(file);
int len;
parport_claim_or_block(qcam->pdev);
@@ -858,43 +858,112 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
-static int qcam_exclusive_open(struct file *file)
+static const struct v4l2_file_operations qcam_fops = {
+ .owner = THIS_MODULE,
+ .unlocked_ioctl = video_ioctl2,
+ .read = qcam_read,
+};
+
+static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
+ .vidioc_querycap = qcam_querycap,
+ .vidioc_g_input = qcam_g_input,
+ .vidioc_s_input = qcam_s_input,
+ .vidioc_enum_input = qcam_enum_input,
+ .vidioc_queryctrl = qcam_queryctrl,
+ .vidioc_g_ctrl = qcam_g_ctrl,
+ .vidioc_s_ctrl = qcam_s_ctrl,
+ .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
+};
+
+/* Initialize the QuickCam driver control structure. This is where
+ * defaults are set for people who don't have a config file.*/
+
+static struct qcam *qcam_init(struct parport *port)
{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
+ struct qcam *qcam;
+ struct v4l2_device *v4l2_dev;
+
+ qcam = kzalloc(sizeof(struct qcam), GFP_KERNEL);
+ if (qcam == NULL)
+ return NULL;
+
+ v4l2_dev = &qcam->v4l2_dev;
+ strlcpy(v4l2_dev->name, "bw-qcam", sizeof(v4l2_dev->name));
- return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
+ if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+ return NULL;
+ }
+
+ qcam->pport = port;
+ qcam->pdev = parport_register_device(port, "bw-qcam", NULL, NULL,
+ NULL, 0, NULL);
+ if (qcam->pdev == NULL) {
+ v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+ kfree(qcam);
+ return NULL;
+ }
+
+ strlcpy(qcam->vdev.name, "Connectix QuickCam", sizeof(qcam->vdev.name));
+ qcam->vdev.v4l2_dev = v4l2_dev;
+ qcam->vdev.fops = &qcam_fops;
+ qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+ qcam->vdev.release = video_device_release_empty;
+ video_set_drvdata(&qcam->vdev, qcam);
+
+ mutex_init(&qcam->lock);
+
+ qcam->port_mode = (QC_ANY | QC_NOTSET);
+ qcam->width = 320;
+ qcam->height = 240;
+ qcam->bpp = 4;
+ qcam->transfer_scale = 2;
+ qcam->contrast = 192;
+ qcam->brightness = 180;
+ qcam->whitebal = 105;
+ qcam->top = 1;
+ qcam->left = 14;
+ qcam->mode = -1;
+ qcam->status = QC_PARAM_CHANGE;
+ return qcam;
}
-static int qcam_exclusive_release(struct file *file)
+static int qc_calibrate(struct qcam *q)
{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
+ /*
+ * Bugfix by Hanno Mueller hmueller@kabel.de, Mai 21 96
+ * The white balance is an individual value for each
+ * quickcam.
+ */
- clear_bit(0, &qcam->in_use);
- return 0;
-}
+ int value;
+ int count = 0;
-static const struct v4l2_file_operations qcam_fops = {
- .owner = THIS_MODULE,
- .open = qcam_exclusive_open,
- .release = qcam_exclusive_release,
- .ioctl = qcam_ioctl,
- .read = qcam_read,
-};
-static struct video_device qcam_template = {
- .name = "Connectix Quickcam",
- .fops = &qcam_fops,
- .release = video_device_release_empty,
-};
+ qc_command(q, 27); /* AutoAdjustOffset */
+ qc_command(q, 0); /* Dummy Parameter, ignored by the camera */
-#define MAX_CAMS 4
-static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams;
+ /* GetOffset (33) will read 255 until autocalibration */
+ /* is finished. After that, a value of 1-254 will be */
+ /* returned. */
+
+ do {
+ qc_command(q, 33);
+ value = qc_readparam(q);
+ mdelay(1);
+ schedule();
+ count++;
+ } while (value == 0xff && count < 2048);
+
+ q->whitebal = value;
+ return value;
+}
static int init_bwqcam(struct parport *port)
{
- struct qcam_device *qcam;
+ struct qcam *qcam;
if (num_cams == MAX_CAMS) {
printk(KERN_ERR "Too many Quickcams (max %d)\n", MAX_CAMS);
@@ -919,7 +988,7 @@ static int init_bwqcam(struct parport *port)
parport_release(qcam->pdev);
- printk(KERN_INFO "Connectix Quickcam on %s\n", qcam->pport->name);
+ v4l2_info(&qcam->v4l2_dev, "Connectix Quickcam on %s\n", qcam->pport->name);
if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
parport_unregister_device(qcam->pdev);
@@ -932,7 +1001,7 @@ static int init_bwqcam(struct parport *port)
return 0;
}
-static void close_bwqcam(struct qcam_device *qcam)
+static void close_bwqcam(struct qcam *qcam)
{
video_unregister_device(&qcam->vdev);
parport_unregister_device(qcam->pdev);
@@ -983,7 +1052,7 @@ static void bwqcam_detach(struct parport *port)
{
int i;
for (i = 0; i < num_cams; i++) {
- struct qcam_device *qcam = qcams[i];
+ struct qcam *qcam = qcams[i];
if (qcam && qcam->pdev->port == port) {
qcams[i] = NULL;
close_bwqcam(qcam);
diff --git a/drivers/media/video/bw-qcam.h b/drivers/media/video/bw-qcam.h
deleted file mode 100644
index 8a60c5de0935..000000000000
--- a/drivers/media/video/bw-qcam.h
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- * Video4Linux bw-qcam driver
- *
- * Derived from code..
- */
-
-/******************************************************************
-
-Copyright (C) 1996 by Scott Laird
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
-IN NO EVENT SHALL SCOTT LAIRD BE LIABLE FOR ANY CLAIM, DAMAGES OR
-OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
-ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
-OTHER DEALINGS IN THE SOFTWARE.
-
-******************************************************************/
-
-/* One from column A... */
-#define QC_NOTSET 0
-#define QC_UNIDIR 1
-#define QC_BIDIR 2
-#define QC_SERIAL 3
-
-/* ... and one from column B */
-#define QC_ANY 0x00
-#define QC_FORCE_UNIDIR 0x10
-#define QC_FORCE_BIDIR 0x20
-#define QC_FORCE_SERIAL 0x30
-/* in the port_mode member */
-
-#define QC_MODE_MASK 0x07
-#define QC_FORCE_MASK 0x70
-
-#define MAX_HEIGHT 243
-#define MAX_WIDTH 336
-
-/* Bit fields for status flags */
-#define QC_PARAM_CHANGE 0x01 /* Camera status change has occurred */
-
-struct qcam_device {
- struct video_device vdev;
- struct pardevice *pdev;
- struct parport *pport;
- struct mutex lock;
- int width, height;
- int bpp;
- int mode;
- int contrast, brightness, whitebal;
- int port_mode;
- int transfer_scale;
- int top, left;
- int status;
- unsigned int saved_bits;
- unsigned long in_use;
-};
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index 8f1dd88b32a6..24fc00965a12 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -33,15 +33,17 @@
#include <linux/mm.h>
#include <linux/parport.h>
#include <linux/sched.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
#include <linux/mutex.h>
#include <linux/jiffies.h>
-
+#include <linux/version.h>
+#include <linux/videodev2.h>
#include <asm/uaccess.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
-struct qcam_device {
+struct qcam {
+ struct v4l2_device v4l2_dev;
struct video_device vdev;
struct pardevice *pdev;
struct parport *pport;
@@ -51,7 +53,6 @@ struct qcam_device {
int contrast, brightness, whitebal;
int top, left;
unsigned int bidirectional;
- unsigned long in_use;
struct mutex lock;
};
@@ -68,33 +69,45 @@ struct qcam_device {
#define QC_DECIMATION_2 2
#define QC_DECIMATION_4 4
-#define BANNER "Colour QuickCam for Video4Linux v0.05"
+#define BANNER "Colour QuickCam for Video4Linux v0.06"
static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
static int probe = 2;
static int force_rgb;
static int video_nr = -1;
-static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
+/* FIXME: parport=auto would never have worked, surely? --RR */
+MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
+ "probe=<0|1|2> for camera detection method\n"
+ "force_rgb=<0|1> for RGB data format (default BGR)");
+module_param_array(parport, int, NULL, 0);
+module_param(probe, int, 0);
+module_param(force_rgb, bool, 0);
+module_param(video_nr, int, 0);
+
+static struct qcam *qcams[MAX_CAMS];
+static unsigned int num_cams;
+
+static inline void qcam_set_ack(struct qcam *qcam, unsigned int i)
{
/* note: the QC specs refer to the PCAck pin by voltage, not
software level. PC ports have builtin inverters. */
parport_frob_control(qcam->pport, 8, i ? 8 : 0);
}
-static inline unsigned int qcam_ready1(struct qcam_device *qcam)
+static inline unsigned int qcam_ready1(struct qcam *qcam)
{
return (parport_read_status(qcam->pport) & 0x8) ? 1 : 0;
}
-static inline unsigned int qcam_ready2(struct qcam_device *qcam)
+static inline unsigned int qcam_ready2(struct qcam *qcam)
{
return (parport_read_data(qcam->pport) & 0x1) ? 1 : 0;
}
-static unsigned int qcam_await_ready1(struct qcam_device *qcam,
- int value)
+static unsigned int qcam_await_ready1(struct qcam *qcam, int value)
{
+ struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
unsigned long oldjiffies = jiffies;
unsigned int i;
@@ -112,14 +125,15 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
}
/* Probably somebody pulled the plug out. Not much we can do. */
- printk(KERN_ERR "c-qcam: ready1 timeout (%d) %x %x\n", value,
+ v4l2_err(v4l2_dev, "ready1 timeout (%d) %x %x\n", value,
parport_read_status(qcam->pport),
parport_read_control(qcam->pport));
return 1;
}
-static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
+static unsigned int qcam_await_ready2(struct qcam *qcam, int value)
{
+ struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
unsigned long oldjiffies = jiffies;
unsigned int i;
@@ -137,14 +151,14 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
}
/* Probably somebody pulled the plug out. Not much we can do. */
- printk(KERN_ERR "c-qcam: ready2 timeout (%d) %x %x %x\n", value,
+ v4l2_err(v4l2_dev, "ready2 timeout (%d) %x %x %x\n", value,
parport_read_status(qcam->pport),
parport_read_control(qcam->pport),
parport_read_data(qcam->pport));
return 1;
}
-static int qcam_read_data(struct qcam_device *qcam)
+static int qcam_read_data(struct qcam *qcam)
{
unsigned int idata;
@@ -159,21 +173,22 @@ static int qcam_read_data(struct qcam_device *qcam)
return idata;
}
-static int qcam_write_data(struct qcam_device *qcam, unsigned int data)
+static int qcam_write_data(struct qcam *qcam, unsigned int data)
{
+ struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
unsigned int idata;
parport_write_data(qcam->pport, data);
idata = qcam_read_data(qcam);
if (data != idata) {
- printk(KERN_WARNING "cqcam: sent %x but received %x\n", data,
+ v4l2_warn(v4l2_dev, "sent %x but received %x\n", data,
idata);
return 1;
}
return 0;
}
-static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned int data)
+static inline int qcam_set(struct qcam *qcam, unsigned int cmd, unsigned int data)
{
if (qcam_write_data(qcam, cmd))
return -1;
@@ -182,14 +197,14 @@ static inline int qcam_set(struct qcam_device *qcam, unsigned int cmd, unsigned
return 0;
}
-static inline int qcam_get(struct qcam_device *qcam, unsigned int cmd)
+static inline int qcam_get(struct qcam *qcam, unsigned int cmd)
{
if (qcam_write_data(qcam, cmd))
return -1;
return qcam_read_data(qcam);
}
-static int qc_detect(struct qcam_device *qcam)
+static int qc_detect(struct qcam *qcam)
{
unsigned int stat, ostat, i, count = 0;
@@ -246,7 +261,7 @@ static int qc_detect(struct qcam_device *qcam)
return 0;
}
-static void qc_reset(struct qcam_device *qcam)
+static void qc_reset(struct qcam *qcam)
{
parport_write_control(qcam->pport, 0xc);
parport_write_control(qcam->pport, 0x8);
@@ -258,55 +273,55 @@ static void qc_reset(struct qcam_device *qcam)
/* Reset the QuickCam and program for brightness, contrast,
* white-balance, and resolution. */
-static void qc_setup(struct qcam_device *q)
+static void qc_setup(struct qcam *qcam)
{
- qc_reset(q);
+ qc_reset(qcam);
/* Set the brightness. */
- qcam_set(q, 11, q->brightness);
+ qcam_set(qcam, 11, qcam->brightness);
/* Set the height and width. These refer to the actual
CCD area *before* applying the selected decimation. */
- qcam_set(q, 17, q->ccd_height);
- qcam_set(q, 19, q->ccd_width / 2);
+ qcam_set(qcam, 17, qcam->ccd_height);
+ qcam_set(qcam, 19, qcam->ccd_width / 2);
/* Set top and left. */
- qcam_set(q, 0xd, q->top);
- qcam_set(q, 0xf, q->left);
+ qcam_set(qcam, 0xd, qcam->top);
+ qcam_set(qcam, 0xf, qcam->left);
/* Set contrast and white balance. */
- qcam_set(q, 0x19, q->contrast);
- qcam_set(q, 0x1f, q->whitebal);
+ qcam_set(qcam, 0x19, qcam->contrast);
+ qcam_set(qcam, 0x1f, qcam->whitebal);
/* Set the speed. */
- qcam_set(q, 45, 2);
+ qcam_set(qcam, 45, 2);
}
/* Read some bytes from the camera and put them in the buffer.
nbytes should be a multiple of 3, because bidirectional mode gives
us three bytes at a time. */
-static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, unsigned int nbytes)
+static unsigned int qcam_read_bytes(struct qcam *qcam, unsigned char *buf, unsigned int nbytes)
{
unsigned int bytes = 0;
- qcam_set_ack(q, 0);
- if (q->bidirectional) {
+ qcam_set_ack(qcam, 0);
+ if (qcam->bidirectional) {
/* It's a bidirectional port */
while (bytes < nbytes) {
unsigned int lo1, hi1, lo2, hi2;
unsigned char r, g, b;
- if (qcam_await_ready2(q, 1))
+ if (qcam_await_ready2(qcam, 1))
return bytes;
- lo1 = parport_read_data(q->pport) >> 1;
- hi1 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
- qcam_set_ack(q, 1);
- if (qcam_await_ready2(q, 0))
+ lo1 = parport_read_data(qcam->pport) >> 1;
+ hi1 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
+ qcam_set_ack(qcam, 1);
+ if (qcam_await_ready2(qcam, 0))
return bytes;
- lo2 = parport_read_data(q->pport) >> 1;
- hi2 = ((parport_read_status(q->pport) >> 3) & 0x1f) ^ 0x10;
- qcam_set_ack(q, 0);
+ lo2 = parport_read_data(qcam->pport) >> 1;
+ hi2 = ((parport_read_status(qcam->pport) >> 3) & 0x1f) ^ 0x10;
+ qcam_set_ack(qcam, 0);
r = lo1 | ((hi1 & 1) << 7);
g = ((hi1 & 0x1e) << 3) | ((hi2 & 0x1e) >> 1);
b = lo2 | ((hi2 & 1) << 7);
@@ -328,14 +343,14 @@ static unsigned int qcam_read_bytes(struct qcam_device *q, unsigned char *buf, u
while (bytes < nbytes) {
unsigned int hi, lo;
- if (qcam_await_ready1(q, 1))
+ if (qcam_await_ready1(qcam, 1))
return bytes;
- hi = (parport_read_status(q->pport) & 0xf0);
- qcam_set_ack(q, 1);
- if (qcam_await_ready1(q, 0))
+ hi = (parport_read_status(qcam->pport) & 0xf0);
+ qcam_set_ack(qcam, 1);
+ if (qcam_await_ready1(qcam, 0))
return bytes;
- lo = (parport_read_status(q->pport) & 0xf0);
- qcam_set_ack(q, 0);
+ lo = (parport_read_status(qcam->pport) & 0xf0);
+ qcam_set_ack(qcam, 0);
/* flip some bits */
rgb[(i = bytes++ % 3)] = (hi | (lo >> 4)) ^ 0x88;
if (i >= 2) {
@@ -361,10 +376,11 @@ get_fragment:
#define BUFSZ 150
-static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long len)
+static long qc_capture(struct qcam *qcam, char __user *buf, unsigned long len)
{
+ struct v4l2_device *v4l2_dev = &qcam->v4l2_dev;
unsigned lines, pixelsperline, bitsperxfer;
- unsigned int is_bi_dir = q->bidirectional;
+ unsigned int is_bi_dir = qcam->bidirectional;
size_t wantlen, outptr = 0;
char tmpbuf[BUFSZ];
@@ -373,10 +389,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
/* Wait for camera to become ready */
for (;;) {
- int i = qcam_get(q, 41);
+ int i = qcam_get(qcam, 41);
if (i == -1) {
- qc_setup(q);
+ qc_setup(qcam);
return -EIO;
}
if ((i & 0x80) == 0)
@@ -384,25 +400,25 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
schedule();
}
- if (qcam_set(q, 7, (q->mode | (is_bi_dir ? 1 : 0)) + 1))
+ if (qcam_set(qcam, 7, (qcam->mode | (is_bi_dir ? 1 : 0)) + 1))
return -EIO;
- lines = q->height;
- pixelsperline = q->width;
+ lines = qcam->height;
+ pixelsperline = qcam->width;
bitsperxfer = (is_bi_dir) ? 24 : 8;
if (is_bi_dir) {
/* Turn the port around */
- parport_data_reverse(q->pport);
+ parport_data_reverse(qcam->pport);
mdelay(3);
- qcam_set_ack(q, 0);
- if (qcam_await_ready1(q, 1)) {
- qc_setup(q);
+ qcam_set_ack(qcam, 0);
+ if (qcam_await_ready1(qcam, 1)) {
+ qc_setup(qcam);
return -EIO;
}
- qcam_set_ack(q, 1);
- if (qcam_await_ready1(q, 0)) {
- qc_setup(q);
+ qcam_set_ack(qcam, 1);
+ if (qcam_await_ready1(qcam, 0)) {
+ qc_setup(qcam);
return -EIO;
}
}
@@ -413,7 +429,7 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
size_t t, s;
s = (wantlen > BUFSZ) ? BUFSZ : wantlen;
- t = qcam_read_bytes(q, tmpbuf, s);
+ t = qcam_read_bytes(qcam, tmpbuf, s);
if (outptr < len) {
size_t sz = len - outptr;
@@ -432,10 +448,10 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
len = outptr;
if (wantlen) {
- printk(KERN_ERR "qcam: short read.\n");
+ v4l2_err(v4l2_dev, "short read.\n");
if (is_bi_dir)
- parport_data_forward(q->pport);
- qc_setup(q);
+ parport_data_forward(qcam->pport);
+ qc_setup(qcam);
return len;
}
@@ -443,49 +459,49 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
int l;
do {
- l = qcam_read_bytes(q, tmpbuf, 3);
+ l = qcam_read_bytes(qcam, tmpbuf, 3);
cond_resched();
} while (l && (tmpbuf[0] == 0x7e || tmpbuf[1] == 0x7e || tmpbuf[2] == 0x7e));
if (force_rgb) {
if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
- printk(KERN_ERR "qcam: bad EOF\n");
+ v4l2_err(v4l2_dev, "bad EOF\n");
} else {
if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
- printk(KERN_ERR "qcam: bad EOF\n");
+ v4l2_err(v4l2_dev, "bad EOF\n");
}
- qcam_set_ack(q, 0);
- if (qcam_await_ready1(q, 1)) {
- printk(KERN_ERR "qcam: no ack after EOF\n");
- parport_data_forward(q->pport);
- qc_setup(q);
+ qcam_set_ack(qcam, 0);
+ if (qcam_await_ready1(qcam, 1)) {
+ v4l2_err(v4l2_dev, "no ack after EOF\n");
+ parport_data_forward(qcam->pport);
+ qc_setup(qcam);
return len;
}
- parport_data_forward(q->pport);
+ parport_data_forward(qcam->pport);
mdelay(3);
- qcam_set_ack(q, 1);
- if (qcam_await_ready1(q, 0)) {
- printk(KERN_ERR "qcam: no ack to port turnaround\n");
- qc_setup(q);
+ qcam_set_ack(qcam, 1);
+ if (qcam_await_ready1(qcam, 0)) {
+ v4l2_err(v4l2_dev, "no ack to port turnaround\n");
+ qc_setup(qcam);
return len;
}
} else {
int l;
do {
- l = qcam_read_bytes(q, tmpbuf, 1);
+ l = qcam_read_bytes(qcam, tmpbuf, 1);
cond_resched();
} while (l && tmpbuf[0] == 0x7e);
- l = qcam_read_bytes(q, tmpbuf + 1, 2);
+ l = qcam_read_bytes(qcam, tmpbuf + 1, 2);
if (force_rgb) {
if (tmpbuf[0] != 0xe || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xf)
- printk(KERN_ERR "qcam: bad EOF\n");
+ v4l2_err(v4l2_dev, "bad EOF\n");
} else {
if (tmpbuf[0] != 0xf || tmpbuf[1] != 0x0 || tmpbuf[2] != 0xe)
- printk(KERN_ERR "qcam: bad EOF\n");
+ v4l2_err(v4l2_dev, "bad EOF\n");
}
}
- qcam_write_data(q, 0);
+ qcam_write_data(qcam, 0);
return len;
}
@@ -493,184 +509,202 @@ static long qc_capture(struct qcam_device *q, char __user *buf, unsigned long le
* Video4linux interfacing
*/
-static long qcam_do_ioctl(struct file *file, unsigned int cmd, void *arg)
+static int qcam_querycap(struct file *file, void *priv,
+ struct v4l2_capability *vcap)
{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
+ struct qcam *qcam = video_drvdata(file);
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
+ strlcpy(vcap->driver, qcam->v4l2_dev.name, sizeof(vcap->driver));
+ strlcpy(vcap->card, "Color Quickcam", sizeof(vcap->card));
+ strlcpy(vcap->bus_info, "parport", sizeof(vcap->bus_info));
+ vcap->version = KERNEL_VERSION(0, 0, 3);
+ vcap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE;
+ return 0;
+}
- strcpy(b->name, "Quickcam");
- b->type = VID_TYPE_CAPTURE | VID_TYPE_SCALES;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = 320;
- b->maxheight = 240;
- b->minwidth = 80;
- b->minheight = 60;
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- /* Good question.. its composite or SVHS so.. */
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Camera");
- return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
+static int qcam_enum_input(struct file *file, void *fh, struct v4l2_input *vin)
+{
+ if (vin->index > 0)
+ return -EINVAL;
+ strlcpy(vin->name, "Camera", sizeof(vin->name));
+ vin->type = V4L2_INPUT_TYPE_CAMERA;
+ vin->audioset = 0;
+ vin->tuner = 0;
+ vin->std = 0;
+ vin->status = 0;
+ return 0;
+}
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGTUNER:
- {
- struct video_tuner *v = arg;
-
- if (v->tuner)
- return -EINVAL;
- memset(v, 0, sizeof(*v));
- strcpy(v->name, "Format");
- v->mode = VIDEO_MODE_AUTO;
- return 0;
+static int qcam_g_input(struct file *file, void *fh, unsigned int *inp)
+{
+ *inp = 0;
+ return 0;
+}
+
+static int qcam_s_input(struct file *file, void *fh, unsigned int inp)
+{
+ return (inp > 0) ? -EINVAL : 0;
+}
+
+static int qcam_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ switch (qc->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 240);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 192);
+ case V4L2_CID_GAMMA:
+ return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
}
- case VIDIOCSTUNER:
- {
- struct video_tuner *v = arg;
-
- if (v->tuner)
- return -EINVAL;
- if (v->mode != VIDEO_MODE_AUTO)
- return -EINVAL;
- return 0;
+ return -EINVAL;
+}
+
+static int qcam_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct qcam *qcam = video_drvdata(file);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = qcam->brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctrl->value = qcam->contrast;
+ break;
+ case V4L2_CID_GAMMA:
+ ctrl->value = qcam->whitebal;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
-
- p->colour = 0x8000;
- p->hue = 0x8000;
- p->brightness = qcam->brightness << 8;
- p->contrast = qcam->contrast << 8;
- p->whiteness = qcam->whitebal << 8;
- p->depth = 24;
- p->palette = VIDEO_PALETTE_RGB24;
- return 0;
+ return ret;
+}
+
+static int qcam_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct qcam *qcam = video_drvdata(file);
+ int ret = 0;
+
+ mutex_lock(&qcam->lock);
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ qcam->brightness = ctrl->value;
+ break;
+ case V4L2_CID_CONTRAST:
+ qcam->contrast = ctrl->value;
+ break;
+ case V4L2_CID_GAMMA:
+ qcam->whitebal = ctrl->value;
+ break;
+ default:
+ ret = -EINVAL;
+ break;
}
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
-
- /*
- * Sanity check args
- */
- if (p->depth != 24 || p->palette != VIDEO_PALETTE_RGB24)
- return -EINVAL;
-
- /*
- * Now load the camera.
- */
- qcam->brightness = p->brightness >> 8;
- qcam->contrast = p->contrast >> 8;
- qcam->whitebal = p->whiteness >> 8;
-
- mutex_lock(&qcam->lock);
+ if (ret == 0) {
parport_claim_or_block(qcam->pdev);
qc_setup(qcam);
parport_release(qcam->pdev);
- mutex_unlock(&qcam->lock);
- return 0;
}
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
-
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->height < 60 || vw->height > 240)
- return -EINVAL;
- if (vw->width < 80 || vw->width > 320)
- return -EINVAL;
-
- qcam->width = 80;
- qcam->height = 60;
- qcam->mode = QC_DECIMATION_4;
+ mutex_unlock(&qcam->lock);
+ return ret;
+}
- if (vw->width >= 160 && vw->height >= 120) {
- qcam->width = 160;
- qcam->height = 120;
- qcam->mode = QC_DECIMATION_2;
- }
- if (vw->width >= 320 && vw->height >= 240) {
- qcam->width = 320;
- qcam->height = 240;
- qcam->mode = QC_DECIMATION_1;
- }
- qcam->mode |= QC_MILLIONS;
-#if 0
- if (vw->width >= 640 && vw->height >= 480) {
- qcam->width = 640;
- qcam->height = 480;
- qcam->mode = QC_BILLIONS | QC_DECIMATION_1;
- }
-#endif
- /* Ok we figured out what to use from our
- wide choice */
- mutex_lock(&qcam->lock);
- parport_claim_or_block(qcam->pdev);
- qc_setup(qcam);
- parport_release(qcam->pdev);
- mutex_unlock(&qcam->lock);
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
- memset(vw, 0, sizeof(*vw));
- vw->width = qcam->width;
- vw->height = qcam->height;
- return 0;
+static int qcam_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct qcam *qcam = video_drvdata(file);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ pix->width = qcam->width;
+ pix->height = qcam->height;
+ pix->pixelformat = V4L2_PIX_FMT_RGB24;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = 3 * qcam->width;
+ pix->sizeimage = 3 * qcam->width * qcam->height;
+ /* Just a guess */
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int qcam_try_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+
+ if (pix->height < 60 || pix->width < 80) {
+ pix->height = 60;
+ pix->width = 80;
+ } else if (pix->height < 120 || pix->width < 160) {
+ pix->height = 120;
+ pix->width = 160;
+ } else {
+ pix->height = 240;
+ pix->width = 320;
}
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
+ pix->pixelformat = V4L2_PIX_FMT_RGB24;
+ pix->field = V4L2_FIELD_NONE;
+ pix->bytesperline = 3 * pix->width;
+ pix->sizeimage = 3 * pix->width * pix->height;
+ /* Just a guess */
+ pix->colorspace = V4L2_COLORSPACE_SRGB;
+ return 0;
+}
+
+static int qcam_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *fmt)
+{
+ struct qcam *qcam = video_drvdata(file);
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ int ret = qcam_try_fmt_vid_cap(file, fh, fmt);
+
+ if (ret)
+ return ret;
+ switch (pix->height) {
+ case 60:
+ qcam->mode = QC_DECIMATION_4;
+ break;
+ case 120:
+ qcam->mode = QC_DECIMATION_2;
+ break;
default:
- return -ENOIOCTLCMD;
+ qcam->mode = QC_DECIMATION_1;
+ break;
}
+
+ mutex_lock(&qcam->lock);
+ qcam->mode |= QC_MILLIONS;
+ qcam->height = pix->height;
+ qcam->width = pix->width;
+ parport_claim_or_block(qcam->pdev);
+ qc_setup(qcam);
+ parport_release(qcam->pdev);
+ mutex_unlock(&qcam->lock);
return 0;
}
-static long qcam_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
+static int qcam_enum_fmt_vid_cap(struct file *file, void *fh, struct v4l2_fmtdesc *fmt)
{
- return video_usercopy(file, cmd, arg, qcam_do_ioctl);
+ static struct v4l2_fmtdesc formats[] = {
+ { 0, 0, 0,
+ "RGB 8:8:8", V4L2_PIX_FMT_RGB24,
+ { 0, 0, 0, 0 }
+ },
+ };
+ enum v4l2_buf_type type = fmt->type;
+
+ if (fmt->index > 0)
+ return -EINVAL;
+
+ *fmt = formats[fmt->index];
+ fmt->type = type;
+ return 0;
}
static ssize_t qcam_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct video_device *v = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)v;
+ struct qcam *qcam = video_drvdata(file);
int len;
mutex_lock(&qcam->lock);
@@ -682,81 +716,80 @@ static ssize_t qcam_read(struct file *file, char __user *buf,
return len;
}
-static int qcam_exclusive_open(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
-
- return test_and_set_bit(0, &qcam->in_use) ? -EBUSY : 0;
-}
-
-static int qcam_exclusive_release(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct qcam_device *qcam = (struct qcam_device *)dev;
-
- clear_bit(0, &qcam->in_use);
- return 0;
-}
-
-/* video device template */
static const struct v4l2_file_operations qcam_fops = {
.owner = THIS_MODULE,
- .open = qcam_exclusive_open,
- .release = qcam_exclusive_release,
- .ioctl = qcam_ioctl,
+ .unlocked_ioctl = video_ioctl2,
.read = qcam_read,
};
-static struct video_device qcam_template = {
- .name = "Colour QuickCam",
- .fops = &qcam_fops,
- .release = video_device_release_empty,
+static const struct v4l2_ioctl_ops qcam_ioctl_ops = {
+ .vidioc_querycap = qcam_querycap,
+ .vidioc_g_input = qcam_g_input,
+ .vidioc_s_input = qcam_s_input,
+ .vidioc_enum_input = qcam_enum_input,
+ .vidioc_queryctrl = qcam_queryctrl,
+ .vidioc_g_ctrl = qcam_g_ctrl,
+ .vidioc_s_ctrl = qcam_s_ctrl,
+ .vidioc_enum_fmt_vid_cap = qcam_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = qcam_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = qcam_s_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = qcam_try_fmt_vid_cap,
};
/* Initialize the QuickCam driver control structure. */
-static struct qcam_device *qcam_init(struct parport *port)
+static struct qcam *qcam_init(struct parport *port)
{
- struct qcam_device *q;
+ struct qcam *qcam;
+ struct v4l2_device *v4l2_dev;
- q = kmalloc(sizeof(struct qcam_device), GFP_KERNEL);
- if (q == NULL)
+ qcam = kzalloc(sizeof(*qcam), GFP_KERNEL);
+ if (qcam == NULL)
return NULL;
- q->pport = port;
- q->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
+ v4l2_dev = &qcam->v4l2_dev;
+ strlcpy(v4l2_dev->name, "c-qcam", sizeof(v4l2_dev->name));
+
+ if (v4l2_device_register(NULL, v4l2_dev) < 0) {
+ v4l2_err(v4l2_dev, "Could not register v4l2_device\n");
+ return NULL;
+ }
+
+ qcam->pport = port;
+ qcam->pdev = parport_register_device(port, "c-qcam", NULL, NULL,
NULL, 0, NULL);
- q->bidirectional = (q->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
+ qcam->bidirectional = (qcam->pport->modes & PARPORT_MODE_TRISTATE) ? 1 : 0;
- if (q->pdev == NULL) {
- printk(KERN_ERR "c-qcam: couldn't register for %s.\n",
- port->name);
- kfree(q);
+ if (qcam->pdev == NULL) {
+ v4l2_err(v4l2_dev, "couldn't register for %s.\n", port->name);
+ kfree(qcam);
return NULL;
}
- memcpy(&q->vdev, &qcam_template, sizeof(qcam_template));
-
- mutex_init(&q->lock);
- q->width = q->ccd_width = 320;
- q->height = q->ccd_height = 240;
- q->mode = QC_MILLIONS | QC_DECIMATION_1;
- q->contrast = 192;
- q->brightness = 240;
- q->whitebal = 128;
- q->top = 1;
- q->left = 14;
- return q;
+ strlcpy(qcam->vdev.name, "Colour QuickCam", sizeof(qcam->vdev.name));
+ qcam->vdev.v4l2_dev = v4l2_dev;
+ qcam->vdev.fops = &qcam_fops;
+ qcam->vdev.ioctl_ops = &qcam_ioctl_ops;
+ qcam->vdev.release = video_device_release_empty;
+ video_set_drvdata(&qcam->vdev, qcam);
+
+ mutex_init(&qcam->lock);
+ qcam->width = qcam->ccd_width = 320;
+ qcam->height = qcam->ccd_height = 240;
+ qcam->mode = QC_MILLIONS | QC_DECIMATION_1;
+ qcam->contrast = 192;
+ qcam->brightness = 240;
+ qcam->whitebal = 128;
+ qcam->top = 1;
+ qcam->left = 14;
+ return qcam;
}
-static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams;
-
static int init_cqcam(struct parport *port)
{
- struct qcam_device *qcam;
+ struct qcam *qcam;
+ struct v4l2_device *v4l2_dev;
if (parport[0] != -1) {
/* The user gave specific instructions */
@@ -777,6 +810,8 @@ static int init_cqcam(struct parport *port)
if (qcam == NULL)
return -ENODEV;
+ v4l2_dev = &qcam->v4l2_dev;
+
parport_claim_or_block(qcam->pdev);
qc_reset(qcam);
@@ -793,14 +828,14 @@ static int init_cqcam(struct parport *port)
parport_release(qcam->pdev);
if (video_register_device(&qcam->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- printk(KERN_ERR "Unable to register Colour QuickCam on %s\n",
+ v4l2_err(v4l2_dev, "Unable to register Colour QuickCam on %s\n",
qcam->pport->name);
parport_unregister_device(qcam->pdev);
kfree(qcam);
return -ENODEV;
}
- printk(KERN_INFO "%s: Colour QuickCam found on %s\n",
+ v4l2_info(v4l2_dev, "%s: Colour QuickCam found on %s\n",
video_device_node_name(&qcam->vdev), qcam->pport->name);
qcams[num_cams++] = qcam;
@@ -808,7 +843,7 @@ static int init_cqcam(struct parport *port)
return 0;
}
-static void close_cqcam(struct qcam_device *qcam)
+static void close_cqcam(struct qcam *qcam)
{
video_unregister_device(&qcam->vdev);
parport_unregister_device(qcam->pdev);
@@ -833,7 +868,7 @@ static struct parport_driver cqcam_driver = {
static int __init cqcam_init(void)
{
- printk(BANNER "\n");
+ printk(KERN_INFO BANNER "\n");
return parport_register_driver(&cqcam_driver);
}
@@ -852,14 +887,5 @@ MODULE_AUTHOR("Philip Blundell <philb@gnu.org>");
MODULE_DESCRIPTION(BANNER);
MODULE_LICENSE("GPL");
-/* FIXME: parport=auto would never have worked, surely? --RR */
-MODULE_PARM_DESC(parport, "parport=<auto|n[,n]...> for port detection method\n"
- "probe=<0|1|2> for camera detection method\n"
- "force_rgb=<0|1> for RGB data format (default BGR)");
-module_param_array(parport, int, NULL, 0);
-module_param(probe, int, 0);
-module_param(force_rgb, bool, 0);
-module_param(video_nr, int, 0);
-
module_init(cqcam_init);
module_exit(cqcam_cleanup);
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index be35e6965829..55ffd60ffa7f 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -4,7 +4,7 @@
* sensor.
*
* The data sheet for this device can be found at:
- * http://www.marvell.com/products/pcconn/88ALP01.jsp
+ * http://www.marvell.com/products/pc_connectivity/88alp01/
*
* Copyright 2006 One Laptop Per Child Association, Inc.
* Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
@@ -25,6 +25,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/fs.h>
+#include <linux/dmi.h>
#include <linux/mm.h>
#include <linux/pci.h>
#include <linux/i2c.h>
@@ -46,6 +47,7 @@
#include <asm/uaccess.h>
#include <asm/io.h>
+#include "ov7670.h"
#include "cafe_ccic-regs.h"
#define CAFE_VERSION 0x000002
@@ -180,6 +182,7 @@ struct cafe_camera
/* Current operating parameters */
u32 sensor_type; /* Currently ov7670 only */
struct v4l2_pix_format pix_format;
+ enum v4l2_mbus_pixelcode mbus_code;
/* Locks */
struct mutex s_mutex; /* Access to this structure */
@@ -207,6 +210,49 @@ static inline struct cafe_camera *to_cam(struct v4l2_device *dev)
return container_of(dev, struct cafe_camera, v4l2_dev);
}
+static struct cafe_format_struct {
+ __u8 *desc;
+ __u32 pixelformat;
+ int bpp; /* Bytes per pixel */
+ enum v4l2_mbus_pixelcode mbus_code;
+} cafe_formats[] = {
+ {
+ .desc = "YUYV 4:2:2",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .bpp = 2,
+ },
+ {
+ .desc = "RGB 444",
+ .pixelformat = V4L2_PIX_FMT_RGB444,
+ .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ .bpp = 2,
+ },
+ {
+ .desc = "RGB 565",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .bpp = 2,
+ },
+ {
+ .desc = "Raw RGB Bayer",
+ .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .bpp = 1
+ },
+};
+#define N_CAFE_FMTS ARRAY_SIZE(cafe_formats)
+
+static struct cafe_format_struct *cafe_find_format(u32 pixelformat)
+{
+ unsigned i;
+
+ for (i = 0; i < N_CAFE_FMTS; i++)
+ if (cafe_formats[i].pixelformat == pixelformat)
+ return cafe_formats + i;
+ /* Not found? Then return the first format. */
+ return cafe_formats;
+}
/*
* Start over with DMA buffers - dev_lock needed.
@@ -319,7 +365,6 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
{
unsigned int rval;
unsigned long flags;
- DEFINE_WAIT(the_wait);
spin_lock_irqsave(&cam->dev_lock, flags);
rval = TWSIC0_EN | ((addr << TWSIC0_SID_SHIFT) & TWSIC0_SID);
@@ -334,28 +379,27 @@ static int cafe_smbus_write_data(struct cafe_camera *cam,
cafe_reg_write(cam, REG_TWSIC1, rval);
spin_unlock_irqrestore(&cam->dev_lock, flags);
+ /* Unfortunately, reading TWSIC1 too soon after sending a command
+ * causes the device to die.
+ * Use a busy-wait because we often send a large quantity of small
+ * commands at-once; using msleep() would cause a lot of context
+ * switches which take longer than 2ms, resulting in a noticable
+ * boot-time and capture-start delays.
+ */
+ mdelay(2);
+
/*
- * Time to wait for the write to complete. THIS IS A RACY
- * WAY TO DO IT, but the sad fact is that reading the TWSIC1
- * register too quickly after starting the operation sends
- * the device into a place that may be kinder and better, but
- * which is absolutely useless for controlling the sensor. In
- * practice we have plenty of time to get into our sleep state
- * before the interrupt hits, and the worst case is that we
- * time out and then see that things completed, so this seems
- * the best way for now.
+ * Another sad fact is that sometimes, commands silently complete but
+ * cafe_smbus_write_done() never becomes aware of this.
+ * This happens at random and appears to possible occur with any
+ * command.
+ * We don't understand why this is. We work around this issue
+ * with the timeout in the wait below, assuming that all commands
+ * complete within the timeout.
*/
- do {
- prepare_to_wait(&cam->smbus_wait, &the_wait,
- TASK_UNINTERRUPTIBLE);
- schedule_timeout(1); /* even 1 jiffy is too long */
- finish_wait(&cam->smbus_wait, &the_wait);
- } while (!cafe_smbus_write_done(cam));
-
-#ifdef IF_THE_CAFE_HARDWARE_WORKED_RIGHT
wait_event_timeout(cam->smbus_wait, cafe_smbus_write_done(cam),
CAFE_SMBUS_TIMEOUT);
-#endif
+
spin_lock_irqsave(&cam->dev_lock, flags);
rval = cafe_reg_read(cam, REG_TWSIC1);
spin_unlock_irqrestore(&cam->dev_lock, flags);
@@ -812,15 +856,13 @@ static int cafe_cam_set_flip(struct cafe_camera *cam)
static int cafe_cam_configure(struct cafe_camera *cam)
{
- struct v4l2_format fmt;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret;
- if (cam->state != S_IDLE)
- return -EINVAL;
- fmt.fmt.pix = cam->pix_format;
+ v4l2_fill_mbus_format(&mbus_fmt, &cam->pix_format, cam->mbus_code);
ret = sensor_call(cam, core, init, 0);
if (ret == 0)
- ret = sensor_call(cam, video, s_fmt, &fmt);
+ ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
/*
* OV7670 does weird things if flip is set *before* format...
*/
@@ -1481,7 +1523,7 @@ static int cafe_vidioc_querycap(struct file *file, void *priv,
/*
* The default format we use until somebody says otherwise.
*/
-static struct v4l2_pix_format cafe_def_pix_format = {
+static const struct v4l2_pix_format cafe_def_pix_format = {
.width = VGA_WIDTH,
.height = VGA_HEIGHT,
.pixelformat = V4L2_PIX_FMT_YUYV,
@@ -1490,28 +1532,38 @@ static struct v4l2_pix_format cafe_def_pix_format = {
.sizeimage = VGA_WIDTH*VGA_HEIGHT*2,
};
+static const enum v4l2_mbus_pixelcode cafe_def_mbus_code =
+ V4L2_MBUS_FMT_YUYV8_2X8;
+
static int cafe_vidioc_enum_fmt_vid_cap(struct file *filp,
void *priv, struct v4l2_fmtdesc *fmt)
{
- struct cafe_camera *cam = priv;
- int ret;
-
- mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, video, enum_fmt, fmt);
- mutex_unlock(&cam->s_mutex);
- return ret;
+ if (fmt->index >= N_CAFE_FMTS)
+ return -EINVAL;
+ strlcpy(fmt->description, cafe_formats[fmt->index].desc,
+ sizeof(fmt->description));
+ fmt->pixelformat = cafe_formats[fmt->index].pixelformat;
+ return 0;
}
-
static int cafe_vidioc_try_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
struct cafe_camera *cam = priv;
+ struct cafe_format_struct *f;
+ struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret;
+ f = cafe_find_format(pix->pixelformat);
+ pix->pixelformat = f->pixelformat;
+ v4l2_fill_mbus_format(&mbus_fmt, pix, f->mbus_code);
mutex_lock(&cam->s_mutex);
- ret = sensor_call(cam, video, try_fmt, fmt);
+ ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
mutex_unlock(&cam->s_mutex);
+ v4l2_fill_pix_format(pix, &mbus_fmt);
+ pix->bytesperline = pix->width * f->bpp;
+ pix->sizeimage = pix->height * pix->bytesperline;
return ret;
}
@@ -1519,6 +1571,7 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
struct v4l2_format *fmt)
{
struct cafe_camera *cam = priv;
+ struct cafe_format_struct *f;
int ret;
/*
@@ -1527,6 +1580,9 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
*/
if (cam->state != S_IDLE || cam->n_sbufs > 0)
return -EBUSY;
+
+ f = cafe_find_format(fmt->fmt.pix.pixelformat);
+
/*
* See if the formatting works in principle.
*/
@@ -1539,6 +1595,8 @@ static int cafe_vidioc_s_fmt_vid_cap(struct file *filp, void *priv,
*/
mutex_lock(&cam->s_mutex);
cam->pix_format = fmt->fmt.pix;
+ cam->mbus_code = f->mbus_code;
+
/*
* Make sure we have appropriate DMA buffers.
*/
@@ -1652,6 +1710,30 @@ static int cafe_vidioc_g_chip_ident(struct file *file, void *priv,
return sensor_call(cam, core, g_chip_ident, chip);
}
+static int cafe_vidioc_enum_framesizes(struct file *filp, void *priv,
+ struct v4l2_frmsizeenum *sizes)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = sensor_call(cam, video, enum_framesizes, sizes);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
+static int cafe_vidioc_enum_frameintervals(struct file *filp, void *priv,
+ struct v4l2_frmivalenum *interval)
+{
+ struct cafe_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->s_mutex);
+ ret = sensor_call(cam, video, enum_frameintervals, interval);
+ mutex_unlock(&cam->s_mutex);
+ return ret;
+}
+
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int cafe_vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
@@ -1691,7 +1773,7 @@ static const struct v4l2_file_operations cafe_v4l_fops = {
.read = cafe_v4l_read,
.poll = cafe_v4l_poll,
.mmap = cafe_v4l_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
@@ -1715,6 +1797,8 @@ static const struct v4l2_ioctl_ops cafe_v4l_ioctl_ops = {
.vidioc_s_ctrl = cafe_vidioc_s_ctrl,
.vidioc_g_parm = cafe_vidioc_g_parm,
.vidioc_s_parm = cafe_vidioc_s_parm,
+ .vidioc_enum_framesizes = cafe_vidioc_enum_framesizes,
+ .vidioc_enum_frameintervals = cafe_vidioc_enum_frameintervals,
.vidioc_g_chip_ident = cafe_vidioc_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.vidioc_g_register = cafe_vidioc_g_register,
@@ -1890,11 +1974,38 @@ static irqreturn_t cafe_irq(int irq, void *data)
* PCI interface stuff.
*/
+static const struct dmi_system_id olpc_xo1_dmi[] = {
+ {
+ .matches = {
+ DMI_MATCH(DMI_SYS_VENDOR, "OLPC"),
+ DMI_MATCH(DMI_PRODUCT_NAME, "XO"),
+ DMI_MATCH(DMI_PRODUCT_VERSION, "1"),
+ },
+ },
+ { }
+};
+
static int cafe_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
int ret;
struct cafe_camera *cam;
+ struct ov7670_config sensor_cfg = {
+ /* This controller only does SMBUS */
+ .use_smbus = true,
+
+ /*
+ * Exclude QCIF mode, because it only captures a tiny portion
+ * of the sensor FOV
+ */
+ .min_width = 320,
+ .min_height = 240,
+ };
+ struct i2c_board_info ov7670_info = {
+ .type = "ov7670",
+ .addr = 0x42,
+ .platform_data = &sensor_cfg,
+ };
/*
* Start putting together one of our big camera structures.
@@ -1915,6 +2026,7 @@ static int cafe_pci_probe(struct pci_dev *pdev,
init_waitqueue_head(&cam->iowait);
cam->pdev = pdev;
cam->pix_format = cafe_def_pix_format;
+ cam->mbus_code = cafe_def_mbus_code;
INIT_LIST_HEAD(&cam->dev_list);
INIT_LIST_HEAD(&cam->sb_avail);
INIT_LIST_HEAD(&cam->sb_full);
@@ -1951,13 +2063,18 @@ static int cafe_pci_probe(struct pci_dev *pdev,
if (ret)
goto out_freeirq;
- cam->sensor_addr = 0x42;
- cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, &cam->i2c_adapter,
- "ov7670", "ov7670", cam->sensor_addr, NULL);
+ /* Apply XO-1 clock speed */
+ if (dmi_check_system(olpc_xo1_dmi))
+ sensor_cfg.clock_speed = 45;
+
+ cam->sensor_addr = ov7670_info.addr;
+ cam->sensor = v4l2_i2c_new_subdev_board(&cam->v4l2_dev, &cam->i2c_adapter,
+ &ov7670_info, NULL);
if (cam->sensor == NULL) {
ret = -ENODEV;
goto out_smbus;
}
+
ret = cafe_cam_init(cam);
if (ret)
goto out_smbus;
@@ -2072,9 +2189,7 @@ static int cafe_pci_resume(struct pci_dev *pdev)
struct cafe_camera *cam = to_cam(v4l2_dev);
int ret = 0;
- ret = pci_restore_state(pdev);
- if (ret)
- return ret;
+ pci_restore_state(pdev);
ret = pci_enable_device(pdev);
if (ret) {
@@ -2082,12 +2197,13 @@ static int cafe_pci_resume(struct pci_dev *pdev)
return ret;
}
cafe_ctlr_init(cam);
- cafe_ctlr_power_down(cam);
mutex_lock(&cam->s_mutex);
if (cam->users > 0) {
cafe_ctlr_power_up(cam);
__cafe_cam_reset(cam);
+ } else {
+ cafe_ctlr_power_down(cam);
}
mutex_unlock(&cam->s_mutex);
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
deleted file mode 100644
index 933ae4c8cb9a..000000000000
--- a/drivers/media/video/cpia.c
+++ /dev/null
@@ -1,4032 +0,0 @@
-/*
- * cpia CPiA driver
- *
- * Supports CPiA based Video Camera's.
- *
- * (C) Copyright 1999-2000 Peter Pregler
- * (C) Copyright 1999-2000 Scott J. Bertin
- * (C) Copyright 1999-2000 Johannes Erdfelt <johannes@erdfelt.com>
- * (C) Copyright 2000 STMicroelectronics
- *
- * 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.
- */
-
-/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_ 1 */
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/sched.h>
-#include <linux/seq_file.h>
-#include <linux/slab.h>
-#include <linux/proc_fs.h>
-#include <linux/ctype.h>
-#include <linux/pagemap.h>
-#include <linux/delay.h>
-#include <asm/io.h>
-#include <linux/mutex.h>
-
-#include "cpia.h"
-
-static int video_nr = -1;
-
-#ifdef MODULE
-module_param(video_nr, int, 0);
-MODULE_AUTHOR("Scott J. Bertin <sbertin@securenym.net> & Peter Pregler <Peter_Pregler@email.com> & Johannes Erdfelt <johannes@erdfelt.com>");
-MODULE_DESCRIPTION("V4L-driver for Vision CPiA based cameras");
-MODULE_LICENSE("GPL");
-MODULE_SUPPORTED_DEVICE("video");
-#endif
-
-static unsigned short colorspace_conv;
-module_param(colorspace_conv, ushort, 0444);
-MODULE_PARM_DESC(colorspace_conv,
- " Colorspace conversion:"
- "\n 0 = disable, 1 = enable"
- "\n Default value is 0"
- );
-
-#define ABOUT "V4L-Driver for Vision CPiA based cameras"
-
-#define CPIA_MODULE_CPIA (0<<5)
-#define CPIA_MODULE_SYSTEM (1<<5)
-#define CPIA_MODULE_VP_CTRL (5<<5)
-#define CPIA_MODULE_CAPTURE (6<<5)
-#define CPIA_MODULE_DEBUG (7<<5)
-
-#define INPUT (DATA_IN << 8)
-#define OUTPUT (DATA_OUT << 8)
-
-#define CPIA_COMMAND_GetCPIAVersion (INPUT | CPIA_MODULE_CPIA | 1)
-#define CPIA_COMMAND_GetPnPID (INPUT | CPIA_MODULE_CPIA | 2)
-#define CPIA_COMMAND_GetCameraStatus (INPUT | CPIA_MODULE_CPIA | 3)
-#define CPIA_COMMAND_GotoHiPower (OUTPUT | CPIA_MODULE_CPIA | 4)
-#define CPIA_COMMAND_GotoLoPower (OUTPUT | CPIA_MODULE_CPIA | 5)
-#define CPIA_COMMAND_GotoSuspend (OUTPUT | CPIA_MODULE_CPIA | 7)
-#define CPIA_COMMAND_GotoPassThrough (OUTPUT | CPIA_MODULE_CPIA | 8)
-#define CPIA_COMMAND_ModifyCameraStatus (OUTPUT | CPIA_MODULE_CPIA | 10)
-
-#define CPIA_COMMAND_ReadVCRegs (INPUT | CPIA_MODULE_SYSTEM | 1)
-#define CPIA_COMMAND_WriteVCReg (OUTPUT | CPIA_MODULE_SYSTEM | 2)
-#define CPIA_COMMAND_ReadMCPorts (INPUT | CPIA_MODULE_SYSTEM | 3)
-#define CPIA_COMMAND_WriteMCPort (OUTPUT | CPIA_MODULE_SYSTEM | 4)
-#define CPIA_COMMAND_SetBaudRate (OUTPUT | CPIA_MODULE_SYSTEM | 5)
-#define CPIA_COMMAND_SetECPTiming (OUTPUT | CPIA_MODULE_SYSTEM | 6)
-#define CPIA_COMMAND_ReadIDATA (INPUT | CPIA_MODULE_SYSTEM | 7)
-#define CPIA_COMMAND_WriteIDATA (OUTPUT | CPIA_MODULE_SYSTEM | 8)
-#define CPIA_COMMAND_GenericCall (OUTPUT | CPIA_MODULE_SYSTEM | 9)
-#define CPIA_COMMAND_I2CStart (OUTPUT | CPIA_MODULE_SYSTEM | 10)
-#define CPIA_COMMAND_I2CStop (OUTPUT | CPIA_MODULE_SYSTEM | 11)
-#define CPIA_COMMAND_I2CWrite (OUTPUT | CPIA_MODULE_SYSTEM | 12)
-#define CPIA_COMMAND_I2CRead (INPUT | CPIA_MODULE_SYSTEM | 13)
-
-#define CPIA_COMMAND_GetVPVersion (INPUT | CPIA_MODULE_VP_CTRL | 1)
-#define CPIA_COMMAND_ResetFrameCounter (INPUT | CPIA_MODULE_VP_CTRL | 2)
-#define CPIA_COMMAND_SetColourParams (OUTPUT | CPIA_MODULE_VP_CTRL | 3)
-#define CPIA_COMMAND_SetExposure (OUTPUT | CPIA_MODULE_VP_CTRL | 4)
-#define CPIA_COMMAND_SetColourBalance (OUTPUT | CPIA_MODULE_VP_CTRL | 6)
-#define CPIA_COMMAND_SetSensorFPS (OUTPUT | CPIA_MODULE_VP_CTRL | 7)
-#define CPIA_COMMAND_SetVPDefaults (OUTPUT | CPIA_MODULE_VP_CTRL | 8)
-#define CPIA_COMMAND_SetApcor (OUTPUT | CPIA_MODULE_VP_CTRL | 9)
-#define CPIA_COMMAND_SetFlickerCtrl (OUTPUT | CPIA_MODULE_VP_CTRL | 10)
-#define CPIA_COMMAND_SetVLOffset (OUTPUT | CPIA_MODULE_VP_CTRL | 11)
-#define CPIA_COMMAND_GetColourParams (INPUT | CPIA_MODULE_VP_CTRL | 16)
-#define CPIA_COMMAND_GetColourBalance (INPUT | CPIA_MODULE_VP_CTRL | 17)
-#define CPIA_COMMAND_GetExposure (INPUT | CPIA_MODULE_VP_CTRL | 18)
-#define CPIA_COMMAND_SetSensorMatrix (OUTPUT | CPIA_MODULE_VP_CTRL | 19)
-#define CPIA_COMMAND_ColourBars (OUTPUT | CPIA_MODULE_VP_CTRL | 25)
-#define CPIA_COMMAND_ReadVPRegs (INPUT | CPIA_MODULE_VP_CTRL | 30)
-#define CPIA_COMMAND_WriteVPReg (OUTPUT | CPIA_MODULE_VP_CTRL | 31)
-
-#define CPIA_COMMAND_GrabFrame (OUTPUT | CPIA_MODULE_CAPTURE | 1)
-#define CPIA_COMMAND_UploadFrame (OUTPUT | CPIA_MODULE_CAPTURE | 2)
-#define CPIA_COMMAND_SetGrabMode (OUTPUT | CPIA_MODULE_CAPTURE | 3)
-#define CPIA_COMMAND_InitStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 4)
-#define CPIA_COMMAND_FiniStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 5)
-#define CPIA_COMMAND_StartStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 6)
-#define CPIA_COMMAND_EndStreamCap (OUTPUT | CPIA_MODULE_CAPTURE | 7)
-#define CPIA_COMMAND_SetFormat (OUTPUT | CPIA_MODULE_CAPTURE | 8)
-#define CPIA_COMMAND_SetROI (OUTPUT | CPIA_MODULE_CAPTURE | 9)
-#define CPIA_COMMAND_SetCompression (OUTPUT | CPIA_MODULE_CAPTURE | 10)
-#define CPIA_COMMAND_SetCompressionTarget (OUTPUT | CPIA_MODULE_CAPTURE | 11)
-#define CPIA_COMMAND_SetYUVThresh (OUTPUT | CPIA_MODULE_CAPTURE | 12)
-#define CPIA_COMMAND_SetCompressionParams (OUTPUT | CPIA_MODULE_CAPTURE | 13)
-#define CPIA_COMMAND_DiscardFrame (OUTPUT | CPIA_MODULE_CAPTURE | 14)
-#define CPIA_COMMAND_GrabReset (OUTPUT | CPIA_MODULE_CAPTURE | 15)
-
-#define CPIA_COMMAND_OutputRS232 (OUTPUT | CPIA_MODULE_DEBUG | 1)
-#define CPIA_COMMAND_AbortProcess (OUTPUT | CPIA_MODULE_DEBUG | 4)
-#define CPIA_COMMAND_SetDramPage (OUTPUT | CPIA_MODULE_DEBUG | 5)
-#define CPIA_COMMAND_StartDramUpload (OUTPUT | CPIA_MODULE_DEBUG | 6)
-#define CPIA_COMMAND_StartDummyDtream (OUTPUT | CPIA_MODULE_DEBUG | 8)
-#define CPIA_COMMAND_AbortStream (OUTPUT | CPIA_MODULE_DEBUG | 9)
-#define CPIA_COMMAND_DownloadDRAM (OUTPUT | CPIA_MODULE_DEBUG | 10)
-#define CPIA_COMMAND_Null (OUTPUT | CPIA_MODULE_DEBUG | 11)
-
-enum {
- FRAME_READY, /* Ready to grab into */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
-};
-
-#define COMMAND_NONE 0x0000
-#define COMMAND_SETCOMPRESSION 0x0001
-#define COMMAND_SETCOMPRESSIONTARGET 0x0002
-#define COMMAND_SETCOLOURPARAMS 0x0004
-#define COMMAND_SETFORMAT 0x0008
-#define COMMAND_PAUSE 0x0010
-#define COMMAND_RESUME 0x0020
-#define COMMAND_SETYUVTHRESH 0x0040
-#define COMMAND_SETECPTIMING 0x0080
-#define COMMAND_SETCOMPRESSIONPARAMS 0x0100
-#define COMMAND_SETEXPOSURE 0x0200
-#define COMMAND_SETCOLOURBALANCE 0x0400
-#define COMMAND_SETSENSORFPS 0x0800
-#define COMMAND_SETAPCOR 0x1000
-#define COMMAND_SETFLICKERCTRL 0x2000
-#define COMMAND_SETVLOFFSET 0x4000
-#define COMMAND_SETLIGHTS 0x8000
-
-#define ROUND_UP_EXP_FOR_FLICKER 15
-
-/* Constants for automatic frame rate adjustment */
-#define MAX_EXP 302
-#define MAX_EXP_102 255
-#define LOW_EXP 140
-#define VERY_LOW_EXP 70
-#define TC 94
-#define EXP_ACC_DARK 50
-#define EXP_ACC_LIGHT 90
-#define HIGH_COMP_102 160
-#define MAX_COMP 239
-#define DARK_TIME 3
-#define LIGHT_TIME 3
-
-/* Maximum number of 10ms loops to wait for the stream to become ready */
-#define READY_TIMEOUT 100
-
-/* Developer's Guide Table 5 p 3-34
- * indexed by [mains][sensorFps.baserate][sensorFps.divisor]*/
-static u8 flicker_jumps[2][2][4] =
-{ { { 76, 38, 19, 9 }, { 92, 46, 23, 11 } },
- { { 64, 32, 16, 8 }, { 76, 38, 19, 9} }
-};
-
-/* forward declaration of local function */
-static void reset_camera_struct(struct cam_data *cam);
-static int find_over_exposure(int brightness);
-static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
- int on);
-
-
-/**********************************************************************
- *
- * Memory management
- *
- **********************************************************************/
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-/**********************************************************************
- *
- * /proc interface
- *
- **********************************************************************/
-#ifdef CONFIG_PROC_FS
-static struct proc_dir_entry *cpia_proc_root=NULL;
-
-static int cpia_proc_show(struct seq_file *m, void *v)
-{
- struct cam_data *cam = m->private;
- int tmp;
- char tmpstr[29];
-
- seq_printf(m, "read-only\n-----------------------\n");
- seq_printf(m, "V4L Driver version: %d.%d.%d\n",
- CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
- seq_printf(m, "CPIA Version: %d.%02d (%d.%d)\n",
- cam->params.version.firmwareVersion,
- cam->params.version.firmwareRevision,
- cam->params.version.vcVersion,
- cam->params.version.vcRevision);
- seq_printf(m, "CPIA PnP-ID: %04x:%04x:%04x\n",
- cam->params.pnpID.vendor, cam->params.pnpID.product,
- cam->params.pnpID.deviceRevision);
- seq_printf(m, "VP-Version: %d.%d %04x\n",
- cam->params.vpVersion.vpVersion,
- cam->params.vpVersion.vpRevision,
- cam->params.vpVersion.cameraHeadID);
-
- seq_printf(m, "system_state: %#04x\n",
- cam->params.status.systemState);
- seq_printf(m, "grab_state: %#04x\n",
- cam->params.status.grabState);
- seq_printf(m, "stream_state: %#04x\n",
- cam->params.status.streamState);
- seq_printf(m, "fatal_error: %#04x\n",
- cam->params.status.fatalError);
- seq_printf(m, "cmd_error: %#04x\n",
- cam->params.status.cmdError);
- seq_printf(m, "debug_flags: %#04x\n",
- cam->params.status.debugFlags);
- seq_printf(m, "vp_status: %#04x\n",
- cam->params.status.vpStatus);
- seq_printf(m, "error_code: %#04x\n",
- cam->params.status.errorCode);
- /* QX3 specific entries */
- if (cam->params.qx3.qx3_detected) {
- seq_printf(m, "button: %4d\n",
- cam->params.qx3.button);
- seq_printf(m, "cradled: %4d\n",
- cam->params.qx3.cradled);
- }
- seq_printf(m, "video_size: %s\n",
- cam->params.format.videoSize == VIDEOSIZE_CIF ?
- "CIF " : "QCIF");
- seq_printf(m, "roi: (%3d, %3d) to (%3d, %3d)\n",
- cam->params.roi.colStart*8,
- cam->params.roi.rowStart*4,
- cam->params.roi.colEnd*8,
- cam->params.roi.rowEnd*4);
- seq_printf(m, "actual_fps: %3d\n", cam->fps);
- seq_printf(m, "transfer_rate: %4dkB/s\n",
- cam->transfer_rate);
-
- seq_printf(m, "\nread-write\n");
- seq_printf(m, "----------------------- current min"
- " max default comment\n");
- seq_printf(m, "brightness: %8d %8d %8d %8d\n",
- cam->params.colourParams.brightness, 0, 100, 50);
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2)
- /* 1-02 firmware limits contrast to 80 */
- tmp = 80;
- else
- tmp = 96;
-
- seq_printf(m, "contrast: %8d %8d %8d %8d"
- " steps of 8\n",
- cam->params.colourParams.contrast, 0, tmp, 48);
- seq_printf(m, "saturation: %8d %8d %8d %8d\n",
- cam->params.colourParams.saturation, 0, 100, 50);
- tmp = (25000+5000*cam->params.sensorFps.baserate)/
- (1<<cam->params.sensorFps.divisor);
- seq_printf(m, "sensor_fps: %4d.%03d %8d %8d %8d\n",
- tmp/1000, tmp%1000, 3, 30, 15);
- seq_printf(m, "stream_start_line: %8d %8d %8d %8d\n",
- 2*cam->params.streamStartLine, 0,
- cam->params.format.videoSize == VIDEOSIZE_CIF ? 288:144,
- cam->params.format.videoSize == VIDEOSIZE_CIF ? 240:120);
- seq_printf(m, "sub_sample: %8s %8s %8s %8s\n",
- cam->params.format.subSample == SUBSAMPLE_420 ?
- "420" : "422", "420", "422", "422");
- seq_printf(m, "yuv_order: %8s %8s %8s %8s\n",
- cam->params.format.yuvOrder == YUVORDER_YUYV ?
- "YUYV" : "UYVY", "YUYV" , "UYVY", "YUYV");
- seq_printf(m, "ecp_timing: %8s %8s %8s %8s\n",
- cam->params.ecpTiming ? "slow" : "normal", "slow",
- "normal", "normal");
-
- if (cam->params.colourBalance.balanceMode == 2) {
- sprintf(tmpstr, "auto");
- } else {
- sprintf(tmpstr, "manual");
- }
- seq_printf(m, "color_balance_mode: %8s %8s %8s"
- " %8s\n", tmpstr, "manual", "auto", "auto");
- seq_printf(m, "red_gain: %8d %8d %8d %8d\n",
- cam->params.colourBalance.redGain, 0, 212, 32);
- seq_printf(m, "green_gain: %8d %8d %8d %8d\n",
- cam->params.colourBalance.greenGain, 0, 212, 6);
- seq_printf(m, "blue_gain: %8d %8d %8d %8d\n",
- cam->params.colourBalance.blueGain, 0, 212, 92);
-
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2)
- /* 1-02 firmware limits gain to 2 */
- sprintf(tmpstr, "%8d %8d %8d", 1, 2, 2);
- else
- sprintf(tmpstr, "%8d %8d %8d", 1, 8, 2);
-
- if (cam->params.exposure.gainMode == 0)
- seq_printf(m, "max_gain: unknown %28s"
- " powers of 2\n", tmpstr);
- else
- seq_printf(m, "max_gain: %8d %28s"
- " 1,2,4 or 8 \n",
- 1<<(cam->params.exposure.gainMode-1), tmpstr);
-
- switch(cam->params.exposure.expMode) {
- case 1:
- case 3:
- sprintf(tmpstr, "manual");
- break;
- case 2:
- sprintf(tmpstr, "auto");
- break;
- default:
- sprintf(tmpstr, "unknown");
- break;
- }
- seq_printf(m, "exposure_mode: %8s %8s %8s"
- " %8s\n", tmpstr, "manual", "auto", "auto");
- seq_printf(m, "centre_weight: %8s %8s %8s %8s\n",
- (2-cam->params.exposure.centreWeight) ? "on" : "off",
- "off", "on", "on");
- seq_printf(m, "gain: %8d %8d max_gain %8d 1,2,4,8 possible\n",
- 1<<cam->params.exposure.gain, 1, 1);
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2)
- /* 1-02 firmware limits fineExp/2 to 127 */
- tmp = 254;
- else
- tmp = 510;
-
- seq_printf(m, "fine_exp: %8d %8d %8d %8d\n",
- cam->params.exposure.fineExp*2, 0, tmp, 0);
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2)
- /* 1-02 firmware limits coarseExpHi to 0 */
- tmp = MAX_EXP_102;
- else
- tmp = MAX_EXP;
-
- seq_printf(m, "coarse_exp: %8d %8d %8d"
- " %8d\n", cam->params.exposure.coarseExpLo+
- 256*cam->params.exposure.coarseExpHi, 0, tmp, 185);
- seq_printf(m, "red_comp: %8d %8d %8d %8d\n",
- cam->params.exposure.redComp, COMP_RED, 255, COMP_RED);
- seq_printf(m, "green1_comp: %8d %8d %8d %8d\n",
- cam->params.exposure.green1Comp, COMP_GREEN1, 255,
- COMP_GREEN1);
- seq_printf(m, "green2_comp: %8d %8d %8d %8d\n",
- cam->params.exposure.green2Comp, COMP_GREEN2, 255,
- COMP_GREEN2);
- seq_printf(m, "blue_comp: %8d %8d %8d %8d\n",
- cam->params.exposure.blueComp, COMP_BLUE, 255, COMP_BLUE);
-
- seq_printf(m, "apcor_gain1: %#8x %#8x %#8x %#8x\n",
- cam->params.apcor.gain1, 0, 0xff, 0x1c);
- seq_printf(m, "apcor_gain2: %#8x %#8x %#8x %#8x\n",
- cam->params.apcor.gain2, 0, 0xff, 0x1a);
- seq_printf(m, "apcor_gain4: %#8x %#8x %#8x %#8x\n",
- cam->params.apcor.gain4, 0, 0xff, 0x2d);
- seq_printf(m, "apcor_gain8: %#8x %#8x %#8x %#8x\n",
- cam->params.apcor.gain8, 0, 0xff, 0x2a);
- seq_printf(m, "vl_offset_gain1: %8d %8d %8d %8d\n",
- cam->params.vlOffset.gain1, 0, 255, 24);
- seq_printf(m, "vl_offset_gain2: %8d %8d %8d %8d\n",
- cam->params.vlOffset.gain2, 0, 255, 28);
- seq_printf(m, "vl_offset_gain4: %8d %8d %8d %8d\n",
- cam->params.vlOffset.gain4, 0, 255, 30);
- seq_printf(m, "vl_offset_gain8: %8d %8d %8d %8d\n",
- cam->params.vlOffset.gain8, 0, 255, 30);
- seq_printf(m, "flicker_control: %8s %8s %8s %8s\n",
- cam->params.flickerControl.flickerMode ? "on" : "off",
- "off", "on", "off");
- seq_printf(m, "mains_frequency: %8d %8d %8d %8d"
- " only 50/60\n",
- cam->mainsFreq ? 60 : 50, 50, 60, 50);
- if(cam->params.flickerControl.allowableOverExposure < 0)
- seq_printf(m, "allowable_overexposure: %4dauto auto %8d auto\n",
- -cam->params.flickerControl.allowableOverExposure,
- 255);
- else
- seq_printf(m, "allowable_overexposure: %8d auto %8d auto\n",
- cam->params.flickerControl.allowableOverExposure,
- 255);
- seq_printf(m, "compression_mode: ");
- switch(cam->params.compression.mode) {
- case CPIA_COMPRESSION_NONE:
- seq_printf(m, "%8s", "none");
- break;
- case CPIA_COMPRESSION_AUTO:
- seq_printf(m, "%8s", "auto");
- break;
- case CPIA_COMPRESSION_MANUAL:
- seq_printf(m, "%8s", "manual");
- break;
- default:
- seq_printf(m, "%8s", "unknown");
- break;
- }
- seq_printf(m, " none,auto,manual auto\n");
- seq_printf(m, "decimation_enable: %8s %8s %8s %8s\n",
- cam->params.compression.decimation ==
- DECIMATION_ENAB ? "on":"off", "off", "on",
- "off");
- seq_printf(m, "compression_target: %9s %9s %9s %9s\n",
- cam->params.compressionTarget.frTargeting ==
- CPIA_COMPRESSION_TARGET_FRAMERATE ?
- "framerate":"quality",
- "framerate", "quality", "quality");
- seq_printf(m, "target_framerate: %8d %8d %8d %8d\n",
- cam->params.compressionTarget.targetFR, 1, 30, 15);
- seq_printf(m, "target_quality: %8d %8d %8d %8d\n",
- cam->params.compressionTarget.targetQ, 1, 64, 5);
- seq_printf(m, "y_threshold: %8d %8d %8d %8d\n",
- cam->params.yuvThreshold.yThreshold, 0, 31, 6);
- seq_printf(m, "uv_threshold: %8d %8d %8d %8d\n",
- cam->params.yuvThreshold.uvThreshold, 0, 31, 6);
- seq_printf(m, "hysteresis: %8d %8d %8d %8d\n",
- cam->params.compressionParams.hysteresis, 0, 255, 3);
- seq_printf(m, "threshold_max: %8d %8d %8d %8d\n",
- cam->params.compressionParams.threshMax, 0, 255, 11);
- seq_printf(m, "small_step: %8d %8d %8d %8d\n",
- cam->params.compressionParams.smallStep, 0, 255, 1);
- seq_printf(m, "large_step: %8d %8d %8d %8d\n",
- cam->params.compressionParams.largeStep, 0, 255, 3);
- seq_printf(m, "decimation_hysteresis: %8d %8d %8d %8d\n",
- cam->params.compressionParams.decimationHysteresis,
- 0, 255, 2);
- seq_printf(m, "fr_diff_step_thresh: %8d %8d %8d %8d\n",
- cam->params.compressionParams.frDiffStepThresh,
- 0, 255, 5);
- seq_printf(m, "q_diff_step_thresh: %8d %8d %8d %8d\n",
- cam->params.compressionParams.qDiffStepThresh,
- 0, 255, 3);
- seq_printf(m, "decimation_thresh_mod: %8d %8d %8d %8d\n",
- cam->params.compressionParams.decimationThreshMod,
- 0, 255, 2);
- /* QX3 specific entries */
- if (cam->params.qx3.qx3_detected) {
- seq_printf(m, "toplight: %8s %8s %8s %8s\n",
- cam->params.qx3.toplight ? "on" : "off",
- "off", "on", "off");
- seq_printf(m, "bottomlight: %8s %8s %8s %8s\n",
- cam->params.qx3.bottomlight ? "on" : "off",
- "off", "on", "off");
- }
-
- return 0;
-}
-
-static int cpia_proc_open(struct inode *inode, struct file *file)
-{
- return single_open(file, cpia_proc_show, PDE(inode)->data);
-}
-
-static int match(char *checkstr, char **buffer, size_t *count,
- int *find_colon, int *err)
-{
- int ret, colon_found = 1;
- int len = strlen(checkstr);
- ret = (len <= *count && strncmp(*buffer, checkstr, len) == 0);
- if (ret) {
- *buffer += len;
- *count -= len;
- if (*find_colon) {
- colon_found = 0;
- while (*count && (**buffer == ' ' || **buffer == '\t' ||
- (!colon_found && **buffer == ':'))) {
- if (**buffer == ':')
- colon_found = 1;
- --*count;
- ++*buffer;
- }
- if (!*count || !colon_found)
- *err = -EINVAL;
- *find_colon = 0;
- }
- }
- return ret;
-}
-
-static unsigned long int value(char **buffer, size_t *count, int *err)
-{
- char *p;
- unsigned long int ret;
- ret = simple_strtoul(*buffer, &p, 0);
- if (p == *buffer)
- *err = -EINVAL;
- else {
- *count -= p - *buffer;
- *buffer = p;
- }
- return ret;
-}
-
-static ssize_t cpia_proc_write(struct file *file, const char __user *buf,
- size_t count, loff_t *pos)
-{
- struct cam_data *cam = PDE(file->f_path.dentry->d_inode)->data;
- struct cam_params new_params;
- char *page, *buffer;
- int retval, find_colon;
- int size = count;
- unsigned long val = 0;
- u32 command_flags = 0;
- u8 new_mains;
-
- /*
- * This code to copy from buf to page is shamelessly copied
- * from the comx driver
- */
- if (count > PAGE_SIZE) {
- printk(KERN_ERR "count is %zu > %d!!!\n", count, (int)PAGE_SIZE);
- return -ENOSPC;
- }
-
- if (!(page = (char *)__get_free_page(GFP_KERNEL))) return -ENOMEM;
-
- if(copy_from_user(page, buf, count))
- {
- retval = -EFAULT;
- goto out;
- }
-
- if (page[count-1] == '\n')
- page[count-1] = '\0';
- else if (count < PAGE_SIZE)
- page[count] = '\0';
- else if (page[count]) {
- retval = -EINVAL;
- goto out;
- }
-
- buffer = page;
-
- if (mutex_lock_interruptible(&cam->param_lock))
- return -ERESTARTSYS;
-
- /*
- * Skip over leading whitespace
- */
- while (count && isspace(*buffer)) {
- --count;
- ++buffer;
- }
-
- memcpy(&new_params, &cam->params, sizeof(struct cam_params));
- new_mains = cam->mainsFreq;
-
-#define MATCH(x) (match(x, &buffer, &count, &find_colon, &retval))
-#define VALUE (value(&buffer,&count, &retval))
-#define FIRMWARE_VERSION(x,y) (new_params.version.firmwareVersion == (x) && \
- new_params.version.firmwareRevision == (y))
-
- retval = 0;
- while (count && !retval) {
- find_colon = 1;
- if (MATCH("brightness")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 100)
- new_params.colourParams.brightness = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURPARAMS;
- if(new_params.flickerControl.allowableOverExposure < 0)
- new_params.flickerControl.allowableOverExposure =
- -find_over_exposure(new_params.colourParams.brightness);
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
-
- } else if (MATCH("contrast")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 100) {
- /* contrast is in steps of 8, so round*/
- val = ((val + 3) / 8) * 8;
- /* 1-02 firmware limits contrast to 80*/
- if (FIRMWARE_VERSION(1,2) && val > 80)
- val = 80;
-
- new_params.colourParams.contrast = val;
- } else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURPARAMS;
- } else if (MATCH("saturation")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 100)
- new_params.colourParams.saturation = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURPARAMS;
- } else if (MATCH("sensor_fps")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- /* find values so that sensorFPS is minimized,
- * but >= val */
- if (val > 30)
- retval = -EINVAL;
- else if (val > 25) {
- new_params.sensorFps.divisor = 0;
- new_params.sensorFps.baserate = 1;
- } else if (val > 15) {
- new_params.sensorFps.divisor = 0;
- new_params.sensorFps.baserate = 0;
- } else if (val > 12) {
- new_params.sensorFps.divisor = 1;
- new_params.sensorFps.baserate = 1;
- } else if (val > 7) {
- new_params.sensorFps.divisor = 1;
- new_params.sensorFps.baserate = 0;
- } else if (val > 6) {
- new_params.sensorFps.divisor = 2;
- new_params.sensorFps.baserate = 1;
- } else if (val > 3) {
- new_params.sensorFps.divisor = 2;
- new_params.sensorFps.baserate = 0;
- } else {
- new_params.sensorFps.divisor = 3;
- /* Either base rate would work here */
- new_params.sensorFps.baserate = 1;
- }
- new_params.flickerControl.coarseJump =
- flicker_jumps[new_mains]
- [new_params.sensorFps.baserate]
- [new_params.sensorFps.divisor];
- if (new_params.flickerControl.flickerMode)
- command_flags |= COMMAND_SETFLICKERCTRL;
- }
- command_flags |= COMMAND_SETSENSORFPS;
- cam->exposure_status = EXPOSURE_NORMAL;
- } else if (MATCH("stream_start_line")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- int max_line = 288;
-
- if (new_params.format.videoSize == VIDEOSIZE_QCIF)
- max_line = 144;
- if (val <= max_line)
- new_params.streamStartLine = val/2;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("sub_sample")) {
- if (!retval && MATCH("420"))
- new_params.format.subSample = SUBSAMPLE_420;
- else if (!retval && MATCH("422"))
- new_params.format.subSample = SUBSAMPLE_422;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETFORMAT;
- } else if (MATCH("yuv_order")) {
- if (!retval && MATCH("YUYV"))
- new_params.format.yuvOrder = YUVORDER_YUYV;
- else if (!retval && MATCH("UYVY"))
- new_params.format.yuvOrder = YUVORDER_UYVY;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETFORMAT;
- } else if (MATCH("ecp_timing")) {
- if (!retval && MATCH("normal"))
- new_params.ecpTiming = 0;
- else if (!retval && MATCH("slow"))
- new_params.ecpTiming = 1;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETECPTIMING;
- } else if (MATCH("color_balance_mode")) {
- if (!retval && MATCH("manual"))
- new_params.colourBalance.balanceMode = 3;
- else if (!retval && MATCH("auto"))
- new_params.colourBalance.balanceMode = 2;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETCOLOURBALANCE;
- } else if (MATCH("red_gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 212) {
- new_params.colourBalance.redGain = val;
- new_params.colourBalance.balanceMode = 1;
- } else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURBALANCE;
- } else if (MATCH("green_gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 212) {
- new_params.colourBalance.greenGain = val;
- new_params.colourBalance.balanceMode = 1;
- } else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURBALANCE;
- } else if (MATCH("blue_gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 212) {
- new_params.colourBalance.blueGain = val;
- new_params.colourBalance.balanceMode = 1;
- } else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOLOURBALANCE;
- } else if (MATCH("max_gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- /* 1-02 firmware limits gain to 2 */
- if (FIRMWARE_VERSION(1,2) && val > 2)
- val = 2;
- switch(val) {
- case 1:
- new_params.exposure.gainMode = 1;
- break;
- case 2:
- new_params.exposure.gainMode = 2;
- break;
- case 4:
- new_params.exposure.gainMode = 3;
- break;
- case 8:
- new_params.exposure.gainMode = 4;
- break;
- default:
- retval = -EINVAL;
- break;
- }
- }
- command_flags |= COMMAND_SETEXPOSURE;
- } else if (MATCH("exposure_mode")) {
- if (!retval && MATCH("auto"))
- new_params.exposure.expMode = 2;
- else if (!retval && MATCH("manual")) {
- if (new_params.exposure.expMode == 2)
- new_params.exposure.expMode = 3;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- new_params.flickerControl.flickerMode = 0;
- } else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETEXPOSURE;
- } else if (MATCH("centre_weight")) {
- if (!retval && MATCH("on"))
- new_params.exposure.centreWeight = 1;
- else if (!retval && MATCH("off"))
- new_params.exposure.centreWeight = 2;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETEXPOSURE;
- } else if (MATCH("gain")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- switch(val) {
- case 1:
- new_params.exposure.gain = 0;
- break;
- case 2:
- new_params.exposure.gain = 1;
- break;
- case 4:
- new_params.exposure.gain = 2;
- break;
- case 8:
- new_params.exposure.gain = 3;
- break;
- default:
- retval = -EINVAL;
- break;
- }
- new_params.exposure.expMode = 1;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- new_params.flickerControl.flickerMode = 0;
- command_flags |= COMMAND_SETEXPOSURE;
- if (new_params.exposure.gain >
- new_params.exposure.gainMode-1)
- retval = -EINVAL;
- }
- } else if (MATCH("fine_exp")) {
- if (!retval)
- val = VALUE/2;
-
- if (!retval) {
- if (val < 256) {
- /* 1-02 firmware limits fineExp/2 to 127*/
- if (FIRMWARE_VERSION(1,2) && val > 127)
- val = 127;
- new_params.exposure.fineExp = val;
- new_params.exposure.expMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- new_params.flickerControl.flickerMode = 0;
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("coarse_exp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= MAX_EXP) {
- if (FIRMWARE_VERSION(1,2) &&
- val > MAX_EXP_102)
- val = MAX_EXP_102;
- new_params.exposure.coarseExpLo =
- val & 0xff;
- new_params.exposure.coarseExpHi =
- val >> 8;
- new_params.exposure.expMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- new_params.flickerControl.flickerMode = 0;
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("red_comp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val >= COMP_RED && val <= 255) {
- new_params.exposure.redComp = val;
- new_params.exposure.compMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("green1_comp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val >= COMP_GREEN1 && val <= 255) {
- new_params.exposure.green1Comp = val;
- new_params.exposure.compMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("green2_comp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val >= COMP_GREEN2 && val <= 255) {
- new_params.exposure.green2Comp = val;
- new_params.exposure.compMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("blue_comp")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val >= COMP_BLUE && val <= 255) {
- new_params.exposure.blueComp = val;
- new_params.exposure.compMode = 1;
- command_flags |= COMMAND_SETEXPOSURE;
- } else
- retval = -EINVAL;
- }
- } else if (MATCH("apcor_gain1")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- command_flags |= COMMAND_SETAPCOR;
- if (val <= 0xff)
- new_params.apcor.gain1 = val;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("apcor_gain2")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- command_flags |= COMMAND_SETAPCOR;
- if (val <= 0xff)
- new_params.apcor.gain2 = val;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("apcor_gain4")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- command_flags |= COMMAND_SETAPCOR;
- if (val <= 0xff)
- new_params.apcor.gain4 = val;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("apcor_gain8")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- command_flags |= COMMAND_SETAPCOR;
- if (val <= 0xff)
- new_params.apcor.gain8 = val;
- else
- retval = -EINVAL;
- }
- } else if (MATCH("vl_offset_gain1")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.vlOffset.gain1 = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETVLOFFSET;
- } else if (MATCH("vl_offset_gain2")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.vlOffset.gain2 = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETVLOFFSET;
- } else if (MATCH("vl_offset_gain4")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.vlOffset.gain4 = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETVLOFFSET;
- } else if (MATCH("vl_offset_gain8")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.vlOffset.gain8 = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETVLOFFSET;
- } else if (MATCH("flicker_control")) {
- if (!retval && MATCH("on")) {
- set_flicker(&new_params, &command_flags, 1);
- } else if (!retval && MATCH("off")) {
- set_flicker(&new_params, &command_flags, 0);
- } else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else if (MATCH("mains_frequency")) {
- if (!retval && MATCH("50")) {
- new_mains = 0;
- new_params.flickerControl.coarseJump =
- flicker_jumps[new_mains]
- [new_params.sensorFps.baserate]
- [new_params.sensorFps.divisor];
- if (new_params.flickerControl.flickerMode)
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else if (!retval && MATCH("60")) {
- new_mains = 1;
- new_params.flickerControl.coarseJump =
- flicker_jumps[new_mains]
- [new_params.sensorFps.baserate]
- [new_params.sensorFps.divisor];
- if (new_params.flickerControl.flickerMode)
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else
- retval = -EINVAL;
- } else if (MATCH("allowable_overexposure")) {
- if (!retval && MATCH("auto")) {
- new_params.flickerControl.allowableOverExposure =
- -find_over_exposure(new_params.colourParams.brightness);
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff) {
- new_params.flickerControl.
- allowableOverExposure = val;
- if(new_params.flickerControl.flickerMode != 0)
- command_flags |= COMMAND_SETFLICKERCTRL;
- } else
- retval = -EINVAL;
- }
- }
- } else if (MATCH("compression_mode")) {
- if (!retval && MATCH("none"))
- new_params.compression.mode =
- CPIA_COMPRESSION_NONE;
- else if (!retval && MATCH("auto"))
- new_params.compression.mode =
- CPIA_COMPRESSION_AUTO;
- else if (!retval && MATCH("manual"))
- new_params.compression.mode =
- CPIA_COMPRESSION_MANUAL;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETCOMPRESSION;
- } else if (MATCH("decimation_enable")) {
- if (!retval && MATCH("off"))
- new_params.compression.decimation = 0;
- else if (!retval && MATCH("on"))
- new_params.compression.decimation = 1;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETCOMPRESSION;
- } else if (MATCH("compression_target")) {
- if (!retval && MATCH("quality"))
- new_params.compressionTarget.frTargeting =
- CPIA_COMPRESSION_TARGET_QUALITY;
- else if (!retval && MATCH("framerate"))
- new_params.compressionTarget.frTargeting =
- CPIA_COMPRESSION_TARGET_FRAMERATE;
- else
- retval = -EINVAL;
-
- command_flags |= COMMAND_SETCOMPRESSIONTARGET;
- } else if (MATCH("target_framerate")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if(val > 0 && val <= 30)
- new_params.compressionTarget.targetFR = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONTARGET;
- } else if (MATCH("target_quality")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if(val > 0 && val <= 64)
- new_params.compressionTarget.targetQ = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONTARGET;
- } else if (MATCH("y_threshold")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val < 32)
- new_params.yuvThreshold.yThreshold = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETYUVTHRESH;
- } else if (MATCH("uv_threshold")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val < 32)
- new_params.yuvThreshold.uvThreshold = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETYUVTHRESH;
- } else if (MATCH("hysteresis")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.hysteresis = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("threshold_max")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.threshMax = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("small_step")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.smallStep = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("large_step")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.largeStep = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("decimation_hysteresis")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.decimationHysteresis = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("fr_diff_step_thresh")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.frDiffStepThresh = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("q_diff_step_thresh")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.qDiffStepThresh = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("decimation_thresh_mod")) {
- if (!retval)
- val = VALUE;
-
- if (!retval) {
- if (val <= 0xff)
- new_params.compressionParams.decimationThreshMod = val;
- else
- retval = -EINVAL;
- }
- command_flags |= COMMAND_SETCOMPRESSIONPARAMS;
- } else if (MATCH("toplight")) {
- if (!retval && MATCH("on"))
- new_params.qx3.toplight = 1;
- else if (!retval && MATCH("off"))
- new_params.qx3.toplight = 0;
- else
- retval = -EINVAL;
- command_flags |= COMMAND_SETLIGHTS;
- } else if (MATCH("bottomlight")) {
- if (!retval && MATCH("on"))
- new_params.qx3.bottomlight = 1;
- else if (!retval && MATCH("off"))
- new_params.qx3.bottomlight = 0;
- else
- retval = -EINVAL;
- command_flags |= COMMAND_SETLIGHTS;
- } else {
- DBG("No match found\n");
- retval = -EINVAL;
- }
-
- if (!retval) {
- while (count && isspace(*buffer) && *buffer != '\n') {
- --count;
- ++buffer;
- }
- if (count) {
- if (*buffer == '\0' && count != 1)
- retval = -EINVAL;
- else if (*buffer != '\n' && *buffer != ';' &&
- *buffer != '\0')
- retval = -EINVAL;
- else {
- --count;
- ++buffer;
- }
- }
- }
- }
-#undef MATCH
-#undef VALUE
-#undef FIRMWARE_VERSION
- if (!retval) {
- if (command_flags & COMMAND_SETCOLOURPARAMS) {
- /* Adjust cam->vp to reflect these changes */
- cam->vp.brightness =
- new_params.colourParams.brightness*65535/100;
- cam->vp.contrast =
- new_params.colourParams.contrast*65535/100;
- cam->vp.colour =
- new_params.colourParams.saturation*65535/100;
- }
- if((command_flags & COMMAND_SETEXPOSURE) &&
- new_params.exposure.expMode == 2)
- cam->exposure_status = EXPOSURE_NORMAL;
-
- memcpy(&cam->params, &new_params, sizeof(struct cam_params));
- cam->mainsFreq = new_mains;
- cam->cmd_queue |= command_flags;
- retval = size;
- } else
- DBG("error: %d\n", retval);
-
- mutex_unlock(&cam->param_lock);
-
-out:
- free_page((unsigned long)page);
- return retval;
-}
-
-static const struct file_operations cpia_proc_fops = {
- .owner = THIS_MODULE,
- .open = cpia_proc_open,
- .read = seq_read,
- .llseek = seq_lseek,
- .release = single_release,
- .write = cpia_proc_write,
-};
-
-static void create_proc_cpia_cam(struct cam_data *cam)
-{
- struct proc_dir_entry *ent;
-
- if (!cpia_proc_root || !cam)
- return;
-
- ent = proc_create_data(video_device_node_name(&cam->vdev),
- S_IRUGO|S_IWUSR, cpia_proc_root,
- &cpia_proc_fops, cam);
- if (!ent)
- return;
-
- /*
- size of the proc entry is 3736 bytes for the standard webcam;
- the extra features of the QX3 microscope add 189 bytes.
- (we have not yet probed the camera to see which type it is).
- */
- ent->size = 3736 + 189;
- cam->proc_entry = ent;
-}
-
-static void destroy_proc_cpia_cam(struct cam_data *cam)
-{
- if (!cam || !cam->proc_entry)
- return;
-
- remove_proc_entry(video_device_node_name(&cam->vdev), cpia_proc_root);
- cam->proc_entry = NULL;
-}
-
-static void proc_cpia_create(void)
-{
- cpia_proc_root = proc_mkdir("cpia", NULL);
-
- if (!cpia_proc_root)
- LOG("Unable to initialise /proc/cpia\n");
-}
-
-static void __exit proc_cpia_destroy(void)
-{
- remove_proc_entry("cpia", NULL);
-}
-#endif /* CONFIG_PROC_FS */
-
-/* ----------------------- debug functions ---------------------- */
-
-#define printstatus(cam) \
- DBG("%02x %02x %02x %02x %02x %02x %02x %02x\n",\
- cam->params.status.systemState, cam->params.status.grabState, \
- cam->params.status.streamState, cam->params.status.fatalError, \
- cam->params.status.cmdError, cam->params.status.debugFlags, \
- cam->params.status.vpStatus, cam->params.status.errorCode);
-
-/* ----------------------- v4l helpers -------------------------- */
-
-/* supported frame palettes and depths */
-static inline int valid_mode(u16 palette, u16 depth)
-{
- if ((palette == VIDEO_PALETTE_YUV422 && depth == 16) ||
- (palette == VIDEO_PALETTE_YUYV && depth == 16))
- return 1;
-
- if (colorspace_conv)
- return (palette == VIDEO_PALETTE_GREY && depth == 8) ||
- (palette == VIDEO_PALETTE_RGB555 && depth == 16) ||
- (palette == VIDEO_PALETTE_RGB565 && depth == 16) ||
- (palette == VIDEO_PALETTE_RGB24 && depth == 24) ||
- (palette == VIDEO_PALETTE_RGB32 && depth == 32) ||
- (palette == VIDEO_PALETTE_UYVY && depth == 16);
-
- return 0;
-}
-
-static int match_videosize( int width, int height )
-{
- /* return the best match, where 'best' is as always
- * the largest that is not bigger than what is requested. */
- if (width>=352 && height>=288)
- return VIDEOSIZE_352_288; /* CIF */
-
- if (width>=320 && height>=240)
- return VIDEOSIZE_320_240; /* SIF */
-
- if (width>=288 && height>=216)
- return VIDEOSIZE_288_216;
-
- if (width>=256 && height>=192)
- return VIDEOSIZE_256_192;
-
- if (width>=224 && height>=168)
- return VIDEOSIZE_224_168;
-
- if (width>=192 && height>=144)
- return VIDEOSIZE_192_144;
-
- if (width>=176 && height>=144)
- return VIDEOSIZE_176_144; /* QCIF */
-
- if (width>=160 && height>=120)
- return VIDEOSIZE_160_120; /* QSIF */
-
- if (width>=128 && height>=96)
- return VIDEOSIZE_128_96;
-
- if (width>=88 && height>=72)
- return VIDEOSIZE_88_72;
-
- if (width>=64 && height>=48)
- return VIDEOSIZE_64_48;
-
- if (width>=48 && height>=48)
- return VIDEOSIZE_48_48;
-
- return -1;
-}
-
-/* these are the capture sizes we support */
-static void set_vw_size(struct cam_data *cam)
-{
- /* the col/row/start/end values are the result of simple math */
- /* study the SetROI-command in cpia developers guide p 2-22 */
- /* streamStartLine is set to the recommended value in the cpia */
- /* developers guide p 3-37 */
- switch(cam->video_size) {
- case VIDEOSIZE_CIF:
- cam->vw.width = 352;
- cam->vw.height = 288;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=0;
- cam->params.roi.rowStart=0;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_SIF:
- cam->vw.width = 320;
- cam->vw.height = 240;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=2;
- cam->params.roi.rowStart=6;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_288_216:
- cam->vw.width = 288;
- cam->vw.height = 216;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=4;
- cam->params.roi.rowStart=9;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_256_192:
- cam->vw.width = 256;
- cam->vw.height = 192;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=6;
- cam->params.roi.rowStart=12;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_224_168:
- cam->vw.width = 224;
- cam->vw.height = 168;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=8;
- cam->params.roi.rowStart=15;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_192_144:
- cam->vw.width = 192;
- cam->vw.height = 144;
- cam->params.format.videoSize=VIDEOSIZE_CIF;
- cam->params.roi.colStart=10;
- cam->params.roi.rowStart=18;
- cam->params.streamStartLine = 120;
- break;
- case VIDEOSIZE_QCIF:
- cam->vw.width = 176;
- cam->vw.height = 144;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=0;
- cam->params.roi.rowStart=0;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_QSIF:
- cam->vw.width = 160;
- cam->vw.height = 120;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=1;
- cam->params.roi.rowStart=3;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_128_96:
- cam->vw.width = 128;
- cam->vw.height = 96;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=3;
- cam->params.roi.rowStart=6;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_88_72:
- cam->vw.width = 88;
- cam->vw.height = 72;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=5;
- cam->params.roi.rowStart=9;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_64_48:
- cam->vw.width = 64;
- cam->vw.height = 48;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=7;
- cam->params.roi.rowStart=12;
- cam->params.streamStartLine = 60;
- break;
- case VIDEOSIZE_48_48:
- cam->vw.width = 48;
- cam->vw.height = 48;
- cam->params.format.videoSize=VIDEOSIZE_QCIF;
- cam->params.roi.colStart=8;
- cam->params.roi.rowStart=6;
- cam->params.streamStartLine = 60;
- break;
- default:
- LOG("bad videosize value: %d\n", cam->video_size);
- return;
- }
-
- if(cam->vc.width == 0)
- cam->vc.width = cam->vw.width;
- if(cam->vc.height == 0)
- cam->vc.height = cam->vw.height;
-
- cam->params.roi.colStart += cam->vc.x >> 3;
- cam->params.roi.colEnd = cam->params.roi.colStart +
- (cam->vc.width >> 3);
- cam->params.roi.rowStart += cam->vc.y >> 2;
- cam->params.roi.rowEnd = cam->params.roi.rowStart +
- (cam->vc.height >> 2);
-
- return;
-}
-
-static int allocate_frame_buf(struct cam_data *cam)
-{
- int i;
-
- cam->frame_buf = rvmalloc(FRAME_NUM * CPIA_MAX_FRAME_SIZE);
- if (!cam->frame_buf)
- return -ENOBUFS;
-
- for (i = 0; i < FRAME_NUM; i++)
- cam->frame[i].data = cam->frame_buf + i * CPIA_MAX_FRAME_SIZE;
-
- return 0;
-}
-
-static int free_frame_buf(struct cam_data *cam)
-{
- int i;
-
- rvfree(cam->frame_buf, FRAME_NUM*CPIA_MAX_FRAME_SIZE);
- cam->frame_buf = NULL;
- for (i=0; i < FRAME_NUM; i++)
- cam->frame[i].data = NULL;
-
- return 0;
-}
-
-
-static inline void free_frames(struct cpia_frame frame[FRAME_NUM])
-{
- int i;
-
- for (i=0; i < FRAME_NUM; i++)
- frame[i].state = FRAME_UNUSED;
- return;
-}
-
-/**********************************************************************
- *
- * General functions
- *
- **********************************************************************/
-/* send an arbitrary command to the camera */
-static int do_command(struct cam_data *cam, u16 command, u8 a, u8 b, u8 c, u8 d)
-{
- int retval, datasize;
- u8 cmd[8], data[8];
-
- switch(command) {
- case CPIA_COMMAND_GetCPIAVersion:
- case CPIA_COMMAND_GetPnPID:
- case CPIA_COMMAND_GetCameraStatus:
- case CPIA_COMMAND_GetVPVersion:
- datasize=8;
- break;
- case CPIA_COMMAND_GetColourParams:
- case CPIA_COMMAND_GetColourBalance:
- case CPIA_COMMAND_GetExposure:
- mutex_lock(&cam->param_lock);
- datasize=8;
- break;
- case CPIA_COMMAND_ReadMCPorts:
- case CPIA_COMMAND_ReadVCRegs:
- datasize = 4;
- break;
- default:
- datasize=0;
- break;
- }
-
- cmd[0] = command>>8;
- cmd[1] = command&0xff;
- cmd[2] = a;
- cmd[3] = b;
- cmd[4] = c;
- cmd[5] = d;
- cmd[6] = datasize;
- cmd[7] = 0;
-
- retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
- if (retval) {
- DBG("%x - failed, retval=%d\n", command, retval);
- if (command == CPIA_COMMAND_GetColourParams ||
- command == CPIA_COMMAND_GetColourBalance ||
- command == CPIA_COMMAND_GetExposure)
- mutex_unlock(&cam->param_lock);
- } else {
- switch(command) {
- case CPIA_COMMAND_GetCPIAVersion:
- cam->params.version.firmwareVersion = data[0];
- cam->params.version.firmwareRevision = data[1];
- cam->params.version.vcVersion = data[2];
- cam->params.version.vcRevision = data[3];
- break;
- case CPIA_COMMAND_GetPnPID:
- cam->params.pnpID.vendor = data[0]+(((u16)data[1])<<8);
- cam->params.pnpID.product = data[2]+(((u16)data[3])<<8);
- cam->params.pnpID.deviceRevision =
- data[4]+(((u16)data[5])<<8);
- break;
- case CPIA_COMMAND_GetCameraStatus:
- cam->params.status.systemState = data[0];
- cam->params.status.grabState = data[1];
- cam->params.status.streamState = data[2];
- cam->params.status.fatalError = data[3];
- cam->params.status.cmdError = data[4];
- cam->params.status.debugFlags = data[5];
- cam->params.status.vpStatus = data[6];
- cam->params.status.errorCode = data[7];
- break;
- case CPIA_COMMAND_GetVPVersion:
- cam->params.vpVersion.vpVersion = data[0];
- cam->params.vpVersion.vpRevision = data[1];
- cam->params.vpVersion.cameraHeadID =
- data[2]+(((u16)data[3])<<8);
- break;
- case CPIA_COMMAND_GetColourParams:
- cam->params.colourParams.brightness = data[0];
- cam->params.colourParams.contrast = data[1];
- cam->params.colourParams.saturation = data[2];
- mutex_unlock(&cam->param_lock);
- break;
- case CPIA_COMMAND_GetColourBalance:
- cam->params.colourBalance.redGain = data[0];
- cam->params.colourBalance.greenGain = data[1];
- cam->params.colourBalance.blueGain = data[2];
- mutex_unlock(&cam->param_lock);
- break;
- case CPIA_COMMAND_GetExposure:
- cam->params.exposure.gain = data[0];
- cam->params.exposure.fineExp = data[1];
- cam->params.exposure.coarseExpLo = data[2];
- cam->params.exposure.coarseExpHi = data[3];
- cam->params.exposure.redComp = data[4];
- cam->params.exposure.green1Comp = data[5];
- cam->params.exposure.green2Comp = data[6];
- cam->params.exposure.blueComp = data[7];
- mutex_unlock(&cam->param_lock);
- break;
-
- case CPIA_COMMAND_ReadMCPorts:
- if (!cam->params.qx3.qx3_detected)
- break;
- /* test button press */
- cam->params.qx3.button = ((data[1] & 0x02) == 0);
- if (cam->params.qx3.button) {
- /* button pressed - unlock the latch */
- do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xDF,0xDF,0);
- do_command(cam,CPIA_COMMAND_WriteMCPort,3,0xFF,0xFF,0);
- }
-
- /* test whether microscope is cradled */
- cam->params.qx3.cradled = ((data[2] & 0x40) == 0);
- break;
-
- default:
- break;
- }
- }
- return retval;
-}
-
-/* send a command to the camera with an additional data transaction */
-static int do_command_extended(struct cam_data *cam, u16 command,
- u8 a, u8 b, u8 c, u8 d,
- u8 e, u8 f, u8 g, u8 h,
- u8 i, u8 j, u8 k, u8 l)
-{
- int retval;
- u8 cmd[8], data[8];
-
- cmd[0] = command>>8;
- cmd[1] = command&0xff;
- cmd[2] = a;
- cmd[3] = b;
- cmd[4] = c;
- cmd[5] = d;
- cmd[6] = 8;
- cmd[7] = 0;
- data[0] = e;
- data[1] = f;
- data[2] = g;
- data[3] = h;
- data[4] = i;
- data[5] = j;
- data[6] = k;
- data[7] = l;
-
- retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
- if (retval)
- DBG("%x - failed\n", command);
-
- return retval;
-}
-
-/**********************************************************************
- *
- * Colorspace conversion
- *
- **********************************************************************/
-#define LIMIT(x) ((((x)>0xffffff)?0xff0000:(((x)<=0xffff)?0:(x)&0xff0000))>>16)
-
-static int convert420(unsigned char *yuv, unsigned char *rgb, int out_fmt,
- int linesize, int mmap_kludge)
-{
- int y, u, v, r, g, b, y1;
-
- /* Odd lines use the same u and v as the previous line.
- * Because of compression, it is necessary to get this
- * information from the decoded image. */
- switch(out_fmt) {
- case VIDEO_PALETTE_RGB555:
- y = (*yuv++ - 16) * 76310;
- y1 = (*yuv - 16) * 76310;
- r = ((*(rgb+1-linesize)) & 0x7c) << 1;
- g = ((*(rgb-linesize)) & 0xe0) >> 4 |
- ((*(rgb+1-linesize)) & 0x03) << 6;
- b = ((*(rgb-linesize)) & 0x1f) << 3;
- u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
- v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
- r = 104635 * v;
- g = -25690 * u - 53294 * v;
- b = 132278 * u;
- *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
- *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
- *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
- *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
- return 4;
- case VIDEO_PALETTE_RGB565:
- y = (*yuv++ - 16) * 76310;
- y1 = (*yuv - 16) * 76310;
- r = (*(rgb+1-linesize)) & 0xf8;
- g = ((*(rgb-linesize)) & 0xe0) >> 3 |
- ((*(rgb+1-linesize)) & 0x07) << 5;
- b = ((*(rgb-linesize)) & 0x1f) << 3;
- u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
- v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
- r = 104635 * v;
- g = -25690 * u - 53294 * v;
- b = 132278 * u;
- *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
- *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
- *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
- *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
- return 4;
- break;
- case VIDEO_PALETTE_RGB24:
- case VIDEO_PALETTE_RGB32:
- y = (*yuv++ - 16) * 76310;
- y1 = (*yuv - 16) * 76310;
- if (mmap_kludge) {
- r = *(rgb+2-linesize);
- g = *(rgb+1-linesize);
- b = *(rgb-linesize);
- } else {
- r = *(rgb-linesize);
- g = *(rgb+1-linesize);
- b = *(rgb+2-linesize);
- }
- u = (-53294 * r - 104635 * g + 157929 * b) / 5756495;
- v = (157968 * r - 132278 * g - 25690 * b) / 5366159;
- r = 104635 * v;
- g = -25690 * u + -53294 * v;
- b = 132278 * u;
- if (mmap_kludge) {
- *rgb++ = LIMIT(b+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(r+y);
- if(out_fmt == VIDEO_PALETTE_RGB32)
- rgb++;
- *rgb++ = LIMIT(b+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(r+y1);
- } else {
- *rgb++ = LIMIT(r+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(b+y);
- if(out_fmt == VIDEO_PALETTE_RGB32)
- rgb++;
- *rgb++ = LIMIT(r+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(b+y1);
- }
- if(out_fmt == VIDEO_PALETTE_RGB32)
- return 8;
- return 6;
- case VIDEO_PALETTE_YUV422:
- case VIDEO_PALETTE_YUYV:
- y = *yuv++;
- u = *(rgb+1-linesize);
- y1 = *yuv;
- v = *(rgb+3-linesize);
- *rgb++ = y;
- *rgb++ = u;
- *rgb++ = y1;
- *rgb = v;
- return 4;
- case VIDEO_PALETTE_UYVY:
- u = *(rgb-linesize);
- y = *yuv++;
- v = *(rgb+2-linesize);
- y1 = *yuv;
- *rgb++ = u;
- *rgb++ = y;
- *rgb++ = v;
- *rgb = y1;
- return 4;
- case VIDEO_PALETTE_GREY:
- *rgb++ = *yuv++;
- *rgb = *yuv;
- return 2;
- default:
- DBG("Empty: %d\n", out_fmt);
- return 0;
- }
-}
-
-
-static int yuvconvert(unsigned char *yuv, unsigned char *rgb, int out_fmt,
- int in_uyvy, int mmap_kludge)
-{
- int y, u, v, r, g, b, y1;
-
- switch(out_fmt) {
- case VIDEO_PALETTE_RGB555:
- case VIDEO_PALETTE_RGB565:
- case VIDEO_PALETTE_RGB24:
- case VIDEO_PALETTE_RGB32:
- if (in_uyvy) {
- u = *yuv++ - 128;
- y = (*yuv++ - 16) * 76310;
- v = *yuv++ - 128;
- y1 = (*yuv - 16) * 76310;
- } else {
- y = (*yuv++ - 16) * 76310;
- u = *yuv++ - 128;
- y1 = (*yuv++ - 16) * 76310;
- v = *yuv - 128;
- }
- r = 104635 * v;
- g = -25690 * u + -53294 * v;
- b = 132278 * u;
- break;
- default:
- y = *yuv++;
- u = *yuv++;
- y1 = *yuv++;
- v = *yuv;
- /* Just to avoid compiler warnings */
- r = 0;
- g = 0;
- b = 0;
- break;
- }
- switch(out_fmt) {
- case VIDEO_PALETTE_RGB555:
- *rgb++ = ((LIMIT(g+y) & 0xf8) << 2) | (LIMIT(b+y) >> 3);
- *rgb++ = ((LIMIT(r+y) & 0xf8) >> 1) | (LIMIT(g+y) >> 6);
- *rgb++ = ((LIMIT(g+y1) & 0xf8) << 2) | (LIMIT(b+y1) >> 3);
- *rgb = ((LIMIT(r+y1) & 0xf8) >> 1) | (LIMIT(g+y1) >> 6);
- return 4;
- case VIDEO_PALETTE_RGB565:
- *rgb++ = ((LIMIT(g+y) & 0xfc) << 3) | (LIMIT(b+y) >> 3);
- *rgb++ = (LIMIT(r+y) & 0xf8) | (LIMIT(g+y) >> 5);
- *rgb++ = ((LIMIT(g+y1) & 0xfc) << 3) | (LIMIT(b+y1) >> 3);
- *rgb = (LIMIT(r+y1) & 0xf8) | (LIMIT(g+y1) >> 5);
- return 4;
- case VIDEO_PALETTE_RGB24:
- if (mmap_kludge) {
- *rgb++ = LIMIT(b+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(r+y);
- *rgb++ = LIMIT(b+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(r+y1);
- } else {
- *rgb++ = LIMIT(r+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(b+y);
- *rgb++ = LIMIT(r+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(b+y1);
- }
- return 6;
- case VIDEO_PALETTE_RGB32:
- if (mmap_kludge) {
- *rgb++ = LIMIT(b+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(r+y);
- rgb++;
- *rgb++ = LIMIT(b+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(r+y1);
- } else {
- *rgb++ = LIMIT(r+y);
- *rgb++ = LIMIT(g+y);
- *rgb++ = LIMIT(b+y);
- rgb++;
- *rgb++ = LIMIT(r+y1);
- *rgb++ = LIMIT(g+y1);
- *rgb = LIMIT(b+y1);
- }
- return 8;
- case VIDEO_PALETTE_GREY:
- *rgb++ = y;
- *rgb = y1;
- return 2;
- case VIDEO_PALETTE_YUV422:
- case VIDEO_PALETTE_YUYV:
- *rgb++ = y;
- *rgb++ = u;
- *rgb++ = y1;
- *rgb = v;
- return 4;
- case VIDEO_PALETTE_UYVY:
- *rgb++ = u;
- *rgb++ = y;
- *rgb++ = v;
- *rgb = y1;
- return 4;
- default:
- DBG("Empty: %d\n", out_fmt);
- return 0;
- }
-}
-
-static int skipcount(int count, int fmt)
-{
- switch(fmt) {
- case VIDEO_PALETTE_GREY:
- return count;
- case VIDEO_PALETTE_RGB555:
- case VIDEO_PALETTE_RGB565:
- case VIDEO_PALETTE_YUV422:
- case VIDEO_PALETTE_YUYV:
- case VIDEO_PALETTE_UYVY:
- return 2*count;
- case VIDEO_PALETTE_RGB24:
- return 3*count;
- case VIDEO_PALETTE_RGB32:
- return 4*count;
- default:
- return 0;
- }
-}
-
-static int parse_picture(struct cam_data *cam, int size)
-{
- u8 *obuf, *ibuf, *end_obuf;
- int ll, in_uyvy, compressed, decimation, even_line, origsize, out_fmt;
- int rows, cols, linesize, subsample_422;
-
- /* make sure params don't change while we are decoding */
- mutex_lock(&cam->param_lock);
-
- obuf = cam->decompressed_frame.data;
- end_obuf = obuf+CPIA_MAX_FRAME_SIZE;
- ibuf = cam->raw_image;
- origsize = size;
- out_fmt = cam->vp.palette;
-
- if ((ibuf[0] != MAGIC_0) || (ibuf[1] != MAGIC_1)) {
- LOG("header not found\n");
- mutex_unlock(&cam->param_lock);
- return -1;
- }
-
- if ((ibuf[16] != VIDEOSIZE_QCIF) && (ibuf[16] != VIDEOSIZE_CIF)) {
- LOG("wrong video size\n");
- mutex_unlock(&cam->param_lock);
- return -1;
- }
-
- if (ibuf[17] != SUBSAMPLE_420 && ibuf[17] != SUBSAMPLE_422) {
- LOG("illegal subtype %d\n",ibuf[17]);
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- subsample_422 = ibuf[17] == SUBSAMPLE_422;
-
- if (ibuf[18] != YUVORDER_YUYV && ibuf[18] != YUVORDER_UYVY) {
- LOG("illegal yuvorder %d\n",ibuf[18]);
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- in_uyvy = ibuf[18] == YUVORDER_UYVY;
-
- if ((ibuf[24] != cam->params.roi.colStart) ||
- (ibuf[25] != cam->params.roi.colEnd) ||
- (ibuf[26] != cam->params.roi.rowStart) ||
- (ibuf[27] != cam->params.roi.rowEnd)) {
- LOG("ROI mismatch\n");
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- cols = 8*(ibuf[25] - ibuf[24]);
- rows = 4*(ibuf[27] - ibuf[26]);
-
-
- if ((ibuf[28] != NOT_COMPRESSED) && (ibuf[28] != COMPRESSED)) {
- LOG("illegal compression %d\n",ibuf[28]);
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- compressed = (ibuf[28] == COMPRESSED);
-
- if (ibuf[29] != NO_DECIMATION && ibuf[29] != DECIMATION_ENAB) {
- LOG("illegal decimation %d\n",ibuf[29]);
- mutex_unlock(&cam->param_lock);
- return -1;
- }
- decimation = (ibuf[29] == DECIMATION_ENAB);
-
- cam->params.yuvThreshold.yThreshold = ibuf[30];
- cam->params.yuvThreshold.uvThreshold = ibuf[31];
- cam->params.status.systemState = ibuf[32];
- cam->params.status.grabState = ibuf[33];
- cam->params.status.streamState = ibuf[34];
- cam->params.status.fatalError = ibuf[35];
- cam->params.status.cmdError = ibuf[36];
- cam->params.status.debugFlags = ibuf[37];
- cam->params.status.vpStatus = ibuf[38];
- cam->params.status.errorCode = ibuf[39];
- cam->fps = ibuf[41];
- mutex_unlock(&cam->param_lock);
-
- linesize = skipcount(cols, out_fmt);
- ibuf += FRAME_HEADER_SIZE;
- size -= FRAME_HEADER_SIZE;
- ll = ibuf[0] | (ibuf[1] << 8);
- ibuf += 2;
- even_line = 1;
-
- while (size > 0) {
- size -= (ll+2);
- if (size < 0) {
- LOG("Insufficient data in buffer\n");
- return -1;
- }
-
- while (ll > 1) {
- if (!compressed || (compressed && !(*ibuf & 1))) {
- if(subsample_422 || even_line) {
- obuf += yuvconvert(ibuf, obuf, out_fmt,
- in_uyvy, cam->mmap_kludge);
- ibuf += 4;
- ll -= 4;
- } else {
- /* SUBSAMPLE_420 on an odd line */
- obuf += convert420(ibuf, obuf,
- out_fmt, linesize,
- cam->mmap_kludge);
- ibuf += 2;
- ll -= 2;
- }
- } else {
- /*skip compressed interval from previous frame*/
- obuf += skipcount(*ibuf >> 1, out_fmt);
- if (obuf > end_obuf) {
- LOG("Insufficient buffer size\n");
- return -1;
- }
- ++ibuf;
- ll--;
- }
- }
- if (ll == 1) {
- if (*ibuf != EOL) {
- DBG("EOL not found giving up after %d/%d"
- " bytes\n", origsize-size, origsize);
- return -1;
- }
-
- ++ibuf; /* skip over EOL */
-
- if ((size > 3) && (ibuf[0] == EOI) && (ibuf[1] == EOI) &&
- (ibuf[2] == EOI) && (ibuf[3] == EOI)) {
- size -= 4;
- break;
- }
-
- if(decimation) {
- /* skip the odd lines for now */
- obuf += linesize;
- }
-
- if (size > 1) {
- ll = ibuf[0] | (ibuf[1] << 8);
- ibuf += 2; /* skip over line length */
- }
- if(!decimation)
- even_line = !even_line;
- } else {
- LOG("line length was not 1 but %d after %d/%d bytes\n",
- ll, origsize-size, origsize);
- return -1;
- }
- }
-
- if(decimation) {
- /* interpolate odd rows */
- int i, j;
- u8 *prev, *next;
- prev = cam->decompressed_frame.data;
- obuf = prev+linesize;
- next = obuf+linesize;
- for(i=1; i<rows-1; i+=2) {
- for(j=0; j<linesize; ++j) {
- *obuf++ = ((int)*prev++ + *next++) / 2;
- }
- prev += linesize;
- obuf += linesize;
- next += linesize;
- }
- /* last row is odd, just copy previous row */
- memcpy(obuf, prev, linesize);
- }
-
- cam->decompressed_frame.count = obuf-cam->decompressed_frame.data;
-
- return cam->decompressed_frame.count;
-}
-
-/* InitStreamCap wrapper to select correct start line */
-static inline int init_stream_cap(struct cam_data *cam)
-{
- return do_command(cam, CPIA_COMMAND_InitStreamCap,
- 0, cam->params.streamStartLine, 0, 0);
-}
-
-
-/* find_over_exposure
- * Finds a suitable value of OverExposure for use with SetFlickerCtrl
- * Some calculation is required because this value changes with the brightness
- * set with SetColourParameters
- *
- * Parameters: Brightness - last brightness value set with SetColourParameters
- *
- * Returns: OverExposure value to use with SetFlickerCtrl
- */
-#define FLICKER_MAX_EXPOSURE 250
-#define FLICKER_ALLOWABLE_OVER_EXPOSURE 146
-#define FLICKER_BRIGHTNESS_CONSTANT 59
-static int find_over_exposure(int brightness)
-{
- int MaxAllowableOverExposure, OverExposure;
-
- MaxAllowableOverExposure = FLICKER_MAX_EXPOSURE - brightness -
- FLICKER_BRIGHTNESS_CONSTANT;
-
- if (MaxAllowableOverExposure < FLICKER_ALLOWABLE_OVER_EXPOSURE) {
- OverExposure = MaxAllowableOverExposure;
- } else {
- OverExposure = FLICKER_ALLOWABLE_OVER_EXPOSURE;
- }
-
- return OverExposure;
-}
-#undef FLICKER_MAX_EXPOSURE
-#undef FLICKER_ALLOWABLE_OVER_EXPOSURE
-#undef FLICKER_BRIGHTNESS_CONSTANT
-
-/* update various camera modes and settings */
-static void dispatch_commands(struct cam_data *cam)
-{
- mutex_lock(&cam->param_lock);
- if (cam->cmd_queue==COMMAND_NONE) {
- mutex_unlock(&cam->param_lock);
- return;
- }
- DEB_BYTE(cam->cmd_queue);
- DEB_BYTE(cam->cmd_queue>>8);
- if (cam->cmd_queue & COMMAND_SETFORMAT) {
- do_command(cam, CPIA_COMMAND_SetFormat,
- cam->params.format.videoSize,
- cam->params.format.subSample,
- cam->params.format.yuvOrder, 0);
- do_command(cam, CPIA_COMMAND_SetROI,
- cam->params.roi.colStart, cam->params.roi.colEnd,
- cam->params.roi.rowStart, cam->params.roi.rowEnd);
- cam->first_frame = 1;
- }
-
- if (cam->cmd_queue & COMMAND_SETCOLOURPARAMS)
- do_command(cam, CPIA_COMMAND_SetColourParams,
- cam->params.colourParams.brightness,
- cam->params.colourParams.contrast,
- cam->params.colourParams.saturation, 0);
-
- if (cam->cmd_queue & COMMAND_SETAPCOR)
- do_command(cam, CPIA_COMMAND_SetApcor,
- cam->params.apcor.gain1,
- cam->params.apcor.gain2,
- cam->params.apcor.gain4,
- cam->params.apcor.gain8);
-
- if (cam->cmd_queue & COMMAND_SETVLOFFSET)
- do_command(cam, CPIA_COMMAND_SetVLOffset,
- cam->params.vlOffset.gain1,
- cam->params.vlOffset.gain2,
- cam->params.vlOffset.gain4,
- cam->params.vlOffset.gain8);
-
- if (cam->cmd_queue & COMMAND_SETEXPOSURE) {
- do_command_extended(cam, CPIA_COMMAND_SetExposure,
- cam->params.exposure.gainMode,
- 1,
- cam->params.exposure.compMode,
- cam->params.exposure.centreWeight,
- cam->params.exposure.gain,
- cam->params.exposure.fineExp,
- cam->params.exposure.coarseExpLo,
- cam->params.exposure.coarseExpHi,
- cam->params.exposure.redComp,
- cam->params.exposure.green1Comp,
- cam->params.exposure.green2Comp,
- cam->params.exposure.blueComp);
- if(cam->params.exposure.expMode != 1) {
- do_command_extended(cam, CPIA_COMMAND_SetExposure,
- 0,
- cam->params.exposure.expMode,
- 0, 0,
- cam->params.exposure.gain,
- cam->params.exposure.fineExp,
- cam->params.exposure.coarseExpLo,
- cam->params.exposure.coarseExpHi,
- 0, 0, 0, 0);
- }
- }
-
- if (cam->cmd_queue & COMMAND_SETCOLOURBALANCE) {
- if (cam->params.colourBalance.balanceMode == 1) {
- do_command(cam, CPIA_COMMAND_SetColourBalance,
- 1,
- cam->params.colourBalance.redGain,
- cam->params.colourBalance.greenGain,
- cam->params.colourBalance.blueGain);
- do_command(cam, CPIA_COMMAND_SetColourBalance,
- 3, 0, 0, 0);
- }
- if (cam->params.colourBalance.balanceMode == 2) {
- do_command(cam, CPIA_COMMAND_SetColourBalance,
- 2, 0, 0, 0);
- }
- if (cam->params.colourBalance.balanceMode == 3) {
- do_command(cam, CPIA_COMMAND_SetColourBalance,
- 3, 0, 0, 0);
- }
- }
-
- if (cam->cmd_queue & COMMAND_SETCOMPRESSIONTARGET)
- do_command(cam, CPIA_COMMAND_SetCompressionTarget,
- cam->params.compressionTarget.frTargeting,
- cam->params.compressionTarget.targetFR,
- cam->params.compressionTarget.targetQ, 0);
-
- if (cam->cmd_queue & COMMAND_SETYUVTHRESH)
- do_command(cam, CPIA_COMMAND_SetYUVThresh,
- cam->params.yuvThreshold.yThreshold,
- cam->params.yuvThreshold.uvThreshold, 0, 0);
-
- if (cam->cmd_queue & COMMAND_SETCOMPRESSIONPARAMS)
- do_command_extended(cam, CPIA_COMMAND_SetCompressionParams,
- 0, 0, 0, 0,
- cam->params.compressionParams.hysteresis,
- cam->params.compressionParams.threshMax,
- cam->params.compressionParams.smallStep,
- cam->params.compressionParams.largeStep,
- cam->params.compressionParams.decimationHysteresis,
- cam->params.compressionParams.frDiffStepThresh,
- cam->params.compressionParams.qDiffStepThresh,
- cam->params.compressionParams.decimationThreshMod);
-
- if (cam->cmd_queue & COMMAND_SETCOMPRESSION)
- do_command(cam, CPIA_COMMAND_SetCompression,
- cam->params.compression.mode,
- cam->params.compression.decimation, 0, 0);
-
- if (cam->cmd_queue & COMMAND_SETSENSORFPS)
- do_command(cam, CPIA_COMMAND_SetSensorFPS,
- cam->params.sensorFps.divisor,
- cam->params.sensorFps.baserate, 0, 0);
-
- if (cam->cmd_queue & COMMAND_SETFLICKERCTRL)
- do_command(cam, CPIA_COMMAND_SetFlickerCtrl,
- cam->params.flickerControl.flickerMode,
- cam->params.flickerControl.coarseJump,
- abs(cam->params.flickerControl.allowableOverExposure),
- 0);
-
- if (cam->cmd_queue & COMMAND_SETECPTIMING)
- do_command(cam, CPIA_COMMAND_SetECPTiming,
- cam->params.ecpTiming, 0, 0, 0);
-
- if (cam->cmd_queue & COMMAND_PAUSE)
- do_command(cam, CPIA_COMMAND_EndStreamCap, 0, 0, 0, 0);
-
- if (cam->cmd_queue & COMMAND_RESUME)
- init_stream_cap(cam);
-
- if (cam->cmd_queue & COMMAND_SETLIGHTS && cam->params.qx3.qx3_detected)
- {
- int p1 = (cam->params.qx3.bottomlight == 0) << 1;
- int p2 = (cam->params.qx3.toplight == 0) << 3;
- do_command(cam, CPIA_COMMAND_WriteVCReg, 0x90, 0x8F, 0x50, 0);
- do_command(cam, CPIA_COMMAND_WriteMCPort, 2, 0, (p1|p2|0xE0), 0);
- }
-
- cam->cmd_queue = COMMAND_NONE;
- mutex_unlock(&cam->param_lock);
- return;
-}
-
-
-
-static void set_flicker(struct cam_params *params, volatile u32 *command_flags,
- int on)
-{
- /* Everything in here is from the Windows driver */
-#define FIRMWARE_VERSION(x,y) (params->version.firmwareVersion == (x) && \
- params->version.firmwareRevision == (y))
-/* define for compgain calculation */
-#if 0
-#define COMPGAIN(base, curexp, newexp) \
- (u8) ((((float) base - 128.0) * ((float) curexp / (float) newexp)) + 128.5)
-#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
- (u16)((float)curexp * (float)(u8)(curcomp + 128) / (float)(u8)(basecomp - 128))
-#else
- /* equivalent functions without floating point math */
-#define COMPGAIN(base, curexp, newexp) \
- (u8)(128 + (((u32)(2*(base-128)*curexp + newexp)) / (2* newexp)) )
-#define EXP_FROM_COMP(basecomp, curcomp, curexp) \
- (u16)(((u32)(curexp * (u8)(curcomp + 128)) / (u8)(basecomp - 128)))
-#endif
-
-
- int currentexp = params->exposure.coarseExpLo +
- params->exposure.coarseExpHi*256;
- int startexp;
- if (on) {
- int cj = params->flickerControl.coarseJump;
- params->flickerControl.flickerMode = 1;
- params->flickerControl.disabled = 0;
- if(params->exposure.expMode != 2)
- *command_flags |= COMMAND_SETEXPOSURE;
- params->exposure.expMode = 2;
- currentexp = currentexp << params->exposure.gain;
- params->exposure.gain = 0;
- /* round down current exposure to nearest value */
- startexp = (currentexp + ROUND_UP_EXP_FOR_FLICKER) / cj;
- if(startexp < 1)
- startexp = 1;
- startexp = (startexp * cj) - 1;
- if(FIRMWARE_VERSION(1,2))
- while(startexp > MAX_EXP_102)
- startexp -= cj;
- else
- while(startexp > MAX_EXP)
- startexp -= cj;
- params->exposure.coarseExpLo = startexp & 0xff;
- params->exposure.coarseExpHi = startexp >> 8;
- if (currentexp > startexp) {
- if (currentexp > (2 * startexp))
- currentexp = 2 * startexp;
- params->exposure.redComp = COMPGAIN (COMP_RED, currentexp, startexp);
- params->exposure.green1Comp = COMPGAIN (COMP_GREEN1, currentexp, startexp);
- params->exposure.green2Comp = COMPGAIN (COMP_GREEN2, currentexp, startexp);
- params->exposure.blueComp = COMPGAIN (COMP_BLUE, currentexp, startexp);
- } else {
- params->exposure.redComp = COMP_RED;
- params->exposure.green1Comp = COMP_GREEN1;
- params->exposure.green2Comp = COMP_GREEN2;
- params->exposure.blueComp = COMP_BLUE;
- }
- if(FIRMWARE_VERSION(1,2))
- params->exposure.compMode = 0;
- else
- params->exposure.compMode = 1;
-
- params->apcor.gain1 = 0x18;
- params->apcor.gain2 = 0x18;
- params->apcor.gain4 = 0x16;
- params->apcor.gain8 = 0x14;
- *command_flags |= COMMAND_SETAPCOR;
- } else {
- params->flickerControl.flickerMode = 0;
- params->flickerControl.disabled = 1;
- /* Coarse = average of equivalent coarse for each comp channel */
- startexp = EXP_FROM_COMP(COMP_RED, params->exposure.redComp, currentexp);
- startexp += EXP_FROM_COMP(COMP_GREEN1, params->exposure.green1Comp, currentexp);
- startexp += EXP_FROM_COMP(COMP_GREEN2, params->exposure.green2Comp, currentexp);
- startexp += EXP_FROM_COMP(COMP_BLUE, params->exposure.blueComp, currentexp);
- startexp = startexp >> 2;
- while(startexp > MAX_EXP &&
- params->exposure.gain < params->exposure.gainMode-1) {
- startexp = startexp >> 1;
- ++params->exposure.gain;
- }
- if(FIRMWARE_VERSION(1,2) && startexp > MAX_EXP_102)
- startexp = MAX_EXP_102;
- if(startexp > MAX_EXP)
- startexp = MAX_EXP;
- params->exposure.coarseExpLo = startexp&0xff;
- params->exposure.coarseExpHi = startexp >> 8;
- params->exposure.redComp = COMP_RED;
- params->exposure.green1Comp = COMP_GREEN1;
- params->exposure.green2Comp = COMP_GREEN2;
- params->exposure.blueComp = COMP_BLUE;
- params->exposure.compMode = 1;
- *command_flags |= COMMAND_SETEXPOSURE;
- params->apcor.gain1 = 0x18;
- params->apcor.gain2 = 0x16;
- params->apcor.gain4 = 0x24;
- params->apcor.gain8 = 0x34;
- *command_flags |= COMMAND_SETAPCOR;
- }
- params->vlOffset.gain1 = 20;
- params->vlOffset.gain2 = 24;
- params->vlOffset.gain4 = 26;
- params->vlOffset.gain8 = 26;
- *command_flags |= COMMAND_SETVLOFFSET;
-#undef FIRMWARE_VERSION
-#undef EXP_FROM_COMP
-#undef COMPGAIN
-}
-
-#define FIRMWARE_VERSION(x,y) (cam->params.version.firmwareVersion == (x) && \
- cam->params.version.firmwareRevision == (y))
-/* monitor the exposure and adjust the sensor frame rate if needed */
-static void monitor_exposure(struct cam_data *cam)
-{
- u8 exp_acc, bcomp, gain, coarseL, cmd[8], data[8];
- int retval, light_exp, dark_exp, very_dark_exp;
- int old_exposure, new_exposure, framerate;
-
- /* get necessary stats and register settings from camera */
- /* do_command can't handle this, so do it ourselves */
- cmd[0] = CPIA_COMMAND_ReadVPRegs>>8;
- cmd[1] = CPIA_COMMAND_ReadVPRegs&0xff;
- cmd[2] = 30;
- cmd[3] = 4;
- cmd[4] = 9;
- cmd[5] = 8;
- cmd[6] = 8;
- cmd[7] = 0;
- retval = cam->ops->transferCmd(cam->lowlevel_data, cmd, data);
- if (retval) {
- LOG("ReadVPRegs(30,4,9,8) - failed, retval=%d\n",
- retval);
- return;
- }
- exp_acc = data[0];
- bcomp = data[1];
- gain = data[2];
- coarseL = data[3];
-
- mutex_lock(&cam->param_lock);
- light_exp = cam->params.colourParams.brightness +
- TC - 50 + EXP_ACC_LIGHT;
- if(light_exp > 255)
- light_exp = 255;
- dark_exp = cam->params.colourParams.brightness +
- TC - 50 - EXP_ACC_DARK;
- if(dark_exp < 0)
- dark_exp = 0;
- very_dark_exp = dark_exp/2;
-
- old_exposure = cam->params.exposure.coarseExpHi * 256 +
- cam->params.exposure.coarseExpLo;
-
- if(!cam->params.flickerControl.disabled) {
- /* Flicker control on */
- int max_comp = FIRMWARE_VERSION(1,2) ? MAX_COMP : HIGH_COMP_102;
- bcomp += 128; /* decode */
- if(bcomp >= max_comp && exp_acc < dark_exp) {
- /* dark */
- if(exp_acc < very_dark_exp) {
- /* very dark */
- if(cam->exposure_status == EXPOSURE_VERY_DARK)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_VERY_DARK;
- cam->exposure_count = 1;
- }
- } else {
- /* just dark */
- if(cam->exposure_status == EXPOSURE_DARK)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_DARK;
- cam->exposure_count = 1;
- }
- }
- } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
- /* light */
- if(old_exposure <= VERY_LOW_EXP) {
- /* very light */
- if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_VERY_LIGHT;
- cam->exposure_count = 1;
- }
- } else {
- /* just light */
- if(cam->exposure_status == EXPOSURE_LIGHT)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_LIGHT;
- cam->exposure_count = 1;
- }
- }
- } else {
- /* not dark or light */
- cam->exposure_status = EXPOSURE_NORMAL;
- }
- } else {
- /* Flicker control off */
- if(old_exposure >= MAX_EXP && exp_acc < dark_exp) {
- /* dark */
- if(exp_acc < very_dark_exp) {
- /* very dark */
- if(cam->exposure_status == EXPOSURE_VERY_DARK)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_VERY_DARK;
- cam->exposure_count = 1;
- }
- } else {
- /* just dark */
- if(cam->exposure_status == EXPOSURE_DARK)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_DARK;
- cam->exposure_count = 1;
- }
- }
- } else if(old_exposure <= LOW_EXP || exp_acc > light_exp) {
- /* light */
- if(old_exposure <= VERY_LOW_EXP) {
- /* very light */
- if(cam->exposure_status == EXPOSURE_VERY_LIGHT)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_VERY_LIGHT;
- cam->exposure_count = 1;
- }
- } else {
- /* just light */
- if(cam->exposure_status == EXPOSURE_LIGHT)
- ++cam->exposure_count;
- else {
- cam->exposure_status = EXPOSURE_LIGHT;
- cam->exposure_count = 1;
- }
- }
- } else {
- /* not dark or light */
- cam->exposure_status = EXPOSURE_NORMAL;
- }
- }
-
- framerate = cam->fps;
- if(framerate > 30 || framerate < 1)
- framerate = 1;
-
- if(!cam->params.flickerControl.disabled) {
- /* Flicker control on */
- if((cam->exposure_status == EXPOSURE_VERY_DARK ||
- cam->exposure_status == EXPOSURE_DARK) &&
- cam->exposure_count >= DARK_TIME*framerate &&
- cam->params.sensorFps.divisor < 3) {
-
- /* dark for too long */
- ++cam->params.sensorFps.divisor;
- cam->cmd_queue |= COMMAND_SETSENSORFPS;
-
- cam->params.flickerControl.coarseJump =
- flicker_jumps[cam->mainsFreq]
- [cam->params.sensorFps.baserate]
- [cam->params.sensorFps.divisor];
- cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
-
- new_exposure = cam->params.flickerControl.coarseJump-1;
- while(new_exposure < old_exposure/2)
- new_exposure += cam->params.flickerControl.coarseJump;
- cam->params.exposure.coarseExpLo = new_exposure & 0xff;
- cam->params.exposure.coarseExpHi = new_exposure >> 8;
- cam->cmd_queue |= COMMAND_SETEXPOSURE;
- cam->exposure_status = EXPOSURE_NORMAL;
- LOG("Automatically decreasing sensor_fps\n");
-
- } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
- cam->exposure_status == EXPOSURE_LIGHT) &&
- cam->exposure_count >= LIGHT_TIME*framerate &&
- cam->params.sensorFps.divisor > 0) {
-
- /* light for too long */
- int max_exp = FIRMWARE_VERSION(1,2) ? MAX_EXP_102 : MAX_EXP ;
-
- --cam->params.sensorFps.divisor;
- cam->cmd_queue |= COMMAND_SETSENSORFPS;
-
- cam->params.flickerControl.coarseJump =
- flicker_jumps[cam->mainsFreq]
- [cam->params.sensorFps.baserate]
- [cam->params.sensorFps.divisor];
- cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
-
- new_exposure = cam->params.flickerControl.coarseJump-1;
- while(new_exposure < 2*old_exposure &&
- new_exposure+
- cam->params.flickerControl.coarseJump < max_exp)
- new_exposure += cam->params.flickerControl.coarseJump;
- cam->params.exposure.coarseExpLo = new_exposure & 0xff;
- cam->params.exposure.coarseExpHi = new_exposure >> 8;
- cam->cmd_queue |= COMMAND_SETEXPOSURE;
- cam->exposure_status = EXPOSURE_NORMAL;
- LOG("Automatically increasing sensor_fps\n");
- }
- } else {
- /* Flicker control off */
- if((cam->exposure_status == EXPOSURE_VERY_DARK ||
- cam->exposure_status == EXPOSURE_DARK) &&
- cam->exposure_count >= DARK_TIME*framerate &&
- cam->params.sensorFps.divisor < 3) {
-
- /* dark for too long */
- ++cam->params.sensorFps.divisor;
- cam->cmd_queue |= COMMAND_SETSENSORFPS;
-
- if(cam->params.exposure.gain > 0) {
- --cam->params.exposure.gain;
- cam->cmd_queue |= COMMAND_SETEXPOSURE;
- }
- cam->exposure_status = EXPOSURE_NORMAL;
- LOG("Automatically decreasing sensor_fps\n");
-
- } else if((cam->exposure_status == EXPOSURE_VERY_LIGHT ||
- cam->exposure_status == EXPOSURE_LIGHT) &&
- cam->exposure_count >= LIGHT_TIME*framerate &&
- cam->params.sensorFps.divisor > 0) {
-
- /* light for too long */
- --cam->params.sensorFps.divisor;
- cam->cmd_queue |= COMMAND_SETSENSORFPS;
-
- if(cam->params.exposure.gain <
- cam->params.exposure.gainMode-1) {
- ++cam->params.exposure.gain;
- cam->cmd_queue |= COMMAND_SETEXPOSURE;
- }
- cam->exposure_status = EXPOSURE_NORMAL;
- LOG("Automatically increasing sensor_fps\n");
- }
- }
- mutex_unlock(&cam->param_lock);
-}
-
-/*-----------------------------------------------------------------*/
-/* if flicker is switched off, this function switches it back on.It checks,
- however, that conditions are suitable before restarting it.
- This should only be called for firmware version 1.2.
-
- It also adjust the colour balance when an exposure step is detected - as
- long as flicker is running
-*/
-static void restart_flicker(struct cam_data *cam)
-{
- int cam_exposure, old_exp;
- if(!FIRMWARE_VERSION(1,2))
- return;
- mutex_lock(&cam->param_lock);
- if(cam->params.flickerControl.flickerMode == 0 ||
- cam->raw_image[39] == 0) {
- mutex_unlock(&cam->param_lock);
- return;
- }
- cam_exposure = cam->raw_image[39]*2;
- old_exp = cam->params.exposure.coarseExpLo +
- cam->params.exposure.coarseExpHi*256;
- /*
- see how far away camera exposure is from a valid
- flicker exposure value
- */
- cam_exposure %= cam->params.flickerControl.coarseJump;
- if(!cam->params.flickerControl.disabled &&
- cam_exposure <= cam->params.flickerControl.coarseJump - 3) {
- /* Flicker control auto-disabled */
- cam->params.flickerControl.disabled = 1;
- }
-
- if(cam->params.flickerControl.disabled &&
- cam->params.flickerControl.flickerMode &&
- old_exp > cam->params.flickerControl.coarseJump +
- ROUND_UP_EXP_FOR_FLICKER) {
- /* exposure is now high enough to switch
- flicker control back on */
- set_flicker(&cam->params, &cam->cmd_queue, 1);
- if((cam->cmd_queue & COMMAND_SETEXPOSURE) &&
- cam->params.exposure.expMode == 2)
- cam->exposure_status = EXPOSURE_NORMAL;
-
- }
- mutex_unlock(&cam->param_lock);
-}
-#undef FIRMWARE_VERSION
-
-static int clear_stall(struct cam_data *cam)
-{
- /* FIXME: Does this actually work? */
- LOG("Clearing stall\n");
-
- cam->ops->streamRead(cam->lowlevel_data, cam->raw_image, 0);
- do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
- return cam->params.status.streamState != STREAM_PAUSED;
-}
-
-/* kernel thread function to read image from camera */
-static int fetch_frame(void *data)
-{
- int image_size, retry;
- struct cam_data *cam = (struct cam_data *)data;
- unsigned long oldjif, rate, diff;
-
- /* Allow up to two bad images in a row to be read and
- * ignored before an error is reported */
- for (retry = 0; retry < 3; ++retry) {
- if (retry)
- DBG("retry=%d\n", retry);
-
- if (!cam->ops)
- continue;
-
- /* load first frame always uncompressed */
- if (cam->first_frame &&
- cam->params.compression.mode != CPIA_COMPRESSION_NONE) {
- do_command(cam, CPIA_COMMAND_SetCompression,
- CPIA_COMPRESSION_NONE,
- NO_DECIMATION, 0, 0);
- /* Trial & error - Discarding a frame prevents the
- first frame from having an error in the data. */
- do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
- }
-
- /* init camera upload */
- if (do_command(cam, CPIA_COMMAND_GrabFrame, 0,
- cam->params.streamStartLine, 0, 0))
- continue;
-
- if (cam->ops->wait_for_stream_ready) {
- /* loop until image ready */
- int count = 0;
- do_command(cam, CPIA_COMMAND_GetCameraStatus,0,0,0,0);
- while (cam->params.status.streamState != STREAM_READY) {
- if(++count > READY_TIMEOUT)
- break;
- if(cam->params.status.streamState ==
- STREAM_PAUSED) {
- /* Bad news */
- if(!clear_stall(cam))
- return -EIO;
- }
-
- cond_resched();
-
- /* sleep for 10 ms, hopefully ;) */
- msleep_interruptible(10);
- if (signal_pending(current))
- return -EINTR;
-
- do_command(cam, CPIA_COMMAND_GetCameraStatus,
- 0, 0, 0, 0);
- }
- if(cam->params.status.streamState != STREAM_READY) {
- continue;
- }
- }
-
- cond_resched();
-
- /* grab image from camera */
- oldjif = jiffies;
- image_size = cam->ops->streamRead(cam->lowlevel_data,
- cam->raw_image, 0);
- if (image_size <= 0) {
- DBG("streamRead failed: %d\n", image_size);
- continue;
- }
-
- rate = image_size * HZ / 1024;
- diff = jiffies-oldjif;
- cam->transfer_rate = diff==0 ? rate : rate/diff;
- /* diff==0 ? unlikely but possible */
-
- /* Switch flicker control back on if it got turned off */
- restart_flicker(cam);
-
- /* If AEC is enabled, monitor the exposure and
- adjust the sensor frame rate if needed */
- if(cam->params.exposure.expMode == 2)
- monitor_exposure(cam);
-
- /* camera idle now so dispatch queued commands */
- dispatch_commands(cam);
-
- /* Update our knowledge of the camera state */
- do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
- do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
- do_command(cam, CPIA_COMMAND_ReadMCPorts, 0, 0, 0, 0);
-
- /* decompress and convert image to by copying it from
- * raw_image to decompressed_frame
- */
-
- cond_resched();
-
- cam->image_size = parse_picture(cam, image_size);
- if (cam->image_size <= 0) {
- DBG("parse_picture failed %d\n", cam->image_size);
- if(cam->params.compression.mode !=
- CPIA_COMPRESSION_NONE) {
- /* Compression may not work right if we
- had a bad frame, get the next one
- uncompressed. */
- cam->first_frame = 1;
- do_command(cam, CPIA_COMMAND_SetGrabMode,
- CPIA_GRAB_SINGLE, 0, 0, 0);
- /* FIXME: Trial & error - need up to 70ms for
- the grab mode change to complete ? */
- msleep_interruptible(70);
- if (signal_pending(current))
- return -EINTR;
- }
- } else
- break;
- }
-
- if (retry < 3) {
- /* FIXME: this only works for double buffering */
- if (cam->frame[cam->curframe].state == FRAME_READY) {
- memcpy(cam->frame[cam->curframe].data,
- cam->decompressed_frame.data,
- cam->decompressed_frame.count);
- cam->frame[cam->curframe].state = FRAME_DONE;
- } else
- cam->decompressed_frame.state = FRAME_DONE;
-
- if (cam->first_frame) {
- cam->first_frame = 0;
- do_command(cam, CPIA_COMMAND_SetCompression,
- cam->params.compression.mode,
- cam->params.compression.decimation, 0, 0);
-
- /* Switch from single-grab to continuous grab */
- do_command(cam, CPIA_COMMAND_SetGrabMode,
- CPIA_GRAB_CONTINUOUS, 0, 0, 0);
- }
- return 0;
- }
- return -EIO;
-}
-
-static int capture_frame(struct cam_data *cam, struct video_mmap *vm)
-{
- if (!cam->frame_buf) {
- /* we do lazy allocation */
- int err;
- if ((err = allocate_frame_buf(cam)))
- return err;
- }
-
- cam->curframe = vm->frame;
- cam->frame[cam->curframe].state = FRAME_READY;
- return fetch_frame(cam);
-}
-
-static int goto_high_power(struct cam_data *cam)
-{
- if (do_command(cam, CPIA_COMMAND_GotoHiPower, 0, 0, 0, 0))
- return -EIO;
- msleep_interruptible(40); /* windows driver does it too */
- if(signal_pending(current))
- return -EINTR;
- if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
- return -EIO;
- if (cam->params.status.systemState == HI_POWER_STATE) {
- DBG("camera now in HIGH power state\n");
- return 0;
- }
- printstatus(cam);
- return -EIO;
-}
-
-static int goto_low_power(struct cam_data *cam)
-{
- if (do_command(cam, CPIA_COMMAND_GotoLoPower, 0, 0, 0, 0))
- return -1;
- if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
- return -1;
- if (cam->params.status.systemState == LO_POWER_STATE) {
- DBG("camera now in LOW power state\n");
- return 0;
- }
- printstatus(cam);
- return -1;
-}
-
-static void save_camera_state(struct cam_data *cam)
-{
- if(!(cam->cmd_queue & COMMAND_SETCOLOURBALANCE))
- do_command(cam, CPIA_COMMAND_GetColourBalance, 0, 0, 0, 0);
- if(!(cam->cmd_queue & COMMAND_SETEXPOSURE))
- do_command(cam, CPIA_COMMAND_GetExposure, 0, 0, 0, 0);
-
- DBG("%d/%d/%d/%d/%d/%d/%d/%d\n",
- cam->params.exposure.gain,
- cam->params.exposure.fineExp,
- cam->params.exposure.coarseExpLo,
- cam->params.exposure.coarseExpHi,
- cam->params.exposure.redComp,
- cam->params.exposure.green1Comp,
- cam->params.exposure.green2Comp,
- cam->params.exposure.blueComp);
- DBG("%d/%d/%d\n",
- cam->params.colourBalance.redGain,
- cam->params.colourBalance.greenGain,
- cam->params.colourBalance.blueGain);
-}
-
-static int set_camera_state(struct cam_data *cam)
-{
- cam->cmd_queue = COMMAND_SETCOMPRESSION |
- COMMAND_SETCOMPRESSIONTARGET |
- COMMAND_SETCOLOURPARAMS |
- COMMAND_SETFORMAT |
- COMMAND_SETYUVTHRESH |
- COMMAND_SETECPTIMING |
- COMMAND_SETCOMPRESSIONPARAMS |
- COMMAND_SETEXPOSURE |
- COMMAND_SETCOLOURBALANCE |
- COMMAND_SETSENSORFPS |
- COMMAND_SETAPCOR |
- COMMAND_SETFLICKERCTRL |
- COMMAND_SETVLOFFSET;
-
- do_command(cam, CPIA_COMMAND_SetGrabMode, CPIA_GRAB_SINGLE,0,0,0);
- dispatch_commands(cam);
-
- /* Wait 6 frames for the sensor to get all settings and
- AEC/ACB to settle */
- msleep_interruptible(6*(cam->params.sensorFps.baserate ? 33 : 40) *
- (1 << cam->params.sensorFps.divisor) + 10);
-
- if(signal_pending(current))
- return -EINTR;
-
- save_camera_state(cam);
-
- return 0;
-}
-
-static void get_version_information(struct cam_data *cam)
-{
- /* GetCPIAVersion */
- do_command(cam, CPIA_COMMAND_GetCPIAVersion, 0, 0, 0, 0);
-
- /* GetPnPID */
- do_command(cam, CPIA_COMMAND_GetPnPID, 0, 0, 0, 0);
-}
-
-/* initialize camera */
-static int reset_camera(struct cam_data *cam)
-{
- int err;
- /* Start the camera in low power mode */
- if (goto_low_power(cam)) {
- if (cam->params.status.systemState != WARM_BOOT_STATE)
- return -ENODEV;
-
- /* FIXME: this is just dirty trial and error */
- err = goto_high_power(cam);
- if(err)
- return err;
- do_command(cam, CPIA_COMMAND_DiscardFrame, 0, 0, 0, 0);
- if (goto_low_power(cam))
- return -ENODEV;
- }
-
- /* procedure described in developer's guide p3-28 */
-
- /* Check the firmware version. */
- cam->params.version.firmwareVersion = 0;
- get_version_information(cam);
- if (cam->params.version.firmwareVersion != 1)
- return -ENODEV;
-
- /* A bug in firmware 1-02 limits gainMode to 2 */
- if(cam->params.version.firmwareRevision <= 2 &&
- cam->params.exposure.gainMode > 2) {
- cam->params.exposure.gainMode = 2;
- }
-
- /* set QX3 detected flag */
- cam->params.qx3.qx3_detected = (cam->params.pnpID.vendor == 0x0813 &&
- cam->params.pnpID.product == 0x0001);
-
- /* The fatal error checking should be done after
- * the camera powers up (developer's guide p 3-38) */
-
- /* Set streamState before transition to high power to avoid bug
- * in firmware 1-02 */
- do_command(cam, CPIA_COMMAND_ModifyCameraStatus, STREAMSTATE, 0,
- STREAM_NOT_READY, 0);
-
- /* GotoHiPower */
- err = goto_high_power(cam);
- if (err)
- return err;
-
- /* Check the camera status */
- if (do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0))
- return -EIO;
-
- if (cam->params.status.fatalError) {
- DBG("fatal_error: %#04x\n",
- cam->params.status.fatalError);
- DBG("vp_status: %#04x\n",
- cam->params.status.vpStatus);
- if (cam->params.status.fatalError & ~(COM_FLAG|CPIA_FLAG)) {
- /* Fatal error in camera */
- return -EIO;
- } else if (cam->params.status.fatalError & (COM_FLAG|CPIA_FLAG)) {
- /* Firmware 1-02 may do this for parallel port cameras,
- * just clear the flags (developer's guide p 3-38) */
- do_command(cam, CPIA_COMMAND_ModifyCameraStatus,
- FATALERROR, ~(COM_FLAG|CPIA_FLAG), 0, 0);
- }
- }
-
- /* Check the camera status again */
- if (cam->params.status.fatalError) {
- if (cam->params.status.fatalError)
- return -EIO;
- }
-
- /* VPVersion can't be retrieved before the camera is in HiPower,
- * so get it here instead of in get_version_information. */
- do_command(cam, CPIA_COMMAND_GetVPVersion, 0, 0, 0, 0);
-
- /* set camera to a known state */
- return set_camera_state(cam);
-}
-
-static void put_cam(struct cpia_camera_ops* ops)
-{
- module_put(ops->owner);
-}
-
-/* ------------------------- V4L interface --------------------- */
-static int cpia_open(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct cam_data *cam = video_get_drvdata(dev);
- int err;
-
- if (!cam) {
- DBG("Internal error, cam_data not found!\n");
- return -ENODEV;
- }
-
- if (cam->open_count > 0) {
- DBG("Camera already open\n");
- return -EBUSY;
- }
-
- if (!try_module_get(cam->ops->owner))
- return -ENODEV;
-
- mutex_lock(&cam->busy_lock);
- err = -ENOMEM;
- if (!cam->raw_image) {
- cam->raw_image = rvmalloc(CPIA_MAX_IMAGE_SIZE);
- if (!cam->raw_image)
- goto oops;
- }
-
- if (!cam->decompressed_frame.data) {
- cam->decompressed_frame.data = rvmalloc(CPIA_MAX_FRAME_SIZE);
- if (!cam->decompressed_frame.data)
- goto oops;
- }
-
- /* open cpia */
- err = -ENODEV;
- if (cam->ops->open(cam->lowlevel_data))
- goto oops;
-
- /* reset the camera */
- if ((err = reset_camera(cam)) != 0) {
- cam->ops->close(cam->lowlevel_data);
- goto oops;
- }
-
- err = -EINTR;
- if(signal_pending(current))
- goto oops;
-
- /* Set ownership of /proc/cpia/videoX to current user */
- if(cam->proc_entry)
- cam->proc_entry->uid = current_uid();
-
- /* set mark for loading first frame uncompressed */
- cam->first_frame = 1;
-
- /* init it to something */
- cam->mmap_kludge = 0;
-
- ++cam->open_count;
- file->private_data = dev;
- mutex_unlock(&cam->busy_lock);
- return 0;
-
- oops:
- if (cam->decompressed_frame.data) {
- rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
- cam->decompressed_frame.data = NULL;
- }
- if (cam->raw_image) {
- rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
- cam->raw_image = NULL;
- }
- mutex_unlock(&cam->busy_lock);
- put_cam(cam->ops);
- return err;
-}
-
-static int cpia_close(struct file *file)
-{
- struct video_device *dev = file->private_data;
- struct cam_data *cam = video_get_drvdata(dev);
-
- if (cam->ops) {
- /* Return ownership of /proc/cpia/videoX to root */
- if(cam->proc_entry)
- cam->proc_entry->uid = 0;
-
- /* save camera state for later open (developers guide ch 3.5.3) */
- save_camera_state(cam);
-
- /* GotoLoPower */
- goto_low_power(cam);
-
- /* Update the camera status */
- do_command(cam, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
-
- /* cleanup internal state stuff */
- free_frames(cam->frame);
-
- /* close cpia */
- cam->ops->close(cam->lowlevel_data);
-
- put_cam(cam->ops);
- }
-
- if (--cam->open_count == 0) {
- /* clean up capture-buffers */
- if (cam->raw_image) {
- rvfree(cam->raw_image, CPIA_MAX_IMAGE_SIZE);
- cam->raw_image = NULL;
- }
-
- if (cam->decompressed_frame.data) {
- rvfree(cam->decompressed_frame.data, CPIA_MAX_FRAME_SIZE);
- cam->decompressed_frame.data = NULL;
- }
-
- if (cam->frame_buf)
- free_frame_buf(cam);
-
- if (!cam->ops)
- kfree(cam);
- }
- file->private_data = NULL;
-
- return 0;
-}
-
-static ssize_t cpia_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct video_device *dev = file->private_data;
- struct cam_data *cam = video_get_drvdata(dev);
- int err;
-
- /* make this _really_ smp and multithread-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -EINTR;
-
- if (!buf) {
- DBG("buf NULL\n");
- mutex_unlock(&cam->busy_lock);
- return -EINVAL;
- }
-
- if (!count) {
- DBG("count 0\n");
- mutex_unlock(&cam->busy_lock);
- return 0;
- }
-
- if (!cam->ops) {
- DBG("ops NULL\n");
- mutex_unlock(&cam->busy_lock);
- return -ENODEV;
- }
-
- /* upload frame */
- cam->decompressed_frame.state = FRAME_READY;
- cam->mmap_kludge=0;
- if((err = fetch_frame(cam)) != 0) {
- DBG("ERROR from fetch_frame: %d\n", err);
- mutex_unlock(&cam->busy_lock);
- return err;
- }
- cam->decompressed_frame.state = FRAME_UNUSED;
-
- /* copy data to user space */
- if (cam->decompressed_frame.count > count) {
- DBG("count wrong: %d, %lu\n", cam->decompressed_frame.count,
- (unsigned long) count);
- mutex_unlock(&cam->busy_lock);
- return -EFAULT;
- }
- if (copy_to_user(buf, cam->decompressed_frame.data,
- cam->decompressed_frame.count)) {
- DBG("copy_to_user failed\n");
- mutex_unlock(&cam->busy_lock);
- return -EFAULT;
- }
-
- mutex_unlock(&cam->busy_lock);
- return cam->decompressed_frame.count;
-}
-
-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);
- int retval = 0;
-
- if (!cam || !cam->ops)
- return -ENODEV;
-
- /* make this _really_ smp-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -EINTR;
-
- /* DBG("cpia_ioctl: %u\n", cmd); */
-
- switch (cmd) {
- /* query capabilities */
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
-
- DBG("VIDIOCGCAP\n");
- strcpy(b->name, "CPiA Camera");
- b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = 352; /* VIDEOSIZE_CIF */
- b->maxheight = 288;
- b->minwidth = 48; /* VIDEOSIZE_48_48 */
- b->minheight = 48;
- break;
- }
-
- /* get/set video source - we are a camera and nothing else */
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- DBG("VIDIOCGCHAN\n");
- if (v->channel != 0) {
- retval = -EINVAL;
- break;
- }
-
- v->channel = 0;
- strcpy(v->name, "Camera");
- v->tuners = 0;
- v->flags = 0;
- v->type = VIDEO_TYPE_CAMERA;
- v->norm = 0;
- break;
- }
-
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
-
- DBG("VIDIOCSCHAN\n");
- if (v->channel != 0)
- retval = -EINVAL;
- break;
- }
-
- /* image properties */
- case VIDIOCGPICT:
- {
- struct video_picture *pic = arg;
- DBG("VIDIOCGPICT\n");
- *pic = cam->vp;
- break;
- }
-
- case VIDIOCSPICT:
- {
- struct video_picture *vp = arg;
-
- DBG("VIDIOCSPICT\n");
-
- /* check validity */
- DBG("palette: %d\n", vp->palette);
- DBG("depth: %d\n", vp->depth);
- if (!valid_mode(vp->palette, vp->depth)) {
- retval = -EINVAL;
- break;
- }
-
- mutex_lock(&cam->param_lock);
- /* brightness, colour, contrast need no check 0-65535 */
- cam->vp = *vp;
- /* update cam->params.colourParams */
- cam->params.colourParams.brightness = vp->brightness*100/65535;
- cam->params.colourParams.contrast = vp->contrast*100/65535;
- cam->params.colourParams.saturation = vp->colour*100/65535;
- /* contrast is in steps of 8, so round */
- cam->params.colourParams.contrast =
- ((cam->params.colourParams.contrast + 3) / 8) * 8;
- if (cam->params.version.firmwareVersion == 1 &&
- cam->params.version.firmwareRevision == 2 &&
- cam->params.colourParams.contrast > 80) {
- /* 1-02 firmware limits contrast to 80 */
- cam->params.colourParams.contrast = 80;
- }
-
- /* Adjust flicker control if necessary */
- if(cam->params.flickerControl.allowableOverExposure < 0)
- cam->params.flickerControl.allowableOverExposure =
- -find_over_exposure(cam->params.colourParams.brightness);
- if(cam->params.flickerControl.flickerMode != 0)
- cam->cmd_queue |= COMMAND_SETFLICKERCTRL;
-
-
- /* queue command to update camera */
- cam->cmd_queue |= COMMAND_SETCOLOURPARAMS;
- mutex_unlock(&cam->param_lock);
- DBG("VIDIOCSPICT: %d / %d // %d / %d / %d / %d\n",
- vp->depth, vp->palette, vp->brightness, vp->hue, vp->colour,
- vp->contrast);
- break;
- }
-
- /* get/set capture window */
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
- DBG("VIDIOCGWIN\n");
-
- *vw = cam->vw;
- break;
- }
-
- case VIDIOCSWIN:
- {
- /* copy_from_user, check validity, copy to internal structure */
- struct video_window *vw = arg;
- DBG("VIDIOCSWIN\n");
-
- if (vw->clipcount != 0) { /* clipping not supported */
- retval = -EINVAL;
- break;
- }
- if (vw->clips != NULL) { /* clipping not supported */
- retval = -EINVAL;
- break;
- }
-
- /* we set the video window to something smaller or equal to what
- * is requested by the user???
- */
- mutex_lock(&cam->param_lock);
- if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
- int video_size = match_videosize(vw->width, vw->height);
-
- if (video_size < 0) {
- retval = -EINVAL;
- mutex_unlock(&cam->param_lock);
- break;
- }
- cam->video_size = video_size;
-
- /* video size is changing, reset the subcapture area */
- memset(&cam->vc, 0, sizeof(cam->vc));
-
- set_vw_size(cam);
- DBG("%d / %d\n", cam->vw.width, cam->vw.height);
- cam->cmd_queue |= COMMAND_SETFORMAT;
- }
-
- mutex_unlock(&cam->param_lock);
-
- /* setformat ignored by camera during streaming,
- * so stop/dispatch/start */
- if (cam->cmd_queue & COMMAND_SETFORMAT) {
- DBG("\n");
- dispatch_commands(cam);
- }
- DBG("%d/%d:%d\n", cam->video_size,
- cam->vw.width, cam->vw.height);
- break;
- }
-
- /* mmap interface */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *vm = arg;
- int i;
-
- DBG("VIDIOCGMBUF\n");
- memset(vm, 0, sizeof(*vm));
- vm->size = CPIA_MAX_FRAME_SIZE*FRAME_NUM;
- vm->frames = FRAME_NUM;
- for (i = 0; i < FRAME_NUM; i++)
- vm->offsets[i] = CPIA_MAX_FRAME_SIZE * i;
- break;
- }
-
- case VIDIOCMCAPTURE:
- {
- struct video_mmap *vm = arg;
- int video_size;
-
- DBG("VIDIOCMCAPTURE: %d / %d / %dx%d\n", vm->format, vm->frame,
- vm->width, vm->height);
- if (vm->frame<0||vm->frame>=FRAME_NUM) {
- retval = -EINVAL;
- break;
- }
-
- /* set video format */
- cam->vp.palette = vm->format;
- switch(vm->format) {
- case VIDEO_PALETTE_GREY:
- cam->vp.depth=8;
- break;
- case VIDEO_PALETTE_RGB555:
- case VIDEO_PALETTE_RGB565:
- case VIDEO_PALETTE_YUV422:
- case VIDEO_PALETTE_YUYV:
- case VIDEO_PALETTE_UYVY:
- cam->vp.depth = 16;
- break;
- case VIDEO_PALETTE_RGB24:
- cam->vp.depth = 24;
- break;
- case VIDEO_PALETTE_RGB32:
- cam->vp.depth = 32;
- break;
- default:
- retval = -EINVAL;
- break;
- }
- if (retval)
- break;
-
- /* set video size */
- video_size = match_videosize(vm->width, vm->height);
- if (video_size < 0) {
- retval = -EINVAL;
- break;
- }
- if (video_size != cam->video_size) {
- cam->video_size = video_size;
-
- /* video size is changing, reset the subcapture area */
- memset(&cam->vc, 0, sizeof(cam->vc));
-
- set_vw_size(cam);
- cam->cmd_queue |= COMMAND_SETFORMAT;
- dispatch_commands(cam);
- }
- /* according to v4l-spec we must start streaming here */
- cam->mmap_kludge = 1;
- retval = capture_frame(cam, vm);
-
- break;
- }
-
- case VIDIOCSYNC:
- {
- int *frame = arg;
-
- //DBG("VIDIOCSYNC: %d\n", *frame);
-
- if (*frame<0 || *frame >= FRAME_NUM) {
- retval = -EINVAL;
- break;
- }
-
- switch (cam->frame[*frame].state) {
- case FRAME_UNUSED:
- case FRAME_READY:
- case FRAME_GRABBING:
- DBG("sync to unused frame %d\n", *frame);
- retval = -EINVAL;
- break;
-
- case FRAME_DONE:
- cam->frame[*frame].state = FRAME_UNUSED;
- //DBG("VIDIOCSYNC: %d synced\n", *frame);
- break;
- }
- if (retval == -EINTR) {
- /* FIXME - xawtv does not handle this nice */
- retval = 0;
- }
- break;
- }
-
- case VIDIOCGCAPTURE:
- {
- struct video_capture *vc = arg;
-
- DBG("VIDIOCGCAPTURE\n");
-
- *vc = cam->vc;
-
- break;
- }
-
- case VIDIOCSCAPTURE:
- {
- struct video_capture *vc = arg;
-
- DBG("VIDIOCSCAPTURE\n");
-
- if (vc->decimation != 0) { /* How should this be used? */
- retval = -EINVAL;
- break;
- }
- if (vc->flags != 0) { /* Even/odd grab not supported */
- retval = -EINVAL;
- break;
- }
-
- /* Clip to the resolution we can set for the ROI
- (every 8 columns and 4 rows) */
- vc->x = vc->x & ~(__u32)7;
- vc->y = vc->y & ~(__u32)3;
- vc->width = vc->width & ~(__u32)7;
- vc->height = vc->height & ~(__u32)3;
-
- if(vc->width == 0 || vc->height == 0 ||
- vc->x + vc->width > cam->vw.width ||
- vc->y + vc->height > cam->vw.height) {
- retval = -EINVAL;
- break;
- }
-
- DBG("%d,%d/%dx%d\n", vc->x,vc->y,vc->width, vc->height);
-
- mutex_lock(&cam->param_lock);
-
- cam->vc.x = vc->x;
- cam->vc.y = vc->y;
- cam->vc.width = vc->width;
- cam->vc.height = vc->height;
-
- set_vw_size(cam);
- cam->cmd_queue |= COMMAND_SETFORMAT;
-
- mutex_unlock(&cam->param_lock);
-
- /* setformat ignored by camera during streaming,
- * so stop/dispatch/start */
- dispatch_commands(cam);
- break;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit *vu = arg;
-
- DBG("VIDIOCGUNIT\n");
-
- vu->video = cam->vdev.minor;
- vu->vbi = VIDEO_NO_UNIT;
- vu->radio = VIDEO_NO_UNIT;
- vu->audio = VIDEO_NO_UNIT;
- vu->teletext = VIDEO_NO_UNIT;
-
- break;
- }
-
-
- /* pointless to implement overlay with this camera */
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCKEY:
- /* tuner interface - we have none */
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- /* audio interface - we have none */
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- retval = -EINVAL;
- break;
- default:
- retval = -ENOIOCTLCMD;
- break;
- }
-
- mutex_unlock(&cam->busy_lock);
- return retval;
-}
-
-static long cpia_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(file, cmd, arg, cpia_do_ioctl);
-}
-
-
-/* FIXME */
-static int cpia_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *dev = file->private_data;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long page, pos;
- struct cam_data *cam = video_get_drvdata(dev);
- int retval;
-
- if (!cam || !cam->ops)
- return -ENODEV;
-
- DBG("cpia_mmap: %ld\n", size);
-
- if (size > FRAME_NUM*CPIA_MAX_FRAME_SIZE)
- return -EINVAL;
-
- /* make this _really_ smp-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -EINTR;
-
- if (!cam->frame_buf) { /* we do lazy allocation */
- if ((retval = allocate_frame_buf(cam))) {
- mutex_unlock(&cam->busy_lock);
- return retval;
- }
- }
-
- pos = (unsigned long)(cam->frame_buf);
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&cam->busy_lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- DBG("cpia_mmap: %ld\n", size);
- mutex_unlock(&cam->busy_lock);
-
- return 0;
-}
-
-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,
-};
-
-static struct video_device cpia_template = {
- .name = "CPiA Camera",
- .fops = &cpia_fops,
- .release = video_device_release_empty,
-};
-
-/* initialise cam_data structure */
-static void reset_camera_struct(struct cam_data *cam)
-{
- /* The following parameter values are the defaults from
- * "Software Developer's Guide for CPiA Cameras". Any changes
- * to the defaults are noted in comments. */
- cam->params.colourParams.brightness = 50;
- cam->params.colourParams.contrast = 48;
- cam->params.colourParams.saturation = 50;
- cam->params.exposure.gainMode = 4;
- cam->params.exposure.expMode = 2; /* AEC */
- cam->params.exposure.compMode = 1;
- cam->params.exposure.centreWeight = 1;
- cam->params.exposure.gain = 0;
- cam->params.exposure.fineExp = 0;
- cam->params.exposure.coarseExpLo = 185;
- cam->params.exposure.coarseExpHi = 0;
- cam->params.exposure.redComp = COMP_RED;
- cam->params.exposure.green1Comp = COMP_GREEN1;
- cam->params.exposure.green2Comp = COMP_GREEN2;
- cam->params.exposure.blueComp = COMP_BLUE;
- cam->params.colourBalance.balanceMode = 2; /* ACB */
- cam->params.colourBalance.redGain = 32;
- cam->params.colourBalance.greenGain = 6;
- cam->params.colourBalance.blueGain = 92;
- cam->params.apcor.gain1 = 0x18;
- cam->params.apcor.gain2 = 0x16;
- cam->params.apcor.gain4 = 0x24;
- cam->params.apcor.gain8 = 0x34;
- cam->params.flickerControl.flickerMode = 0;
- cam->params.flickerControl.disabled = 1;
-
- cam->params.flickerControl.coarseJump =
- flicker_jumps[cam->mainsFreq]
- [cam->params.sensorFps.baserate]
- [cam->params.sensorFps.divisor];
- cam->params.flickerControl.allowableOverExposure =
- -find_over_exposure(cam->params.colourParams.brightness);
- cam->params.vlOffset.gain1 = 20;
- cam->params.vlOffset.gain2 = 24;
- cam->params.vlOffset.gain4 = 26;
- cam->params.vlOffset.gain8 = 26;
- cam->params.compressionParams.hysteresis = 3;
- cam->params.compressionParams.threshMax = 11;
- cam->params.compressionParams.smallStep = 1;
- cam->params.compressionParams.largeStep = 3;
- cam->params.compressionParams.decimationHysteresis = 2;
- cam->params.compressionParams.frDiffStepThresh = 5;
- cam->params.compressionParams.qDiffStepThresh = 3;
- cam->params.compressionParams.decimationThreshMod = 2;
- /* End of default values from Software Developer's Guide */
-
- cam->transfer_rate = 0;
- cam->exposure_status = EXPOSURE_NORMAL;
-
- /* Set Sensor FPS to 15fps. This seems better than 30fps
- * for indoor lighting. */
- cam->params.sensorFps.divisor = 1;
- cam->params.sensorFps.baserate = 1;
-
- cam->params.yuvThreshold.yThreshold = 6; /* From windows driver */
- cam->params.yuvThreshold.uvThreshold = 6; /* From windows driver */
-
- cam->params.format.subSample = SUBSAMPLE_422;
- cam->params.format.yuvOrder = YUVORDER_YUYV;
-
- cam->params.compression.mode = CPIA_COMPRESSION_AUTO;
- cam->params.compressionTarget.frTargeting =
- CPIA_COMPRESSION_TARGET_QUALITY;
- cam->params.compressionTarget.targetFR = 15; /* From windows driver */
- cam->params.compressionTarget.targetQ = 5; /* From windows driver */
-
- cam->params.qx3.qx3_detected = 0;
- cam->params.qx3.toplight = 0;
- cam->params.qx3.bottomlight = 0;
- cam->params.qx3.button = 0;
- cam->params.qx3.cradled = 0;
-
- cam->video_size = VIDEOSIZE_CIF;
-
- cam->vp.colour = 32768; /* 50% */
- cam->vp.hue = 32768; /* 50% */
- cam->vp.brightness = 32768; /* 50% */
- cam->vp.contrast = 32768; /* 50% */
- cam->vp.whiteness = 0; /* not used -> grayscale only */
- cam->vp.depth = 24; /* to be set by user */
- cam->vp.palette = VIDEO_PALETTE_RGB24; /* to be set by user */
-
- cam->vc.x = 0;
- cam->vc.y = 0;
- cam->vc.width = 0;
- cam->vc.height = 0;
-
- cam->vw.x = 0;
- cam->vw.y = 0;
- set_vw_size(cam);
- cam->vw.chromakey = 0;
- cam->vw.flags = 0;
- cam->vw.clipcount = 0;
- cam->vw.clips = NULL;
-
- cam->cmd_queue = COMMAND_NONE;
- cam->first_frame = 1;
-
- return;
-}
-
-/* initialize cam_data structure */
-static void init_camera_struct(struct cam_data *cam,
- struct cpia_camera_ops *ops )
-{
- int i;
-
- /* Default everything to 0 */
- memset(cam, 0, sizeof(struct cam_data));
-
- cam->ops = ops;
- mutex_init(&cam->param_lock);
- mutex_init(&cam->busy_lock);
-
- reset_camera_struct(cam);
-
- cam->proc_entry = NULL;
-
- memcpy(&cam->vdev, &cpia_template, sizeof(cpia_template));
- video_set_drvdata(&cam->vdev, cam);
-
- cam->curframe = 0;
- for (i = 0; i < FRAME_NUM; i++) {
- cam->frame[i].width = 0;
- cam->frame[i].height = 0;
- cam->frame[i].state = FRAME_UNUSED;
- cam->frame[i].data = NULL;
- }
- cam->decompressed_frame.width = 0;
- cam->decompressed_frame.height = 0;
- cam->decompressed_frame.state = FRAME_UNUSED;
- cam->decompressed_frame.data = NULL;
-}
-
-struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel)
-{
- struct cam_data *camera;
-
- if ((camera = kmalloc(sizeof(struct cam_data), GFP_KERNEL)) == NULL)
- return NULL;
-
-
- init_camera_struct( camera, ops );
- camera->lowlevel_data = lowlevel;
-
- /* register v4l device */
- if (video_register_device(&camera->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- kfree(camera);
- printk(KERN_DEBUG "video_register_device failed\n");
- return NULL;
- }
-
- /* get version information from camera: open/reset/close */
-
- /* open cpia */
- if (camera->ops->open(camera->lowlevel_data))
- return camera;
-
- /* reset the camera */
- if (reset_camera(camera) != 0) {
- camera->ops->close(camera->lowlevel_data);
- return camera;
- }
-
- /* close cpia */
- camera->ops->close(camera->lowlevel_data);
-
-#ifdef CONFIG_PROC_FS
- create_proc_cpia_cam(camera);
-#endif
-
- printk(KERN_INFO " CPiA Version: %d.%02d (%d.%d)\n",
- camera->params.version.firmwareVersion,
- camera->params.version.firmwareRevision,
- camera->params.version.vcVersion,
- camera->params.version.vcRevision);
- printk(KERN_INFO " CPiA PnP-ID: %04x:%04x:%04x\n",
- camera->params.pnpID.vendor,
- camera->params.pnpID.product,
- camera->params.pnpID.deviceRevision);
- printk(KERN_INFO " VP-Version: %d.%d %04x\n",
- camera->params.vpVersion.vpVersion,
- camera->params.vpVersion.vpRevision,
- camera->params.vpVersion.cameraHeadID);
-
- return camera;
-}
-
-void cpia_unregister_camera(struct cam_data *cam)
-{
- DBG("unregistering video\n");
- video_unregister_device(&cam->vdev);
- if (cam->open_count) {
- put_cam(cam->ops);
- DBG("camera open -- setting ops to NULL\n");
- cam->ops = NULL;
- }
-
-#ifdef CONFIG_PROC_FS
- DBG("destroying /proc/cpia/%s\n", video_device_node_name(&cam->vdev));
- destroy_proc_cpia_cam(cam);
-#endif
- if (!cam->open_count) {
- DBG("freeing camera\n");
- kfree(cam);
- }
-}
-
-static int __init cpia_init(void)
-{
- printk(KERN_INFO "%s v%d.%d.%d\n", ABOUT,
- CPIA_MAJ_VER, CPIA_MIN_VER, CPIA_PATCH_VER);
-
- printk(KERN_WARNING "Since in-kernel colorspace conversion is not "
- "allowed, it is disabled by default now. Users should fix the "
- "applications in case they don't work without conversion "
- "reenabled by setting the 'colorspace_conv' module "
- "parameter to 1\n");
-
-#ifdef CONFIG_PROC_FS
- proc_cpia_create();
-#endif
-
- return 0;
-}
-
-static void __exit cpia_exit(void)
-{
-#ifdef CONFIG_PROC_FS
- proc_cpia_destroy();
-#endif
-}
-
-module_init(cpia_init);
-module_exit(cpia_exit);
-
-/* Exported symbols for modules. */
-
-EXPORT_SYMBOL(cpia_register_camera);
-EXPORT_SYMBOL(cpia_unregister_camera);
diff --git a/drivers/media/video/cpia.h b/drivers/media/video/cpia.h
deleted file mode 100644
index 8f0cfee4b8a1..000000000000
--- a/drivers/media/video/cpia.h
+++ /dev/null
@@ -1,432 +0,0 @@
-#ifndef cpia_h
-#define cpia_h
-
-/*
- * CPiA Parallel Port Video4Linux driver
- *
- * Supports CPiA based parallel port Video Camera's.
- *
- * (C) Copyright 1999 Bas Huisman,
- * Peter Pregler,
- * Scott J. Bertin,
- * VLSI Vision Ltd.
- *
- * 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.
- */
-
-#define CPIA_MAJ_VER 1
-#define CPIA_MIN_VER 2
-#define CPIA_PATCH_VER 3
-
-#define CPIA_PP_MAJ_VER CPIA_MAJ_VER
-#define CPIA_PP_MIN_VER CPIA_MIN_VER
-#define CPIA_PP_PATCH_VER CPIA_PATCH_VER
-
-#define CPIA_USB_MAJ_VER CPIA_MAJ_VER
-#define CPIA_USB_MIN_VER CPIA_MIN_VER
-#define CPIA_USB_PATCH_VER CPIA_PATCH_VER
-
-#define CPIA_MAX_FRAME_SIZE_UNALIGNED (352 * 288 * 4) /* CIF at RGB32 */
-#define CPIA_MAX_FRAME_SIZE ((CPIA_MAX_FRAME_SIZE_UNALIGNED + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)) /* align above to PAGE_SIZE */
-
-#ifdef __KERNEL__
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/list.h>
-#include <linux/mutex.h>
-
-struct cpia_camera_ops
-{
- /* open sets privdata to point to structure for this camera.
- * Returns negative value on error, otherwise 0.
- */
- int (*open)(void *privdata);
-
- /* Registers callback function cb to be called with cbdata
- * when an image is ready. If cb is NULL, only single image grabs
- * should be used. cb should immediately call streamRead to read
- * the data or data may be lost. Returns negative value on error,
- * otherwise 0.
- */
- int (*registerCallback)(void *privdata, void (*cb)(void *cbdata),
- void *cbdata);
-
- /* transferCmd sends commands to the camera. command MUST point to
- * an 8 byte buffer in kernel space. data can be NULL if no extra
- * data is needed. The size of the data is given by the last 2
- * bytes of command. data must also point to memory in kernel space.
- * Returns negative value on error, otherwise 0.
- */
- int (*transferCmd)(void *privdata, u8 *command, u8 *data);
-
- /* streamStart initiates stream capture mode.
- * Returns negative value on error, otherwise 0.
- */
- int (*streamStart)(void *privdata);
-
- /* streamStop terminates stream capture mode.
- * Returns negative value on error, otherwise 0.
- */
- int (*streamStop)(void *privdata);
-
- /* streamRead reads a frame from the camera. buffer points to a
- * buffer large enough to hold a complete frame in kernel space.
- * noblock indicates if this should be a non blocking read.
- * Returns the number of bytes read, or negative value on error.
- */
- int (*streamRead)(void *privdata, u8 *buffer, int noblock);
-
- /* close disables the device until open() is called again.
- * Returns negative value on error, otherwise 0.
- */
- int (*close)(void *privdata);
-
- /* If wait_for_stream_ready is non-zero, wait until the streamState
- * is STREAM_READY before calling streamRead.
- */
- int wait_for_stream_ready;
-
- /*
- * Used to maintain lowlevel module usage counts
- */
- struct module *owner;
-};
-
-struct cpia_frame {
- u8 *data;
- int count;
- int width;
- int height;
- volatile int state;
-};
-
-struct cam_params {
- struct {
- u8 firmwareVersion;
- u8 firmwareRevision;
- u8 vcVersion;
- u8 vcRevision;
- } version;
- struct {
- u16 vendor;
- u16 product;
- u16 deviceRevision;
- } pnpID;
- struct {
- u8 vpVersion;
- u8 vpRevision;
- u16 cameraHeadID;
- } vpVersion;
- struct {
- u8 systemState;
- u8 grabState;
- u8 streamState;
- u8 fatalError;
- u8 cmdError;
- u8 debugFlags;
- u8 vpStatus;
- u8 errorCode;
- } status;
- struct {
- u8 brightness;
- u8 contrast;
- u8 saturation;
- } colourParams;
- struct {
- u8 gainMode;
- u8 expMode;
- u8 compMode;
- u8 centreWeight;
- u8 gain;
- u8 fineExp;
- u8 coarseExpLo;
- u8 coarseExpHi;
- u8 redComp;
- u8 green1Comp;
- u8 green2Comp;
- u8 blueComp;
- } exposure;
- struct {
- u8 balanceMode;
- u8 redGain;
- u8 greenGain;
- u8 blueGain;
- } colourBalance;
- struct {
- u8 divisor;
- u8 baserate;
- } sensorFps;
- struct {
- u8 gain1;
- u8 gain2;
- u8 gain4;
- u8 gain8;
- } apcor;
- struct {
- u8 disabled;
- u8 flickerMode;
- u8 coarseJump;
- int allowableOverExposure;
- } flickerControl;
- struct {
- u8 gain1;
- u8 gain2;
- u8 gain4;
- u8 gain8;
- } vlOffset;
- struct {
- u8 mode;
- u8 decimation;
- } compression;
- struct {
- u8 frTargeting;
- u8 targetFR;
- u8 targetQ;
- } compressionTarget;
- struct {
- u8 yThreshold;
- u8 uvThreshold;
- } yuvThreshold;
- struct {
- u8 hysteresis;
- u8 threshMax;
- u8 smallStep;
- u8 largeStep;
- u8 decimationHysteresis;
- u8 frDiffStepThresh;
- u8 qDiffStepThresh;
- u8 decimationThreshMod;
- } compressionParams;
- struct {
- u8 videoSize; /* CIF/QCIF */
- u8 subSample;
- u8 yuvOrder;
- } format;
- struct { /* Intel QX3 specific data */
- u8 qx3_detected; /* a QX3 is present */
- u8 toplight; /* top light lit , R/W */
- u8 bottomlight; /* bottom light lit, R/W */
- u8 button; /* snapshot button pressed (R/O) */
- u8 cradled; /* microscope is in cradle (R/O) */
- } qx3;
- struct {
- u8 colStart; /* skip first 8*colStart pixels */
- u8 colEnd; /* finish at 8*colEnd pixels */
- u8 rowStart; /* skip first 4*rowStart lines */
- u8 rowEnd; /* finish at 4*rowEnd lines */
- } roi;
- u8 ecpTiming;
- u8 streamStartLine;
-};
-
-enum v4l_camstates {
- CPIA_V4L_IDLE = 0,
- CPIA_V4L_ERROR,
- CPIA_V4L_COMMAND,
- CPIA_V4L_GRABBING,
- CPIA_V4L_STREAMING,
- CPIA_V4L_STREAMING_PAUSED,
-};
-
-#define FRAME_NUM 2 /* double buffering for now */
-
-struct cam_data {
- struct list_head cam_data_list;
-
- struct mutex busy_lock; /* guard against SMP multithreading */
- struct cpia_camera_ops *ops; /* lowlevel driver operations */
- void *lowlevel_data; /* private data for lowlevel driver */
- u8 *raw_image; /* buffer for raw image data */
- struct cpia_frame decompressed_frame;
- /* buffer to hold decompressed frame */
- int image_size; /* sizeof last decompressed image */
- int open_count; /* # of process that have camera open */
-
- /* camera status */
- int fps; /* actual fps reported by the camera */
- int transfer_rate; /* transfer rate from camera in kB/s */
- u8 mainsFreq; /* for flicker control */
-
- /* proc interface */
- struct mutex param_lock; /* params lock for this camera */
- struct cam_params params; /* camera settings */
- struct proc_dir_entry *proc_entry; /* /proc/cpia/videoX */
-
- /* v4l */
- int video_size; /* VIDEO_SIZE_ */
- volatile enum v4l_camstates camstate; /* v4l layer status */
- struct video_device vdev; /* v4l videodev */
- struct video_picture vp; /* v4l camera settings */
- struct video_window vw; /* v4l capture area */
- struct video_capture vc; /* v4l subcapture area */
-
- /* mmap interface */
- int curframe; /* the current frame to grab into */
- u8 *frame_buf; /* frame buffer data */
- struct cpia_frame frame[FRAME_NUM];
- /* FRAME_NUM-buffering, so we need a array */
-
- int first_frame;
- int mmap_kludge; /* 'wrong' byte order for mmap */
- volatile u32 cmd_queue; /* queued commands */
- int exposure_status; /* EXPOSURE_* */
- int exposure_count; /* number of frames at this status */
-};
-
-/* cpia_register_camera is called by low level driver for each camera.
- * A unique camera number is returned, or a negative value on error */
-struct cam_data *cpia_register_camera(struct cpia_camera_ops *ops, void *lowlevel);
-
-/* cpia_unregister_camera is called by low level driver when a camera
- * is removed. This must not fail. */
-void cpia_unregister_camera(struct cam_data *cam);
-
-/* raw CIF + 64 byte header + (2 bytes line_length + EOL) per line + 4*EOI +
- * one byte 16bit DMA alignment
- */
-#define CPIA_MAX_IMAGE_SIZE ((352*288*2)+64+(288*3)+5)
-
-/* constant value's */
-#define MAGIC_0 0x19
-#define MAGIC_1 0x68
-#define DATA_IN 0xC0
-#define DATA_OUT 0x40
-#define VIDEOSIZE_QCIF 0 /* 176x144 */
-#define VIDEOSIZE_CIF 1 /* 352x288 */
-#define VIDEOSIZE_SIF 2 /* 320x240 */
-#define VIDEOSIZE_QSIF 3 /* 160x120 */
-#define VIDEOSIZE_48_48 4 /* where no one has gone before, iconsize! */
-#define VIDEOSIZE_64_48 5
-#define VIDEOSIZE_128_96 6
-#define VIDEOSIZE_160_120 VIDEOSIZE_QSIF
-#define VIDEOSIZE_176_144 VIDEOSIZE_QCIF
-#define VIDEOSIZE_192_144 7
-#define VIDEOSIZE_224_168 8
-#define VIDEOSIZE_256_192 9
-#define VIDEOSIZE_288_216 10
-#define VIDEOSIZE_320_240 VIDEOSIZE_SIF
-#define VIDEOSIZE_352_288 VIDEOSIZE_CIF
-#define VIDEOSIZE_88_72 11 /* quarter CIF */
-#define SUBSAMPLE_420 0
-#define SUBSAMPLE_422 1
-#define YUVORDER_YUYV 0
-#define YUVORDER_UYVY 1
-#define NOT_COMPRESSED 0
-#define COMPRESSED 1
-#define NO_DECIMATION 0
-#define DECIMATION_ENAB 1
-#define EOI 0xff /* End Of Image */
-#define EOL 0xfd /* End Of Line */
-#define FRAME_HEADER_SIZE 64
-
-/* Image grab modes */
-#define CPIA_GRAB_SINGLE 0
-#define CPIA_GRAB_CONTINUOUS 1
-
-/* Compression parameters */
-#define CPIA_COMPRESSION_NONE 0
-#define CPIA_COMPRESSION_AUTO 1
-#define CPIA_COMPRESSION_MANUAL 2
-#define CPIA_COMPRESSION_TARGET_QUALITY 0
-#define CPIA_COMPRESSION_TARGET_FRAMERATE 1
-
-/* Return offsets for GetCameraState */
-#define SYSTEMSTATE 0
-#define GRABSTATE 1
-#define STREAMSTATE 2
-#define FATALERROR 3
-#define CMDERROR 4
-#define DEBUGFLAGS 5
-#define VPSTATUS 6
-#define ERRORCODE 7
-
-/* SystemState */
-#define UNINITIALISED_STATE 0
-#define PASS_THROUGH_STATE 1
-#define LO_POWER_STATE 2
-#define HI_POWER_STATE 3
-#define WARM_BOOT_STATE 4
-
-/* GrabState */
-#define GRAB_IDLE 0
-#define GRAB_ACTIVE 1
-#define GRAB_DONE 2
-
-/* StreamState */
-#define STREAM_NOT_READY 0
-#define STREAM_READY 1
-#define STREAM_OPEN 2
-#define STREAM_PAUSED 3
-#define STREAM_FINISHED 4
-
-/* Fatal Error, CmdError, and DebugFlags */
-#define CPIA_FLAG 1
-#define SYSTEM_FLAG 2
-#define INT_CTRL_FLAG 4
-#define PROCESS_FLAG 8
-#define COM_FLAG 16
-#define VP_CTRL_FLAG 32
-#define CAPTURE_FLAG 64
-#define DEBUG_FLAG 128
-
-/* VPStatus */
-#define VP_STATE_OK 0x00
-
-#define VP_STATE_FAILED_VIDEOINIT 0x01
-#define VP_STATE_FAILED_AECACBINIT 0x02
-#define VP_STATE_AEC_MAX 0x04
-#define VP_STATE_ACB_BMAX 0x08
-
-#define VP_STATE_ACB_RMIN 0x10
-#define VP_STATE_ACB_GMIN 0x20
-#define VP_STATE_ACB_RMAX 0x40
-#define VP_STATE_ACB_GMAX 0x80
-
-/* default (minimum) compensation values */
-#define COMP_RED 220
-#define COMP_GREEN1 214
-#define COMP_GREEN2 COMP_GREEN1
-#define COMP_BLUE 230
-
-/* exposure status */
-#define EXPOSURE_VERY_LIGHT 0
-#define EXPOSURE_LIGHT 1
-#define EXPOSURE_NORMAL 2
-#define EXPOSURE_DARK 3
-#define EXPOSURE_VERY_DARK 4
-
-/* ErrorCode */
-#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */
-#define ALOG(fmt,args...) printk(fmt, ##args)
-#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __func__ , __LINE__ , ##args)
-
-#ifdef _CPIA_DEBUG_
-#define ADBG(fmt,args...) printk(fmt, jiffies, ##args)
-#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __func__, __LINE__ , ##args)
-#else
-#define DBG(fmn,args...) do {} while(0)
-#endif
-
-#define DEB_BYTE(p)\
- DBG("%1d %1d %1d %1d %1d %1d %1d %1d \n",\
- (p)&0x80?1:0, (p)&0x40?1:0, (p)&0x20?1:0, (p)&0x10?1:0,\
- (p)&0x08?1:0, (p)&0x04?1:0, (p)&0x02?1:0, (p)&0x01?1:0);
-
-#endif /* __KERNEL__ */
-
-#endif /* cpia_h */
diff --git a/drivers/media/video/cpia2/Kconfig b/drivers/media/video/cpia2/Kconfig
index e39a96152004..66e9283f5993 100644
--- a/drivers/media/video/cpia2/Kconfig
+++ b/drivers/media/video/cpia2/Kconfig
@@ -1,6 +1,6 @@
config VIDEO_CPIA2
tristate "CPiA2 Video For Linux"
- depends on VIDEO_DEV && USB && VIDEO_V4L1
+ depends on VIDEO_DEV && USB && VIDEO_V4L2
---help---
This is the video4linux driver for cameras based on Vision's CPiA2
(Colour Processor Interface ASIC), such as the Digital Blue QX5
diff --git a/drivers/media/video/cpia2/cpia2.h b/drivers/media/video/cpia2/cpia2.h
index 8d2dfc128821..6d6d1843791c 100644
--- a/drivers/media/video/cpia2/cpia2.h
+++ b/drivers/media/video/cpia2/cpia2.h
@@ -32,7 +32,7 @@
#define __CPIA2_H__
#include <linux/version.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/usb.h>
#include <linux/poll.h>
@@ -43,7 +43,7 @@
/* define for verbose debug output */
//#define _CPIA2_DEBUG_
-#define CPIA2_MAJ_VER 2
+#define CPIA2_MAJ_VER 3
#define CPIA2_MIN_VER 0
#define CPIA2_PATCH_VER 0
@@ -378,7 +378,7 @@ struct cpia2_fh {
struct camera_data {
/* locks */
- struct mutex busy_lock; /* guard against SMP multithreading */
+ struct mutex v4l2_lock; /* serialize file operations */
struct v4l2_prio_state prio;
/* camera status */
@@ -396,8 +396,8 @@ struct camera_data {
/* v4l */
int video_size; /* VIDEO_SIZE_ */
struct video_device *vdev; /* v4l videodev */
- struct video_picture vp; /* v4l camera settings */
- struct video_window vw; /* v4l capture area */
+ u32 width;
+ u32 height; /* Its size */
__u32 pixelformat; /* Format fourcc */
/* USB */
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index 1cc0df8befff..aaffca8e13fd 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -1058,44 +1058,44 @@ static int set_vw_size(struct camera_data *cam, int size)
DBG("Setting size to VGA\n");
cam->params.roi.width = STV_IMAGE_VGA_COLS;
cam->params.roi.height = STV_IMAGE_VGA_ROWS;
- cam->vw.width = STV_IMAGE_VGA_COLS;
- cam->vw.height = STV_IMAGE_VGA_ROWS;
+ cam->width = STV_IMAGE_VGA_COLS;
+ cam->height = STV_IMAGE_VGA_ROWS;
break;
case VIDEOSIZE_CIF:
DBG("Setting size to CIF\n");
cam->params.roi.width = STV_IMAGE_CIF_COLS;
cam->params.roi.height = STV_IMAGE_CIF_ROWS;
- cam->vw.width = STV_IMAGE_CIF_COLS;
- cam->vw.height = STV_IMAGE_CIF_ROWS;
+ cam->width = STV_IMAGE_CIF_COLS;
+ cam->height = STV_IMAGE_CIF_ROWS;
break;
case VIDEOSIZE_QVGA:
DBG("Setting size to QVGA\n");
cam->params.roi.width = STV_IMAGE_QVGA_COLS;
cam->params.roi.height = STV_IMAGE_QVGA_ROWS;
- cam->vw.width = STV_IMAGE_QVGA_COLS;
- cam->vw.height = STV_IMAGE_QVGA_ROWS;
+ cam->width = STV_IMAGE_QVGA_COLS;
+ cam->height = STV_IMAGE_QVGA_ROWS;
break;
case VIDEOSIZE_288_216:
cam->params.roi.width = 288;
cam->params.roi.height = 216;
- cam->vw.width = 288;
- cam->vw.height = 216;
+ cam->width = 288;
+ cam->height = 216;
break;
case VIDEOSIZE_256_192:
- cam->vw.width = 256;
- cam->vw.height = 192;
+ cam->width = 256;
+ cam->height = 192;
cam->params.roi.width = 256;
cam->params.roi.height = 192;
break;
case VIDEOSIZE_224_168:
- cam->vw.width = 224;
- cam->vw.height = 168;
+ cam->width = 224;
+ cam->height = 168;
cam->params.roi.width = 224;
cam->params.roi.height = 168;
break;
case VIDEOSIZE_192_144:
- cam->vw.width = 192;
- cam->vw.height = 144;
+ cam->width = 192;
+ cam->height = 144;
cam->params.roi.width = 192;
cam->params.roi.height = 144;
break;
@@ -1103,8 +1103,8 @@ static int set_vw_size(struct camera_data *cam, int size)
DBG("Setting size to QCIF\n");
cam->params.roi.width = STV_IMAGE_QCIF_COLS;
cam->params.roi.height = STV_IMAGE_QCIF_ROWS;
- cam->vw.width = STV_IMAGE_QCIF_COLS;
- cam->vw.height = STV_IMAGE_QCIF_ROWS;
+ cam->width = STV_IMAGE_QCIF_COLS;
+ cam->height = STV_IMAGE_QCIF_ROWS;
break;
default:
retval = -EINVAL;
@@ -2224,23 +2224,8 @@ static void reset_camera_struct(struct camera_data *cam)
cam->params.roi.height = STV_IMAGE_CIF_ROWS;
}
- /***
- * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP
- * Ioctl. Here, just do the window and picture stucts.
- ***/
- cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */
- cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
- cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
- cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
-
- cam->vw.x = 0;
- cam->vw.y = 0;
- cam->vw.width = cam->params.roi.width;
- cam->vw.height = cam->params.roi.height;
- cam->vw.flags = 0;
- cam->vw.clipcount = 0;
-
- return;
+ cam->width = cam->params.roi.width;
+ cam->height = cam->params.roi.height;
}
/******************************************************************************
@@ -2262,7 +2247,7 @@ struct camera_data *cpia2_init_camera_struct(void)
cam->present = 1;
- mutex_init(&cam->busy_lock);
+ mutex_init(&cam->v4l2_lock);
init_waitqueue_head(&cam->wq_stream);
return cam;
@@ -2380,9 +2365,9 @@ long cpia2_read(struct camera_data *cam,
char __user *buf, unsigned long count, int noblock)
{
struct framebuf *frame;
- if (!count) {
+
+ if (!count)
return 0;
- }
if (!buf) {
ERR("%s: buffer NULL\n",__func__);
@@ -2394,17 +2379,12 @@ long cpia2_read(struct camera_data *cam,
return -EINVAL;
}
- /* make this _really_ smp and multithread-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -ERESTARTSYS;
-
if (!cam->present) {
LOG("%s: camera removed\n",__func__);
- mutex_unlock(&cam->busy_lock);
return 0; /* EOF */
}
- if(!cam->streaming) {
+ if (!cam->streaming) {
/* Start streaming */
cpia2_usb_stream_start(cam,
cam->params.camera_state.stream_mode);
@@ -2413,42 +2393,31 @@ long cpia2_read(struct camera_data *cam,
/* Copy cam->curbuff in case it changes while we're processing */
frame = cam->curbuff;
if (noblock && frame->status != FRAME_READY) {
- mutex_unlock(&cam->busy_lock);
return -EAGAIN;
}
- if(frame->status != FRAME_READY) {
- mutex_unlock(&cam->busy_lock);
+ if (frame->status != FRAME_READY) {
+ mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
!cam->present ||
(frame = cam->curbuff)->status == FRAME_READY);
+ mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
- /* make this _really_ smp and multithread-safe */
- if (mutex_lock_interruptible(&cam->busy_lock)) {
- return -ERESTARTSYS;
- }
- if(!cam->present) {
- mutex_unlock(&cam->busy_lock);
+ if (!cam->present)
return 0;
- }
}
/* copy data to user space */
- if (frame->length > count) {
- mutex_unlock(&cam->busy_lock);
+ if (frame->length > count)
return -EFAULT;
- }
- if (copy_to_user(buf, frame->data, frame->length)) {
- mutex_unlock(&cam->busy_lock);
+ if (copy_to_user(buf, frame->data, frame->length))
return -EFAULT;
- }
count = frame->length;
frame->status = FRAME_EMPTY;
- mutex_unlock(&cam->busy_lock);
return count;
}
@@ -2462,17 +2431,13 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
{
unsigned int status=0;
- if(!cam) {
+ if (!cam) {
ERR("%s: Internal error, camera_data not found!\n",__func__);
return POLLERR;
}
- mutex_lock(&cam->busy_lock);
-
- if(!cam->present) {
- mutex_unlock(&cam->busy_lock);
+ if (!cam->present)
return POLLHUP;
- }
if(!cam->streaming) {
/* Start streaming */
@@ -2480,16 +2445,13 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
cam->params.camera_state.stream_mode);
}
- mutex_unlock(&cam->busy_lock);
poll_wait(filp, &cam->wq_stream, wait);
- mutex_lock(&cam->busy_lock);
if(!cam->present)
status = POLLHUP;
else if(cam->curbuff->status == FRAME_READY)
status = POLLIN | POLLRDNORM;
- mutex_unlock(&cam->busy_lock);
return status;
}
@@ -2511,29 +2473,19 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
DBG("mmap offset:%ld size:%ld\n", start_offset, size);
- /* make this _really_ smp-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -ERESTARTSYS;
-
- if (!cam->present) {
- mutex_unlock(&cam->busy_lock);
+ if (!cam->present)
return -ENODEV;
- }
if (size > cam->frame_size*cam->num_frames ||
(start_offset % cam->frame_size) != 0 ||
- (start_offset+size > cam->frame_size*cam->num_frames)) {
- mutex_unlock(&cam->busy_lock);
+ (start_offset+size > cam->frame_size*cam->num_frames))
return -EINVAL;
- }
pos = ((unsigned long) (cam->frame_buffer)) + start_offset;
while (size > 0) {
page = kvirt_to_pa(pos);
- if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&cam->busy_lock);
+ if (remap_pfn_range(vma, start, page >> PAGE_SHIFT, PAGE_SIZE, PAGE_SHARED))
return -EAGAIN;
- }
start += PAGE_SIZE;
pos += PAGE_SIZE;
if (size > PAGE_SIZE)
@@ -2543,7 +2495,5 @@ int cpia2_remap_buffer(struct camera_data *cam, struct vm_area_struct *vma)
}
cam->mmapped = true;
- mutex_unlock(&cam->busy_lock);
return 0;
}
-
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index 5520789854da..9bad39842936 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -37,7 +37,7 @@
#include <linux/sched.h>
#include <linux/slab.h>
#include <linux/init.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <linux/stringify.h>
#include <media/v4l2-ioctl.h>
@@ -238,59 +238,40 @@ static struct v4l2_queryctrl controls[] = {
static int cpia2_open(struct file *file)
{
struct camera_data *cam = video_drvdata(file);
- int retval = 0;
+ struct cpia2_fh *fh;
if (!cam) {
ERR("Internal error, camera_data not found!\n");
return -ENODEV;
}
- if(mutex_lock_interruptible(&cam->busy_lock))
- return -ERESTARTSYS;
-
- if(!cam->present) {
- retval = -ENODEV;
- goto err_return;
- }
+ if (!cam->present)
+ return -ENODEV;
- if (cam->open_count > 0) {
- goto skip_init;
- }
+ if (cam->open_count == 0) {
+ if (cpia2_allocate_buffers(cam))
+ return -ENOMEM;
- if (cpia2_allocate_buffers(cam)) {
- retval = -ENOMEM;
- goto err_return;
- }
+ /* reset the camera */
+ if (cpia2_reset_camera(cam) < 0)
+ return -EIO;
- /* reset the camera */
- if (cpia2_reset_camera(cam) < 0) {
- retval = -EIO;
- goto err_return;
+ cam->APP_len = 0;
+ cam->COM_len = 0;
}
- cam->APP_len = 0;
- cam->COM_len = 0;
-
-skip_init:
- {
- struct cpia2_fh *fh = kmalloc(sizeof(*fh),GFP_KERNEL);
- if(!fh) {
- retval = -ENOMEM;
- goto err_return;
- }
- file->private_data = fh;
- fh->prio = V4L2_PRIORITY_UNSET;
- v4l2_prio_open(&cam->prio, &fh->prio);
- fh->mmapped = 0;
- }
+ fh = kmalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh)
+ return -ENOMEM;
+ file->private_data = fh;
+ fh->prio = V4L2_PRIORITY_UNSET;
+ v4l2_prio_open(&cam->prio, &fh->prio);
+ fh->mmapped = 0;
++cam->open_count;
cpia2_dbg_dump_registers(cam);
-
-err_return:
- mutex_unlock(&cam->busy_lock);
- return retval;
+ return 0;
}
/******************************************************************************
@@ -304,15 +285,11 @@ static int cpia2_close(struct file *file)
struct camera_data *cam = video_get_drvdata(dev);
struct cpia2_fh *fh = file->private_data;
- mutex_lock(&cam->busy_lock);
-
if (cam->present &&
- (cam->open_count == 1
- || fh->prio == V4L2_PRIORITY_RECORD
- )) {
+ (cam->open_count == 1 || fh->prio == V4L2_PRIORITY_RECORD)) {
cpia2_usb_stream_stop(cam);
- if(cam->open_count == 1) {
+ if (cam->open_count == 1) {
/* save camera state for later open */
cpia2_save_camera_state(cam);
@@ -321,26 +298,21 @@ static int cpia2_close(struct file *file)
}
}
- {
- if(fh->mmapped)
- cam->mmapped = 0;
- v4l2_prio_close(&cam->prio, fh->prio);
- file->private_data = NULL;
- kfree(fh);
- }
+ if (fh->mmapped)
+ cam->mmapped = 0;
+ v4l2_prio_close(&cam->prio, fh->prio);
+ file->private_data = NULL;
+ kfree(fh);
if (--cam->open_count == 0) {
cpia2_free_buffers(cam);
if (!cam->present) {
video_unregister_device(dev);
- mutex_unlock(&cam->busy_lock);
kfree(cam);
return 0;
}
}
- mutex_unlock(&cam->busy_lock);
-
return 0;
}
@@ -391,113 +363,6 @@ static unsigned int cpia2_v4l_poll(struct file *filp, struct poll_table_struct *
}
-/******************************************************************************
- *
- * ioctl_cap_query
- *
- *****************************************************************************/
-static int ioctl_cap_query(void *arg, struct camera_data *cam)
-{
- struct video_capability *vc;
- int retval = 0;
- vc = arg;
-
- if (cam->params.pnp_id.product == 0x151)
- strcpy(vc->name, "QX5 Microscope");
- else
- strcpy(vc->name, "CPiA2 Camera");
-
- vc->type = VID_TYPE_CAPTURE | VID_TYPE_MJPEG_ENCODER;
- vc->channels = 1;
- vc->audios = 0;
- vc->minwidth = 176; /* VIDEOSIZE_QCIF */
- vc->minheight = 144;
- switch (cam->params.version.sensor_flags) {
- case CPIA2_VP_SENSOR_FLAGS_500:
- vc->maxwidth = STV_IMAGE_VGA_COLS;
- vc->maxheight = STV_IMAGE_VGA_ROWS;
- break;
- case CPIA2_VP_SENSOR_FLAGS_410:
- vc->maxwidth = STV_IMAGE_CIF_COLS;
- vc->maxheight = STV_IMAGE_CIF_ROWS;
- break;
- default:
- return -EINVAL;
- }
-
- return retval;
-}
-
-/******************************************************************************
- *
- * ioctl_get_channel
- *
- *****************************************************************************/
-static int ioctl_get_channel(void *arg)
-{
- int retval = 0;
- struct video_channel *v;
- v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
-
- v->channel = 0;
- strcpy(v->name, "Camera");
- v->tuners = 0;
- v->flags = 0;
- v->type = VIDEO_TYPE_CAMERA;
- v->norm = 0;
-
- return retval;
-}
-
-/******************************************************************************
- *
- * ioctl_set_channel
- *
- *****************************************************************************/
-static int ioctl_set_channel(void *arg)
-{
- struct video_channel *v;
- int retval = 0;
- v = arg;
-
- if (retval == 0 && v->channel != 0)
- retval = -EINVAL;
-
- return retval;
-}
-
-/******************************************************************************
- *
- * ioctl_set_image_prop
- *
- *****************************************************************************/
-static int ioctl_set_image_prop(void *arg, struct camera_data *cam)
-{
- struct video_picture *vp;
- int retval = 0;
- vp = arg;
-
- /* brightness, color, contrast need no check 0-65535 */
- memcpy(&cam->vp, vp, sizeof(*vp));
-
- /* update cam->params.colorParams */
- cam->params.color_params.brightness = vp->brightness / 256;
- cam->params.color_params.saturation = vp->colour / 256;
- cam->params.color_params.contrast = vp->contrast / 256;
-
- DBG("Requested params: bright 0x%X, sat 0x%X, contrast 0x%X\n",
- cam->params.color_params.brightness,
- cam->params.color_params.saturation,
- cam->params.color_params.contrast);
-
- cpia2_set_color_params(cam);
-
- return retval;
-}
-
static int sync(struct camera_data *cam, int frame_nr)
{
struct framebuf *frame = &cam->buffers[frame_nr];
@@ -512,11 +377,11 @@ static int sync(struct camera_data *cam, int frame_nr)
return 0;
}
- mutex_unlock(&cam->busy_lock);
+ mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
!cam->streaming ||
frame->status == FRAME_READY);
- mutex_lock(&cam->busy_lock);
+ mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
if(!cam->present)
@@ -526,138 +391,6 @@ static int sync(struct camera_data *cam, int frame_nr)
/******************************************************************************
*
- * ioctl_set_window_size
- *
- *****************************************************************************/
-static int ioctl_set_window_size(void *arg, struct camera_data *cam,
- struct cpia2_fh *fh)
-{
- /* copy_from_user, check validity, copy to internal structure */
- struct video_window *vw;
- int frame, err;
- vw = arg;
-
- if (vw->clipcount != 0) /* clipping not supported */
- return -EINVAL;
-
- if (vw->clips != NULL) /* clipping not supported */
- return -EINVAL;
-
- /* Ensure that only this process can change the format. */
- err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
- if(err != 0)
- return err;
-
- cam->pixelformat = V4L2_PIX_FMT_JPEG;
-
- /* Be sure to supply the Huffman tables, this isn't MJPEG */
- cam->params.compression.inhibit_htables = 0;
-
- /* we set the video window to something smaller or equal to what
- * is requested by the user???
- */
- DBG("Requested width = %d, height = %d\n", vw->width, vw->height);
- if (vw->width != cam->vw.width || vw->height != cam->vw.height) {
- cam->vw.width = vw->width;
- cam->vw.height = vw->height;
- cam->params.roi.width = vw->width;
- cam->params.roi.height = vw->height;
- cpia2_set_format(cam);
- }
-
- for (frame = 0; frame < cam->num_frames; ++frame) {
- if (cam->buffers[frame].status == FRAME_READING)
- if ((err = sync(cam, frame)) < 0)
- return err;
-
- cam->buffers[frame].status = FRAME_EMPTY;
- }
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_get_mbuf
- *
- *****************************************************************************/
-static int ioctl_get_mbuf(void *arg, struct camera_data *cam)
-{
- struct video_mbuf *vm;
- int i;
- vm = arg;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = cam->frame_size*cam->num_frames;
- vm->frames = cam->num_frames;
- for (i = 0; i < cam->num_frames; i++)
- vm->offsets[i] = cam->frame_size * i;
-
- return 0;
-}
-
-/******************************************************************************
- *
- * ioctl_mcapture
- *
- *****************************************************************************/
-static int ioctl_mcapture(void *arg, struct camera_data *cam,
- struct cpia2_fh *fh)
-{
- struct video_mmap *vm;
- int video_size, err;
- vm = arg;
-
- if (vm->frame < 0 || vm->frame >= cam->num_frames)
- return -EINVAL;
-
- /* set video size */
- video_size = cpia2_match_video_size(vm->width, vm->height);
- if (cam->video_size < 0) {
- return -EINVAL;
- }
-
- /* Ensure that only this process can change the format. */
- err = v4l2_prio_change(&cam->prio, &fh->prio, V4L2_PRIORITY_RECORD);
- if(err != 0)
- return err;
-
- if (video_size != cam->video_size) {
- cam->video_size = video_size;
- cam->params.roi.width = vm->width;
- cam->params.roi.height = vm->height;
- cpia2_set_format(cam);
- }
-
- if (cam->buffers[vm->frame].status == FRAME_READING)
- if ((err=sync(cam, vm->frame)) < 0)
- return err;
-
- cam->buffers[vm->frame].status = FRAME_EMPTY;
-
- return cpia2_usb_stream_start(cam,cam->params.camera_state.stream_mode);
-}
-
-/******************************************************************************
- *
- * ioctl_sync
- *
- *****************************************************************************/
-static int ioctl_sync(void *arg, struct camera_data *cam)
-{
- int frame;
-
- frame = *(int*)arg;
-
- if (frame < 0 || frame >= cam->num_frames)
- return -EINVAL;
-
- return sync(cam, frame);
-}
-
-
-/******************************************************************************
- *
* ioctl_set_gpio
*
*****************************************************************************/
@@ -897,10 +630,10 @@ static int ioctl_set_fmt(void *arg,struct camera_data *cam, struct cpia2_fh *fh)
*/
DBG("Requested width = %d, height = %d\n",
f->fmt.pix.width, f->fmt.pix.height);
- if (f->fmt.pix.width != cam->vw.width ||
- f->fmt.pix.height != cam->vw.height) {
- cam->vw.width = f->fmt.pix.width;
- cam->vw.height = f->fmt.pix.height;
+ if (f->fmt.pix.width != cam->width ||
+ f->fmt.pix.height != cam->height) {
+ cam->width = f->fmt.pix.width;
+ cam->height = f->fmt.pix.height;
cam->params.roi.width = f->fmt.pix.width;
cam->params.roi.height = f->fmt.pix.height;
cpia2_set_format(cam);
@@ -932,8 +665,8 @@ static int ioctl_get_fmt(void *arg,struct camera_data *cam)
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- f->fmt.pix.width = cam->vw.width;
- f->fmt.pix.height = cam->vw.height;
+ f->fmt.pix.width = cam->width;
+ f->fmt.pix.height = cam->height;
f->fmt.pix.pixelformat = cam->pixelformat;
f->fmt.pix.field = V4L2_FIELD_NONE;
f->fmt.pix.bytesperline = 0;
@@ -962,12 +695,12 @@ static int ioctl_cropcap(void *arg,struct camera_data *cam)
c->bounds.left = 0;
c->bounds.top = 0;
- c->bounds.width = cam->vw.width;
- c->bounds.height = cam->vw.height;
+ c->bounds.width = cam->width;
+ c->bounds.height = cam->height;
c->defrect.left = 0;
c->defrect.top = 0;
- c->defrect.width = cam->vw.width;
- c->defrect.height = cam->vw.height;
+ c->defrect.width = cam->width;
+ c->defrect.height = cam->height;
c->pixelaspect.numerator = 1;
c->pixelaspect.denominator = 1;
@@ -1532,11 +1265,11 @@ static int ioctl_dqbuf(void *arg,struct camera_data *cam, struct file *file)
if(frame < 0) {
/* Wait for a frame to become available */
struct framebuf *cb=cam->curbuff;
- mutex_unlock(&cam->busy_lock);
+ mutex_unlock(&cam->v4l2_lock);
wait_event_interruptible(cam->wq_stream,
!cam->present ||
(cb=cam->curbuff)->status == FRAME_READY);
- mutex_lock(&cam->busy_lock);
+ mutex_lock(&cam->v4l2_lock);
if (signal_pending(current))
return -ERESTARTSYS;
if(!cam->present)
@@ -1576,37 +1309,17 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!cam)
return -ENOTTY;
- /* make this _really_ smp-safe */
- if (mutex_lock_interruptible(&cam->busy_lock))
- return -ERESTARTSYS;
-
- if (!cam->present) {
- mutex_unlock(&cam->busy_lock);
+ if (!cam->present)
return -ENODEV;
- }
/* Priority check */
switch (cmd) {
- case VIDIOCSWIN:
- case VIDIOCMCAPTURE:
case VIDIOC_S_FMT:
{
struct cpia2_fh *fh = file->private_data;
retval = v4l2_prio_check(&cam->prio, fh->prio);
- if(retval) {
- mutex_unlock(&cam->busy_lock);
+ if (retval)
return retval;
- }
- break;
- }
- case VIDIOCGMBUF:
- case VIDIOCSYNC:
- {
- struct cpia2_fh *fh = file->private_data;
- if(fh->prio != V4L2_PRIORITY_RECORD) {
- mutex_unlock(&cam->busy_lock);
- return -EBUSY;
- }
break;
}
default:
@@ -1614,59 +1327,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
switch (cmd) {
- case VIDIOCGCAP: /* query capabilities */
- retval = ioctl_cap_query(arg, cam);
- break;
-
- case VIDIOCGCHAN: /* get video source - we are a camera, nothing else */
- retval = ioctl_get_channel(arg);
- break;
- case VIDIOCSCHAN: /* set video source - we are a camera, nothing else */
- retval = ioctl_set_channel(arg);
- break;
- case VIDIOCGPICT: /* image properties */
- memcpy(arg, &cam->vp, sizeof(struct video_picture));
- break;
- case VIDIOCSPICT:
- retval = ioctl_set_image_prop(arg, cam);
- break;
- case VIDIOCGWIN: /* get/set capture window */
- memcpy(arg, &cam->vw, sizeof(struct video_window));
- break;
- case VIDIOCSWIN:
- retval = ioctl_set_window_size(arg, cam, file->private_data);
- break;
- case VIDIOCGMBUF: /* mmap interface */
- retval = ioctl_get_mbuf(arg, cam);
- break;
- case VIDIOCMCAPTURE:
- retval = ioctl_mcapture(arg, cam, file->private_data);
- break;
- case VIDIOCSYNC:
- retval = ioctl_sync(arg, cam);
- break;
- /* pointless to implement overlay with this camera */
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCKEY:
- retval = -EINVAL;
- break;
-
- /* tuner interface - we have none */
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- retval = -EINVAL;
- break;
-
- /* audio interface - we have none */
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- retval = -EINVAL;
- break;
-
/* CPIA2 extension to Video4Linux API */
case CPIA2_IOC_SET_GPIO:
retval = ioctl_set_gpio(arg, cam);
@@ -1833,7 +1493,6 @@ static long cpia2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
break;
}
- mutex_unlock(&cam->busy_lock);
return retval;
}
@@ -1874,21 +1533,8 @@ static int cpia2_mmap(struct file *file, struct vm_area_struct *area)
*****************************************************************************/
static void reset_camera_struct_v4l(struct camera_data *cam)
{
- /***
- * Fill in the v4l structures. video_cap is filled in inside the VIDIOCCAP
- * Ioctl. Here, just do the window and picture stucts.
- ***/
- cam->vp.palette = (u16) VIDEO_PALETTE_RGB24; /* Is this right? */
- cam->vp.brightness = (u16) cam->params.color_params.brightness * 256;
- cam->vp.colour = (u16) cam->params.color_params.saturation * 256;
- cam->vp.contrast = (u16) cam->params.color_params.contrast * 256;
-
- cam->vw.x = 0;
- cam->vw.y = 0;
- cam->vw.width = cam->params.roi.width;
- cam->vw.height = cam->params.roi.height;
- cam->vw.flags = 0;
- cam->vw.clipcount = 0;
+ cam->width = cam->params.roi.width;
+ cam->height = cam->params.roi.height;
cam->frame_size = buffer_size;
cam->num_frames = num_buffers;
@@ -1902,27 +1548,26 @@ static void reset_camera_struct_v4l(struct camera_data *cam)
cam->pixelformat = V4L2_PIX_FMT_JPEG;
v4l2_prio_init(&cam->prio);
- return;
}
/***
* The v4l video device structure initialized for this device
***/
-static const struct v4l2_file_operations fops_template = {
+static const struct v4l2_file_operations cpia2_fops = {
.owner = THIS_MODULE,
.open = cpia2_open,
.release = cpia2_close,
.read = cpia2_v4l_read,
.poll = cpia2_v4l_poll,
- .ioctl = cpia2_ioctl,
+ .unlocked_ioctl = cpia2_ioctl,
.mmap = cpia2_mmap,
};
static struct video_device cpia2_template = {
/* I could not find any place for the old .initialize initializer?? */
- .name= "CPiA2 Camera",
- .fops= &fops_template,
- .release= video_device_release,
+ .name = "CPiA2 Camera",
+ .fops = &cpia2_fops,
+ .release = video_device_release,
};
/******************************************************************************
@@ -1938,6 +1583,7 @@ int cpia2_register_camera(struct camera_data *cam)
memcpy(cam->vdev, &cpia2_template, sizeof(cpia2_template));
video_set_drvdata(cam->vdev, cam);
+ cam->vdev->lock = &cam->v4l2_lock;
reset_camera_struct_v4l(cam);
diff --git a/drivers/media/video/cpia2/cpia2dev.h b/drivers/media/video/cpia2/cpia2dev.h
index d58097ce0d5e..f66691fe5a35 100644
--- a/drivers/media/video/cpia2/cpia2dev.h
+++ b/drivers/media/video/cpia2/cpia2dev.h
@@ -29,14 +29,14 @@
#ifndef CPIA2_DEV_HEADER
#define CPIA2_DEV_HEADER
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
/***
* The following defines are ioctl numbers based on video4linux private ioctls,
* which can range from 192 (BASE_VIDIOCPRIVATE) to 255. All of these take int
* args
*/
-#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOCPRIVATE + 17, __u32)
+#define CPIA2_IOC_SET_GPIO _IOW('v', BASE_VIDIOC_PRIVATE + 17, __u32)
/* V4L2 driver specific controls */
#define CPIA2_CID_TARGET_KB (V4L2_CID_PRIVATE_BASE+0)
diff --git a/drivers/media/video/cpia_pp.c b/drivers/media/video/cpia_pp.c
deleted file mode 100644
index f5604c16a092..000000000000
--- a/drivers/media/video/cpia_pp.c
+++ /dev/null
@@ -1,869 +0,0 @@
-/*
- * cpia_pp CPiA Parallel Port driver
- *
- * Supports CPiA based parallel port Video Camera's.
- *
- * (C) Copyright 1999 Bas Huisman <bhuism@cs.utwente.nl>
- * (C) Copyright 1999-2000 Scott J. Bertin <sbertin@securenym.net>,
- * (C) Copyright 1999-2000 Peter Pregler <Peter_Pregler@email.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_ 1 */
-
-
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include <linux/kernel.h>
-#include <linux/parport.h>
-#include <linux/interrupt.h>
-#include <linux/delay.h>
-#include <linux/workqueue.h>
-#include <linux/sched.h>
-#include <linux/slab.h>
-
-#include <linux/kmod.h>
-
-/* #define _CPIA_DEBUG_ define for verbose debug output */
-#include "cpia.h"
-
-static int cpia_pp_open(void *privdata);
-static int cpia_pp_registerCallback(void *privdata, void (*cb) (void *cbdata),
- void *cbdata);
-static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data);
-static int cpia_pp_streamStart(void *privdata);
-static int cpia_pp_streamStop(void *privdata);
-static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock);
-static int cpia_pp_close(void *privdata);
-
-
-#define ABOUT "Parallel port driver for Vision CPiA based cameras"
-
-#define PACKET_LENGTH 8
-
-/* Magic numbers for defining port-device mappings */
-#define PPCPIA_PARPORT_UNSPEC -4
-#define PPCPIA_PARPORT_AUTO -3
-#define PPCPIA_PARPORT_OFF -2
-#define PPCPIA_PARPORT_NONE -1
-
-static int parport_nr[PARPORT_MAX] = {[0 ... PARPORT_MAX - 1] = PPCPIA_PARPORT_UNSPEC};
-static char *parport[PARPORT_MAX] = {NULL,};
-
-MODULE_AUTHOR("B. Huisman <bhuism@cs.utwente.nl> & Peter Pregler <Peter_Pregler@email.com>");
-MODULE_DESCRIPTION("Parallel port driver for Vision CPiA based cameras");
-MODULE_LICENSE("GPL");
-
-module_param_array(parport, charp, NULL, 0);
-MODULE_PARM_DESC(parport, "'auto' or a list of parallel port numbers. Just like lp.");
-
-struct pp_cam_entry {
- struct pardevice *pdev;
- struct parport *port;
- struct work_struct cb_task;
- void (*cb_func)(void *cbdata);
- void *cb_data;
- int open_count;
- wait_queue_head_t wq_stream;
- /* image state flags */
- int image_ready; /* we got an interrupt */
- int image_complete; /* we have seen 4 EOI */
-
- int streaming; /* we are in streaming mode */
- int stream_irq;
-};
-
-static struct cpia_camera_ops cpia_pp_ops =
-{
- cpia_pp_open,
- cpia_pp_registerCallback,
- cpia_pp_transferCmd,
- cpia_pp_streamStart,
- cpia_pp_streamStop,
- cpia_pp_streamRead,
- cpia_pp_close,
- 1,
- THIS_MODULE
-};
-
-static LIST_HEAD(cam_list);
-static spinlock_t cam_list_lock_pp;
-
-/* FIXME */
-static void cpia_parport_enable_irq( struct parport *port ) {
- parport_enable_irq(port);
- mdelay(10);
- return;
-}
-
-static void cpia_parport_disable_irq( struct parport *port ) {
- parport_disable_irq(port);
- mdelay(10);
- return;
-}
-
-/* Special CPiA PPC modes: These are invoked by using the 1284 Extensibility
- * Link Flag during negotiation */
-#define UPLOAD_FLAG 0x08
-#define NIBBLE_TRANSFER 0x01
-#define ECP_TRANSFER 0x03
-
-#define PARPORT_CHUNK_SIZE PAGE_SIZE
-
-
-static void cpia_pp_run_callback(struct work_struct *work)
-{
- void (*cb_func)(void *cbdata);
- void *cb_data;
- struct pp_cam_entry *cam;
-
- cam = container_of(work, struct pp_cam_entry, cb_task);
- cb_func = cam->cb_func;
- cb_data = cam->cb_data;
-
- cb_func(cb_data);
-}
-
-/****************************************************************************
- *
- * CPiA-specific low-level parport functions for nibble uploads
- *
- ***************************************************************************/
-/* CPiA nonstandard "Nibble" mode (no nDataAvail signal after each byte). */
-/* The standard kernel parport_ieee1284_read_nibble() fails with the CPiA... */
-
-static size_t cpia_read_nibble (struct parport *port,
- void *buffer, size_t len,
- int flags)
-{
- /* adapted verbatim, with one change, from
- parport_ieee1284_read_nibble() in drivers/parport/ieee1284-ops.c */
-
- unsigned char *buf = buffer;
- int i;
- unsigned char byte = 0;
-
- len *= 2; /* in nibbles */
- for (i=0; i < len; i++) {
- unsigned char nibble;
-
- /* The CPiA firmware suppresses the use of nDataAvail (nFault LO)
- * after every second nibble to signal that more
- * data is available. (the total number of Bytes that
- * should be sent is known; if too few are received, an error
- * will be recorded after a timeout).
- * This is incompatible with parport_ieee1284_read_nibble(),
- * which expects to find nFault LO after every second nibble.
- */
-
- /* Solution: modify cpia_read_nibble to only check for
- * nDataAvail before the first nibble is sent.
- */
-
- /* Does the error line indicate end of data? */
- if (((i /*& 1*/) == 0) &&
- (parport_read_status(port) & PARPORT_STATUS_ERROR)) {
- DBG("%s: No more nibble data (%d bytes)\n",
- port->name, i/2);
- goto end_of_data;
- }
-
- /* Event 7: Set nAutoFd low. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 9: nAck goes low. */
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK, 0)) {
- /* Timeout -- no more data? */
- DBG("%s: Nibble timeout at event 9 (%d bytes)\n",
- port->name, i/2);
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
- break;
- }
-
-
- /* Read a nibble. */
- nibble = parport_read_status (port) >> 3;
- nibble &= ~8;
- if ((nibble & 0x10) == 0)
- nibble |= 8;
- nibble &= 0xf;
-
- /* Event 10: Set nAutoFd high. */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
- /* Event 11: nAck goes high. */
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK)) {
- /* Timeout -- no more data? */
- DBG("%s: Nibble timeout at event 11\n",
- port->name);
- break;
- }
-
- if (i & 1) {
- /* Second nibble */
- byte |= nibble << 4;
- *buf++ = byte;
- } else
- byte = nibble;
- }
-
- if (i == len) {
- /* Read the last nibble without checking data avail. */
- if (parport_read_status (port) & PARPORT_STATUS_ERROR) {
- end_of_data:
- /* Go to reverse idle phase. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
- port->physport->ieee1284.phase = IEEE1284_PH_REV_IDLE;
- }
- else
- port->physport->ieee1284.phase = IEEE1284_PH_HBUSY_DAVAIL;
- }
-
- return i/2;
-}
-
-/* CPiA nonstandard "Nibble Stream" mode (2 nibbles per cycle, instead of 1)
- * (See CPiA Data sheet p. 31)
- *
- * "Nibble Stream" mode used by CPiA for uploads to non-ECP ports is a
- * nonstandard variant of nibble mode which allows the same (mediocre)
- * data flow of 8 bits per cycle as software-enabled ECP by TRISTATE-capable
- * parallel ports, but works also for non-TRISTATE-capable ports.
- * (Standard nibble mode only send 4 bits per cycle)
- *
- */
-
-static size_t cpia_read_nibble_stream(struct parport *port,
- void *buffer, size_t len,
- int flags)
-{
- int i;
- unsigned char *buf = buffer;
- int endseen = 0;
-
- for (i=0; i < len; i++) {
- unsigned char nibble[2], byte = 0;
- int j;
-
- /* Image Data is complete when 4 consecutive EOI bytes (0xff) are seen */
- if (endseen > 3 )
- break;
-
- /* Event 7: Set nAutoFd low. */
- parport_frob_control (port,
- PARPORT_CONTROL_AUTOFD,
- PARPORT_CONTROL_AUTOFD);
-
- /* Event 9: nAck goes low. */
- port->ieee1284.phase = IEEE1284_PH_REV_DATA;
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK, 0)) {
- /* Timeout -- no more data? */
- DBG("%s: Nibble timeout at event 9 (%d bytes)\n",
- port->name, i/2);
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
- break;
- }
-
- /* Read lower nibble */
- nibble[0] = parport_read_status (port) >>3;
-
- /* Event 10: Set nAutoFd high. */
- parport_frob_control (port, PARPORT_CONTROL_AUTOFD, 0);
-
- /* Event 11: nAck goes high. */
- if (parport_wait_peripheral (port,
- PARPORT_STATUS_ACK,
- PARPORT_STATUS_ACK)) {
- /* Timeout -- no more data? */
- DBG("%s: Nibble timeout at event 11\n",
- port->name);
- break;
- }
-
- /* Read upper nibble */
- nibble[1] = parport_read_status (port) >>3;
-
- /* reassemble the byte */
- for (j = 0; j < 2 ; j++ ) {
- nibble[j] &= ~8;
- if ((nibble[j] & 0x10) == 0)
- nibble[j] |= 8;
- nibble[j] &= 0xf;
- }
- byte = (nibble[0] |(nibble[1] << 4));
- *buf++ = byte;
-
- if(byte == EOI)
- endseen++;
- else
- endseen = 0;
- }
- return i;
-}
-
-/****************************************************************************
- *
- * EndTransferMode
- *
- ***************************************************************************/
-static void EndTransferMode(struct pp_cam_entry *cam)
-{
- parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
-}
-
-/****************************************************************************
- *
- * ForwardSetup
- *
- ***************************************************************************/
-static int ForwardSetup(struct pp_cam_entry *cam)
-{
- int retry;
-
- /* The CPiA uses ECP protocol for Downloads from the Host to the camera.
- * This will be software-emulated if ECP hardware is not present
- */
-
- /* the usual camera maximum response time is 10ms, but after receiving
- * some commands, it needs up to 40ms. (Data Sheet p. 32)*/
-
- for(retry = 0; retry < 4; ++retry) {
- if(!parport_negotiate(cam->port, IEEE1284_MODE_ECP)) {
- break;
- }
- mdelay(10);
- }
- if(retry == 4) {
- DBG("Unable to negotiate IEEE1284 ECP Download mode\n");
- return -1;
- }
- return 0;
-}
-/****************************************************************************
- *
- * ReverseSetup
- *
- ***************************************************************************/
-static int ReverseSetup(struct pp_cam_entry *cam, int extensibility)
-{
- int retry;
- int upload_mode, mode = IEEE1284_MODE_ECP;
- int transfer_mode = ECP_TRANSFER;
-
- if (!(cam->port->modes & PARPORT_MODE_ECP) &&
- !(cam->port->modes & PARPORT_MODE_TRISTATE)) {
- mode = IEEE1284_MODE_NIBBLE;
- transfer_mode = NIBBLE_TRANSFER;
- }
-
- upload_mode = mode;
- if(extensibility) mode = UPLOAD_FLAG|transfer_mode|IEEE1284_EXT_LINK;
-
- /* the usual camera maximum response time is 10ms, but after
- * receiving some commands, it needs up to 40ms. */
-
- for(retry = 0; retry < 4; ++retry) {
- if(!parport_negotiate(cam->port, mode)) {
- break;
- }
- mdelay(10);
- }
- if(retry == 4) {
- if(extensibility)
- DBG("Unable to negotiate upload extensibility mode\n");
- else
- DBG("Unable to negotiate upload mode\n");
- return -1;
- }
- if(extensibility) cam->port->ieee1284.mode = upload_mode;
- return 0;
-}
-
-/****************************************************************************
- *
- * WritePacket
- *
- ***************************************************************************/
-static int WritePacket(struct pp_cam_entry *cam, const u8 *packet, size_t size)
-{
- int retval=0;
- int size_written;
-
- if (packet == NULL) {
- return -EINVAL;
- }
- if (ForwardSetup(cam)) {
- DBG("Write failed in setup\n");
- return -EIO;
- }
- size_written = parport_write(cam->port, packet, size);
- if(size_written != size) {
- DBG("Write failed, wrote %d/%d\n", size_written, size);
- retval = -EIO;
- }
- EndTransferMode(cam);
- return retval;
-}
-
-/****************************************************************************
- *
- * ReadPacket
- *
- ***************************************************************************/
-static int ReadPacket(struct pp_cam_entry *cam, u8 *packet, size_t size)
-{
- int retval=0;
-
- if (packet == NULL) {
- return -EINVAL;
- }
- if (ReverseSetup(cam, 0)) {
- return -EIO;
- }
-
- /* support for CPiA variant nibble reads */
- if(cam->port->ieee1284.mode == IEEE1284_MODE_NIBBLE) {
- if(cpia_read_nibble(cam->port, packet, size, 0) != size)
- retval = -EIO;
- } else {
- if(parport_read(cam->port, packet, size) != size)
- retval = -EIO;
- }
- EndTransferMode(cam);
- return retval;
-}
-
-/****************************************************************************
- *
- * cpia_pp_streamStart
- *
- ***************************************************************************/
-static int cpia_pp_streamStart(void *privdata)
-{
- struct pp_cam_entry *cam = privdata;
- DBG("\n");
- cam->streaming=1;
- cam->image_ready=0;
- //if (ReverseSetup(cam,1)) return -EIO;
- if(cam->stream_irq) cpia_parport_enable_irq(cam->port);
- return 0;
-}
-
-/****************************************************************************
- *
- * cpia_pp_streamStop
- *
- ***************************************************************************/
-static int cpia_pp_streamStop(void *privdata)
-{
- struct pp_cam_entry *cam = privdata;
-
- DBG("\n");
- cam->streaming=0;
- cpia_parport_disable_irq(cam->port);
- //EndTransferMode(cam);
-
- return 0;
-}
-
-/****************************************************************************
- *
- * cpia_pp_streamRead
- *
- ***************************************************************************/
-static int cpia_pp_read(struct parport *port, u8 *buffer, int len)
-{
- int bytes_read;
-
- /* support for CPiA variant "nibble stream" reads */
- if(port->ieee1284.mode == IEEE1284_MODE_NIBBLE)
- bytes_read = cpia_read_nibble_stream(port,buffer,len,0);
- else {
- int new_bytes;
- for(bytes_read=0; bytes_read<len; bytes_read += new_bytes) {
- new_bytes = parport_read(port, buffer+bytes_read,
- len-bytes_read);
- if(new_bytes < 0) break;
- }
- }
- return bytes_read;
-}
-
-static int cpia_pp_streamRead(void *privdata, u8 *buffer, int noblock)
-{
- struct pp_cam_entry *cam = privdata;
- int read_bytes = 0;
- int i, endseen, block_size, new_bytes;
-
- if(cam == NULL) {
- DBG("Internal driver error: cam is NULL\n");
- return -EINVAL;
- }
- if(buffer == NULL) {
- DBG("Internal driver error: buffer is NULL\n");
- return -EINVAL;
- }
- //if(cam->streaming) DBG("%d / %d\n", cam->image_ready, noblock);
- if( cam->stream_irq ) {
- DBG("%d\n", cam->image_ready);
- cam->image_ready--;
- }
- cam->image_complete=0;
- if (0/*cam->streaming*/) {
- if(!cam->image_ready) {
- if(noblock) return -EWOULDBLOCK;
- interruptible_sleep_on(&cam->wq_stream);
- if( signal_pending(current) ) return -EINTR;
- DBG("%d\n", cam->image_ready);
- }
- } else {
- if (ReverseSetup(cam, 1)) {
- DBG("unable to ReverseSetup\n");
- return -EIO;
- }
- }
- endseen = 0;
- block_size = PARPORT_CHUNK_SIZE;
- while( !cam->image_complete ) {
- cond_resched();
-
- new_bytes = cpia_pp_read(cam->port, buffer, block_size );
- if( new_bytes <= 0 ) {
- break;
- }
- i=-1;
- while(++i<new_bytes && endseen<4) {
- if(*buffer==EOI) {
- endseen++;
- } else {
- endseen=0;
- }
- buffer++;
- }
- read_bytes += i;
- if( endseen==4 ) {
- cam->image_complete=1;
- break;
- }
- if( CPIA_MAX_IMAGE_SIZE-read_bytes <= PARPORT_CHUNK_SIZE ) {
- block_size=CPIA_MAX_IMAGE_SIZE-read_bytes;
- }
- }
- EndTransferMode(cam);
- return cam->image_complete ? read_bytes : -EIO;
-}
-/****************************************************************************
- *
- * cpia_pp_transferCmd
- *
- ***************************************************************************/
-static int cpia_pp_transferCmd(void *privdata, u8 *command, u8 *data)
-{
- int err;
- int retval=0;
- int databytes;
- struct pp_cam_entry *cam = privdata;
-
- if(cam == NULL) {
- DBG("Internal driver error: cam is NULL\n");
- return -EINVAL;
- }
- if(command == NULL) {
- DBG("Internal driver error: command is NULL\n");
- return -EINVAL;
- }
- databytes = (((int)command[7])<<8) | command[6];
- if ((err = WritePacket(cam, command, PACKET_LENGTH)) < 0) {
- DBG("Error writing command\n");
- return err;
- }
- if(command[0] == DATA_IN) {
- u8 buffer[8];
- if(data == NULL) {
- DBG("Internal driver error: data is NULL\n");
- return -EINVAL;
- }
- if((err = ReadPacket(cam, buffer, 8)) < 0) {
- DBG("Error reading command result\n");
- return err;
- }
- memcpy(data, buffer, databytes);
- } else if(command[0] == DATA_OUT) {
- if(databytes > 0) {
- if(data == NULL) {
- DBG("Internal driver error: data is NULL\n");
- retval = -EINVAL;
- } else {
- if((err=WritePacket(cam, data, databytes)) < 0){
- DBG("Error writing command data\n");
- return err;
- }
- }
- }
- } else {
- DBG("Unexpected first byte of command: %x\n", command[0]);
- retval = -EINVAL;
- }
- return retval;
-}
-
-/****************************************************************************
- *
- * cpia_pp_open
- *
- ***************************************************************************/
-static int cpia_pp_open(void *privdata)
-{
- struct pp_cam_entry *cam = (struct pp_cam_entry *)privdata;
-
- if (cam == NULL)
- return -EINVAL;
-
- if(cam->open_count == 0) {
- if (parport_claim(cam->pdev)) {
- DBG("failed to claim the port\n");
- return -EBUSY;
- }
- parport_negotiate(cam->port, IEEE1284_MODE_COMPAT);
- parport_data_forward(cam->port);
- parport_write_control(cam->port, PARPORT_CONTROL_SELECT);
- udelay(50);
- parport_write_control(cam->port,
- PARPORT_CONTROL_SELECT
- | PARPORT_CONTROL_INIT);
- }
-
- ++cam->open_count;
-
- return 0;
-}
-
-/****************************************************************************
- *
- * cpia_pp_registerCallback
- *
- ***************************************************************************/
-static int cpia_pp_registerCallback(void *privdata, void (*cb)(void *cbdata), void *cbdata)
-{
- struct pp_cam_entry *cam = privdata;
- int retval = 0;
-
- if(cam->port->irq != PARPORT_IRQ_NONE) {
- cam->cb_func = cb;
- cam->cb_data = cbdata;
- INIT_WORK(&cam->cb_task, cpia_pp_run_callback);
- } else {
- retval = -1;
- }
- return retval;
-}
-
-/****************************************************************************
- *
- * cpia_pp_close
- *
- ***************************************************************************/
-static int cpia_pp_close(void *privdata)
-{
- struct pp_cam_entry *cam = privdata;
- if (--cam->open_count == 0) {
- parport_release(cam->pdev);
- }
- return 0;
-}
-
-/****************************************************************************
- *
- * cpia_pp_register
- *
- ***************************************************************************/
-static int cpia_pp_register(struct parport *port)
-{
- struct pardevice *pdev = NULL;
- struct pp_cam_entry *cam;
- struct cam_data *cpia;
-
- if (!(port->modes & PARPORT_MODE_PCSPP)) {
- LOG("port is not supported by CPiA driver\n");
- return -ENXIO;
- }
-
- cam = kzalloc(sizeof(struct pp_cam_entry), GFP_KERNEL);
- if (cam == NULL) {
- LOG("failed to allocate camera structure\n");
- return -ENOMEM;
- }
-
- pdev = parport_register_device(port, "cpia_pp", NULL, NULL,
- NULL, 0, cam);
-
- if (!pdev) {
- LOG("failed to parport_register_device\n");
- kfree(cam);
- return -ENXIO;
- }
-
- cam->pdev = pdev;
- cam->port = port;
- init_waitqueue_head(&cam->wq_stream);
-
- cam->streaming = 0;
- cam->stream_irq = 0;
-
- if((cpia = cpia_register_camera(&cpia_pp_ops, cam)) == NULL) {
- LOG("failed to cpia_register_camera\n");
- parport_unregister_device(pdev);
- kfree(cam);
- return -ENXIO;
- }
- spin_lock( &cam_list_lock_pp );
- list_add( &cpia->cam_data_list, &cam_list );
- spin_unlock( &cam_list_lock_pp );
-
- return 0;
-}
-
-static void cpia_pp_detach (struct parport *port)
-{
- struct list_head *tmp;
- struct cam_data *cpia = NULL;
- struct pp_cam_entry *cam;
-
- spin_lock( &cam_list_lock_pp );
- list_for_each (tmp, &cam_list) {
- cpia = list_entry(tmp, struct cam_data, cam_data_list);
- cam = (struct pp_cam_entry *) cpia->lowlevel_data;
- if (cam && cam->port->number == port->number) {
- list_del(&cpia->cam_data_list);
- break;
- }
- cpia = NULL;
- }
- spin_unlock( &cam_list_lock_pp );
-
- if (!cpia) {
- DBG("cpia_pp_detach failed to find cam_data in cam_list\n");
- return;
- }
-
- cam = (struct pp_cam_entry *) cpia->lowlevel_data;
- cpia_unregister_camera(cpia);
- if(cam->open_count > 0)
- cpia_pp_close(cam);
- parport_unregister_device(cam->pdev);
- cpia->lowlevel_data = NULL;
- kfree(cam);
-}
-
-static void cpia_pp_attach (struct parport *port)
-{
- unsigned int i;
-
- switch (parport_nr[0])
- {
- case PPCPIA_PARPORT_UNSPEC:
- case PPCPIA_PARPORT_AUTO:
- if (port->probe_info[0].class != PARPORT_CLASS_MEDIA ||
- port->probe_info[0].cmdset == NULL ||
- strncmp(port->probe_info[0].cmdset, "CPIA_1", 6) != 0)
- return;
-
- cpia_pp_register(port);
-
- break;
-
- default:
- for (i = 0; i < PARPORT_MAX; ++i) {
- if (port->number == parport_nr[i]) {
- cpia_pp_register(port);
- break;
- }
- }
- break;
- }
-}
-
-static struct parport_driver cpia_pp_driver = {
- .name = "cpia_pp",
- .attach = cpia_pp_attach,
- .detach = cpia_pp_detach,
-};
-
-static int __init cpia_pp_init(void)
-{
- printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
- CPIA_PP_MAJ_VER,CPIA_PP_MIN_VER,CPIA_PP_PATCH_VER);
-
- if(parport_nr[0] == PPCPIA_PARPORT_OFF) {
- printk(" disabled\n");
- return 0;
- }
-
- spin_lock_init( &cam_list_lock_pp );
-
- if (parport_register_driver (&cpia_pp_driver)) {
- LOG ("unable to register with parport\n");
- return -EIO;
- }
- return 0;
-}
-
-static int __init cpia_init(void)
-{
- if (parport[0]) {
- /* The user gave some parameters. Let's see what they were. */
- if (!strncmp(parport[0], "auto", 4)) {
- parport_nr[0] = PPCPIA_PARPORT_AUTO;
- } else {
- int n;
- for (n = 0; n < PARPORT_MAX && parport[n]; n++) {
- if (!strncmp(parport[n], "none", 4)) {
- parport_nr[n] = PPCPIA_PARPORT_NONE;
- } else {
- char *ep;
- unsigned long r = simple_strtoul(parport[n], &ep, 0);
- if (ep != parport[n]) {
- parport_nr[n] = r;
- } else {
- LOG("bad port specifier `%s'\n", parport[n]);
- return -ENODEV;
- }
- }
- }
- }
- }
- return cpia_pp_init();
-}
-
-static void __exit cpia_cleanup(void)
-{
- parport_unregister_driver(&cpia_pp_driver);
- return;
-}
-
-module_init(cpia_init);
-module_exit(cpia_cleanup);
diff --git a/drivers/media/video/cpia_usb.c b/drivers/media/video/cpia_usb.c
deleted file mode 100644
index ef1f89399983..000000000000
--- a/drivers/media/video/cpia_usb.c
+++ /dev/null
@@ -1,643 +0,0 @@
-/*
- * cpia_usb CPiA USB driver
- *
- * Supports CPiA based parallel port Video Camera's.
- *
- * Copyright (C) 1999 Jochen Scharrlach <Jochen.Scharrlach@schwaben.de>
- * Copyright (C) 1999, 2000 Johannes Erdfelt <johannes@erdfelt.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-/* define _CPIA_DEBUG_ for verbose debug output (see cpia.h) */
-/* #define _CPIA_DEBUG_ 1 */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/wait.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/vmalloc.h>
-#include <linux/usb.h>
-
-#include "cpia.h"
-
-#define USB_REQ_CPIA_GRAB_FRAME 0xC1
-#define USB_REQ_CPIA_UPLOAD_FRAME 0xC2
-#define WAIT_FOR_NEXT_FRAME 0
-#define FORCE_FRAME_UPLOAD 1
-
-#define FRAMES_PER_DESC 10
-#define FRAME_SIZE_PER_DESC 960 /* Shouldn't be hardcoded */
-#define CPIA_NUMSBUF 2
-#define STREAM_BUF_SIZE (PAGE_SIZE * 4)
-#define SCRATCH_BUF_SIZE (STREAM_BUF_SIZE * 2)
-
-struct cpia_sbuf {
- char *data;
- struct urb *urb;
-};
-
-#define FRAMEBUF_LEN (CPIA_MAX_FRAME_SIZE+100)
-enum framebuf_status {
- FRAME_EMPTY,
- FRAME_READING,
- FRAME_READY,
- FRAME_ERROR,
-};
-
-struct framebuf {
- int length;
- enum framebuf_status status;
- u8 data[FRAMEBUF_LEN];
- struct framebuf *next;
-};
-
-struct usb_cpia {
- /* Device structure */
- struct usb_device *dev;
-
- unsigned char iface;
- wait_queue_head_t wq_stream;
-
- int cursbuf; /* Current receiving sbuf */
- struct cpia_sbuf sbuf[CPIA_NUMSBUF]; /* Double buffering */
-
- int streaming;
- int open;
- int present;
- struct framebuf *buffers[3];
- struct framebuf *curbuff, *workbuff;
-};
-
-static int cpia_usb_open(void *privdata);
-static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
- void *cbdata);
-static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data);
-static int cpia_usb_streamStart(void *privdata);
-static int cpia_usb_streamStop(void *privdata);
-static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock);
-static int cpia_usb_close(void *privdata);
-
-#define ABOUT "USB driver for Vision CPiA based cameras"
-
-static struct cpia_camera_ops cpia_usb_ops = {
- cpia_usb_open,
- cpia_usb_registerCallback,
- cpia_usb_transferCmd,
- cpia_usb_streamStart,
- cpia_usb_streamStop,
- cpia_usb_streamRead,
- cpia_usb_close,
- 0,
- THIS_MODULE
-};
-
-static LIST_HEAD(cam_list);
-static spinlock_t cam_list_lock_usb;
-
-static void cpia_usb_complete(struct urb *urb)
-{
- int i;
- char *cdata;
- struct usb_cpia *ucpia;
-
- if (!urb || !urb->context)
- return;
-
- ucpia = (struct usb_cpia *) urb->context;
-
- if (!ucpia->dev || !ucpia->streaming || !ucpia->present || !ucpia->open)
- return;
-
- if (ucpia->workbuff->status == FRAME_EMPTY) {
- ucpia->workbuff->status = FRAME_READING;
- ucpia->workbuff->length = 0;
- }
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
-
- cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- if (st)
- printk(KERN_DEBUG "cpia data error: [%d] len=%d, status=%X\n", i, n, st);
-
- if (FRAMEBUF_LEN < ucpia->workbuff->length + n) {
- printk(KERN_DEBUG "cpia: scratch buf overflow!scr_len: %d, n: %d\n", ucpia->workbuff->length, n);
- return;
- }
-
- if (n) {
- if ((ucpia->workbuff->length > 0) ||
- (0x19 == cdata[0] && 0x68 == cdata[1])) {
- memcpy(ucpia->workbuff->data + ucpia->workbuff->length, cdata, n);
- ucpia->workbuff->length += n;
- } else
- DBG("Ignoring packet!\n");
- } else {
- if (ucpia->workbuff->length > 4 &&
- 0xff == ucpia->workbuff->data[ucpia->workbuff->length-1] &&
- 0xff == ucpia->workbuff->data[ucpia->workbuff->length-2] &&
- 0xff == ucpia->workbuff->data[ucpia->workbuff->length-3] &&
- 0xff == ucpia->workbuff->data[ucpia->workbuff->length-4]) {
- ucpia->workbuff->status = FRAME_READY;
- ucpia->curbuff = ucpia->workbuff;
- ucpia->workbuff = ucpia->workbuff->next;
- ucpia->workbuff->status = FRAME_EMPTY;
- ucpia->workbuff->length = 0;
-
- if (waitqueue_active(&ucpia->wq_stream))
- wake_up_interruptible(&ucpia->wq_stream);
- }
- }
- }
-
- /* resubmit */
- urb->dev = ucpia->dev;
- if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
- printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __func__, i);
-}
-
-static int cpia_usb_open(void *privdata)
-{
- struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
- struct urb *urb;
- int ret, retval = 0, fx, err;
-
- if (!ucpia)
- return -EINVAL;
-
- ucpia->sbuf[0].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!ucpia->sbuf[0].data)
- return -EINVAL;
-
- ucpia->sbuf[1].data = kmalloc(FRAMES_PER_DESC * FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!ucpia->sbuf[1].data) {
- retval = -EINVAL;
- goto error_0;
- }
-
- ret = usb_set_interface(ucpia->dev, ucpia->iface, 3);
- if (ret < 0) {
- printk(KERN_ERR "cpia_usb_open: usb_set_interface error (ret = %d)\n", ret);
- retval = -EBUSY;
- goto error_1;
- }
-
- ucpia->buffers[0]->status = FRAME_EMPTY;
- ucpia->buffers[0]->length = 0;
- ucpia->buffers[1]->status = FRAME_EMPTY;
- ucpia->buffers[1]->length = 0;
- ucpia->buffers[2]->status = FRAME_EMPTY;
- ucpia->buffers[2]->length = 0;
- ucpia->curbuff = ucpia->buffers[0];
- ucpia->workbuff = ucpia->buffers[1];
-
- /* We double buffer the Iso lists, and also know the polling
- * interval is every frame (1 == (1 << (bInterval -1))).
- */
- urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 0\n");
- retval = -ENOMEM;
- goto error_1;
- }
-
- ucpia->sbuf[0].urb = urb;
- urb->dev = ucpia->dev;
- urb->context = ucpia;
- urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = ucpia->sbuf[0].data;
- urb->complete = cpia_usb_complete;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->interval = 1;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
-
- urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if (!urb) {
- printk(KERN_ERR "cpia_init_isoc: usb_alloc_urb 1\n");
- retval = -ENOMEM;
- goto error_urb0;
- }
-
- ucpia->sbuf[1].urb = urb;
- urb->dev = ucpia->dev;
- urb->context = ucpia;
- urb->pipe = usb_rcvisocpipe(ucpia->dev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = ucpia->sbuf[1].data;
- urb->complete = cpia_usb_complete;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->interval = 1;
- urb->transfer_buffer_length = FRAME_SIZE_PER_DESC * FRAMES_PER_DESC;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = FRAME_SIZE_PER_DESC * fx;
- urb->iso_frame_desc[fx].length = FRAME_SIZE_PER_DESC;
- }
-
- /* queue the ISO urbs, and resubmit in the completion handler */
- err = usb_submit_urb(ucpia->sbuf[0].urb, GFP_KERNEL);
- if (err) {
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 0 ret %d\n",
- err);
- goto error_urb1;
- }
- err = usb_submit_urb(ucpia->sbuf[1].urb, GFP_KERNEL);
- if (err) {
- printk(KERN_ERR "cpia_init_isoc: usb_submit_urb 1 ret %d\n",
- err);
- goto error_urb1;
- }
-
- ucpia->streaming = 1;
- ucpia->open = 1;
-
- return 0;
-
-error_urb1: /* free urb 1 */
- usb_free_urb(ucpia->sbuf[1].urb);
- ucpia->sbuf[1].urb = NULL;
-error_urb0: /* free urb 0 */
- usb_free_urb(ucpia->sbuf[0].urb);
- ucpia->sbuf[0].urb = NULL;
-error_1:
- kfree (ucpia->sbuf[1].data);
- ucpia->sbuf[1].data = NULL;
-error_0:
- kfree (ucpia->sbuf[0].data);
- ucpia->sbuf[0].data = NULL;
-
- return retval;
-}
-
-//
-// convenience functions
-//
-
-/****************************************************************************
- *
- * WritePacket
- *
- ***************************************************************************/
-static int WritePacket(struct usb_device *udev, const u8 *packet, u8 *buf, size_t size)
-{
- if (!packet)
- return -EINVAL;
-
- return usb_control_msg(udev, usb_sndctrlpipe(udev, 0),
- packet[1] + (packet[0] << 8),
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- packet[2] + (packet[3] << 8),
- packet[4] + (packet[5] << 8), buf, size, 1000);
-}
-
-/****************************************************************************
- *
- * ReadPacket
- *
- ***************************************************************************/
-static int ReadPacket(struct usb_device *udev, u8 *packet, u8 *buf, size_t size)
-{
- if (!packet || size <= 0)
- return -EINVAL;
-
- return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0),
- packet[1] + (packet[0] << 8),
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- packet[2] + (packet[3] << 8),
- packet[4] + (packet[5] << 8), buf, size, 1000);
-}
-
-static int cpia_usb_transferCmd(void *privdata, u8 *command, u8 *data)
-{
- int err = 0;
- int databytes;
- struct usb_cpia *ucpia = (struct usb_cpia *)privdata;
- struct usb_device *udev = ucpia->dev;
-
- if (!udev) {
- DBG("Internal driver error: udev is NULL\n");
- return -EINVAL;
- }
-
- if (!command) {
- DBG("Internal driver error: command is NULL\n");
- return -EINVAL;
- }
-
- databytes = (((int)command[7])<<8) | command[6];
-
- if (command[0] == DATA_IN) {
- u8 buffer[8];
-
- if (!data) {
- DBG("Internal driver error: data is NULL\n");
- return -EINVAL;
- }
-
- err = ReadPacket(udev, command, buffer, 8);
- if (err < 0)
- return err;
-
- memcpy(data, buffer, databytes);
- } else if(command[0] == DATA_OUT)
- WritePacket(udev, command, data, databytes);
- else {
- DBG("Unexpected first byte of command: %x\n", command[0]);
- err = -EINVAL;
- }
-
- return 0;
-}
-
-static int cpia_usb_registerCallback(void *privdata, void (*cb) (void *cbdata),
- void *cbdata)
-{
- return -ENODEV;
-}
-
-static int cpia_usb_streamStart(void *privdata)
-{
- return -ENODEV;
-}
-
-static int cpia_usb_streamStop(void *privdata)
-{
- return -ENODEV;
-}
-
-static int cpia_usb_streamRead(void *privdata, u8 *frame, int noblock)
-{
- struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
- struct framebuf *mybuff;
-
- if (!ucpia || !ucpia->present)
- return -1;
-
- if (ucpia->curbuff->status != FRAME_READY)
- interruptible_sleep_on(&ucpia->wq_stream);
- else
- DBG("Frame already waiting!\n");
-
- mybuff = ucpia->curbuff;
-
- if (!mybuff)
- return -1;
-
- if (mybuff->status != FRAME_READY || mybuff->length < 4) {
- DBG("Something went wrong!\n");
- return -1;
- }
-
- memcpy(frame, mybuff->data, mybuff->length);
- mybuff->status = FRAME_EMPTY;
-
-/* DBG("read done, %d bytes, Header: %x/%x, Footer: %x%x%x%x\n", */
-/* mybuff->length, frame[0], frame[1], */
-/* frame[mybuff->length-4], frame[mybuff->length-3], */
-/* frame[mybuff->length-2], frame[mybuff->length-1]); */
-
- return mybuff->length;
-}
-
-static void cpia_usb_free_resources(struct usb_cpia *ucpia, int try)
-{
- if (!ucpia->streaming)
- return;
-
- ucpia->streaming = 0;
-
- /* Set packet size to 0 */
- if (try) {
- int ret;
-
- ret = usb_set_interface(ucpia->dev, ucpia->iface, 0);
- if (ret < 0) {
- printk(KERN_ERR "usb_set_interface error (ret = %d)\n", ret);
- return;
- }
- }
-
- /* Unschedule all of the iso td's */
- if (ucpia->sbuf[1].urb) {
- usb_kill_urb(ucpia->sbuf[1].urb);
- usb_free_urb(ucpia->sbuf[1].urb);
- ucpia->sbuf[1].urb = NULL;
- }
-
- kfree(ucpia->sbuf[1].data);
- ucpia->sbuf[1].data = NULL;
-
- if (ucpia->sbuf[0].urb) {
- usb_kill_urb(ucpia->sbuf[0].urb);
- usb_free_urb(ucpia->sbuf[0].urb);
- ucpia->sbuf[0].urb = NULL;
- }
-
- kfree(ucpia->sbuf[0].data);
- ucpia->sbuf[0].data = NULL;
-}
-
-static int cpia_usb_close(void *privdata)
-{
- struct usb_cpia *ucpia = (struct usb_cpia *) privdata;
-
- if(!ucpia)
- return -ENODEV;
-
- ucpia->open = 0;
-
- /* ucpia->present = 0 protects against trying to reset the
- * alt setting if camera is physically disconnected while open */
- cpia_usb_free_resources(ucpia, ucpia->present);
-
- return 0;
-}
-
-/* Probing and initializing */
-
-static int cpia_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct usb_host_interface *interface;
- struct usb_cpia *ucpia;
- struct cam_data *cam;
- int ret;
-
- /* A multi-config CPiA camera? */
- if (udev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- interface = intf->cur_altsetting;
-
- printk(KERN_INFO "USB CPiA camera found\n");
-
- ucpia = kzalloc(sizeof(*ucpia), GFP_KERNEL);
- if (!ucpia) {
- printk(KERN_ERR "couldn't kmalloc cpia struct\n");
- return -ENOMEM;
- }
-
- ucpia->dev = udev;
- ucpia->iface = interface->desc.bInterfaceNumber;
- init_waitqueue_head(&ucpia->wq_stream);
-
- ucpia->buffers[0] = vmalloc(sizeof(*ucpia->buffers[0]));
- if (!ucpia->buffers[0]) {
- printk(KERN_ERR "couldn't vmalloc frame buffer 0\n");
- goto fail_alloc_0;
- }
-
- ucpia->buffers[1] = vmalloc(sizeof(*ucpia->buffers[1]));
- if (!ucpia->buffers[1]) {
- printk(KERN_ERR "couldn't vmalloc frame buffer 1\n");
- goto fail_alloc_1;
- }
-
- ucpia->buffers[2] = vmalloc(sizeof(*ucpia->buffers[2]));
- if (!ucpia->buffers[2]) {
- printk(KERN_ERR "couldn't vmalloc frame buffer 2\n");
- goto fail_alloc_2;
- }
-
- ucpia->buffers[0]->next = ucpia->buffers[1];
- ucpia->buffers[1]->next = ucpia->buffers[2];
- ucpia->buffers[2]->next = ucpia->buffers[0];
-
- ret = usb_set_interface(udev, ucpia->iface, 0);
- if (ret < 0) {
- printk(KERN_ERR "cpia_probe: usb_set_interface error (ret = %d)\n", ret);
- /* goto fail_all; */
- }
-
- /* Before register_camera, important */
- ucpia->present = 1;
-
- cam = cpia_register_camera(&cpia_usb_ops, ucpia);
- if (!cam) {
- LOG("failed to cpia_register_camera\n");
- goto fail_all;
- }
-
- spin_lock( &cam_list_lock_usb );
- list_add( &cam->cam_data_list, &cam_list );
- spin_unlock( &cam_list_lock_usb );
-
- usb_set_intfdata(intf, cam);
- return 0;
-
-fail_all:
- vfree(ucpia->buffers[2]);
- ucpia->buffers[2] = NULL;
-fail_alloc_2:
- vfree(ucpia->buffers[1]);
- ucpia->buffers[1] = NULL;
-fail_alloc_1:
- vfree(ucpia->buffers[0]);
- ucpia->buffers[0] = NULL;
-fail_alloc_0:
- kfree(ucpia);
- return -EIO;
-}
-
-static void cpia_disconnect(struct usb_interface *intf);
-
-static struct usb_device_id cpia_id_table [] = {
- { USB_DEVICE(0x0553, 0x0002) },
- { USB_DEVICE(0x0813, 0x0001) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, cpia_id_table);
-MODULE_LICENSE("GPL");
-
-
-static struct usb_driver cpia_driver = {
- .name = "cpia",
- .probe = cpia_probe,
- .disconnect = cpia_disconnect,
- .id_table = cpia_id_table,
-};
-
-static void cpia_disconnect(struct usb_interface *intf)
-{
- struct cam_data *cam = usb_get_intfdata(intf);
- struct usb_cpia *ucpia;
- struct usb_device *udev;
-
- usb_set_intfdata(intf, NULL);
- if (!cam)
- return;
-
- ucpia = (struct usb_cpia *) cam->lowlevel_data;
- spin_lock( &cam_list_lock_usb );
- list_del(&cam->cam_data_list);
- spin_unlock( &cam_list_lock_usb );
-
- ucpia->present = 0;
-
- cpia_unregister_camera(cam);
- if(ucpia->open)
- cpia_usb_close(cam->lowlevel_data);
-
- ucpia->curbuff->status = FRAME_ERROR;
-
- if (waitqueue_active(&ucpia->wq_stream))
- wake_up_interruptible(&ucpia->wq_stream);
-
- udev = interface_to_usbdev(intf);
-
- ucpia->curbuff = ucpia->workbuff = NULL;
-
- vfree(ucpia->buffers[2]);
- ucpia->buffers[2] = NULL;
-
- vfree(ucpia->buffers[1]);
- ucpia->buffers[1] = NULL;
-
- vfree(ucpia->buffers[0]);
- ucpia->buffers[0] = NULL;
-
- cam->lowlevel_data = NULL;
- kfree(ucpia);
-}
-
-static int __init usb_cpia_init(void)
-{
- printk(KERN_INFO "%s v%d.%d.%d\n",ABOUT,
- CPIA_USB_MAJ_VER,CPIA_USB_MIN_VER,CPIA_USB_PATCH_VER);
-
- spin_lock_init(&cam_list_lock_usb);
- return usb_register(&cpia_driver);
-}
-
-static void __exit usb_cpia_cleanup(void)
-{
- usb_deregister(&cpia_driver);
-}
-
-
-module_init (usb_cpia_init);
-module_exit (usb_cpia_cleanup);
-
diff --git a/drivers/media/video/cs5345.c b/drivers/media/video/cs5345.c
index 8362db509e2c..9358fe77e562 100644
--- a/drivers/media/video/cs5345.c
+++ b/drivers/media/video/cs5345.c
@@ -25,7 +25,6 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("i2c device driver for cs5345 Audio ADC");
MODULE_AUTHOR("Hans Verkuil");
@@ -209,9 +208,25 @@ static const struct i2c_device_id cs5345_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cs5345_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "cs5345",
- .probe = cs5345_probe,
- .remove = cs5345_remove,
- .id_table = cs5345_id,
+static struct i2c_driver cs5345_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cs5345",
+ },
+ .probe = cs5345_probe,
+ .remove = cs5345_remove,
+ .id_table = cs5345_id,
};
+
+static __init int init_cs5345(void)
+{
+ return i2c_add_driver(&cs5345_driver);
+}
+
+static __exit void exit_cs5345(void)
+{
+ i2c_del_driver(&cs5345_driver);
+}
+
+module_init(init_cs5345);
+module_exit(exit_cs5345);
diff --git a/drivers/media/video/cs53l32a.c b/drivers/media/video/cs53l32a.c
index 3cc135a98d82..d93e5ab45fd3 100644
--- a/drivers/media/video/cs53l32a.c
+++ b/drivers/media/video/cs53l32a.c
@@ -26,11 +26,10 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("i2c device driver for cs53l32a Audio ADC");
MODULE_AUTHOR("Martin Vaughan");
@@ -43,6 +42,21 @@ module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debugging messages, 0=Off (default), 1=On");
+struct cs53l32a_state {
+ struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+};
+
+static inline struct cs53l32a_state *to_state(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct cs53l32a_state, sd);
+}
+
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct cs53l32a_state, hdl)->sd;
+}
+
/* ----------------------------------------------------------------------- */
static int cs53l32a_write(struct v4l2_subdev *sd, u8 reg, u8 value)
@@ -74,31 +88,20 @@ static int cs53l32a_s_routing(struct v4l2_subdev *sd,
return 0;
}
-static int cs53l32a_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int cs53l32a_s_ctrl(struct v4l2_ctrl *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;
-}
+ struct v4l2_subdev *sd = to_sd(ctrl);
-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);
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ cs53l32a_write(sd, 0x03, ctrl->val ? 0xf0 : 0x30);
+ return 0;
+ case V4L2_CID_AUDIO_VOLUME:
+ cs53l32a_write(sd, 0x04, (u8)ctrl->val);
+ cs53l32a_write(sd, 0x05, (u8)ctrl->val);
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;
+ return -EINVAL;
}
static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
@@ -111,23 +114,30 @@ static int cs53l32a_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_id
static int cs53l32a_log_status(struct v4l2_subdev *sd)
{
+ struct cs53l32a_state *state = to_state(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);
+ v4l2_info(sd, "Input: %d\n", (v >> 4) & 3);
+ v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
return 0;
}
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops cs53l32a_ctrl_ops = {
+ .s_ctrl = cs53l32a_s_ctrl,
+};
+
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,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
};
static const struct v4l2_subdev_audio_ops cs53l32a_audio_ops = {
@@ -151,6 +161,7 @@ static const struct v4l2_subdev_ops cs53l32a_ops = {
static int cs53l32a_probe(struct i2c_client *client,
const struct i2c_device_id *id)
{
+ struct cs53l32a_state *state;
struct v4l2_subdev *sd;
int i;
@@ -164,9 +175,10 @@ 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)
+ state = kzalloc(sizeof(struct cs53l32a_state), GFP_KERNEL);
+ if (state == NULL)
return -ENOMEM;
+ sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &cs53l32a_ops);
for (i = 1; i <= 7; i++) {
@@ -175,15 +187,29 @@ static int cs53l32a_probe(struct i2c_client *client,
v4l2_dbg(1, debug, sd, "Read Reg %d %02x\n", i, v);
}
+ v4l2_ctrl_handler_init(&state->hdl, 2);
+ v4l2_ctrl_new_std(&state->hdl, &cs53l32a_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, -96, 12, 1, 0);
+ v4l2_ctrl_new_std(&state->hdl, &cs53l32a_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ sd->ctrl_handler = &state->hdl;
+ if (state->hdl.error) {
+ int err = state->hdl.error;
+
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return err;
+ }
+
/* Set cs53l32a internal register for Adaptec 2010/2410 setup */
- 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);
+ cs53l32a_write(sd, 0x01, 0x21);
+ cs53l32a_write(sd, 0x02, 0x29);
+ cs53l32a_write(sd, 0x03, 0x30);
+ cs53l32a_write(sd, 0x04, 0x00);
+ cs53l32a_write(sd, 0x05, 0x00);
+ cs53l32a_write(sd, 0x06, 0x00);
+ cs53l32a_write(sd, 0x07, 0x00);
/* Display results, should be 0x21,0x29,0x30,0x00,0x00,0x00,0x00 */
@@ -198,9 +224,11 @@ static int cs53l32a_probe(struct i2c_client *client,
static int cs53l32a_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct cs53l32a_state *state = to_state(sd);
v4l2_device_unregister_subdev(sd);
- kfree(sd);
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
return 0;
}
@@ -210,9 +238,25 @@ static const struct i2c_device_id cs53l32a_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cs53l32a_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "cs53l32a",
- .remove = cs53l32a_remove,
- .probe = cs53l32a_probe,
- .id_table = cs53l32a_id,
+static struct i2c_driver cs53l32a_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cs53l32a",
+ },
+ .probe = cs53l32a_probe,
+ .remove = cs53l32a_remove,
+ .id_table = cs53l32a_id,
};
+
+static __init int init_cs53l32a(void)
+{
+ return i2c_add_driver(&cs53l32a_driver);
+}
+
+static __exit void exit_cs53l32a(void)
+{
+ i2c_del_driver(&cs53l32a_driver);
+}
+
+module_init(init_cs53l32a);
+module_exit(exit_cs53l32a);
diff --git a/drivers/media/video/cx18/Kconfig b/drivers/media/video/cx18/Kconfig
index baf7e91ee0f5..d9d2f6ad6ffb 100644
--- a/drivers/media/video/cx18/Kconfig
+++ b/drivers/media/video/cx18/Kconfig
@@ -1,9 +1,8 @@
config VIDEO_CX18
tristate "Conexant cx23418 MPEG encoder support"
depends on VIDEO_V4L2 && DVB_CORE && PCI && I2C && EXPERIMENTAL
- depends on INPUT # due to VIDEO_IR
select I2C_ALGOBIT
- select VIDEO_IR
+ depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_CX2341X
diff --git a/drivers/media/video/cx18/cx18-alsa-main.c b/drivers/media/video/cx18/cx18-alsa-main.c
index b5d7cbf4528a..d50d69da387b 100644
--- a/drivers/media/video/cx18/cx18-alsa-main.c
+++ b/drivers/media/video/cx18/cx18-alsa-main.c
@@ -1,7 +1,7 @@
/*
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
* Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
*
* Portions of this work were sponsored by ONELAN Limited.
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.c b/drivers/media/video/cx18/cx18-alsa-mixer.c
index ef21114309fe..341bddc00b77 100644
--- a/drivers/media/video/cx18/cx18-alsa-mixer.c
+++ b/drivers/media/video/cx18/cx18-alsa-mixer.c
@@ -2,7 +2,7 @@
* ALSA mixer controls for the
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-alsa-mixer.h b/drivers/media/video/cx18/cx18-alsa-mixer.h
index 2d418db000fe..ec9238793f6f 100644
--- a/drivers/media/video/cx18/cx18-alsa-mixer.h
+++ b/drivers/media/video/cx18/cx18-alsa-mixer.h
@@ -2,7 +2,7 @@
* ALSA mixer controls for the
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.c b/drivers/media/video/cx18/cx18-alsa-pcm.c
index 2bd312daeb1e..82d195be9197 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.c
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.c
@@ -2,7 +2,7 @@
* ALSA PCM device for the
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
* Copyright (C) 2009 Devin Heitmueller <dheitmueller@kernellabs.com>
*
* Portions of this work were sponsored by ONELAN Limited.
@@ -218,7 +218,13 @@ static int snd_cx18_pcm_capture_close(struct snd_pcm_substream *substream)
static int snd_cx18_pcm_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg)
{
- return snd_pcm_lib_ioctl(substream, cmd, arg);
+ struct snd_cx18_card *cxsc = snd_pcm_substream_chip(substream);
+ int ret;
+
+ snd_cx18_lock(cxsc);
+ ret = snd_pcm_lib_ioctl(substream, cmd, arg);
+ snd_cx18_unlock(cxsc);
+ return ret;
}
diff --git a/drivers/media/video/cx18/cx18-alsa-pcm.h b/drivers/media/video/cx18/cx18-alsa-pcm.h
index 325662c647a0..d26e51f94577 100644
--- a/drivers/media/video/cx18/cx18-alsa-pcm.h
+++ b/drivers/media/video/cx18/cx18-alsa-pcm.h
@@ -2,7 +2,7 @@
* ALSA PCM device for the
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-alsa.h b/drivers/media/video/cx18/cx18-alsa.h
index 88a1cde7540b..447da374c9e8 100644
--- a/drivers/media/video/cx18/cx18-alsa.h
+++ b/drivers/media/video/cx18/cx18-alsa.h
@@ -1,7 +1,7 @@
/*
* ALSA interface to cx18 PCM capture streams
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-av-audio.c b/drivers/media/video/cx18/cx18-av-audio.c
index 9e30983f2ff6..43d09a24b262 100644
--- a/drivers/media/video/cx18/cx18-av-audio.c
+++ b/drivers/media/video/cx18/cx18-av-audio.c
@@ -4,7 +4,7 @@
* Derived from cx25840-audio.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx18/cx18-av-core.c b/drivers/media/video/cx18/cx18-av-core.c
index 0e5006b14279..a41951cab276 100644
--- a/drivers/media/video/cx18/cx18-av-core.c
+++ b/drivers/media/video/cx18/cx18-av-core.c
@@ -4,7 +4,7 @@
* Derived from cx25840-core.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -1021,86 +1021,74 @@ static int cx18_av_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
return -EINVAL;
}
-static int cx18_av_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- return cx18_av_g_sliced_fmt(sd, &fmt->fmt.sliced);
-}
-
-static int cx18_av_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int cx18_av_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
struct cx18_av_state *state = to_cx18_av_state(sd);
struct cx18 *cx = 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);
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- pix = &(fmt->fmt.pix);
+ if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
- Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
- Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
- Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
- Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
+ Vsrc = (cx18_av_read(cx, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx18_av_read(cx, 0x475) & 0xf0) >> 4;
- /*
- * This adjustment reflects the excess of vactive, set in
- * cx18_av_std_setup(), above standard values:
- *
- * 480 + 1 for 60 Hz systems
- * 576 + 3 for 50 Hz systems
- */
- Vlines = pix->height + (is_50Hz ? 3 : 1);
-
- /*
- * Invalid height and width scaling requests are:
- * 1. width less than 1/16 of the source width
- * 2. width greater than the source width
- * 3. height less than 1/8 of the source height
- * 4. height greater than the source height
- */
- if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
- (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
- CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
- pix->width, pix->height);
- return -ERANGE;
- }
+ Hsrc = (cx18_av_read(cx, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx18_av_read(cx, 0x471) & 0xf0) >> 4;
- HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
- VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
- VSC &= 0x1fff;
+ /*
+ * This adjustment reflects the excess of vactive, set in
+ * cx18_av_std_setup(), above standard values:
+ *
+ * 480 + 1 for 60 Hz systems
+ * 576 + 3 for 50 Hz systems
+ */
+ Vlines = fmt->height + (is_50Hz ? 3 : 1);
- if (pix->width >= 385)
- filter = 0;
- else if (pix->width > 192)
- filter = 1;
- else if (pix->width > 96)
- filter = 2;
- else
- filter = 3;
+ /*
+ * Invalid height and width scaling requests are:
+ * 1. width less than 1/16 of the source width
+ * 2. width greater than the source width
+ * 3. height less than 1/8 of the source height
+ * 4. height greater than the source height
+ */
+ if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ CX18_ERR_DEV(sd, "%dx%d is not a valid size!\n",
+ fmt->width, fmt->height);
+ return -ERANGE;
+ }
- CX18_DEBUG_INFO_DEV(sd,
- "decoder set size %dx%d -> scale %ux%u\n",
- pix->width, pix->height, HSC, VSC);
-
- /* HSCALE=HSC */
- cx18_av_write(cx, 0x418, HSC & 0xff);
- cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
- cx18_av_write(cx, 0x41a, HSC >> 16);
- /* VSCALE=VSC */
- cx18_av_write(cx, 0x41c, VSC & 0xff);
- cx18_av_write(cx, 0x41d, VSC >> 8);
- /* VS_INTRLACE=1 VFILT=filter */
- cx18_av_write(cx, 0x41e, 0x8 | filter);
- break;
+ HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
- default:
- return -EINVAL;
- }
+ if (fmt->width >= 385)
+ filter = 0;
+ else if (fmt->width > 192)
+ filter = 1;
+ else if (fmt->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ CX18_DEBUG_INFO_DEV(sd,
+ "decoder set size %dx%d -> scale %ux%u\n",
+ fmt->width, fmt->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx18_av_write(cx, 0x418, HSC & 0xff);
+ cx18_av_write(cx, 0x419, (HSC >> 8) & 0xff);
+ cx18_av_write(cx, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx18_av_write(cx, 0x41c, VSC & 0xff);
+ cx18_av_write(cx, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx18_av_write(cx, 0x41e, 0x8 | filter);
return 0;
}
@@ -1398,8 +1386,7 @@ static const struct v4l2_subdev_audio_ops cx18_av_audio_ops = {
static const struct v4l2_subdev_video_ops cx18_av_video_ops = {
.s_routing = cx18_av_s_video_routing,
.s_stream = cx18_av_s_stream,
- .g_fmt = cx18_av_g_fmt,
- .s_fmt = cx18_av_s_fmt,
+ .s_mbus_fmt = cx18_av_s_mbus_fmt,
};
static const struct v4l2_subdev_vbi_ops cx18_av_vbi_ops = {
diff --git a/drivers/media/video/cx18/cx18-av-core.h b/drivers/media/video/cx18/cx18-av-core.h
index c106967bdcc3..1956991795e3 100644
--- a/drivers/media/video/cx18/cx18-av-core.h
+++ b/drivers/media/video/cx18/cx18-av-core.h
@@ -4,7 +4,7 @@
* Derived from cx25840-core.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx18/cx18-av-firmware.c b/drivers/media/video/cx18/cx18-av-firmware.c
index b9e8cc5d264a..280aa4d22488 100644
--- a/drivers/media/video/cx18/cx18-av-firmware.c
+++ b/drivers/media/video/cx18/cx18-av-firmware.c
@@ -2,7 +2,7 @@
* cx18 ADEC firmware functions
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx18/cx18-cards.c b/drivers/media/video/cx18/cx18-cards.c
index 74e122b5fc49..87177733cf92 100644
--- a/drivers/media/video/cx18/cx18-cards.c
+++ b/drivers/media/video/cx18/cx18-cards.c
@@ -4,7 +4,7 @@
* Derived from ivtv-cards.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -39,7 +39,7 @@ static struct cx18_card_tuner_i2c cx18_i2c_std = {
.tv = { 0x61, 0x60, I2C_CLIENT_END },
};
-/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
New vendor IDs should still be added to the vendor ID list. */
@@ -251,6 +251,66 @@ static const struct cx18_card cx18_card_mpc718 = {
/* ------------------------------------------------------------------------- */
+/* GoTView PCI */
+
+static const struct cx18_card_pci_info cx18_pci_gotview_dvd3[] = {
+ { PCI_DEVICE_ID_CX23418, CX18_PCI_ID_GOTVIEW, 0x3343 },
+ { 0, 0, 0 }
+};
+
+static const struct cx18_card cx18_card_gotview_dvd3 = {
+ .type = CX18_CARD_GOTVIEW_PCI_DVD3,
+ .name = "GoTView PCI DVD3 Hybrid",
+ .comment = "Experimenters needed for device to work well.\n"
+ "\tTo help, mail the ivtv-devel list (www.ivtvdriver.org).\n",
+ .v4l2_capabilities = CX18_CAP_ENCODER,
+ .hw_audio_ctrl = CX18_HW_418_AV,
+ .hw_muxer = CX18_HW_GPIO_MUX,
+ .hw_all = CX18_HW_TVEEPROM | CX18_HW_418_AV | CX18_HW_TUNER |
+ CX18_HW_GPIO_MUX | CX18_HW_DVB | CX18_HW_GPIO_RESET_CTRL,
+ .video_inputs = {
+ { CX18_CARD_INPUT_VID_TUNER, 0, CX18_AV_COMPOSITE2 },
+ { CX18_CARD_INPUT_SVIDEO1, 1,
+ CX18_AV_SVIDEO_LUMA3 | CX18_AV_SVIDEO_CHROMA4 },
+ { CX18_CARD_INPUT_COMPOSITE1, 1, CX18_AV_COMPOSITE1 },
+ { CX18_CARD_INPUT_SVIDEO2, 2,
+ CX18_AV_SVIDEO_LUMA7 | CX18_AV_SVIDEO_CHROMA8 },
+ { CX18_CARD_INPUT_COMPOSITE2, 2, CX18_AV_COMPOSITE6 },
+ },
+ .audio_inputs = {
+ { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 0 },
+ { CX18_CARD_INPUT_LINE_IN1, CX18_AV_AUDIO_SERIAL1, 1 },
+ { CX18_CARD_INPUT_LINE_IN2, CX18_AV_AUDIO_SERIAL2, 1 },
+ },
+ .tuners = {
+ /* XC3028 tuner */
+ { .std = V4L2_STD_ALL, .tuner = TUNER_XC2028 },
+ },
+ /* FIXME - the FM radio is just a guess and driver doesn't use SIF */
+ .radio_input = { CX18_CARD_INPUT_AUD_TUNER, CX18_AV_AUDIO5, 2 },
+ .ddr = {
+ /* Hynix HY5DU283222B DDR RAM */
+ .chip_config = 0x303,
+ .refresh = 0x3bd,
+ .timing1 = 0x36320966,
+ .timing2 = 0x1f,
+ .tune_lane = 0,
+ .initial_emrs = 2,
+ },
+ .gpio_init.initial_value = 0x1,
+ .gpio_init.direction = 0x3,
+
+ .gpio_audio_input = { .mask = 0x3,
+ .tuner = 0x1,
+ .linein = 0x2,
+ .radio = 0x1 },
+ .xceive_pin = 0,
+ .pci_list = cx18_pci_gotview_dvd3,
+ .i2c = &cx18_i2c_std,
+};
+
+/* ------------------------------------------------------------------------- */
+
/* Conexant Raptor PAL/SECAM: note that this card is analog only! */
static const struct cx18_card_pci_info cx18_pci_cnxt_raptor_pal[] = {
@@ -463,6 +523,7 @@ static const struct cx18_card *cx18_card_list[] = {
&cx18_card_toshiba_qosmio_dvbt,
&cx18_card_leadtek_pvr2100,
&cx18_card_leadtek_dvr3100h,
+ &cx18_card_gotview_dvd3
};
const struct cx18_card *cx18_get_card(u16 index)
@@ -485,7 +546,6 @@ int cx18_get_input(struct cx18 *cx, u16 index, struct v4l2_input *input)
"Component 1"
};
- memset(input, 0, sizeof(*input));
if (index >= cx->nof_inputs)
return -EINVAL;
input->index = index;
diff --git a/drivers/media/video/cx18/cx18-cards.h b/drivers/media/video/cx18/cx18-cards.h
index 796e517300ac..3e750068f275 100644
--- a/drivers/media/video/cx18/cx18-cards.h
+++ b/drivers/media/video/cx18/cx18-cards.h
@@ -4,7 +4,7 @@
* Derived from ivtv-cards.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-controls.c b/drivers/media/video/cx18/cx18-controls.c
index 4b4b46544d5a..97d7b7e100a3 100644
--- a/drivers/media/video/cx18/cx18-controls.c
+++ b/drivers/media/video/cx18/cx18-controls.c
@@ -108,7 +108,7 @@ static int cx18_try_ctrl(struct file *file, void *fh,
struct v4l2_ext_control *vctrl)
{
struct v4l2_queryctrl qctrl;
- const char **menu_items = NULL;
+ const char * const *menu_items = NULL;
int err;
qctrl.id = vctrl->id;
@@ -297,14 +297,13 @@ int cx18_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
if (p.video_encoding != cx->params.video_encoding) {
int is_mpeg1 = p.video_encoding ==
V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- struct v4l2_format fmt;
+ struct v4l2_mbus_framefmt fmt;
/* fix videodecoder resolution */
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = cx->params.width
- / (is_mpeg1 ? 2 : 1);
- fmt.fmt.pix.height = cx->params.height;
- v4l2_subdev_call(cx->sd_av, video, s_fmt, &fmt);
+ fmt.width = cx->params.width / (is_mpeg1 ? 2 : 1);
+ fmt.height = cx->params.height;
+ fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &fmt);
}
priv.cx = cx;
priv.s = &cx->streams[id->type];
diff --git a/drivers/media/video/cx18/cx18-driver.c b/drivers/media/video/cx18/cx18-driver.c
index c95a86ba33b0..944af8adbe0c 100644
--- a/drivers/media/video/cx18/cx18-driver.c
+++ b/drivers/media/video/cx18/cx18-driver.c
@@ -4,7 +4,7 @@
* Derived from ivtv-driver.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -156,6 +156,7 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t 6 = Toshiba Qosmio DVB-T/Analog\n"
"\t\t\t 7 = Leadtek WinFast PVR2100\n"
"\t\t\t 8 = Leadtek WinFast DVR3100 H\n"
+ "\t\t\t 9 = GoTView PCI DVD3 Hybrid\n"
"\t\t\t 0 = Autodetect (default)\n"
"\t\t\t-1 = Ignore this card\n\t\t");
MODULE_PARM_DESC(pal, "Set PAL standard: B, G, H, D, K, I, M, N, Nc, 60");
@@ -266,8 +267,14 @@ static void request_modules(struct cx18 *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct cx18 *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
/* Generic utility functions */
@@ -333,6 +340,7 @@ void cx18_read_eeprom(struct cx18 *cx, struct tveeprom *tv)
tveeprom_hauppauge_analog(&c, tv, eedata);
break;
case CX18_CARD_YUAN_MPC718:
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
tv->model = 0x718;
cx18_eeprom_dump(cx, eedata, sizeof(eedata));
CX18_INFO("eeprom PCI ID: %02x%02x:%02x%02x\n",
@@ -656,7 +664,7 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx)
{
snprintf(cx->in_workq_name, sizeof(cx->in_workq_name), "%s-in",
cx->v4l2_dev.name);
- cx->in_work_queue = create_singlethread_workqueue(cx->in_workq_name);
+ cx->in_work_queue = alloc_ordered_workqueue(cx->in_workq_name, 0);
if (cx->in_work_queue == NULL) {
CX18_ERR("Unable to create incoming mailbox handler thread\n");
return -ENOMEM;
@@ -664,18 +672,6 @@ static int __devinit cx18_create_in_workq(struct cx18 *cx)
return 0;
}
-static int __devinit cx18_create_out_workq(struct cx18 *cx)
-{
- snprintf(cx->out_workq_name, sizeof(cx->out_workq_name), "%s-out",
- cx->v4l2_dev.name);
- cx->out_work_queue = create_workqueue(cx->out_workq_name);
- if (cx->out_work_queue == NULL) {
- CX18_ERR("Unable to create outgoing mailbox handler threads\n");
- return -ENOMEM;
- }
- return 0;
-}
-
static void __devinit cx18_init_in_work_orders(struct cx18 *cx)
{
int i;
@@ -702,15 +698,9 @@ static int __devinit cx18_init_struct1(struct cx18 *cx)
mutex_init(&cx->epu2apu_mb_lock);
mutex_init(&cx->epu2cpu_mb_lock);
- ret = cx18_create_out_workq(cx);
- if (ret)
- return ret;
-
ret = cx18_create_in_workq(cx);
- if (ret) {
- destroy_workqueue(cx->out_work_queue);
+ if (ret)
return ret;
- }
cx18_init_in_work_orders(cx);
@@ -923,8 +913,13 @@ static int __devinit cx18_probe(struct pci_dev *pci_dev,
cx->enc_mem = ioremap_nocache(cx->base_addr + CX18_MEM_OFFSET,
CX18_MEM_SIZE);
if (!cx->enc_mem) {
- CX18_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- CX18_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ CX18_ERR("ioremap failed. Can't get a window into CX23418 "
+ "memory and register space\n");
+ CX18_ERR("Each capture card with a CX23418 needs 64 MB of "
+ "vmalloc address space for the window\n");
+ CX18_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+ CX18_ERR("Use the vmalloc= kernel command line option to set "
+ "VmallocTotal to a larger value\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1094,7 +1089,6 @@ free_mem:
release_mem_region(cx->base_addr, CX18_MEM_SIZE);
free_workqueues:
destroy_workqueue(cx->in_work_queue);
- destroy_workqueue(cx->out_work_queue);
err:
if (retval == 0)
retval = -ENODEV;
@@ -1226,6 +1220,8 @@ static void cx18_remove(struct pci_dev *pci_dev)
CX18_DEBUG_INFO("Removing Card\n");
+ flush_request_modules(cx);
+
/* Stop all captures */
CX18_DEBUG_INFO("Stopping all streams\n");
if (atomic_read(&cx->tot_capturing) > 0)
@@ -1244,7 +1240,6 @@ static void cx18_remove(struct pci_dev *pci_dev)
cx18_halt_firmware(cx);
destroy_workqueue(cx->in_work_queue);
- destroy_workqueue(cx->out_work_queue);
cx18_streams_cleanup(cx, 1);
diff --git a/drivers/media/video/cx18/cx18-driver.h b/drivers/media/video/cx18/cx18-driver.h
index b9728e8eee40..306caac6d3fc 100644
--- a/drivers/media/video/cx18/cx18-driver.h
+++ b/drivers/media/video/cx18/cx18-driver.h
@@ -4,7 +4,7 @@
* Derived from ivtv-driver.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -84,7 +84,8 @@
#define CX18_CARD_TOSHIBA_QOSMIO_DVBT 5 /* Toshiba Qosmio Interal DVB-T/Analog*/
#define CX18_CARD_LEADTEK_PVR2100 6 /* Leadtek WinFast PVR2100 */
#define CX18_CARD_LEADTEK_DVR3100H 7 /* Leadtek WinFast DVR3100 H */
-#define CX18_CARD_LAST 7
+#define CX18_CARD_GOTVIEW_PCI_DVD3 8 /* GoTView PCI DVD3 Hybrid */
+#define CX18_CARD_LAST 8
#define CX18_ENC_STREAM_TYPE_MPG 0
#define CX18_ENC_STREAM_TYPE_TS 1
@@ -106,6 +107,7 @@
#define CX18_PCI_ID_CONEXANT 0x14f1
#define CX18_PCI_ID_TOSHIBA 0x1179
#define CX18_PCI_ID_LEADTEK 0x107D
+#define CX18_PCI_ID_GOTVIEW 0x5854
/* ======================================================================== */
/* ========================== START USER SETTABLE DMA VARIABLES =========== */
@@ -323,7 +325,10 @@ struct cx18_queue {
spinlock_t lock;
};
+struct cx18_stream; /* forward reference */
+
struct cx18_dvb {
+ struct cx18_stream *stream;
struct dmx_frontend hw_frontend;
struct dmx_frontend mem_frontend;
struct dmxdev dmxdev;
@@ -363,9 +368,10 @@ struct cx18_in_work_order {
#define CX18_INVALID_TASK_HANDLE 0xffffffff
struct cx18_stream {
- /* These first four fields are always set, even if the stream
+ /* These first five fields are always set, even if the stream
is not actually created. */
struct video_device *video_dev; /* NULL when stream not created */
+ struct cx18_dvb *dvb; /* DVB / Digital Transport */
struct cx18 *cx; /* for ease of use */
const char *name; /* name of the stream */
int type; /* stream type */
@@ -395,9 +401,6 @@ struct cx18_stream {
struct cx18_queue q_idle; /* idle - not in rotation */
struct work_struct out_work_order;
-
- /* DVB / Digital Transport */
- struct cx18_dvb dvb;
};
struct cx18_open_id {
@@ -614,9 +617,6 @@ struct cx18 {
struct cx18_in_work_order in_work_order[CX18_MAX_IN_WORK_ORDERS];
char epu_debug_str[256]; /* CX18_EPU_DEBUG is rare: use shared space */
- struct workqueue_struct *out_work_queue;
- char out_workq_name[12]; /* "cx18-NN-out" */
-
/* i2c */
struct i2c_adapter i2c_adap[2];
struct i2c_algo_bit_data i2c_algo[2];
@@ -674,18 +674,25 @@ static inline int cx18_raw_vbi(const struct cx18 *cx)
/* Call the specified callback for all subdevs with a grp_id bit matching the
* mask in hw (if 0, then match them all). Ignore any errors. */
-#define cx18_call_hw(cx, hw, o, f, args...) \
- __v4l2_device_call_subdevs(&(cx)->v4l2_dev, \
- !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+#define cx18_call_hw(cx, hw, o, f, args...) \
+ do { \
+ struct v4l2_subdev *__sd; \
+ __v4l2_device_call_subdevs_p(&(cx)->v4l2_dev, __sd, \
+ !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \
+ } while (0)
#define cx18_call_all(cx, o, f, args...) cx18_call_hw(cx, 0, o, f , ##args)
/* Call the specified callback for all subdevs with a grp_id bit matching the
* mask in 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 cx18_call_hw_err(cx, hw, o, f, args...) \
- __v4l2_device_call_subdevs_until_err( \
- &(cx)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+#define cx18_call_hw_err(cx, hw, o, f, args...) \
+({ \
+ struct v4l2_subdev *__sd; \
+ __v4l2_device_call_subdevs_until_err_p(&(cx)->v4l2_dev, \
+ __sd, !(hw) || (__sd->grp_id & (hw)), o, f, \
+ ##args); \
+})
#define cx18_call_all_err(cx, o, f, args...) \
cx18_call_hw_err(cx, 0, o, f , ##args)
diff --git a/drivers/media/video/cx18/cx18-dvb.c b/drivers/media/video/cx18/cx18-dvb.c
index 0ae2c2e1eab5..f0381d62518d 100644
--- a/drivers/media/video/cx18/cx18-dvb.c
+++ b/drivers/media/video/cx18/cx18-dvb.c
@@ -2,7 +2,7 @@
* cx18 functions for DVB support
*
* Copyright (c) 2008 Steven Toth <stoth@linuxtv.org>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -137,7 +137,7 @@ static int yuan_mpc718_mt352_init(struct dvb_frontend *fe)
{
struct cx18_dvb *dvb = container_of(fe->dvb,
struct cx18_dvb, dvb_adapter);
- struct cx18_stream *stream = container_of(dvb, struct cx18_stream, dvb);
+ struct cx18_stream *stream = dvb->stream;
const struct firmware *fw = NULL;
int ret;
int i;
@@ -203,6 +203,14 @@ static struct zl10353_config yuan_mpc718_zl10353_demod = {
.disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
};
+static struct zl10353_config gotview_dvd3_zl10353_demod = {
+ .demod_address = 0x1e >> 1, /* Datasheet suggested straps */
+ .if2 = 45600, /* 4.560 MHz IF from the XC3028 */
+ .parallel_ts = 1, /* Not a serial TS */
+ .no_tuner = 1, /* XC3028 is not behind the gate */
+ .disable_i2c_gate_ctrl = 1, /* Disable the I2C gate */
+};
+
static int dvb_register(struct cx18_stream *stream);
/* Kernel DVB framework calls this when the feed needs to start.
@@ -247,6 +255,7 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
case CX18_CARD_LEADTEK_DVR3100H:
case CX18_CARD_YUAN_MPC718:
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
default:
/* Assumption - Parallel transport - Signalling
* undefined or default.
@@ -257,22 +266,22 @@ static int cx18_dvb_start_feed(struct dvb_demux_feed *feed)
if (!demux->dmx.frontend)
return -EINVAL;
- mutex_lock(&stream->dvb.feedlock);
- if (stream->dvb.feeding++ == 0) {
+ mutex_lock(&stream->dvb->feedlock);
+ if (stream->dvb->feeding++ == 0) {
CX18_DEBUG_INFO("Starting Transport DMA\n");
mutex_lock(&cx->serialize_lock);
set_bit(CX18_F_S_STREAMING, &stream->s_flags);
ret = cx18_start_v4l2_encode_stream(stream);
if (ret < 0) {
CX18_DEBUG_INFO("Failed to start Transport DMA\n");
- stream->dvb.feeding--;
- if (stream->dvb.feeding == 0)
+ stream->dvb->feeding--;
+ if (stream->dvb->feeding == 0)
clear_bit(CX18_F_S_STREAMING, &stream->s_flags);
}
mutex_unlock(&cx->serialize_lock);
} else
ret = 0;
- mutex_unlock(&stream->dvb.feedlock);
+ mutex_unlock(&stream->dvb->feedlock);
return ret;
}
@@ -290,15 +299,15 @@ static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
CX18_DEBUG_INFO("Stop feed: pid = 0x%x index = %d\n",
feed->pid, feed->index);
- mutex_lock(&stream->dvb.feedlock);
- if (--stream->dvb.feeding == 0) {
+ mutex_lock(&stream->dvb->feedlock);
+ if (--stream->dvb->feeding == 0) {
CX18_DEBUG_INFO("Stopping Transport DMA\n");
mutex_lock(&cx->serialize_lock);
ret = cx18_stop_v4l2_encode_stream(stream, 0);
mutex_unlock(&cx->serialize_lock);
} else
ret = 0;
- mutex_unlock(&stream->dvb.feedlock);
+ mutex_unlock(&stream->dvb->feedlock);
}
return ret;
@@ -307,7 +316,7 @@ static int cx18_dvb_stop_feed(struct dvb_demux_feed *feed)
int cx18_dvb_register(struct cx18_stream *stream)
{
struct cx18 *cx = stream->cx;
- struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18_dvb *dvb = stream->dvb;
struct dvb_adapter *dvb_adapter;
struct dvb_demux *dvbdemux;
struct dmx_demux *dmx;
@@ -316,6 +325,9 @@ int cx18_dvb_register(struct cx18_stream *stream)
if (!dvb)
return -EINVAL;
+ dvb->enabled = 0;
+ dvb->stream = stream;
+
ret = dvb_register_adapter(&dvb->dvb_adapter,
CX18_DRIVER_NAME,
THIS_MODULE, &cx->pci_dev->dev, adapter_nr);
@@ -369,7 +381,7 @@ int cx18_dvb_register(struct cx18_stream *stream)
CX18_INFO("DVB Frontend registered\n");
CX18_INFO("Registered DVB adapter%d for %s (%d x %d.%02d kB)\n",
- stream->dvb.dvb_adapter.num, stream->name,
+ stream->dvb->dvb_adapter.num, stream->name,
stream->buffers, stream->buf_size/1024,
(stream->buf_size * 100 / 1024) % 100);
@@ -396,13 +408,16 @@ err_out:
void cx18_dvb_unregister(struct cx18_stream *stream)
{
struct cx18 *cx = stream->cx;
- struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18_dvb *dvb = stream->dvb;
struct dvb_adapter *dvb_adapter;
struct dvb_demux *dvbdemux;
struct dmx_demux *dmx;
CX18_INFO("unregister DVB\n");
+ if (dvb == NULL || !dvb->enabled)
+ return;
+
dvb_adapter = &dvb->dvb_adapter;
dvbdemux = &dvb->demux;
dmx = &dvbdemux->dmx;
@@ -423,7 +438,7 @@ void cx18_dvb_unregister(struct cx18_stream *stream)
*/
static int dvb_register(struct cx18_stream *stream)
{
- struct cx18_dvb *dvb = &stream->dvb;
+ struct cx18_dvb *dvb = stream->dvb;
struct cx18 *cx = stream->cx;
int ret = 0;
@@ -495,6 +510,29 @@ static int dvb_register(struct cx18_stream *stream)
fe->ops.tuner_ops.set_config(fe, &ctrl);
}
break;
+ case CX18_CARD_GOTVIEW_PCI_DVD3:
+ dvb->fe = dvb_attach(zl10353_attach,
+ &gotview_dvd3_zl10353_demod,
+ &cx->i2c_adap[1]);
+ if (dvb->fe != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &cx->i2c_adap[1],
+ .i2c_addr = 0xc2 >> 1,
+ .ctrl = NULL,
+ };
+ static struct xc2028_ctrl ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_ZARLINK456,
+ .type = XC2028_AUTO,
+ };
+
+ fe = dvb_attach(xc2028_attach, dvb->fe, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctrl);
+ }
+ break;
default:
/* No Digital Tv Support */
break;
diff --git a/drivers/media/video/cx18/cx18-fileops.c b/drivers/media/video/cx18/cx18-fileops.c
index e12a15020cda..9f23b90732f2 100644
--- a/drivers/media/video/cx18/cx18-fileops.c
+++ b/drivers/media/video/cx18/cx18-fileops.c
@@ -4,7 +4,7 @@
* Derived from ivtv-fileops.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-firmware.c b/drivers/media/video/cx18/cx18-firmware.c
index 83cd559cc609..1b3fb502e6be 100644
--- a/drivers/media/video/cx18/cx18-firmware.c
+++ b/drivers/media/video/cx18/cx18-firmware.c
@@ -2,7 +2,7 @@
* cx18 firmware functions
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-gpio.c b/drivers/media/video/cx18/cx18-gpio.c
index 86a204b5448e..5374aeb0cd22 100644
--- a/drivers/media/video/cx18/cx18-gpio.c
+++ b/drivers/media/video/cx18/cx18-gpio.c
@@ -4,7 +4,7 @@
* Derived from ivtv-gpio.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-gpio.h b/drivers/media/video/cx18/cx18-gpio.h
index f9a5ca3566af..4aea2ef88e8d 100644
--- a/drivers/media/video/cx18/cx18-gpio.h
+++ b/drivers/media/video/cx18/cx18-gpio.h
@@ -4,7 +4,7 @@
* Derived from ivtv-gpio.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-i2c.c b/drivers/media/video/cx18/cx18-i2c.c
index cfa1f289b0f5..c330fb917b50 100644
--- a/drivers/media/video/cx18/cx18-i2c.c
+++ b/drivers/media/video/cx18/cx18-i2c.c
@@ -4,7 +4,7 @@
* Derived from ivtv-i2c.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -71,19 +71,6 @@ static const u8 hw_bus[] = {
};
/* This array should match the CX18_HW_ defines */
-static const char * const hw_modules[] = {
- "tuner", /* CX18_HW_TUNER */
- NULL, /* CX18_HW_TVEEPROM */
- "cs5345", /* CX18_HW_CS5345 */
- NULL, /* CX18_HW_DVB */
- NULL, /* CX18_HW_418_AV */
- NULL, /* CX18_HW_GPIO_MUX */
- NULL, /* CX18_HW_GPIO_RESET_CTRL */
- NULL, /* CX18_HW_Z8F0811_IR_TX_HAUP */
- NULL, /* CX18_HW_Z8F0811_IR_RX_HAUP */
-};
-
-/* This array should match the CX18_HW_ defines */
static const char * const hw_devicenames[] = {
"tuner",
"tveeprom",
@@ -111,13 +98,14 @@ static int cx18_i2c_new_ir(struct cx18 *cx, struct i2c_adapter *adap, u32 hw,
case CX18_HW_Z8F0811_IR_RX_HAUP:
init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = IR_TYPE_RC5;
+ init_data->type = RC_TYPE_RC5;
init_data->name = cx->card_name;
info.platform_data = init_data;
break;
}
- return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+ return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
+ -1 : 0;
}
int cx18_i2c_register(struct cx18 *cx, unsigned idx)
@@ -125,7 +113,6 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
struct v4l2_subdev *sd;
int bus = hw_bus[idx];
struct i2c_adapter *adap = &cx->i2c_adap[bus];
- const char *mod = hw_modules[idx];
const char *type = hw_devicenames[idx];
u32 hw = 1 << idx;
@@ -135,15 +122,15 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
if (hw == CX18_HW_TUNER) {
/* special tuner group handling */
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->radio);
+ adap, type, 0, cx->card_i2c->radio);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->demod);
+ adap, type, 0, cx->card_i2c->demod);
if (sd != NULL)
sd->grp_id = hw;
sd = v4l2_i2c_new_subdev(&cx->v4l2_dev,
- adap, mod, type, 0, cx->card_i2c->tv);
+ adap, type, 0, cx->card_i2c->tv);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
@@ -157,7 +144,8 @@ int cx18_i2c_register(struct cx18 *cx, unsigned idx)
return -1;
/* It's an I2C device other than an analog tuner or IR chip */
- sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, mod, type, hw_addrs[idx], NULL);
+ sd = v4l2_i2c_new_subdev(&cx->v4l2_dev, adap, type, hw_addrs[idx],
+ NULL);
if (sd != NULL)
sd->grp_id = hw;
return sd != NULL ? 0 : -1;
diff --git a/drivers/media/video/cx18/cx18-io.c b/drivers/media/video/cx18/cx18-io.c
index ec5b3d7bcc6b..49b9dbd06248 100644
--- a/drivers/media/video/cx18/cx18-io.c
+++ b/drivers/media/video/cx18/cx18-io.c
@@ -2,7 +2,7 @@
* cx18 driver PCI memory mapped IO access routines
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-io.h b/drivers/media/video/cx18/cx18-io.h
index 2635b3a8cc96..18974d886cf7 100644
--- a/drivers/media/video/cx18/cx18-io.h
+++ b/drivers/media/video/cx18/cx18-io.h
@@ -2,7 +2,7 @@
* cx18 driver PCI memory mapped IO access routines
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -28,7 +28,7 @@
/*
* Readback and retry of MMIO access for reliability:
* The concept was suggested by Steve Toth <stoth@linuxtv.org>.
- * The implmentation is the fault of Andy Walls <awalls@radix.net>.
+ * The implmentation is the fault of Andy Walls <awalls@md.metrocast.net>.
*
* *write* functions are implied to retry the mmio unless suffixed with _noretry
* *read* functions never retry the mmio (it never helps to do so)
diff --git a/drivers/media/video/cx18/cx18-ioctl.c b/drivers/media/video/cx18/cx18-ioctl.c
index 2530fc54daaf..7150195740dc 100644
--- a/drivers/media/video/cx18/cx18-ioctl.c
+++ b/drivers/media/video/cx18/cx18-ioctl.c
@@ -4,7 +4,7 @@
* Derived from ivtv-ioctl.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -40,7 +40,6 @@
#include "cx18-av-core.h"
#include <media/tveeprom.h>
#include <media/v4l2-chip-ident.h>
-#include <linux/i2c-id.h>
u16 cx18_service2vbi(int type)
{
@@ -274,6 +273,7 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
{
struct cx18_open_id *id = fh;
struct cx18 *cx = id->cx;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret;
int w, h;
@@ -293,9 +293,10 @@ static int cx18_s_fmt_vid_cap(struct file *file, void *fh,
if (atomic_read(&cx->ana_capturing) > 0)
return -EBUSY;
- cx->params.width = w;
- cx->params.height = h;
- v4l2_subdev_call(cx->sd_av, video, s_fmt, fmt);
+ mbus_fmt.width = cx->params.width = w;
+ mbus_fmt.height = cx->params.height = h;
+ mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(cx->sd_av, video, s_mbus_fmt, &mbus_fmt);
return cx18_g_fmt_vid_cap(file, fh, fmt);
}
@@ -1079,7 +1080,7 @@ 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_open_id *id = filp->private_data;
struct cx18 *cx = id->cx;
long res;
diff --git a/drivers/media/video/cx18/cx18-ioctl.h b/drivers/media/video/cx18/cx18-ioctl.h
index e2ca0d152116..dcb2559ad520 100644
--- a/drivers/media/video/cx18/cx18-ioctl.h
+++ b/drivers/media/video/cx18/cx18-ioctl.h
@@ -4,7 +4,7 @@
* Derived from ivtv-ioctl.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-irq.c b/drivers/media/video/cx18/cx18-irq.c
index af2f504eda2b..80edfe93a3d8 100644
--- a/drivers/media/video/cx18/cx18-irq.c
+++ b/drivers/media/video/cx18/cx18-irq.c
@@ -2,7 +2,7 @@
* cx18 interrupt handling
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-irq.h b/drivers/media/video/cx18/cx18-irq.h
index 91f0b5278ef9..30e7eaf8cb55 100644
--- a/drivers/media/video/cx18/cx18-irq.h
+++ b/drivers/media/video/cx18/cx18-irq.h
@@ -2,7 +2,7 @@
* cx18 interrupt handling
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-mailbox.c b/drivers/media/video/cx18/cx18-mailbox.c
index 6dcce297752f..c545f3beef78 100644
--- a/drivers/media/video/cx18/cx18-mailbox.c
+++ b/drivers/media/video/cx18/cx18-mailbox.c
@@ -2,7 +2,7 @@
* cx18 mailbox functions
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -136,7 +136,7 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
{
struct cx18_buffer *buf;
- if (!s->dvb.enabled || mdl->bytesused == 0)
+ if (s->dvb == NULL || !s->dvb->enabled || mdl->bytesused == 0)
return;
/* We ignore mdl and buf readpos accounting here - it doesn't matter */
@@ -146,7 +146,7 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
buf = list_first_entry(&mdl->buf_list, struct cx18_buffer,
list);
if (buf->bytesused)
- dvb_dmx_swfilter(&s->dvb.demux,
+ dvb_dmx_swfilter(&s->dvb->demux,
buf->buf, buf->bytesused);
return;
}
@@ -154,7 +154,7 @@ static void cx18_mdl_send_to_dvb(struct cx18_stream *s, struct cx18_mdl *mdl)
list_for_each_entry(buf, &mdl->buf_list, list) {
if (buf->bytesused == 0)
break;
- dvb_dmx_swfilter(&s->dvb.demux, buf->buf, buf->bytesused);
+ dvb_dmx_swfilter(&s->dvb->demux, buf->buf, buf->bytesused);
}
}
diff --git a/drivers/media/video/cx18/cx18-mailbox.h b/drivers/media/video/cx18/cx18-mailbox.h
index 33a3491c4537..077952fcbcca 100644
--- a/drivers/media/video/cx18/cx18-mailbox.h
+++ b/drivers/media/video/cx18/cx18-mailbox.h
@@ -2,7 +2,7 @@
* cx18 mailbox functions
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-queue.c b/drivers/media/video/cx18/cx18-queue.c
index aefc8c8cf3c1..8884537bd62f 100644
--- a/drivers/media/video/cx18/cx18-queue.c
+++ b/drivers/media/video/cx18/cx18-queue.c
@@ -4,7 +4,7 @@
* Derived from ivtv-queue.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-queue.h b/drivers/media/video/cx18/cx18-queue.h
index 88a6d34ad3bb..4201ddc16091 100644
--- a/drivers/media/video/cx18/cx18-queue.h
+++ b/drivers/media/video/cx18/cx18-queue.h
@@ -4,7 +4,7 @@
* Derived from ivtv-queue.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-scb.c b/drivers/media/video/cx18/cx18-scb.c
index 34b4d03c55cd..85cc59637e54 100644
--- a/drivers/media/video/cx18/cx18-scb.c
+++ b/drivers/media/video/cx18/cx18-scb.c
@@ -2,7 +2,7 @@
* cx18 System Control Block initialization
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-scb.h b/drivers/media/video/cx18/cx18-scb.h
index 368f23d08709..08877652e321 100644
--- a/drivers/media/video/cx18/cx18-scb.h
+++ b/drivers/media/video/cx18/cx18-scb.h
@@ -2,7 +2,7 @@
* cx18 System Control Block initialization
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx18/cx18-streams.c b/drivers/media/video/cx18/cx18-streams.c
index f5c91261b2db..94f5d7967c5c 100644
--- a/drivers/media/video/cx18/cx18-streams.c
+++ b/drivers/media/video/cx18/cx18-streams.c
@@ -4,7 +4,7 @@
* Derived from ivtv-streams.c
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -41,7 +41,7 @@ static struct v4l2_file_operations cx18_v4l2_enc_fops = {
.read = cx18_v4l2_read,
.open = cx18_v4l2_open,
/* FIXME change to video_ioctl2 if serialization lock can be removed */
- .ioctl = cx18_v4l2_ioctl,
+ .unlocked_ioctl = cx18_v4l2_ioctl,
.release = cx18_v4l2_close,
.poll = cx18_v4l2_enc_poll,
};
@@ -107,6 +107,7 @@ static void cx18_stream_init(struct cx18 *cx, int type)
s->video_dev = video_dev;
/* initialize cx18_stream fields */
+ s->dvb = NULL;
s->cx = cx;
s->type = type;
s->name = cx18_stream_info[type].name;
@@ -140,10 +141,15 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
int num_offset = cx18_stream_info[type].num_offset;
int num = cx->instance + cx18_first_minor + num_offset;
- /* These four fields are always initialized. If video_dev == NULL, then
- this stream is not in use. In that case no other fields but these
- four can be used. */
+ /*
+ * These five fields are always initialized.
+ * For analog capture related streams, if video_dev == NULL then the
+ * stream is not in use.
+ * For the TS stream, if dvb == NULL then the stream is not in use.
+ * In those cases no other fields but these four can be used.
+ */
s->video_dev = NULL;
+ s->dvb = NULL;
s->cx = cx;
s->type = type;
s->name = cx18_stream_info[type].name;
@@ -167,6 +173,21 @@ static int cx18_prep_dev(struct cx18 *cx, int type)
cx18_stream_init(cx, type);
+ /* Allocate the cx18_dvb struct only for the TS on cards with DTV */
+ if (type == CX18_ENC_STREAM_TYPE_TS) {
+ if (cx->card->hw_all & CX18_HW_DVB) {
+ s->dvb = kzalloc(sizeof(struct cx18_dvb), GFP_KERNEL);
+ if (s->dvb == NULL) {
+ CX18_ERR("Couldn't allocate cx18_dvb structure"
+ " for %s\n", s->name);
+ return -ENOMEM;
+ }
+ } else {
+ /* Don't need buffers for the TS, if there is no DVB */
+ s->buffers = 0;
+ }
+ }
+
if (num_offset == -1)
return 0;
@@ -222,13 +243,7 @@ static int cx18_reg_dev(struct cx18 *cx, int type)
const char *name;
int num, ret;
- /* TODO: Shouldn't this be a VFL_TYPE_TRANSPORT or something?
- * We need a VFL_TYPE_TS defined.
- */
- if (strcmp("TS", s->name) == 0) {
- /* just return if no DVB is supported */
- if ((cx->card->hw_all & CX18_HW_DVB) == 0)
- return 0;
+ if (type == CX18_ENC_STREAM_TYPE_TS && s->dvb != NULL) {
ret = cx18_dvb_register(s);
if (ret < 0) {
CX18_ERR("DVB failed to register\n");
@@ -320,11 +335,13 @@ void cx18_streams_cleanup(struct cx18 *cx, int unregister)
/* Teardown all streams */
for (type = 0; type < CX18_MAX_STREAMS; type++) {
- /* No struct video_device, but can have buffers allocated */
+ /* The TS has a cx18_dvb structure, not a video_device */
if (type == CX18_ENC_STREAM_TYPE_TS) {
- if (cx->streams[type].dvb.enabled) {
- cx18_dvb_unregister(&cx->streams[type]);
- cx->streams[type].dvb.enabled = false;
+ if (cx->streams[type].dvb != NULL) {
+ if (unregister)
+ cx18_dvb_unregister(&cx->streams[type]);
+ kfree(cx->streams[type].dvb);
+ cx->streams[type].dvb = NULL;
cx18_stream_free(&cx->streams[type]);
}
continue;
diff --git a/drivers/media/video/cx18/cx18-streams.h b/drivers/media/video/cx18/cx18-streams.h
index 0bff0fa29763..713b0e61536d 100644
--- a/drivers/media/video/cx18/cx18-streams.h
+++ b/drivers/media/video/cx18/cx18-streams.h
@@ -4,7 +4,7 @@
* Derived from ivtv-streams.h
*
* Copyright (C) 2007 Hans Verkuil <hverkuil@xs4all.nl>
- * Copyright (C) 2008 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2008 Andy Walls <awalls@md.metrocast.net>
*
* 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
@@ -33,7 +33,8 @@ void cx18_stream_rotate_idx_mdls(struct cx18 *cx);
static inline bool cx18_stream_enabled(struct cx18_stream *s)
{
- return s->video_dev || s->dvb.enabled ||
+ return s->video_dev ||
+ (s->dvb && s->dvb->enabled) ||
(s->type == CX18_ENC_STREAM_TYPE_IDX &&
s->cx->stream_buffers[CX18_ENC_STREAM_TYPE_IDX] != 0);
}
@@ -41,8 +42,7 @@ static inline bool cx18_stream_enabled(struct cx18_stream *s)
/* Related to submission of mdls to firmware */
static inline void cx18_stream_load_fw_queue(struct cx18_stream *s)
{
- struct cx18 *cx = s->cx;
- queue_work(cx->out_work_queue, &s->out_work_order);
+ schedule_work(&s->out_work_order);
}
static inline void cx18_stream_put_mdl_fw(struct cx18_stream *s,
diff --git a/drivers/media/video/cx18/cx23418.h b/drivers/media/video/cx18/cx23418.h
index 2c00980acfcb..7e40035028d2 100644
--- a/drivers/media/video/cx18/cx23418.h
+++ b/drivers/media/video/cx18/cx23418.h
@@ -177,7 +177,7 @@
IN[0] - Task handle.
IN[1] - luma type: 0 = disable, 1 = 1D horizontal only, 2 = 1D vertical only,
3 = 2D H/V separable, 4 = 2D symmetric non-separable
- IN[2] - chroma type: 0 - diable, 1 = 1D horizontal
+ IN[2] - chroma type: 0 - disable, 1 = 1D horizontal
ReturnCode - One of the ERR_CAPTURE_... */
#define CX18_CPU_SET_SPATIAL_FILTER_TYPE (CPU_CMD_MASK_CAPTURE | 0x000C)
diff --git a/drivers/media/video/cx231xx/Kconfig b/drivers/media/video/cx231xx/Kconfig
index 477d4ab5e9ac..ae85a7a7bd73 100644
--- a/drivers/media/video/cx231xx/Kconfig
+++ b/drivers/media/video/cx231xx/Kconfig
@@ -1,11 +1,12 @@
config VIDEO_CX231XX
tristate "Conexant cx231xx USB video capture support"
- depends on VIDEO_DEV && I2C && INPUT
+ depends on VIDEO_DEV && I2C
select VIDEO_TUNER
select VIDEO_TVEEPROM
- select VIDEO_IR
+ depends on RC_CORE
select VIDEOBUF_VMALLOC
select VIDEO_CX25840
+ select VIDEO_CX2341X
---help---
This is a video4linux driver for Conexant 231xx USB based TV cards.
@@ -13,6 +14,19 @@ config VIDEO_CX231XX
To compile this driver as a module, choose M here: the
module will be called cx231xx
+config VIDEO_CX231XX_RC
+ bool "Conexant cx231xx Remote Controller additional support"
+ depends on RC_CORE
+ depends on VIDEO_CX231XX
+ default y
+ ---help---
+ cx231xx hardware has a builtin RX/TX support. However, a few
+ designs opted to not use it, but, instead, some other hardware.
+ This module enables the usage of those other hardware, like the
+ ones used with ISDB-T boards.
+
+ On most cases, all you need for IR is mceusb module.
+
config VIDEO_CX231XX_ALSA
tristate "Conexant Cx231xx ALSA audio module"
depends on VIDEO_CX231XX && SND
@@ -29,6 +43,8 @@ config VIDEO_CX231XX_DVB
depends on VIDEO_CX231XX && DVB_CORE
select VIDEOBUF_DVB
select MEDIA_TUNER_XC5000 if !DVB_FE_CUSTOMISE
+ select MEDIA_TUNER_NXP18271 if !DVB_FE_CUSTOMISE
+ select DVB_MB86A20S if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/video/cx231xx/Makefile b/drivers/media/video/cx231xx/Makefile
index 755dd0ce65ff..2c2484355449 100644
--- a/drivers/media/video/cx231xx/Makefile
+++ b/drivers/media/video/cx231xx/Makefile
@@ -1,5 +1,6 @@
-cx231xx-objs := cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o \
- cx231xx-avcore.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+cx231xx-y += cx231xx-video.o cx231xx-i2c.o cx231xx-cards.o cx231xx-core.o
+cx231xx-y += cx231xx-avcore.o cx231xx-417.o cx231xx-pcb-cfg.o cx231xx-vbi.o
+cx231xx-$(CONFIG_VIDEO_CX231XX_RC) += cx231xx-input.o
cx231xx-alsa-objs := cx231xx-audio.o
@@ -11,4 +12,5 @@ EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-usb
diff --git a/drivers/media/video/cx231xx/cx231xx-417.c b/drivers/media/video/cx231xx/cx231xx-417.c
new file mode 100644
index 000000000000..fc9526a5b746
--- /dev/null
+++ b/drivers/media/video/cx231xx/cx231xx-417.c
@@ -0,0 +1,2192 @@
+/*
+ *
+ * Support for a cx23417 mpeg encoder via cx231xx host port.
+ *
+ * (c) 2004 Jelle Foks <jelle@foks.us>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2008 Steven Toth <stoth@linuxtv.org>
+ * - CX23885/7/8 support
+ *
+ * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <linux/vmalloc.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/cx2341x.h>
+#include <linux/usb.h>
+
+#include "cx231xx.h"
+/*#include "cx23885-ioctl.h"*/
+
+#define CX231xx_FIRM_IMAGE_SIZE 376836
+#define CX231xx_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+/* for polaris ITVC */
+#define ITVC_WRITE_DIR 0x03FDFC00
+#define ITVC_READ_DIR 0x0001FC00
+
+#define MCI_MEMORY_DATA_BYTE0 0x00
+#define MCI_MEMORY_DATA_BYTE1 0x08
+#define MCI_MEMORY_DATA_BYTE2 0x10
+#define MCI_MEMORY_DATA_BYTE3 0x18
+
+#define MCI_MEMORY_ADDRESS_BYTE2 0x20
+#define MCI_MEMORY_ADDRESS_BYTE1 0x28
+#define MCI_MEMORY_ADDRESS_BYTE0 0x30
+
+#define MCI_REGISTER_DATA_BYTE0 0x40
+#define MCI_REGISTER_DATA_BYTE1 0x48
+#define MCI_REGISTER_DATA_BYTE2 0x50
+#define MCI_REGISTER_DATA_BYTE3 0x58
+
+#define MCI_REGISTER_ADDRESS_BYTE0 0x60
+#define MCI_REGISTER_ADDRESS_BYTE1 0x68
+
+#define MCI_REGISTER_MODE 0x70
+
+/* Read and write modes for polaris ITVC */
+#define MCI_MODE_REGISTER_READ 0x000
+#define MCI_MODE_REGISTER_WRITE 0x100
+#define MCI_MODE_MEMORY_READ 0x000
+#define MCI_MODE_MEMORY_WRITE 0x4000
+
+static unsigned int mpegbufs = 8;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 128;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+ "number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug = 1;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+struct cx231xx_dmaqueue *dma_qq;
+#define dprintk(level, fmt, arg...)\
+ do { if (v4l_debug >= level) \
+ printk(KERN_INFO "%s: " fmt, \
+ (dev) ? dev->name : "cx231xx[?]", ## arg); \
+ } while (0)
+
+static struct cx231xx_tvnorm cx231xx_tvnorms[] = {
+ {
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
+ }, {
+ .name = "NTSC-JP",
+ .id = V4L2_STD_NTSC_M_JP,
+ }, {
+ .name = "PAL-BG",
+ .id = V4L2_STD_PAL_BG,
+ }, {
+ .name = "PAL-DK",
+ .id = V4L2_STD_PAL_DK,
+ }, {
+ .name = "PAL-I",
+ .id = V4L2_STD_PAL_I,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ }, {
+ .name = "PAL-N",
+ .id = V4L2_STD_PAL_N,
+ }, {
+ .name = "PAL-Nc",
+ .id = V4L2_STD_PAL_Nc,
+ }, {
+ .name = "PAL-60",
+ .id = V4L2_STD_PAL_60,
+ }, {
+ .name = "SECAM-L",
+ .id = V4L2_STD_SECAM_L,
+ }, {
+ .name = "SECAM-DK",
+ .id = V4L2_STD_SECAM_DK,
+ }
+};
+
+/* ------------------------------------------------------------------ */
+enum cx231xx_capture_type {
+ CX231xx_MPEG_CAPTURE,
+ CX231xx_RAW_CAPTURE,
+ CX231xx_RAW_PASSTHRU_CAPTURE
+};
+enum cx231xx_capture_bits {
+ CX231xx_RAW_BITS_NONE = 0x00,
+ CX231xx_RAW_BITS_YUV_CAPTURE = 0x01,
+ CX231xx_RAW_BITS_PCM_CAPTURE = 0x02,
+ CX231xx_RAW_BITS_VBI_CAPTURE = 0x04,
+ CX231xx_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+ CX231xx_RAW_BITS_TO_HOST_CAPTURE = 0x10
+};
+enum cx231xx_capture_end {
+ CX231xx_END_AT_GOP, /* stop at the end of gop, generate irq */
+ CX231xx_END_NOW, /* stop immediately, no irq */
+};
+enum cx231xx_framerate {
+ CX231xx_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+ CX231xx_FRAMERATE_PAL_25 /* PAL: 25fps */
+};
+enum cx231xx_stream_port {
+ CX231xx_OUTPUT_PORT_MEMORY,
+ CX231xx_OUTPUT_PORT_STREAMING,
+ CX231xx_OUTPUT_PORT_SERIAL
+};
+enum cx231xx_data_xfer_status {
+ CX231xx_MORE_BUFFERS_FOLLOW,
+ CX231xx_LAST_BUFFER,
+};
+enum cx231xx_picture_mask {
+ CX231xx_PICTURE_MASK_NONE,
+ CX231xx_PICTURE_MASK_I_FRAMES,
+ CX231xx_PICTURE_MASK_I_P_FRAMES = 0x3,
+ CX231xx_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx231xx_vbi_mode_bits {
+ CX231xx_VBI_BITS_SLICED,
+ CX231xx_VBI_BITS_RAW,
+};
+enum cx231xx_vbi_insertion_bits {
+ CX231xx_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+ CX231xx_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+ CX231xx_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+ CX231xx_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+ CX231xx_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx231xx_dma_unit {
+ CX231xx_DMA_BYTES,
+ CX231xx_DMA_FRAMES,
+};
+enum cx231xx_dma_transfer_status_bits {
+ CX231xx_DMA_TRANSFER_BITS_DONE = 0x01,
+ CX231xx_DMA_TRANSFER_BITS_ERROR = 0x04,
+ CX231xx_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx231xx_pause {
+ CX231xx_PAUSE_ENCODING,
+ CX231xx_RESUME_ENCODING,
+};
+enum cx231xx_copyright {
+ CX231xx_COPYRIGHT_OFF,
+ CX231xx_COPYRIGHT_ON,
+};
+enum cx231xx_notification_type {
+ CX231xx_NOTIFICATION_REFRESH,
+};
+enum cx231xx_notification_status {
+ CX231xx_NOTIFICATION_OFF,
+ CX231xx_NOTIFICATION_ON,
+};
+enum cx231xx_notification_mailbox {
+ CX231xx_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx231xx_field1_lines {
+ CX231xx_FIELD1_SAA7114 = 0x00EF, /* 239 */
+ CX231xx_FIELD1_SAA7115 = 0x00F0, /* 240 */
+ CX231xx_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx231xx_field2_lines {
+ CX231xx_FIELD2_SAA7114 = 0x00EF, /* 239 */
+ CX231xx_FIELD2_SAA7115 = 0x00F0, /* 240 */
+ CX231xx_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx231xx_custom_data_type {
+ CX231xx_CUSTOM_EXTENSION_USR_DATA,
+ CX231xx_CUSTOM_PRIVATE_PACKET,
+};
+enum cx231xx_mute {
+ CX231xx_UNMUTE,
+ CX231xx_MUTE,
+};
+enum cx231xx_mute_video_mask {
+ CX231xx_MUTE_VIDEO_V_MASK = 0x0000FF00,
+ CX231xx_MUTE_VIDEO_U_MASK = 0x00FF0000,
+ CX231xx_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx231xx_mute_video_shift {
+ CX231xx_MUTE_VIDEO_V_SHIFT = 8,
+ CX231xx_MUTE_VIDEO_U_SHIFT = 16,
+ CX231xx_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/*
+ * Bit definitions for MC417_RWD and MC417_OEN registers
+ *
+ * bits 31-16
+ *+-----------+
+ *| Reserved |
+ *|+-----------+
+ *| bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *|| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *| bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ *||MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
+ *|+-------+-------+-------+-------+-------+-------+-------+-------+
+ */
+#define MC417_MIWR 0x8000
+#define MC417_MIRD 0x4000
+#define MC417_MICS 0x2000
+#define MC417_MIRDY 0x1000
+#define MC417_MIADDR 0x0F00
+#define MC417_MIDATA 0x00FF
+
+
+/* Bit definitions for MC417_CTL register ****
+ *bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0
+ *+--------+-------------+--------+--------------+------------+
+ *|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
+ *+--------+-------------+--------+--------------+------------+
+ */
+#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN 0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW 0x1
+#define MC417_SPD_CTL_MEDIUM 0x0
+#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3 0x3
+#define MC417_GPIO_SEL_GPIO2 0x2
+#define MC417_GPIO_SEL_GPIO1 0x1
+#define MC417_GPIO_SEL_GPIO0 0x0
+
+
+#define CX23417_GPIO_MASK 0xFC0003FF
+static int setITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 value)
+{
+ int status = 0;
+ u32 _gpio_direction = 0;
+
+ _gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
+ _gpio_direction = _gpio_direction|gpio_direction;
+ status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
+ (u8 *)&value, 4, 0, 0);
+ return status;
+}
+static int getITVCReg(struct cx231xx *dev, u32 gpio_direction, u32 *pValue)
+{
+ int status = 0;
+ u32 _gpio_direction = 0;
+
+ _gpio_direction = _gpio_direction & CX23417_GPIO_MASK;
+ _gpio_direction = _gpio_direction|gpio_direction;
+
+ status = cx231xx_send_gpio_cmd(dev, _gpio_direction,
+ (u8 *)pValue, 4, 0, 1);
+ return status;
+}
+
+static int waitForMciComplete(struct cx231xx *dev)
+{
+ u32 gpio;
+ u32 gpio_driection = 0;
+ u8 count = 0;
+ getITVCReg(dev, gpio_driection, &gpio);
+
+ while (!(gpio&0x020000)) {
+ msleep(10);
+
+ getITVCReg(dev, gpio_driection, &gpio);
+
+ if (count++ > 100) {
+ dprintk(3, "ERROR: Timeout - gpio=%x\n", gpio);
+ return -1;
+ }
+ }
+ return 0;
+}
+
+static int mc417_register_write(struct cx231xx *dev, u16 address, u32 value)
+{
+ u32 temp;
+ int status = 0;
+
+ temp = 0x82|MCI_REGISTER_DATA_BYTE0|((value&0x000000FF)<<8);
+ temp = temp<<10;
+ status = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ if (status < 0)
+ return status;
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 1;*/
+ temp = 0x82|MCI_REGISTER_DATA_BYTE1|(value&0x0000FF00);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 2;*/
+ temp = 0x82|MCI_REGISTER_DATA_BYTE2|((value&0x00FF0000)>>8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 3;*/
+ temp = 0x82|MCI_REGISTER_DATA_BYTE3|((value&0xFF000000)>>16);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 0;*/
+ temp = 0x82|MCI_REGISTER_ADDRESS_BYTE0|((address&0x000000FF)<<8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 1;*/
+ temp = 0x82|MCI_REGISTER_ADDRESS_BYTE1|(address&0x0000FF00);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*Write that the mode is write.*/
+ temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_WRITE;
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ return waitForMciComplete(dev);
+}
+
+static int mc417_register_read(struct cx231xx *dev, u16 address, u32 *value)
+{
+ /*write address byte 0;*/
+ u32 temp;
+ u32 return_value = 0;
+ int ret = 0;
+
+ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE0 | ((address & 0x00FF) << 8);
+ temp = temp << 10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 1;*/
+ temp = 0x82 | MCI_REGISTER_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp << 10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write that the mode is read;*/
+ temp = 0x82 | MCI_REGISTER_MODE | MCI_MODE_REGISTER_READ;
+ temp = temp << 10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*wait for the MIRDY line to be asserted ,
+ signalling that the read is done;*/
+ ret = waitForMciComplete(dev);
+
+ /*switch the DATA- GPIO to input mode;*/
+
+ /*Read data byte 0;*/
+ temp = (0x82 | MCI_REGISTER_DATA_BYTE0) << 10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_REGISTER_DATA_BYTE0) << 10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 18);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+ /* Read data byte 1;*/
+ temp = (0x82 | MCI_REGISTER_DATA_BYTE1) << 10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_REGISTER_DATA_BYTE1) << 10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+
+ return_value |= ((temp & 0x03FC0000) >> 10);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+ /*Read data byte 2;*/
+ temp = (0x82 | MCI_REGISTER_DATA_BYTE2) << 10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_REGISTER_DATA_BYTE2) << 10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) >> 2);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+ /*Read data byte 3;*/
+ temp = (0x82 | MCI_REGISTER_DATA_BYTE3) << 10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81 | MCI_REGISTER_DATA_BYTE3) << 10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp & 0x03FC0000) << 6);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87 << 10));
+
+ *value = return_value;
+
+
+ return ret;
+}
+
+static int mc417_memory_write(struct cx231xx *dev, u32 address, u32 value)
+{
+ /*write data byte 0;*/
+
+ u32 temp;
+ int ret = 0;
+
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE0|((value & 0x000000FF) << 8);
+ temp = temp << 10;
+ ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ if (ret < 0)
+ return ret;
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 1;*/
+ temp = 0x82 | MCI_MEMORY_DATA_BYTE1 | (value & 0x0000FF00);
+ temp = temp << 10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp | ((0x05) << 10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 2;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write data byte 3;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /* write address byte 2;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+ ((address & 0x003F0000)>>8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /* write address byte 1;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /* write address byte 0;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*wait for MIRDY line;*/
+ waitForMciComplete(dev);
+
+ return 0;
+}
+
+static int mc417_memory_read(struct cx231xx *dev, u32 address, u32 *value)
+{
+ u32 temp = 0;
+ u32 return_value = 0;
+ int ret = 0;
+
+ /*write address byte 2;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_READ |
+ ((address & 0x003F0000)>>8);
+ temp = temp<<10;
+ ret = setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ if (ret < 0)
+ return ret;
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 1*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*write address byte 0*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0 | ((address & 0x00FF)<<8);
+ temp = temp<<10;
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+ temp = temp|((0x05)<<10);
+ setITVCReg(dev, ITVC_WRITE_DIR, temp);
+
+ /*Wait for MIRDY line*/
+ ret = waitForMciComplete(dev);
+
+
+ /*Read data byte 3;*/
+ temp = (0x82|MCI_MEMORY_DATA_BYTE3)<<10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81|MCI_MEMORY_DATA_BYTE3)<<10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp&0x03FC0000)<<6);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+ /*Read data byte 2;*/
+ temp = (0x82|MCI_MEMORY_DATA_BYTE2)<<10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81|MCI_MEMORY_DATA_BYTE2)<<10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp&0x03FC0000)>>2);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+ /* Read data byte 1;*/
+ temp = (0x82|MCI_MEMORY_DATA_BYTE1)<<10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81|MCI_MEMORY_DATA_BYTE1)<<10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp&0x03FC0000)>>10);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+ /*Read data byte 0;*/
+ temp = (0x82|MCI_MEMORY_DATA_BYTE0)<<10;
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ temp = ((0x81|MCI_MEMORY_DATA_BYTE0)<<10);
+ setITVCReg(dev, ITVC_READ_DIR, temp);
+ getITVCReg(dev, ITVC_READ_DIR, &temp);
+ return_value |= ((temp&0x03FC0000)>>18);
+ setITVCReg(dev, ITVC_READ_DIR, (0x87<<10));
+
+ *value = return_value;
+ return ret;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+static char *cmd_to_str(int cmd)
+{
+ switch (cmd) {
+ case CX2341X_ENC_PING_FW:
+ return "PING_FW";
+ case CX2341X_ENC_START_CAPTURE:
+ return "START_CAPTURE";
+ case CX2341X_ENC_STOP_CAPTURE:
+ return "STOP_CAPTURE";
+ case CX2341X_ENC_SET_AUDIO_ID:
+ return "SET_AUDIO_ID";
+ case CX2341X_ENC_SET_VIDEO_ID:
+ return "SET_VIDEO_ID";
+ case CX2341X_ENC_SET_PCR_ID:
+ return "SET_PCR_PID";
+ case CX2341X_ENC_SET_FRAME_RATE:
+ return "SET_FRAME_RATE";
+ case CX2341X_ENC_SET_FRAME_SIZE:
+ return "SET_FRAME_SIZE";
+ case CX2341X_ENC_SET_BIT_RATE:
+ return "SET_BIT_RATE";
+ case CX2341X_ENC_SET_GOP_PROPERTIES:
+ return "SET_GOP_PROPERTIES";
+ case CX2341X_ENC_SET_ASPECT_RATIO:
+ return "SET_ASPECT_RATIO";
+ case CX2341X_ENC_SET_DNR_FILTER_MODE:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_CORING_LEVELS:
+ return "SET_CORING_LEVELS";
+ case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+ return "SET_SPATIAL_FILTER_TYPE";
+ case CX2341X_ENC_SET_VBI_LINE:
+ return "SET_VBI_LINE";
+ case CX2341X_ENC_SET_STREAM_TYPE:
+ return "SET_STREAM_TYPE";
+ case CX2341X_ENC_SET_OUTPUT_PORT:
+ return "SET_OUTPUT_PORT";
+ case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+ return "SET_AUDIO_PROPERTIES";
+ case CX2341X_ENC_HALT_FW:
+ return "HALT_FW";
+ case CX2341X_ENC_GET_VERSION:
+ return "GET_VERSION";
+ case CX2341X_ENC_SET_GOP_CLOSURE:
+ return "SET_GOP_CLOSURE";
+ case CX2341X_ENC_GET_SEQ_END:
+ return "GET_SEQ_END";
+ case CX2341X_ENC_SET_PGM_INDEX_INFO:
+ return "SET_PGM_INDEX_INFO";
+ case CX2341X_ENC_SET_VBI_CONFIG:
+ return "SET_VBI_CONFIG";
+ case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+ return "SET_DMA_BLOCK_SIZE";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+ return "GET_PREV_DMA_INFO_MB_10";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+ return "GET_PREV_DMA_INFO_MB_9";
+ case CX2341X_ENC_SCHED_DMA_TO_HOST:
+ return "SCHED_DMA_TO_HOST";
+ case CX2341X_ENC_INITIALIZE_INPUT:
+ return "INITIALIZE_INPUT";
+ case CX2341X_ENC_SET_FRAME_DROP_RATE:
+ return "SET_FRAME_DROP_RATE";
+ case CX2341X_ENC_PAUSE_ENCODER:
+ return "PAUSE_ENCODER";
+ case CX2341X_ENC_REFRESH_INPUT:
+ return "REFRESH_INPUT";
+ case CX2341X_ENC_SET_COPYRIGHT:
+ return "SET_COPYRIGHT";
+ case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+ return "SET_EVENT_NOTIFICATION";
+ case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+ return "SET_NUM_VSYNC_LINES";
+ case CX2341X_ENC_SET_PLACEHOLDER:
+ return "SET_PLACEHOLDER";
+ case CX2341X_ENC_MUTE_VIDEO:
+ return "MUTE_VIDEO";
+ case CX2341X_ENC_MUTE_AUDIO:
+ return "MUTE_AUDIO";
+ case CX2341X_ENC_MISC:
+ return "MISC";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int cx231xx_mbox_func(void *priv,
+ u32 command,
+ int in,
+ int out,
+ u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ struct cx231xx *dev = priv;
+ unsigned long timeout;
+ u32 value, flag, retval = 0;
+ int i;
+
+ dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+ cmd_to_str(command));
+
+ /* this may not be 100% safe if we can't read any memory location
+ without side effects */
+ mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+ if (value != 0x12345678) {
+ dprintk(3,
+ "Firmware and/or mailbox pointer not initialized "
+ "or corrupted, signature = 0x%x, cmd = %s\n", value,
+ cmd_to_str(command));
+ return -1;
+ }
+
+ /* This read looks at 32 bits, but flag is only 8 bits.
+ * Seems we also bail if CMD or TIMEOUT bytes are set???
+ */
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (flag) {
+ dprintk(3, "ERROR: Mailbox appears to be in use "
+ "(%x), cmd = %s\n", flag, cmd_to_str(command));
+ return -1;
+ }
+
+ flag |= 1; /* tell 'em we're working on it */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* write command + args + fill remaining with zeros */
+ /* command code */
+ mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+ mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+ IVTV_API_STD_TIMEOUT); /* timeout */
+ for (i = 0; i < in; i++) {
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+ dprintk(3, "API Input %d = %d\n", i, data[i]);
+ }
+ for (; i < CX2341X_MBOX_MAX_DATA; i++)
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+ flag |= 3; /* tell 'em we're done writing */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* wait for firmware to handle the API command */
+ timeout = jiffies + msecs_to_jiffies(10);
+ for (;;) {
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (0 != (flag & 4))
+ break;
+ if (time_after(jiffies, timeout)) {
+ dprintk(3, "ERROR: API Mailbox timeout\n");
+ return -1;
+ }
+ udelay(10);
+ }
+
+ /* read output values */
+ for (i = 0; i < out; i++) {
+ mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+ dprintk(3, "API Output %d = %d\n", i, data[i]);
+ }
+
+ mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+ dprintk(3, "API result = %d\n", retval);
+
+ flag = 0;
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx231xx_api_cmd(struct cx231xx *dev,
+ u32 command,
+ u32 inputcnt,
+ u32 outputcnt,
+ ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i, err;
+
+ dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+ va_start(vargs, outputcnt);
+ for (i = 0; i < inputcnt; i++)
+ data[i] = va_arg(vargs, int);
+
+ err = cx231xx_mbox_func(dev, command, inputcnt, outputcnt, data);
+ for (i = 0; i < outputcnt; i++) {
+ int *vptr = va_arg(vargs, int *);
+ *vptr = data[i];
+ }
+ va_end(vargs);
+
+ return err;
+}
+
+static int cx231xx_find_mailbox(struct cx231xx *dev)
+{
+ u32 signature[4] = {
+ 0x12345678, 0x34567812, 0x56781234, 0x78123456
+ };
+ int signaturecnt = 0;
+ u32 value;
+ int i;
+ int ret = 0;
+
+ dprintk(2, "%s()\n", __func__);
+
+ for (i = 0; i < 0x100; i++) {/*CX231xx_FIRM_IMAGE_SIZE*/
+ ret = mc417_memory_read(dev, i, &value);
+ if (ret < 0)
+ return ret;
+ if (value == signature[signaturecnt])
+ signaturecnt++;
+ else
+ signaturecnt = 0;
+ if (4 == signaturecnt) {
+ dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+ return i+1;
+ }
+ }
+ dprintk(3, "Mailbox signature values not found!\n");
+ return -1;
+}
+
+static void mciWriteMemoryToGPIO(struct cx231xx *dev, u32 address, u32 value,
+ u32 *p_fw_image)
+{
+
+ u32 temp = 0;
+ int i = 0;
+
+ temp = 0x82|MCI_MEMORY_DATA_BYTE0|((value&0x000000FF)<<8);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /*write data byte 1;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE1|(value&0x0000FF00);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /*write data byte 2;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE2|((value&0x00FF0000)>>8);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /*write data byte 3;*/
+ temp = 0x82|MCI_MEMORY_DATA_BYTE3|((value&0xFF000000)>>16);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /* write address byte 2;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE2 | MCI_MODE_MEMORY_WRITE |
+ ((address & 0x003F0000)>>8);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /* write address byte 1;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE1 | (address & 0xFF00);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ /* write address byte 0;*/
+ temp = 0x82|MCI_MEMORY_ADDRESS_BYTE0|((address & 0x00FF)<<8);
+ temp = temp<<10;
+ *p_fw_image = temp;
+ p_fw_image++;
+ temp = temp|((0x05)<<10);
+ *p_fw_image = temp;
+ p_fw_image++;
+
+ for (i = 0; i < 6; i++) {
+ *p_fw_image = 0xFFFFFFFF;
+ p_fw_image++;
+ }
+}
+
+
+static int cx231xx_load_firmware(struct cx231xx *dev)
+{
+ static const unsigned char magic[8] = {
+ 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+ };
+ const struct firmware *firmware;
+ int i, retval = 0;
+ u32 value = 0;
+ u32 gpio_output = 0;
+ /*u32 checksum = 0;*/
+ /*u32 *dataptr;*/
+ u32 transfer_size = 0;
+ u32 fw_data = 0;
+ u32 address = 0;
+ /*u32 current_fw[800];*/
+ u32 *p_current_fw, *p_fw;
+ u32 *p_fw_data;
+ int frame = 0;
+ u16 _buffer_size = 4096;
+ u8 *p_buffer;
+
+ p_current_fw = vmalloc(1884180 * 4);
+ p_fw = p_current_fw;
+ if (p_current_fw == 0) {
+ dprintk(2, "FAIL!!!\n");
+ return -1;
+ }
+
+ p_buffer = vmalloc(4096);
+ if (p_buffer == 0) {
+ dprintk(2, "FAIL!!!\n");
+ return -1;
+ }
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Save GPIO settings before reset of APU */
+ retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+ retval |= mc417_memory_read(dev, 0x900C, &value);
+
+ retval = mc417_register_write(dev,
+ IVTV_REG_VPU, 0xFFFFFFED);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_APU, 0);
+
+ if (retval != 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return -1;
+ }
+
+ retval = request_firmware(&firmware, CX231xx_FIRM_IMAGE_NAME,
+ &dev->udev->dev);
+
+ if (retval != 0) {
+ printk(KERN_ERR
+ "ERROR: Hotplug firmware request failed (%s).\n",
+ CX231xx_FIRM_IMAGE_NAME);
+ printk(KERN_ERR "Please fix your hotplug setup, the board will "
+ "not work without firmware loaded!\n");
+ return -1;
+ }
+
+ if (firmware->size != CX231xx_FIRM_IMAGE_SIZE) {
+ printk(KERN_ERR "ERROR: Firmware size mismatch "
+ "(have %zd, expected %d)\n",
+ firmware->size, CX231xx_FIRM_IMAGE_SIZE);
+ release_firmware(firmware);
+ return -1;
+ }
+
+ if (0 != memcmp(firmware->data, magic, 8)) {
+ printk(KERN_ERR
+ "ERROR: Firmware magic mismatch, wrong file?\n");
+ release_firmware(firmware);
+ return -1;
+ }
+
+ initGPIO(dev);
+
+ /* transfer to the chip */
+ dprintk(2, "Loading firmware to GPIO...\n");
+ p_fw_data = (u32 *)firmware->data;
+ dprintk(2, "firmware->size=%zd\n", firmware->size);
+ for (transfer_size = 0; transfer_size < firmware->size;
+ transfer_size += 4) {
+ fw_data = *p_fw_data;
+
+ mciWriteMemoryToGPIO(dev, address, fw_data, p_current_fw);
+ address = address + 1;
+ p_current_fw += 20;
+ p_fw_data += 1;
+ }
+
+ /*download the firmware by ep5-out*/
+
+ for (frame = 0; frame < (int)(CX231xx_FIRM_IMAGE_SIZE*20/_buffer_size);
+ frame++) {
+ for (i = 0; i < _buffer_size; i++) {
+ *(p_buffer + i) = (u8)(*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x000000FF);
+ i++;
+ *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x0000FF00) >> 8);
+ i++;
+ *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0x00FF0000) >> 16);
+ i++;
+ *(p_buffer + i) = (u8)((*(p_fw + (frame * 128 * 8 + (i / 4))) & 0xFF000000) >> 24);
+ }
+ cx231xx_ep5_bulkout(dev, p_buffer, _buffer_size);
+ }
+
+ p_current_fw = p_fw;
+ vfree(p_current_fw);
+ p_current_fw = NULL;
+ uninitGPIO(dev);
+ release_firmware(firmware);
+ dprintk(1, "Firmware upload successful.\n");
+
+ retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+ IVTV_CMD_HW_BLOCKS_RST);
+ if (retval < 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return retval;
+ }
+ /* F/W power up disturbs the GPIOs, restore state */
+ retval |= mc417_register_write(dev, 0x9020, gpio_output);
+ retval |= mc417_register_write(dev, 0x900C, value);
+
+ retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
+ retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+ if (retval < 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return retval;
+ }
+ return 0;
+}
+
+static void cx231xx_417_check_encoder(struct cx231xx *dev)
+{
+ u32 status, seq;
+
+ status = 0;
+ seq = 0;
+ cx231xx_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+ dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+static void cx231xx_codec_settings(struct cx231xx *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ /* assign frame size */
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ dev->ts1.height, dev->ts1.width);
+
+ dev->mpeg_params.width = dev->ts1.width;
+ dev->mpeg_params.height = dev->ts1.height;
+
+ cx2341x_update(dev, cx231xx_mbox_func, NULL, &dev->mpeg_params);
+
+ cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+ cx231xx_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx231xx_initialize_codec(struct cx231xx *dev)
+{
+ int version;
+ int retval;
+ u32 i, data[7];
+ u32 val = 0;
+
+ dprintk(1, "%s()\n", __func__);
+ cx231xx_disable656(dev);
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+ if (retval < 0) {
+ dprintk(2, "%s() PING OK\n", __func__);
+ retval = cx231xx_load_firmware(dev);
+ if (retval < 0) {
+ printk(KERN_ERR "%s() f/w load failed\n", __func__);
+ return retval;
+ }
+ retval = cx231xx_find_mailbox(dev);
+ if (retval < 0) {
+ printk(KERN_ERR "%s() mailbox < 0, error\n",
+ __func__);
+ return -1;
+ }
+ dev->cx23417_mailbox = retval;
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "ERROR: cx23417 firmware ping failed!\n");
+ return -1;
+ }
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+ &version);
+ if (retval < 0) {
+ printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+ "version failed!\n");
+ return -1;
+ }
+ dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+ msleep(200);
+ }
+
+ for (i = 0; i < 1; i++) {
+ retval = mc417_register_read(dev, 0x20f8, &val);
+ dprintk(3, "***before enable656() VIM Capture Lines =%d ***\n",
+ val);
+ if (retval < 0)
+ return retval;
+ }
+
+ cx231xx_enable656(dev);
+ /* stop mpeg capture */
+ cx231xx_api_cmd(dev, CX2341X_ENC_STOP_CAPTURE,
+ 3, 0, 1, 3, 4);
+
+ cx231xx_codec_settings(dev);
+ msleep(60);
+
+/* cx231xx_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+ CX231xx_FIELD1_SAA7115, CX231xx_FIELD2_SAA7115);
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+ CX231xx_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0);
+*/
+ /* Setup to capture VBI */
+ data[0] = 0x0001BD00;
+ data[1] = 1; /* frames per interrupt */
+ data[2] = 4; /* total bufs */
+ data[3] = 0x91559155; /* start codes */
+ data[4] = 0x206080C0; /* stop codes */
+ data[5] = 6; /* lines */
+ data[6] = 64; /* BPL */
+/*
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+ data[2], data[3], data[4], data[5], data[6]);
+
+ for (i = 2; i <= 24; i++) {
+ int valid;
+
+ valid = ((i >= 19) && (i <= 21));
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+ valid, 0 , 0, 0);
+ cx231xx_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+ i | 0x80000000, valid, 0, 0, 0);
+ }
+*/
+/* cx231xx_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX231xx_UNMUTE);
+ msleep(60);
+*/
+ /* initialize the video input */
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+ if (retval < 0)
+ return retval;
+ msleep(60);
+
+ /* Enable VIP style pixel invalidation so we work with scaled mode */
+ mc417_memory_write(dev, 2120, 0x00000080);
+
+ /* start capturing to the host interface */
+ retval = cx231xx_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+ CX231xx_MPEG_CAPTURE, CX231xx_RAW_BITS_NONE);
+ if (retval < 0)
+ return retval;
+ msleep(10);
+
+ for (i = 0; i < 1; i++) {
+ mc417_register_read(dev, 0x20f8, &val);
+ dprintk(3, "***VIM Capture Lines =%d ***\n", val);
+ }
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx231xx_fh *fh = q->priv_data;
+
+ fh->dev->ts1.ts_packet_size = mpeglinesize;
+ fh->dev->ts1.ts_packet_count = mpeglines;
+
+ *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+ *count = mpegbufs;
+
+ return 0;
+}
+static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
+{
+ struct cx231xx_fh *fh = vq->priv_data;
+ struct cx231xx *dev = fh->dev;
+ unsigned long flags = 0;
+
+ if (in_interrupt())
+ BUG();
+
+ spin_lock_irqsave(&dev->video_mode.slock, flags);
+ if (dev->USE_ISO) {
+ if (dev->video_mode.isoc_ctl.buf == buf)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ } else {
+ if (dev->video_mode.bulk_ctl.buf == buf)
+ dev->video_mode.bulk_ctl.buf = NULL;
+ }
+ spin_unlock_irqrestore(&dev->video_mode.slock, flags);
+ videobuf_waiton(vq, &buf->vb, 0, 0);
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static void buffer_copy(struct cx231xx *dev, char *data, int len, struct urb *urb,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ void *vbuf;
+ struct cx231xx_buffer *buf;
+ u32 tail_data = 0;
+ char *p_data;
+
+ if (dma_q->mpeg_buffer_done == 0) {
+ if (list_empty(&dma_q->active))
+ return;
+
+ buf = list_entry(dma_q->active.next,
+ struct cx231xx_buffer, vb.queue);
+ dev->video_mode.isoc_ctl.buf = buf;
+ dma_q->mpeg_buffer_done = 1;
+ }
+ /* Fill buffer */
+ buf = dev->video_mode.isoc_ctl.buf;
+ vbuf = videobuf_to_vmalloc(&buf->vb);
+
+ if ((dma_q->mpeg_buffer_completed+len) <
+ mpeglines*mpeglinesize) {
+ if (dma_q->add_ps_package_head ==
+ CX231XX_NEED_ADD_PS_PACKAGE_HEAD) {
+ memcpy(vbuf+dma_q->mpeg_buffer_completed,
+ dma_q->ps_head, 3);
+ dma_q->mpeg_buffer_completed =
+ dma_q->mpeg_buffer_completed + 3;
+ dma_q->add_ps_package_head =
+ CX231XX_NONEED_PS_PACKAGE_HEAD;
+ }
+ memcpy(vbuf+dma_q->mpeg_buffer_completed, data, len);
+ dma_q->mpeg_buffer_completed =
+ dma_q->mpeg_buffer_completed + len;
+ } else {
+ dma_q->mpeg_buffer_done = 0;
+
+ tail_data =
+ mpeglines*mpeglinesize - dma_q->mpeg_buffer_completed;
+ memcpy(vbuf+dma_q->mpeg_buffer_completed,
+ data, tail_data);
+
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+ dma_q->mpeg_buffer_completed = 0;
+
+ if (len - tail_data > 0) {
+ p_data = data + tail_data;
+ dma_q->left_data_count = len - tail_data;
+ memcpy(dma_q->p_left_data,
+ p_data, len - tail_data);
+ }
+
+ }
+
+ return;
+}
+
+static void buffer_filled(char *data, int len, struct urb *urb,
+ struct cx231xx_dmaqueue *dma_q)
+{
+ void *vbuf;
+ struct cx231xx_buffer *buf;
+
+ if (list_empty(&dma_q->active))
+ return;
+
+
+ buf = list_entry(dma_q->active.next,
+ struct cx231xx_buffer, vb.queue);
+
+
+ /* Fill buffer */
+ vbuf = videobuf_to_vmalloc(&buf->vb);
+ memcpy(vbuf, data, len);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+
+ return;
+}
+static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
+{
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ unsigned char *p_buffer;
+ u32 buffer_size = 0;
+ u32 i = 0;
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ if (dma_q->left_data_count > 0) {
+ buffer_copy(dev, dma_q->p_left_data,
+ dma_q->left_data_count, urb, dma_q);
+ dma_q->mpeg_buffer_completed = dma_q->left_data_count;
+ dma_q->left_data_count = 0;
+ }
+
+ p_buffer = urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset;
+ buffer_size = urb->iso_frame_desc[i].actual_length;
+
+ if (buffer_size > 0)
+ buffer_copy(dev, p_buffer, buffer_size, urb, dma_q);
+ }
+
+ return 0;
+}
+static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+
+ /*char *outp;*/
+ /*struct cx231xx_buffer *buf;*/
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ unsigned char *p_buffer, *buffer;
+ u32 buffer_size = 0;
+
+ p_buffer = urb->transfer_buffer;
+ buffer_size = urb->actual_length;
+
+ buffer = kmalloc(buffer_size, GFP_ATOMIC);
+
+ memcpy(buffer, dma_q->ps_head, 3);
+ memcpy(buffer+3, p_buffer, buffer_size-3);
+ memcpy(dma_q->ps_head, p_buffer+buffer_size-3, 3);
+
+ p_buffer = buffer;
+ buffer_filled(p_buffer, buffer_size, urb, dma_q);
+
+ kfree(buffer);
+ return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx231xx_fh *fh = q->priv_data;
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+ int size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+
+ dma_qq = &dev->video_mode.vidq;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < size)
+ return -EINVAL;
+ buf->vb.width = fh->dev->ts1.ts_packet_size;
+ buf->vb.height = fh->dev->ts1.ts_packet_count;
+ buf->vb.size = size;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(q, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ if (dev->USE_ISO) {
+ if (!dev->video_mode.isoc_ctl.num_bufs)
+ urb_init = 1;
+ } else {
+ if (!dev->video_mode.bulk_ctl.num_bufs)
+ urb_init = 1;
+ }
+ /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+ urb_init, dev->video_mode.max_pkt_size);*/
+ dev->mode_tv = 1;
+
+ if (urb_init) {
+ rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ rc = cx231xx_unmute_audio(dev);
+ if (dev->USE_ISO) {
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
+ rc = cx231xx_init_isoc(dev, mpeglines,
+ mpegbufs,
+ dev->ts1_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ } else {
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+ rc = cx231xx_init_bulk(dev, mpeglines,
+ mpegbufs,
+ dev->ts1_mode.max_pkt_size,
+ cx231xx_bulk_copy);
+ }
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(q, buf);
+ return rc;
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx231xx_fh *fh = q->priv_data;
+
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ struct cx231xx *dev = fh->dev;
+ struct cx231xx_dmaqueue *vidq = &dev->video_mode.vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx231xx_buffer *buf =
+ container_of(vb, struct cx231xx_buffer, vb);
+ /*struct cx231xx_fh *fh = q->priv_data;*/
+ /*struct cx231xx *dev = (struct cx231xx *)fh->dev;*/
+
+ free_buffer(q, buf);
+}
+
+static struct videobuf_queue_ops cx231xx_qops = {
+ .buf_setup = bb_buf_setup,
+ .buf_prepare = bb_buf_prepare,
+ .buf_queue = bb_buf_queue,
+ .buf_release = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int cx231xx_queryctrl(struct cx231xx *dev,
+ struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ /* MPEG V4L2 controls */
+ if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+ return 0;
+}
+
+static int cx231xx_querymenu(struct cx231xx *dev,
+ struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ cx231xx_queryctrl(dev, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ cx2341x_ctrl_get_menu(&dev->mpeg_params, qmenu->id));
+}
+
+static int vidioc_g_std(struct file *file, void *fh0, v4l2_std_id *norm)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ *norm = dev->encodernorm.id;
+ return 0;
+}
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cx231xx_tvnorms); i++)
+ if (*id & cx231xx_tvnorms[i].id)
+ break;
+ if (i == ARRAY_SIZE(cx231xx_tvnorms))
+ return -EINVAL;
+ dev->encodernorm = cx231xx_tvnorms[i];
+
+ if (dev->encodernorm.id & 0xb000) {
+ dprintk(3, "encodernorm set to NTSC\n");
+ dev->norm = V4L2_STD_NTSC;
+ dev->ts1.height = 480;
+ dev->mpeg_params.is_50hz = 0;
+ } else {
+ dprintk(3, "encodernorm set to PAL\n");
+ dev->norm = V4L2_STD_PAL_B;
+ dev->ts1.height = 576;
+ dev->mpeg_params.is_50hz = 1;
+ }
+ call_all(dev, core, s_std, dev->norm);
+ /* do mode control overrides */
+ cx231xx_do_mode_ctrl_overrides(dev);
+
+ dprintk(3, "exit vidioc_s_std() i=0x%x\n", i);
+ return 0;
+}
+static int vidioc_g_audio(struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ struct v4l2_audio *vin = a;
+
+ int ret = -EINVAL;
+ if (vin->index > 0)
+ return ret;
+ strncpy(vin->name, "VideoGrabber Audio", 14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+return 0;
+}
+static int vidioc_enumaudio(struct file *file, void *fh,
+ struct v4l2_audio *a)
+{
+ struct v4l2_audio *vin = a;
+
+ int ret = -EINVAL;
+
+ if (vin->index > 0)
+ return ret;
+ strncpy(vin->name, "VideoGrabber Audio", 14);
+ vin->capability = V4L2_AUDCAP_STEREO;
+
+
+return 0;
+}
+static const char *iname[] = {
+ [CX231XX_VMUX_COMPOSITE1] = "Composite1",
+ [CX231XX_VMUX_SVIDEO] = "S-Video",
+ [CX231XX_VMUX_TELEVISION] = "Television",
+ [CX231XX_VMUX_CABLE] = "Cable TV",
+ [CX231XX_VMUX_DVB] = "DVB",
+ [CX231XX_VMUX_DEBUG] = "for debug only",
+};
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ struct cx231xx_input *input;
+ int n;
+ dprintk(3, "enter vidioc_enum_input()i->index=%d\n", i->index);
+
+ if (i->index >= 4)
+ return -EINVAL;
+
+
+ input = &cx231xx_boards[dev->model].input[i->index];
+
+ if (input->type == 0)
+ return -EINVAL;
+
+ /* FIXME
+ * strcpy(i->name, input->name); */
+
+ n = i->index;
+ strcpy(i->name, iname[INPUT(n)->type]);
+
+ if (input->type == CX231XX_VMUX_TELEVISION ||
+ input->type == CX231XX_VMUX_CABLE)
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ dprintk(3, "enter vidioc_s_input() i=%d\n", i);
+
+ mutex_lock(&dev->lock);
+
+ video_mux(dev, i);
+
+ mutex_unlock(&dev->lock);
+
+ if (i >= 4)
+ return -EINVAL;
+ dev->input = i;
+ dprintk(3, "exit vidioc_s_input()\n");
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+
+
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_s_ctrl()\n");
+ /* Update the A/V core */
+ call_all(dev, core, s_ctrl, ctl);
+ dprintk(3, "exit vidioc_s_ctrl()\n");
+ return 0;
+}
+static struct v4l2_capability pvr_capability = {
+ .driver = "cx231xx",
+ .card = "VideoGrabber",
+ .bus_info = "usb",
+ .version = 1,
+ .capabilities = (V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_TUNER | V4L2_CAP_AUDIO | V4L2_CAP_RADIO |
+ V4L2_CAP_STREAMING | V4L2_CAP_READWRITE),
+ .reserved = {0, 0, 0, 0}
+};
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+
+
+
+ memcpy(cap, &pvr_capability, sizeof(struct v4l2_capability));
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_g_fmt_vid_cap()\n");
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->ts1.width;
+ f->fmt.pix.height = dev->ts1.height;
+ f->fmt.pix.field = fh->vidq.field;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->vidq.field);
+ dprintk(3, "exit vidioc_g_fmt_vid_cap()\n");
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_try_fmt_vid_cap()\n");
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->vidq.field);
+ dprintk(3, "exit vidioc_try_fmt_vid_cap()\n");
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ return videobuf_reqbufs(&fh->vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ return videobuf_querybuf(&fh->vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ return videobuf_qbuf(&fh->vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct cx231xx_fh *fh = priv;
+
+ return videobuf_dqbuf(&fh->vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+
+static int vidioc_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type i)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ struct cx231xx *dev = fh->dev;
+ int rc = 0;
+ dprintk(3, "enter vidioc_streamon()\n");
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+ rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ if (dev->USE_ISO)
+ rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_isoc_copy);
+ else {
+ rc = cx231xx_init_bulk(dev, 320,
+ 5,
+ dev->ts1_mode.max_pkt_size,
+ cx231xx_bulk_copy);
+ }
+ dprintk(3, "exit vidioc_streamon()\n");
+ return videobuf_streamon(&fh->vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct cx231xx_fh *fh = file->private_data;
+
+ return videobuf_streamoff(&fh->vidq);
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_g_ext_ctrls()\n");
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ dprintk(3, "exit vidioc_g_ext_ctrls()\n");
+ return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, VIDIOC_G_EXT_CTRLS);
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+ dprintk(3, "enter vidioc_s_ext_ctrls()\n");
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+ if (err == 0) {
+ err = cx2341x_update(dev, cx231xx_mbox_func,
+ &dev->mpeg_params, &p);
+ dev->mpeg_params = p;
+ }
+
+ return err;
+
+
+return 0;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *f)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ struct cx2341x_mpeg_params p;
+ int err;
+ dprintk(3, "enter vidioc_try_ext_ctrls()\n");
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, VIDIOC_TRY_EXT_CTRLS);
+ dprintk(3, "exit vidioc_try_ext_ctrls() err=%d\n", err);
+ return err;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", dev->name);
+ dprintk(3,
+ "%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
+ call_all(dev, core, log_status);
+ cx2341x_log_status(&dev->mpeg_params, name);
+ dprintk(3,
+ "%s/2: ============= END LOG STATUS =============\n",
+ dev->name);
+ return 0;
+}
+
+static int vidioc_querymenu(struct file *file, void *priv,
+ struct v4l2_querymenu *a)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_querymenu()\n");
+ dprintk(3, "exit vidioc_querymenu()\n");
+ return cx231xx_querymenu(dev, a);
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ struct cx231xx_fh *fh = priv;
+ struct cx231xx *dev = fh->dev;
+ dprintk(3, "enter vidioc_queryctrl()\n");
+ dprintk(3, "exit vidioc_queryctrl()\n");
+ return cx231xx_queryctrl(dev, c);
+}
+
+static int mpeg_open(struct file *file)
+{
+ int minor = video_devdata(file)->minor;
+ struct cx231xx *h, *dev = NULL;
+ /*struct list_head *list;*/
+ struct cx231xx_fh *fh;
+ /*u32 value = 0;*/
+
+ dprintk(2, "%s()\n", __func__);
+
+ list_for_each_entry(h, &cx231xx_devlist, devlist) {
+ if (h->v4l_device->minor == minor)
+ dev = h;
+ }
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ mutex_lock(&dev->lock);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh) {
+ mutex_unlock(&dev->lock);
+ return -ENOMEM;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+
+ videobuf_queue_vmalloc_init(&fh->vidq, &cx231xx_qops,
+ NULL, &dev->video_mode.slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_INTERLACED,
+ sizeof(struct cx231xx_buffer), fh, NULL);
+/*
+ videobuf_queue_sg_init(&fh->vidq, &cx231xx_qops,
+ &dev->udev->dev, &dev->ts1.slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx231xx_buffer),
+ fh, NULL);
+*/
+
+
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
+ cx231xx_set_gpio_value(dev, 2, 0);
+
+ cx231xx_initialize_codec(dev);
+
+ mutex_unlock(&dev->lock);
+ cx231xx_start_TS1(dev);
+
+ return 0;
+}
+
+static int mpeg_release(struct file *file)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ dprintk(3, "mpeg_release()! dev=0x%p\n", dev);
+
+ if (!dev) {
+ dprintk(3, "abort!!!\n");
+ return 0;
+ }
+
+ mutex_lock(&dev->lock);
+
+ cx231xx_stop_TS1(dev);
+
+ /* do this before setting alternate! */
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
+ cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
+ cx231xx_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX231xx_END_NOW, CX231xx_MPEG_CAPTURE,
+ CX231xx_RAW_BITS_NONE);
+
+ /* FIXME: Review this crap */
+ /* Shut device down on last close */
+ if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+ if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+ /* stop mpeg capture */
+
+ msleep(500);
+ cx231xx_417_check_encoder(dev);
+
+ }
+ }
+
+ if (fh->vidq.streaming)
+ videobuf_streamoff(&fh->vidq);
+ if (fh->vidq.reading)
+ videobuf_read_stop(&fh->vidq);
+
+ videobuf_mmap_free(&fh->vidq);
+ file->private_data = NULL;
+ kfree(fh);
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+
+ /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+ /* Start mpeg encoder on first read. */
+ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+ if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
+ if (cx231xx_initialize_codec(dev) < 0)
+ return -EINVAL;
+ }
+ }
+
+ return videobuf_read_stream(&fh->vidq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ /*struct cx231xx *dev = fh->dev;*/
+
+ /*dprintk(2, "%s\n", __func__);*/
+
+ return videobuf_poll_stream(file, &fh->vidq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct cx231xx_fh *fh = file->private_data;
+ struct cx231xx *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ return videobuf_mmap_mapper(&fh->vidq, vma);
+}
+
+static struct v4l2_file_operations mpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = mpeg_open,
+ .release = mpeg_release,
+ .read = mpeg_read,
+ .poll = mpeg_poll,
+ .mmap = mpeg_mmap,
+ .ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_enumaudio = vidioc_enumaudio,
+ .vidioc_g_audio = vidioc_g_audio,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_querymenu = vidioc_querymenu,
+ .vidioc_queryctrl = vidioc_queryctrl,
+/* .vidioc_g_chip_ident = cx231xx_g_chip_ident,*/
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/* .vidioc_g_register = cx231xx_g_register,*/
+/* .vidioc_s_register = cx231xx_s_register,*/
+#endif
+};
+
+static struct video_device cx231xx_mpeg_template = {
+ .name = "cx231xx",
+ .fops = &mpeg_fops,
+ .ioctl_ops = &mpeg_ioctl_ops,
+ .minor = -1,
+ .tvnorms = CX231xx_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+void cx231xx_417_unregister(struct cx231xx *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+ dprintk(3, "%s()\n", __func__);
+
+ if (dev->v4l_device) {
+ if (-1 != dev->v4l_device->minor)
+ video_unregister_device(dev->v4l_device);
+ else
+ video_device_release(dev->v4l_device);
+ dev->v4l_device = NULL;
+ }
+}
+
+static struct video_device *cx231xx_video_dev_alloc(
+ struct cx231xx *dev,
+ struct usb_device *usbdev,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+
+ dprintk(1, "%s()\n", __func__);
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template;
+ vfd->minor = -1;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+ type, cx231xx_boards[dev->model].name);
+
+ vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->release = video_device_release;
+
+ return vfd;
+
+}
+
+int cx231xx_417_register(struct cx231xx *dev)
+{
+ /* FIXME: Port1 hardcoded here */
+ int err = -ENODEV;
+ struct cx231xx_tsport *tsport = &dev->ts1;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Set default TV standard */
+ dev->encodernorm = cx231xx_tvnorms[0];
+
+ if (dev->encodernorm.id & V4L2_STD_525_60)
+ tsport->height = 480;
+ else
+ tsport->height = 576;
+
+ tsport->width = 720;
+ cx2341x_fill_defaults(&dev->mpeg_params);
+ dev->norm = V4L2_STD_NTSC;
+
+ dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+ /* Allocate and initialize V4L video device */
+ dev->v4l_device = cx231xx_video_dev_alloc(dev,
+ dev->udev, &cx231xx_mpeg_template, "mpeg");
+ err = video_register_device(dev->v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (err < 0) {
+ dprintk(3, "%s: can't register mpeg device\n", dev->name);
+ return err;
+ }
+
+ dprintk(3, "%s: registered device video%d [mpeg]\n",
+ dev->name, dev->v4l_device->num);
+
+ return 0;
+}
diff --git a/drivers/media/video/cx231xx/cx231xx-audio.c b/drivers/media/video/cx231xx/cx231xx-audio.c
index 7cae95a2245e..30d13c15739a 100644
--- a/drivers/media/video/cx231xx/cx231xx-audio.c
+++ b/drivers/media/video/cx231xx/cx231xx-audio.c
@@ -75,6 +75,30 @@ static int cx231xx_isoc_audio_deinit(struct cx231xx *dev)
return 0;
}
+static int cx231xx_bulk_audio_deinit(struct cx231xx *dev)
+{
+ int i;
+
+ dprintk("Stopping bulk\n");
+
+ for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+ if (dev->adev.urb[i]) {
+ if (!irqs_disabled())
+ usb_kill_urb(dev->adev.urb[i]);
+ else
+ usb_unlink_urb(dev->adev.urb[i]);
+
+ usb_free_urb(dev->adev.urb[i]);
+ dev->adev.urb[i] = NULL;
+
+ kfree(dev->adev.transfer_buffer[i]);
+ dev->adev.transfer_buffer[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
static void cx231xx_audio_isocirq(struct urb *urb)
{
struct cx231xx *dev = urb->context;
@@ -100,6 +124,9 @@ static void cx231xx_audio_isocirq(struct urb *urb)
break;
}
+ if (atomic_read(&dev->stream_started) == 0)
+ return;
+
if (dev->adev.capture_pcm_substream) {
substream = dev->adev.capture_pcm_substream;
runtime = substream->runtime;
@@ -158,14 +185,95 @@ static void cx231xx_audio_isocirq(struct urb *urb)
return;
}
+static void cx231xx_audio_bulkirq(struct urb *urb)
+{
+ struct cx231xx *dev = urb->context;
+ unsigned int oldptr;
+ int period_elapsed = 0;
+ int status;
+ unsigned char *cp;
+ unsigned int stride;
+ struct snd_pcm_substream *substream;
+ struct snd_pcm_runtime *runtime;
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ dprintk("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ if (atomic_read(&dev->stream_started) == 0)
+ return;
+
+ if (dev->adev.capture_pcm_substream) {
+ substream = dev->adev.capture_pcm_substream;
+ runtime = substream->runtime;
+ stride = runtime->frame_bits >> 3;
+
+ if (1) {
+ int length = urb->actual_length /
+ stride;
+ cp = (unsigned char *)urb->transfer_buffer;
+
+ oldptr = dev->adev.hwptr_done_capture;
+ if (oldptr + length >= runtime->buffer_size) {
+ unsigned int cnt;
+
+ cnt = runtime->buffer_size - oldptr;
+ memcpy(runtime->dma_area + oldptr * stride, cp,
+ cnt * stride);
+ memcpy(runtime->dma_area, cp + cnt * stride,
+ length * stride - cnt * stride);
+ } else {
+ memcpy(runtime->dma_area + oldptr * stride, cp,
+ length * stride);
+ }
+
+ snd_pcm_stream_lock(substream);
+
+ 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;
+ }
+ snd_pcm_stream_unlock(substream);
+ }
+ if (period_elapsed)
+ snd_pcm_period_elapsed(substream);
+ }
+ urb->status = 0;
+
+ status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (status < 0) {
+ cx231xx_errdev("resubmit of audio urb failed (error=%i)\n",
+ status);
+ }
+ return;
+}
+
static int cx231xx_init_audio_isoc(struct cx231xx *dev)
{
int i, errCode;
int sb_size;
- cx231xx_info("%s: Starting AUDIO transfers\n", __func__);
+ cx231xx_info("%s: Starting ISO AUDIO transfers\n", __func__);
- sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
+ sb_size = CX231XX_ISO_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
struct urb *urb;
@@ -176,7 +284,7 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
return -ENOMEM;
memset(dev->adev.transfer_buffer[i], 0x80, sb_size);
- urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+ urb = usb_alloc_urb(CX231XX_ISO_NUM_AUDIO_PACKETS, GFP_ATOMIC);
if (!urb) {
cx231xx_errdev("usb_alloc_urb failed!\n");
for (j = 0; j < i; j++) {
@@ -194,10 +302,10 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
urb->transfer_buffer = dev->adev.transfer_buffer[i];
urb->interval = 1;
urb->complete = cx231xx_audio_isocirq;
- urb->number_of_packets = CX231XX_NUM_AUDIO_PACKETS;
+ urb->number_of_packets = CX231XX_ISO_NUM_AUDIO_PACKETS;
urb->transfer_buffer_length = sb_size;
- for (j = k = 0; j < CX231XX_NUM_AUDIO_PACKETS;
+ for (j = k = 0; j < CX231XX_ISO_NUM_AUDIO_PACKETS;
j++, k += dev->adev.max_pkt_size) {
urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length = dev->adev.max_pkt_size;
@@ -216,27 +324,56 @@ static int cx231xx_init_audio_isoc(struct cx231xx *dev)
return errCode;
}
-static int cx231xx_cmd(struct cx231xx *dev, int cmd, int arg)
+static int cx231xx_init_audio_bulk(struct cx231xx *dev)
{
- dprintk("%s transfer\n", (dev->adev.capture_stream == STREAM_ON) ?
- "stop" : "start");
+ int i, errCode;
+ int sb_size;
- switch (cmd) {
- case CX231XX_CAPTURE_STREAM_EN:
- if (dev->adev.capture_stream == STREAM_OFF && arg == 1) {
- dev->adev.capture_stream = STREAM_ON;
- cx231xx_init_audio_isoc(dev);
- } else if (dev->adev.capture_stream == STREAM_ON && arg == 0) {
- dev->adev.capture_stream = STREAM_OFF;
- cx231xx_isoc_audio_deinit(dev);
- } else {
- cx231xx_errdev("An underrun very likely occurred. "
- "Ignoring it.\n");
+ cx231xx_info("%s: Starting BULK AUDIO transfers\n", __func__);
+
+ sb_size = CX231XX_NUM_AUDIO_PACKETS * dev->adev.max_pkt_size;
+
+ for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+ struct urb *urb;
+ int j;
+
+ 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);
+ urb = usb_alloc_urb(CX231XX_NUM_AUDIO_PACKETS, GFP_ATOMIC);
+ if (!urb) {
+ cx231xx_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]);
+ }
+ return -ENOMEM;
}
- return 0;
- default:
- return -EINVAL;
+
+ urb->dev = dev->udev;
+ urb->context = dev;
+ urb->pipe = usb_rcvbulkpipe(dev->udev,
+ dev->adev.end_point_addr);
+ urb->transfer_flags = 0;
+ urb->transfer_buffer = dev->adev.transfer_buffer[i];
+ urb->complete = cx231xx_audio_bulkirq;
+ urb->transfer_buffer_length = sb_size;
+
+ dev->adev.urb[i] = urb;
+
}
+
+ for (i = 0; i < CX231XX_AUDIO_BUFS; i++) {
+ errCode = usb_submit_urb(dev->adev.urb[i], GFP_ATOMIC);
+ if (errCode < 0) {
+ cx231xx_bulk_audio_deinit(dev);
+ return errCode;
+ }
+ }
+
+ return errCode;
}
static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
@@ -300,19 +437,24 @@ static int snd_cx231xx_capture_open(struct snd_pcm_substream *substream)
/* set alternate setting for audio interface */
/* 1 - 48000 samples per sec */
- ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
+ mutex_lock(&dev->lock);
+ if (dev->USE_ISO)
+ ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 1);
+ else
+ ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
+ mutex_unlock(&dev->lock);
if (ret < 0) {
cx231xx_errdev("failed to set alternate setting !\n");
return ret;
}
- /* inform hardware to start streaming */
- ret = cx231xx_capture_start(dev, 1, Audio);
-
runtime->hw = snd_cx231xx_hw_capture;
mutex_lock(&dev->lock);
+ /* inform hardware to start streaming */
+ ret = cx231xx_capture_start(dev, 1, Audio);
+
dev->adev.users++;
mutex_unlock(&dev->lock);
@@ -330,20 +472,21 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
dprintk("closing device\n");
+ /* inform hardware to stop streaming */
+ mutex_lock(&dev->lock);
+ ret = cx231xx_capture_start(dev, 0, Audio);
+
/* set alternate setting for audio interface */
/* 1 - 48000 samples per sec */
ret = cx231xx_set_alt_setting(dev, INDEX_AUDIO, 0);
if (ret < 0) {
cx231xx_errdev("failed to set alternate setting !\n");
+ mutex_unlock(&dev->lock);
return ret;
}
- /* inform hardware to start streaming */
- ret = cx231xx_capture_start(dev, 0, Audio);
-
dev->mute = 1;
- mutex_lock(&dev->lock);
dev->adev.users--;
mutex_unlock(&dev->lock);
@@ -352,7 +495,10 @@ static int snd_cx231xx_pcm_close(struct snd_pcm_substream *substream)
dprintk("disabling audio stream!\n");
dev->adev.shutdown = 0;
dprintk("released lock\n");
- cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, 0);
+ if (atomic_read(&dev->stream_started) > 0) {
+ atomic_set(&dev->stream_started, 0);
+ schedule_work(&dev->wq_trigger);
+ }
}
return 0;
}
@@ -383,43 +529,64 @@ static int snd_cx231xx_hw_capture_free(struct snd_pcm_substream *substream)
dprintk("Stop capture, if needed\n");
- if (dev->adev.capture_stream == STREAM_ON)
- cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
+ if (atomic_read(&dev->stream_started) > 0) {
+ atomic_set(&dev->stream_started, 0);
+ schedule_work(&dev->wq_trigger);
+ }
return 0;
}
static int snd_cx231xx_prepare(struct snd_pcm_substream *substream)
{
+ struct cx231xx *dev = snd_pcm_substream_chip(substream);
+
+ dev->adev.hwptr_done_capture = 0;
+ dev->adev.capture_transfer_done = 0;
+
return 0;
}
+static void audio_trigger(struct work_struct *work)
+{
+ struct cx231xx *dev = container_of(work, struct cx231xx, wq_trigger);
+
+ if (atomic_read(&dev->stream_started)) {
+ dprintk("starting capture");
+ if (is_fw_load(dev) == 0)
+ cx25840_call(dev, core, load_fw);
+ if (dev->USE_ISO)
+ cx231xx_init_audio_isoc(dev);
+ else
+ cx231xx_init_audio_bulk(dev);
+ } else {
+ dprintk("stopping capture");
+ cx231xx_isoc_audio_deinit(dev);
+ }
+}
+
static int snd_cx231xx_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct cx231xx *dev = snd_pcm_substream_chip(substream);
int retval;
- dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
- "start" : "stop");
-
spin_lock(&dev->adev.slock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN,
- CX231XX_START_AUDIO);
- retval = 0;
+ atomic_set(&dev->stream_started, 1);
break;
case SNDRV_PCM_TRIGGER_STOP:
- cx231xx_cmd(dev, CX231XX_CAPTURE_STREAM_EN, CX231XX_STOP_AUDIO);
- retval = 0;
+ atomic_set(&dev->stream_started, 0);
break;
default:
retval = -EINVAL;
}
-
spin_unlock(&dev->adev.slock);
- return retval;
+
+ schedule_work(&dev->wq_trigger);
+
+ return 0;
}
static snd_pcm_uframes_t snd_cx231xx_capture_pointer(struct snd_pcm_substream
@@ -495,10 +662,13 @@ static int cx231xx_audio_init(struct cx231xx *dev)
pcm->info_flags = 0;
pcm->private_data = dev;
strcpy(pcm->name, "Conexant cx231xx Capture");
+ snd_card_set_dev(card, &dev->udev->dev);
strcpy(card->driver, "Cx231xx-Audio");
strcpy(card->shortname, "Cx231xx Audio");
strcpy(card->longname, "Conexant cx231xx Audio");
+ INIT_WORK(&dev->wq_trigger, audio_trigger);
+
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
diff --git a/drivers/media/video/cx231xx/cx231xx-avcore.c b/drivers/media/video/cx231xx/cx231xx-avcore.c
index c2174413ab29..c53e97295a0d 100644
--- a/drivers/media/video/cx231xx/cx231xx-avcore.c
+++ b/drivers/media/video/cx231xx/cx231xx-avcore.c
@@ -31,13 +31,16 @@
#include <linux/i2c.h>
#include <linux/mm.h>
#include <linux/mutex.h>
+#include <media/tuner.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/v4l2-chip-ident.h>
#include "cx231xx.h"
+#include "cx231xx-dif.h"
+#define TUNER_MODE_FM_RADIO 0
/******************************************************************************
-: BLOCK ARRANGEMENT :-
I2S block ----------------------|
@@ -50,6 +53,57 @@
[Video]
*******************************************************************************/
+/******************************************************************************
+ * VERVE REGISTER *
+ * *
+ ******************************************************************************/
+static int verve_write_byte(struct cx231xx *dev, u8 saddr, u8 data)
+{
+ return cx231xx_write_i2c_data(dev, VERVE_I2C_ADDRESS,
+ saddr, 1, data, 1);
+}
+
+static int verve_read_byte(struct cx231xx *dev, u8 saddr, u8 *data)
+{
+ int status;
+ u32 temp = 0;
+
+ status = cx231xx_read_i2c_data(dev, VERVE_I2C_ADDRESS,
+ saddr, 1, &temp, 1);
+ *data = (u8) temp;
+ return status;
+}
+void initGPIO(struct cx231xx *dev)
+{
+ u32 _gpio_direction = 0;
+ u32 value = 0;
+ u8 val = 0;
+
+ _gpio_direction = _gpio_direction & 0xFC0003FF;
+ _gpio_direction = _gpio_direction | 0x03FDFC00;
+ cx231xx_send_gpio_cmd(dev, _gpio_direction, (u8 *)&value, 4, 0, 0);
+
+ verve_read_byte(dev, 0x07, &val);
+ cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
+ verve_write_byte(dev, 0x07, 0xF4);
+ verve_read_byte(dev, 0x07, &val);
+ cx231xx_info(" verve_read_byte address0x07=0x%x\n", val);
+
+ cx231xx_capture_start(dev, 1, 2);
+
+ cx231xx_mode_register(dev, EP_MODE_SET, 0x0500FE00);
+ cx231xx_mode_register(dev, GBULK_BIT_EN, 0xFFFDFFFF);
+
+}
+void uninitGPIO(struct cx231xx *dev)
+{
+ u8 value[4] = { 0, 0, 0, 0 };
+
+ cx231xx_capture_start(dev, 0, 2);
+ verve_write_byte(dev, 0x07, 0x14);
+ cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ 0x68, value, 4);
+}
/******************************************************************************
* A F E - B L O C K C O N T R O L functions *
@@ -220,7 +274,7 @@ int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux)
if (ch1_setting != 0) {
status = afe_read_byte(dev, ADC_INPUT_CH1, &value);
- value &= (!INPUT_SEL_MASK);
+ value &= ~INPUT_SEL_MASK;
value |= (ch1_setting - 1) << 4;
value &= 0xff;
status = afe_write_byte(dev, ADC_INPUT_CH1, value);
@@ -228,7 +282,7 @@ int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux)
if (ch2_setting != 0) {
status = afe_read_byte(dev, ADC_INPUT_CH2, &value);
- value &= (!INPUT_SEL_MASK);
+ value &= ~INPUT_SEL_MASK;
value |= (ch2_setting - 1) << 4;
value &= 0xff;
status = afe_write_byte(dev, ADC_INPUT_CH2, value);
@@ -238,7 +292,7 @@ int cx231xx_afe_set_input_mux(struct cx231xx *dev, u32 input_mux)
7 less than the input number */
if (ch3_setting != 0) {
status = afe_read_byte(dev, ADC_INPUT_CH3, &value);
- value &= (!INPUT_SEL_MASK);
+ value &= ~INPUT_SEL_MASK;
value |= (ch3_setting - 1) << 4;
value &= 0xff;
status = afe_write_byte(dev, ADC_INPUT_CH3, value);
@@ -258,7 +312,7 @@ int cx231xx_afe_set_mode(struct cx231xx *dev, enum AFE_MODE mode)
switch (mode) {
case AFE_MODE_LOW_IF:
- /* SetupAFEforLowIF(); */
+ cx231xx_Setup_AFE_for_LowIF(dev);
break;
case AFE_MODE_BASEBAND:
status = cx231xx_afe_setup_AFE_for_baseband(dev);
@@ -291,8 +345,16 @@ int cx231xx_afe_update_power_control(struct cx231xx *dev,
int status = 0;
switch (dev->model) {
+ case CX231XX_BOARD_CNXT_CARRAERA:
case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_SHELBY:
case CX231XX_BOARD_CNXT_RDU_250:
+ case CX231XX_BOARD_CNXT_RDE_253S:
+ case CX231XX_BOARD_CNXT_RDU_253S:
+ case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
+ case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_HAUPPAUGE_USBLIVE2:
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
if (avmode == POLARIS_AVMODE_ANALOGT_TV) {
while (afe_power_status != (FLD_PWRDN_TUNING_BIAS |
FLD_PWRDN_ENABLE_PLL)) {
@@ -483,6 +545,17 @@ static int vid_blk_read_word(struct cx231xx *dev, u16 saddr, u32 *data)
return cx231xx_read_i2c_data(dev, VID_BLK_I2C_ADDRESS,
saddr, 2, data, 4);
}
+int cx231xx_check_fw(struct cx231xx *dev)
+{
+ u8 temp = 0;
+ int status = 0;
+ status = vid_blk_read_byte(dev, DL_CTL_ADDRESS_LOW, &temp);
+ if (status < 0)
+ return status;
+ else
+ return temp;
+
+}
int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
{
@@ -521,9 +594,15 @@ int cx231xx_set_video_input_mux(struct cx231xx *dev, u8 input)
return status;
}
}
- status = cx231xx_set_decoder_video_input(dev,
+ if (dev->tuner_type == TUNER_NXP_TDA18271)
+ status = cx231xx_set_decoder_video_input(dev,
+ CX231XX_VMUX_TELEVISION,
+ INPUT(input)->vmux);
+ else
+ status = cx231xx_set_decoder_video_input(dev,
CX231XX_VMUX_COMPOSITE1,
INPUT(input)->vmux);
+
break;
default:
cx231xx_errdev("%s: set_power_mode : Unknown Input %d !\n",
@@ -578,12 +657,12 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
value |= (1 << 7);
status = vid_blk_write_word(dev, OUT_CTRL1, value);
- /* Set vip 1.1 output mode */
+ /* Set output mode */
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
OUT_CTRL1,
FLD_OUT_MODE,
- OUT_MODE_VIP11);
+ dev->board.output_mode);
/* Tell DIF object to go to baseband mode */
status = cx231xx_dif_set_standard(dev, DIF_USE_BASEBAND);
@@ -681,7 +760,9 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
case CX231XX_VMUX_CABLE:
default:
switch (dev->model) {
+ case CX231XX_BOARD_CNXT_CARRAERA:
case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_SHELBY:
case CX231XX_BOARD_CNXT_RDU_250:
/* Disable the use of DIF */
@@ -699,11 +780,11 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
value |= (1 << 7);
status = vid_blk_write_word(dev, OUT_CTRL1, value);
- /* Set vip 1.1 output mode */
+ /* Set output mode */
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
OUT_CTRL1, FLD_OUT_MODE,
- OUT_MODE_VIP11);
+ dev->board.output_mode);
/* Tell DIF object to go to baseband mode */
status = cx231xx_dif_set_standard(dev,
@@ -790,11 +871,11 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
(FLD_OEF_AGC_IF);
status = vid_blk_write_word(dev, PIN_CTRL, value);
- /* Set vip 1.1 output mode */
+ /* Set output mode */
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
OUT_CTRL1, FLD_OUT_MODE,
- OUT_MODE_VIP11);
+ dev->board.output_mode);
/* Disable auto config of registers */
status = cx231xx_read_modify_write_i2c_dword(dev,
@@ -816,9 +897,21 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
/* Set VGA_SEL (for audio control) (bit 7-8) */
status = vid_blk_read_word(dev, AFE_CTRL, &value);
+ /*Set Func mode:01-DIF 10-baseband 11-YUV*/
+ value &= (~(FLD_FUNC_MODE));
+ value |= 0x800000;
+
value |= FLD_VGA_SEL_CH3 | FLD_VGA_SEL_CH2;
status = vid_blk_write_word(dev, AFE_CTRL, value);
+
+ if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ status = vid_blk_read_word(dev, PIN_CTRL,
+ &value);
+ status = vid_blk_write_word(dev, PIN_CTRL,
+ (value & 0xFFFFFFEF));
+ }
+
break;
}
@@ -840,6 +933,39 @@ int cx231xx_set_decoder_video_input(struct cx231xx *dev,
return status;
}
+void cx231xx_enable656(struct cx231xx *dev)
+{
+ u8 temp = 0;
+ int status;
+ /*enable TS1 data[0:7] as output to export 656*/
+
+ status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0xFF);
+
+ /*enable TS1 clock as output to export 656*/
+
+ status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+ temp = temp|0x04;
+
+ status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_enable656);
+
+void cx231xx_disable656(struct cx231xx *dev)
+{
+ u8 temp = 0;
+ int status;
+
+
+ status = vid_blk_write_byte(dev, TS1_PIN_CTL0, 0x00);
+
+ status = vid_blk_read_byte(dev, TS1_PIN_CTL1, &temp);
+ temp = temp&0xFB;
+
+ status = vid_blk_write_byte(dev, TS1_PIN_CTL1, temp);
+}
+EXPORT_SYMBOL_GPL(cx231xx_disable656);
+
/*
* Handle any video-mode specific overrides that are different
* on a per video standards basis after touching the MODE_CTRL
@@ -868,12 +994,12 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
VID_BLK_I2C_ADDRESS,
VERT_TIM_CTRL,
FLD_VACTIVE_CNT,
- 0x1E6000);
+ 0x1E7000);
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
VERT_TIM_CTRL,
FLD_V656BLANK_CNT,
- 0x1E000000);
+ 0x1C000000);
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
@@ -881,12 +1007,27 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
FLD_HBLANK_CNT,
cx231xx_set_field
(FLD_HBLANK_CNT, 0x79));
+
} else if (dev->norm & V4L2_STD_SECAM) {
cx231xx_info("do_mode_ctrl_overrides SECAM\n");
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
VERT_TIM_CTRL,
- FLD_VBLANK_CNT, 0x24);
+ FLD_VBLANK_CNT, 0x20);
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_VACTIVE_CNT,
+ cx231xx_set_field
+ (FLD_VACTIVE_CNT,
+ 0x244));
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_V656BLANK_CNT,
+ cx231xx_set_field
+ (FLD_V656BLANK_CNT,
+ 0x24));
/* Adjust the active video horizontal start point */
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
@@ -899,7 +1040,21 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
VERT_TIM_CTRL,
- FLD_VBLANK_CNT, 0x24);
+ FLD_VBLANK_CNT, 0x20);
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_VACTIVE_CNT,
+ cx231xx_set_field
+ (FLD_VACTIVE_CNT,
+ 0x244));
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ VERT_TIM_CTRL,
+ FLD_V656BLANK_CNT,
+ cx231xx_set_field
+ (FLD_V656BLANK_CNT,
+ 0x24));
/* Adjust the active video horizontal start point */
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
@@ -907,11 +1062,28 @@ int cx231xx_do_mode_ctrl_overrides(struct cx231xx *dev)
FLD_HBLANK_CNT,
cx231xx_set_field
(FLD_HBLANK_CNT, 0x85));
+
}
return status;
}
+int cx231xx_unmute_audio(struct cx231xx *dev)
+{
+ return vid_blk_write_byte(dev, PATH1_VOL_CTL, 0x24);
+}
+EXPORT_SYMBOL_GPL(cx231xx_unmute_audio);
+
+int stopAudioFirmware(struct cx231xx *dev)
+{
+ return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x03);
+}
+
+int restartAudioFirmware(struct cx231xx *dev)
+{
+ return vid_blk_write_byte(dev, DL_CTL_CONTROL, 0x13);
+}
+
int cx231xx_set_audio_input(struct cx231xx *dev, u8 input)
{
int status = 0;
@@ -970,6 +1142,7 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
/* unmute all, AC97 in, independence mode
adr 08d0, data 0x00063073 */
+ status = vid_blk_write_word(dev, DL_CTL, 0x3000001);
status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063073);
/* set AVC maximum threshold, adr 08d4, dat ffff0024 */
@@ -985,7 +1158,7 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
case AUDIO_INPUT_TUNER_TV:
default:
-
+ status = stopAudioFirmware(dev);
/* Setup SRC sources and clocks */
status = vid_blk_write_word(dev, BAND_OUT_SEL,
cx231xx_set_field(FLD_SRC6_IN_SEL, 0x00) |
@@ -1013,18 +1186,32 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
status = vid_blk_write_word(dev, PATH1_CTL1, 0x1F063870);
/* setAudioStandard(_audio_standard); */
-
status = vid_blk_write_word(dev, PATH1_CTL1, 0x00063870);
- switch (dev->model) {
- case CX231XX_BOARD_CNXT_RDE_250:
- case CX231XX_BOARD_CNXT_RDU_250:
+
+ status = restartAudioFirmware(dev);
+
+ switch (dev->board.tuner_type) {
+ case TUNER_XC5000:
+ /* SIF passthrough at 28.6363 MHz sample rate */
status = cx231xx_read_modify_write_i2c_dword(dev,
VID_BLK_I2C_ADDRESS,
CHIP_CTRL,
FLD_SIF_EN,
cx231xx_set_field(FLD_SIF_EN, 1));
break;
+ case TUNER_NXP_TDA18271:
+ /* Normal mode: SIF passthrough at 14.32 MHz */
+ status = cx231xx_read_modify_write_i2c_dword(dev,
+ VID_BLK_I2C_ADDRESS,
+ CHIP_CTRL,
+ FLD_SIF_EN,
+ cx231xx_set_field(FLD_SIF_EN, 0));
+ break;
default:
+ /* This is just a casual suggestion to people adding
+ new boards in case they use a tuner type we don't
+ currently know about */
+ printk(KERN_INFO "Unknown tuner type configuring SIF");
break;
}
break;
@@ -1049,18 +1236,6 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
return status;
}
-/* Set resolution of the video */
-int cx231xx_resolution_set(struct cx231xx *dev)
-{
- /* set horzontal scale */
- int status = vid_blk_write_word(dev, HSCALE_CTRL, dev->hscale);
- if (status)
- return status;
-
- /* set vertical scale */
- return vid_blk_write_word(dev, VSCALE_CTRL, dev->vscale);
-}
-
/******************************************************************************
* C H I P Specific C O N T R O L functions *
******************************************************************************/
@@ -1094,34 +1269,350 @@ int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
return status;
}
-int cx231xx_enable_i2c_for_tuner(struct cx231xx *dev, u8 I2CIndex)
+int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3)
{
u8 value[4] = { 0, 0, 0, 0 };
int status = 0;
-
- cx231xx_info("Changing the i2c port for tuner to %d\n", I2CIndex);
+ bool current_is_port_3;
status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
PWR_CTL_EN, value, 4);
if (status < 0)
return status;
- if (I2CIndex == I2C_1) {
- if (value[0] & I2C_DEMOD_EN) {
- value[0] &= ~I2C_DEMOD_EN;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
- PWR_CTL_EN, value, 4);
- }
+ current_is_port_3 = value[0] & I2C_DEMOD_EN ? true : false;
+
+ /* Just return, if already using the right port */
+ if (current_is_port_3 == is_port_3)
+ return 0;
+
+ if (is_port_3)
+ value[0] |= I2C_DEMOD_EN;
+ else
+ value[0] &= ~I2C_DEMOD_EN;
+
+ cx231xx_info("Changing the i2c master port to %d\n",
+ is_port_3 ? 3 : 1);
+
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+
+ return status;
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_enable_i2c_port_3);
+
+void update_HH_register_after_set_DIF(struct cx231xx *dev)
+{
+/*
+ u8 status = 0;
+ u32 value = 0;
+
+ vid_blk_write_word(dev, PIN_CTRL, 0xA0FFF82F);
+ vid_blk_write_word(dev, DIF_MISC_CTRL, 0x0A203F11);
+ vid_blk_write_word(dev, DIF_SRC_PHASE_INC, 0x1BEFBF06);
+
+ status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+ vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
+ status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+*/
+}
+
+void cx231xx_dump_HH_reg(struct cx231xx *dev)
+{
+ u8 status = 0;
+ u32 value = 0;
+ u16 i = 0;
+
+ value = 0x45005390;
+ status = vid_blk_write_word(dev, 0x104, value);
+
+ for (i = 0x100; i < 0x140; i++) {
+ status = vid_blk_read_word(dev, i, &value);
+ cx231xx_info("reg0x%x=0x%x\n", i, value);
+ i = i+3;
+ }
+
+ for (i = 0x300; i < 0x400; i++) {
+ status = vid_blk_read_word(dev, i, &value);
+ cx231xx_info("reg0x%x=0x%x\n", i, value);
+ i = i+3;
+ }
+
+ for (i = 0x400; i < 0x440; i++) {
+ status = vid_blk_read_word(dev, i, &value);
+ cx231xx_info("reg0x%x=0x%x\n", i, value);
+ i = i+3;
+ }
+
+ status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+ cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
+ vid_blk_write_word(dev, AFE_CTRL_C2HH_SRC_CTRL, 0x4485D390);
+ status = vid_blk_read_word(dev, AFE_CTRL_C2HH_SRC_CTRL, &value);
+ cx231xx_info("AFE_CTRL_C2HH_SRC_CTRL=0x%x\n", value);
+}
+
+void cx231xx_dump_SC_reg(struct cx231xx *dev)
+{
+ u8 value[4] = { 0, 0, 0, 0 };
+ int status = 0;
+ cx231xx_info("cx231xx_dump_SC_reg %s!\n", __TIME__);
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, BOARD_CFG_STAT,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", BOARD_CFG_STAT, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS_MODE_REG,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS_MODE_REG, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_CFG_REG,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_CFG_REG, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS1_LENGTH_REG,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS1_LENGTH_REG, value[0],
+ value[1], value[2], value[3]);
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_CFG_REG,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_CFG_REG, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, TS2_LENGTH_REG,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", TS2_LENGTH_REG, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, EP_MODE_SET,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", EP_MODE_SET, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN1,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN1, value[0],
+ value[1], value[2], value[3]);
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN2,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN2, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_PTN3,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_PTN3, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK0,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK0, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK1,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK1, value[0],
+ value[1], value[2], value[3]);
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_PWR_MASK2,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_PWR_MASK2, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_GAIN,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_GAIN, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_CAR_REG,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_CAR_REG, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG1,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG1, value[0],
+ value[1], value[2], value[3]);
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, CIR_OT_CFG2,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", CIR_OT_CFG2, value[0],
+ value[1], value[2], value[3]);
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+ value, 4);
+ cx231xx_info("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN, value[0],
+ value[1], value[2], value[3]);
+
+
+}
+
+void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev)
+
+{
+ u8 status = 0;
+ u8 value = 0;
+
+
+
+ status = afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+ value = (value & 0xFE)|0x01;
+ status = afe_write_byte(dev, ADC_STATUS2_CH3, value);
+
+ status = afe_read_byte(dev, ADC_STATUS2_CH3, &value);
+ value = (value & 0xFE)|0x00;
+ status = afe_write_byte(dev, ADC_STATUS2_CH3, value);
+
+
+/*
+ config colibri to lo-if mode
+
+ FIXME: ntf_mode = 2'b00 by default. But set 0x1 would reduce
+ the diff IF input by half,
+
+ for low-if agc defect
+*/
+
+ status = afe_read_byte(dev, ADC_NTF_PRECLMP_EN_CH3, &value);
+ value = (value & 0xFC)|0x00;
+ status = afe_write_byte(dev, ADC_NTF_PRECLMP_EN_CH3, value);
+
+ status = afe_read_byte(dev, ADC_INPUT_CH3, &value);
+ value = (value & 0xF9)|0x02;
+ status = afe_write_byte(dev, ADC_INPUT_CH3, value);
+
+ status = afe_read_byte(dev, ADC_FB_FRCRST_CH3, &value);
+ value = (value & 0xFB)|0x04;
+ status = afe_write_byte(dev, ADC_FB_FRCRST_CH3, value);
+
+ status = afe_read_byte(dev, ADC_DCSERVO_DEM_CH3, &value);
+ value = (value & 0xFC)|0x03;
+ status = afe_write_byte(dev, ADC_DCSERVO_DEM_CH3, value);
+
+ status = afe_read_byte(dev, ADC_CTRL_DAC1_CH3, &value);
+ value = (value & 0xFB)|0x04;
+ status = afe_write_byte(dev, ADC_CTRL_DAC1_CH3, value);
+
+ status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+ value = (value & 0xF8)|0x06;
+ status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+
+ status = afe_read_byte(dev, ADC_CTRL_DAC23_CH3, &value);
+ value = (value & 0x8F)|0x40;
+ status = afe_write_byte(dev, ADC_CTRL_DAC23_CH3, value);
+
+ status = afe_read_byte(dev, ADC_PWRDN_CLAMP_CH3, &value);
+ value = (value & 0xDF)|0x20;
+ status = afe_write_byte(dev, ADC_PWRDN_CLAMP_CH3, value);
+}
+
+void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
+ u8 spectral_invert, u32 mode)
+{
+ u32 colibri_carrier_offset = 0;
+ u8 status = 0;
+ u32 func_mode = 0x01; /* Device has a DIF if this function is called */
+ u32 standard = 0;
+ u8 value[4] = { 0, 0, 0, 0 };
+
+ cx231xx_info("Enter cx231xx_set_Colibri_For_LowIF()\n");
+ value[0] = (u8) 0x6F;
+ value[1] = (u8) 0x6F;
+ value[2] = (u8) 0x6F;
+ value[3] = (u8) 0x6F;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+
+ /*Set colibri for low IF*/
+ status = cx231xx_afe_set_mode(dev, AFE_MODE_LOW_IF);
+
+ /* Set C2HH for low IF operation.*/
+ standard = dev->norm;
+ status = cx231xx_dif_configure_C2HH_for_low_IF(dev, dev->active_mode,
+ func_mode, standard);
+
+ /* Get colibri offsets.*/
+ colibri_carrier_offset = cx231xx_Get_Colibri_CarrierOffset(mode,
+ standard);
+
+ cx231xx_info("colibri_carrier_offset=%d, standard=0x%x\n",
+ colibri_carrier_offset, standard);
+
+ /* Set the band Pass filter for DIF*/
+ cx231xx_set_DIF_bandpass(dev, (if_freq+colibri_carrier_offset),
+ spectral_invert, mode);
+}
+
+u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd)
+{
+ u32 colibri_carrier_offset = 0;
+
+ if (mode == TUNER_MODE_FM_RADIO) {
+ colibri_carrier_offset = 1100000;
+ } else if (standerd & (V4L2_STD_MN | V4L2_STD_NTSC_M_JP)) {
+ colibri_carrier_offset = 4832000; /*4.83MHz */
+ } else if (standerd & (V4L2_STD_PAL_B | V4L2_STD_PAL_G)) {
+ colibri_carrier_offset = 2700000; /*2.70MHz */
+ } else if (standerd & (V4L2_STD_PAL_D | V4L2_STD_PAL_I
+ | V4L2_STD_SECAM)) {
+ colibri_carrier_offset = 2100000; /*2.10MHz */
+ }
+
+ return colibri_carrier_offset;
+}
+
+void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
+ u8 spectral_invert, u32 mode)
+{
+ unsigned long pll_freq_word;
+ int status = 0;
+ u32 dif_misc_ctrl_value = 0;
+ u64 pll_freq_u64 = 0;
+ u32 i = 0;
+
+ cx231xx_info("if_freq=%d;spectral_invert=0x%x;mode=0x%x\n",
+ if_freq, spectral_invert, mode);
+
+
+ if (mode == TUNER_MODE_FM_RADIO) {
+ pll_freq_word = 0x905A1CAC;
+ status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word);
+
+ } else /*KSPROPERTY_TUNER_MODE_TV*/{
+ /* Calculate the PLL frequency word based on the adjusted if_freq*/
+ pll_freq_word = if_freq;
+ pll_freq_u64 = (u64)pll_freq_word << 28L;
+ do_div(pll_freq_u64, 50000000);
+ pll_freq_word = (u32)pll_freq_u64;
+ /*pll_freq_word = 0x3463497;*/
+ status = vid_blk_write_word(dev, DIF_PLL_FREQ_WORD, pll_freq_word);
+
+ if (spectral_invert) {
+ if_freq -= 400000;
+ /* Enable Spectral Invert*/
+ status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+ &dif_misc_ctrl_value);
+ dif_misc_ctrl_value = dif_misc_ctrl_value | 0x00200000;
+ status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+ dif_misc_ctrl_value);
} else {
- if (!(value[0] & I2C_DEMOD_EN)) {
- value[0] |= I2C_DEMOD_EN;
- status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
- PWR_CTL_EN, value, 4);
- }
+ if_freq += 400000;
+ /* Disable Spectral Invert*/
+ status = vid_blk_read_word(dev, DIF_MISC_CTRL,
+ &dif_misc_ctrl_value);
+ dif_misc_ctrl_value = dif_misc_ctrl_value & 0xFFDFFFFF;
+ status = vid_blk_write_word(dev, DIF_MISC_CTRL,
+ dif_misc_ctrl_value);
}
- return status;
+ if_freq = (if_freq/100000)*100000;
+ if (if_freq < 3000000)
+ if_freq = 3000000;
+
+ if (if_freq > 16000000)
+ if_freq = 16000000;
+ }
+
+ cx231xx_info("Enter IF=%zd\n",
+ sizeof(Dif_set_array)/sizeof(struct dif_settings));
+ for (i = 0; i < sizeof(Dif_set_array)/sizeof(struct dif_settings); i++) {
+ if (Dif_set_array[i].if_freq == if_freq) {
+ status = vid_blk_write_word(dev,
+ Dif_set_array[i].register_address, Dif_set_array[i].value);
+ }
+ }
}
/******************************************************************************
@@ -1132,6 +1623,7 @@ int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
{
int status = 0;
+
if (mode == V4L2_TUNER_RADIO) {
/* C2HH */
/* lo if big signal */
@@ -1174,6 +1666,7 @@ int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
VID_BLK_I2C_ADDRESS, 32,
AUD_IO_CTRL, 0, 31, 0x00000003);
} else if ((standard == V4L2_STD_PAL_I) |
+ (standard & V4L2_STD_PAL_D) |
(standard & V4L2_STD_SECAM)) {
/* C2HH setup */
/* lo if big signal */
@@ -1232,10 +1725,18 @@ int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard)
dev->norm = standard;
switch (dev->model) {
+ case CX231XX_BOARD_CNXT_CARRAERA:
case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_SHELBY:
case CX231XX_BOARD_CNXT_RDU_250:
+ case CX231XX_BOARD_CNXT_VIDEO_GRABBER:
+ case CX231XX_BOARD_HAUPPAUGE_EXETER:
func_mode = 0x03;
break;
+ case CX231XX_BOARD_CNXT_RDE_253S:
+ case CX231XX_BOARD_CNXT_RDU_253S:
+ func_mode = 0x01;
+ break;
default:
func_mode = 0x01;
}
@@ -1617,17 +2118,27 @@ int cx231xx_tuner_post_channel_change(struct cx231xx *dev)
{
int status = 0;
u32 dwval;
-
+ cx231xx_info("cx231xx_tuner_post_channel_change dev->tuner_type =0%d\n",
+ dev->tuner_type);
/* Set the RF and IF k_agc values to 4 for PAL/NTSC and 8 for
* SECAM L/B/D standards */
status = vid_blk_read_word(dev, DIF_AGC_IF_REF, &dwval);
dwval &= ~(FLD_DIF_K_AGC_RF | FLD_DIF_K_AGC_IF);
if (dev->norm & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_B |
- V4L2_STD_SECAM_D))
- dwval |= 0x88000000;
- else
- dwval |= 0x44000000;
+ V4L2_STD_SECAM_D)) {
+ if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ dwval &= ~FLD_DIF_IF_REF;
+ dwval |= 0x88000300;
+ } else
+ dwval |= 0x88000000;
+ } else {
+ if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ dwval &= ~FLD_DIF_IF_REF;
+ dwval |= 0xCC000300;
+ } else
+ dwval |= 0x44000000;
+ }
status = vid_blk_write_word(dev, DIF_AGC_IF_REF, dwval);
@@ -1714,8 +2225,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
return 0;
}
- cx231xx_info(" setPowerMode::mode = %d\n", mode);
-
status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value,
4);
if (status < 0)
@@ -1761,7 +2270,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
case POLARIS_AVMODE_ANALOGT_TV:
- tmp &= (~PWR_DEMOD_EN);
+ tmp |= PWR_DEMOD_EN;
tmp |= (I2C_DEMOD_EN);
value[0] = (u8) tmp;
value[1] = (u8) (tmp >> 8);
@@ -1814,14 +2323,18 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
msleep(PWR_SLEEP_INTERVAL);
}
- if ((dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
- (dev->model == CX231XX_BOARD_CNXT_RDU_250)) {
- /* tuner path to channel 1 from port 3 */
- cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+ if (dev->board.tuner_type != TUNER_ABSENT) {
+ /* Enable tuner */
+ cx231xx_enable_i2c_port_3(dev, true);
+
+ /* reset the Tuner */
+ if (dev->board.tuner_gpio)
+ cx231xx_gpio_set(dev, dev->board.tuner_gpio);
if (dev->cx231xx_reset_analog_tuner)
dev->cx231xx_reset_analog_tuner(dev);
}
+
break;
case POLARIS_AVMODE_DIGITAL:
@@ -1856,6 +2369,7 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
msleep(PWR_SLEEP_INTERVAL);
}
+ tmp &= (~PWR_AV_MODE);
tmp |= POLARIS_AVMODE_DIGITAL | I2C_DEMOD_EN;
value[0] = (u8) tmp;
value[1] = (u8) (tmp >> 8);
@@ -1876,10 +2390,19 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
msleep(PWR_SLEEP_INTERVAL);
}
- if ((dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
- (dev->model == CX231XX_BOARD_CNXT_RDU_250)) {
- /* tuner path to channel 1 from port 3 */
- cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+ if (dev->board.tuner_type != TUNER_ABSENT) {
+ /*
+ * Enable tuner
+ * Hauppauge Exeter seems to need to do something different!
+ */
+ if (dev->model == CX231XX_BOARD_HAUPPAUGE_EXETER)
+ cx231xx_enable_i2c_port_3(dev, false);
+ else
+ cx231xx_enable_i2c_port_3(dev, true);
+
+ /* reset the Tuner */
+ if (dev->board.tuner_gpio)
+ cx231xx_gpio_set(dev, dev->board.tuner_gpio);
if (dev->cx231xx_reset_analog_tuner)
dev->cx231xx_reset_analog_tuner(dev);
@@ -1913,9 +2436,6 @@ int cx231xx_set_power_mode(struct cx231xx *dev, enum AV_MODE mode)
status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN, value,
4);
- cx231xx_info(" The data of PWR_CTL_EN register 0x74"
- "=0x%0x,0x%0x,0x%0x,0x%0x\n",
- value[0], value[1], value[2], value[3]);
return status;
}
@@ -2000,6 +2520,8 @@ int cx231xx_stop_stream(struct cx231xx *dev, u32 ep_mask)
int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
{
int status = 0;
+ u32 value = 0;
+ u8 val[4] = { 0, 0, 0, 0 };
if (dev->udev->speed == USB_SPEED_HIGH) {
switch (media_type) {
@@ -2026,10 +2548,36 @@ int cx231xx_initialize_stream_xfer(struct cx231xx *dev, u32 media_type)
break;
case 4: /* ts1 */
- cx231xx_info("%s: set ts1 registers\n", __func__);
+ cx231xx_info("%s: set ts1 registers", __func__);
+
+ if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+ cx231xx_info(" MPEG\n");
+ value &= 0xFFFFFFFC;
+ value |= 0x3;
+
+ status = cx231xx_mode_register(dev, TS_MODE_REG, value);
+
+ val[0] = 0x04;
+ val[1] = 0xA3;
+ val[2] = 0x3B;
+ val[3] = 0x00;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS1_CFG_REG, val, 4);
+
+ val[0] = 0x00;
+ val[1] = 0x08;
+ val[2] = 0x00;
+ val[3] = 0x08;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS1_LENGTH_REG, val, 4);
+
+ } else {
+ cx231xx_info(" BDA\n");
status = cx231xx_mode_register(dev, TS_MODE_REG, 0x101);
- status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x400);
+ status = cx231xx_mode_register(dev, TS1_CFG_REG, 0x010);
+ }
break;
+
case 6: /* ts1 parallel mode */
cx231xx_info("%s: set ts1 parrallel mode registers\n",
__func__);
@@ -2128,7 +2676,7 @@ EXPORT_SYMBOL_GPL(cx231xx_capture_start);
/*****************************************************************************
* G P I O B I T control functions *
******************************************************************************/
-int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val)
+int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
{
int status = 0;
@@ -2137,7 +2685,7 @@ int cx231xx_set_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val)
return status;
}
-int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val)
+int cx231xx_get_gpio_bit(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val)
{
int status = 0;
@@ -2344,7 +2892,7 @@ int cx231xx_gpio_i2c_write_byte(struct cx231xx *dev, u8 data)
return status;
}
-int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 * buf)
+int cx231xx_gpio_i2c_read_byte(struct cx231xx *dev, u8 *buf)
{
u8 value = 0;
int status = 0;
@@ -2494,7 +3042,7 @@ int cx231xx_gpio_i2c_write_nak(struct cx231xx *dev)
/* cx231xx_gpio_i2c_read
* Function to read data from gpio based I2C interface
*/
-int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 * buf, u8 len)
+int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
{
int status = 0;
int i = 0;
@@ -2538,7 +3086,7 @@ int cx231xx_gpio_i2c_read(struct cx231xx *dev, u8 dev_addr, u8 * buf, u8 len)
/* cx231xx_gpio_i2c_write
* Function to write data to gpio based I2C interface
*/
-int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 * buf, u8 len)
+int cx231xx_gpio_i2c_write(struct cx231xx *dev, u8 dev_addr, u8 *buf, u8 len)
{
int status = 0;
int i = 0;
diff --git a/drivers/media/video/cx231xx/cx231xx-cards.c b/drivers/media/video/cx231xx/cx231xx-cards.c
index 6bdc0ef18119..588f3e8f028b 100644
--- a/drivers/media/video/cx231xx/cx231xx-cards.c
+++ b/drivers/media/video/cx231xx/cx231xx-cards.c
@@ -32,7 +32,9 @@
#include <media/v4l2-chip-ident.h>
#include <media/cx25840.h>
+#include "dvb-usb-ids.h"
#include "xc5000.h"
+#include "tda18271.h"
#include "cx231xx.h"
@@ -40,6 +42,10 @@ static int tuner = -1;
module_param(tuner, int, 0444);
MODULE_PARM_DESC(tuner, "tuner type");
+static int transfer_mode = 1;
+module_param(transfer_mode, int, 0444);
+MODULE_PARM_DESC(transfer_mode, "transfer mode (1-ISO or 0-BULK)");
+
static unsigned int disable_ir;
module_param(disable_ir, int, 0444);
MODULE_PARM_DESC(disable_ir, "disable infrared remote support");
@@ -85,8 +91,8 @@ struct cx231xx_board cx231xx_boards[] = {
}
},
},
- [CX231XX_BOARD_CNXT_RDE_250] = {
- .name = "Conexant Hybrid TV - RDE250",
+ [CX231XX_BOARD_CNXT_CARRAERA] = {
+ .name = "Conexant Hybrid TV - CARRAERA",
.tuner_type = TUNER_XC5000,
.tuner_addr = 0x61,
.tuner_gpio = RDE250_XCV_TUNER,
@@ -94,6 +100,7 @@ struct cx231xx_board cx231xx_boards[] = {
.tuner_scl_gpio = 0x1a,
.tuner_sda_gpio = 0x1b,
.decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
.demod_xfer_mode = 0,
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
@@ -124,9 +131,8 @@ struct cx231xx_board cx231xx_boards[] = {
}
},
},
-
- [CX231XX_BOARD_CNXT_RDU_250] = {
- .name = "Conexant Hybrid TV - RDU250",
+ [CX231XX_BOARD_CNXT_SHELBY] = {
+ .name = "Conexant Hybrid TV - SHELBY",
.tuner_type = TUNER_XC5000,
.tuner_addr = 0x61,
.tuner_gpio = RDE250_XCV_TUNER,
@@ -134,6 +140,7 @@ struct cx231xx_board cx231xx_boards[] = {
.tuner_scl_gpio = 0x1a,
.tuner_sda_gpio = 0x1b,
.decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
.demod_xfer_mode = 0,
.ctl_pin_status_mask = 0xFFFFFFC4,
.agc_analog_digital_select_gpio = 0x0c,
@@ -164,6 +171,270 @@ struct cx231xx_board cx231xx_boards[] = {
}
},
},
+ [CX231XX_BOARD_CNXT_RDE_253S] = {
+ .name = "Conexant Hybrid TV - RDE253S",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x1c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x02,
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }
+ },
+ },
+
+ [CX231XX_BOARD_CNXT_RDU_253S] = {
+ .name = "Conexant Hybrid TV - RDU253S",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x1c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x02,
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }
+ },
+ },
+ [CX231XX_BOARD_CNXT_VIDEO_GRABBER] = {
+ .name = "Conexant VIDEO GRABBER",
+ .tuner_type = TUNER_ABSENT,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x1c,
+ .gpio_pin_status_mask = 0x4001000,
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = NULL,
+ }
+ },
+ },
+ [CX231XX_BOARD_CNXT_RDE_250] = {
+ .name = "Conexant Hybrid TV - rde 250",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x02,
+ .norm = V4L2_STD_PAL,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }
+ },
+ },
+ [CX231XX_BOARD_CNXT_RDU_250] = {
+ .name = "Conexant Hybrid TV - RDU 250",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x61,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x32,
+ .norm = V4L2_STD_NTSC,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = NULL,
+ }
+ },
+ },
+ [CX231XX_BOARD_HAUPPAUGE_EXETER] = {
+ .name = "Hauppauge EXETER",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .tuner_gpio = RDE250_XCV_TUNER,
+ .tuner_sif_gpio = 0x05,
+ .tuner_scl_gpio = 0x1a,
+ .tuner_sda_gpio = 0x1b,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 1,
+ .demod_i2c_master = 2,
+ .has_dvb = 1,
+ .demod_addr = 0x0e,
+ .norm = V4L2_STD_NTSC,
+
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ } },
+ },
+ [CX231XX_BOARD_HAUPPAUGE_USBLIVE2] = {
+ .name = "Hauppauge USB Live 2",
+ .tuner_type = TUNER_ABSENT,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x0c,
+ .gpio_pin_status_mask = 0x4001000,
+ .norm = V4L2_STD_NTSC,
+ .input = {{
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ } },
+ },
+ [CX231XX_BOARD_PV_PLAYTV_USB_HYBRID] = {
+ .name = "Pixelview PlayTV USB Hybrid",
+ .tuner_type = TUNER_NXP_TDA18271,
+ .tuner_addr = 0x60,
+ .decoder = CX231XX_AVDECODER,
+ .output_mode = OUT_MODE_VIP11,
+ .demod_xfer_mode = 0,
+ .ctl_pin_status_mask = 0xFFFFFFC4,
+ .agc_analog_digital_select_gpio = 0x00, /* According with PV cxPolaris.inf file */
+ .tuner_sif_gpio = -1,
+ .tuner_scl_gpio = -1,
+ .tuner_sda_gpio = -1,
+ .gpio_pin_status_mask = 0x4001000,
+ .tuner_i2c_master = 2,
+ .demod_i2c_master = 1,
+ .ir_i2c_master = 2,
+ .rc_map_name = RC_MAP_PIXELVIEW_002T,
+ .has_dvb = 1,
+ .demod_addr = 0x10,
+ .norm = V4L2_STD_PAL_M,
+ .input = {{
+ .type = CX231XX_VMUX_TELEVISION,
+ .vmux = CX231XX_VIN_3_1,
+ .amux = CX231XX_AMUX_VIDEO,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_COMPOSITE1,
+ .vmux = CX231XX_VIN_2_1,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ }, {
+ .type = CX231XX_VMUX_SVIDEO,
+ .vmux = CX231XX_VIN_1_1 |
+ (CX231XX_VIN_1_2 << 8) |
+ CX25840_SVIDEO_ON,
+ .amux = CX231XX_AMUX_LINE_IN,
+ .gpio = 0,
+ } },
+ },
};
const unsigned int cx231xx_bcount = ARRAY_SIZE(cx231xx_boards);
@@ -172,9 +443,27 @@ struct usb_device_id cx231xx_id_table[] = {
{USB_DEVICE(0x0572, 0x5A3C),
.driver_info = CX231XX_BOARD_UNKNOWN},
{USB_DEVICE(0x0572, 0x58A2),
- .driver_info = CX231XX_BOARD_CNXT_RDE_250},
+ .driver_info = CX231XX_BOARD_CNXT_CARRAERA},
{USB_DEVICE(0x0572, 0x58A1),
+ .driver_info = CX231XX_BOARD_CNXT_SHELBY},
+ {USB_DEVICE(0x0572, 0x58A4),
+ .driver_info = CX231XX_BOARD_CNXT_RDE_253S},
+ {USB_DEVICE(0x0572, 0x58A5),
+ .driver_info = CX231XX_BOARD_CNXT_RDU_253S},
+ {USB_DEVICE(0x0572, 0x58A6),
+ .driver_info = CX231XX_BOARD_CNXT_VIDEO_GRABBER},
+ {USB_DEVICE(0x0572, 0x589E),
+ .driver_info = CX231XX_BOARD_CNXT_RDE_250},
+ {USB_DEVICE(0x0572, 0x58A0),
.driver_info = CX231XX_BOARD_CNXT_RDU_250},
+ {USB_DEVICE(0x2040, 0xb120),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+ {USB_DEVICE(0x2040, 0xb140),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_EXETER},
+ {USB_DEVICE(0x2040, 0xc200),
+ .driver_info = CX231XX_BOARD_HAUPPAUGE_USBLIVE2},
+ {USB_DEVICE_VER(USB_VID_PIXELVIEW, USB_PID_PIXELVIEW_SBTVD, 0x4000, 0x4001),
+ .driver_info = CX231XX_BOARD_PV_PLAYTV_USB_HYBRID},
{},
};
@@ -204,11 +493,38 @@ int cx231xx_tuner_callback(void *ptr, int component, int command, int arg)
1);
msleep(10);
}
+ } else if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ switch (command) {
+ case TDA18271_CALLBACK_CMD_AGC_ENABLE:
+ if (dev->model == CX231XX_BOARD_PV_PLAYTV_USB_HYBRID)
+ rc = cx231xx_set_agc_analog_digital_mux_select(dev, arg);
+ break;
+ default:
+ rc = -EINVAL;
+ break;
+ }
}
return rc;
}
EXPORT_SYMBOL_GPL(cx231xx_tuner_callback);
+void cx231xx_reset_out(struct cx231xx *dev)
+{
+ cx231xx_set_gpio_value(dev, CX23417_RESET, 1);
+ msleep(200);
+ cx231xx_set_gpio_value(dev, CX23417_RESET, 0);
+ msleep(200);
+ cx231xx_set_gpio_value(dev, CX23417_RESET, 1);
+}
+void cx231xx_enable_OSC(struct cx231xx *dev)
+{
+ cx231xx_set_gpio_value(dev, CX23417_OSC_EN, 1);
+}
+void cx231xx_sleep_s5h1432(struct cx231xx *dev)
+{
+ cx231xx_set_gpio_value(dev, SLEEP_S5H1432, 0);
+}
+
static inline void cx231xx_set_model(struct cx231xx *dev)
{
memcpy(&dev->board, &cx231xx_boards[dev->model], sizeof(dev->board));
@@ -226,15 +542,15 @@ void cx231xx_pre_card_setup(struct cx231xx *dev)
dev->board.name, dev->model);
/* set the direction for GPIO pins */
- cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1);
- cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1);
- cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1);
+ if (dev->board.tuner_gpio) {
+ cx231xx_set_gpio_direction(dev, dev->board.tuner_gpio->bit, 1);
+ cx231xx_set_gpio_value(dev, dev->board.tuner_gpio->bit, 1);
+ }
+ if (dev->board.tuner_sif_gpio >= 0)
+ cx231xx_set_gpio_direction(dev, dev->board.tuner_sif_gpio, 1);
/* request some modules if any required */
- /* reset the Tuner */
- cx231xx_gpio_set(dev, dev->board.tuner_gpio);
-
/* set the mode to Analog mode initially */
cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
@@ -281,26 +597,6 @@ static void cx231xx_config_tuner(struct cx231xx *dev)
}
-/* ----------------------------------------------------------------------- */
-void cx231xx_register_i2c_ir(struct cx231xx *dev)
-{
- if (disable_ir)
- return;
-
- /* REVISIT: instantiate IR device */
-
- /* detect & configure */
- switch (dev->model) {
-
- case CX231XX_BOARD_CNXT_RDE_250:
- break;
- case CX231XX_BOARD_CNXT_RDU_250:
- break;
- default:
- break;
- }
-}
-
void cx231xx_card_setup(struct cx231xx *dev)
{
@@ -314,29 +610,24 @@ void cx231xx_card_setup(struct cx231xx *dev)
if (dev->board.decoder == CX231XX_AVDECODER) {
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[0].i2c_adap,
- "cx25840", "cx25840", 0x88 >> 1, NULL);
+ "cx25840", 0x88 >> 1, NULL);
if (dev->sd_cx25840 == NULL)
cx231xx_info("cx25840 subdev registration failure\n");
cx25840_call(dev, core, load_fw);
}
+ /* Initialize the tuner */
if (dev->board.tuner_type != TUNER_ABSENT) {
- dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", 0xc2 >> 1, NULL);
+ dev->sd_tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev,
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ "tuner",
+ dev->tuner_addr, NULL);
if (dev->sd_tuner == NULL)
cx231xx_info("tuner subdev registration failure\n");
-
- cx231xx_config_tuner(dev);
+ else
+ cx231xx_config_tuner(dev);
}
-
- cx231xx_config_tuner(dev);
-
-#if 0
- /* TBD IR will be added later */
- cx231xx_ir_init(dev);
-#endif
}
/*
@@ -370,18 +661,15 @@ void cx231xx_config_i2c(struct cx231xx *dev)
*/
void cx231xx_release_resources(struct cx231xx *dev)
{
-
-#if 0 /* TBD IR related */
- if (dev->ir)
- cx231xx_ir_fini(dev);
-#endif
-
cx231xx_release_analog_resources(dev);
cx231xx_remove_from_devlist(dev);
+ /* Release I2C buses */
cx231xx_dev_uninit(dev);
+ cx231xx_ir_exit(dev);
+
usb_put_dev(dev->udev);
/* Mark device as unused */
@@ -404,6 +692,7 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
mutex_init(&dev->lock);
mutex_init(&dev->ctrl_urb_lock);
mutex_init(&dev->gpio_i2c_lock);
+ mutex_init(&dev->i2c_lock);
spin_lock_init(&dev->video_mode.slock);
spin_lock_init(&dev->vbi_mode.slock);
@@ -422,6 +711,13 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
/* Query cx231xx to find what pcb config it is related to */
initialize_cx231xx(dev);
+ /*To workaround error number=-71 on EP0 for VideoGrabber,
+ need set alt here.*/
+ if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+ dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) {
+ cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 1);
+ }
/* Cx231xx pre card setup */
cx231xx_pre_card_setup(dev);
@@ -437,6 +733,7 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
/* register i2c bus */
errCode = cx231xx_dev_init(dev);
if (errCode < 0) {
+ cx231xx_dev_uninit(dev);
cx231xx_errdev("%s: cx231xx_i2c_register - errCode [%d]!\n",
__func__, errCode);
return errCode;
@@ -455,8 +752,6 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
dev->width = maxw;
dev->height = maxh;
dev->interlaced = 0;
- dev->hscale = 0;
- dev->vscale = 0;
dev->video_input = 0;
errCode = cx231xx_config(dev);
@@ -475,22 +770,28 @@ static int cx231xx_init_dev(struct cx231xx **devhandle, struct usb_device *udev,
INIT_LIST_HEAD(&dev->vbi_mode.vidq.queued);
/* Reset other chips required if they are tied up with GPIO pins */
-
cx231xx_add_into_devlist(dev);
+ if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+ printk(KERN_INFO "attach 417 %d\n", dev->model);
+ if (cx231xx_417_register(dev) < 0) {
+ printk(KERN_ERR
+ "%s() Failed to register 417 on VID_B\n",
+ __func__);
+ }
+ }
+
retval = cx231xx_register_analog_devices(dev);
if (retval < 0) {
cx231xx_release_resources(dev);
- goto fail_reg_devices;
+ return retval;
}
+ cx231xx_ir_init(dev);
+
cx231xx_init_extension(dev);
return 0;
-
-fail_reg_devices:
- mutex_unlock(&dev->lock);
- return retval;
}
#if defined(CONFIG_MODULES) && defined(MODULE)
@@ -512,8 +813,14 @@ static void request_modules(struct cx231xx *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct cx231xx *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
/*
@@ -532,13 +839,12 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
char *speed;
char descr[255] = "";
struct usb_interface *lif = NULL;
- int skip_interface = 0;
struct usb_interface_assoc_descriptor *assoc_desc;
udev = usb_get_dev(interface_to_usbdev(interface));
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
- if (!ifnum) {
+ if (ifnum == 1) {
/*
* Interface number 0 - IR interface
*/
@@ -547,8 +853,8 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
cx231xx_devused |= 1 << nr;
if (nr >= CX231XX_MAXBOARDS) {
- cx231xx_err(DRIVER_NAME ": Supports only %i cx231xx boards.\n",
- CX231XX_MAXBOARDS);
+ cx231xx_err(DRIVER_NAME
+ ": Supports only %i cx231xx boards.\n", CX231XX_MAXBOARDS);
cx231xx_devused &= ~(1 << nr);
return -ENOMEM;
}
@@ -573,6 +879,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
dev->xc_fw_load_done = 0;
dev->has_alsa_audio = 1;
dev->power_mode = -1;
+ atomic_set(&dev->devlist_count, 0);
/* 0 - vbi ; 1 -sliced cc mode */
dev->vbi_or_sliced_cc_mode = 0;
@@ -586,6 +893,11 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* store the current interface */
lif = interface;
+ /*mode_tv: digital=1 or analog=0*/
+ dev->mode_tv = 0;
+
+ dev->USE_ISO = transfer_mode;
+
switch (udev->speed) {
case USB_SPEED_LOW:
speed = "1.5";
@@ -619,13 +931,6 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
le16_to_cpu(udev->descriptor.idVendor),
le16_to_cpu(udev->descriptor.idProduct),
dev->max_iad_interface_count);
- } else {
- /* Get dev structure first */
- dev = usb_get_intfdata(udev->actconfig->interface[0]);
- if (dev == NULL) {
- cx231xx_err(DRIVER_NAME ": out of first interface!\n");
- return -ENODEV;
- }
/* store the interface 0 back */
lif = udev->actconfig->interface[0];
@@ -636,35 +941,21 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
/* get device number */
nr = dev->devno;
- /*
- * set skip interface, for all interfaces but
- * interface 1 and the last one
- */
- if ((ifnum != 1) && ((dev->interface_count - 1)
- != dev->max_iad_interface_count))
- skip_interface = 1;
-
- if (ifnum == 1) {
- assoc_desc = udev->actconfig->intf_assoc[0];
- if (assoc_desc->bFirstInterface != ifnum) {
- cx231xx_err(DRIVER_NAME ": Not found "
- "matching IAD interface\n");
- return -ENODEV;
- }
+ assoc_desc = udev->actconfig->intf_assoc[0];
+ if (assoc_desc->bFirstInterface != ifnum) {
+ cx231xx_err(DRIVER_NAME ": Not found "
+ "matching IAD interface\n");
+ return -ENODEV;
}
- }
-
- if (skip_interface)
+ } else {
return -ENODEV;
+ }
cx231xx_info("registering interface %d\n", ifnum);
/* save our data pointer in this interface device */
usb_set_intfdata(lif, dev);
- if ((dev->interface_count - 1) != dev->max_iad_interface_count)
- return 0;
-
/*
* AV device initialization - only done at the last interface
*/
@@ -675,15 +966,18 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
cx231xx_errdev("v4l2_device_register failed\n");
cx231xx_devused &= ~(1 << nr);
kfree(dev);
+ dev = NULL;
return -EIO;
}
-
/* allocate device struct */
retval = cx231xx_init_dev(&dev, udev, nr);
if (retval) {
cx231xx_devused &= ~(1 << dev->devno);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
+ dev = NULL;
+ usb_set_intfdata(lif, NULL);
+
return retval;
}
@@ -706,6 +1000,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
cx231xx_devused &= ~(1 << nr);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
+ dev = NULL;
return -ENOMEM;
}
@@ -739,6 +1034,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
cx231xx_devused &= ~(1 << nr);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
+ dev = NULL;
return -ENOMEM;
}
@@ -773,6 +1069,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
cx231xx_devused &= ~(1 << nr);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
+ dev = NULL;
return -ENOMEM;
}
@@ -808,6 +1105,7 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
cx231xx_devused &= ~(1 << nr);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
+ dev = NULL;
return -ENOMEM;
}
@@ -822,6 +1120,15 @@ static int cx231xx_usb_probe(struct usb_interface *interface,
}
}
+ if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER) {
+ cx231xx_enable_OSC(dev);
+ cx231xx_reset_out(dev);
+ cx231xx_set_alt_setting(dev, INDEX_VIDEO, 3);
+ }
+
+ if (dev->model == CX231XX_BOARD_CNXT_RDE_253S)
+ cx231xx_sleep_s5h1432(dev);
+
/* load other modules required */
request_modules(dev);
@@ -846,6 +1153,8 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
if (!dev->udev)
return;
+ flush_request_modules(dev);
+
/* delete v4l2 device */
v4l2_device_unregister(&dev->v4l2_dev);
@@ -862,7 +1171,10 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
video_device_node_name(dev->vdev));
dev->state |= DEV_MISCONFIGURED;
- cx231xx_uninit_isoc(dev);
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
dev->state |= DEV_DISCONNECTED;
wake_up_interruptible(&dev->wait_frame);
wake_up_interruptible(&dev->wait_stream);
@@ -881,6 +1193,7 @@ static void cx231xx_usb_disconnect(struct usb_interface *interface)
kfree(dev->sliced_cc_mode.alt_max_pkt_size);
kfree(dev->ts1_mode.alt_max_pkt_size);
kfree(dev);
+ dev = NULL;
}
}
diff --git a/drivers/media/video/cx231xx/cx231xx-conf-reg.h b/drivers/media/video/cx231xx/cx231xx-conf-reg.h
index 31a8759f6e54..25593f212abf 100644
--- a/drivers/media/video/cx231xx/cx231xx-conf-reg.h
+++ b/drivers/media/video/cx231xx/cx231xx-conf-reg.h
@@ -39,6 +39,7 @@
#define CIR_CAR_REG 0x38
#define CIR_OT_CFG1 0x40
#define CIR_OT_CFG2 0x44
+#define GBULK_BIT_EN 0x68
#define PWR_CTL_EN 0x74
/* Polaris Endpoints capture mask for register EP_MODE_SET */
diff --git a/drivers/media/video/cx231xx/cx231xx-core.c b/drivers/media/video/cx231xx/cx231xx-core.c
index 912a4d740206..7d62d58617f5 100644
--- a/drivers/media/video/cx231xx/cx231xx-core.c
+++ b/drivers/media/video/cx231xx/cx231xx-core.c
@@ -27,6 +27,7 @@
#include <linux/usb.h>
#include <linux/vmalloc.h>
#include <media/v4l2-common.h>
+#include <media/tuner.h>
#include "cx231xx.h"
#include "cx231xx-reg.h"
@@ -46,11 +47,6 @@ static unsigned int reg_debug;
module_param(reg_debug, int, 0644);
MODULE_PARM_DESC(reg_debug, "enable debug messages [URB reg]");
-#define cx231xx_regdbg(fmt, arg...) do {\
- if (reg_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
-
static int alt = CX231XX_PINOUT;
module_param(alt, int, 0644);
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
@@ -64,7 +60,7 @@ MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
* Device control list functions *
******************************************************************/
-static LIST_HEAD(cx231xx_devlist);
+LIST_HEAD(cx231xx_devlist);
static DEFINE_MUTEX(cx231xx_devlist_mutex);
/*
@@ -74,33 +70,39 @@ static DEFINE_MUTEX(cx231xx_devlist_mutex);
*/
void cx231xx_remove_from_devlist(struct cx231xx *dev)
{
- mutex_lock(&cx231xx_devlist_mutex);
- list_del(&dev->devlist);
- mutex_unlock(&cx231xx_devlist_mutex);
+ if (dev == NULL)
+ return;
+ if (dev->udev == NULL)
+ return;
+
+ if (atomic_read(&dev->devlist_count) > 0) {
+ mutex_lock(&cx231xx_devlist_mutex);
+ list_del(&dev->devlist);
+ atomic_dec(&dev->devlist_count);
+ mutex_unlock(&cx231xx_devlist_mutex);
+ }
};
void cx231xx_add_into_devlist(struct cx231xx *dev)
{
mutex_lock(&cx231xx_devlist_mutex);
list_add_tail(&dev->devlist, &cx231xx_devlist);
+ atomic_inc(&dev->devlist_count);
mutex_unlock(&cx231xx_devlist_mutex);
};
static LIST_HEAD(cx231xx_extension_devlist);
-static DEFINE_MUTEX(cx231xx_extension_devlist_lock);
int cx231xx_register_extension(struct cx231xx_ops *ops)
{
struct cx231xx *dev = NULL;
mutex_lock(&cx231xx_devlist_mutex);
- mutex_lock(&cx231xx_extension_devlist_lock);
list_add_tail(&ops->next, &cx231xx_extension_devlist);
list_for_each_entry(dev, &cx231xx_devlist, devlist)
ops->init(dev);
printk(KERN_INFO DRIVER_NAME ": %s initialized\n", ops->name);
- mutex_unlock(&cx231xx_extension_devlist_lock);
mutex_unlock(&cx231xx_devlist_mutex);
return 0;
}
@@ -114,10 +116,9 @@ void cx231xx_unregister_extension(struct cx231xx_ops *ops)
list_for_each_entry(dev, &cx231xx_devlist, devlist)
ops->fini(dev);
- mutex_lock(&cx231xx_extension_devlist_lock);
+
printk(KERN_INFO DRIVER_NAME ": %s removed\n", ops->name);
list_del(&ops->next);
- mutex_unlock(&cx231xx_extension_devlist_lock);
mutex_unlock(&cx231xx_devlist_mutex);
}
EXPORT_SYMBOL(cx231xx_unregister_extension);
@@ -126,28 +127,28 @@ void cx231xx_init_extension(struct cx231xx *dev)
{
struct cx231xx_ops *ops = NULL;
- mutex_lock(&cx231xx_extension_devlist_lock);
+ mutex_lock(&cx231xx_devlist_mutex);
if (!list_empty(&cx231xx_extension_devlist)) {
list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
if (ops->init)
ops->init(dev);
}
}
- mutex_unlock(&cx231xx_extension_devlist_lock);
+ mutex_unlock(&cx231xx_devlist_mutex);
}
void cx231xx_close_extension(struct cx231xx *dev)
{
struct cx231xx_ops *ops = NULL;
- mutex_lock(&cx231xx_extension_devlist_lock);
+ mutex_lock(&cx231xx_devlist_mutex);
if (!list_empty(&cx231xx_extension_devlist)) {
list_for_each_entry(ops, &cx231xx_extension_devlist, next) {
if (ops->fini)
ops->fini(dev);
}
}
- mutex_unlock(&cx231xx_extension_devlist_lock);
+ mutex_unlock(&cx231xx_devlist_mutex);
}
/****************************************************************
@@ -234,6 +235,66 @@ int cx231xx_send_usb_command(struct cx231xx_i2c *i2c_bus,
EXPORT_SYMBOL_GPL(cx231xx_send_usb_command);
/*
+ * Sends/Receives URB control messages, assuring to use a kalloced buffer
+ * for all operations (dev->urb_buf), to avoid using stacked buffers, as
+ * they aren't safe for usage with USB, due to DMA restrictions.
+ * Also implements the debug code for control URB's.
+ */
+static int __usb_control_msg(struct cx231xx *dev, unsigned int pipe,
+ __u8 request, __u8 requesttype, __u16 value, __u16 index,
+ void *data, __u16 size, int timeout)
+{
+ int rc, i;
+
+ if (reg_debug) {
+ printk(KERN_DEBUG "%s: (pipe 0x%08x): "
+ "%s: %02x %02x %02x %02x %02x %02x %02x %02x ",
+ dev->name,
+ pipe,
+ (requesttype & USB_DIR_IN) ? "IN" : "OUT",
+ requesttype,
+ request,
+ value & 0xff, value >> 8,
+ index & 0xff, index >> 8,
+ size & 0xff, size >> 8);
+ if (!(requesttype & USB_DIR_IN)) {
+ printk(KERN_CONT ">>>");
+ for (i = 0; i < size; i++)
+ printk(KERN_CONT " %02x",
+ ((unsigned char *)data)[i]);
+ }
+ }
+
+ /* Do the real call to usb_control_msg */
+ mutex_lock(&dev->ctrl_urb_lock);
+ if (!(requesttype & USB_DIR_IN) && size)
+ memcpy(dev->urb_buf, data, size);
+ rc = usb_control_msg(dev->udev, pipe, request, requesttype, value,
+ index, dev->urb_buf, size, timeout);
+ if ((requesttype & USB_DIR_IN) && size)
+ memcpy(data, dev->urb_buf, size);
+ mutex_unlock(&dev->ctrl_urb_lock);
+
+ if (reg_debug) {
+ if (unlikely(rc < 0)) {
+ printk(KERN_CONT "FAILED!\n");
+ return rc;
+ }
+
+ if ((requesttype & USB_DIR_IN)) {
+ printk(KERN_CONT "<<<");
+ for (i = 0; i < size; i++)
+ printk(KERN_CONT " %02x",
+ ((unsigned char *)data)[i]);
+ }
+ printk(KERN_CONT "\n");
+ }
+
+ return rc;
+}
+
+
+/*
* cx231xx_read_ctrl_reg()
* reads data from the usb device specifying bRequest and wValue
*/
@@ -270,39 +331,9 @@ int cx231xx_read_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg,
if (val == 0xFF)
return -EINVAL;
- if (reg_debug) {
- cx231xx_isocdbg("(pipe 0x%08x): "
- "IN: %02x %02x %02x %02x %02x %02x %02x %02x ",
- pipe,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- req, 0, val,
- reg & 0xff, reg >> 8, len & 0xff, len >> 8);
- }
-
- mutex_lock(&dev->ctrl_urb_lock);
- ret = usb_control_msg(dev->udev, pipe, req,
+ ret = __usb_control_msg(dev, pipe, req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- val, reg, dev->urb_buf, len, HZ);
- if (ret < 0) {
- cx231xx_isocdbg(" failed!\n");
- /* mutex_unlock(&dev->ctrl_urb_lock); */
- return ret;
- }
-
- if (len)
- memcpy(buf, dev->urb_buf, len);
-
- mutex_unlock(&dev->ctrl_urb_lock);
-
- if (reg_debug) {
- int byte;
-
- cx231xx_isocdbg("<<<");
- for (byte = 0; byte < len; byte++)
- cx231xx_isocdbg(" %02x", (unsigned char)buf[byte]);
- cx231xx_isocdbg("\n");
- }
-
+ val, reg, buf, len, HZ);
return ret;
}
@@ -311,6 +342,8 @@ int cx231xx_send_vendor_cmd(struct cx231xx *dev,
{
int ret;
int pipe = 0;
+ int unsend_size = 0;
+ u8 *pdata;
if (dev->state & DEV_DISCONNECTED)
return -ENODEV;
@@ -323,31 +356,54 @@ int cx231xx_send_vendor_cmd(struct cx231xx *dev,
else
pipe = usb_sndctrlpipe(dev->udev, 0);
- if (reg_debug) {
- int byte;
+ /*
+ * If the cx23102 read more than 4 bytes with i2c bus,
+ * need chop to 4 byte per request
+ */
+ if ((ven_req->wLength > 4) && ((ven_req->bRequest == 0x4) ||
+ (ven_req->bRequest == 0x5) ||
+ (ven_req->bRequest == 0x6))) {
+ unsend_size = 0;
+ pdata = ven_req->pBuff;
+
+
+ unsend_size = ven_req->wLength;
+
+ /* the first package */
+ ven_req->wValue = ven_req->wValue & 0xFFFB;
+ ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x2;
+ ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+ ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ ven_req->wValue, ven_req->wIndex, pdata,
+ 0x0004, HZ);
+ unsend_size = unsend_size - 4;
+
+ /* the middle package */
+ ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x42;
+ while (unsend_size - 4 > 0) {
+ pdata = pdata + 4;
+ ret = __usb_control_msg(dev, pipe,
+ ven_req->bRequest,
+ ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ ven_req->wValue, ven_req->wIndex, pdata,
+ 0x0004, HZ);
+ unsend_size = unsend_size - 4;
+ }
- cx231xx_isocdbg("(pipe 0x%08x): "
- "OUT: %02x %02x %02x %04x %04x %04x >>>",
- pipe,
- ven_req->
- direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- ven_req->bRequest, 0, ven_req->wValue,
- ven_req->wIndex, ven_req->wLength);
-
- for (byte = 0; byte < ven_req->wLength; byte++)
- cx231xx_isocdbg(" %02x",
- (unsigned char)ven_req->pBuff[byte]);
- cx231xx_isocdbg("\n");
+ /* the last package */
+ ven_req->wValue = (ven_req->wValue & 0xFFBD) | 0x40;
+ pdata = pdata + 4;
+ ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+ ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ ven_req->wValue, ven_req->wIndex, pdata,
+ unsend_size, HZ);
+ } else {
+ ret = __usb_control_msg(dev, pipe, ven_req->bRequest,
+ ven_req->direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ ven_req->wValue, ven_req->wIndex,
+ ven_req->pBuff, ven_req->wLength, HZ);
}
- mutex_lock(&dev->ctrl_urb_lock);
- ret = usb_control_msg(dev->udev, pipe, ven_req->bRequest,
- ven_req->
- direction | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- ven_req->wValue, ven_req->wIndex, ven_req->pBuff,
- ven_req->wLength, HZ);
- mutex_unlock(&dev->ctrl_urb_lock);
-
return ret;
}
@@ -403,12 +459,9 @@ int cx231xx_write_ctrl_reg(struct cx231xx *dev, u8 req, u16 reg, char *buf,
cx231xx_isocdbg("\n");
}
- mutex_lock(&dev->ctrl_urb_lock);
- memcpy(dev->urb_buf, buf, len);
- ret = usb_control_msg(dev->udev, pipe, req,
+ ret = __usb_control_msg(dev, pipe, req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- val, reg, dev->urb_buf, len, HZ);
- mutex_unlock(&dev->ctrl_urb_lock);
+ val, reg, buf, len, HZ);
return ret;
}
@@ -444,6 +497,11 @@ int cx231xx_set_video_alternate(struct cx231xx *dev)
dev->video_mode.alt = 0;
}
+ if (dev->USE_ISO == 0)
+ dev->video_mode.alt = 0;
+
+ cx231xx_coredbg("dev->video_mode.alt= %d\n", dev->video_mode.alt);
+
/* Get the correct video interface Index */
usb_interface_index =
dev->current_pcb_config.hs_config_info[0].interface_info.
@@ -452,15 +510,13 @@ int cx231xx_set_video_alternate(struct cx231xx *dev)
if (dev->video_mode.alt != prev_alt) {
cx231xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
min_pkt_size, dev->video_mode.alt);
- dev->video_mode.max_pkt_size =
- dev->video_mode.alt_max_pkt_size[dev->video_mode.alt];
+
+ if (dev->video_mode.alt_max_pkt_size != NULL)
+ dev->video_mode.max_pkt_size =
+ dev->video_mode.alt_max_pkt_size[dev->video_mode.alt];
cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
dev->video_mode.alt,
dev->video_mode.max_pkt_size);
- cx231xx_info
- (" setting alt %d with wMaxPktSize=%u , Interface = %d\n",
- dev->video_mode.alt, dev->video_mode.max_pkt_size,
- usb_interface_index);
errCode =
usb_set_interface(dev->udev, usb_interface_index,
dev->video_mode.alt);
@@ -485,7 +541,7 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
usb_interface_index =
dev->current_pcb_config.hs_config_info[0].interface_info.
ts1_index + 1;
- dev->video_mode.alt = alt;
+ dev->ts1_mode.alt = alt;
if (dev->ts1_mode.alt_max_pkt_size != NULL)
max_pkt_size = dev->ts1_mode.max_pkt_size =
dev->ts1_mode.alt_max_pkt_size[dev->ts1_mode.alt];
@@ -542,12 +598,16 @@ int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt)
cx231xx_errdev
("can't change interface %d alt no. to %d: Max. Pkt size = 0\n",
usb_interface_index, alt);
- return -1;
+ /*To workaround error number=-71 on EP0 for videograbber,
+ need add following codes.*/
+ if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
+ dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+ return -1;
}
- cx231xx_info
- (" setting alternate %d with wMaxPacketSize=%u , Interface = %d\n",
- alt, max_pkt_size, usb_interface_index);
+ cx231xx_coredbg("setting alternate %d with wMaxPacketSize=%u,"
+ "Interface = %d\n", alt, max_pkt_size,
+ usb_interface_index);
if (usb_interface_index > 0) {
status = usb_set_interface(dev->udev, usb_interface_index, alt);
@@ -584,8 +644,56 @@ int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio)
return rc;
}
+int cx231xx_demod_reset(struct cx231xx *dev)
+{
+
+ u8 status = 0;
+ u8 value[4] = { 0, 0, 0, 0 };
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+ value, 4);
+
+ cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN,
+ value[0], value[1], value[2], value[3]);
+
+ cx231xx_coredbg("Enter cx231xx_demod_reset()\n");
+
+ value[1] = (u8) 0x3;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(10);
+
+ value[1] = (u8) 0x0;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(10);
+
+ value[1] = (u8) 0x3;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ PWR_CTL_EN, value, 4);
+ msleep(10);
+
+
+
+ status = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER, PWR_CTL_EN,
+ value, 4);
+
+ cx231xx_coredbg("reg0x%x=0x%x 0x%x 0x%x 0x%x\n", PWR_CTL_EN,
+ value[0], value[1], value[2], value[3]);
+
+ return status;
+}
+EXPORT_SYMBOL_GPL(cx231xx_demod_reset);
+int is_fw_load(struct cx231xx *dev)
+{
+ return cx231xx_check_fw(dev);
+}
+EXPORT_SYMBOL_GPL(is_fw_load);
+
int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
{
+ int errCode = 0;
+
if (dev->mode == set_mode)
return 0;
@@ -600,15 +708,76 @@ int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode)
dev->mode = set_mode;
- if (dev->mode == CX231XX_DIGITAL_MODE)
- ;/* Set Digital power mode */
- else
- ;/* Set Analog Power mode */
+ if (dev->mode == CX231XX_DIGITAL_MODE)/* Set Digital power mode */ {
+ /* set AGC mode to Digital */
+ switch (dev->model) {
+ case CX231XX_BOARD_CNXT_CARRAERA:
+ case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_SHELBY:
+ case CX231XX_BOARD_CNXT_RDU_250:
+ errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+ break;
+ case CX231XX_BOARD_CNXT_RDE_253S:
+ case CX231XX_BOARD_CNXT_RDU_253S:
+ errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+ break;
+ case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ errCode = cx231xx_set_power_mode(dev,
+ POLARIS_AVMODE_DIGITAL);
+ break;
+ default:
+ break;
+ }
+ } else/* Set Analog Power mode */ {
+ /* set AGC mode to Analog */
+ switch (dev->model) {
+ case CX231XX_BOARD_CNXT_CARRAERA:
+ case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_SHELBY:
+ case CX231XX_BOARD_CNXT_RDU_250:
+ errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+ break;
+ case CX231XX_BOARD_CNXT_RDE_253S:
+ case CX231XX_BOARD_CNXT_RDU_253S:
+ case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+ errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+ break;
+ default:
+ break;
+ }
+ }
return 0;
}
EXPORT_SYMBOL_GPL(cx231xx_set_mode);
+int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size)
+{
+ int errCode = 0;
+ int actlen, ret = -ENOMEM;
+ u32 *buffer;
+
+buffer = kzalloc(4096, GFP_KERNEL);
+ if (buffer == NULL) {
+ cx231xx_info("out of mem\n");
+ return -ENOMEM;
+ }
+ memcpy(&buffer[0], firmware, 4096);
+
+ ret = usb_bulk_msg(dev->udev, usb_sndbulkpipe(dev->udev, 5),
+ buffer, 4096, &actlen, 2000);
+
+ if (ret)
+ cx231xx_info("bulk message failed: %d (%d/%d)", ret,
+ size, actlen);
+ else {
+ errCode = actlen != size ? -1 : 0;
+ }
+kfree(buffer);
+ return 0;
+}
+
/*****************************************************************
* URB Streaming functions *
******************************************************************/
@@ -616,7 +785,7 @@ EXPORT_SYMBOL_GPL(cx231xx_set_mode);
/*
* IRQ callback, called by URB callback
*/
-static void cx231xx_irq_callback(struct urb *urb)
+static void cx231xx_isoc_irq_callback(struct urb *urb)
{
struct cx231xx_dmaqueue *dma_q = urb->context;
struct cx231xx_video_mode *vmode =
@@ -655,12 +824,54 @@ static void cx231xx_irq_callback(struct urb *urb)
urb->status);
}
}
+/*****************************************************************
+* URB Streaming functions *
+******************************************************************/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+static void cx231xx_bulk_irq_callback(struct urb *urb)
+{
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ struct cx231xx_video_mode *vmode =
+ container_of(dma_q, struct cx231xx_video_mode, vidq);
+ struct cx231xx *dev = container_of(vmode, struct cx231xx, video_mode);
+ int rc;
+
+ switch (urb->status) {
+ case 0: /* success */
+ case -ETIMEDOUT: /* NAK */
+ break;
+ case -ECONNRESET: /* kill */
+ case -ENOENT:
+ case -ESHUTDOWN:
+ return;
+ default: /* error */
+ cx231xx_isocdbg("urb completition error %d.\n", urb->status);
+ break;
+ }
+
+ /* Copy data from URB */
+ spin_lock(&dev->video_mode.slock);
+ rc = dev->video_mode.bulk_ctl.bulk_copy(dev, urb);
+ spin_unlock(&dev->video_mode.slock);
+
+ /* Reset urb buffers */
+ urb->status = 0;
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ cx231xx_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
+ }
+}
/*
* Stop and Deallocate URBs
*/
void cx231xx_uninit_isoc(struct cx231xx *dev)
{
+ struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
struct urb *urb;
int i;
@@ -690,16 +901,71 @@ void cx231xx_uninit_isoc(struct cx231xx *dev)
kfree(dev->video_mode.isoc_ctl.urb);
kfree(dev->video_mode.isoc_ctl.transfer_buffer);
+ kfree(dma_q->p_left_data);
dev->video_mode.isoc_ctl.urb = NULL;
dev->video_mode.isoc_ctl.transfer_buffer = NULL;
dev->video_mode.isoc_ctl.num_bufs = 0;
+ dma_q->p_left_data = NULL;
+
+ if (dev->mode_tv == 0)
+ cx231xx_capture_start(dev, 0, Raw_Video);
+ else
+ cx231xx_capture_start(dev, 0, TS1_serial_mode);
+
- cx231xx_capture_start(dev, 0, Raw_Video);
}
EXPORT_SYMBOL_GPL(cx231xx_uninit_isoc);
/*
+ * Stop and Deallocate URBs
+ */
+void cx231xx_uninit_bulk(struct cx231xx *dev)
+{
+ struct urb *urb;
+ int i;
+
+ cx231xx_isocdbg("cx231xx: called cx231xx_uninit_bulk\n");
+
+ dev->video_mode.bulk_ctl.nfields = -1;
+ for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+ urb = dev->video_mode.bulk_ctl.urb[i];
+ if (urb) {
+ if (!irqs_disabled())
+ usb_kill_urb(urb);
+ else
+ usb_unlink_urb(urb);
+
+ if (dev->video_mode.bulk_ctl.transfer_buffer[i]) {
+ usb_free_coherent(dev->udev,
+ urb->transfer_buffer_length,
+ dev->video_mode.isoc_ctl.
+ transfer_buffer[i],
+ urb->transfer_dma);
+ }
+ usb_free_urb(urb);
+ dev->video_mode.bulk_ctl.urb[i] = NULL;
+ }
+ dev->video_mode.bulk_ctl.transfer_buffer[i] = NULL;
+ }
+
+ kfree(dev->video_mode.bulk_ctl.urb);
+ kfree(dev->video_mode.bulk_ctl.transfer_buffer);
+
+ dev->video_mode.bulk_ctl.urb = NULL;
+ dev->video_mode.bulk_ctl.transfer_buffer = NULL;
+ dev->video_mode.bulk_ctl.num_bufs = 0;
+
+ if (dev->mode_tv == 0)
+ cx231xx_capture_start(dev, 0, Raw_Video);
+ else
+ cx231xx_capture_start(dev, 0, TS1_serial_mode);
+
+
+}
+EXPORT_SYMBOL_GPL(cx231xx_uninit_bulk);
+
+/*
* Allocate URBs and start IRQ
*/
int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
@@ -713,15 +979,16 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
int j, k;
int rc;
- cx231xx_isocdbg("cx231xx: called cx231xx_prepare_isoc\n");
+ /* De-allocates all pending stuff */
+ cx231xx_uninit_isoc(dev);
- dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+ dma_q->p_left_data = kzalloc(4096, GFP_KERNEL);
+ if (dma_q->p_left_data == NULL) {
+ cx231xx_info("out of mem\n");
+ return -ENOMEM;
+ }
- cx231xx_info("Setting Video mux to %d\n", dev->video_input);
- video_mux(dev, dev->video_input);
- /* De-allocates all pending stuff */
- cx231xx_uninit_isoc(dev);
dev->video_mode.isoc_ctl.isoc_copy = isoc_copy;
dev->video_mode.isoc_ctl.num_bufs = num_bufs;
@@ -733,6 +1000,14 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
dma_q->lines_per_field = dev->height / 2;
dma_q->bytes_left_in_line = dev->width << 1;
dma_q->lines_completed = 0;
+ dma_q->mpeg_buffer_done = 0;
+ dma_q->left_data_count = 0;
+ dma_q->mpeg_buffer_completed = 0;
+ dma_q->add_ps_package_head = CX231XX_NEED_ADD_PS_PACKAGE_HEAD;
+ dma_q->ps_head[0] = 0x00;
+ dma_q->ps_head[1] = 0x00;
+ dma_q->ps_head[2] = 0x01;
+ dma_q->ps_head[3] = 0xBA;
for (i = 0; i < 8; i++)
dma_q->partial_buf[i] = 0;
@@ -756,6 +1031,12 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
sb_size = max_packets * dev->video_mode.isoc_ctl.max_pkt_size;
+ if (dev->mode_tv == 1)
+ dev->video_mode.end_point_addr = 0x81;
+ else
+ dev->video_mode.end_point_addr = 0x84;
+
+
/* allocate urbs and transfer buffers */
for (i = 0; i < dev->video_mode.isoc_ctl.num_bufs; i++) {
urb = usb_alloc_urb(max_packets, GFP_KERNEL);
@@ -784,7 +1065,7 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
usb_fill_int_urb(urb, dev->udev, pipe,
dev->video_mode.isoc_ctl.transfer_buffer[i],
- sb_size, cx231xx_irq_callback, dma_q, 1);
+ sb_size, cx231xx_isoc_irq_callback, dma_q, 1);
urb->number_of_packets = max_packets;
urb->transfer_flags = URB_ISO_ASAP;
@@ -812,12 +1093,176 @@ int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
}
}
- cx231xx_capture_start(dev, 1, Raw_Video);
+ if (dev->mode_tv == 0)
+ cx231xx_capture_start(dev, 1, Raw_Video);
+ else
+ cx231xx_capture_start(dev, 1, TS1_serial_mode);
return 0;
}
EXPORT_SYMBOL_GPL(cx231xx_init_isoc);
+/*
+ * Allocate URBs and start IRQ
+ */
+int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*bulk_copy) (struct cx231xx *dev, struct urb *urb))
+{
+ struct cx231xx_dmaqueue *dma_q = &dev->video_mode.vidq;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int rc;
+
+ dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
+
+ cx231xx_coredbg("Setting Video mux to %d\n", dev->video_input);
+
+ video_mux(dev, dev->video_input);
+
+ /* De-allocates all pending stuff */
+ cx231xx_uninit_bulk(dev);
+
+ dev->video_mode.bulk_ctl.bulk_copy = bulk_copy;
+ dev->video_mode.bulk_ctl.num_bufs = num_bufs;
+ dma_q->pos = 0;
+ dma_q->is_partial_line = 0;
+ dma_q->last_sav = 0;
+ dma_q->current_field = -1;
+ dma_q->field1_done = 0;
+ dma_q->lines_per_field = dev->height / 2;
+ dma_q->bytes_left_in_line = dev->width << 1;
+ dma_q->lines_completed = 0;
+ dma_q->mpeg_buffer_done = 0;
+ dma_q->left_data_count = 0;
+ dma_q->mpeg_buffer_completed = 0;
+ dma_q->ps_head[0] = 0x00;
+ dma_q->ps_head[1] = 0x00;
+ dma_q->ps_head[2] = 0x01;
+ dma_q->ps_head[3] = 0xBA;
+ for (i = 0; i < 8; i++)
+ dma_q->partial_buf[i] = 0;
+
+ dev->video_mode.bulk_ctl.urb =
+ kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+ if (!dev->video_mode.bulk_ctl.urb) {
+ cx231xx_errdev("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->video_mode.bulk_ctl.transfer_buffer =
+ kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
+ if (!dev->video_mode.bulk_ctl.transfer_buffer) {
+ cx231xx_errdev("cannot allocate memory for usbtransfer\n");
+ kfree(dev->video_mode.bulk_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dev->video_mode.bulk_ctl.max_pkt_size = max_pkt_size;
+ dev->video_mode.bulk_ctl.buf = NULL;
+
+ sb_size = max_packets * dev->video_mode.bulk_ctl.max_pkt_size;
+
+ if (dev->mode_tv == 1)
+ dev->video_mode.end_point_addr = 0x81;
+ else
+ dev->video_mode.end_point_addr = 0x84;
+
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+ urb = usb_alloc_urb(0, GFP_KERNEL);
+ if (!urb) {
+ cx231xx_err("cannot alloc bulk_ctl.urb %i\n", i);
+ cx231xx_uninit_bulk(dev);
+ return -ENOMEM;
+ }
+ dev->video_mode.bulk_ctl.urb[i] = urb;
+ urb->transfer_flags = 0;
+
+ dev->video_mode.bulk_ctl.transfer_buffer[i] =
+ usb_alloc_coherent(dev->udev, sb_size, GFP_KERNEL,
+ &urb->transfer_dma);
+ if (!dev->video_mode.bulk_ctl.transfer_buffer[i]) {
+ cx231xx_err("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt() ? " while in int" : "");
+ cx231xx_uninit_bulk(dev);
+ return -ENOMEM;
+ }
+ memset(dev->video_mode.bulk_ctl.transfer_buffer[i], 0, sb_size);
+
+ pipe = usb_rcvbulkpipe(dev->udev,
+ dev->video_mode.end_point_addr);
+ usb_fill_bulk_urb(urb, dev->udev, pipe,
+ dev->video_mode.bulk_ctl.transfer_buffer[i],
+ sb_size, cx231xx_bulk_irq_callback, dma_q);
+ }
+
+ init_waitqueue_head(&dma_q->wq);
+
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->video_mode.bulk_ctl.num_bufs; i++) {
+ rc = usb_submit_urb(dev->video_mode.bulk_ctl.urb[i],
+ GFP_ATOMIC);
+ if (rc) {
+ cx231xx_err("submit of urb %i failed (error=%i)\n", i,
+ rc);
+ cx231xx_uninit_bulk(dev);
+ return rc;
+ }
+ }
+
+ if (dev->mode_tv == 0)
+ cx231xx_capture_start(dev, 1, Raw_Video);
+ else
+ cx231xx_capture_start(dev, 1, TS1_serial_mode);
+
+ return 0;
+}
+EXPORT_SYMBOL_GPL(cx231xx_init_bulk);
+void cx231xx_stop_TS1(struct cx231xx *dev)
+{
+ int status = 0;
+ u8 val[4] = { 0, 0, 0, 0 };
+
+ val[0] = 0x00;
+ val[1] = 0x03;
+ val[2] = 0x00;
+ val[3] = 0x00;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS_MODE_REG, val, 4);
+
+ val[0] = 0x00;
+ val[1] = 0x70;
+ val[2] = 0x04;
+ val[3] = 0x00;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS1_CFG_REG, val, 4);
+}
+/* EXPORT_SYMBOL_GPL(cx231xx_stop_TS1); */
+void cx231xx_start_TS1(struct cx231xx *dev)
+{
+ int status = 0;
+ u8 val[4] = { 0, 0, 0, 0 };
+
+ val[0] = 0x03;
+ val[1] = 0x03;
+ val[2] = 0x00;
+ val[3] = 0x00;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS_MODE_REG, val, 4);
+
+ val[0] = 0x04;
+ val[1] = 0xA3;
+ val[2] = 0x3B;
+ val[3] = 0x00;
+ status = cx231xx_write_ctrl_reg(dev, VRT_SET_REGISTER,
+ TS1_CFG_REG, val, 4);
+}
+/* EXPORT_SYMBOL_GPL(cx231xx_start_TS1); */
/*****************************************************************
* Device Init/UnInit functions *
******************************************************************/
@@ -830,21 +1275,21 @@ int cx231xx_dev_init(struct cx231xx *dev)
/* External Master 1 Bus */
dev->i2c_bus[0].nr = 0;
dev->i2c_bus[0].dev = dev;
- dev->i2c_bus[0].i2c_period = I2C_SPEED_1M; /* 1MHz */
+ dev->i2c_bus[0].i2c_period = I2C_SPEED_100K; /* 100 KHz */
dev->i2c_bus[0].i2c_nostop = 0;
dev->i2c_bus[0].i2c_reserve = 0;
/* External Master 2 Bus */
dev->i2c_bus[1].nr = 1;
dev->i2c_bus[1].dev = dev;
- dev->i2c_bus[1].i2c_period = I2C_SPEED_1M; /* 1MHz */
+ dev->i2c_bus[1].i2c_period = I2C_SPEED_100K; /* 100 KHz */
dev->i2c_bus[1].i2c_nostop = 0;
dev->i2c_bus[1].i2c_reserve = 0;
/* Internal Master 3 Bus */
dev->i2c_bus[2].nr = 2;
dev->i2c_bus[2].dev = dev;
- dev->i2c_bus[2].i2c_period = I2C_SPEED_400K; /* 400kHz */
+ dev->i2c_bus[2].i2c_period = I2C_SPEED_100K; /* 100kHz */
dev->i2c_bus[2].i2c_nostop = 0;
dev->i2c_bus[2].i2c_reserve = 0;
@@ -856,14 +1301,34 @@ int cx231xx_dev_init(struct cx231xx *dev)
/* init hardware */
/* Note : with out calling set power mode function,
afe can not be set up correctly */
- errCode = cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
- if (errCode < 0) {
- cx231xx_errdev
- ("%s: Failed to set Power - errCode [%d]!\n",
- __func__, errCode);
- return errCode;
+ if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+ dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2) {
+ errCode = cx231xx_set_power_mode(dev,
+ POLARIS_AVMODE_ENXTERNAL_AV);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("%s: Failed to set Power - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
+ } else {
+ errCode = cx231xx_set_power_mode(dev,
+ POLARIS_AVMODE_ANALOGT_TV);
+ if (errCode < 0) {
+ cx231xx_errdev
+ ("%s: Failed to set Power - errCode [%d]!\n",
+ __func__, errCode);
+ return errCode;
+ }
}
+ /* reset the Tuner */
+ if ((dev->model == CX231XX_BOARD_CNXT_CARRAERA) ||
+ (dev->model == CX231XX_BOARD_CNXT_RDE_250) ||
+ (dev->model == CX231XX_BOARD_CNXT_SHELBY) ||
+ (dev->model == CX231XX_BOARD_CNXT_RDU_250))
+ cx231xx_gpio_set(dev, dev->board.tuner_gpio);
+
/* initialize Colibri block */
errCode = cx231xx_afe_init_super_block(dev, 0x23c);
if (errCode < 0) {
@@ -907,7 +1372,22 @@ int cx231xx_dev_init(struct cx231xx *dev)
}
/* set AGC mode to Analog */
+ switch (dev->model) {
+ case CX231XX_BOARD_CNXT_CARRAERA:
+ case CX231XX_BOARD_CNXT_RDE_250:
+ case CX231XX_BOARD_CNXT_SHELBY:
+ case CX231XX_BOARD_CNXT_RDU_250:
errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 1);
+ break;
+ case CX231XX_BOARD_CNXT_RDE_253S:
+ case CX231XX_BOARD_CNXT_RDU_253S:
+ case CX231XX_BOARD_HAUPPAUGE_EXETER:
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+ errCode = cx231xx_set_agc_analog_digital_mux_select(dev, 0);
+ break;
+ default:
+ break;
+ }
if (errCode < 0) {
cx231xx_errdev
("%s: cx231xx_AGC mode to Analog - errCode [%d]!\n",
@@ -923,7 +1403,7 @@ int cx231xx_dev_init(struct cx231xx *dev)
cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
/* set the I2C master port to 3 on channel 1 */
- errCode = cx231xx_enable_i2c_for_tuner(dev, I2C_3);
+ errCode = cx231xx_enable_i2c_port_3(dev, true);
return errCode;
}
@@ -941,7 +1421,7 @@ EXPORT_SYMBOL_GPL(cx231xx_dev_uninit);
/*****************************************************************
* G P I O related functions *
******************************************************************/
-int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 * gpio_val,
+int cx231xx_send_gpio_cmd(struct cx231xx *dev, u32 gpio_bit, u8 *gpio_val,
u8 len, u8 request, u8 direction)
{
int status = 0;
@@ -1026,6 +1506,91 @@ int cx231xx_mode_register(struct cx231xx *dev, u16 address, u32 mode)
/*****************************************************************
* I 2 C Internal C O N T R O L functions *
*****************************************************************/
+int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+ u8 saddr_len, u32 *data, u8 data_len, int master)
+{
+ int status = 0;
+ struct cx231xx_i2c_xfer_data req_data;
+ u8 value[64] = "0";
+
+ if (saddr_len == 0)
+ saddr = 0;
+ else if (saddr_len == 1)
+ saddr &= 0xff;
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = dev_addr >> 1;
+ req_data.direction = I2C_M_RD;
+ req_data.saddr_len = saddr_len;
+ req_data.saddr_dat = saddr;
+ req_data.buf_size = data_len;
+ req_data.p_buffer = (u8 *) value;
+
+ /* usb send command */
+ if (master == 0)
+ status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0],
+ &req_data);
+ else if (master == 1)
+ status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1],
+ &req_data);
+ else if (master == 2)
+ status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2],
+ &req_data);
+
+ if (status >= 0) {
+ /* Copy the data read back to main buffer */
+ if (data_len == 1)
+ *data = value[0];
+ else if (data_len == 4)
+ *data =
+ value[0] | value[1] << 8 | value[2] << 16 | value[3]
+ << 24;
+ else if (data_len > 4)
+ *data = value[saddr];
+ }
+
+ return status;
+}
+
+int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+ u8 saddr_len, u32 data, u8 data_len, int master)
+{
+ int status = 0;
+ u8 value[4] = { 0, 0, 0, 0 };
+ struct cx231xx_i2c_xfer_data req_data;
+
+ value[0] = (u8) data;
+ value[1] = (u8) (data >> 8);
+ value[2] = (u8) (data >> 16);
+ value[3] = (u8) (data >> 24);
+
+ if (saddr_len == 0)
+ saddr = 0;
+ else if (saddr_len == 1)
+ saddr &= 0xff;
+
+ /* prepare xfer_data struct */
+ req_data.dev_addr = dev_addr >> 1;
+ req_data.direction = 0;
+ req_data.saddr_len = saddr_len;
+ req_data.saddr_dat = saddr;
+ req_data.buf_size = data_len;
+ req_data.p_buffer = value;
+
+ /* usb send command */
+ if (master == 0)
+ status = dev->cx231xx_send_usb_command(&dev->i2c_bus[0],
+ &req_data);
+ else if (master == 1)
+ status = dev->cx231xx_send_usb_command(&dev->i2c_bus[1],
+ &req_data);
+ else if (master == 2)
+ status = dev->cx231xx_send_usb_command(&dev->i2c_bus[2],
+ &req_data);
+
+ return status;
+}
+
int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
u8 saddr_len, u32 *data, u8 data_len)
{
@@ -1035,7 +1600,7 @@ int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
if (saddr_len == 0)
saddr = 0;
- else if (saddr_len == 0)
+ else if (saddr_len == 1)
saddr &= 0xff;
/* prepare xfer_data struct */
@@ -1076,7 +1641,7 @@ int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr, u16 saddr,
if (saddr_len == 0)
saddr = 0;
- else if (saddr_len == 0)
+ else if (saddr_len == 1)
saddr &= 0xff;
/* prepare xfer_data struct */
diff --git a/drivers/media/video/cx231xx/cx231xx-dif.h b/drivers/media/video/cx231xx/cx231xx-dif.h
new file mode 100644
index 000000000000..2b63c2f6d3b0
--- /dev/null
+++ b/drivers/media/video/cx231xx/cx231xx-dif.h
@@ -0,0 +1,3178 @@
+/*
+ * cx231xx-dif.h - driver for Conexant Cx23100/101/102 USB video capture devices
+ *
+ * Copyright {C} 2009 <Bill.Liu@conexant.com>
+ *
+ * This program is free software, you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY, without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program, if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#ifndef _CX231XX_DIF_H
+#define _CX231XX_DIF_H
+
+#include "cx231xx-reg.h"
+
+struct dif_settings{
+ u32 if_freq;
+ u32 register_address;
+ u32 value;
+};
+
+static struct dif_settings Dif_set_array[] = {
+
+/*case 3000000:*/
+/* BEGIN - DIF BPF register values from 30_quant.dat*/
+{3000000, DIF_BPF_COEFF01, 0x00000002},
+{3000000, DIF_BPF_COEFF23, 0x00080012},
+{3000000, DIF_BPF_COEFF45, 0x001e0024},
+{3000000, DIF_BPF_COEFF67, 0x001bfff8},
+{3000000, DIF_BPF_COEFF89, 0xffb4ff50},
+{3000000, DIF_BPF_COEFF1011, 0xfed8fe68},
+{3000000, DIF_BPF_COEFF1213, 0xfe24fe34},
+{3000000, DIF_BPF_COEFF1415, 0xfebaffc7},
+{3000000, DIF_BPF_COEFF1617, 0x014d031f},
+{3000000, DIF_BPF_COEFF1819, 0x04f0065d},
+{3000000, DIF_BPF_COEFF2021, 0x07010688},
+{3000000, DIF_BPF_COEFF2223, 0x04c901d6},
+{3000000, DIF_BPF_COEFF2425, 0xfe00f9d3},
+{3000000, DIF_BPF_COEFF2627, 0xf600f342},
+{3000000, DIF_BPF_COEFF2829, 0xf235f337},
+{3000000, DIF_BPF_COEFF3031, 0xf64efb22},
+{3000000, DIF_BPF_COEFF3233, 0x0105070f},
+{3000000, DIF_BPF_COEFF3435, 0x0c460fce},
+{3000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 30_quant.dat*/
+
+
+/*case 3100000:*/
+/* BEGIN - DIF BPF register values from 31_quant.dat*/
+{3100000, DIF_BPF_COEFF01, 0x00000001},
+{3100000, DIF_BPF_COEFF23, 0x00070012},
+{3100000, DIF_BPF_COEFF45, 0x00220032},
+{3100000, DIF_BPF_COEFF67, 0x00370026},
+{3100000, DIF_BPF_COEFF89, 0xfff0ff91},
+{3100000, DIF_BPF_COEFF1011, 0xff0efe7c},
+{3100000, DIF_BPF_COEFF1213, 0xfe01fdcc},
+{3100000, DIF_BPF_COEFF1415, 0xfe0afedb},
+{3100000, DIF_BPF_COEFF1617, 0x00440224},
+{3100000, DIF_BPF_COEFF1819, 0x0434060c},
+{3100000, DIF_BPF_COEFF2021, 0x0738074e},
+{3100000, DIF_BPF_COEFF2223, 0x06090361},
+{3100000, DIF_BPF_COEFF2425, 0xff99fb39},
+{3100000, DIF_BPF_COEFF2627, 0xf6fef3b6},
+{3100000, DIF_BPF_COEFF2829, 0xf21af2a5},
+{3100000, DIF_BPF_COEFF3031, 0xf573fa33},
+{3100000, DIF_BPF_COEFF3233, 0x0034067d},
+{3100000, DIF_BPF_COEFF3435, 0x0bfb0fb9},
+{3100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 31_quant.dat*/
+
+
+/*case 3200000:*/
+/* BEGIN - DIF BPF register values from 32_quant.dat*/
+{3200000, DIF_BPF_COEFF01, 0x00000000},
+{3200000, DIF_BPF_COEFF23, 0x0004000e},
+{3200000, DIF_BPF_COEFF45, 0x00200038},
+{3200000, DIF_BPF_COEFF67, 0x004c004f},
+{3200000, DIF_BPF_COEFF89, 0x002fffdf},
+{3200000, DIF_BPF_COEFF1011, 0xff5cfeb6},
+{3200000, DIF_BPF_COEFF1213, 0xfe0dfd92},
+{3200000, DIF_BPF_COEFF1415, 0xfd7ffe03},
+{3200000, DIF_BPF_COEFF1617, 0xff36010a},
+{3200000, DIF_BPF_COEFF1819, 0x03410575},
+{3200000, DIF_BPF_COEFF2021, 0x072607d2},
+{3200000, DIF_BPF_COEFF2223, 0x071804d5},
+{3200000, DIF_BPF_COEFF2425, 0x0134fcb7},
+{3200000, DIF_BPF_COEFF2627, 0xf81ff451},
+{3200000, DIF_BPF_COEFF2829, 0xf223f22e},
+{3200000, DIF_BPF_COEFF3031, 0xf4a7f94b},
+{3200000, DIF_BPF_COEFF3233, 0xff6405e8},
+{3200000, DIF_BPF_COEFF3435, 0x0bae0fa4},
+{3200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 32_quant.dat*/
+
+
+/*case 3300000:*/
+/* BEGIN - DIF BPF register values from 33_quant.dat*/
+{3300000, DIF_BPF_COEFF01, 0x0000ffff},
+{3300000, DIF_BPF_COEFF23, 0x00000008},
+{3300000, DIF_BPF_COEFF45, 0x001a0036},
+{3300000, DIF_BPF_COEFF67, 0x0056006d},
+{3300000, DIF_BPF_COEFF89, 0x00670030},
+{3300000, DIF_BPF_COEFF1011, 0xffbdff10},
+{3300000, DIF_BPF_COEFF1213, 0xfe46fd8d},
+{3300000, DIF_BPF_COEFF1415, 0xfd25fd4f},
+{3300000, DIF_BPF_COEFF1617, 0xfe35ffe0},
+{3300000, DIF_BPF_COEFF1819, 0x0224049f},
+{3300000, DIF_BPF_COEFF2021, 0x06c9080e},
+{3300000, DIF_BPF_COEFF2223, 0x07ef0627},
+{3300000, DIF_BPF_COEFF2425, 0x02c9fe45},
+{3300000, DIF_BPF_COEFF2627, 0xf961f513},
+{3300000, DIF_BPF_COEFF2829, 0xf250f1d2},
+{3300000, DIF_BPF_COEFF3031, 0xf3ecf869},
+{3300000, DIF_BPF_COEFF3233, 0xfe930552},
+{3300000, DIF_BPF_COEFF3435, 0x0b5f0f8f},
+{3300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 33_quant.dat*/
+
+
+/*case 3400000:*/
+/* BEGIN - DIF BPF register values from 34_quant.dat*/
+{3400000, DIF_BPF_COEFF01, 0xfffffffe},
+{3400000, DIF_BPF_COEFF23, 0xfffd0001},
+{3400000, DIF_BPF_COEFF45, 0x000f002c},
+{3400000, DIF_BPF_COEFF67, 0x0054007d},
+{3400000, DIF_BPF_COEFF89, 0x0093007c},
+{3400000, DIF_BPF_COEFF1011, 0x0024ff82},
+{3400000, DIF_BPF_COEFF1213, 0xfea6fdbb},
+{3400000, DIF_BPF_COEFF1415, 0xfd03fcca},
+{3400000, DIF_BPF_COEFF1617, 0xfd51feb9},
+{3400000, DIF_BPF_COEFF1819, 0x00eb0392},
+{3400000, DIF_BPF_COEFF2021, 0x06270802},
+{3400000, DIF_BPF_COEFF2223, 0x08880750},
+{3400000, DIF_BPF_COEFF2425, 0x044dffdb},
+{3400000, DIF_BPF_COEFF2627, 0xfabdf5f8},
+{3400000, DIF_BPF_COEFF2829, 0xf2a0f193},
+{3400000, DIF_BPF_COEFF3031, 0xf342f78f},
+{3400000, DIF_BPF_COEFF3233, 0xfdc404b9},
+{3400000, DIF_BPF_COEFF3435, 0x0b0e0f78},
+{3400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 34_quant.dat*/
+
+
+/*case 3500000:*/
+/* BEGIN - DIF BPF register values from 35_quant.dat*/
+{3500000, DIF_BPF_COEFF01, 0xfffffffd},
+{3500000, DIF_BPF_COEFF23, 0xfffafff9},
+{3500000, DIF_BPF_COEFF45, 0x0002001b},
+{3500000, DIF_BPF_COEFF67, 0x0046007d},
+{3500000, DIF_BPF_COEFF89, 0x00ad00ba},
+{3500000, DIF_BPF_COEFF1011, 0x00870000},
+{3500000, DIF_BPF_COEFF1213, 0xff26fe1a},
+{3500000, DIF_BPF_COEFF1415, 0xfd1bfc7e},
+{3500000, DIF_BPF_COEFF1617, 0xfc99fda4},
+{3500000, DIF_BPF_COEFF1819, 0xffa5025c},
+{3500000, DIF_BPF_COEFF2021, 0x054507ad},
+{3500000, DIF_BPF_COEFF2223, 0x08dd0847},
+{3500000, DIF_BPF_COEFF2425, 0x05b80172},
+{3500000, DIF_BPF_COEFF2627, 0xfc2ef6ff},
+{3500000, DIF_BPF_COEFF2829, 0xf313f170},
+{3500000, DIF_BPF_COEFF3031, 0xf2abf6bd},
+{3500000, DIF_BPF_COEFF3233, 0xfcf6041f},
+{3500000, DIF_BPF_COEFF3435, 0x0abc0f61},
+{3500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 35_quant.dat*/
+
+
+/*case 3600000:*/
+/* BEGIN - DIF BPF register values from 36_quant.dat*/
+{3600000, DIF_BPF_COEFF01, 0xfffffffd},
+{3600000, DIF_BPF_COEFF23, 0xfff8fff3},
+{3600000, DIF_BPF_COEFF45, 0xfff50006},
+{3600000, DIF_BPF_COEFF67, 0x002f006c},
+{3600000, DIF_BPF_COEFF89, 0x00b200e3},
+{3600000, DIF_BPF_COEFF1011, 0x00dc007e},
+{3600000, DIF_BPF_COEFF1213, 0xffb9fea0},
+{3600000, DIF_BPF_COEFF1415, 0xfd6bfc71},
+{3600000, DIF_BPF_COEFF1617, 0xfc17fcb1},
+{3600000, DIF_BPF_COEFF1819, 0xfe65010b},
+{3600000, DIF_BPF_COEFF2021, 0x042d0713},
+{3600000, DIF_BPF_COEFF2223, 0x08ec0906},
+{3600000, DIF_BPF_COEFF2425, 0x07020302},
+{3600000, DIF_BPF_COEFF2627, 0xfdaff823},
+{3600000, DIF_BPF_COEFF2829, 0xf3a7f16a},
+{3600000, DIF_BPF_COEFF3031, 0xf228f5f5},
+{3600000, DIF_BPF_COEFF3233, 0xfc2a0384},
+{3600000, DIF_BPF_COEFF3435, 0x0a670f4a},
+{3600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 36_quant.dat*/
+
+
+/*case 3700000:*/
+/* BEGIN - DIF BPF register values from 37_quant.dat*/
+{3700000, DIF_BPF_COEFF01, 0x0000fffd},
+{3700000, DIF_BPF_COEFF23, 0xfff7ffef},
+{3700000, DIF_BPF_COEFF45, 0xffe9fff1},
+{3700000, DIF_BPF_COEFF67, 0x0010004d},
+{3700000, DIF_BPF_COEFF89, 0x00a100f2},
+{3700000, DIF_BPF_COEFF1011, 0x011a00f0},
+{3700000, DIF_BPF_COEFF1213, 0x0053ff44},
+{3700000, DIF_BPF_COEFF1415, 0xfdedfca2},
+{3700000, DIF_BPF_COEFF1617, 0xfbd3fbef},
+{3700000, DIF_BPF_COEFF1819, 0xfd39ffae},
+{3700000, DIF_BPF_COEFF2021, 0x02ea0638},
+{3700000, DIF_BPF_COEFF2223, 0x08b50987},
+{3700000, DIF_BPF_COEFF2425, 0x08230483},
+{3700000, DIF_BPF_COEFF2627, 0xff39f960},
+{3700000, DIF_BPF_COEFF2829, 0xf45bf180},
+{3700000, DIF_BPF_COEFF3031, 0xf1b8f537},
+{3700000, DIF_BPF_COEFF3233, 0xfb6102e7},
+{3700000, DIF_BPF_COEFF3435, 0x0a110f32},
+{3700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 37_quant.dat*/
+
+
+/*case 3800000:*/
+/* BEGIN - DIF BPF register values from 38_quant.dat*/
+{3800000, DIF_BPF_COEFF01, 0x0000fffe},
+{3800000, DIF_BPF_COEFF23, 0xfff9ffee},
+{3800000, DIF_BPF_COEFF45, 0xffe1ffdd},
+{3800000, DIF_BPF_COEFF67, 0xfff00024},
+{3800000, DIF_BPF_COEFF89, 0x007c00e5},
+{3800000, DIF_BPF_COEFF1011, 0x013a014a},
+{3800000, DIF_BPF_COEFF1213, 0x00e6fff8},
+{3800000, DIF_BPF_COEFF1415, 0xfe98fd0f},
+{3800000, DIF_BPF_COEFF1617, 0xfbd3fb67},
+{3800000, DIF_BPF_COEFF1819, 0xfc32fe54},
+{3800000, DIF_BPF_COEFF2021, 0x01880525},
+{3800000, DIF_BPF_COEFF2223, 0x083909c7},
+{3800000, DIF_BPF_COEFF2425, 0x091505ee},
+{3800000, DIF_BPF_COEFF2627, 0x00c7fab3},
+{3800000, DIF_BPF_COEFF2829, 0xf52df1b4},
+{3800000, DIF_BPF_COEFF3031, 0xf15df484},
+{3800000, DIF_BPF_COEFF3233, 0xfa9b0249},
+{3800000, DIF_BPF_COEFF3435, 0x09ba0f19},
+{3800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 38_quant.dat*/
+
+
+/*case 3900000:*/
+/* BEGIN - DIF BPF register values from 39_quant.dat*/
+{3900000, DIF_BPF_COEFF01, 0x00000000},
+{3900000, DIF_BPF_COEFF23, 0xfffbfff0},
+{3900000, DIF_BPF_COEFF45, 0xffdeffcf},
+{3900000, DIF_BPF_COEFF67, 0xffd1fff6},
+{3900000, DIF_BPF_COEFF89, 0x004800be},
+{3900000, DIF_BPF_COEFF1011, 0x01390184},
+{3900000, DIF_BPF_COEFF1213, 0x016300ac},
+{3900000, DIF_BPF_COEFF1415, 0xff5efdb1},
+{3900000, DIF_BPF_COEFF1617, 0xfc17fb23},
+{3900000, DIF_BPF_COEFF1819, 0xfb5cfd0d},
+{3900000, DIF_BPF_COEFF2021, 0x001703e4},
+{3900000, DIF_BPF_COEFF2223, 0x077b09c4},
+{3900000, DIF_BPF_COEFF2425, 0x09d2073c},
+{3900000, DIF_BPF_COEFF2627, 0x0251fc18},
+{3900000, DIF_BPF_COEFF2829, 0xf61cf203},
+{3900000, DIF_BPF_COEFF3031, 0xf118f3dc},
+{3900000, DIF_BPF_COEFF3233, 0xf9d801aa},
+{3900000, DIF_BPF_COEFF3435, 0x09600eff},
+{3900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 39_quant.dat*/
+
+
+/*case 4000000:*/
+/* BEGIN - DIF BPF register values from 40_quant.dat*/
+{4000000, DIF_BPF_COEFF01, 0x00000001},
+{4000000, DIF_BPF_COEFF23, 0xfffefff4},
+{4000000, DIF_BPF_COEFF45, 0xffe1ffc8},
+{4000000, DIF_BPF_COEFF67, 0xffbaffca},
+{4000000, DIF_BPF_COEFF89, 0x000b0082},
+{4000000, DIF_BPF_COEFF1011, 0x01170198},
+{4000000, DIF_BPF_COEFF1213, 0x01c10152},
+{4000000, DIF_BPF_COEFF1415, 0x0030fe7b},
+{4000000, DIF_BPF_COEFF1617, 0xfc99fb24},
+{4000000, DIF_BPF_COEFF1819, 0xfac3fbe9},
+{4000000, DIF_BPF_COEFF2021, 0xfea5027f},
+{4000000, DIF_BPF_COEFF2223, 0x0683097f},
+{4000000, DIF_BPF_COEFF2425, 0x0a560867},
+{4000000, DIF_BPF_COEFF2627, 0x03d2fd89},
+{4000000, DIF_BPF_COEFF2829, 0xf723f26f},
+{4000000, DIF_BPF_COEFF3031, 0xf0e8f341},
+{4000000, DIF_BPF_COEFF3233, 0xf919010a},
+{4000000, DIF_BPF_COEFF3435, 0x09060ee5},
+{4000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 40_quant.dat*/
+
+
+/*case 4100000:*/
+/* BEGIN - DIF BPF register values from 41_quant.dat*/
+{4100000, DIF_BPF_COEFF01, 0x00010002},
+{4100000, DIF_BPF_COEFF23, 0x0002fffb},
+{4100000, DIF_BPF_COEFF45, 0xffe8ffca},
+{4100000, DIF_BPF_COEFF67, 0xffacffa4},
+{4100000, DIF_BPF_COEFF89, 0xffcd0036},
+{4100000, DIF_BPF_COEFF1011, 0x00d70184},
+{4100000, DIF_BPF_COEFF1213, 0x01f601dc},
+{4100000, DIF_BPF_COEFF1415, 0x00ffff60},
+{4100000, DIF_BPF_COEFF1617, 0xfd51fb6d},
+{4100000, DIF_BPF_COEFF1819, 0xfa6efaf5},
+{4100000, DIF_BPF_COEFF2021, 0xfd410103},
+{4100000, DIF_BPF_COEFF2223, 0x055708f9},
+{4100000, DIF_BPF_COEFF2425, 0x0a9e0969},
+{4100000, DIF_BPF_COEFF2627, 0x0543ff02},
+{4100000, DIF_BPF_COEFF2829, 0xf842f2f5},
+{4100000, DIF_BPF_COEFF3031, 0xf0cef2b2},
+{4100000, DIF_BPF_COEFF3233, 0xf85e006b},
+{4100000, DIF_BPF_COEFF3435, 0x08aa0ecb},
+{4100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 41_quant.dat*/
+
+
+/*case 4200000:*/
+/* BEGIN - DIF BPF register values from 42_quant.dat*/
+{4200000, DIF_BPF_COEFF01, 0x00010003},
+{4200000, DIF_BPF_COEFF23, 0x00050003},
+{4200000, DIF_BPF_COEFF45, 0xfff3ffd3},
+{4200000, DIF_BPF_COEFF67, 0xffaaff8b},
+{4200000, DIF_BPF_COEFF89, 0xff95ffe5},
+{4200000, DIF_BPF_COEFF1011, 0x0080014a},
+{4200000, DIF_BPF_COEFF1213, 0x01fe023f},
+{4200000, DIF_BPF_COEFF1415, 0x01ba0050},
+{4200000, DIF_BPF_COEFF1617, 0xfe35fbf8},
+{4200000, DIF_BPF_COEFF1819, 0xfa62fa3b},
+{4200000, DIF_BPF_COEFF2021, 0xfbf9ff7e},
+{4200000, DIF_BPF_COEFF2223, 0x04010836},
+{4200000, DIF_BPF_COEFF2425, 0x0aa90a3d},
+{4200000, DIF_BPF_COEFF2627, 0x069f007f},
+{4200000, DIF_BPF_COEFF2829, 0xf975f395},
+{4200000, DIF_BPF_COEFF3031, 0xf0cbf231},
+{4200000, DIF_BPF_COEFF3233, 0xf7a9ffcb},
+{4200000, DIF_BPF_COEFF3435, 0x084c0eaf},
+{4200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 42_quant.dat*/
+
+
+/*case 4300000:*/
+/* BEGIN - DIF BPF register values from 43_quant.dat*/
+{4300000, DIF_BPF_COEFF01, 0x00010003},
+{4300000, DIF_BPF_COEFF23, 0x0008000a},
+{4300000, DIF_BPF_COEFF45, 0x0000ffe4},
+{4300000, DIF_BPF_COEFF67, 0xffb4ff81},
+{4300000, DIF_BPF_COEFF89, 0xff6aff96},
+{4300000, DIF_BPF_COEFF1011, 0x001c00f0},
+{4300000, DIF_BPF_COEFF1213, 0x01d70271},
+{4300000, DIF_BPF_COEFF1415, 0x0254013b},
+{4300000, DIF_BPF_COEFF1617, 0xff36fcbd},
+{4300000, DIF_BPF_COEFF1819, 0xfa9ff9c5},
+{4300000, DIF_BPF_COEFF2021, 0xfadbfdfe},
+{4300000, DIF_BPF_COEFF2223, 0x028c073b},
+{4300000, DIF_BPF_COEFF2425, 0x0a750adf},
+{4300000, DIF_BPF_COEFF2627, 0x07e101fa},
+{4300000, DIF_BPF_COEFF2829, 0xfab8f44e},
+{4300000, DIF_BPF_COEFF3031, 0xf0ddf1be},
+{4300000, DIF_BPF_COEFF3233, 0xf6f9ff2b},
+{4300000, DIF_BPF_COEFF3435, 0x07ed0e94},
+{4300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 43_quant.dat*/
+
+
+/*case 4400000:*/
+/* BEGIN - DIF BPF register values from 44_quant.dat*/
+{4400000, DIF_BPF_COEFF01, 0x00000003},
+{4400000, DIF_BPF_COEFF23, 0x0009000f},
+{4400000, DIF_BPF_COEFF45, 0x000efff8},
+{4400000, DIF_BPF_COEFF67, 0xffc9ff87},
+{4400000, DIF_BPF_COEFF89, 0xff52ff54},
+{4400000, DIF_BPF_COEFF1011, 0xffb5007e},
+{4400000, DIF_BPF_COEFF1213, 0x01860270},
+{4400000, DIF_BPF_COEFF1415, 0x02c00210},
+{4400000, DIF_BPF_COEFF1617, 0x0044fdb2},
+{4400000, DIF_BPF_COEFF1819, 0xfb22f997},
+{4400000, DIF_BPF_COEFF2021, 0xf9f2fc90},
+{4400000, DIF_BPF_COEFF2223, 0x0102060f},
+{4400000, DIF_BPF_COEFF2425, 0x0a050b4c},
+{4400000, DIF_BPF_COEFF2627, 0x0902036e},
+{4400000, DIF_BPF_COEFF2829, 0xfc0af51e},
+{4400000, DIF_BPF_COEFF3031, 0xf106f15a},
+{4400000, DIF_BPF_COEFF3233, 0xf64efe8b},
+{4400000, DIF_BPF_COEFF3435, 0x078d0e77},
+{4400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 44_quant.dat*/
+
+
+/*case 4500000:*/
+/* BEGIN - DIF BPF register values from 45_quant.dat*/
+{4500000, DIF_BPF_COEFF01, 0x00000002},
+{4500000, DIF_BPF_COEFF23, 0x00080012},
+{4500000, DIF_BPF_COEFF45, 0x0019000e},
+{4500000, DIF_BPF_COEFF67, 0xffe5ff9e},
+{4500000, DIF_BPF_COEFF89, 0xff4fff25},
+{4500000, DIF_BPF_COEFF1011, 0xff560000},
+{4500000, DIF_BPF_COEFF1213, 0x0112023b},
+{4500000, DIF_BPF_COEFF1415, 0x02f702c0},
+{4500000, DIF_BPF_COEFF1617, 0x014dfec8},
+{4500000, DIF_BPF_COEFF1819, 0xfbe5f9b3},
+{4500000, DIF_BPF_COEFF2021, 0xf947fb41},
+{4500000, DIF_BPF_COEFF2223, 0xff7004b9},
+{4500000, DIF_BPF_COEFF2425, 0x095a0b81},
+{4500000, DIF_BPF_COEFF2627, 0x0a0004d8},
+{4500000, DIF_BPF_COEFF2829, 0xfd65f603},
+{4500000, DIF_BPF_COEFF3031, 0xf144f104},
+{4500000, DIF_BPF_COEFF3233, 0xf5aafdec},
+{4500000, DIF_BPF_COEFF3435, 0x072b0e5a},
+{4500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 45_quant.dat*/
+
+
+/*case 4600000:*/
+/* BEGIN - DIF BPF register values from 46_quant.dat*/
+{4600000, DIF_BPF_COEFF01, 0x00000001},
+{4600000, DIF_BPF_COEFF23, 0x00060012},
+{4600000, DIF_BPF_COEFF45, 0x00200022},
+{4600000, DIF_BPF_COEFF67, 0x0005ffc1},
+{4600000, DIF_BPF_COEFF89, 0xff61ff10},
+{4600000, DIF_BPF_COEFF1011, 0xff09ff82},
+{4600000, DIF_BPF_COEFF1213, 0x008601d7},
+{4600000, DIF_BPF_COEFF1415, 0x02f50340},
+{4600000, DIF_BPF_COEFF1617, 0x0241fff0},
+{4600000, DIF_BPF_COEFF1819, 0xfcddfa19},
+{4600000, DIF_BPF_COEFF2021, 0xf8e2fa1e},
+{4600000, DIF_BPF_COEFF2223, 0xfde30343},
+{4600000, DIF_BPF_COEFF2425, 0x08790b7f},
+{4600000, DIF_BPF_COEFF2627, 0x0ad50631},
+{4600000, DIF_BPF_COEFF2829, 0xfec7f6fc},
+{4600000, DIF_BPF_COEFF3031, 0xf198f0bd},
+{4600000, DIF_BPF_COEFF3233, 0xf50dfd4e},
+{4600000, DIF_BPF_COEFF3435, 0x06c90e3d},
+{4600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 46_quant.dat*/
+
+
+/*case 4700000:*/
+/* BEGIN - DIF BPF register values from 47_quant.dat*/
+{4700000, DIF_BPF_COEFF01, 0x0000ffff},
+{4700000, DIF_BPF_COEFF23, 0x0003000f},
+{4700000, DIF_BPF_COEFF45, 0x00220030},
+{4700000, DIF_BPF_COEFF67, 0x0025ffed},
+{4700000, DIF_BPF_COEFF89, 0xff87ff15},
+{4700000, DIF_BPF_COEFF1011, 0xfed6ff10},
+{4700000, DIF_BPF_COEFF1213, 0xffed014c},
+{4700000, DIF_BPF_COEFF1415, 0x02b90386},
+{4700000, DIF_BPF_COEFF1617, 0x03110119},
+{4700000, DIF_BPF_COEFF1819, 0xfdfefac4},
+{4700000, DIF_BPF_COEFF2021, 0xf8c6f92f},
+{4700000, DIF_BPF_COEFF2223, 0xfc6701b7},
+{4700000, DIF_BPF_COEFF2425, 0x07670b44},
+{4700000, DIF_BPF_COEFF2627, 0x0b7e0776},
+{4700000, DIF_BPF_COEFF2829, 0x002df807},
+{4700000, DIF_BPF_COEFF3031, 0xf200f086},
+{4700000, DIF_BPF_COEFF3233, 0xf477fcb1},
+{4700000, DIF_BPF_COEFF3435, 0x06650e1e},
+{4700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 47_quant.dat*/
+
+
+/*case 4800000:*/
+/* BEGIN - DIF BPF register values from 48_quant.dat*/
+{4800000, DIF_BPF_COEFF01, 0xfffffffe},
+{4800000, DIF_BPF_COEFF23, 0xffff0009},
+{4800000, DIF_BPF_COEFF45, 0x001e0038},
+{4800000, DIF_BPF_COEFF67, 0x003f001b},
+{4800000, DIF_BPF_COEFF89, 0xffbcff36},
+{4800000, DIF_BPF_COEFF1011, 0xfec2feb6},
+{4800000, DIF_BPF_COEFF1213, 0xff5600a5},
+{4800000, DIF_BPF_COEFF1415, 0x0248038d},
+{4800000, DIF_BPF_COEFF1617, 0x03b00232},
+{4800000, DIF_BPF_COEFF1819, 0xff39fbab},
+{4800000, DIF_BPF_COEFF2021, 0xf8f4f87f},
+{4800000, DIF_BPF_COEFF2223, 0xfb060020},
+{4800000, DIF_BPF_COEFF2425, 0x062a0ad2},
+{4800000, DIF_BPF_COEFF2627, 0x0bf908a3},
+{4800000, DIF_BPF_COEFF2829, 0x0192f922},
+{4800000, DIF_BPF_COEFF3031, 0xf27df05e},
+{4800000, DIF_BPF_COEFF3233, 0xf3e8fc14},
+{4800000, DIF_BPF_COEFF3435, 0x06000e00},
+{4800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 48_quant.dat*/
+
+
+/*case 4900000:*/
+/* BEGIN - DIF BPF register values from 49_quant.dat*/
+{4900000, DIF_BPF_COEFF01, 0xfffffffd},
+{4900000, DIF_BPF_COEFF23, 0xfffc0002},
+{4900000, DIF_BPF_COEFF45, 0x00160037},
+{4900000, DIF_BPF_COEFF67, 0x00510046},
+{4900000, DIF_BPF_COEFF89, 0xfff9ff6d},
+{4900000, DIF_BPF_COEFF1011, 0xfed0fe7c},
+{4900000, DIF_BPF_COEFF1213, 0xfecefff0},
+{4900000, DIF_BPF_COEFF1415, 0x01aa0356},
+{4900000, DIF_BPF_COEFF1617, 0x0413032b},
+{4900000, DIF_BPF_COEFF1819, 0x007ffcc5},
+{4900000, DIF_BPF_COEFF2021, 0xf96cf812},
+{4900000, DIF_BPF_COEFF2223, 0xf9cefe87},
+{4900000, DIF_BPF_COEFF2425, 0x04c90a2c},
+{4900000, DIF_BPF_COEFF2627, 0x0c4309b4},
+{4900000, DIF_BPF_COEFF2829, 0x02f3fa4a},
+{4900000, DIF_BPF_COEFF3031, 0xf30ef046},
+{4900000, DIF_BPF_COEFF3233, 0xf361fb7a},
+{4900000, DIF_BPF_COEFF3435, 0x059b0de0},
+{4900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 49_quant.dat*/
+
+
+/*case 5000000:*/
+/* BEGIN - DIF BPF register values from 50_quant.dat*/
+{5000000, DIF_BPF_COEFF01, 0xfffffffd},
+{5000000, DIF_BPF_COEFF23, 0xfff9fffa},
+{5000000, DIF_BPF_COEFF45, 0x000a002d},
+{5000000, DIF_BPF_COEFF67, 0x00570067},
+{5000000, DIF_BPF_COEFF89, 0x0037ffb5},
+{5000000, DIF_BPF_COEFF1011, 0xfefffe68},
+{5000000, DIF_BPF_COEFF1213, 0xfe62ff3d},
+{5000000, DIF_BPF_COEFF1415, 0x00ec02e3},
+{5000000, DIF_BPF_COEFF1617, 0x043503f6},
+{5000000, DIF_BPF_COEFF1819, 0x01befe05},
+{5000000, DIF_BPF_COEFF2021, 0xfa27f7ee},
+{5000000, DIF_BPF_COEFF2223, 0xf8c6fcf8},
+{5000000, DIF_BPF_COEFF2425, 0x034c0954},
+{5000000, DIF_BPF_COEFF2627, 0x0c5c0aa4},
+{5000000, DIF_BPF_COEFF2829, 0x044cfb7e},
+{5000000, DIF_BPF_COEFF3031, 0xf3b1f03f},
+{5000000, DIF_BPF_COEFF3233, 0xf2e2fae1},
+{5000000, DIF_BPF_COEFF3435, 0x05340dc0},
+{5000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 50_quant.dat*/
+
+
+/*case 5100000:*/
+/* BEGIN - DIF BPF register values from 51_quant.dat*/
+{5100000, DIF_BPF_COEFF01, 0x0000fffd},
+{5100000, DIF_BPF_COEFF23, 0xfff8fff4},
+{5100000, DIF_BPF_COEFF45, 0xfffd001e},
+{5100000, DIF_BPF_COEFF67, 0x0051007b},
+{5100000, DIF_BPF_COEFF89, 0x006e0006},
+{5100000, DIF_BPF_COEFF1011, 0xff48fe7c},
+{5100000, DIF_BPF_COEFF1213, 0xfe1bfe9a},
+{5100000, DIF_BPF_COEFF1415, 0x001d023e},
+{5100000, DIF_BPF_COEFF1617, 0x04130488},
+{5100000, DIF_BPF_COEFF1819, 0x02e6ff5b},
+{5100000, DIF_BPF_COEFF2021, 0xfb1ef812},
+{5100000, DIF_BPF_COEFF2223, 0xf7f7fb7f},
+{5100000, DIF_BPF_COEFF2425, 0x01bc084e},
+{5100000, DIF_BPF_COEFF2627, 0x0c430b72},
+{5100000, DIF_BPF_COEFF2829, 0x059afcba},
+{5100000, DIF_BPF_COEFF3031, 0xf467f046},
+{5100000, DIF_BPF_COEFF3233, 0xf26cfa4a},
+{5100000, DIF_BPF_COEFF3435, 0x04cd0da0},
+{5100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 51_quant.dat*/
+
+
+/*case 5200000:*/
+/* BEGIN - DIF BPF register values from 52_quant.dat*/
+{5200000, DIF_BPF_COEFF01, 0x0000fffe},
+{5200000, DIF_BPF_COEFF23, 0xfff8ffef},
+{5200000, DIF_BPF_COEFF45, 0xfff00009},
+{5200000, DIF_BPF_COEFF67, 0x003f007f},
+{5200000, DIF_BPF_COEFF89, 0x00980056},
+{5200000, DIF_BPF_COEFF1011, 0xffa5feb6},
+{5200000, DIF_BPF_COEFF1213, 0xfe00fe15},
+{5200000, DIF_BPF_COEFF1415, 0xff4b0170},
+{5200000, DIF_BPF_COEFF1617, 0x03b004d7},
+{5200000, DIF_BPF_COEFF1819, 0x03e800b9},
+{5200000, DIF_BPF_COEFF2021, 0xfc48f87f},
+{5200000, DIF_BPF_COEFF2223, 0xf768fa23},
+{5200000, DIF_BPF_COEFF2425, 0x0022071f},
+{5200000, DIF_BPF_COEFF2627, 0x0bf90c1b},
+{5200000, DIF_BPF_COEFF2829, 0x06dafdfd},
+{5200000, DIF_BPF_COEFF3031, 0xf52df05e},
+{5200000, DIF_BPF_COEFF3233, 0xf1fef9b5},
+{5200000, DIF_BPF_COEFF3435, 0x04640d7f},
+{5200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 52_quant.dat*/
+
+
+/*case 5300000:*/
+/* BEGIN - DIF BPF register values from 53_quant.dat*/
+{5300000, DIF_BPF_COEFF01, 0x0000ffff},
+{5300000, DIF_BPF_COEFF23, 0xfff9ffee},
+{5300000, DIF_BPF_COEFF45, 0xffe6fff3},
+{5300000, DIF_BPF_COEFF67, 0x00250072},
+{5300000, DIF_BPF_COEFF89, 0x00af009c},
+{5300000, DIF_BPF_COEFF1011, 0x000cff10},
+{5300000, DIF_BPF_COEFF1213, 0xfe13fdb8},
+{5300000, DIF_BPF_COEFF1415, 0xfe870089},
+{5300000, DIF_BPF_COEFF1617, 0x031104e1},
+{5300000, DIF_BPF_COEFF1819, 0x04b8020f},
+{5300000, DIF_BPF_COEFF2021, 0xfd98f92f},
+{5300000, DIF_BPF_COEFF2223, 0xf71df8f0},
+{5300000, DIF_BPF_COEFF2425, 0xfe8805ce},
+{5300000, DIF_BPF_COEFF2627, 0x0b7e0c9c},
+{5300000, DIF_BPF_COEFF2829, 0x0808ff44},
+{5300000, DIF_BPF_COEFF3031, 0xf603f086},
+{5300000, DIF_BPF_COEFF3233, 0xf19af922},
+{5300000, DIF_BPF_COEFF3435, 0x03fb0d5e},
+{5300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 53_quant.dat*/
+
+
+/*case 5400000:*/
+/* BEGIN - DIF BPF register values from 54_quant.dat*/
+{5400000, DIF_BPF_COEFF01, 0x00000001},
+{5400000, DIF_BPF_COEFF23, 0xfffcffef},
+{5400000, DIF_BPF_COEFF45, 0xffe0ffe0},
+{5400000, DIF_BPF_COEFF67, 0x00050056},
+{5400000, DIF_BPF_COEFF89, 0x00b000d1},
+{5400000, DIF_BPF_COEFF1011, 0x0071ff82},
+{5400000, DIF_BPF_COEFF1213, 0xfe53fd8c},
+{5400000, DIF_BPF_COEFF1415, 0xfddfff99},
+{5400000, DIF_BPF_COEFF1617, 0x024104a3},
+{5400000, DIF_BPF_COEFF1819, 0x054a034d},
+{5400000, DIF_BPF_COEFF2021, 0xff01fa1e},
+{5400000, DIF_BPF_COEFF2223, 0xf717f7ed},
+{5400000, DIF_BPF_COEFF2425, 0xfcf50461},
+{5400000, DIF_BPF_COEFF2627, 0x0ad50cf4},
+{5400000, DIF_BPF_COEFF2829, 0x0921008d},
+{5400000, DIF_BPF_COEFF3031, 0xf6e7f0bd},
+{5400000, DIF_BPF_COEFF3233, 0xf13ff891},
+{5400000, DIF_BPF_COEFF3435, 0x03920d3b},
+{5400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 54_quant.dat*/
+
+
+/*case 5500000:*/
+/* BEGIN - DIF BPF register values from 55_quant.dat*/
+{5500000, DIF_BPF_COEFF01, 0x00010002},
+{5500000, DIF_BPF_COEFF23, 0xfffffff3},
+{5500000, DIF_BPF_COEFF45, 0xffdeffd1},
+{5500000, DIF_BPF_COEFF67, 0xffe5002f},
+{5500000, DIF_BPF_COEFF89, 0x009c00ed},
+{5500000, DIF_BPF_COEFF1011, 0x00cb0000},
+{5500000, DIF_BPF_COEFF1213, 0xfebafd94},
+{5500000, DIF_BPF_COEFF1415, 0xfd61feb0},
+{5500000, DIF_BPF_COEFF1617, 0x014d0422},
+{5500000, DIF_BPF_COEFF1819, 0x05970464},
+{5500000, DIF_BPF_COEFF2021, 0x0074fb41},
+{5500000, DIF_BPF_COEFF2223, 0xf759f721},
+{5500000, DIF_BPF_COEFF2425, 0xfb7502de},
+{5500000, DIF_BPF_COEFF2627, 0x0a000d21},
+{5500000, DIF_BPF_COEFF2829, 0x0a2201d4},
+{5500000, DIF_BPF_COEFF3031, 0xf7d9f104},
+{5500000, DIF_BPF_COEFF3233, 0xf0edf804},
+{5500000, DIF_BPF_COEFF3435, 0x03280d19},
+{5500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 55_quant.dat*/
+
+
+/*case 5600000:*/
+/* BEGIN - DIF BPF register values from 56_quant.dat*/
+{5600000, DIF_BPF_COEFF01, 0x00010003},
+{5600000, DIF_BPF_COEFF23, 0x0003fffa},
+{5600000, DIF_BPF_COEFF45, 0xffe3ffc9},
+{5600000, DIF_BPF_COEFF67, 0xffc90002},
+{5600000, DIF_BPF_COEFF89, 0x007500ef},
+{5600000, DIF_BPF_COEFF1011, 0x010e007e},
+{5600000, DIF_BPF_COEFF1213, 0xff3dfdcf},
+{5600000, DIF_BPF_COEFF1415, 0xfd16fddd},
+{5600000, DIF_BPF_COEFF1617, 0x00440365},
+{5600000, DIF_BPF_COEFF1819, 0x059b0548},
+{5600000, DIF_BPF_COEFF2021, 0x01e3fc90},
+{5600000, DIF_BPF_COEFF2223, 0xf7dff691},
+{5600000, DIF_BPF_COEFF2425, 0xfa0f014d},
+{5600000, DIF_BPF_COEFF2627, 0x09020d23},
+{5600000, DIF_BPF_COEFF2829, 0x0b0a0318},
+{5600000, DIF_BPF_COEFF3031, 0xf8d7f15a},
+{5600000, DIF_BPF_COEFF3233, 0xf0a5f779},
+{5600000, DIF_BPF_COEFF3435, 0x02bd0cf6},
+{5600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 56_quant.dat*/
+
+
+/*case 5700000:*/
+/* BEGIN - DIF BPF register values from 57_quant.dat*/
+{5700000, DIF_BPF_COEFF01, 0x00010003},
+{5700000, DIF_BPF_COEFF23, 0x00060001},
+{5700000, DIF_BPF_COEFF45, 0xffecffc9},
+{5700000, DIF_BPF_COEFF67, 0xffb4ffd4},
+{5700000, DIF_BPF_COEFF89, 0x004000d5},
+{5700000, DIF_BPF_COEFF1011, 0x013600f0},
+{5700000, DIF_BPF_COEFF1213, 0xffd3fe39},
+{5700000, DIF_BPF_COEFF1415, 0xfd04fd31},
+{5700000, DIF_BPF_COEFF1617, 0xff360277},
+{5700000, DIF_BPF_COEFF1819, 0x055605ef},
+{5700000, DIF_BPF_COEFF2021, 0x033efdfe},
+{5700000, DIF_BPF_COEFF2223, 0xf8a5f642},
+{5700000, DIF_BPF_COEFF2425, 0xf8cbffb6},
+{5700000, DIF_BPF_COEFF2627, 0x07e10cfb},
+{5700000, DIF_BPF_COEFF2829, 0x0bd50456},
+{5700000, DIF_BPF_COEFF3031, 0xf9dff1be},
+{5700000, DIF_BPF_COEFF3233, 0xf067f6f2},
+{5700000, DIF_BPF_COEFF3435, 0x02520cd2},
+{5700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 57_quant.dat*/
+
+
+/*case 5800000:*/
+/* BEGIN - DIF BPF register values from 58_quant.dat*/
+{5800000, DIF_BPF_COEFF01, 0x00000003},
+{5800000, DIF_BPF_COEFF23, 0x00080009},
+{5800000, DIF_BPF_COEFF45, 0xfff8ffd2},
+{5800000, DIF_BPF_COEFF67, 0xffaaffac},
+{5800000, DIF_BPF_COEFF89, 0x000200a3},
+{5800000, DIF_BPF_COEFF1011, 0x013c014a},
+{5800000, DIF_BPF_COEFF1213, 0x006dfec9},
+{5800000, DIF_BPF_COEFF1415, 0xfd2bfcb7},
+{5800000, DIF_BPF_COEFF1617, 0xfe350165},
+{5800000, DIF_BPF_COEFF1819, 0x04cb0651},
+{5800000, DIF_BPF_COEFF2021, 0x0477ff7e},
+{5800000, DIF_BPF_COEFF2223, 0xf9a5f635},
+{5800000, DIF_BPF_COEFF2425, 0xf7b1fe20},
+{5800000, DIF_BPF_COEFF2627, 0x069f0ca8},
+{5800000, DIF_BPF_COEFF2829, 0x0c81058b},
+{5800000, DIF_BPF_COEFF3031, 0xfaf0f231},
+{5800000, DIF_BPF_COEFF3233, 0xf033f66d},
+{5800000, DIF_BPF_COEFF3435, 0x01e60cae},
+{5800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 58_quant.dat*/
+
+
+/*case 5900000:*/
+/* BEGIN - DIF BPF register values from 59_quant.dat*/
+{5900000, DIF_BPF_COEFF01, 0x00000002},
+{5900000, DIF_BPF_COEFF23, 0x0009000e},
+{5900000, DIF_BPF_COEFF45, 0x0005ffe1},
+{5900000, DIF_BPF_COEFF67, 0xffacff90},
+{5900000, DIF_BPF_COEFF89, 0xffc5005f},
+{5900000, DIF_BPF_COEFF1011, 0x01210184},
+{5900000, DIF_BPF_COEFF1213, 0x00fcff72},
+{5900000, DIF_BPF_COEFF1415, 0xfd8afc77},
+{5900000, DIF_BPF_COEFF1617, 0xfd51003f},
+{5900000, DIF_BPF_COEFF1819, 0x04020669},
+{5900000, DIF_BPF_COEFF2021, 0x05830103},
+{5900000, DIF_BPF_COEFF2223, 0xfad7f66b},
+{5900000, DIF_BPF_COEFF2425, 0xf6c8fc93},
+{5900000, DIF_BPF_COEFF2627, 0x05430c2b},
+{5900000, DIF_BPF_COEFF2829, 0x0d0d06b5},
+{5900000, DIF_BPF_COEFF3031, 0xfc08f2b2},
+{5900000, DIF_BPF_COEFF3233, 0xf00af5ec},
+{5900000, DIF_BPF_COEFF3435, 0x017b0c89},
+{5900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 59_quant.dat*/
+
+
+/*case 6000000:*/
+/* BEGIN - DIF BPF register values from 60_quant.dat*/
+{6000000, DIF_BPF_COEFF01, 0x00000001},
+{6000000, DIF_BPF_COEFF23, 0x00070012},
+{6000000, DIF_BPF_COEFF45, 0x0012fff5},
+{6000000, DIF_BPF_COEFF67, 0xffbaff82},
+{6000000, DIF_BPF_COEFF89, 0xff8e000f},
+{6000000, DIF_BPF_COEFF1011, 0x00e80198},
+{6000000, DIF_BPF_COEFF1213, 0x01750028},
+{6000000, DIF_BPF_COEFF1415, 0xfe18fc75},
+{6000000, DIF_BPF_COEFF1617, 0xfc99ff15},
+{6000000, DIF_BPF_COEFF1819, 0x03050636},
+{6000000, DIF_BPF_COEFF2021, 0x0656027f},
+{6000000, DIF_BPF_COEFF2223, 0xfc32f6e2},
+{6000000, DIF_BPF_COEFF2425, 0xf614fb17},
+{6000000, DIF_BPF_COEFF2627, 0x03d20b87},
+{6000000, DIF_BPF_COEFF2829, 0x0d7707d2},
+{6000000, DIF_BPF_COEFF3031, 0xfd26f341},
+{6000000, DIF_BPF_COEFF3233, 0xefeaf56f},
+{6000000, DIF_BPF_COEFF3435, 0x010f0c64},
+{6000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 60_quant.dat*/
+
+
+/*case 6100000:*/
+/* BEGIN - DIF BPF register values from 61_quant.dat*/
+{6100000, DIF_BPF_COEFF01, 0xffff0000},
+{6100000, DIF_BPF_COEFF23, 0x00050012},
+{6100000, DIF_BPF_COEFF45, 0x001c000b},
+{6100000, DIF_BPF_COEFF67, 0xffd1ff84},
+{6100000, DIF_BPF_COEFF89, 0xff66ffbe},
+{6100000, DIF_BPF_COEFF1011, 0x00960184},
+{6100000, DIF_BPF_COEFF1213, 0x01cd00da},
+{6100000, DIF_BPF_COEFF1415, 0xfeccfcb2},
+{6100000, DIF_BPF_COEFF1617, 0xfc17fdf9},
+{6100000, DIF_BPF_COEFF1819, 0x01e005bc},
+{6100000, DIF_BPF_COEFF2021, 0x06e703e4},
+{6100000, DIF_BPF_COEFF2223, 0xfdabf798},
+{6100000, DIF_BPF_COEFF2425, 0xf599f9b3},
+{6100000, DIF_BPF_COEFF2627, 0x02510abd},
+{6100000, DIF_BPF_COEFF2829, 0x0dbf08df},
+{6100000, DIF_BPF_COEFF3031, 0xfe48f3dc},
+{6100000, DIF_BPF_COEFF3233, 0xefd5f4f6},
+{6100000, DIF_BPF_COEFF3435, 0x00a20c3e},
+{6100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 61_quant.dat*/
+
+
+/*case 6200000:*/
+/* BEGIN - DIF BPF register values from 62_quant.dat*/
+{6200000, DIF_BPF_COEFF01, 0xfffffffe},
+{6200000, DIF_BPF_COEFF23, 0x0002000f},
+{6200000, DIF_BPF_COEFF45, 0x0021001f},
+{6200000, DIF_BPF_COEFF67, 0xfff0ff97},
+{6200000, DIF_BPF_COEFF89, 0xff50ff74},
+{6200000, DIF_BPF_COEFF1011, 0x0034014a},
+{6200000, DIF_BPF_COEFF1213, 0x01fa0179},
+{6200000, DIF_BPF_COEFF1415, 0xff97fd2a},
+{6200000, DIF_BPF_COEFF1617, 0xfbd3fcfa},
+{6200000, DIF_BPF_COEFF1819, 0x00a304fe},
+{6200000, DIF_BPF_COEFF2021, 0x07310525},
+{6200000, DIF_BPF_COEFF2223, 0xff37f886},
+{6200000, DIF_BPF_COEFF2425, 0xf55cf86e},
+{6200000, DIF_BPF_COEFF2627, 0x00c709d0},
+{6200000, DIF_BPF_COEFF2829, 0x0de209db},
+{6200000, DIF_BPF_COEFF3031, 0xff6df484},
+{6200000, DIF_BPF_COEFF3233, 0xefcbf481},
+{6200000, DIF_BPF_COEFF3435, 0x00360c18},
+{6200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 62_quant.dat*/
+
+
+/*case 6300000:*/
+/* BEGIN - DIF BPF register values from 63_quant.dat*/
+{6300000, DIF_BPF_COEFF01, 0xfffffffd},
+{6300000, DIF_BPF_COEFF23, 0xfffe000a},
+{6300000, DIF_BPF_COEFF45, 0x0021002f},
+{6300000, DIF_BPF_COEFF67, 0x0010ffb8},
+{6300000, DIF_BPF_COEFF89, 0xff50ff3b},
+{6300000, DIF_BPF_COEFF1011, 0xffcc00f0},
+{6300000, DIF_BPF_COEFF1213, 0x01fa01fa},
+{6300000, DIF_BPF_COEFF1415, 0x0069fdd4},
+{6300000, DIF_BPF_COEFF1617, 0xfbd3fc26},
+{6300000, DIF_BPF_COEFF1819, 0xff5d0407},
+{6300000, DIF_BPF_COEFF2021, 0x07310638},
+{6300000, DIF_BPF_COEFF2223, 0x00c9f9a8},
+{6300000, DIF_BPF_COEFF2425, 0xf55cf74e},
+{6300000, DIF_BPF_COEFF2627, 0xff3908c3},
+{6300000, DIF_BPF_COEFF2829, 0x0de20ac3},
+{6300000, DIF_BPF_COEFF3031, 0x0093f537},
+{6300000, DIF_BPF_COEFF3233, 0xefcbf410},
+{6300000, DIF_BPF_COEFF3435, 0xffca0bf2},
+{6300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 63_quant.dat*/
+
+
+/*case 6400000:*/
+/* BEGIN - DIF BPF register values from 64_quant.dat*/
+{6400000, DIF_BPF_COEFF01, 0xfffffffd},
+{6400000, DIF_BPF_COEFF23, 0xfffb0003},
+{6400000, DIF_BPF_COEFF45, 0x001c0037},
+{6400000, DIF_BPF_COEFF67, 0x002fffe2},
+{6400000, DIF_BPF_COEFF89, 0xff66ff17},
+{6400000, DIF_BPF_COEFF1011, 0xff6a007e},
+{6400000, DIF_BPF_COEFF1213, 0x01cd0251},
+{6400000, DIF_BPF_COEFF1415, 0x0134fea5},
+{6400000, DIF_BPF_COEFF1617, 0xfc17fb8b},
+{6400000, DIF_BPF_COEFF1819, 0xfe2002e0},
+{6400000, DIF_BPF_COEFF2021, 0x06e70713},
+{6400000, DIF_BPF_COEFF2223, 0x0255faf5},
+{6400000, DIF_BPF_COEFF2425, 0xf599f658},
+{6400000, DIF_BPF_COEFF2627, 0xfdaf0799},
+{6400000, DIF_BPF_COEFF2829, 0x0dbf0b96},
+{6400000, DIF_BPF_COEFF3031, 0x01b8f5f5},
+{6400000, DIF_BPF_COEFF3233, 0xefd5f3a3},
+{6400000, DIF_BPF_COEFF3435, 0xff5e0bca},
+{6400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 64_quant.dat*/
+
+
+/*case 6500000:*/
+/* BEGIN - DIF BPF register values from 65_quant.dat*/
+{6500000, DIF_BPF_COEFF01, 0x0000fffd},
+{6500000, DIF_BPF_COEFF23, 0xfff9fffb},
+{6500000, DIF_BPF_COEFF45, 0x00120037},
+{6500000, DIF_BPF_COEFF67, 0x00460010},
+{6500000, DIF_BPF_COEFF89, 0xff8eff0f},
+{6500000, DIF_BPF_COEFF1011, 0xff180000},
+{6500000, DIF_BPF_COEFF1213, 0x01750276},
+{6500000, DIF_BPF_COEFF1415, 0x01e8ff8d},
+{6500000, DIF_BPF_COEFF1617, 0xfc99fb31},
+{6500000, DIF_BPF_COEFF1819, 0xfcfb0198},
+{6500000, DIF_BPF_COEFF2021, 0x065607ad},
+{6500000, DIF_BPF_COEFF2223, 0x03cefc64},
+{6500000, DIF_BPF_COEFF2425, 0xf614f592},
+{6500000, DIF_BPF_COEFF2627, 0xfc2e0656},
+{6500000, DIF_BPF_COEFF2829, 0x0d770c52},
+{6500000, DIF_BPF_COEFF3031, 0x02daf6bd},
+{6500000, DIF_BPF_COEFF3233, 0xefeaf33b},
+{6500000, DIF_BPF_COEFF3435, 0xfef10ba3},
+{6500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 65_quant.dat*/
+
+
+/*case 6600000:*/
+/* BEGIN - DIF BPF register values from 66_quant.dat*/
+{6600000, DIF_BPF_COEFF01, 0x0000fffe},
+{6600000, DIF_BPF_COEFF23, 0xfff7fff5},
+{6600000, DIF_BPF_COEFF45, 0x0005002f},
+{6600000, DIF_BPF_COEFF67, 0x0054003c},
+{6600000, DIF_BPF_COEFF89, 0xffc5ff22},
+{6600000, DIF_BPF_COEFF1011, 0xfedfff82},
+{6600000, DIF_BPF_COEFF1213, 0x00fc0267},
+{6600000, DIF_BPF_COEFF1415, 0x0276007e},
+{6600000, DIF_BPF_COEFF1617, 0xfd51fb1c},
+{6600000, DIF_BPF_COEFF1819, 0xfbfe003e},
+{6600000, DIF_BPF_COEFF2021, 0x05830802},
+{6600000, DIF_BPF_COEFF2223, 0x0529fdec},
+{6600000, DIF_BPF_COEFF2425, 0xf6c8f4fe},
+{6600000, DIF_BPF_COEFF2627, 0xfabd04ff},
+{6600000, DIF_BPF_COEFF2829, 0x0d0d0cf6},
+{6600000, DIF_BPF_COEFF3031, 0x03f8f78f},
+{6600000, DIF_BPF_COEFF3233, 0xf00af2d7},
+{6600000, DIF_BPF_COEFF3435, 0xfe850b7b},
+{6600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 66_quant.dat*/
+
+
+/*case 6700000:*/
+/* BEGIN - DIF BPF register values from 67_quant.dat*/
+{6700000, DIF_BPF_COEFF01, 0x0000ffff},
+{6700000, DIF_BPF_COEFF23, 0xfff8fff0},
+{6700000, DIF_BPF_COEFF45, 0xfff80020},
+{6700000, DIF_BPF_COEFF67, 0x00560060},
+{6700000, DIF_BPF_COEFF89, 0x0002ff4e},
+{6700000, DIF_BPF_COEFF1011, 0xfec4ff10},
+{6700000, DIF_BPF_COEFF1213, 0x006d0225},
+{6700000, DIF_BPF_COEFF1415, 0x02d50166},
+{6700000, DIF_BPF_COEFF1617, 0xfe35fb4e},
+{6700000, DIF_BPF_COEFF1819, 0xfb35fee1},
+{6700000, DIF_BPF_COEFF2021, 0x0477080e},
+{6700000, DIF_BPF_COEFF2223, 0x065bff82},
+{6700000, DIF_BPF_COEFF2425, 0xf7b1f4a0},
+{6700000, DIF_BPF_COEFF2627, 0xf9610397},
+{6700000, DIF_BPF_COEFF2829, 0x0c810d80},
+{6700000, DIF_BPF_COEFF3031, 0x0510f869},
+{6700000, DIF_BPF_COEFF3233, 0xf033f278},
+{6700000, DIF_BPF_COEFF3435, 0xfe1a0b52},
+{6700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 67_quant.dat*/
+
+
+/*case 6800000:*/
+/* BEGIN - DIF BPF register values from 68_quant.dat*/
+{6800000, DIF_BPF_COEFF01, 0x00010000},
+{6800000, DIF_BPF_COEFF23, 0xfffaffee},
+{6800000, DIF_BPF_COEFF45, 0xffec000c},
+{6800000, DIF_BPF_COEFF67, 0x004c0078},
+{6800000, DIF_BPF_COEFF89, 0x0040ff8e},
+{6800000, DIF_BPF_COEFF1011, 0xfecafeb6},
+{6800000, DIF_BPF_COEFF1213, 0xffd301b6},
+{6800000, DIF_BPF_COEFF1415, 0x02fc0235},
+{6800000, DIF_BPF_COEFF1617, 0xff36fbc5},
+{6800000, DIF_BPF_COEFF1819, 0xfaaafd90},
+{6800000, DIF_BPF_COEFF2021, 0x033e07d2},
+{6800000, DIF_BPF_COEFF2223, 0x075b011b},
+{6800000, DIF_BPF_COEFF2425, 0xf8cbf47a},
+{6800000, DIF_BPF_COEFF2627, 0xf81f0224},
+{6800000, DIF_BPF_COEFF2829, 0x0bd50def},
+{6800000, DIF_BPF_COEFF3031, 0x0621f94b},
+{6800000, DIF_BPF_COEFF3233, 0xf067f21e},
+{6800000, DIF_BPF_COEFF3435, 0xfdae0b29},
+{6800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 68_quant.dat*/
+
+
+/*case 6900000:*/
+/* BEGIN - DIF BPF register values from 69_quant.dat*/
+{6900000, DIF_BPF_COEFF01, 0x00010001},
+{6900000, DIF_BPF_COEFF23, 0xfffdffef},
+{6900000, DIF_BPF_COEFF45, 0xffe3fff6},
+{6900000, DIF_BPF_COEFF67, 0x0037007f},
+{6900000, DIF_BPF_COEFF89, 0x0075ffdc},
+{6900000, DIF_BPF_COEFF1011, 0xfef2fe7c},
+{6900000, DIF_BPF_COEFF1213, 0xff3d0122},
+{6900000, DIF_BPF_COEFF1415, 0x02ea02dd},
+{6900000, DIF_BPF_COEFF1617, 0x0044fc79},
+{6900000, DIF_BPF_COEFF1819, 0xfa65fc5d},
+{6900000, DIF_BPF_COEFF2021, 0x01e3074e},
+{6900000, DIF_BPF_COEFF2223, 0x082102ad},
+{6900000, DIF_BPF_COEFF2425, 0xfa0ff48c},
+{6900000, DIF_BPF_COEFF2627, 0xf6fe00a9},
+{6900000, DIF_BPF_COEFF2829, 0x0b0a0e43},
+{6900000, DIF_BPF_COEFF3031, 0x0729fa33},
+{6900000, DIF_BPF_COEFF3233, 0xf0a5f1c9},
+{6900000, DIF_BPF_COEFF3435, 0xfd430b00},
+{6900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 69_quant.dat*/
+
+
+/*case 7000000:*/
+/* BEGIN - DIF BPF register values from 70_quant.dat*/
+{7000000, DIF_BPF_COEFF01, 0x00010002},
+{7000000, DIF_BPF_COEFF23, 0x0001fff3},
+{7000000, DIF_BPF_COEFF45, 0xffdeffe2},
+{7000000, DIF_BPF_COEFF67, 0x001b0076},
+{7000000, DIF_BPF_COEFF89, 0x009c002d},
+{7000000, DIF_BPF_COEFF1011, 0xff35fe68},
+{7000000, DIF_BPF_COEFF1213, 0xfeba0076},
+{7000000, DIF_BPF_COEFF1415, 0x029f0352},
+{7000000, DIF_BPF_COEFF1617, 0x014dfd60},
+{7000000, DIF_BPF_COEFF1819, 0xfa69fb53},
+{7000000, DIF_BPF_COEFF2021, 0x00740688},
+{7000000, DIF_BPF_COEFF2223, 0x08a7042d},
+{7000000, DIF_BPF_COEFF2425, 0xfb75f4d6},
+{7000000, DIF_BPF_COEFF2627, 0xf600ff2d},
+{7000000, DIF_BPF_COEFF2829, 0x0a220e7a},
+{7000000, DIF_BPF_COEFF3031, 0x0827fb22},
+{7000000, DIF_BPF_COEFF3233, 0xf0edf17a},
+{7000000, DIF_BPF_COEFF3435, 0xfcd80ad6},
+{7000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 70_quant.dat*/
+
+
+/*case 7100000:*/
+/* BEGIN - DIF BPF register values from 71_quant.dat*/
+{7100000, DIF_BPF_COEFF01, 0x00000003},
+{7100000, DIF_BPF_COEFF23, 0x0004fff9},
+{7100000, DIF_BPF_COEFF45, 0xffe0ffd2},
+{7100000, DIF_BPF_COEFF67, 0xfffb005e},
+{7100000, DIF_BPF_COEFF89, 0x00b0007a},
+{7100000, DIF_BPF_COEFF1011, 0xff8ffe7c},
+{7100000, DIF_BPF_COEFF1213, 0xfe53ffc1},
+{7100000, DIF_BPF_COEFF1415, 0x0221038c},
+{7100000, DIF_BPF_COEFF1617, 0x0241fe6e},
+{7100000, DIF_BPF_COEFF1819, 0xfab6fa80},
+{7100000, DIF_BPF_COEFF2021, 0xff010587},
+{7100000, DIF_BPF_COEFF2223, 0x08e90590},
+{7100000, DIF_BPF_COEFF2425, 0xfcf5f556},
+{7100000, DIF_BPF_COEFF2627, 0xf52bfdb3},
+{7100000, DIF_BPF_COEFF2829, 0x09210e95},
+{7100000, DIF_BPF_COEFF3031, 0x0919fc15},
+{7100000, DIF_BPF_COEFF3233, 0xf13ff12f},
+{7100000, DIF_BPF_COEFF3435, 0xfc6e0aab},
+{7100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 71_quant.dat*/
+
+
+/*case 7200000:*/
+/* BEGIN - DIF BPF register values from 72_quant.dat*/
+{7200000, DIF_BPF_COEFF01, 0x00000003},
+{7200000, DIF_BPF_COEFF23, 0x00070000},
+{7200000, DIF_BPF_COEFF45, 0xffe6ffc9},
+{7200000, DIF_BPF_COEFF67, 0xffdb0039},
+{7200000, DIF_BPF_COEFF89, 0x00af00b8},
+{7200000, DIF_BPF_COEFF1011, 0xfff4feb6},
+{7200000, DIF_BPF_COEFF1213, 0xfe13ff10},
+{7200000, DIF_BPF_COEFF1415, 0x01790388},
+{7200000, DIF_BPF_COEFF1617, 0x0311ff92},
+{7200000, DIF_BPF_COEFF1819, 0xfb48f9ed},
+{7200000, DIF_BPF_COEFF2021, 0xfd980453},
+{7200000, DIF_BPF_COEFF2223, 0x08e306cd},
+{7200000, DIF_BPF_COEFF2425, 0xfe88f60a},
+{7200000, DIF_BPF_COEFF2627, 0xf482fc40},
+{7200000, DIF_BPF_COEFF2829, 0x08080e93},
+{7200000, DIF_BPF_COEFF3031, 0x09fdfd0c},
+{7200000, DIF_BPF_COEFF3233, 0xf19af0ea},
+{7200000, DIF_BPF_COEFF3435, 0xfc050a81},
+{7200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 72_quant.dat*/
+
+
+/*case 7300000:*/
+/* BEGIN - DIF BPF register values from 73_quant.dat*/
+{7300000, DIF_BPF_COEFF01, 0x00000002},
+{7300000, DIF_BPF_COEFF23, 0x00080008},
+{7300000, DIF_BPF_COEFF45, 0xfff0ffc9},
+{7300000, DIF_BPF_COEFF67, 0xffc1000d},
+{7300000, DIF_BPF_COEFF89, 0x009800e2},
+{7300000, DIF_BPF_COEFF1011, 0x005bff10},
+{7300000, DIF_BPF_COEFF1213, 0xfe00fe74},
+{7300000, DIF_BPF_COEFF1415, 0x00b50345},
+{7300000, DIF_BPF_COEFF1617, 0x03b000bc},
+{7300000, DIF_BPF_COEFF1819, 0xfc18f9a1},
+{7300000, DIF_BPF_COEFF2021, 0xfc4802f9},
+{7300000, DIF_BPF_COEFF2223, 0x089807dc},
+{7300000, DIF_BPF_COEFF2425, 0x0022f6f0},
+{7300000, DIF_BPF_COEFF2627, 0xf407fada},
+{7300000, DIF_BPF_COEFF2829, 0x06da0e74},
+{7300000, DIF_BPF_COEFF3031, 0x0ad3fe06},
+{7300000, DIF_BPF_COEFF3233, 0xf1fef0ab},
+{7300000, DIF_BPF_COEFF3435, 0xfb9c0a55},
+{7300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 73_quant.dat*/
+
+
+/*case 7400000:*/
+/* BEGIN - DIF BPF register values from 74_quant.dat*/
+{7400000, DIF_BPF_COEFF01, 0x00000001},
+{7400000, DIF_BPF_COEFF23, 0x0008000e},
+{7400000, DIF_BPF_COEFF45, 0xfffdffd0},
+{7400000, DIF_BPF_COEFF67, 0xffafffdf},
+{7400000, DIF_BPF_COEFF89, 0x006e00f2},
+{7400000, DIF_BPF_COEFF1011, 0x00b8ff82},
+{7400000, DIF_BPF_COEFF1213, 0xfe1bfdf8},
+{7400000, DIF_BPF_COEFF1415, 0xffe302c8},
+{7400000, DIF_BPF_COEFF1617, 0x041301dc},
+{7400000, DIF_BPF_COEFF1819, 0xfd1af99e},
+{7400000, DIF_BPF_COEFF2021, 0xfb1e0183},
+{7400000, DIF_BPF_COEFF2223, 0x080908b5},
+{7400000, DIF_BPF_COEFF2425, 0x01bcf801},
+{7400000, DIF_BPF_COEFF2627, 0xf3bdf985},
+{7400000, DIF_BPF_COEFF2829, 0x059a0e38},
+{7400000, DIF_BPF_COEFF3031, 0x0b99ff03},
+{7400000, DIF_BPF_COEFF3233, 0xf26cf071},
+{7400000, DIF_BPF_COEFF3435, 0xfb330a2a},
+{7400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 74_quant.dat*/
+
+
+/*case 7500000:*/
+/* BEGIN - DIF BPF register values from 75_quant.dat*/
+{7500000, DIF_BPF_COEFF01, 0xffff0000},
+{7500000, DIF_BPF_COEFF23, 0x00070011},
+{7500000, DIF_BPF_COEFF45, 0x000affdf},
+{7500000, DIF_BPF_COEFF67, 0xffa9ffb5},
+{7500000, DIF_BPF_COEFF89, 0x003700e6},
+{7500000, DIF_BPF_COEFF1011, 0x01010000},
+{7500000, DIF_BPF_COEFF1213, 0xfe62fda8},
+{7500000, DIF_BPF_COEFF1415, 0xff140219},
+{7500000, DIF_BPF_COEFF1617, 0x043502e1},
+{7500000, DIF_BPF_COEFF1819, 0xfe42f9e6},
+{7500000, DIF_BPF_COEFF2021, 0xfa270000},
+{7500000, DIF_BPF_COEFF2223, 0x073a0953},
+{7500000, DIF_BPF_COEFF2425, 0x034cf939},
+{7500000, DIF_BPF_COEFF2627, 0xf3a4f845},
+{7500000, DIF_BPF_COEFF2829, 0x044c0de1},
+{7500000, DIF_BPF_COEFF3031, 0x0c4f0000},
+{7500000, DIF_BPF_COEFF3233, 0xf2e2f03c},
+{7500000, DIF_BPF_COEFF3435, 0xfacc09fe},
+{7500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 75_quant.dat*/
+
+
+/*case 7600000:*/
+/* BEGIN - DIF BPF register values from 76_quant.dat*/
+{7600000, DIF_BPF_COEFF01, 0xffffffff},
+{7600000, DIF_BPF_COEFF23, 0x00040012},
+{7600000, DIF_BPF_COEFF45, 0x0016fff3},
+{7600000, DIF_BPF_COEFF67, 0xffafff95},
+{7600000, DIF_BPF_COEFF89, 0xfff900c0},
+{7600000, DIF_BPF_COEFF1011, 0x0130007e},
+{7600000, DIF_BPF_COEFF1213, 0xfecefd89},
+{7600000, DIF_BPF_COEFF1415, 0xfe560146},
+{7600000, DIF_BPF_COEFF1617, 0x041303bc},
+{7600000, DIF_BPF_COEFF1819, 0xff81fa76},
+{7600000, DIF_BPF_COEFF2021, 0xf96cfe7d},
+{7600000, DIF_BPF_COEFF2223, 0x063209b1},
+{7600000, DIF_BPF_COEFF2425, 0x04c9fa93},
+{7600000, DIF_BPF_COEFF2627, 0xf3bdf71e},
+{7600000, DIF_BPF_COEFF2829, 0x02f30d6e},
+{7600000, DIF_BPF_COEFF3031, 0x0cf200fd},
+{7600000, DIF_BPF_COEFF3233, 0xf361f00e},
+{7600000, DIF_BPF_COEFF3435, 0xfa6509d1},
+{7600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 76_quant.dat*/
+
+
+/*case 7700000:*/
+/* BEGIN - DIF BPF register values from 77_quant.dat*/
+{7700000, DIF_BPF_COEFF01, 0xfffffffe},
+{7700000, DIF_BPF_COEFF23, 0x00010010},
+{7700000, DIF_BPF_COEFF45, 0x001e0008},
+{7700000, DIF_BPF_COEFF67, 0xffc1ff84},
+{7700000, DIF_BPF_COEFF89, 0xffbc0084},
+{7700000, DIF_BPF_COEFF1011, 0x013e00f0},
+{7700000, DIF_BPF_COEFF1213, 0xff56fd9f},
+{7700000, DIF_BPF_COEFF1415, 0xfdb8005c},
+{7700000, DIF_BPF_COEFF1617, 0x03b00460},
+{7700000, DIF_BPF_COEFF1819, 0x00c7fb45},
+{7700000, DIF_BPF_COEFF2021, 0xf8f4fd07},
+{7700000, DIF_BPF_COEFF2223, 0x04fa09ce},
+{7700000, DIF_BPF_COEFF2425, 0x062afc07},
+{7700000, DIF_BPF_COEFF2627, 0xf407f614},
+{7700000, DIF_BPF_COEFF2829, 0x01920ce0},
+{7700000, DIF_BPF_COEFF3031, 0x0d8301fa},
+{7700000, DIF_BPF_COEFF3233, 0xf3e8efe5},
+{7700000, DIF_BPF_COEFF3435, 0xfa0009a4},
+{7700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 77_quant.dat*/
+
+
+/*case 7800000:*/
+/* BEGIN - DIF BPF register values from 78_quant.dat*/
+{7800000, DIF_BPF_COEFF01, 0x0000fffd},
+{7800000, DIF_BPF_COEFF23, 0xfffd000b},
+{7800000, DIF_BPF_COEFF45, 0x0022001d},
+{7800000, DIF_BPF_COEFF67, 0xffdbff82},
+{7800000, DIF_BPF_COEFF89, 0xff870039},
+{7800000, DIF_BPF_COEFF1011, 0x012a014a},
+{7800000, DIF_BPF_COEFF1213, 0xffedfde7},
+{7800000, DIF_BPF_COEFF1415, 0xfd47ff6b},
+{7800000, DIF_BPF_COEFF1617, 0x031104c6},
+{7800000, DIF_BPF_COEFF1819, 0x0202fc4c},
+{7800000, DIF_BPF_COEFF2021, 0xf8c6fbad},
+{7800000, DIF_BPF_COEFF2223, 0x039909a7},
+{7800000, DIF_BPF_COEFF2425, 0x0767fd8e},
+{7800000, DIF_BPF_COEFF2627, 0xf482f52b},
+{7800000, DIF_BPF_COEFF2829, 0x002d0c39},
+{7800000, DIF_BPF_COEFF3031, 0x0e0002f4},
+{7800000, DIF_BPF_COEFF3233, 0xf477efc2},
+{7800000, DIF_BPF_COEFF3435, 0xf99b0977},
+{7800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 78_quant.dat*/
+
+
+/*case 7900000:*/
+/* BEGIN - DIF BPF register values from 79_quant.dat*/
+{7900000, DIF_BPF_COEFF01, 0x0000fffd},
+{7900000, DIF_BPF_COEFF23, 0xfffa0004},
+{7900000, DIF_BPF_COEFF45, 0x0020002d},
+{7900000, DIF_BPF_COEFF67, 0xfffbff91},
+{7900000, DIF_BPF_COEFF89, 0xff61ffe8},
+{7900000, DIF_BPF_COEFF1011, 0x00f70184},
+{7900000, DIF_BPF_COEFF1213, 0x0086fe5c},
+{7900000, DIF_BPF_COEFF1415, 0xfd0bfe85},
+{7900000, DIF_BPF_COEFF1617, 0x024104e5},
+{7900000, DIF_BPF_COEFF1819, 0x0323fd7d},
+{7900000, DIF_BPF_COEFF2021, 0xf8e2fa79},
+{7900000, DIF_BPF_COEFF2223, 0x021d093f},
+{7900000, DIF_BPF_COEFF2425, 0x0879ff22},
+{7900000, DIF_BPF_COEFF2627, 0xf52bf465},
+{7900000, DIF_BPF_COEFF2829, 0xfec70b79},
+{7900000, DIF_BPF_COEFF3031, 0x0e6803eb},
+{7900000, DIF_BPF_COEFF3233, 0xf50defa5},
+{7900000, DIF_BPF_COEFF3435, 0xf937094a},
+{7900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 79_quant.dat*/
+
+
+/*case 8000000:*/
+/* BEGIN - DIF BPF register values from 80_quant.dat*/
+{8000000, DIF_BPF_COEFF01, 0x0000fffe},
+{8000000, DIF_BPF_COEFF23, 0xfff8fffd},
+{8000000, DIF_BPF_COEFF45, 0x00190036},
+{8000000, DIF_BPF_COEFF67, 0x001bffaf},
+{8000000, DIF_BPF_COEFF89, 0xff4fff99},
+{8000000, DIF_BPF_COEFF1011, 0x00aa0198},
+{8000000, DIF_BPF_COEFF1213, 0x0112fef3},
+{8000000, DIF_BPF_COEFF1415, 0xfd09fdb9},
+{8000000, DIF_BPF_COEFF1617, 0x014d04be},
+{8000000, DIF_BPF_COEFF1819, 0x041bfecc},
+{8000000, DIF_BPF_COEFF2021, 0xf947f978},
+{8000000, DIF_BPF_COEFF2223, 0x00900897},
+{8000000, DIF_BPF_COEFF2425, 0x095a00b9},
+{8000000, DIF_BPF_COEFF2627, 0xf600f3c5},
+{8000000, DIF_BPF_COEFF2829, 0xfd650aa3},
+{8000000, DIF_BPF_COEFF3031, 0x0ebc04de},
+{8000000, DIF_BPF_COEFF3233, 0xf5aaef8e},
+{8000000, DIF_BPF_COEFF3435, 0xf8d5091c},
+{8000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 80_quant.dat*/
+
+
+/*case 8100000:*/
+/* BEGIN - DIF BPF register values from 81_quant.dat*/
+{8100000, DIF_BPF_COEFF01, 0x0000ffff},
+{8100000, DIF_BPF_COEFF23, 0xfff7fff6},
+{8100000, DIF_BPF_COEFF45, 0x000e0038},
+{8100000, DIF_BPF_COEFF67, 0x0037ffd7},
+{8100000, DIF_BPF_COEFF89, 0xff52ff56},
+{8100000, DIF_BPF_COEFF1011, 0x004b0184},
+{8100000, DIF_BPF_COEFF1213, 0x0186ffa1},
+{8100000, DIF_BPF_COEFF1415, 0xfd40fd16},
+{8100000, DIF_BPF_COEFF1617, 0x00440452},
+{8100000, DIF_BPF_COEFF1819, 0x04de0029},
+{8100000, DIF_BPF_COEFF2021, 0xf9f2f8b2},
+{8100000, DIF_BPF_COEFF2223, 0xfefe07b5},
+{8100000, DIF_BPF_COEFF2425, 0x0a05024d},
+{8100000, DIF_BPF_COEFF2627, 0xf6fef34d},
+{8100000, DIF_BPF_COEFF2829, 0xfc0a09b8},
+{8100000, DIF_BPF_COEFF3031, 0x0efa05cd},
+{8100000, DIF_BPF_COEFF3233, 0xf64eef7d},
+{8100000, DIF_BPF_COEFF3435, 0xf87308ed},
+{8100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 81_quant.dat*/
+
+
+/*case 8200000:*/
+/* BEGIN - DIF BPF register values from 82_quant.dat*/
+{8200000, DIF_BPF_COEFF01, 0x00010000},
+{8200000, DIF_BPF_COEFF23, 0xfff8fff0},
+{8200000, DIF_BPF_COEFF45, 0x00000031},
+{8200000, DIF_BPF_COEFF67, 0x004c0005},
+{8200000, DIF_BPF_COEFF89, 0xff6aff27},
+{8200000, DIF_BPF_COEFF1011, 0xffe4014a},
+{8200000, DIF_BPF_COEFF1213, 0x01d70057},
+{8200000, DIF_BPF_COEFF1415, 0xfdacfca6},
+{8200000, DIF_BPF_COEFF1617, 0xff3603a7},
+{8200000, DIF_BPF_COEFF1819, 0x05610184},
+{8200000, DIF_BPF_COEFF2021, 0xfadbf82e},
+{8200000, DIF_BPF_COEFF2223, 0xfd74069f},
+{8200000, DIF_BPF_COEFF2425, 0x0a7503d6},
+{8200000, DIF_BPF_COEFF2627, 0xf81ff2ff},
+{8200000, DIF_BPF_COEFF2829, 0xfab808b9},
+{8200000, DIF_BPF_COEFF3031, 0x0f2306b5},
+{8200000, DIF_BPF_COEFF3233, 0xf6f9ef72},
+{8200000, DIF_BPF_COEFF3435, 0xf81308bf},
+{8200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 82_quant.dat*/
+
+
+/*case 8300000:*/
+/* BEGIN - DIF BPF register values from 83_quant.dat*/
+{8300000, DIF_BPF_COEFF01, 0x00010001},
+{8300000, DIF_BPF_COEFF23, 0xfffbffee},
+{8300000, DIF_BPF_COEFF45, 0xfff30022},
+{8300000, DIF_BPF_COEFF67, 0x00560032},
+{8300000, DIF_BPF_COEFF89, 0xff95ff10},
+{8300000, DIF_BPF_COEFF1011, 0xff8000f0},
+{8300000, DIF_BPF_COEFF1213, 0x01fe0106},
+{8300000, DIF_BPF_COEFF1415, 0xfe46fc71},
+{8300000, DIF_BPF_COEFF1617, 0xfe3502c7},
+{8300000, DIF_BPF_COEFF1819, 0x059e02ce},
+{8300000, DIF_BPF_COEFF2021, 0xfbf9f7f2},
+{8300000, DIF_BPF_COEFF2223, 0xfbff055b},
+{8300000, DIF_BPF_COEFF2425, 0x0aa9054c},
+{8300000, DIF_BPF_COEFF2627, 0xf961f2db},
+{8300000, DIF_BPF_COEFF2829, 0xf97507aa},
+{8300000, DIF_BPF_COEFF3031, 0x0f350797},
+{8300000, DIF_BPF_COEFF3233, 0xf7a9ef6d},
+{8300000, DIF_BPF_COEFF3435, 0xf7b40890},
+{8300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 83_quant.dat*/
+
+
+/*case 8400000:*/
+/* BEGIN - DIF BPF register values from 84_quant.dat*/
+{8400000, DIF_BPF_COEFF01, 0x00010002},
+{8400000, DIF_BPF_COEFF23, 0xfffeffee},
+{8400000, DIF_BPF_COEFF45, 0xffe8000f},
+{8400000, DIF_BPF_COEFF67, 0x00540058},
+{8400000, DIF_BPF_COEFF89, 0xffcdff14},
+{8400000, DIF_BPF_COEFF1011, 0xff29007e},
+{8400000, DIF_BPF_COEFF1213, 0x01f6019e},
+{8400000, DIF_BPF_COEFF1415, 0xff01fc7c},
+{8400000, DIF_BPF_COEFF1617, 0xfd5101bf},
+{8400000, DIF_BPF_COEFF1819, 0x059203f6},
+{8400000, DIF_BPF_COEFF2021, 0xfd41f7fe},
+{8400000, DIF_BPF_COEFF2223, 0xfaa903f3},
+{8400000, DIF_BPF_COEFF2425, 0x0a9e06a9},
+{8400000, DIF_BPF_COEFF2627, 0xfabdf2e2},
+{8400000, DIF_BPF_COEFF2829, 0xf842068b},
+{8400000, DIF_BPF_COEFF3031, 0x0f320871},
+{8400000, DIF_BPF_COEFF3233, 0xf85eef6e},
+{8400000, DIF_BPF_COEFF3435, 0xf7560860},
+{8400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 84_quant.dat*/
+
+
+/*case 8500000:*/
+/* BEGIN - DIF BPF register values from 85_quant.dat*/
+{8500000, DIF_BPF_COEFF01, 0x00000003},
+{8500000, DIF_BPF_COEFF23, 0x0002fff2},
+{8500000, DIF_BPF_COEFF45, 0xffe1fff9},
+{8500000, DIF_BPF_COEFF67, 0x00460073},
+{8500000, DIF_BPF_COEFF89, 0x000bff34},
+{8500000, DIF_BPF_COEFF1011, 0xfee90000},
+{8500000, DIF_BPF_COEFF1213, 0x01c10215},
+{8500000, DIF_BPF_COEFF1415, 0xffd0fcc5},
+{8500000, DIF_BPF_COEFF1617, 0xfc99009d},
+{8500000, DIF_BPF_COEFF1819, 0x053d04f1},
+{8500000, DIF_BPF_COEFF2021, 0xfea5f853},
+{8500000, DIF_BPF_COEFF2223, 0xf97d0270},
+{8500000, DIF_BPF_COEFF2425, 0x0a5607e4},
+{8500000, DIF_BPF_COEFF2627, 0xfc2ef314},
+{8500000, DIF_BPF_COEFF2829, 0xf723055f},
+{8500000, DIF_BPF_COEFF3031, 0x0f180943},
+{8500000, DIF_BPF_COEFF3233, 0xf919ef75},
+{8500000, DIF_BPF_COEFF3435, 0xf6fa0830},
+{8500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 85_quant.dat*/
+
+
+/*case 8600000:*/
+/* BEGIN - DIF BPF register values from 86_quant.dat*/
+{8600000, DIF_BPF_COEFF01, 0x00000003},
+{8600000, DIF_BPF_COEFF23, 0x0005fff8},
+{8600000, DIF_BPF_COEFF45, 0xffdeffe4},
+{8600000, DIF_BPF_COEFF67, 0x002f007f},
+{8600000, DIF_BPF_COEFF89, 0x0048ff6b},
+{8600000, DIF_BPF_COEFF1011, 0xfec7ff82},
+{8600000, DIF_BPF_COEFF1213, 0x0163025f},
+{8600000, DIF_BPF_COEFF1415, 0x00a2fd47},
+{8600000, DIF_BPF_COEFF1617, 0xfc17ff73},
+{8600000, DIF_BPF_COEFF1819, 0x04a405b2},
+{8600000, DIF_BPF_COEFF2021, 0x0017f8ed},
+{8600000, DIF_BPF_COEFF2223, 0xf88500dc},
+{8600000, DIF_BPF_COEFF2425, 0x09d208f9},
+{8600000, DIF_BPF_COEFF2627, 0xfdaff370},
+{8600000, DIF_BPF_COEFF2829, 0xf61c0429},
+{8600000, DIF_BPF_COEFF3031, 0x0ee80a0b},
+{8600000, DIF_BPF_COEFF3233, 0xf9d8ef82},
+{8600000, DIF_BPF_COEFF3435, 0xf6a00800},
+{8600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 86_quant.dat*/
+
+
+/*case 8700000:*/
+/* BEGIN - DIF BPF register values from 87_quant.dat*/
+{8700000, DIF_BPF_COEFF01, 0x00000003},
+{8700000, DIF_BPF_COEFF23, 0x0007ffff},
+{8700000, DIF_BPF_COEFF45, 0xffe1ffd4},
+{8700000, DIF_BPF_COEFF67, 0x0010007a},
+{8700000, DIF_BPF_COEFF89, 0x007cffb2},
+{8700000, DIF_BPF_COEFF1011, 0xfec6ff10},
+{8700000, DIF_BPF_COEFF1213, 0x00e60277},
+{8700000, DIF_BPF_COEFF1415, 0x0168fdf9},
+{8700000, DIF_BPF_COEFF1617, 0xfbd3fe50},
+{8700000, DIF_BPF_COEFF1819, 0x03ce0631},
+{8700000, DIF_BPF_COEFF2021, 0x0188f9c8},
+{8700000, DIF_BPF_COEFF2223, 0xf7c7ff43},
+{8700000, DIF_BPF_COEFF2425, 0x091509e3},
+{8700000, DIF_BPF_COEFF2627, 0xff39f3f6},
+{8700000, DIF_BPF_COEFF2829, 0xf52d02ea},
+{8700000, DIF_BPF_COEFF3031, 0x0ea30ac9},
+{8700000, DIF_BPF_COEFF3233, 0xfa9bef95},
+{8700000, DIF_BPF_COEFF3435, 0xf64607d0},
+{8700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 87_quant.dat*/
+
+
+/*case 8800000:*/
+/* BEGIN - DIF BPF register values from 88_quant.dat*/
+{8800000, DIF_BPF_COEFF01, 0x00000002},
+{8800000, DIF_BPF_COEFF23, 0x00090007},
+{8800000, DIF_BPF_COEFF45, 0xffe9ffca},
+{8800000, DIF_BPF_COEFF67, 0xfff00065},
+{8800000, DIF_BPF_COEFF89, 0x00a10003},
+{8800000, DIF_BPF_COEFF1011, 0xfee6feb6},
+{8800000, DIF_BPF_COEFF1213, 0x0053025b},
+{8800000, DIF_BPF_COEFF1415, 0x0213fed0},
+{8800000, DIF_BPF_COEFF1617, 0xfbd3fd46},
+{8800000, DIF_BPF_COEFF1819, 0x02c70668},
+{8800000, DIF_BPF_COEFF2021, 0x02eafadb},
+{8800000, DIF_BPF_COEFF2223, 0xf74bfdae},
+{8800000, DIF_BPF_COEFF2425, 0x08230a9c},
+{8800000, DIF_BPF_COEFF2627, 0x00c7f4a3},
+{8800000, DIF_BPF_COEFF2829, 0xf45b01a6},
+{8800000, DIF_BPF_COEFF3031, 0x0e480b7c},
+{8800000, DIF_BPF_COEFF3233, 0xfb61efae},
+{8800000, DIF_BPF_COEFF3435, 0xf5ef079f},
+{8800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 88_quant.dat*/
+
+
+/*case 8900000:*/
+/* BEGIN - DIF BPF register values from 89_quant.dat*/
+{8900000, DIF_BPF_COEFF01, 0xffff0000},
+{8900000, DIF_BPF_COEFF23, 0x0008000d},
+{8900000, DIF_BPF_COEFF45, 0xfff5ffc8},
+{8900000, DIF_BPF_COEFF67, 0xffd10043},
+{8900000, DIF_BPF_COEFF89, 0x00b20053},
+{8900000, DIF_BPF_COEFF1011, 0xff24fe7c},
+{8900000, DIF_BPF_COEFF1213, 0xffb9020c},
+{8900000, DIF_BPF_COEFF1415, 0x0295ffbb},
+{8900000, DIF_BPF_COEFF1617, 0xfc17fc64},
+{8900000, DIF_BPF_COEFF1819, 0x019b0654},
+{8900000, DIF_BPF_COEFF2021, 0x042dfc1c},
+{8900000, DIF_BPF_COEFF2223, 0xf714fc2a},
+{8900000, DIF_BPF_COEFF2425, 0x07020b21},
+{8900000, DIF_BPF_COEFF2627, 0x0251f575},
+{8900000, DIF_BPF_COEFF2829, 0xf3a7005e},
+{8900000, DIF_BPF_COEFF3031, 0x0dd80c24},
+{8900000, DIF_BPF_COEFF3233, 0xfc2aefcd},
+{8900000, DIF_BPF_COEFF3435, 0xf599076e},
+{8900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 89_quant.dat*/
+
+
+/*case 9000000:*/
+/* BEGIN - DIF BPF register values from 90_quant.dat*/
+{9000000, DIF_BPF_COEFF01, 0xffffffff},
+{9000000, DIF_BPF_COEFF23, 0x00060011},
+{9000000, DIF_BPF_COEFF45, 0x0002ffcf},
+{9000000, DIF_BPF_COEFF67, 0xffba0018},
+{9000000, DIF_BPF_COEFF89, 0x00ad009a},
+{9000000, DIF_BPF_COEFF1011, 0xff79fe68},
+{9000000, DIF_BPF_COEFF1213, 0xff260192},
+{9000000, DIF_BPF_COEFF1415, 0x02e500ab},
+{9000000, DIF_BPF_COEFF1617, 0xfc99fbb6},
+{9000000, DIF_BPF_COEFF1819, 0x005b05f7},
+{9000000, DIF_BPF_COEFF2021, 0x0545fd81},
+{9000000, DIF_BPF_COEFF2223, 0xf723fabf},
+{9000000, DIF_BPF_COEFF2425, 0x05b80b70},
+{9000000, DIF_BPF_COEFF2627, 0x03d2f669},
+{9000000, DIF_BPF_COEFF2829, 0xf313ff15},
+{9000000, DIF_BPF_COEFF3031, 0x0d550cbf},
+{9000000, DIF_BPF_COEFF3233, 0xfcf6eff2},
+{9000000, DIF_BPF_COEFF3435, 0xf544073d},
+{9000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 90_quant.dat*/
+
+
+/*case 9100000:*/
+/* BEGIN - DIF BPF register values from 91_quant.dat*/
+{9100000, DIF_BPF_COEFF01, 0xfffffffe},
+{9100000, DIF_BPF_COEFF23, 0x00030012},
+{9100000, DIF_BPF_COEFF45, 0x000fffdd},
+{9100000, DIF_BPF_COEFF67, 0xffacffea},
+{9100000, DIF_BPF_COEFF89, 0x009300cf},
+{9100000, DIF_BPF_COEFF1011, 0xffdcfe7c},
+{9100000, DIF_BPF_COEFF1213, 0xfea600f7},
+{9100000, DIF_BPF_COEFF1415, 0x02fd0190},
+{9100000, DIF_BPF_COEFF1617, 0xfd51fb46},
+{9100000, DIF_BPF_COEFF1819, 0xff150554},
+{9100000, DIF_BPF_COEFF2021, 0x0627fefd},
+{9100000, DIF_BPF_COEFF2223, 0xf778f978},
+{9100000, DIF_BPF_COEFF2425, 0x044d0b87},
+{9100000, DIF_BPF_COEFF2627, 0x0543f77d},
+{9100000, DIF_BPF_COEFF2829, 0xf2a0fdcf},
+{9100000, DIF_BPF_COEFF3031, 0x0cbe0d4e},
+{9100000, DIF_BPF_COEFF3233, 0xfdc4f01d},
+{9100000, DIF_BPF_COEFF3435, 0xf4f2070b},
+{9100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 91_quant.dat*/
+
+
+/*case 9200000:*/
+/* BEGIN - DIF BPF register values from 92_quant.dat*/
+{9200000, DIF_BPF_COEFF01, 0x0000fffd},
+{9200000, DIF_BPF_COEFF23, 0x00000010},
+{9200000, DIF_BPF_COEFF45, 0x001afff0},
+{9200000, DIF_BPF_COEFF67, 0xffaaffbf},
+{9200000, DIF_BPF_COEFF89, 0x006700ed},
+{9200000, DIF_BPF_COEFF1011, 0x0043feb6},
+{9200000, DIF_BPF_COEFF1213, 0xfe460047},
+{9200000, DIF_BPF_COEFF1415, 0x02db0258},
+{9200000, DIF_BPF_COEFF1617, 0xfe35fb1b},
+{9200000, DIF_BPF_COEFF1819, 0xfddc0473},
+{9200000, DIF_BPF_COEFF2021, 0x06c90082},
+{9200000, DIF_BPF_COEFF2223, 0xf811f85e},
+{9200000, DIF_BPF_COEFF2425, 0x02c90b66},
+{9200000, DIF_BPF_COEFF2627, 0x069ff8ad},
+{9200000, DIF_BPF_COEFF2829, 0xf250fc8d},
+{9200000, DIF_BPF_COEFF3031, 0x0c140dcf},
+{9200000, DIF_BPF_COEFF3233, 0xfe93f04d},
+{9200000, DIF_BPF_COEFF3435, 0xf4a106d9},
+{9200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 92_quant.dat*/
+
+
+/*case 9300000:*/
+/* BEGIN - DIF BPF register values from 93_quant.dat*/
+{9300000, DIF_BPF_COEFF01, 0x0000fffd},
+{9300000, DIF_BPF_COEFF23, 0xfffc000c},
+{9300000, DIF_BPF_COEFF45, 0x00200006},
+{9300000, DIF_BPF_COEFF67, 0xffb4ff9c},
+{9300000, DIF_BPF_COEFF89, 0x002f00ef},
+{9300000, DIF_BPF_COEFF1011, 0x00a4ff10},
+{9300000, DIF_BPF_COEFF1213, 0xfe0dff92},
+{9300000, DIF_BPF_COEFF1415, 0x028102f7},
+{9300000, DIF_BPF_COEFF1617, 0xff36fb37},
+{9300000, DIF_BPF_COEFF1819, 0xfcbf035e},
+{9300000, DIF_BPF_COEFF2021, 0x07260202},
+{9300000, DIF_BPF_COEFF2223, 0xf8e8f778},
+{9300000, DIF_BPF_COEFF2425, 0x01340b0d},
+{9300000, DIF_BPF_COEFF2627, 0x07e1f9f4},
+{9300000, DIF_BPF_COEFF2829, 0xf223fb51},
+{9300000, DIF_BPF_COEFF3031, 0x0b590e42},
+{9300000, DIF_BPF_COEFF3233, 0xff64f083},
+{9300000, DIF_BPF_COEFF3435, 0xf45206a7},
+{9300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 93_quant.dat*/
+
+
+/*case 9400000:*/
+/* BEGIN - DIF BPF register values from 94_quant.dat*/
+{9400000, DIF_BPF_COEFF01, 0x0000fffd},
+{9400000, DIF_BPF_COEFF23, 0xfff90005},
+{9400000, DIF_BPF_COEFF45, 0x0022001a},
+{9400000, DIF_BPF_COEFF67, 0xffc9ff86},
+{9400000, DIF_BPF_COEFF89, 0xfff000d7},
+{9400000, DIF_BPF_COEFF1011, 0x00f2ff82},
+{9400000, DIF_BPF_COEFF1213, 0xfe01fee5},
+{9400000, DIF_BPF_COEFF1415, 0x01f60362},
+{9400000, DIF_BPF_COEFF1617, 0x0044fb99},
+{9400000, DIF_BPF_COEFF1819, 0xfbcc0222},
+{9400000, DIF_BPF_COEFF2021, 0x07380370},
+{9400000, DIF_BPF_COEFF2223, 0xf9f7f6cc},
+{9400000, DIF_BPF_COEFF2425, 0xff990a7e},
+{9400000, DIF_BPF_COEFF2627, 0x0902fb50},
+{9400000, DIF_BPF_COEFF2829, 0xf21afa1f},
+{9400000, DIF_BPF_COEFF3031, 0x0a8d0ea6},
+{9400000, DIF_BPF_COEFF3233, 0x0034f0bf},
+{9400000, DIF_BPF_COEFF3435, 0xf4050675},
+{9400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 94_quant.dat*/
+
+
+/*case 9500000:*/
+/* BEGIN - DIF BPF register values from 95_quant.dat*/
+{9500000, DIF_BPF_COEFF01, 0x0000fffe},
+{9500000, DIF_BPF_COEFF23, 0xfff8fffe},
+{9500000, DIF_BPF_COEFF45, 0x001e002b},
+{9500000, DIF_BPF_COEFF67, 0xffe5ff81},
+{9500000, DIF_BPF_COEFF89, 0xffb400a5},
+{9500000, DIF_BPF_COEFF1011, 0x01280000},
+{9500000, DIF_BPF_COEFF1213, 0xfe24fe50},
+{9500000, DIF_BPF_COEFF1415, 0x01460390},
+{9500000, DIF_BPF_COEFF1617, 0x014dfc3a},
+{9500000, DIF_BPF_COEFF1819, 0xfb1000ce},
+{9500000, DIF_BPF_COEFF2021, 0x070104bf},
+{9500000, DIF_BPF_COEFF2223, 0xfb37f65f},
+{9500000, DIF_BPF_COEFF2425, 0xfe0009bc},
+{9500000, DIF_BPF_COEFF2627, 0x0a00fcbb},
+{9500000, DIF_BPF_COEFF2829, 0xf235f8f8},
+{9500000, DIF_BPF_COEFF3031, 0x09b20efc},
+{9500000, DIF_BPF_COEFF3233, 0x0105f101},
+{9500000, DIF_BPF_COEFF3435, 0xf3ba0642},
+{9500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 95_quant.dat*/
+
+
+/*case 9600000:*/
+/* BEGIN - DIF BPF register values from 96_quant.dat*/
+{9600000, DIF_BPF_COEFF01, 0x0001ffff},
+{9600000, DIF_BPF_COEFF23, 0xfff8fff7},
+{9600000, DIF_BPF_COEFF45, 0x00150036},
+{9600000, DIF_BPF_COEFF67, 0x0005ff8c},
+{9600000, DIF_BPF_COEFF89, 0xff810061},
+{9600000, DIF_BPF_COEFF1011, 0x013d007e},
+{9600000, DIF_BPF_COEFF1213, 0xfe71fddf},
+{9600000, DIF_BPF_COEFF1415, 0x007c0380},
+{9600000, DIF_BPF_COEFF1617, 0x0241fd13},
+{9600000, DIF_BPF_COEFF1819, 0xfa94ff70},
+{9600000, DIF_BPF_COEFF2021, 0x068005e2},
+{9600000, DIF_BPF_COEFF2223, 0xfc9bf633},
+{9600000, DIF_BPF_COEFF2425, 0xfc7308ca},
+{9600000, DIF_BPF_COEFF2627, 0x0ad5fe30},
+{9600000, DIF_BPF_COEFF2829, 0xf274f7e0},
+{9600000, DIF_BPF_COEFF3031, 0x08c90f43},
+{9600000, DIF_BPF_COEFF3233, 0x01d4f147},
+{9600000, DIF_BPF_COEFF3435, 0xf371060f},
+{9600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 96_quant.dat*/
+
+
+/*case 9700000:*/
+/* BEGIN - DIF BPF register values from 97_quant.dat*/
+{9700000, DIF_BPF_COEFF01, 0x00010001},
+{9700000, DIF_BPF_COEFF23, 0xfff9fff1},
+{9700000, DIF_BPF_COEFF45, 0x00090038},
+{9700000, DIF_BPF_COEFF67, 0x0025ffa7},
+{9700000, DIF_BPF_COEFF89, 0xff5e0012},
+{9700000, DIF_BPF_COEFF1011, 0x013200f0},
+{9700000, DIF_BPF_COEFF1213, 0xfee3fd9b},
+{9700000, DIF_BPF_COEFF1415, 0xffaa0331},
+{9700000, DIF_BPF_COEFF1617, 0x0311fe15},
+{9700000, DIF_BPF_COEFF1819, 0xfa60fe18},
+{9700000, DIF_BPF_COEFF2021, 0x05bd06d1},
+{9700000, DIF_BPF_COEFF2223, 0xfe1bf64a},
+{9700000, DIF_BPF_COEFF2425, 0xfafa07ae},
+{9700000, DIF_BPF_COEFF2627, 0x0b7effab},
+{9700000, DIF_BPF_COEFF2829, 0xf2d5f6d7},
+{9700000, DIF_BPF_COEFF3031, 0x07d30f7a},
+{9700000, DIF_BPF_COEFF3233, 0x02a3f194},
+{9700000, DIF_BPF_COEFF3435, 0xf32905dc},
+{9700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 97_quant.dat*/
+
+
+/*case 9800000:*/
+/* BEGIN - DIF BPF register values from 98_quant.dat*/
+{9800000, DIF_BPF_COEFF01, 0x00010002},
+{9800000, DIF_BPF_COEFF23, 0xfffcffee},
+{9800000, DIF_BPF_COEFF45, 0xfffb0032},
+{9800000, DIF_BPF_COEFF67, 0x003fffcd},
+{9800000, DIF_BPF_COEFF89, 0xff4effc1},
+{9800000, DIF_BPF_COEFF1011, 0x0106014a},
+{9800000, DIF_BPF_COEFF1213, 0xff6efd8a},
+{9800000, DIF_BPF_COEFF1415, 0xfedd02aa},
+{9800000, DIF_BPF_COEFF1617, 0x03b0ff34},
+{9800000, DIF_BPF_COEFF1819, 0xfa74fcd7},
+{9800000, DIF_BPF_COEFF2021, 0x04bf0781},
+{9800000, DIF_BPF_COEFF2223, 0xffaaf6a3},
+{9800000, DIF_BPF_COEFF2425, 0xf99e066b},
+{9800000, DIF_BPF_COEFF2627, 0x0bf90128},
+{9800000, DIF_BPF_COEFF2829, 0xf359f5e1},
+{9800000, DIF_BPF_COEFF3031, 0x06d20fa2},
+{9800000, DIF_BPF_COEFF3233, 0x0370f1e5},
+{9800000, DIF_BPF_COEFF3435, 0xf2e405a8},
+{9800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 98_quant.dat*/
+
+
+/*case 9900000:*/
+/* BEGIN - DIF BPF register values from 99_quant.dat*/
+{9900000, DIF_BPF_COEFF01, 0x00000003},
+{9900000, DIF_BPF_COEFF23, 0xffffffee},
+{9900000, DIF_BPF_COEFF45, 0xffef0024},
+{9900000, DIF_BPF_COEFF67, 0x0051fffa},
+{9900000, DIF_BPF_COEFF89, 0xff54ff77},
+{9900000, DIF_BPF_COEFF1011, 0x00be0184},
+{9900000, DIF_BPF_COEFF1213, 0x0006fdad},
+{9900000, DIF_BPF_COEFF1415, 0xfe2701f3},
+{9900000, DIF_BPF_COEFF1617, 0x0413005e},
+{9900000, DIF_BPF_COEFF1819, 0xfad1fbba},
+{9900000, DIF_BPF_COEFF2021, 0x039007ee},
+{9900000, DIF_BPF_COEFF2223, 0x013bf73d},
+{9900000, DIF_BPF_COEFF2425, 0xf868050a},
+{9900000, DIF_BPF_COEFF2627, 0x0c4302a1},
+{9900000, DIF_BPF_COEFF2829, 0xf3fdf4fe},
+{9900000, DIF_BPF_COEFF3031, 0x05c70fba},
+{9900000, DIF_BPF_COEFF3233, 0x043bf23c},
+{9900000, DIF_BPF_COEFF3435, 0xf2a10575},
+{9900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 99_quant.dat*/
+
+
+/*case 10000000:*/
+/* BEGIN - DIF BPF register values from 100_quant.dat*/
+{10000000, DIF_BPF_COEFF01, 0x00000003},
+{10000000, DIF_BPF_COEFF23, 0x0003fff1},
+{10000000, DIF_BPF_COEFF45, 0xffe50011},
+{10000000, DIF_BPF_COEFF67, 0x00570027},
+{10000000, DIF_BPF_COEFF89, 0xff70ff3c},
+{10000000, DIF_BPF_COEFF1011, 0x00620198},
+{10000000, DIF_BPF_COEFF1213, 0x009efe01},
+{10000000, DIF_BPF_COEFF1415, 0xfd95011a},
+{10000000, DIF_BPF_COEFF1617, 0x04350183},
+{10000000, DIF_BPF_COEFF1819, 0xfb71fad0},
+{10000000, DIF_BPF_COEFF2021, 0x023c0812},
+{10000000, DIF_BPF_COEFF2223, 0x02c3f811},
+{10000000, DIF_BPF_COEFF2425, 0xf75e0390},
+{10000000, DIF_BPF_COEFF2627, 0x0c5c0411},
+{10000000, DIF_BPF_COEFF2829, 0xf4c1f432},
+{10000000, DIF_BPF_COEFF3031, 0x04b30fc1},
+{10000000, DIF_BPF_COEFF3233, 0x0503f297},
+{10000000, DIF_BPF_COEFF3435, 0xf2610541},
+{10000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 100_quant.dat*/
+
+
+/*case 10100000:*/
+/* BEGIN - DIF BPF register values from 101_quant.dat*/
+{10100000, DIF_BPF_COEFF01, 0x00000003},
+{10100000, DIF_BPF_COEFF23, 0x0006fff7},
+{10100000, DIF_BPF_COEFF45, 0xffdffffc},
+{10100000, DIF_BPF_COEFF67, 0x00510050},
+{10100000, DIF_BPF_COEFF89, 0xff9dff18},
+{10100000, DIF_BPF_COEFF1011, 0xfffc0184},
+{10100000, DIF_BPF_COEFF1213, 0x0128fe80},
+{10100000, DIF_BPF_COEFF1415, 0xfd32002e},
+{10100000, DIF_BPF_COEFF1617, 0x04130292},
+{10100000, DIF_BPF_COEFF1819, 0xfc4dfa21},
+{10100000, DIF_BPF_COEFF2021, 0x00d107ee},
+{10100000, DIF_BPF_COEFF2223, 0x0435f91c},
+{10100000, DIF_BPF_COEFF2425, 0xf6850205},
+{10100000, DIF_BPF_COEFF2627, 0x0c430573},
+{10100000, DIF_BPF_COEFF2829, 0xf5a1f37d},
+{10100000, DIF_BPF_COEFF3031, 0x03990fba},
+{10100000, DIF_BPF_COEFF3233, 0x05c7f2f8},
+{10100000, DIF_BPF_COEFF3435, 0xf222050d},
+{10100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 101_quant.dat*/
+
+
+/*case 10200000:*/
+/* BEGIN - DIF BPF register values from 102_quant.dat*/
+{10200000, DIF_BPF_COEFF01, 0x00000002},
+{10200000, DIF_BPF_COEFF23, 0x0008fffe},
+{10200000, DIF_BPF_COEFF45, 0xffdfffe7},
+{10200000, DIF_BPF_COEFF67, 0x003f006e},
+{10200000, DIF_BPF_COEFF89, 0xffd6ff0f},
+{10200000, DIF_BPF_COEFF1011, 0xff96014a},
+{10200000, DIF_BPF_COEFF1213, 0x0197ff1f},
+{10200000, DIF_BPF_COEFF1415, 0xfd05ff3e},
+{10200000, DIF_BPF_COEFF1617, 0x03b0037c},
+{10200000, DIF_BPF_COEFF1819, 0xfd59f9b7},
+{10200000, DIF_BPF_COEFF2021, 0xff5d0781},
+{10200000, DIF_BPF_COEFF2223, 0x0585fa56},
+{10200000, DIF_BPF_COEFF2425, 0xf5e4006f},
+{10200000, DIF_BPF_COEFF2627, 0x0bf906c4},
+{10200000, DIF_BPF_COEFF2829, 0xf69df2e0},
+{10200000, DIF_BPF_COEFF3031, 0x02790fa2},
+{10200000, DIF_BPF_COEFF3233, 0x0688f35d},
+{10200000, DIF_BPF_COEFF3435, 0xf1e604d8},
+{10200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 102_quant.dat*/
+
+
+/*case 10300000:*/
+/* BEGIN - DIF BPF register values from 103_quant.dat*/
+{10300000, DIF_BPF_COEFF01, 0xffff0001},
+{10300000, DIF_BPF_COEFF23, 0x00090005},
+{10300000, DIF_BPF_COEFF45, 0xffe4ffd6},
+{10300000, DIF_BPF_COEFF67, 0x0025007e},
+{10300000, DIF_BPF_COEFF89, 0x0014ff20},
+{10300000, DIF_BPF_COEFF1011, 0xff3c00f0},
+{10300000, DIF_BPF_COEFF1213, 0x01e1ffd0},
+{10300000, DIF_BPF_COEFF1415, 0xfd12fe5c},
+{10300000, DIF_BPF_COEFF1617, 0x03110433},
+{10300000, DIF_BPF_COEFF1819, 0xfe88f996},
+{10300000, DIF_BPF_COEFF2021, 0xfdf106d1},
+{10300000, DIF_BPF_COEFF2223, 0x06aafbb7},
+{10300000, DIF_BPF_COEFF2425, 0xf57efed8},
+{10300000, DIF_BPF_COEFF2627, 0x0b7e07ff},
+{10300000, DIF_BPF_COEFF2829, 0xf7b0f25e},
+{10300000, DIF_BPF_COEFF3031, 0x01560f7a},
+{10300000, DIF_BPF_COEFF3233, 0x0745f3c7},
+{10300000, DIF_BPF_COEFF3435, 0xf1ac04a4},
+{10300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 103_quant.dat*/
+
+
+/*case 10400000:*/
+/* BEGIN - DIF BPF register values from 104_quant.dat*/
+{10400000, DIF_BPF_COEFF01, 0xffffffff},
+{10400000, DIF_BPF_COEFF23, 0x0008000c},
+{10400000, DIF_BPF_COEFF45, 0xffedffcb},
+{10400000, DIF_BPF_COEFF67, 0x0005007d},
+{10400000, DIF_BPF_COEFF89, 0x0050ff4c},
+{10400000, DIF_BPF_COEFF1011, 0xfef6007e},
+{10400000, DIF_BPF_COEFF1213, 0x01ff0086},
+{10400000, DIF_BPF_COEFF1415, 0xfd58fd97},
+{10400000, DIF_BPF_COEFF1617, 0x024104ad},
+{10400000, DIF_BPF_COEFF1819, 0xffcaf9c0},
+{10400000, DIF_BPF_COEFF2021, 0xfc9905e2},
+{10400000, DIF_BPF_COEFF2223, 0x079afd35},
+{10400000, DIF_BPF_COEFF2425, 0xf555fd46},
+{10400000, DIF_BPF_COEFF2627, 0x0ad50920},
+{10400000, DIF_BPF_COEFF2829, 0xf8d9f1f6},
+{10400000, DIF_BPF_COEFF3031, 0x00310f43},
+{10400000, DIF_BPF_COEFF3233, 0x07fdf435},
+{10400000, DIF_BPF_COEFF3435, 0xf174046f},
+{10400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 104_quant.dat*/
+
+
+/*case 10500000:*/
+/* BEGIN - DIF BPF register values from 105_quant.dat*/
+{10500000, DIF_BPF_COEFF01, 0xfffffffe},
+{10500000, DIF_BPF_COEFF23, 0x00050011},
+{10500000, DIF_BPF_COEFF45, 0xfffaffc8},
+{10500000, DIF_BPF_COEFF67, 0xffe5006b},
+{10500000, DIF_BPF_COEFF89, 0x0082ff8c},
+{10500000, DIF_BPF_COEFF1011, 0xfecc0000},
+{10500000, DIF_BPF_COEFF1213, 0x01f00130},
+{10500000, DIF_BPF_COEFF1415, 0xfdd2fcfc},
+{10500000, DIF_BPF_COEFF1617, 0x014d04e3},
+{10500000, DIF_BPF_COEFF1819, 0x010efa32},
+{10500000, DIF_BPF_COEFF2021, 0xfb6404bf},
+{10500000, DIF_BPF_COEFF2223, 0x084efec5},
+{10500000, DIF_BPF_COEFF2425, 0xf569fbc2},
+{10500000, DIF_BPF_COEFF2627, 0x0a000a23},
+{10500000, DIF_BPF_COEFF2829, 0xfa15f1ab},
+{10500000, DIF_BPF_COEFF3031, 0xff0b0efc},
+{10500000, DIF_BPF_COEFF3233, 0x08b0f4a7},
+{10500000, DIF_BPF_COEFF3435, 0xf13f043a},
+{10500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 105_quant.dat*/
+
+
+/*case 10600000:*/
+/* BEGIN - DIF BPF register values from 106_quant.dat*/
+{10600000, DIF_BPF_COEFF01, 0x0000fffd},
+{10600000, DIF_BPF_COEFF23, 0x00020012},
+{10600000, DIF_BPF_COEFF45, 0x0007ffcd},
+{10600000, DIF_BPF_COEFF67, 0xffc9004c},
+{10600000, DIF_BPF_COEFF89, 0x00a4ffd9},
+{10600000, DIF_BPF_COEFF1011, 0xfec3ff82},
+{10600000, DIF_BPF_COEFF1213, 0x01b401c1},
+{10600000, DIF_BPF_COEFF1415, 0xfe76fc97},
+{10600000, DIF_BPF_COEFF1617, 0x004404d2},
+{10600000, DIF_BPF_COEFF1819, 0x0245fae8},
+{10600000, DIF_BPF_COEFF2021, 0xfa5f0370},
+{10600000, DIF_BPF_COEFF2223, 0x08c1005f},
+{10600000, DIF_BPF_COEFF2425, 0xf5bcfa52},
+{10600000, DIF_BPF_COEFF2627, 0x09020b04},
+{10600000, DIF_BPF_COEFF2829, 0xfb60f17b},
+{10600000, DIF_BPF_COEFF3031, 0xfde70ea6},
+{10600000, DIF_BPF_COEFF3233, 0x095df51e},
+{10600000, DIF_BPF_COEFF3435, 0xf10c0405},
+{10600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 106_quant.dat*/
+
+
+/*case 10700000:*/
+/* BEGIN - DIF BPF register values from 107_quant.dat*/
+{10700000, DIF_BPF_COEFF01, 0x0000fffd},
+{10700000, DIF_BPF_COEFF23, 0xffff0011},
+{10700000, DIF_BPF_COEFF45, 0x0014ffdb},
+{10700000, DIF_BPF_COEFF67, 0xffb40023},
+{10700000, DIF_BPF_COEFF89, 0x00b2002a},
+{10700000, DIF_BPF_COEFF1011, 0xfedbff10},
+{10700000, DIF_BPF_COEFF1213, 0x0150022d},
+{10700000, DIF_BPF_COEFF1415, 0xff38fc6f},
+{10700000, DIF_BPF_COEFF1617, 0xff36047b},
+{10700000, DIF_BPF_COEFF1819, 0x035efbda},
+{10700000, DIF_BPF_COEFF2021, 0xf9940202},
+{10700000, DIF_BPF_COEFF2223, 0x08ee01f5},
+{10700000, DIF_BPF_COEFF2425, 0xf649f8fe},
+{10700000, DIF_BPF_COEFF2627, 0x07e10bc2},
+{10700000, DIF_BPF_COEFF2829, 0xfcb6f169},
+{10700000, DIF_BPF_COEFF3031, 0xfcc60e42},
+{10700000, DIF_BPF_COEFF3233, 0x0a04f599},
+{10700000, DIF_BPF_COEFF3435, 0xf0db03d0},
+{10700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 107_quant.dat*/
+
+
+/*case 10800000:*/
+/* BEGIN - DIF BPF register values from 108_quant.dat*/
+{10800000, DIF_BPF_COEFF01, 0x0000fffd},
+{10800000, DIF_BPF_COEFF23, 0xfffb000d},
+{10800000, DIF_BPF_COEFF45, 0x001dffed},
+{10800000, DIF_BPF_COEFF67, 0xffaafff5},
+{10800000, DIF_BPF_COEFF89, 0x00aa0077},
+{10800000, DIF_BPF_COEFF1011, 0xff13feb6},
+{10800000, DIF_BPF_COEFF1213, 0x00ce026b},
+{10800000, DIF_BPF_COEFF1415, 0x000afc85},
+{10800000, DIF_BPF_COEFF1617, 0xfe3503e3},
+{10800000, DIF_BPF_COEFF1819, 0x044cfcfb},
+{10800000, DIF_BPF_COEFF2021, 0xf90c0082},
+{10800000, DIF_BPF_COEFF2223, 0x08d5037f},
+{10800000, DIF_BPF_COEFF2425, 0xf710f7cc},
+{10800000, DIF_BPF_COEFF2627, 0x069f0c59},
+{10800000, DIF_BPF_COEFF2829, 0xfe16f173},
+{10800000, DIF_BPF_COEFF3031, 0xfbaa0dcf},
+{10800000, DIF_BPF_COEFF3233, 0x0aa5f617},
+{10800000, DIF_BPF_COEFF3435, 0xf0ad039b},
+{10800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 108_quant.dat*/
+
+
+/*case 10900000:*/
+/* BEGIN - DIF BPF register values from 109_quant.dat*/
+{10900000, DIF_BPF_COEFF01, 0x0000fffe},
+{10900000, DIF_BPF_COEFF23, 0xfff90006},
+{10900000, DIF_BPF_COEFF45, 0x00210003},
+{10900000, DIF_BPF_COEFF67, 0xffacffc8},
+{10900000, DIF_BPF_COEFF89, 0x008e00b6},
+{10900000, DIF_BPF_COEFF1011, 0xff63fe7c},
+{10900000, DIF_BPF_COEFF1213, 0x003a0275},
+{10900000, DIF_BPF_COEFF1415, 0x00dafcda},
+{10900000, DIF_BPF_COEFF1617, 0xfd510313},
+{10900000, DIF_BPF_COEFF1819, 0x0501fe40},
+{10900000, DIF_BPF_COEFF2021, 0xf8cbfefd},
+{10900000, DIF_BPF_COEFF2223, 0x087604f0},
+{10900000, DIF_BPF_COEFF2425, 0xf80af6c2},
+{10900000, DIF_BPF_COEFF2627, 0x05430cc8},
+{10900000, DIF_BPF_COEFF2829, 0xff7af19a},
+{10900000, DIF_BPF_COEFF3031, 0xfa940d4e},
+{10900000, DIF_BPF_COEFF3233, 0x0b3ff699},
+{10900000, DIF_BPF_COEFF3435, 0xf0810365},
+{10900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 109_quant.dat*/
+
+
+/*case 11000000:*/
+/* BEGIN - DIF BPF register values from 110_quant.dat*/
+{11000000, DIF_BPF_COEFF01, 0x0001ffff},
+{11000000, DIF_BPF_COEFF23, 0xfff8ffff},
+{11000000, DIF_BPF_COEFF45, 0x00210018},
+{11000000, DIF_BPF_COEFF67, 0xffbaffa3},
+{11000000, DIF_BPF_COEFF89, 0x006000e1},
+{11000000, DIF_BPF_COEFF1011, 0xffc4fe68},
+{11000000, DIF_BPF_COEFF1213, 0xffa0024b},
+{11000000, DIF_BPF_COEFF1415, 0x019afd66},
+{11000000, DIF_BPF_COEFF1617, 0xfc990216},
+{11000000, DIF_BPF_COEFF1819, 0x0575ff99},
+{11000000, DIF_BPF_COEFF2021, 0xf8d4fd81},
+{11000000, DIF_BPF_COEFF2223, 0x07d40640},
+{11000000, DIF_BPF_COEFF2425, 0xf932f5e6},
+{11000000, DIF_BPF_COEFF2627, 0x03d20d0d},
+{11000000, DIF_BPF_COEFF2829, 0x00dff1de},
+{11000000, DIF_BPF_COEFF3031, 0xf9860cbf},
+{11000000, DIF_BPF_COEFF3233, 0x0bd1f71e},
+{11000000, DIF_BPF_COEFF3435, 0xf058032f},
+{11000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 110_quant.dat*/
+
+
+/*case 11100000:*/
+/* BEGIN - DIF BPF register values from 111_quant.dat*/
+{11100000, DIF_BPF_COEFF01, 0x00010000},
+{11100000, DIF_BPF_COEFF23, 0xfff8fff8},
+{11100000, DIF_BPF_COEFF45, 0x001b0029},
+{11100000, DIF_BPF_COEFF67, 0xffd1ff8a},
+{11100000, DIF_BPF_COEFF89, 0x002600f2},
+{11100000, DIF_BPF_COEFF1011, 0x002cfe7c},
+{11100000, DIF_BPF_COEFF1213, 0xff0f01f0},
+{11100000, DIF_BPF_COEFF1415, 0x023bfe20},
+{11100000, DIF_BPF_COEFF1617, 0xfc1700fa},
+{11100000, DIF_BPF_COEFF1819, 0x05a200f7},
+{11100000, DIF_BPF_COEFF2021, 0xf927fc1c},
+{11100000, DIF_BPF_COEFF2223, 0x06f40765},
+{11100000, DIF_BPF_COEFF2425, 0xfa82f53b},
+{11100000, DIF_BPF_COEFF2627, 0x02510d27},
+{11100000, DIF_BPF_COEFF2829, 0x0243f23d},
+{11100000, DIF_BPF_COEFF3031, 0xf8810c24},
+{11100000, DIF_BPF_COEFF3233, 0x0c5cf7a7},
+{11100000, DIF_BPF_COEFF3435, 0xf03102fa},
+{11100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 111_quant.dat*/
+
+
+/*case 11200000:*/
+/* BEGIN - DIF BPF register values from 112_quant.dat*/
+{11200000, DIF_BPF_COEFF01, 0x00010002},
+{11200000, DIF_BPF_COEFF23, 0xfffafff2},
+{11200000, DIF_BPF_COEFF45, 0x00110035},
+{11200000, DIF_BPF_COEFF67, 0xfff0ff81},
+{11200000, DIF_BPF_COEFF89, 0xffe700e7},
+{11200000, DIF_BPF_COEFF1011, 0x008ffeb6},
+{11200000, DIF_BPF_COEFF1213, 0xfe94016d},
+{11200000, DIF_BPF_COEFF1415, 0x02b0fefb},
+{11200000, DIF_BPF_COEFF1617, 0xfbd3ffd1},
+{11200000, DIF_BPF_COEFF1819, 0x05850249},
+{11200000, DIF_BPF_COEFF2021, 0xf9c1fadb},
+{11200000, DIF_BPF_COEFF2223, 0x05de0858},
+{11200000, DIF_BPF_COEFF2425, 0xfbf2f4c4},
+{11200000, DIF_BPF_COEFF2627, 0x00c70d17},
+{11200000, DIF_BPF_COEFF2829, 0x03a0f2b8},
+{11200000, DIF_BPF_COEFF3031, 0xf7870b7c},
+{11200000, DIF_BPF_COEFF3233, 0x0cdff833},
+{11200000, DIF_BPF_COEFF3435, 0xf00d02c4},
+{11200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 112_quant.dat*/
+
+
+/*case 11300000:*/
+/* BEGIN - DIF BPF register values from 113_quant.dat*/
+{11300000, DIF_BPF_COEFF01, 0x00000003},
+{11300000, DIF_BPF_COEFF23, 0xfffdffee},
+{11300000, DIF_BPF_COEFF45, 0x00040038},
+{11300000, DIF_BPF_COEFF67, 0x0010ff88},
+{11300000, DIF_BPF_COEFF89, 0xffac00c2},
+{11300000, DIF_BPF_COEFF1011, 0x00e2ff10},
+{11300000, DIF_BPF_COEFF1213, 0xfe3900cb},
+{11300000, DIF_BPF_COEFF1415, 0x02f1ffe9},
+{11300000, DIF_BPF_COEFF1617, 0xfbd3feaa},
+{11300000, DIF_BPF_COEFF1819, 0x05210381},
+{11300000, DIF_BPF_COEFF2021, 0xfa9cf9c8},
+{11300000, DIF_BPF_COEFF2223, 0x04990912},
+{11300000, DIF_BPF_COEFF2425, 0xfd7af484},
+{11300000, DIF_BPF_COEFF2627, 0xff390cdb},
+{11300000, DIF_BPF_COEFF2829, 0x04f4f34d},
+{11300000, DIF_BPF_COEFF3031, 0xf69a0ac9},
+{11300000, DIF_BPF_COEFF3233, 0x0d5af8c1},
+{11300000, DIF_BPF_COEFF3435, 0xefec028e},
+{11300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 113_quant.dat*/
+
+
+/*case 11400000:*/
+/* BEGIN - DIF BPF register values from 114_quant.dat*/
+{11400000, DIF_BPF_COEFF01, 0x00000003},
+{11400000, DIF_BPF_COEFF23, 0x0000ffee},
+{11400000, DIF_BPF_COEFF45, 0xfff60033},
+{11400000, DIF_BPF_COEFF67, 0x002fff9f},
+{11400000, DIF_BPF_COEFF89, 0xff7b0087},
+{11400000, DIF_BPF_COEFF1011, 0x011eff82},
+{11400000, DIF_BPF_COEFF1213, 0xfe080018},
+{11400000, DIF_BPF_COEFF1415, 0x02f900d8},
+{11400000, DIF_BPF_COEFF1617, 0xfc17fd96},
+{11400000, DIF_BPF_COEFF1819, 0x04790490},
+{11400000, DIF_BPF_COEFF2021, 0xfbadf8ed},
+{11400000, DIF_BPF_COEFF2223, 0x032f098e},
+{11400000, DIF_BPF_COEFF2425, 0xff10f47d},
+{11400000, DIF_BPF_COEFF2627, 0xfdaf0c75},
+{11400000, DIF_BPF_COEFF2829, 0x063cf3fc},
+{11400000, DIF_BPF_COEFF3031, 0xf5ba0a0b},
+{11400000, DIF_BPF_COEFF3233, 0x0dccf952},
+{11400000, DIF_BPF_COEFF3435, 0xefcd0258},
+{11400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 114_quant.dat*/
+
+
+/*case 11500000:*/
+/* BEGIN - DIF BPF register values from 115_quant.dat*/
+{11500000, DIF_BPF_COEFF01, 0x00000003},
+{11500000, DIF_BPF_COEFF23, 0x0004fff1},
+{11500000, DIF_BPF_COEFF45, 0xffea0026},
+{11500000, DIF_BPF_COEFF67, 0x0046ffc3},
+{11500000, DIF_BPF_COEFF89, 0xff5a003c},
+{11500000, DIF_BPF_COEFF1011, 0x013b0000},
+{11500000, DIF_BPF_COEFF1213, 0xfe04ff63},
+{11500000, DIF_BPF_COEFF1415, 0x02c801b8},
+{11500000, DIF_BPF_COEFF1617, 0xfc99fca6},
+{11500000, DIF_BPF_COEFF1819, 0x0397056a},
+{11500000, DIF_BPF_COEFF2021, 0xfcecf853},
+{11500000, DIF_BPF_COEFF2223, 0x01ad09c9},
+{11500000, DIF_BPF_COEFF2425, 0x00acf4ad},
+{11500000, DIF_BPF_COEFF2627, 0xfc2e0be7},
+{11500000, DIF_BPF_COEFF2829, 0x0773f4c2},
+{11500000, DIF_BPF_COEFF3031, 0xf4e90943},
+{11500000, DIF_BPF_COEFF3233, 0x0e35f9e6},
+{11500000, DIF_BPF_COEFF3435, 0xefb10221},
+{11500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 115_quant.dat*/
+
+
+/*case 11600000:*/
+/* BEGIN - DIF BPF register values from 116_quant.dat*/
+{11600000, DIF_BPF_COEFF01, 0x00000002},
+{11600000, DIF_BPF_COEFF23, 0x0007fff6},
+{11600000, DIF_BPF_COEFF45, 0xffe20014},
+{11600000, DIF_BPF_COEFF67, 0x0054ffee},
+{11600000, DIF_BPF_COEFF89, 0xff4effeb},
+{11600000, DIF_BPF_COEFF1011, 0x0137007e},
+{11600000, DIF_BPF_COEFF1213, 0xfe2efebb},
+{11600000, DIF_BPF_COEFF1415, 0x0260027a},
+{11600000, DIF_BPF_COEFF1617, 0xfd51fbe6},
+{11600000, DIF_BPF_COEFF1819, 0x02870605},
+{11600000, DIF_BPF_COEFF2021, 0xfe4af7fe},
+{11600000, DIF_BPF_COEFF2223, 0x001d09c1},
+{11600000, DIF_BPF_COEFF2425, 0x0243f515},
+{11600000, DIF_BPF_COEFF2627, 0xfabd0b32},
+{11600000, DIF_BPF_COEFF2829, 0x0897f59e},
+{11600000, DIF_BPF_COEFF3031, 0xf4280871},
+{11600000, DIF_BPF_COEFF3233, 0x0e95fa7c},
+{11600000, DIF_BPF_COEFF3435, 0xef9701eb},
+{11600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 116_quant.dat*/
+
+
+/*case 11700000:*/
+/* BEGIN - DIF BPF register values from 117_quant.dat*/
+{11700000, DIF_BPF_COEFF01, 0xffff0001},
+{11700000, DIF_BPF_COEFF23, 0x0008fffd},
+{11700000, DIF_BPF_COEFF45, 0xffdeffff},
+{11700000, DIF_BPF_COEFF67, 0x0056001d},
+{11700000, DIF_BPF_COEFF89, 0xff57ff9c},
+{11700000, DIF_BPF_COEFF1011, 0x011300f0},
+{11700000, DIF_BPF_COEFF1213, 0xfe82fe2e},
+{11700000, DIF_BPF_COEFF1415, 0x01ca0310},
+{11700000, DIF_BPF_COEFF1617, 0xfe35fb62},
+{11700000, DIF_BPF_COEFF1819, 0x0155065a},
+{11700000, DIF_BPF_COEFF2021, 0xffbaf7f2},
+{11700000, DIF_BPF_COEFF2223, 0xfe8c0977},
+{11700000, DIF_BPF_COEFF2425, 0x03cef5b2},
+{11700000, DIF_BPF_COEFF2627, 0xf9610a58},
+{11700000, DIF_BPF_COEFF2829, 0x09a5f68f},
+{11700000, DIF_BPF_COEFF3031, 0xf3790797},
+{11700000, DIF_BPF_COEFF3233, 0x0eebfb14},
+{11700000, DIF_BPF_COEFF3435, 0xef8001b5},
+{11700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 117_quant.dat*/
+
+
+/*case 11800000:*/
+/* BEGIN - DIF BPF register values from 118_quant.dat*/
+{11800000, DIF_BPF_COEFF01, 0xffff0000},
+{11800000, DIF_BPF_COEFF23, 0x00080004},
+{11800000, DIF_BPF_COEFF45, 0xffe0ffe9},
+{11800000, DIF_BPF_COEFF67, 0x004c0047},
+{11800000, DIF_BPF_COEFF89, 0xff75ff58},
+{11800000, DIF_BPF_COEFF1011, 0x00d1014a},
+{11800000, DIF_BPF_COEFF1213, 0xfef9fdc8},
+{11800000, DIF_BPF_COEFF1415, 0x0111036f},
+{11800000, DIF_BPF_COEFF1617, 0xff36fb21},
+{11800000, DIF_BPF_COEFF1819, 0x00120665},
+{11800000, DIF_BPF_COEFF2021, 0x012df82e},
+{11800000, DIF_BPF_COEFF2223, 0xfd0708ec},
+{11800000, DIF_BPF_COEFF2425, 0x0542f682},
+{11800000, DIF_BPF_COEFF2627, 0xf81f095c},
+{11800000, DIF_BPF_COEFF2829, 0x0a9af792},
+{11800000, DIF_BPF_COEFF3031, 0xf2db06b5},
+{11800000, DIF_BPF_COEFF3233, 0x0f38fbad},
+{11800000, DIF_BPF_COEFF3435, 0xef6c017e},
+{11800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 118_quant.dat*/
+
+
+/*case 11900000:*/
+/* BEGIN - DIF BPF register values from 119_quant.dat*/
+{11900000, DIF_BPF_COEFF01, 0xffffffff},
+{11900000, DIF_BPF_COEFF23, 0x0007000b},
+{11900000, DIF_BPF_COEFF45, 0xffe7ffd8},
+{11900000, DIF_BPF_COEFF67, 0x00370068},
+{11900000, DIF_BPF_COEFF89, 0xffa4ff28},
+{11900000, DIF_BPF_COEFF1011, 0x00790184},
+{11900000, DIF_BPF_COEFF1213, 0xff87fd91},
+{11900000, DIF_BPF_COEFF1415, 0x00430392},
+{11900000, DIF_BPF_COEFF1617, 0x0044fb26},
+{11900000, DIF_BPF_COEFF1819, 0xfece0626},
+{11900000, DIF_BPF_COEFF2021, 0x0294f8b2},
+{11900000, DIF_BPF_COEFF2223, 0xfb990825},
+{11900000, DIF_BPF_COEFF2425, 0x0698f77f},
+{11900000, DIF_BPF_COEFF2627, 0xf6fe0842},
+{11900000, DIF_BPF_COEFF2829, 0x0b73f8a7},
+{11900000, DIF_BPF_COEFF3031, 0xf25105cd},
+{11900000, DIF_BPF_COEFF3233, 0x0f7bfc48},
+{11900000, DIF_BPF_COEFF3435, 0xef5a0148},
+{11900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 119_quant.dat*/
+
+
+/*case 12000000:*/
+/* BEGIN - DIF BPF register values from 120_quant.dat*/
+{12000000, DIF_BPF_COEFF01, 0x0000fffe},
+{12000000, DIF_BPF_COEFF23, 0x00050010},
+{12000000, DIF_BPF_COEFF45, 0xfff2ffcc},
+{12000000, DIF_BPF_COEFF67, 0x001b007b},
+{12000000, DIF_BPF_COEFF89, 0xffdfff10},
+{12000000, DIF_BPF_COEFF1011, 0x00140198},
+{12000000, DIF_BPF_COEFF1213, 0x0020fd8e},
+{12000000, DIF_BPF_COEFF1415, 0xff710375},
+{12000000, DIF_BPF_COEFF1617, 0x014dfb73},
+{12000000, DIF_BPF_COEFF1819, 0xfd9a059f},
+{12000000, DIF_BPF_COEFF2021, 0x03e0f978},
+{12000000, DIF_BPF_COEFF2223, 0xfa4e0726},
+{12000000, DIF_BPF_COEFF2425, 0x07c8f8a7},
+{12000000, DIF_BPF_COEFF2627, 0xf600070c},
+{12000000, DIF_BPF_COEFF2829, 0x0c2ff9c9},
+{12000000, DIF_BPF_COEFF3031, 0xf1db04de},
+{12000000, DIF_BPF_COEFF3233, 0x0fb4fce5},
+{12000000, DIF_BPF_COEFF3435, 0xef4b0111},
+{12000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 120_quant.dat*/
+
+
+/*case 12100000:*/
+/* BEGIN - DIF BPF register values from 121_quant.dat*/
+{12100000, DIF_BPF_COEFF01, 0x0000fffd},
+{12100000, DIF_BPF_COEFF23, 0x00010012},
+{12100000, DIF_BPF_COEFF45, 0xffffffc8},
+{12100000, DIF_BPF_COEFF67, 0xfffb007e},
+{12100000, DIF_BPF_COEFF89, 0x001dff14},
+{12100000, DIF_BPF_COEFF1011, 0xffad0184},
+{12100000, DIF_BPF_COEFF1213, 0x00b7fdbe},
+{12100000, DIF_BPF_COEFF1415, 0xfea9031b},
+{12100000, DIF_BPF_COEFF1617, 0x0241fc01},
+{12100000, DIF_BPF_COEFF1819, 0xfc8504d6},
+{12100000, DIF_BPF_COEFF2021, 0x0504fa79},
+{12100000, DIF_BPF_COEFF2223, 0xf93005f6},
+{12100000, DIF_BPF_COEFF2425, 0x08caf9f2},
+{12100000, DIF_BPF_COEFF2627, 0xf52b05c0},
+{12100000, DIF_BPF_COEFF2829, 0x0ccbfaf9},
+{12100000, DIF_BPF_COEFF3031, 0xf17903eb},
+{12100000, DIF_BPF_COEFF3233, 0x0fe3fd83},
+{12100000, DIF_BPF_COEFF3435, 0xef3f00db},
+{12100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 121_quant.dat*/
+
+
+/*case 12200000:*/
+/* BEGIN - DIF BPF register values from 122_quant.dat*/
+{12200000, DIF_BPF_COEFF01, 0x0000fffd},
+{12200000, DIF_BPF_COEFF23, 0xfffe0011},
+{12200000, DIF_BPF_COEFF45, 0x000cffcc},
+{12200000, DIF_BPF_COEFF67, 0xffdb0071},
+{12200000, DIF_BPF_COEFF89, 0x0058ff32},
+{12200000, DIF_BPF_COEFF1011, 0xff4f014a},
+{12200000, DIF_BPF_COEFF1213, 0x013cfe1f},
+{12200000, DIF_BPF_COEFF1415, 0xfdfb028a},
+{12200000, DIF_BPF_COEFF1617, 0x0311fcc9},
+{12200000, DIF_BPF_COEFF1819, 0xfb9d03d6},
+{12200000, DIF_BPF_COEFF2021, 0x05f4fbad},
+{12200000, DIF_BPF_COEFF2223, 0xf848049d},
+{12200000, DIF_BPF_COEFF2425, 0x0999fb5b},
+{12200000, DIF_BPF_COEFF2627, 0xf4820461},
+{12200000, DIF_BPF_COEFF2829, 0x0d46fc32},
+{12200000, DIF_BPF_COEFF3031, 0xf12d02f4},
+{12200000, DIF_BPF_COEFF3233, 0x1007fe21},
+{12200000, DIF_BPF_COEFF3435, 0xef3600a4},
+{12200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 122_quant.dat*/
+
+
+/*case 12300000:*/
+/* BEGIN - DIF BPF register values from 123_quant.dat*/
+{12300000, DIF_BPF_COEFF01, 0x0000fffe},
+{12300000, DIF_BPF_COEFF23, 0xfffa000e},
+{12300000, DIF_BPF_COEFF45, 0x0017ffd9},
+{12300000, DIF_BPF_COEFF67, 0xffc10055},
+{12300000, DIF_BPF_COEFF89, 0x0088ff68},
+{12300000, DIF_BPF_COEFF1011, 0xff0400f0},
+{12300000, DIF_BPF_COEFF1213, 0x01a6fea7},
+{12300000, DIF_BPF_COEFF1415, 0xfd7501cc},
+{12300000, DIF_BPF_COEFF1617, 0x03b0fdc0},
+{12300000, DIF_BPF_COEFF1819, 0xfaef02a8},
+{12300000, DIF_BPF_COEFF2021, 0x06a7fd07},
+{12300000, DIF_BPF_COEFF2223, 0xf79d0326},
+{12300000, DIF_BPF_COEFF2425, 0x0a31fcda},
+{12300000, DIF_BPF_COEFF2627, 0xf40702f3},
+{12300000, DIF_BPF_COEFF2829, 0x0d9ffd72},
+{12300000, DIF_BPF_COEFF3031, 0xf0f601fa},
+{12300000, DIF_BPF_COEFF3233, 0x1021fec0},
+{12300000, DIF_BPF_COEFF3435, 0xef2f006d},
+{12300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 123_quant.dat*/
+
+
+/*case 12400000:*/
+/* BEGIN - DIF BPF register values from 124_quant.dat*/
+{12400000, DIF_BPF_COEFF01, 0x0001ffff},
+{12400000, DIF_BPF_COEFF23, 0xfff80007},
+{12400000, DIF_BPF_COEFF45, 0x001fffeb},
+{12400000, DIF_BPF_COEFF67, 0xffaf002d},
+{12400000, DIF_BPF_COEFF89, 0x00a8ffb0},
+{12400000, DIF_BPF_COEFF1011, 0xfed3007e},
+{12400000, DIF_BPF_COEFF1213, 0x01e9ff4c},
+{12400000, DIF_BPF_COEFF1415, 0xfd2000ee},
+{12400000, DIF_BPF_COEFF1617, 0x0413fed8},
+{12400000, DIF_BPF_COEFF1819, 0xfa82015c},
+{12400000, DIF_BPF_COEFF2021, 0x0715fe7d},
+{12400000, DIF_BPF_COEFF2223, 0xf7340198},
+{12400000, DIF_BPF_COEFF2425, 0x0a8dfe69},
+{12400000, DIF_BPF_COEFF2627, 0xf3bd017c},
+{12400000, DIF_BPF_COEFF2829, 0x0dd5feb8},
+{12400000, DIF_BPF_COEFF3031, 0xf0d500fd},
+{12400000, DIF_BPF_COEFF3233, 0x1031ff60},
+{12400000, DIF_BPF_COEFF3435, 0xef2b0037},
+{12400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 124_quant.dat*/
+
+
+/*case 12500000:*/
+/* BEGIN - DIF BPF register values from 125_quant.dat*/
+{12500000, DIF_BPF_COEFF01, 0x00010000},
+{12500000, DIF_BPF_COEFF23, 0xfff70000},
+{12500000, DIF_BPF_COEFF45, 0x00220000},
+{12500000, DIF_BPF_COEFF67, 0xffa90000},
+{12500000, DIF_BPF_COEFF89, 0x00b30000},
+{12500000, DIF_BPF_COEFF1011, 0xfec20000},
+{12500000, DIF_BPF_COEFF1213, 0x02000000},
+{12500000, DIF_BPF_COEFF1415, 0xfd030000},
+{12500000, DIF_BPF_COEFF1617, 0x04350000},
+{12500000, DIF_BPF_COEFF1819, 0xfa5e0000},
+{12500000, DIF_BPF_COEFF2021, 0x073b0000},
+{12500000, DIF_BPF_COEFF2223, 0xf7110000},
+{12500000, DIF_BPF_COEFF2425, 0x0aac0000},
+{12500000, DIF_BPF_COEFF2627, 0xf3a40000},
+{12500000, DIF_BPF_COEFF2829, 0x0de70000},
+{12500000, DIF_BPF_COEFF3031, 0xf0c90000},
+{12500000, DIF_BPF_COEFF3233, 0x10360000},
+{12500000, DIF_BPF_COEFF3435, 0xef290000},
+{12500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 125_quant.dat*/
+
+
+/*case 12600000:*/
+/* BEGIN - DIF BPF register values from 126_quant.dat*/
+{12600000, DIF_BPF_COEFF01, 0x00010001},
+{12600000, DIF_BPF_COEFF23, 0xfff8fff9},
+{12600000, DIF_BPF_COEFF45, 0x001f0015},
+{12600000, DIF_BPF_COEFF67, 0xffafffd3},
+{12600000, DIF_BPF_COEFF89, 0x00a80050},
+{12600000, DIF_BPF_COEFF1011, 0xfed3ff82},
+{12600000, DIF_BPF_COEFF1213, 0x01e900b4},
+{12600000, DIF_BPF_COEFF1415, 0xfd20ff12},
+{12600000, DIF_BPF_COEFF1617, 0x04130128},
+{12600000, DIF_BPF_COEFF1819, 0xfa82fea4},
+{12600000, DIF_BPF_COEFF2021, 0x07150183},
+{12600000, DIF_BPF_COEFF2223, 0xf734fe68},
+{12600000, DIF_BPF_COEFF2425, 0x0a8d0197},
+{12600000, DIF_BPF_COEFF2627, 0xf3bdfe84},
+{12600000, DIF_BPF_COEFF2829, 0x0dd50148},
+{12600000, DIF_BPF_COEFF3031, 0xf0d5ff03},
+{12600000, DIF_BPF_COEFF3233, 0x103100a0},
+{12600000, DIF_BPF_COEFF3435, 0xef2bffc9},
+{12600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 126_quant.dat*/
+
+
+/*case 12700000:*/
+/* BEGIN - DIF BPF register values from 127_quant.dat*/
+{12700000, DIF_BPF_COEFF01, 0x00000002},
+{12700000, DIF_BPF_COEFF23, 0xfffafff2},
+{12700000, DIF_BPF_COEFF45, 0x00170027},
+{12700000, DIF_BPF_COEFF67, 0xffc1ffab},
+{12700000, DIF_BPF_COEFF89, 0x00880098},
+{12700000, DIF_BPF_COEFF1011, 0xff04ff10},
+{12700000, DIF_BPF_COEFF1213, 0x01a60159},
+{12700000, DIF_BPF_COEFF1415, 0xfd75fe34},
+{12700000, DIF_BPF_COEFF1617, 0x03b00240},
+{12700000, DIF_BPF_COEFF1819, 0xfaeffd58},
+{12700000, DIF_BPF_COEFF2021, 0x06a702f9},
+{12700000, DIF_BPF_COEFF2223, 0xf79dfcda},
+{12700000, DIF_BPF_COEFF2425, 0x0a310326},
+{12700000, DIF_BPF_COEFF2627, 0xf407fd0d},
+{12700000, DIF_BPF_COEFF2829, 0x0d9f028e},
+{12700000, DIF_BPF_COEFF3031, 0xf0f6fe06},
+{12700000, DIF_BPF_COEFF3233, 0x10210140},
+{12700000, DIF_BPF_COEFF3435, 0xef2fff93},
+{12700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 127_quant.dat*/
+
+
+/*case 12800000:*/
+/* BEGIN - DIF BPF register values from 128_quant.dat*/
+{12800000, DIF_BPF_COEFF01, 0x00000003},
+{12800000, DIF_BPF_COEFF23, 0xfffeffef},
+{12800000, DIF_BPF_COEFF45, 0x000c0034},
+{12800000, DIF_BPF_COEFF67, 0xffdbff8f},
+{12800000, DIF_BPF_COEFF89, 0x005800ce},
+{12800000, DIF_BPF_COEFF1011, 0xff4ffeb6},
+{12800000, DIF_BPF_COEFF1213, 0x013c01e1},
+{12800000, DIF_BPF_COEFF1415, 0xfdfbfd76},
+{12800000, DIF_BPF_COEFF1617, 0x03110337},
+{12800000, DIF_BPF_COEFF1819, 0xfb9dfc2a},
+{12800000, DIF_BPF_COEFF2021, 0x05f40453},
+{12800000, DIF_BPF_COEFF2223, 0xf848fb63},
+{12800000, DIF_BPF_COEFF2425, 0x099904a5},
+{12800000, DIF_BPF_COEFF2627, 0xf482fb9f},
+{12800000, DIF_BPF_COEFF2829, 0x0d4603ce},
+{12800000, DIF_BPF_COEFF3031, 0xf12dfd0c},
+{12800000, DIF_BPF_COEFF3233, 0x100701df},
+{12800000, DIF_BPF_COEFF3435, 0xef36ff5c},
+{12800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 128_quant.dat*/
+
+
+/*case 12900000:*/
+/* BEGIN - DIF BPF register values from 129_quant.dat*/
+{12900000, DIF_BPF_COEFF01, 0x00000003},
+{12900000, DIF_BPF_COEFF23, 0x0001ffee},
+{12900000, DIF_BPF_COEFF45, 0xffff0038},
+{12900000, DIF_BPF_COEFF67, 0xfffbff82},
+{12900000, DIF_BPF_COEFF89, 0x001d00ec},
+{12900000, DIF_BPF_COEFF1011, 0xffadfe7c},
+{12900000, DIF_BPF_COEFF1213, 0x00b70242},
+{12900000, DIF_BPF_COEFF1415, 0xfea9fce5},
+{12900000, DIF_BPF_COEFF1617, 0x024103ff},
+{12900000, DIF_BPF_COEFF1819, 0xfc85fb2a},
+{12900000, DIF_BPF_COEFF2021, 0x05040587},
+{12900000, DIF_BPF_COEFF2223, 0xf930fa0a},
+{12900000, DIF_BPF_COEFF2425, 0x08ca060e},
+{12900000, DIF_BPF_COEFF2627, 0xf52bfa40},
+{12900000, DIF_BPF_COEFF2829, 0x0ccb0507},
+{12900000, DIF_BPF_COEFF3031, 0xf179fc15},
+{12900000, DIF_BPF_COEFF3233, 0x0fe3027d},
+{12900000, DIF_BPF_COEFF3435, 0xef3fff25},
+{12900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 129_quant.dat*/
+
+
+/*case 113000000:*/
+/* BEGIN - DIF BPF register values from 130_quant.dat*/
+{13000000, DIF_BPF_COEFF01, 0x00000002},
+{13000000, DIF_BPF_COEFF23, 0x0005fff0},
+{13000000, DIF_BPF_COEFF45, 0xfff20034},
+{13000000, DIF_BPF_COEFF67, 0x001bff85},
+{13000000, DIF_BPF_COEFF89, 0xffdf00f0},
+{13000000, DIF_BPF_COEFF1011, 0x0014fe68},
+{13000000, DIF_BPF_COEFF1213, 0x00200272},
+{13000000, DIF_BPF_COEFF1415, 0xff71fc8b},
+{13000000, DIF_BPF_COEFF1617, 0x014d048d},
+{13000000, DIF_BPF_COEFF1819, 0xfd9afa61},
+{13000000, DIF_BPF_COEFF2021, 0x03e00688},
+{13000000, DIF_BPF_COEFF2223, 0xfa4ef8da},
+{13000000, DIF_BPF_COEFF2425, 0x07c80759},
+{13000000, DIF_BPF_COEFF2627, 0xf600f8f4},
+{13000000, DIF_BPF_COEFF2829, 0x0c2f0637},
+{13000000, DIF_BPF_COEFF3031, 0xf1dbfb22},
+{13000000, DIF_BPF_COEFF3233, 0x0fb4031b},
+{13000000, DIF_BPF_COEFF3435, 0xef4bfeef},
+{13000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 130_quant.dat*/
+
+
+/*case 13100000:*/
+/* BEGIN - DIF BPF register values from 131_quant.dat*/
+{13100000, DIF_BPF_COEFF01, 0xffff0001},
+{13100000, DIF_BPF_COEFF23, 0x0007fff5},
+{13100000, DIF_BPF_COEFF45, 0xffe70028},
+{13100000, DIF_BPF_COEFF67, 0x0037ff98},
+{13100000, DIF_BPF_COEFF89, 0xffa400d8},
+{13100000, DIF_BPF_COEFF1011, 0x0079fe7c},
+{13100000, DIF_BPF_COEFF1213, 0xff87026f},
+{13100000, DIF_BPF_COEFF1415, 0x0043fc6e},
+{13100000, DIF_BPF_COEFF1617, 0x004404da},
+{13100000, DIF_BPF_COEFF1819, 0xfecef9da},
+{13100000, DIF_BPF_COEFF2021, 0x0294074e},
+{13100000, DIF_BPF_COEFF2223, 0xfb99f7db},
+{13100000, DIF_BPF_COEFF2425, 0x06980881},
+{13100000, DIF_BPF_COEFF2627, 0xf6fef7be},
+{13100000, DIF_BPF_COEFF2829, 0x0b730759},
+{13100000, DIF_BPF_COEFF3031, 0xf251fa33},
+{13100000, DIF_BPF_COEFF3233, 0x0f7b03b8},
+{13100000, DIF_BPF_COEFF3435, 0xef5afeb8},
+{13100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 131_quant.dat*/
+
+
+/*case 13200000:*/
+/* BEGIN - DIF BPF register values from 132_quant.dat*/
+{13200000, DIF_BPF_COEFF01, 0xffff0000},
+{13200000, DIF_BPF_COEFF23, 0x0008fffc},
+{13200000, DIF_BPF_COEFF45, 0xffe00017},
+{13200000, DIF_BPF_COEFF67, 0x004cffb9},
+{13200000, DIF_BPF_COEFF89, 0xff7500a8},
+{13200000, DIF_BPF_COEFF1011, 0x00d1feb6},
+{13200000, DIF_BPF_COEFF1213, 0xfef90238},
+{13200000, DIF_BPF_COEFF1415, 0x0111fc91},
+{13200000, DIF_BPF_COEFF1617, 0xff3604df},
+{13200000, DIF_BPF_COEFF1819, 0x0012f99b},
+{13200000, DIF_BPF_COEFF2021, 0x012d07d2},
+{13200000, DIF_BPF_COEFF2223, 0xfd07f714},
+{13200000, DIF_BPF_COEFF2425, 0x0542097e},
+{13200000, DIF_BPF_COEFF2627, 0xf81ff6a4},
+{13200000, DIF_BPF_COEFF2829, 0x0a9a086e},
+{13200000, DIF_BPF_COEFF3031, 0xf2dbf94b},
+{13200000, DIF_BPF_COEFF3233, 0x0f380453},
+{13200000, DIF_BPF_COEFF3435, 0xef6cfe82},
+{13200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 132_quant.dat*/
+
+
+/*case 13300000:*/
+/* BEGIN - DIF BPF register values from 133_quant.dat*/
+{13300000, DIF_BPF_COEFF01, 0xffffffff},
+{13300000, DIF_BPF_COEFF23, 0x00080003},
+{13300000, DIF_BPF_COEFF45, 0xffde0001},
+{13300000, DIF_BPF_COEFF67, 0x0056ffe3},
+{13300000, DIF_BPF_COEFF89, 0xff570064},
+{13300000, DIF_BPF_COEFF1011, 0x0113ff10},
+{13300000, DIF_BPF_COEFF1213, 0xfe8201d2},
+{13300000, DIF_BPF_COEFF1415, 0x01cafcf0},
+{13300000, DIF_BPF_COEFF1617, 0xfe35049e},
+{13300000, DIF_BPF_COEFF1819, 0x0155f9a6},
+{13300000, DIF_BPF_COEFF2021, 0xffba080e},
+{13300000, DIF_BPF_COEFF2223, 0xfe8cf689},
+{13300000, DIF_BPF_COEFF2425, 0x03ce0a4e},
+{13300000, DIF_BPF_COEFF2627, 0xf961f5a8},
+{13300000, DIF_BPF_COEFF2829, 0x09a50971},
+{13300000, DIF_BPF_COEFF3031, 0xf379f869},
+{13300000, DIF_BPF_COEFF3233, 0x0eeb04ec},
+{13300000, DIF_BPF_COEFF3435, 0xef80fe4b},
+{13300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 133_quant.dat*/
+
+
+/*case 13400000:*/
+/* BEGIN - DIF BPF register values from 134_quant.dat*/
+{13400000, DIF_BPF_COEFF01, 0x0000fffe},
+{13400000, DIF_BPF_COEFF23, 0x0007000a},
+{13400000, DIF_BPF_COEFF45, 0xffe2ffec},
+{13400000, DIF_BPF_COEFF67, 0x00540012},
+{13400000, DIF_BPF_COEFF89, 0xff4e0015},
+{13400000, DIF_BPF_COEFF1011, 0x0137ff82},
+{13400000, DIF_BPF_COEFF1213, 0xfe2e0145},
+{13400000, DIF_BPF_COEFF1415, 0x0260fd86},
+{13400000, DIF_BPF_COEFF1617, 0xfd51041a},
+{13400000, DIF_BPF_COEFF1819, 0x0287f9fb},
+{13400000, DIF_BPF_COEFF2021, 0xfe4a0802},
+{13400000, DIF_BPF_COEFF2223, 0x001df63f},
+{13400000, DIF_BPF_COEFF2425, 0x02430aeb},
+{13400000, DIF_BPF_COEFF2627, 0xfabdf4ce},
+{13400000, DIF_BPF_COEFF2829, 0x08970a62},
+{13400000, DIF_BPF_COEFF3031, 0xf428f78f},
+{13400000, DIF_BPF_COEFF3233, 0x0e950584},
+{13400000, DIF_BPF_COEFF3435, 0xef97fe15},
+{13400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 134_quant.dat*/
+
+
+/*case 13500000:*/
+/* BEGIN - DIF BPF register values from 135_quant.dat*/
+{13500000, DIF_BPF_COEFF01, 0x0000fffd},
+{13500000, DIF_BPF_COEFF23, 0x0004000f},
+{13500000, DIF_BPF_COEFF45, 0xffeaffda},
+{13500000, DIF_BPF_COEFF67, 0x0046003d},
+{13500000, DIF_BPF_COEFF89, 0xff5affc4},
+{13500000, DIF_BPF_COEFF1011, 0x013b0000},
+{13500000, DIF_BPF_COEFF1213, 0xfe04009d},
+{13500000, DIF_BPF_COEFF1415, 0x02c8fe48},
+{13500000, DIF_BPF_COEFF1617, 0xfc99035a},
+{13500000, DIF_BPF_COEFF1819, 0x0397fa96},
+{13500000, DIF_BPF_COEFF2021, 0xfcec07ad},
+{13500000, DIF_BPF_COEFF2223, 0x01adf637},
+{13500000, DIF_BPF_COEFF2425, 0x00ac0b53},
+{13500000, DIF_BPF_COEFF2627, 0xfc2ef419},
+{13500000, DIF_BPF_COEFF2829, 0x07730b3e},
+{13500000, DIF_BPF_COEFF3031, 0xf4e9f6bd},
+{13500000, DIF_BPF_COEFF3233, 0x0e35061a},
+{13500000, DIF_BPF_COEFF3435, 0xefb1fddf},
+{13500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 135_quant.dat*/
+
+
+/*case 13600000:*/
+/* BEGIN - DIF BPF register values from 136_quant.dat*/
+{13600000, DIF_BPF_COEFF01, 0x0000fffd},
+{13600000, DIF_BPF_COEFF23, 0x00000012},
+{13600000, DIF_BPF_COEFF45, 0xfff6ffcd},
+{13600000, DIF_BPF_COEFF67, 0x002f0061},
+{13600000, DIF_BPF_COEFF89, 0xff7bff79},
+{13600000, DIF_BPF_COEFF1011, 0x011e007e},
+{13600000, DIF_BPF_COEFF1213, 0xfe08ffe8},
+{13600000, DIF_BPF_COEFF1415, 0x02f9ff28},
+{13600000, DIF_BPF_COEFF1617, 0xfc17026a},
+{13600000, DIF_BPF_COEFF1819, 0x0479fb70},
+{13600000, DIF_BPF_COEFF2021, 0xfbad0713},
+{13600000, DIF_BPF_COEFF2223, 0x032ff672},
+{13600000, DIF_BPF_COEFF2425, 0xff100b83},
+{13600000, DIF_BPF_COEFF2627, 0xfdaff38b},
+{13600000, DIF_BPF_COEFF2829, 0x063c0c04},
+{13600000, DIF_BPF_COEFF3031, 0xf5baf5f5},
+{13600000, DIF_BPF_COEFF3233, 0x0dcc06ae},
+{13600000, DIF_BPF_COEFF3435, 0xefcdfda8},
+{13600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 136_quant.dat*/
+
+
+/*case 13700000:*/
+/* BEGIN - DIF BPF register values from 137_quant.dat*/
+{13700000, DIF_BPF_COEFF01, 0x0000fffd},
+{13700000, DIF_BPF_COEFF23, 0xfffd0012},
+{13700000, DIF_BPF_COEFF45, 0x0004ffc8},
+{13700000, DIF_BPF_COEFF67, 0x00100078},
+{13700000, DIF_BPF_COEFF89, 0xffacff3e},
+{13700000, DIF_BPF_COEFF1011, 0x00e200f0},
+{13700000, DIF_BPF_COEFF1213, 0xfe39ff35},
+{13700000, DIF_BPF_COEFF1415, 0x02f10017},
+{13700000, DIF_BPF_COEFF1617, 0xfbd30156},
+{13700000, DIF_BPF_COEFF1819, 0x0521fc7f},
+{13700000, DIF_BPF_COEFF2021, 0xfa9c0638},
+{13700000, DIF_BPF_COEFF2223, 0x0499f6ee},
+{13700000, DIF_BPF_COEFF2425, 0xfd7a0b7c},
+{13700000, DIF_BPF_COEFF2627, 0xff39f325},
+{13700000, DIF_BPF_COEFF2829, 0x04f40cb3},
+{13700000, DIF_BPF_COEFF3031, 0xf69af537},
+{13700000, DIF_BPF_COEFF3233, 0x0d5a073f},
+{13700000, DIF_BPF_COEFF3435, 0xefecfd72},
+{13700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 137_quant.dat*/
+
+
+/*case 13800000:*/
+/* BEGIN - DIF BPF register values from 138_quant.dat*/
+{13800000, DIF_BPF_COEFF01, 0x0001fffe},
+{13800000, DIF_BPF_COEFF23, 0xfffa000e},
+{13800000, DIF_BPF_COEFF45, 0x0011ffcb},
+{13800000, DIF_BPF_COEFF67, 0xfff0007f},
+{13800000, DIF_BPF_COEFF89, 0xffe7ff19},
+{13800000, DIF_BPF_COEFF1011, 0x008f014a},
+{13800000, DIF_BPF_COEFF1213, 0xfe94fe93},
+{13800000, DIF_BPF_COEFF1415, 0x02b00105},
+{13800000, DIF_BPF_COEFF1617, 0xfbd3002f},
+{13800000, DIF_BPF_COEFF1819, 0x0585fdb7},
+{13800000, DIF_BPF_COEFF2021, 0xf9c10525},
+{13800000, DIF_BPF_COEFF2223, 0x05def7a8},
+{13800000, DIF_BPF_COEFF2425, 0xfbf20b3c},
+{13800000, DIF_BPF_COEFF2627, 0x00c7f2e9},
+{13800000, DIF_BPF_COEFF2829, 0x03a00d48},
+{13800000, DIF_BPF_COEFF3031, 0xf787f484},
+{13800000, DIF_BPF_COEFF3233, 0x0cdf07cd},
+{13800000, DIF_BPF_COEFF3435, 0xf00dfd3c},
+{13800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 138_quant.dat*/
+
+
+/*case 13900000:*/
+/* BEGIN - DIF BPF register values from 139_quant.dat*/
+{13900000, DIF_BPF_COEFF01, 0x00010000},
+{13900000, DIF_BPF_COEFF23, 0xfff80008},
+{13900000, DIF_BPF_COEFF45, 0x001bffd7},
+{13900000, DIF_BPF_COEFF67, 0xffd10076},
+{13900000, DIF_BPF_COEFF89, 0x0026ff0e},
+{13900000, DIF_BPF_COEFF1011, 0x002c0184},
+{13900000, DIF_BPF_COEFF1213, 0xff0ffe10},
+{13900000, DIF_BPF_COEFF1415, 0x023b01e0},
+{13900000, DIF_BPF_COEFF1617, 0xfc17ff06},
+{13900000, DIF_BPF_COEFF1819, 0x05a2ff09},
+{13900000, DIF_BPF_COEFF2021, 0xf92703e4},
+{13900000, DIF_BPF_COEFF2223, 0x06f4f89b},
+{13900000, DIF_BPF_COEFF2425, 0xfa820ac5},
+{13900000, DIF_BPF_COEFF2627, 0x0251f2d9},
+{13900000, DIF_BPF_COEFF2829, 0x02430dc3},
+{13900000, DIF_BPF_COEFF3031, 0xf881f3dc},
+{13900000, DIF_BPF_COEFF3233, 0x0c5c0859},
+{13900000, DIF_BPF_COEFF3435, 0xf031fd06},
+{13900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 139_quant.dat*/
+
+
+/*case 14000000:*/
+/* BEGIN - DIF BPF register values from 140_quant.dat*/
+{14000000, DIF_BPF_COEFF01, 0x00010001},
+{14000000, DIF_BPF_COEFF23, 0xfff80001},
+{14000000, DIF_BPF_COEFF45, 0x0021ffe8},
+{14000000, DIF_BPF_COEFF67, 0xffba005d},
+{14000000, DIF_BPF_COEFF89, 0x0060ff1f},
+{14000000, DIF_BPF_COEFF1011, 0xffc40198},
+{14000000, DIF_BPF_COEFF1213, 0xffa0fdb5},
+{14000000, DIF_BPF_COEFF1415, 0x019a029a},
+{14000000, DIF_BPF_COEFF1617, 0xfc99fdea},
+{14000000, DIF_BPF_COEFF1819, 0x05750067},
+{14000000, DIF_BPF_COEFF2021, 0xf8d4027f},
+{14000000, DIF_BPF_COEFF2223, 0x07d4f9c0},
+{14000000, DIF_BPF_COEFF2425, 0xf9320a1a},
+{14000000, DIF_BPF_COEFF2627, 0x03d2f2f3},
+{14000000, DIF_BPF_COEFF2829, 0x00df0e22},
+{14000000, DIF_BPF_COEFF3031, 0xf986f341},
+{14000000, DIF_BPF_COEFF3233, 0x0bd108e2},
+{14000000, DIF_BPF_COEFF3435, 0xf058fcd1},
+{14000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 140_quant.dat*/
+
+
+/*case 14100000:*/
+/* BEGIN - DIF BPF register values from 141_quant.dat*/
+{14100000, DIF_BPF_COEFF01, 0x00000002},
+{14100000, DIF_BPF_COEFF23, 0xfff9fffa},
+{14100000, DIF_BPF_COEFF45, 0x0021fffd},
+{14100000, DIF_BPF_COEFF67, 0xffac0038},
+{14100000, DIF_BPF_COEFF89, 0x008eff4a},
+{14100000, DIF_BPF_COEFF1011, 0xff630184},
+{14100000, DIF_BPF_COEFF1213, 0x003afd8b},
+{14100000, DIF_BPF_COEFF1415, 0x00da0326},
+{14100000, DIF_BPF_COEFF1617, 0xfd51fced},
+{14100000, DIF_BPF_COEFF1819, 0x050101c0},
+{14100000, DIF_BPF_COEFF2021, 0xf8cb0103},
+{14100000, DIF_BPF_COEFF2223, 0x0876fb10},
+{14100000, DIF_BPF_COEFF2425, 0xf80a093e},
+{14100000, DIF_BPF_COEFF2627, 0x0543f338},
+{14100000, DIF_BPF_COEFF2829, 0xff7a0e66},
+{14100000, DIF_BPF_COEFF3031, 0xfa94f2b2},
+{14100000, DIF_BPF_COEFF3233, 0x0b3f0967},
+{14100000, DIF_BPF_COEFF3435, 0xf081fc9b},
+{14100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 141_quant.dat*/
+
+
+/*case 14200000:*/
+/* BEGIN - DIF BPF register values from 142_quant.dat*/
+{14200000, DIF_BPF_COEFF01, 0x00000003},
+{14200000, DIF_BPF_COEFF23, 0xfffbfff3},
+{14200000, DIF_BPF_COEFF45, 0x001d0013},
+{14200000, DIF_BPF_COEFF67, 0xffaa000b},
+{14200000, DIF_BPF_COEFF89, 0x00aaff89},
+{14200000, DIF_BPF_COEFF1011, 0xff13014a},
+{14200000, DIF_BPF_COEFF1213, 0x00cefd95},
+{14200000, DIF_BPF_COEFF1415, 0x000a037b},
+{14200000, DIF_BPF_COEFF1617, 0xfe35fc1d},
+{14200000, DIF_BPF_COEFF1819, 0x044c0305},
+{14200000, DIF_BPF_COEFF2021, 0xf90cff7e},
+{14200000, DIF_BPF_COEFF2223, 0x08d5fc81},
+{14200000, DIF_BPF_COEFF2425, 0xf7100834},
+{14200000, DIF_BPF_COEFF2627, 0x069ff3a7},
+{14200000, DIF_BPF_COEFF2829, 0xfe160e8d},
+{14200000, DIF_BPF_COEFF3031, 0xfbaaf231},
+{14200000, DIF_BPF_COEFF3233, 0x0aa509e9},
+{14200000, DIF_BPF_COEFF3435, 0xf0adfc65},
+{14200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 142_quant.dat*/
+
+
+/*case 14300000:*/
+/* BEGIN - DIF BPF register values from 143_quant.dat*/
+{14300000, DIF_BPF_COEFF01, 0x00000003},
+{14300000, DIF_BPF_COEFF23, 0xffffffef},
+{14300000, DIF_BPF_COEFF45, 0x00140025},
+{14300000, DIF_BPF_COEFF67, 0xffb4ffdd},
+{14300000, DIF_BPF_COEFF89, 0x00b2ffd6},
+{14300000, DIF_BPF_COEFF1011, 0xfedb00f0},
+{14300000, DIF_BPF_COEFF1213, 0x0150fdd3},
+{14300000, DIF_BPF_COEFF1415, 0xff380391},
+{14300000, DIF_BPF_COEFF1617, 0xff36fb85},
+{14300000, DIF_BPF_COEFF1819, 0x035e0426},
+{14300000, DIF_BPF_COEFF2021, 0xf994fdfe},
+{14300000, DIF_BPF_COEFF2223, 0x08eefe0b},
+{14300000, DIF_BPF_COEFF2425, 0xf6490702},
+{14300000, DIF_BPF_COEFF2627, 0x07e1f43e},
+{14300000, DIF_BPF_COEFF2829, 0xfcb60e97},
+{14300000, DIF_BPF_COEFF3031, 0xfcc6f1be},
+{14300000, DIF_BPF_COEFF3233, 0x0a040a67},
+{14300000, DIF_BPF_COEFF3435, 0xf0dbfc30},
+{14300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 143_quant.dat*/
+
+
+/*case 14400000:*/
+/* BEGIN - DIF BPF register values from 144_quant.dat*/
+{14400000, DIF_BPF_COEFF01, 0x00000003},
+{14400000, DIF_BPF_COEFF23, 0x0002ffee},
+{14400000, DIF_BPF_COEFF45, 0x00070033},
+{14400000, DIF_BPF_COEFF67, 0xffc9ffb4},
+{14400000, DIF_BPF_COEFF89, 0x00a40027},
+{14400000, DIF_BPF_COEFF1011, 0xfec3007e},
+{14400000, DIF_BPF_COEFF1213, 0x01b4fe3f},
+{14400000, DIF_BPF_COEFF1415, 0xfe760369},
+{14400000, DIF_BPF_COEFF1617, 0x0044fb2e},
+{14400000, DIF_BPF_COEFF1819, 0x02450518},
+{14400000, DIF_BPF_COEFF2021, 0xfa5ffc90},
+{14400000, DIF_BPF_COEFF2223, 0x08c1ffa1},
+{14400000, DIF_BPF_COEFF2425, 0xf5bc05ae},
+{14400000, DIF_BPF_COEFF2627, 0x0902f4fc},
+{14400000, DIF_BPF_COEFF2829, 0xfb600e85},
+{14400000, DIF_BPF_COEFF3031, 0xfde7f15a},
+{14400000, DIF_BPF_COEFF3233, 0x095d0ae2},
+{14400000, DIF_BPF_COEFF3435, 0xf10cfbfb},
+{14400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 144_quant.dat*/
+
+
+/*case 14500000:*/
+/* BEGIN - DIF BPF register values from 145_quant.dat*/
+{14500000, DIF_BPF_COEFF01, 0xffff0002},
+{14500000, DIF_BPF_COEFF23, 0x0005ffef},
+{14500000, DIF_BPF_COEFF45, 0xfffa0038},
+{14500000, DIF_BPF_COEFF67, 0xffe5ff95},
+{14500000, DIF_BPF_COEFF89, 0x00820074},
+{14500000, DIF_BPF_COEFF1011, 0xfecc0000},
+{14500000, DIF_BPF_COEFF1213, 0x01f0fed0},
+{14500000, DIF_BPF_COEFF1415, 0xfdd20304},
+{14500000, DIF_BPF_COEFF1617, 0x014dfb1d},
+{14500000, DIF_BPF_COEFF1819, 0x010e05ce},
+{14500000, DIF_BPF_COEFF2021, 0xfb64fb41},
+{14500000, DIF_BPF_COEFF2223, 0x084e013b},
+{14500000, DIF_BPF_COEFF2425, 0xf569043e},
+{14500000, DIF_BPF_COEFF2627, 0x0a00f5dd},
+{14500000, DIF_BPF_COEFF2829, 0xfa150e55},
+{14500000, DIF_BPF_COEFF3031, 0xff0bf104},
+{14500000, DIF_BPF_COEFF3233, 0x08b00b59},
+{14500000, DIF_BPF_COEFF3435, 0xf13ffbc6},
+{14500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 145_quant.dat*/
+
+
+/*case 14600000:*/
+/* BEGIN - DIF BPF register values from 146_quant.dat*/
+{14600000, DIF_BPF_COEFF01, 0xffff0001},
+{14600000, DIF_BPF_COEFF23, 0x0008fff4},
+{14600000, DIF_BPF_COEFF45, 0xffed0035},
+{14600000, DIF_BPF_COEFF67, 0x0005ff83},
+{14600000, DIF_BPF_COEFF89, 0x005000b4},
+{14600000, DIF_BPF_COEFF1011, 0xfef6ff82},
+{14600000, DIF_BPF_COEFF1213, 0x01ffff7a},
+{14600000, DIF_BPF_COEFF1415, 0xfd580269},
+{14600000, DIF_BPF_COEFF1617, 0x0241fb53},
+{14600000, DIF_BPF_COEFF1819, 0xffca0640},
+{14600000, DIF_BPF_COEFF2021, 0xfc99fa1e},
+{14600000, DIF_BPF_COEFF2223, 0x079a02cb},
+{14600000, DIF_BPF_COEFF2425, 0xf55502ba},
+{14600000, DIF_BPF_COEFF2627, 0x0ad5f6e0},
+{14600000, DIF_BPF_COEFF2829, 0xf8d90e0a},
+{14600000, DIF_BPF_COEFF3031, 0x0031f0bd},
+{14600000, DIF_BPF_COEFF3233, 0x07fd0bcb},
+{14600000, DIF_BPF_COEFF3435, 0xf174fb91},
+{14600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 146_quant.dat*/
+
+
+/*case 14700000:*/
+/* BEGIN - DIF BPF register values from 147_quant.dat*/
+{14700000, DIF_BPF_COEFF01, 0xffffffff},
+{14700000, DIF_BPF_COEFF23, 0x0009fffb},
+{14700000, DIF_BPF_COEFF45, 0xffe4002a},
+{14700000, DIF_BPF_COEFF67, 0x0025ff82},
+{14700000, DIF_BPF_COEFF89, 0x001400e0},
+{14700000, DIF_BPF_COEFF1011, 0xff3cff10},
+{14700000, DIF_BPF_COEFF1213, 0x01e10030},
+{14700000, DIF_BPF_COEFF1415, 0xfd1201a4},
+{14700000, DIF_BPF_COEFF1617, 0x0311fbcd},
+{14700000, DIF_BPF_COEFF1819, 0xfe88066a},
+{14700000, DIF_BPF_COEFF2021, 0xfdf1f92f},
+{14700000, DIF_BPF_COEFF2223, 0x06aa0449},
+{14700000, DIF_BPF_COEFF2425, 0xf57e0128},
+{14700000, DIF_BPF_COEFF2627, 0x0b7ef801},
+{14700000, DIF_BPF_COEFF2829, 0xf7b00da2},
+{14700000, DIF_BPF_COEFF3031, 0x0156f086},
+{14700000, DIF_BPF_COEFF3233, 0x07450c39},
+{14700000, DIF_BPF_COEFF3435, 0xf1acfb5c},
+{14700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 147_quant.dat*/
+
+
+/*case 14800000:*/
+/* BEGIN - DIF BPF register values from 148_quant.dat*/
+{14800000, DIF_BPF_COEFF01, 0x0000fffe},
+{14800000, DIF_BPF_COEFF23, 0x00080002},
+{14800000, DIF_BPF_COEFF45, 0xffdf0019},
+{14800000, DIF_BPF_COEFF67, 0x003fff92},
+{14800000, DIF_BPF_COEFF89, 0xffd600f1},
+{14800000, DIF_BPF_COEFF1011, 0xff96feb6},
+{14800000, DIF_BPF_COEFF1213, 0x019700e1},
+{14800000, DIF_BPF_COEFF1415, 0xfd0500c2},
+{14800000, DIF_BPF_COEFF1617, 0x03b0fc84},
+{14800000, DIF_BPF_COEFF1819, 0xfd590649},
+{14800000, DIF_BPF_COEFF2021, 0xff5df87f},
+{14800000, DIF_BPF_COEFF2223, 0x058505aa},
+{14800000, DIF_BPF_COEFF2425, 0xf5e4ff91},
+{14800000, DIF_BPF_COEFF2627, 0x0bf9f93c},
+{14800000, DIF_BPF_COEFF2829, 0xf69d0d20},
+{14800000, DIF_BPF_COEFF3031, 0x0279f05e},
+{14800000, DIF_BPF_COEFF3233, 0x06880ca3},
+{14800000, DIF_BPF_COEFF3435, 0xf1e6fb28},
+{14800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 148_quant.dat*/
+
+
+/*case 14900000:*/
+/* BEGIN - DIF BPF register values from 149_quant.dat*/
+{14900000, DIF_BPF_COEFF01, 0x0000fffd},
+{14900000, DIF_BPF_COEFF23, 0x00060009},
+{14900000, DIF_BPF_COEFF45, 0xffdf0004},
+{14900000, DIF_BPF_COEFF67, 0x0051ffb0},
+{14900000, DIF_BPF_COEFF89, 0xff9d00e8},
+{14900000, DIF_BPF_COEFF1011, 0xfffcfe7c},
+{14900000, DIF_BPF_COEFF1213, 0x01280180},
+{14900000, DIF_BPF_COEFF1415, 0xfd32ffd2},
+{14900000, DIF_BPF_COEFF1617, 0x0413fd6e},
+{14900000, DIF_BPF_COEFF1819, 0xfc4d05df},
+{14900000, DIF_BPF_COEFF2021, 0x00d1f812},
+{14900000, DIF_BPF_COEFF2223, 0x043506e4},
+{14900000, DIF_BPF_COEFF2425, 0xf685fdfb},
+{14900000, DIF_BPF_COEFF2627, 0x0c43fa8d},
+{14900000, DIF_BPF_COEFF2829, 0xf5a10c83},
+{14900000, DIF_BPF_COEFF3031, 0x0399f046},
+{14900000, DIF_BPF_COEFF3233, 0x05c70d08},
+{14900000, DIF_BPF_COEFF3435, 0xf222faf3},
+{14900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 149_quant.dat*/
+
+
+/*case 15000000:*/
+/* BEGIN - DIF BPF register values from 150_quant.dat*/
+{15000000, DIF_BPF_COEFF01, 0x0000fffd},
+{15000000, DIF_BPF_COEFF23, 0x0003000f},
+{15000000, DIF_BPF_COEFF45, 0xffe5ffef},
+{15000000, DIF_BPF_COEFF67, 0x0057ffd9},
+{15000000, DIF_BPF_COEFF89, 0xff7000c4},
+{15000000, DIF_BPF_COEFF1011, 0x0062fe68},
+{15000000, DIF_BPF_COEFF1213, 0x009e01ff},
+{15000000, DIF_BPF_COEFF1415, 0xfd95fee6},
+{15000000, DIF_BPF_COEFF1617, 0x0435fe7d},
+{15000000, DIF_BPF_COEFF1819, 0xfb710530},
+{15000000, DIF_BPF_COEFF2021, 0x023cf7ee},
+{15000000, DIF_BPF_COEFF2223, 0x02c307ef},
+{15000000, DIF_BPF_COEFF2425, 0xf75efc70},
+{15000000, DIF_BPF_COEFF2627, 0x0c5cfbef},
+{15000000, DIF_BPF_COEFF2829, 0xf4c10bce},
+{15000000, DIF_BPF_COEFF3031, 0x04b3f03f},
+{15000000, DIF_BPF_COEFF3233, 0x05030d69},
+{15000000, DIF_BPF_COEFF3435, 0xf261fabf},
+{15000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 150_quant.dat*/
+
+
+/*case 15100000:*/
+/* BEGIN - DIF BPF register values from 151_quant.dat*/
+{15100000, DIF_BPF_COEFF01, 0x0000fffd},
+{15100000, DIF_BPF_COEFF23, 0xffff0012},
+{15100000, DIF_BPF_COEFF45, 0xffefffdc},
+{15100000, DIF_BPF_COEFF67, 0x00510006},
+{15100000, DIF_BPF_COEFF89, 0xff540089},
+{15100000, DIF_BPF_COEFF1011, 0x00befe7c},
+{15100000, DIF_BPF_COEFF1213, 0x00060253},
+{15100000, DIF_BPF_COEFF1415, 0xfe27fe0d},
+{15100000, DIF_BPF_COEFF1617, 0x0413ffa2},
+{15100000, DIF_BPF_COEFF1819, 0xfad10446},
+{15100000, DIF_BPF_COEFF2021, 0x0390f812},
+{15100000, DIF_BPF_COEFF2223, 0x013b08c3},
+{15100000, DIF_BPF_COEFF2425, 0xf868faf6},
+{15100000, DIF_BPF_COEFF2627, 0x0c43fd5f},
+{15100000, DIF_BPF_COEFF2829, 0xf3fd0b02},
+{15100000, DIF_BPF_COEFF3031, 0x05c7f046},
+{15100000, DIF_BPF_COEFF3233, 0x043b0dc4},
+{15100000, DIF_BPF_COEFF3435, 0xf2a1fa8b},
+{15100000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 151_quant.dat*/
+
+
+/*case 15200000:*/
+/* BEGIN - DIF BPF register values from 152_quant.dat*/
+{15200000, DIF_BPF_COEFF01, 0x0001fffe},
+{15200000, DIF_BPF_COEFF23, 0xfffc0012},
+{15200000, DIF_BPF_COEFF45, 0xfffbffce},
+{15200000, DIF_BPF_COEFF67, 0x003f0033},
+{15200000, DIF_BPF_COEFF89, 0xff4e003f},
+{15200000, DIF_BPF_COEFF1011, 0x0106feb6},
+{15200000, DIF_BPF_COEFF1213, 0xff6e0276},
+{15200000, DIF_BPF_COEFF1415, 0xfeddfd56},
+{15200000, DIF_BPF_COEFF1617, 0x03b000cc},
+{15200000, DIF_BPF_COEFF1819, 0xfa740329},
+{15200000, DIF_BPF_COEFF2021, 0x04bff87f},
+{15200000, DIF_BPF_COEFF2223, 0xffaa095d},
+{15200000, DIF_BPF_COEFF2425, 0xf99ef995},
+{15200000, DIF_BPF_COEFF2627, 0x0bf9fed8},
+{15200000, DIF_BPF_COEFF2829, 0xf3590a1f},
+{15200000, DIF_BPF_COEFF3031, 0x06d2f05e},
+{15200000, DIF_BPF_COEFF3233, 0x03700e1b},
+{15200000, DIF_BPF_COEFF3435, 0xf2e4fa58},
+{15200000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 152_quant.dat*/
+
+
+/*case 115300000:*/
+/* BEGIN - DIF BPF register values from 153_quant.dat*/
+{15300000, DIF_BPF_COEFF01, 0x0001ffff},
+{15300000, DIF_BPF_COEFF23, 0xfff9000f},
+{15300000, DIF_BPF_COEFF45, 0x0009ffc8},
+{15300000, DIF_BPF_COEFF67, 0x00250059},
+{15300000, DIF_BPF_COEFF89, 0xff5effee},
+{15300000, DIF_BPF_COEFF1011, 0x0132ff10},
+{15300000, DIF_BPF_COEFF1213, 0xfee30265},
+{15300000, DIF_BPF_COEFF1415, 0xffaafccf},
+{15300000, DIF_BPF_COEFF1617, 0x031101eb},
+{15300000, DIF_BPF_COEFF1819, 0xfa6001e8},
+{15300000, DIF_BPF_COEFF2021, 0x05bdf92f},
+{15300000, DIF_BPF_COEFF2223, 0xfe1b09b6},
+{15300000, DIF_BPF_COEFF2425, 0xfafaf852},
+{15300000, DIF_BPF_COEFF2627, 0x0b7e0055},
+{15300000, DIF_BPF_COEFF2829, 0xf2d50929},
+{15300000, DIF_BPF_COEFF3031, 0x07d3f086},
+{15300000, DIF_BPF_COEFF3233, 0x02a30e6c},
+{15300000, DIF_BPF_COEFF3435, 0xf329fa24},
+{15300000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 153_quant.dat*/
+
+
+/*case 115400000:*/
+/* BEGIN - DIF BPF register values from 154_quant.dat*/
+{15400000, DIF_BPF_COEFF01, 0x00010001},
+{15400000, DIF_BPF_COEFF23, 0xfff80009},
+{15400000, DIF_BPF_COEFF45, 0x0015ffca},
+{15400000, DIF_BPF_COEFF67, 0x00050074},
+{15400000, DIF_BPF_COEFF89, 0xff81ff9f},
+{15400000, DIF_BPF_COEFF1011, 0x013dff82},
+{15400000, DIF_BPF_COEFF1213, 0xfe710221},
+{15400000, DIF_BPF_COEFF1415, 0x007cfc80},
+{15400000, DIF_BPF_COEFF1617, 0x024102ed},
+{15400000, DIF_BPF_COEFF1819, 0xfa940090},
+{15400000, DIF_BPF_COEFF2021, 0x0680fa1e},
+{15400000, DIF_BPF_COEFF2223, 0xfc9b09cd},
+{15400000, DIF_BPF_COEFF2425, 0xfc73f736},
+{15400000, DIF_BPF_COEFF2627, 0x0ad501d0},
+{15400000, DIF_BPF_COEFF2829, 0xf2740820},
+{15400000, DIF_BPF_COEFF3031, 0x08c9f0bd},
+{15400000, DIF_BPF_COEFF3233, 0x01d40eb9},
+{15400000, DIF_BPF_COEFF3435, 0xf371f9f1},
+{15400000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 154_quant.dat*/
+
+
+/*case 115500000:*/
+/* BEGIN - DIF BPF register values from 155_quant.dat*/
+{15500000, DIF_BPF_COEFF01, 0x00000002},
+{15500000, DIF_BPF_COEFF23, 0xfff80002},
+{15500000, DIF_BPF_COEFF45, 0x001effd5},
+{15500000, DIF_BPF_COEFF67, 0xffe5007f},
+{15500000, DIF_BPF_COEFF89, 0xffb4ff5b},
+{15500000, DIF_BPF_COEFF1011, 0x01280000},
+{15500000, DIF_BPF_COEFF1213, 0xfe2401b0},
+{15500000, DIF_BPF_COEFF1415, 0x0146fc70},
+{15500000, DIF_BPF_COEFF1617, 0x014d03c6},
+{15500000, DIF_BPF_COEFF1819, 0xfb10ff32},
+{15500000, DIF_BPF_COEFF2021, 0x0701fb41},
+{15500000, DIF_BPF_COEFF2223, 0xfb3709a1},
+{15500000, DIF_BPF_COEFF2425, 0xfe00f644},
+{15500000, DIF_BPF_COEFF2627, 0x0a000345},
+{15500000, DIF_BPF_COEFF2829, 0xf2350708},
+{15500000, DIF_BPF_COEFF3031, 0x09b2f104},
+{15500000, DIF_BPF_COEFF3233, 0x01050eff},
+{15500000, DIF_BPF_COEFF3435, 0xf3baf9be},
+{15500000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 155_quant.dat*/
+
+
+/*case 115600000:*/
+/* BEGIN - DIF BPF register values from 156_quant.dat*/
+{15600000, DIF_BPF_COEFF01, 0x00000003},
+{15600000, DIF_BPF_COEFF23, 0xfff9fffb},
+{15600000, DIF_BPF_COEFF45, 0x0022ffe6},
+{15600000, DIF_BPF_COEFF67, 0xffc9007a},
+{15600000, DIF_BPF_COEFF89, 0xfff0ff29},
+{15600000, DIF_BPF_COEFF1011, 0x00f2007e},
+{15600000, DIF_BPF_COEFF1213, 0xfe01011b},
+{15600000, DIF_BPF_COEFF1415, 0x01f6fc9e},
+{15600000, DIF_BPF_COEFF1617, 0x00440467},
+{15600000, DIF_BPF_COEFF1819, 0xfbccfdde},
+{15600000, DIF_BPF_COEFF2021, 0x0738fc90},
+{15600000, DIF_BPF_COEFF2223, 0xf9f70934},
+{15600000, DIF_BPF_COEFF2425, 0xff99f582},
+{15600000, DIF_BPF_COEFF2627, 0x090204b0},
+{15600000, DIF_BPF_COEFF2829, 0xf21a05e1},
+{15600000, DIF_BPF_COEFF3031, 0x0a8df15a},
+{15600000, DIF_BPF_COEFF3233, 0x00340f41},
+{15600000, DIF_BPF_COEFF3435, 0xf405f98b},
+{15600000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 156_quant.dat*/
+
+
+/*case 115700000:*/
+/* BEGIN - DIF BPF register values from 157_quant.dat*/
+{15700000, DIF_BPF_COEFF01, 0x00000003},
+{15700000, DIF_BPF_COEFF23, 0xfffcfff4},
+{15700000, DIF_BPF_COEFF45, 0x0020fffa},
+{15700000, DIF_BPF_COEFF67, 0xffb40064},
+{15700000, DIF_BPF_COEFF89, 0x002fff11},
+{15700000, DIF_BPF_COEFF1011, 0x00a400f0},
+{15700000, DIF_BPF_COEFF1213, 0xfe0d006e},
+{15700000, DIF_BPF_COEFF1415, 0x0281fd09},
+{15700000, DIF_BPF_COEFF1617, 0xff3604c9},
+{15700000, DIF_BPF_COEFF1819, 0xfcbffca2},
+{15700000, DIF_BPF_COEFF2021, 0x0726fdfe},
+{15700000, DIF_BPF_COEFF2223, 0xf8e80888},
+{15700000, DIF_BPF_COEFF2425, 0x0134f4f3},
+{15700000, DIF_BPF_COEFF2627, 0x07e1060c},
+{15700000, DIF_BPF_COEFF2829, 0xf22304af},
+{15700000, DIF_BPF_COEFF3031, 0x0b59f1be},
+{15700000, DIF_BPF_COEFF3233, 0xff640f7d},
+{15700000, DIF_BPF_COEFF3435, 0xf452f959},
+{15700000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 157_quant.dat*/
+
+
+/*case 115800000:*/
+/* BEGIN - DIF BPF register values from 158_quant.dat*/
+{15800000, DIF_BPF_COEFF01, 0x00000003},
+{15800000, DIF_BPF_COEFF23, 0x0000fff0},
+{15800000, DIF_BPF_COEFF45, 0x001a0010},
+{15800000, DIF_BPF_COEFF67, 0xffaa0041},
+{15800000, DIF_BPF_COEFF89, 0x0067ff13},
+{15800000, DIF_BPF_COEFF1011, 0x0043014a},
+{15800000, DIF_BPF_COEFF1213, 0xfe46ffb9},
+{15800000, DIF_BPF_COEFF1415, 0x02dbfda8},
+{15800000, DIF_BPF_COEFF1617, 0xfe3504e5},
+{15800000, DIF_BPF_COEFF1819, 0xfddcfb8d},
+{15800000, DIF_BPF_COEFF2021, 0x06c9ff7e},
+{15800000, DIF_BPF_COEFF2223, 0xf81107a2},
+{15800000, DIF_BPF_COEFF2425, 0x02c9f49a},
+{15800000, DIF_BPF_COEFF2627, 0x069f0753},
+{15800000, DIF_BPF_COEFF2829, 0xf2500373},
+{15800000, DIF_BPF_COEFF3031, 0x0c14f231},
+{15800000, DIF_BPF_COEFF3233, 0xfe930fb3},
+{15800000, DIF_BPF_COEFF3435, 0xf4a1f927},
+{15800000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 158_quant.dat*/
+
+
+/*case 115900000:*/
+/* BEGIN - DIF BPF register values from 159_quant.dat*/
+{15900000, DIF_BPF_COEFF01, 0xffff0002},
+{15900000, DIF_BPF_COEFF23, 0x0003ffee},
+{15900000, DIF_BPF_COEFF45, 0x000f0023},
+{15900000, DIF_BPF_COEFF67, 0xffac0016},
+{15900000, DIF_BPF_COEFF89, 0x0093ff31},
+{15900000, DIF_BPF_COEFF1011, 0xffdc0184},
+{15900000, DIF_BPF_COEFF1213, 0xfea6ff09},
+{15900000, DIF_BPF_COEFF1415, 0x02fdfe70},
+{15900000, DIF_BPF_COEFF1617, 0xfd5104ba},
+{15900000, DIF_BPF_COEFF1819, 0xff15faac},
+{15900000, DIF_BPF_COEFF2021, 0x06270103},
+{15900000, DIF_BPF_COEFF2223, 0xf7780688},
+{15900000, DIF_BPF_COEFF2425, 0x044df479},
+{15900000, DIF_BPF_COEFF2627, 0x05430883},
+{15900000, DIF_BPF_COEFF2829, 0xf2a00231},
+{15900000, DIF_BPF_COEFF3031, 0x0cbef2b2},
+{15900000, DIF_BPF_COEFF3233, 0xfdc40fe3},
+{15900000, DIF_BPF_COEFF3435, 0xf4f2f8f5},
+{15900000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 159_quant.dat*/
+
+
+/*case 116000000:*/
+/* BEGIN - DIF BPF register values from 160_quant.dat*/
+{16000000, DIF_BPF_COEFF01, 0xffff0001},
+{16000000, DIF_BPF_COEFF23, 0x0006ffef},
+{16000000, DIF_BPF_COEFF45, 0x00020031},
+{16000000, DIF_BPF_COEFF67, 0xffbaffe8},
+{16000000, DIF_BPF_COEFF89, 0x00adff66},
+{16000000, DIF_BPF_COEFF1011, 0xff790198},
+{16000000, DIF_BPF_COEFF1213, 0xff26fe6e},
+{16000000, DIF_BPF_COEFF1415, 0x02e5ff55},
+{16000000, DIF_BPF_COEFF1617, 0xfc99044a},
+{16000000, DIF_BPF_COEFF1819, 0x005bfa09},
+{16000000, DIF_BPF_COEFF2021, 0x0545027f},
+{16000000, DIF_BPF_COEFF2223, 0xf7230541},
+{16000000, DIF_BPF_COEFF2425, 0x05b8f490},
+{16000000, DIF_BPF_COEFF2627, 0x03d20997},
+{16000000, DIF_BPF_COEFF2829, 0xf31300eb},
+{16000000, DIF_BPF_COEFF3031, 0x0d55f341},
+{16000000, DIF_BPF_COEFF3233, 0xfcf6100e},
+{16000000, DIF_BPF_COEFF3435, 0xf544f8c3},
+{16000000, DIF_BPF_COEFF36, 0x110d0000},
+/* END - DIF BPF register values from 160_quant.dat*/
+};
+
+#endif
diff --git a/drivers/media/video/cx231xx/cx231xx-dvb.c b/drivers/media/video/cx231xx/cx231xx-dvb.c
index 4ea3776b39fb..363aa6004221 100644
--- a/drivers/media/video/cx231xx/cx231xx-dvb.c
+++ b/drivers/media/video/cx231xx/cx231xx-dvb.c
@@ -28,7 +28,11 @@
#include <media/videobuf-vmalloc.h>
#include "xc5000.h"
-#include "dvb_dummy_fe.h"
+#include "s5h1432.h"
+#include "tda18271.h"
+#include "s5h1411.h"
+#include "lgdt3305.h"
+#include "mb86a20s.h"
MODULE_DESCRIPTION("driver for cx231xx based DVB cards");
MODULE_AUTHOR("Srinivasa Deevi <srinivasa.deevi@conexant.com>");
@@ -65,6 +69,88 @@ struct cx231xx_dvb {
struct dvb_net net;
};
+static struct s5h1432_config dvico_s5h1432_config = {
+ .output_mode = S5H1432_SERIAL_OUTPUT,
+ .gpio = S5H1432_GPIO_ON,
+ .qam_if = S5H1432_IF_4000,
+ .vsb_if = S5H1432_IF_4000,
+ .inversion = S5H1432_INVERSION_OFF,
+ .status_mode = S5H1432_DEMODLOCKING,
+ .mpeg_timing = S5H1432_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct tda18271_std_map cnxt_rde253s_tda18271_std_map = {
+ .dvbt_6 = { .if_freq = 4000, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .dvbt_7 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .dvbt_8 = { .if_freq = 4000, .agc_mode = 3, .std = 6,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_std_map mb86a20s_tda18271_config = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 7, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config cnxt_rde253s_tunerconfig = {
+ .std_map = &cnxt_rde253s_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static struct s5h1411_config tda18271_s5h1411_config = {
+ .output_mode = S5H1411_SERIAL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .vsb_if = S5H1411_IF_3250,
+ .qam_if = S5H1411_IF_4000,
+ .inversion = S5H1411_INVERSION_ON,
+ .status_mode = S5H1411_DEMODLOCKING,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+static struct s5h1411_config xc5000_s5h1411_config = {
+ .output_mode = S5H1411_SERIAL_OUTPUT,
+ .gpio = S5H1411_GPIO_OFF,
+ .vsb_if = S5H1411_IF_3250,
+ .qam_if = S5H1411_IF_3250,
+ .inversion = S5H1411_INVERSION_OFF,
+ .status_mode = S5H1411_DEMODLOCKING,
+ .mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct lgdt3305_config hcw_lgdt3305_config = {
+ .i2c_addr = 0x0e,
+ .mpeg_mode = LGDT3305_MPEG_SERIAL,
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .deny_i2c_rptr = 1,
+ .spectral_inversion = 1,
+ .qam_if_khz = 4000,
+ .vsb_if_khz = 3250,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x58, },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x58, },
+};
+
+static struct tda18271_config hcw_tda18271_config = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+};
+
+static const struct mb86a20s_config pv_mb86a20s_config = {
+ .demod_address = 0x10,
+ .is_serial = true,
+};
+
+static struct tda18271_config pv_tda18271_config = {
+ .std_map = &mb86a20s_tda18271_config,
+ .gate = TDA18271_GATE_DIGITAL,
+ .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
+};
+
static inline void print_err_status(struct cx231xx *dev, int packet, int status)
{
char *errmsg = "Unknown";
@@ -128,34 +214,79 @@ static inline int dvb_isoc_copy(struct cx231xx *dev, struct urb *urb)
continue;
}
- dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
- urb->iso_frame_desc[i].offset,
- urb->iso_frame_desc[i].actual_length);
+ dvb_dmx_swfilter(&dev->dvb->demux,
+ urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
}
return 0;
}
+static inline int dvb_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ /* Feed the transport payload into the kernel demux */
+ dvb_dmx_swfilter(&dev->dvb->demux,
+ urb->transfer_buffer, urb->actual_length);
+
+ return 0;
+}
+
static int start_streaming(struct cx231xx_dvb *dvb)
{
int rc;
struct cx231xx *dev = dvb->adapter.priv;
- usb_set_interface(dev->udev, 0, 1);
- rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
- if (rc < 0)
- return rc;
+ if (dev->USE_ISO) {
+ cx231xx_info("DVB transfer mode is ISO.\n");
+ mutex_lock(&dev->i2c_lock);
+ cx231xx_enable_i2c_port_3(dev, false);
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 4);
+ cx231xx_enable_i2c_port_3(dev, true);
+ mutex_unlock(&dev->i2c_lock);
+ rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ if (rc < 0)
+ return rc;
+ dev->mode_tv = 1;
+ return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
+ CX231XX_DVB_NUM_BUFS,
+ dev->ts1_mode.max_pkt_size,
+ dvb_isoc_copy);
+ } else {
+ cx231xx_info("DVB transfer mode is BULK.\n");
+ cx231xx_set_alt_setting(dev, INDEX_TS1, 0);
+ rc = cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ if (rc < 0)
+ return rc;
+ dev->mode_tv = 1;
+ return cx231xx_init_bulk(dev, CX231XX_DVB_MAX_PACKETS,
+ CX231XX_DVB_NUM_BUFS,
+ dev->ts1_mode.max_pkt_size,
+ dvb_bulk_copy);
+ }
- return cx231xx_init_isoc(dev, CX231XX_DVB_MAX_PACKETS,
- CX231XX_DVB_NUM_BUFS,
- CX231XX_DVB_MAX_PACKETSIZE, dvb_isoc_copy);
}
static int stop_streaming(struct cx231xx_dvb *dvb)
{
struct cx231xx *dev = dvb->adapter.priv;
- cx231xx_uninit_isoc(dev);
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
cx231xx_set_mode(dev, CX231XX_SUSPEND);
@@ -216,7 +347,11 @@ static int cx231xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
static struct xc5000_config cnxt_rde250_tunerconfig = {
.i2c_address = 0x61,
- .if_khz = 5380,
+ .if_khz = 4000,
+};
+static struct xc5000_config cnxt_rdu250_tunerconfig = {
+ .i2c_address = 0x61,
+ .if_khz = 3250,
};
/* ------------------------------------------------------------------ */
@@ -228,7 +363,7 @@ static int attach_xc5000(u8 addr, struct cx231xx *dev)
struct xc5000_config cfg;
memset(&cfg, 0, sizeof(cfg));
- cfg.i2c_adap = &dev->i2c_bus[1].i2c_adap;
+ cfg.i2c_adap = &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap;
cfg.i2c_addr = addr;
if (!dev->dvb->frontend) {
@@ -268,7 +403,6 @@ int cx231xx_set_analog_freq(struct cx231xx *dev, u32 freq)
/*params.audmode = ; */
/* Set the analog parameters to set the frequency */
- cx231xx_info("Setting Frequency for XC5000\n");
dops->set_analog_params(dev->dvb->frontend, &params);
}
@@ -445,19 +579,21 @@ static int dvb_init(struct cx231xx *dev)
dev->cx231xx_set_analog_freq = cx231xx_set_analog_freq;
dev->cx231xx_reset_analog_tuner = cx231xx_reset_analog_tuner;
+ mutex_lock(&dev->lock);
cx231xx_set_mode(dev, CX231XX_DIGITAL_MODE);
+ cx231xx_demod_reset(dev);
/* init frontend */
switch (dev->model) {
+ case CX231XX_BOARD_CNXT_CARRAERA:
case CX231XX_BOARD_CNXT_RDE_250:
- /* dev->dvb->frontend = dvb_attach(s5h1411_attach,
- &dvico_s5h1411_config,
- &dev->i2c_bus[1].i2c_adap); */
- dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
+ dev->dvb->frontend = dvb_attach(s5h1432_attach,
+ &dvico_s5h1432_config,
+ &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
if (dev->dvb->frontend == NULL) {
printk(DRIVER_NAME
- ": Failed to attach dummy front end\n");
+ ": Failed to attach s5h1432 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -466,20 +602,23 @@ static int dvb_init(struct cx231xx *dev)
dvb->frontend->callback = cx231xx_tuner_callback;
if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
- &dev->i2c_bus[1].i2c_adap,
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
&cnxt_rde250_tunerconfig)) {
result = -EINVAL;
goto out_free;
}
break;
+ case CX231XX_BOARD_CNXT_SHELBY:
case CX231XX_BOARD_CNXT_RDU_250:
- dev->dvb->frontend = dvb_attach(dvb_dummy_fe_ofdm_attach);
+ dev->dvb->frontend = dvb_attach(s5h1411_attach,
+ &xc5000_s5h1411_config,
+ &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
if (dev->dvb->frontend == NULL) {
printk(DRIVER_NAME
- ": Failed to attach dummy front end\n");
+ ": Failed to attach s5h1411 front end\n");
result = -EINVAL;
goto out_free;
}
@@ -488,12 +627,105 @@ static int dvb_init(struct cx231xx *dev)
dvb->frontend->callback = cx231xx_tuner_callback;
if (!dvb_attach(xc5000_attach, dev->dvb->frontend,
- &dev->i2c_bus[1].i2c_adap,
- &cnxt_rde250_tunerconfig)) {
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &cnxt_rdu250_tunerconfig)) {
result = -EINVAL;
goto out_free;
}
break;
+ case CX231XX_BOARD_CNXT_RDE_253S:
+
+ dev->dvb->frontend = dvb_attach(s5h1432_attach,
+ &dvico_s5h1432_config,
+ &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach s5h1432 front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+ 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &cnxt_rde253s_tunerconfig)) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case CX231XX_BOARD_CNXT_RDU_253S:
+
+ dev->dvb->frontend = dvb_attach(s5h1411_attach,
+ &tda18271_s5h1411_config,
+ &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach s5h1411 front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ if (!dvb_attach(tda18271_attach, dev->dvb->frontend,
+ 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &cnxt_rde253s_tunerconfig)) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case CX231XX_BOARD_HAUPPAUGE_EXETER:
+
+ printk(KERN_INFO "%s: looking for tuner / demod on i2c bus: %d\n",
+ __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
+
+ dev->dvb->frontend = dvb_attach(lgdt3305_attach,
+ &hcw_lgdt3305_config,
+ &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap);
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach LG3305 front end\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ dvb_attach(tda18271_attach, dev->dvb->frontend,
+ 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &hcw_tda18271_config);
+ break;
+
+ case CX231XX_BOARD_PV_PLAYTV_USB_HYBRID:
+
+ printk(KERN_INFO "%s: looking for demod on i2c bus: %d\n",
+ __func__, i2c_adapter_id(&dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap));
+
+ dev->dvb->frontend = dvb_attach(mb86a20s_attach,
+ &pv_mb86a20s_config,
+ &dev->i2c_bus[dev->board.demod_i2c_master].i2c_adap);
+
+ if (dev->dvb->frontend == NULL) {
+ printk(DRIVER_NAME
+ ": Failed to attach mb86a20s demod\n");
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* define general-purpose callback pointer */
+ dvb->frontend->callback = cx231xx_tuner_callback;
+
+ dvb_attach(tda18271_attach, dev->dvb->frontend,
+ 0x60, &dev->i2c_bus[dev->board.tuner_i2c_master].i2c_adap,
+ &pv_tda18271_config);
+ break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
@@ -513,15 +745,18 @@ static int dvb_init(struct cx231xx *dev)
if (result < 0)
goto out_free;
- cx231xx_set_mode(dev, CX231XX_SUSPEND);
+
printk(KERN_INFO "Successfully loaded cx231xx-dvb\n");
- return 0;
-out_free:
+ret:
cx231xx_set_mode(dev, CX231XX_SUSPEND);
+ mutex_unlock(&dev->lock);
+ return result;
+
+out_free:
kfree(dvb);
dev->dvb = NULL;
- return result;
+ goto ret;
}
static int dvb_fini(struct cx231xx *dev)
diff --git a/drivers/media/video/cx231xx/cx231xx-i2c.c b/drivers/media/video/cx231xx/cx231xx-i2c.c
index 58d9cc0867b9..835670623dfb 100644
--- a/drivers/media/video/cx231xx/cx231xx-i2c.c
+++ b/drivers/media/video/cx231xx/cx231xx-i2c.c
@@ -359,7 +359,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
if (num <= 0)
return 0;
-
+ mutex_lock(&dev->i2c_lock);
for (i = 0; i < num; i++) {
addr = msgs[i].addr >> 1;
@@ -372,6 +372,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = cx231xx_i2c_check_for_device(i2c_adap, &msgs[i]);
if (rc < 0) {
dprintk2(2, " no device\n");
+ mutex_unlock(&dev->i2c_lock);
return rc;
}
@@ -384,7 +385,7 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
}
} else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
msgs[i].addr == msgs[i + 1].addr
- && (msgs[i].len <= 2) && (bus->nr < 2)) {
+ && (msgs[i].len <= 2) && (bus->nr < 3)) {
/* read bytes */
rc = cx231xx_i2c_recv_bytes_with_saddr(i2c_adap,
&msgs[i],
@@ -407,10 +408,11 @@ static int cx231xx_i2c_xfer(struct i2c_adapter *i2c_adap,
if (i2c_debug >= 2)
printk("\n");
}
-
+ mutex_unlock(&dev->i2c_lock);
return num;
err:
dprintk2(2, " ERROR: %i\n", rc);
+ mutex_unlock(&dev->i2c_lock);
return rc;
}
@@ -507,9 +509,6 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus)
if (0 == bus->i2c_rc) {
if (i2c_scan)
cx231xx_do_i2c_scan(dev, &bus->i2c_client);
-
- /* Instantiate the IR receiver device, if present */
- cx231xx_register_i2c_ir(dev);
} else
cx231xx_warn("%s: i2c bus %d register FAILED\n",
dev->name, bus->nr);
diff --git a/drivers/media/video/cx231xx/cx231xx-input.c b/drivers/media/video/cx231xx/cx231xx-input.c
index fd099153b746..45e14cac4622 100644
--- a/drivers/media/video/cx231xx/cx231xx-input.c
+++ b/drivers/media/video/cx231xx/cx231xx-input.c
@@ -1,222 +1,112 @@
/*
- handle cx231xx IR remotes via linux kernel input layer.
-
- Copyright (C) 2008 <srinivasa.deevi at conexant dot com>
- Based on em28xx driver
-
- < This is a place holder for IR now.>
-
- 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
+ * cx231xx IR glue driver
+ *
+ * Copyright (C) 2010 Mauro Carvalho Chehab <mchehab@redhat.com>
+ *
+ * Polaris (cx231xx) has its support for IR's with a design close to MCE.
+ * however, a few designs are using an external I2C chip for IR, instead
+ * of using the one provided by the chip.
+ * This driver provides support for those extra devices
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation version 2.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
*/
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/interrupt.h>
-#include <linux/input.h>
+#include "cx231xx.h"
#include <linux/usb.h>
#include <linux/slab.h>
-#include "cx231xx.h"
+#define MODULE_NAME "cx231xx-input"
-static unsigned int ir_debug;
-module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
-
-#define MODULE_NAME "cx231xx"
-
-#define i2cdprintk(fmt, arg...) \
- if (ir_debug) { \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
- }
-
-#define dprintk(fmt, arg...) \
- if (ir_debug) { \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg); \
- }
-
-/**********************************************************
- Polling structure used by cx231xx IR's
- **********************************************************/
-
-struct cx231xx_ir_poll_result {
- unsigned int toggle_bit:1;
- unsigned int read_count:7;
- u8 rc_address;
- u8 rc_data[4];
-};
-
-struct cx231xx_IR {
- struct cx231xx *dev;
- struct input_dev *input;
- char name[32];
- char phys[32];
-
- /* poll external decoder */
- int polling;
- struct work_struct work;
- struct timer_list timer;
- unsigned int last_readcount;
-
- int (*get_key) (struct cx231xx_IR *, struct cx231xx_ir_poll_result *);
-};
-
-/**********************************************************
- Polling code for cx231xx
- **********************************************************/
-
-static void cx231xx_ir_handle_key(struct cx231xx_IR *ir)
+static int get_key_isdbt(struct IR_i2c *ir, u32 *ir_key,
+ u32 *ir_raw)
{
- int result;
- struct cx231xx_ir_poll_result poll_result;
-
- /* read the registers containing the IR status */
- result = ir->get_key(ir, &poll_result);
- if (result < 0) {
- dprintk("ir->get_key() failed %d\n", result);
- return;
- }
-
- dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x\n",
- poll_result.toggle_bit, poll_result.read_count,
- ir->last_readcount, poll_result.rc_data[0]);
-
- if (poll_result.read_count > 0 &&
- poll_result.read_count != ir->last_readcount)
- ir_keydown(ir->input,
- poll_result.rc_data[0],
- poll_result.toggle_bit);
-
- if (ir->dev->chip_id == CHIP_ID_EM2874)
- /* The em2874 clears the readcount field every time the
- register is read. The em2860/2880 datasheet says that it
- is supposed to clear the readcount, but it doesn't. So with
- the em2874, we are looking for a non-zero read count as
- opposed to a readcount that is incrementing */
- ir->last_readcount = 0;
- else
- ir->last_readcount = poll_result.read_count;
-
- }
-}
+ u8 cmd, scancode;
-static void ir_timer(unsigned long data)
-{
- struct cx231xx_IR *ir = (struct cx231xx_IR *)data;
+ dev_dbg(&ir->rc->input_dev->dev, "%s\n", __func__);
- schedule_work(&ir->work);
-}
-
-static void cx231xx_ir_work(struct work_struct *work)
-{
- struct cx231xx_IR *ir = container_of(work, struct cx231xx_IR, work);
+ /* poll IR chip */
+ if (1 != i2c_master_recv(ir->c, &cmd, 1))
+ return -EIO;
- cx231xx_ir_handle_key(ir);
- mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
-}
+ /* it seems that 0xFE indicates that a button is still hold
+ down, while 0xff indicates that no button is hold
+ down. 0xfe sequences are sometimes interrupted by 0xFF */
-void cx231xx_ir_start(struct cx231xx_IR *ir)
-{
- setup_timer(&ir->timer, ir_timer, (unsigned long)ir);
- INIT_WORK(&ir->work, cx231xx_ir_work);
- schedule_work(&ir->work);
-}
+ if (cmd == 0xff)
+ return 0;
-static void cx231xx_ir_stop(struct cx231xx_IR *ir)
-{
- del_timer_sync(&ir->timer);
- flush_scheduled_work();
+ scancode =
+ ((cmd & 0x01) ? 0x80 : 0) |
+ ((cmd & 0x02) ? 0x40 : 0) |
+ ((cmd & 0x04) ? 0x20 : 0) |
+ ((cmd & 0x08) ? 0x10 : 0) |
+ ((cmd & 0x10) ? 0x08 : 0) |
+ ((cmd & 0x20) ? 0x04 : 0) |
+ ((cmd & 0x40) ? 0x02 : 0) |
+ ((cmd & 0x80) ? 0x01 : 0);
+
+ dev_dbg(&ir->rc->input_dev->dev, "cmd %02x, scan = %02x\n",
+ cmd, scancode);
+
+ *ir_key = scancode;
+ *ir_raw = scancode;
+ return 1;
}
int cx231xx_ir_init(struct cx231xx *dev)
{
- struct cx231xx_IR *ir;
- struct input_dev *input_dev;
- u8 ir_config;
- int err = -ENOMEM;
-
- if (dev->board.ir_codes == NULL) {
- /* No remote control support */
- return 0;
- }
-
- ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
- goto err_out_free;
-
- ir->input = input_dev;
-
- /* Setup the proper handler based on the chip */
- switch (dev->chip_id) {
- default:
- printk("Unrecognized cx231xx chip id: IR not supported\n");
- goto err_out_free;
- }
-
- /* This is how often we ask the chip for IR information */
- ir->polling = 100; /* ms */
-
- /* init input device */
- snprintf(ir->name, sizeof(ir->name), "cx231xx IR (%s)", dev->name);
-
- usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
- strlcat(ir->phys, "/input0", sizeof(ir->phys));
-
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_USB;
- input_dev->id.version = 1;
- input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
- input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
-
- input_dev->dev.parent = &dev->udev->dev;
- /* record handles to ourself */
- ir->dev = dev;
- dev->ir = ir;
-
- cx231xx_ir_start(ir);
-
- /* all done */
- err = __ir_input_register(ir->input, dev->board.ir_codes,
- NULL, MODULE_NAME);
- if (err)
- goto err_out_stop;
+ struct i2c_board_info info;
+ u8 ir_i2c_bus;
+
+ dev_dbg(&dev->udev->dev, "%s\n", __func__);
+
+ /* Only initialize if a rc keycode map is defined */
+ if (!cx231xx_boards[dev->model].rc_map_name)
+ return -ENODEV;
+
+ request_module("ir-kbd-i2c");
+
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ memset(&dev->init_data, 0, sizeof(dev->init_data));
+ dev->init_data.rc_dev = rc_allocate_device();
+ if (!dev->init_data.rc_dev)
+ return -ENOMEM;
+
+ dev->init_data.name = cx231xx_boards[dev->model].name;
+
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ info.platform_data = &dev->init_data;
+
+ /*
+ * Board-dependent values
+ *
+ * For now, there's just one type of hardware design using
+ * an i2c device.
+ */
+ dev->init_data.get_key = get_key_isdbt;
+ dev->init_data.ir_codes = cx231xx_boards[dev->model].rc_map_name;
+ /* The i2c micro-controller only outputs the cmd part of NEC protocol */
+ dev->init_data.rc_dev->scanmask = 0xff;
+ dev->init_data.rc_dev->driver_name = "cx231xx";
+ dev->init_data.type = RC_TYPE_NEC;
+ info.addr = 0x30;
+
+ /* Load and bind ir-kbd-i2c */
+ ir_i2c_bus = cx231xx_boards[dev->model].ir_i2c_master;
+ dev_dbg(&dev->udev->dev, "Trying to bind ir at bus %d, addr 0x%02x\n",
+ ir_i2c_bus, info.addr);
+ i2c_new_device(&dev->i2c_bus[ir_i2c_bus].i2c_adap, &info);
return 0;
-err_out_stop:
- cx231xx_ir_stop(ir);
- dev->ir = NULL;
-err_out_free:
- kfree(ir);
- return err;
}
-int cx231xx_ir_fini(struct cx231xx *dev)
+void cx231xx_ir_exit(struct cx231xx *dev)
{
- struct cx231xx_IR *ir = dev->ir;
-
- /* skip detach on non attached boards */
- if (!ir)
- return 0;
-
- cx231xx_ir_stop(ir);
- ir_input_unregister(ir->input);
- kfree(ir);
-
- /* done */
- dev->ir = NULL;
- return 0;
}
diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.c b/drivers/media/video/cx231xx/cx231xx-vbi.c
index 689c5e25776c..1d914488dbb3 100644
--- a/drivers/media/video/cx231xx/cx231xx-vbi.c
+++ b/drivers/media/video/cx231xx/cx231xx-vbi.c
@@ -102,7 +102,7 @@ static inline int cx231xx_isoc_vbi_copy(struct cx231xx *dev, struct urb *urb)
return 0;
}
- buf = dev->vbi_mode.isoc_ctl.buf;
+ buf = dev->vbi_mode.bulk_ctl.buf;
/* get buffer pointer and length */
p_buffer = urb->transfer_buffer;
@@ -180,7 +180,7 @@ vbi_buffer_setup(struct videobuf_queue *vq, unsigned int *count,
height = ((dev->norm & V4L2_STD_625_50) ?
PAL_VBI_LINES : NTSC_VBI_LINES);
- *size = (dev->width * height * 2);
+ *size = (dev->width * height * 2 * 2);
if (0 == *count)
*count = CX231XX_DEF_VBI_BUF;
@@ -209,8 +209,8 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
VIDEOBUF_ACTIVE, it won't be, though.
*/
spin_lock_irqsave(&dev->vbi_mode.slock, flags);
- if (dev->vbi_mode.isoc_ctl.buf == buf)
- dev->vbi_mode.isoc_ctl.buf = NULL;
+ if (dev->vbi_mode.bulk_ctl.buf == buf)
+ dev->vbi_mode.bulk_ctl.buf = NULL;
spin_unlock_irqrestore(&dev->vbi_mode.slock, flags);
videobuf_vmalloc_free(&buf->vb);
@@ -230,7 +230,7 @@ vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
height = ((dev->norm & V4L2_STD_625_50) ?
PAL_VBI_LINES : NTSC_VBI_LINES);
- buf->vb.size = ((dev->width << 1) * height);
+ buf->vb.size = ((dev->width << 1) * height * 2);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
@@ -246,7 +246,7 @@ vbi_buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
goto fail;
}
- if (!dev->vbi_mode.isoc_ctl.num_bufs)
+ if (!dev->vbi_mode.bulk_ctl.num_bufs)
urb_init = 1;
if (urb_init) {
@@ -328,7 +328,7 @@ static void cx231xx_irq_vbi_callback(struct urb *urb)
/* Copy data from URB */
spin_lock(&dev->vbi_mode.slock);
- rc = dev->vbi_mode.isoc_ctl.isoc_copy(dev, urb);
+ rc = dev->vbi_mode.bulk_ctl.bulk_copy(dev, urb);
spin_unlock(&dev->vbi_mode.slock);
/* Reset status */
@@ -351,34 +351,34 @@ void cx231xx_uninit_vbi_isoc(struct cx231xx *dev)
cx231xx_info(DRIVER_NAME "cx231xx: called cx231xx_uninit_vbi_isoc\n");
- dev->vbi_mode.isoc_ctl.nfields = -1;
- for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
- urb = dev->vbi_mode.isoc_ctl.urb[i];
+ dev->vbi_mode.bulk_ctl.nfields = -1;
+ for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
+ urb = dev->vbi_mode.bulk_ctl.urb[i];
if (urb) {
if (!irqs_disabled())
usb_kill_urb(urb);
else
usb_unlink_urb(urb);
- if (dev->vbi_mode.isoc_ctl.transfer_buffer[i]) {
+ if (dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
- kfree(dev->vbi_mode.isoc_ctl.
+ kfree(dev->vbi_mode.bulk_ctl.
transfer_buffer[i]);
- dev->vbi_mode.isoc_ctl.transfer_buffer[i] =
+ dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
NULL;
}
usb_free_urb(urb);
- dev->vbi_mode.isoc_ctl.urb[i] = NULL;
+ dev->vbi_mode.bulk_ctl.urb[i] = NULL;
}
- dev->vbi_mode.isoc_ctl.transfer_buffer[i] = NULL;
+ dev->vbi_mode.bulk_ctl.transfer_buffer[i] = NULL;
}
- kfree(dev->vbi_mode.isoc_ctl.urb);
- kfree(dev->vbi_mode.isoc_ctl.transfer_buffer);
+ kfree(dev->vbi_mode.bulk_ctl.urb);
+ kfree(dev->vbi_mode.bulk_ctl.transfer_buffer);
- dev->vbi_mode.isoc_ctl.urb = NULL;
- dev->vbi_mode.isoc_ctl.transfer_buffer = NULL;
- dev->vbi_mode.isoc_ctl.num_bufs = 0;
+ dev->vbi_mode.bulk_ctl.urb = NULL;
+ dev->vbi_mode.bulk_ctl.transfer_buffer = NULL;
+ dev->vbi_mode.bulk_ctl.num_bufs = 0;
cx231xx_capture_start(dev, 0, Vbi);
}
@@ -389,7 +389,7 @@ EXPORT_SYMBOL_GPL(cx231xx_uninit_vbi_isoc);
*/
int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
int num_bufs, int max_pkt_size,
- int (*isoc_copy) (struct cx231xx *dev,
+ int (*bulk_copy) (struct cx231xx *dev,
struct urb *urb))
{
struct cx231xx_dmaqueue *dma_q = &dev->vbi_mode.vidq;
@@ -408,8 +408,8 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
usb_rcvbulkpipe(dev->udev,
dev->vbi_mode.end_point_addr));
- dev->vbi_mode.isoc_ctl.isoc_copy = isoc_copy;
- dev->vbi_mode.isoc_ctl.num_bufs = num_bufs;
+ dev->vbi_mode.bulk_ctl.bulk_copy = bulk_copy;
+ dev->vbi_mode.bulk_ctl.num_bufs = num_bufs;
dma_q->pos = 0;
dma_q->is_partial_line = 0;
dma_q->last_sav = 0;
@@ -421,42 +421,42 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
for (i = 0; i < 8; i++)
dma_q->partial_buf[i] = 0;
- dev->vbi_mode.isoc_ctl.urb = kzalloc(sizeof(void *) * num_bufs,
+ dev->vbi_mode.bulk_ctl.urb = kzalloc(sizeof(void *) * num_bufs,
GFP_KERNEL);
- if (!dev->vbi_mode.isoc_ctl.urb) {
+ if (!dev->vbi_mode.bulk_ctl.urb) {
cx231xx_errdev("cannot alloc memory for usb buffers\n");
return -ENOMEM;
}
- dev->vbi_mode.isoc_ctl.transfer_buffer =
+ dev->vbi_mode.bulk_ctl.transfer_buffer =
kzalloc(sizeof(void *) * num_bufs, GFP_KERNEL);
- if (!dev->vbi_mode.isoc_ctl.transfer_buffer) {
+ if (!dev->vbi_mode.bulk_ctl.transfer_buffer) {
cx231xx_errdev("cannot allocate memory for usbtransfer\n");
- kfree(dev->vbi_mode.isoc_ctl.urb);
+ kfree(dev->vbi_mode.bulk_ctl.urb);
return -ENOMEM;
}
- dev->vbi_mode.isoc_ctl.max_pkt_size = max_pkt_size;
- dev->vbi_mode.isoc_ctl.buf = NULL;
+ dev->vbi_mode.bulk_ctl.max_pkt_size = max_pkt_size;
+ dev->vbi_mode.bulk_ctl.buf = NULL;
- sb_size = max_packets * dev->vbi_mode.isoc_ctl.max_pkt_size;
+ sb_size = max_packets * dev->vbi_mode.bulk_ctl.max_pkt_size;
/* allocate urbs and transfer buffers */
- for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
+ for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
urb = usb_alloc_urb(0, GFP_KERNEL);
if (!urb) {
cx231xx_err(DRIVER_NAME
- ": cannot alloc isoc_ctl.urb %i\n", i);
+ ": cannot alloc bulk_ctl.urb %i\n", i);
cx231xx_uninit_vbi_isoc(dev);
return -ENOMEM;
}
- dev->vbi_mode.isoc_ctl.urb[i] = urb;
+ dev->vbi_mode.bulk_ctl.urb[i] = urb;
urb->transfer_flags = 0;
- dev->vbi_mode.isoc_ctl.transfer_buffer[i] =
+ dev->vbi_mode.bulk_ctl.transfer_buffer[i] =
kzalloc(sb_size, GFP_KERNEL);
- if (!dev->vbi_mode.isoc_ctl.transfer_buffer[i]) {
+ if (!dev->vbi_mode.bulk_ctl.transfer_buffer[i]) {
cx231xx_err(DRIVER_NAME
": unable to allocate %i bytes for transfer"
" buffer %i%s\n", sb_size, i,
@@ -467,15 +467,15 @@ int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
pipe = usb_rcvbulkpipe(dev->udev, dev->vbi_mode.end_point_addr);
usb_fill_bulk_urb(urb, dev->udev, pipe,
- dev->vbi_mode.isoc_ctl.transfer_buffer[i],
+ dev->vbi_mode.bulk_ctl.transfer_buffer[i],
sb_size, cx231xx_irq_vbi_callback, dma_q);
}
init_waitqueue_head(&dma_q->wq);
/* submit urbs and enables IRQ */
- for (i = 0; i < dev->vbi_mode.isoc_ctl.num_bufs; i++) {
- rc = usb_submit_urb(dev->vbi_mode.isoc_ctl.urb[i], GFP_ATOMIC);
+ for (i = 0; i < dev->vbi_mode.bulk_ctl.num_bufs; i++) {
+ rc = usb_submit_urb(dev->vbi_mode.bulk_ctl.urb[i], GFP_ATOMIC);
if (rc) {
cx231xx_err(DRIVER_NAME
": submit of urb %i failed (error=%i)\n", i,
@@ -536,7 +536,7 @@ static inline void vbi_buffer_filled(struct cx231xx *dev,
buf->vb.field_count++;
do_gettimeofday(&buf->vb.ts);
- dev->vbi_mode.isoc_ctl.buf = NULL;
+ dev->vbi_mode.bulk_ctl.buf = NULL;
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
@@ -549,11 +549,16 @@ u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
struct cx231xx_buffer *buf;
u32 _line_size = dev->width * 2;
- if (dma_q->current_field != field_number)
+ if (dma_q->current_field == -1) {
+ /* Just starting up */
cx231xx_reset_vbi_buffer(dev, dma_q);
+ }
+
+ if (dma_q->current_field != field_number)
+ dma_q->lines_completed = 0;
/* get the buffer pointer */
- buf = dev->vbi_mode.isoc_ctl.buf;
+ buf = dev->vbi_mode.bulk_ctl.buf;
/* Remember the field number for next time */
dma_q->current_field = field_number;
@@ -597,8 +602,8 @@ u32 cx231xx_copy_vbi_line(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
vbi_buffer_filled(dev, dma_q, buf);
dma_q->pos = 0;
- buf = NULL;
dma_q->lines_completed = 0;
+ cx231xx_reset_vbi_buffer(dev, dma_q);
}
}
@@ -618,7 +623,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
if (list_empty(&dma_q->active)) {
cx231xx_err(DRIVER_NAME ": No active queue to serve\n");
- dev->vbi_mode.isoc_ctl.buf = NULL;
+ dev->vbi_mode.bulk_ctl.buf = NULL;
*buf = NULL;
return;
}
@@ -630,7 +635,7 @@ static inline void get_next_vbi_buf(struct cx231xx_dmaqueue *dma_q,
outp = videobuf_to_vmalloc(&(*buf)->vb);
memset(outp, 0, (*buf)->vb.size);
- dev->vbi_mode.isoc_ctl.buf = *buf;
+ dev->vbi_mode.bulk_ctl.buf = *buf;
return;
}
@@ -640,7 +645,7 @@ void cx231xx_reset_vbi_buffer(struct cx231xx *dev,
{
struct cx231xx_buffer *buf;
- buf = dev->vbi_mode.isoc_ctl.buf;
+ buf = dev->vbi_mode.bulk_ctl.buf;
if (buf == NULL) {
/* first try to get the buffer */
@@ -664,7 +669,7 @@ int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
void *startwrite;
int offset, lencopy;
- buf = dev->vbi_mode.isoc_ctl.buf;
+ buf = dev->vbi_mode.bulk_ctl.buf;
if (buf == NULL)
return -EINVAL;
@@ -679,6 +684,11 @@ int cx231xx_do_vbi_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
offset = (dma_q->lines_completed * _line_size) +
current_line_bytes_copied;
+ if (dma_q->current_field == 2) {
+ /* Populate the second half of the frame */
+ offset += (dev->width * 2 * dma_q->lines_per_field);
+ }
+
/* prepare destination address */
startwrite = p_out_buffer + offset;
@@ -697,5 +707,8 @@ u8 cx231xx_is_vbi_buffer_done(struct cx231xx *dev,
height = ((dev->norm & V4L2_STD_625_50) ?
PAL_VBI_LINES : NTSC_VBI_LINES);
- return (dma_q->lines_completed == height) ? 1 : 0;
+ if (dma_q->lines_completed == height && dma_q->current_field == 2)
+ return 1;
+ else
+ return 0;
}
diff --git a/drivers/media/video/cx231xx/cx231xx-vbi.h b/drivers/media/video/cx231xx/cx231xx-vbi.h
index 89c7fe80b261..16c7d20a22a4 100644
--- a/drivers/media/video/cx231xx/cx231xx-vbi.h
+++ b/drivers/media/video/cx231xx/cx231xx-vbi.h
@@ -41,7 +41,7 @@ extern struct videobuf_queue_ops cx231xx_vbi_qops;
/* stream functions */
int cx231xx_init_vbi_isoc(struct cx231xx *dev, int max_packets,
int num_bufs, int max_pkt_size,
- int (*isoc_copy) (struct cx231xx *dev,
+ int (*bulk_copy) (struct cx231xx *dev,
struct urb *urb));
void cx231xx_uninit_vbi_isoc(struct cx231xx *dev);
diff --git a/drivers/media/video/cx231xx/cx231xx-video.c b/drivers/media/video/cx231xx/cx231xx-video.c
index 2782709b263f..7e3e8c4f19b7 100644
--- a/drivers/media/video/cx231xx/cx231xx-video.c
+++ b/drivers/media/video/cx231xx/cx231xx-video.c
@@ -237,7 +237,10 @@ static inline void buffer_filled(struct cx231xx *dev,
buf->vb.field_count++;
do_gettimeofday(&buf->vb.ts);
- dev->video_mode.isoc_ctl.buf = NULL;
+ if (dev->USE_ISO)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ else
+ dev->video_mode.bulk_ctl.buf = NULL;
list_del(&buf->vb.queue);
wake_up(&buf->vb.done);
@@ -295,7 +298,10 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
if (list_empty(&dma_q->active)) {
cx231xx_isocdbg("No active queue to serve\n");
- dev->video_mode.isoc_ctl.buf = NULL;
+ if (dev->USE_ISO)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ else
+ dev->video_mode.bulk_ctl.buf = NULL;
*buf = NULL;
return;
}
@@ -307,7 +313,10 @@ static inline void get_next_buf(struct cx231xx_dmaqueue *dma_q,
outp = videobuf_to_vmalloc(&(*buf)->vb);
memset(outp, 0, (*buf)->vb.size);
- dev->video_mode.isoc_ctl.buf = *buf;
+ if (dev->USE_ISO)
+ dev->video_mode.isoc_ctl.buf = *buf;
+ else
+ dev->video_mode.bulk_ctl.buf = *buf;
return;
}
@@ -418,6 +427,93 @@ static inline int cx231xx_isoc_copy(struct cx231xx *dev, struct urb *urb)
return rc;
}
+static inline int cx231xx_bulk_copy(struct cx231xx *dev, struct urb *urb)
+{
+ struct cx231xx_buffer *buf;
+ struct cx231xx_dmaqueue *dma_q = urb->context;
+ unsigned char *outp = NULL;
+ int rc = 1;
+ unsigned char *p_buffer;
+ u32 bytes_parsed = 0, buffer_size = 0;
+ u8 sav_eav = 0;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->video_mode.bulk_ctl.buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ if (1) {
+
+ /* get buffer pointer and length */
+ p_buffer = urb->transfer_buffer;
+ buffer_size = urb->actual_length;
+ bytes_parsed = 0;
+
+ if (dma_q->is_partial_line) {
+ /* Handle the case of a partial line */
+ sav_eav = dma_q->last_sav;
+ } else {
+ /* Check for a SAV/EAV overlapping
+ the buffer boundary */
+ sav_eav =
+ cx231xx_find_boundary_SAV_EAV(p_buffer,
+ dma_q->partial_buf,
+ &bytes_parsed);
+ }
+
+ sav_eav &= 0xF0;
+ /* Get the first line if we have some portion of an SAV/EAV from
+ the last buffer or a partial line */
+ if (sav_eav) {
+ bytes_parsed += cx231xx_get_video_line(dev, dma_q,
+ sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed);/* buf size */
+ }
+
+ /* Now parse data that is completely in this buffer */
+ /* dma_q->is_partial_line = 0; */
+
+ while (bytes_parsed < buffer_size) {
+ u32 bytes_used = 0;
+
+ sav_eav = cx231xx_find_next_SAV_EAV(
+ p_buffer + bytes_parsed, /* p_buffer */
+ buffer_size - bytes_parsed, /* buf size */
+ &bytes_used);/* bytes used to get SAV/EAV */
+
+ bytes_parsed += bytes_used;
+
+ sav_eav &= 0xF0;
+ if (sav_eav && (bytes_parsed < buffer_size)) {
+ bytes_parsed += cx231xx_get_video_line(dev,
+ dma_q, sav_eav, /* SAV/EAV */
+ p_buffer + bytes_parsed,/* p_buffer */
+ buffer_size - bytes_parsed);/*buf size*/
+ }
+ }
+
+ /* Save the last four bytes of the buffer so we can check the
+ buffer boundary condition next time */
+ memcpy(dma_q->partial_buf, p_buffer + buffer_size - 4, 4);
+ bytes_parsed = 0;
+
+ }
+ return rc;
+}
+
+
u8 cx231xx_find_boundary_SAV_EAV(u8 *p_buffer, u8 *partial_buf,
u32 *p_bytes_used)
{
@@ -533,7 +629,10 @@ u32 cx231xx_copy_video_line(struct cx231xx *dev,
cx231xx_reset_video_buffer(dev, dma_q);
/* get the buffer pointer */
- buf = dev->video_mode.isoc_ctl.buf;
+ if (dev->USE_ISO)
+ buf = dev->video_mode.isoc_ctl.buf;
+ else
+ buf = dev->video_mode.bulk_ctl.buf;
/* Remember the field number for next time */
dma_q->current_field = field_number;
@@ -596,7 +695,10 @@ void cx231xx_reset_video_buffer(struct cx231xx *dev,
dma_q->field1_done = 0;
}
- buf = dev->video_mode.isoc_ctl.buf;
+ if (dev->USE_ISO)
+ buf = dev->video_mode.isoc_ctl.buf;
+ else
+ buf = dev->video_mode.bulk_ctl.buf;
if (buf == NULL) {
u8 *outp = NULL;
@@ -626,7 +728,10 @@ int cx231xx_do_copy(struct cx231xx *dev, struct cx231xx_dmaqueue *dma_q,
void *startwrite;
int offset, lencopy;
- buf = dev->video_mode.isoc_ctl.buf;
+ if (dev->USE_ISO)
+ buf = dev->video_mode.isoc_ctl.buf;
+ else
+ buf = dev->video_mode.bulk_ctl.buf;
if (buf == NULL)
return -1;
@@ -691,7 +796,6 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
{
struct cx231xx_fh *fh = vq->priv_data;
struct cx231xx *dev = fh->dev;
- struct v4l2_frequency f;
*size = (fh->dev->width * fh->dev->height * dev->format->depth + 7)>>3;
if (0 == *count)
@@ -700,13 +804,6 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
if (*count < CX231XX_MIN_BUF)
*count = CX231XX_MIN_BUF;
- /* Ask tuner to go to analog mode */
- memset(&f, 0, sizeof(f));
- f.frequency = dev->ctl_freq;
- f.type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
-
- call_all(dev, tuner, s_frequency, &f);
-
return 0;
}
@@ -730,8 +827,13 @@ static void free_buffer(struct videobuf_queue *vq, struct cx231xx_buffer *buf)
VIDEOBUF_ACTIVE, it won't be, though.
*/
spin_lock_irqsave(&dev->video_mode.slock, flags);
- if (dev->video_mode.isoc_ctl.buf == buf)
- dev->video_mode.isoc_ctl.buf = NULL;
+ if (dev->USE_ISO) {
+ if (dev->video_mode.isoc_ctl.buf == buf)
+ dev->video_mode.isoc_ctl.buf = NULL;
+ } else {
+ if (dev->video_mode.bulk_ctl.buf == buf)
+ dev->video_mode.bulk_ctl.buf = NULL;
+ }
spin_unlock_irqrestore(&dev->video_mode.slock, flags);
videobuf_vmalloc_free(&buf->vb);
@@ -764,14 +866,27 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
goto fail;
}
- if (!dev->video_mode.isoc_ctl.num_bufs)
- urb_init = 1;
-
+ if (dev->USE_ISO) {
+ if (!dev->video_mode.isoc_ctl.num_bufs)
+ urb_init = 1;
+ } else {
+ if (!dev->video_mode.bulk_ctl.num_bufs)
+ urb_init = 1;
+ }
+ /*cx231xx_info("urb_init=%d dev->video_mode.max_pkt_size=%d\n",
+ urb_init, dev->video_mode.max_pkt_size);*/
if (urb_init) {
- rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
+ dev->mode_tv = 0;
+ if (dev->USE_ISO)
+ rc = cx231xx_init_isoc(dev, CX231XX_NUM_PACKETS,
CX231XX_NUM_BUFS,
dev->video_mode.max_pkt_size,
cx231xx_isoc_copy);
+ else
+ rc = cx231xx_init_bulk(dev, CX231XX_NUM_PACKETS,
+ CX231XX_NUM_BUFS,
+ dev->video_mode.max_pkt_size,
+ cx231xx_bulk_copy);
if (rc < 0)
goto fail;
}
@@ -894,22 +1009,6 @@ static int check_dev(struct cx231xx *dev)
return 0;
}
-static void get_scale(struct cx231xx *dev,
- unsigned int width, unsigned int height,
- unsigned int *hscale, unsigned int *vscale)
-{
- unsigned int maxw = norm_maxw(dev);
- unsigned int maxh = norm_maxh(dev);
-
- *hscale = (((unsigned long)maxw) << 12) / width - 4096L;
- if (*hscale >= 0x4000)
- *hscale = 0x3fff;
-
- *vscale = (((unsigned long)maxh) << 12) / height - 4096L;
- if (*vscale >= 0x4000)
- *vscale = 0x3fff;
-}
-
/* ------------------------------------------------------------------
IOCTL vidioc handling
------------------------------------------------------------------*/
@@ -920,8 +1019,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- mutex_lock(&dev->lock);
-
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
f->fmt.pix.pixelformat = dev->format->fourcc;
@@ -931,8 +1028,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
f->fmt.pix.field = V4L2_FIELD_INTERLACED;
- mutex_unlock(&dev->lock);
-
return 0;
}
@@ -956,7 +1051,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
unsigned int height = f->fmt.pix.height;
unsigned int maxw = norm_maxw(dev);
unsigned int maxh = norm_maxh(dev);
- unsigned int hscale, vscale;
struct cx231xx_fmt *fmt;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -970,11 +1064,6 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
height must be even because of interlacing */
v4l_bound_align_image(&width, 48, maxw, 1, &height, 32, maxh, 1, 0);
- get_scale(dev, width, height, &hscale, &vscale);
-
- width = (((unsigned long)maxw) << 12) / (hscale + 4096L);
- height = (((unsigned long)maxh) << 12) / (vscale + 4096L);
-
f->fmt.pix.width = width;
f->fmt.pix.height = height;
f->fmt.pix.pixelformat = fmt->fourcc;
@@ -993,50 +1082,41 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct cx231xx *dev = fh->dev;
int rc;
struct cx231xx_fmt *fmt;
+ struct v4l2_mbus_framefmt mbus_fmt;
rc = check_dev(dev);
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
-
vidioc_try_fmt_vid_cap(file, priv, f);
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
- if (!fmt) {
- rc = -EINVAL;
- goto out;
- }
+ if (!fmt)
+ return -EINVAL;
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
cx231xx_errdev("%s queue busy\n", __func__);
- rc = -EBUSY;
- goto out;
+ return -EBUSY;
}
if (dev->stream_on && !fh->stream_on) {
cx231xx_errdev("%s device in use by another fh\n", __func__);
- rc = -EBUSY;
- goto out;
+ return -EBUSY;
}
/* 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);
-
- call_all(dev, video, s_fmt, f);
- /* Set the correct alternate setting for this resolution */
- cx231xx_resolution_set(dev);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
-out:
- mutex_unlock(&dev->lock);
return rc;
}
-static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id * id)
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *id)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
@@ -1049,6 +1129,7 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
+ struct v4l2_mbus_framefmt mbus_fmt;
struct v4l2_format f;
int rc;
@@ -1058,7 +1139,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
cx231xx_info("vidioc_s_std : 0x%x\n", (unsigned int)*norm);
- mutex_lock(&dev->lock);
dev->norm = *norm;
/* Adjusts width/height, if needed */
@@ -1066,16 +1146,18 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
f.fmt.pix.height = dev->height;
vidioc_try_fmt_vid_cap(file, priv, &f);
- /* set new image size */
- dev->width = f.fmt.pix.width;
- dev->height = f.fmt.pix.height;
- get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
-
call_all(dev, core, s_std, dev->norm);
- mutex_unlock(&dev->lock);
+ /* We need to reset basic properties in the decoder related to
+ resolution (since a standard change effects things like the number
+ of lines in VACT, etc) */
+ v4l2_fill_mbus_format(&mbus_fmt, &f.fmt.pix, V4L2_MBUS_FMT_FIXED);
+ call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f.fmt.pix, &mbus_fmt);
- cx231xx_resolution_set(dev);
+ /* set new image size */
+ dev->width = f.fmt.pix.width;
+ dev->height = f.fmt.pix.height;
/* do mode control overrides */
cx231xx_do_mode_ctrl_overrides(dev);
@@ -1135,6 +1217,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
struct cx231xx *dev = fh->dev;
int rc;
+ dev->mode_tv = 0;
rc = check_dev(dev);
if (rc < 0)
return rc;
@@ -1144,11 +1227,16 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
if (0 == INPUT(i)->type)
return -EINVAL;
- mutex_lock(&dev->lock);
-
video_mux(dev, i);
- mutex_unlock(&dev->lock);
+ if (INPUT(i)->type == CX231XX_VMUX_TELEVISION ||
+ INPUT(i)->type == CX231XX_VMUX_CABLE) {
+ /* There's a tuner, so reset the standard and put it on the
+ last known frequency (since it was probably powered down
+ until now */
+ call_all(dev, core, s_std, dev->norm);
+ }
+
return 0;
}
@@ -1224,9 +1312,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
}
*qc = cx231xx_ctls[i].v;
- mutex_lock(&dev->lock);
call_all(dev, core, queryctrl, qc);
- mutex_unlock(&dev->lock);
if (qc->type)
return 0;
@@ -1245,9 +1331,7 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
call_all(dev, core, g_ctrl, ctrl);
- mutex_unlock(&dev->lock);
return rc;
}
@@ -1262,9 +1346,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
call_all(dev, core, s_ctrl, ctrl);
- mutex_unlock(&dev->lock);
return rc;
}
@@ -1304,9 +1386,7 @@ static int vidioc_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (0 != t->index)
return -EINVAL;
#if 0
- mutex_lock(&dev->lock);
call_all(dev, tuner, s_tuner, t);
- mutex_unlock(&dev->lock);
#endif
return 0;
}
@@ -1317,14 +1397,11 @@ static int vidioc_g_frequency(struct file *file, void *priv,
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
- mutex_lock(&dev->lock);
f->type = fh->radio ? V4L2_TUNER_RADIO : V4L2_TUNER_ANALOG_TV;
f->frequency = dev->ctl_freq;
call_all(dev, tuner, g_frequency, f);
- mutex_unlock(&dev->lock);
-
return 0;
}
@@ -1334,6 +1411,11 @@ static int vidioc_s_frequency(struct file *file, void *priv,
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
int rc;
+ u32 if_frequency = 5400000;
+
+ cx231xx_info("Enter vidioc_s_frequency()f->frequency=%d;f->type=%d\n",
+ f->frequency, f->type);
+ /*cx231xx_info("f->type: 1-radio 2-analogTV 3-digitalTV\n");*/
rc = check_dev(dev);
if (rc < 0)
@@ -1350,21 +1432,34 @@ static int vidioc_s_frequency(struct file *file, void *priv,
/* set pre channel change settings in DIF first */
rc = cx231xx_tuner_pre_channel_change(dev);
- mutex_lock(&dev->lock);
-
dev->ctl_freq = f->frequency;
-
- if (dev->tuner_type == TUNER_XC5000) {
- if (dev->cx231xx_set_analog_freq != NULL)
- dev->cx231xx_set_analog_freq(dev, f->frequency);
- } else
- call_all(dev, tuner, s_frequency, f);
-
- mutex_unlock(&dev->lock);
+ call_all(dev, tuner, s_frequency, f);
/* set post channel change settings in DIF first */
rc = cx231xx_tuner_post_channel_change(dev);
+ if (dev->tuner_type == TUNER_NXP_TDA18271) {
+ if (dev->norm & (V4L2_STD_MN | V4L2_STD_NTSC_443))
+ if_frequency = 5400000; /*5.4MHz */
+ else if (dev->norm & V4L2_STD_B)
+ if_frequency = 6000000; /*6.0MHz */
+ else if (dev->norm & (V4L2_STD_PAL_DK | V4L2_STD_SECAM_DK))
+ if_frequency = 6900000; /*6.9MHz */
+ else if (dev->norm & V4L2_STD_GH)
+ if_frequency = 7100000; /*7.1MHz */
+ else if (dev->norm & V4L2_STD_PAL_I)
+ if_frequency = 7250000; /*7.25MHz */
+ else if (dev->norm & V4L2_STD_SECAM_L)
+ if_frequency = 6900000; /*6.9MHz */
+ else if (dev->norm & V4L2_STD_SECAM_LC)
+ if_frequency = 1250000; /*1.25MHz */
+
+ cx231xx_info("if_frequency is set to %d\n", if_frequency);
+ cx231xx_set_Colibri_For_LowIF(dev, if_frequency, 1, 1);
+
+ update_HH_register_after_set_DIF(dev);
+ }
+
cx231xx_info("Set New FREQUENCY to %d\n", f->frequency);
return rc;
@@ -1442,17 +1537,92 @@ static int vidioc_g_register(struct file *file, void *priv,
case V4L2_CHIP_MATCH_I2C_DRIVER:
call_all(dev, core, g_register, reg);
return 0;
- case V4L2_CHIP_MATCH_I2C_ADDR:
- /* Not supported yet */
- return -EINVAL;
+ case V4L2_CHIP_MATCH_I2C_ADDR:/*for register debug*/
+ switch (reg->match.addr) {
+ case 0: /* Cx231xx - internal registers */
+ ret = cx231xx_read_ctrl_reg(dev, VRT_GET_REGISTER,
+ (u16)reg->reg, value, 4);
+ reg->val = value[0] | value[1] << 8 |
+ value[2] << 16 | value[3] << 24;
+
+ break;
+ case 0x600:/* AFE - read byte */
+ ret = cx231xx_read_i2c_master(dev, AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2,
+ &data, 1 , 0);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+
+ case 0x880:/* Video Block - read byte */
+ if (reg->reg < 0x0b) {
+ ret = cx231xx_read_i2c_master(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ &data, 1 , 0);
+ reg->val = le32_to_cpu(data & 0xff);
+ } else {
+ ret = cx231xx_read_i2c_master(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ &data, 4 , 0);
+ reg->val = le32_to_cpu(data);
+ }
+ break;
+ case 0x980:
+ ret = cx231xx_read_i2c_master(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ &data, 1 , 0);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 0x400:
+ ret =
+ cx231xx_read_i2c_master(dev, 0x40,
+ (u16)reg->reg, 1,
+ &data, 1 , 0);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 0xc01:
+ ret =
+ cx231xx_read_i2c_master(dev, 0xc0,
+ (u16)reg->reg, 2,
+ &data, 38, 1);
+ reg->val = le32_to_cpu(data);
+ break;
+ case 0x022:
+ ret =
+ cx231xx_read_i2c_master(dev, 0x02,
+ (u16)reg->reg, 1,
+ &data, 1, 2);
+ reg->val = le32_to_cpu(data & 0xff);
+ break;
+ case 0x322:
+ ret = cx231xx_read_i2c_master(dev,
+ 0x32,
+ (u16)reg->reg, 1,
+ &data, 4 , 2);
+ reg->val = le32_to_cpu(data);
+ break;
+ case 0x342:
+ ret = cx231xx_read_i2c_master(dev,
+ 0x34,
+ (u16)reg->reg, 1,
+ &data, 4 , 2);
+ reg->val = le32_to_cpu(data);
+ break;
+
+ default:
+ cx231xx_info("no match device address!!\n");
+ break;
+ }
+ return ret < 0 ? ret : 0;
+ /*return -EINVAL;*/
default:
if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
}
- mutex_lock(&dev->lock);
call_all(dev, core, g_register, reg);
- mutex_unlock(&dev->lock);
return ret;
}
@@ -1528,14 +1698,96 @@ static int vidioc_s_register(struct file *file, void *priv,
}
}
return ret < 0 ? ret : 0;
+ case V4L2_CHIP_MATCH_I2C_ADDR:
+ {
+ value = (u32) buf & 0xffffffff;
+ switch (reg->match.addr) {
+ case 0:/*cx231xx internal registers*/
+ data[0] = (u8) value;
+ data[1] = (u8) (value >> 8);
+ data[2] = (u8) (value >> 16);
+ data[3] = (u8) (value >> 24);
+ ret = cx231xx_write_ctrl_reg(dev,
+ VRT_SET_REGISTER,
+ (u16)reg->reg, data,
+ 4);
+ break;
+ case 0x600:/* AFE - read byte */
+ ret = cx231xx_write_i2c_master(dev,
+ AFE_DEVICE_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 1 , 0);
+ break;
+
+ case 0x880:/* Video Block - read byte */
+ if (reg->reg < 0x0b)
+ cx231xx_write_i2c_master(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 1, 0);
+ else
+ cx231xx_write_i2c_master(dev,
+ VID_BLK_I2C_ADDRESS,
+ (u16)reg->reg, 2,
+ value, 4, 0);
+ break;
+ case 0x980:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ I2S_BLK_DEVICE_ADDRESS,
+ (u16)reg->reg, 1,
+ value, 1, 0);
+ break;
+ case 0x400:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0x40,
+ (u16)reg->reg, 1,
+ value, 1, 0);
+ break;
+ case 0xc01:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0xc0,
+ (u16)reg->reg, 1,
+ value, 1, 1);
+ break;
+
+ case 0x022:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0x02,
+ (u16)reg->reg, 1,
+ value, 1, 2);
+ case 0x322:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0x32,
+ (u16)reg->reg, 1,
+ value, 4, 2);
+ break;
+
+ case 0x342:
+ ret =
+ cx231xx_write_i2c_master(dev,
+ 0x34,
+ (u16)reg->reg, 1,
+ value, 4, 2);
+ break;
+ default:
+ cx231xx_info("no match device address, "
+ "the value is %x\n", reg->match.addr);
+ break;
+
+ }
+
+ }
default:
break;
}
- mutex_lock(&dev->lock);
call_all(dev, core, s_register, reg);
- mutex_unlock(&dev->lock);
return ret;
}
@@ -1572,7 +1824,6 @@ static int vidioc_streamon(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
rc = res_get(fh);
if (likely(rc >= 0))
@@ -1580,8 +1831,6 @@ static int vidioc_streamon(struct file *file, void *priv,
call_all(dev, video, s_stream, 1);
- mutex_unlock(&dev->lock);
-
return rc;
}
@@ -1602,15 +1851,11 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (type != fh->type)
return -EINVAL;
- mutex_lock(&dev->lock);
-
cx25840_call(dev, video, s_stream, 0);
videobuf_streamoff(&fh->vb_vidq);
res_free(fh);
- mutex_unlock(&dev->lock);
-
return 0;
}
@@ -1665,8 +1910,6 @@ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
-
f->fmt.sliced.service_set = 0;
call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
@@ -1674,7 +1917,6 @@ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
if (f->fmt.sliced.service_set == 0)
rc = -EINVAL;
- mutex_unlock(&dev->lock);
return rc;
}
@@ -1689,9 +1931,7 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
call_all(dev, vbi, g_sliced_fmt, &f->fmt.sliced);
- mutex_unlock(&dev->lock);
if (f->fmt.sliced.service_set == 0)
return -EINVAL;
@@ -1706,12 +1946,10 @@ static int vidioc_g_fmt_vbi_cap(struct file *file, void *priv,
{
struct cx231xx_fh *fh = priv;
struct cx231xx *dev = fh->dev;
-
- f->fmt.vbi.sampling_rate = (dev->norm & V4L2_STD_625_50) ?
- 35468950 : 28636363;
+ f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = 64 * 4;
+ f->fmt.vbi.offset = 0;
f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
f->fmt.vbi.count[0] = (dev->norm & V4L2_STD_625_50) ?
@@ -1736,11 +1974,10 @@ static int vidioc_try_fmt_vbi_cap(struct file *file, void *priv,
}
f->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- f->fmt.vbi.sampling_rate = (dev->norm & V4L2_STD_625_50) ?
- 35468950 : 28636363;
+ f->fmt.vbi.sampling_rate = 6750000 * 4;
f->fmt.vbi.samples_per_line = VBI_LINE_LENGTH;
f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- f->fmt.vbi.offset = 244;
+ f->fmt.vbi.offset = 0;
f->fmt.vbi.flags = 0;
f->fmt.vbi.start[0] = (dev->norm & V4L2_STD_625_50) ?
PAL_VBI_START_LINE : NTSC_VBI_START_LINE;
@@ -1807,15 +2044,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct cx231xx_fh *fh = priv;
-
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
@@ -1844,9 +2072,7 @@ static int radio_g_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
- mutex_lock(&dev->lock);
call_all(dev, tuner, s_tuner, t);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1877,9 +2103,7 @@ static int radio_s_tuner(struct file *file, void *priv, struct v4l2_tuner *t)
if (0 != t->index)
return -EINVAL;
- mutex_lock(&dev->lock);
call_all(dev, tuner, s_tuner, t);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1938,8 +2162,6 @@ static int cx231xx_v4l2_open(struct file *filp)
break;
}
- mutex_lock(&dev->lock);
-
cx231xx_videodbg("open dev=%s type=%s users=%d\n",
video_device_node_name(vdev), v4l2_type_names[fh_type],
dev->users);
@@ -1949,7 +2171,6 @@ static int cx231xx_v4l2_open(struct file *filp)
if (errCode < 0) {
cx231xx_errdev
("Device locked on digital mode. Can't open analog\n");
- mutex_unlock(&dev->lock);
return -EBUSY;
}
#endif
@@ -1957,7 +2178,6 @@ static int cx231xx_v4l2_open(struct file *filp)
fh = kzalloc(sizeof(struct cx231xx_fh), GFP_KERNEL);
if (!fh) {
cx231xx_errdev("cx231xx-video.c: Out of memory?!\n");
- mutex_unlock(&dev->lock);
return -ENOMEM;
}
fh->dev = dev;
@@ -1968,16 +2188,18 @@ static int cx231xx_v4l2_open(struct file *filp)
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
- dev->hscale = 0;
- dev->vscale = 0;
/* Power up in Analog TV mode */
- cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
+ if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER ||
+ dev->model == CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+ cx231xx_set_power_mode(dev,
+ POLARIS_AVMODE_ENXTERNAL_AV);
+ else
+ cx231xx_set_power_mode(dev, POLARIS_AVMODE_ANALOGT_TV);
#if 0
cx231xx_set_mode(dev, CX231XX_ANALOG_MODE);
#endif
- cx231xx_resolution_set(dev);
/* set video alternate setting */
cx231xx_set_video_alternate(dev);
@@ -1988,7 +2210,6 @@ static int cx231xx_v4l2_open(struct file *filp)
/* device needs to be initialized before isoc transfer */
dev->video_input = dev->video_input > 2 ? 2 : dev->video_input;
- video_mux(dev, dev->video_input);
}
if (fh->radio) {
@@ -2005,20 +2226,22 @@ static int cx231xx_v4l2_open(struct file *filp)
videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_video_qops,
NULL, &dev->video_mode.slock,
fh->type, V4L2_FIELD_INTERLACED,
- sizeof(struct cx231xx_buffer), fh);
+ sizeof(struct cx231xx_buffer),
+ fh, &dev->lock);
if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
/* Set the required alternate setting VBI interface works in
Bulk mode only */
- cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+ if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
+ dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
videobuf_queue_vmalloc_init(&fh->vb_vidq, &cx231xx_vbi_qops,
NULL, &dev->vbi_mode.slock,
fh->type, V4L2_FIELD_SEQ_TB,
- sizeof(struct cx231xx_buffer), fh);
+ sizeof(struct cx231xx_buffer),
+ fh, &dev->lock);
}
- mutex_unlock(&dev->lock);
-
return errCode;
}
@@ -2051,6 +2274,10 @@ void cx231xx_release_analog_resources(struct cx231xx *dev)
if (dev->vdev) {
cx231xx_info("V4L2 device %s deregistered\n",
video_device_node_name(dev->vdev));
+
+ if (dev->model == CX231XX_BOARD_CNXT_VIDEO_GRABBER)
+ cx231xx_417_unregister(dev);
+
if (video_is_registered(dev->vdev))
video_unregister_device(dev->vdev);
else
@@ -2071,39 +2298,44 @@ static int cx231xx_v4l2_close(struct file *filp)
cx231xx_videodbg("users=%d\n", dev->users);
- mutex_lock(&dev->lock);
-
+ cx231xx_videodbg("users=%d\n", dev->users);
if (res_check(fh))
res_free(fh);
- if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- videobuf_stop(&fh->vb_vidq);
- videobuf_mmap_free(&fh->vb_vidq);
-
- /* the device is already disconnect,
- free the remaining resources */
- if (dev->state & DEV_DISCONNECTED) {
- cx231xx_release_resources(dev);
- mutex_unlock(&dev->lock);
- kfree(dev);
- return 0;
- }
+ /*To workaround error number=-71 on EP0 for VideoGrabber,
+ need exclude following.*/
+ if (dev->model != CX231XX_BOARD_CNXT_VIDEO_GRABBER &&
+ dev->model != CX231XX_BOARD_HAUPPAUGE_USBLIVE2)
+ if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ /* the device is already disconnect,
+ free the remaining resources */
+ if (dev->state & DEV_DISCONNECTED) {
+ if (atomic_read(&dev->devlist_count) > 0) {
+ cx231xx_release_resources(dev);
+ kfree(dev);
+ dev = NULL;
+ return 0;
+ }
+ return 0;
+ }
- /* do this before setting alternate! */
- cx231xx_uninit_vbi_isoc(dev);
+ /* do this before setting alternate! */
+ cx231xx_uninit_vbi_isoc(dev);
- /* set alternate 0 */
- if (!dev->vbi_or_sliced_cc_mode)
- cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
- else
- cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
+ /* set alternate 0 */
+ if (!dev->vbi_or_sliced_cc_mode)
+ cx231xx_set_alt_setting(dev, INDEX_VANC, 0);
+ else
+ cx231xx_set_alt_setting(dev, INDEX_HANC, 0);
- kfree(fh);
- dev->users--;
- wake_up_interruptible_nr(&dev->open, 1);
- mutex_unlock(&dev->lock);
- return 0;
- }
+ kfree(fh);
+ dev->users--;
+ wake_up_interruptible_nr(&dev->open, 1);
+ return 0;
+ }
if (dev->users == 1) {
videobuf_stop(&fh->vb_vidq);
@@ -2113,8 +2345,8 @@ static int cx231xx_v4l2_close(struct file *filp)
free the remaining resources */
if (dev->state & DEV_DISCONNECTED) {
cx231xx_release_resources(dev);
- mutex_unlock(&dev->lock);
kfree(dev);
+ dev = NULL;
return 0;
}
@@ -2122,7 +2354,10 @@ static int cx231xx_v4l2_close(struct file *filp)
call_all(dev, core, s_power, 0);
/* do this before setting alternate! */
- cx231xx_uninit_isoc(dev);
+ if (dev->USE_ISO)
+ cx231xx_uninit_isoc(dev);
+ else
+ cx231xx_uninit_bulk(dev);
cx231xx_set_mode(dev, CX231XX_SUSPEND);
/* set alternate 0 */
@@ -2131,7 +2366,6 @@ static int cx231xx_v4l2_close(struct file *filp)
kfree(fh);
dev->users--;
wake_up_interruptible_nr(&dev->open, 1);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -2153,9 +2387,7 @@ cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
if ((fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) ||
(fh->type == V4L2_BUF_TYPE_VBI_CAPTURE)) {
- mutex_lock(&dev->lock);
rc = res_get(fh);
- mutex_unlock(&dev->lock);
if (unlikely(rc < 0))
return rc;
@@ -2170,7 +2402,7 @@ cx231xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
* cx231xx_v4l2_poll()
* will allocate buffers when called for the first time
*/
-static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table * wait)
+static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table *wait)
{
struct cx231xx_fh *fh = filp->private_data;
struct cx231xx *dev = fh->dev;
@@ -2180,9 +2412,7 @@ static unsigned int cx231xx_v4l2_poll(struct file *filp, poll_table * wait)
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
rc = res_get(fh);
- mutex_unlock(&dev->lock);
if (unlikely(rc < 0))
return POLLERR;
@@ -2207,9 +2437,7 @@ static int cx231xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
rc = res_get(fh);
- mutex_unlock(&dev->lock);
if (unlikely(rc < 0))
return rc;
@@ -2231,7 +2459,7 @@ static const struct v4l2_file_operations cx231xx_v4l_fops = {
.read = cx231xx_v4l2_read,
.poll = cx231xx_v4l2_poll,
.mmap = cx231xx_v4l2_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -2270,9 +2498,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static struct video_device cx231xx_vbi_template;
@@ -2333,6 +2558,7 @@ static struct video_device *cx231xx_vdev_init(struct cx231xx *dev,
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
vfd->debug = video_debug;
+ vfd->lock = &dev->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s %s", dev->name, type_name);
@@ -2355,12 +2581,12 @@ int cx231xx_register_analog_devices(struct cx231xx *dev)
dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
dev->interlaced = 0;
- dev->hscale = 0;
- dev->vscale = 0;
/* Analog specific initialization */
dev->format = &format[0];
- /* video_mux(dev, dev->video_input); */
+
+ /* Set the initial input */
+ video_mux(dev, dev->video_input);
/* Audio defaults */
dev->mute = 1;
diff --git a/drivers/media/video/cx231xx/cx231xx.h b/drivers/media/video/cx231xx/cx231xx.h
index 38d417191a65..72bbea2bcd56 100644
--- a/drivers/media/video/cx231xx/cx231xx.h
+++ b/drivers/media/video/cx231xx/cx231xx.h
@@ -27,16 +27,16 @@
#include <linux/ioctl.h>
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
+#include <linux/workqueue.h>
#include <linux/mutex.h>
+#include <media/cx2341x.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
-#include <media/ir-core.h>
-#if defined(CONFIG_VIDEO_CX231XX_DVB) || \
- defined(CONFIG_VIDEO_CX231XX_DVB_MODULE)
+#include <media/rc-core.h>
+#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dvb.h>
-#endif
#include "cx231xx-reg.h"
#include "cx231xx-pcb-cfg.h"
@@ -49,12 +49,21 @@
#define AFE_DEVICE_ADDRESS 0x60
#define I2S_BLK_DEVICE_ADDRESS 0x98
#define VID_BLK_I2C_ADDRESS 0x88
+#define VERVE_I2C_ADDRESS 0x40
#define DIF_USE_BASEBAND 0xFFFFFFFF
/* Boards supported by driver */
#define CX231XX_BOARD_UNKNOWN 0
-#define CX231XX_BOARD_CNXT_RDE_250 1
-#define CX231XX_BOARD_CNXT_RDU_250 2
+#define CX231XX_BOARD_CNXT_CARRAERA 1
+#define CX231XX_BOARD_CNXT_SHELBY 2
+#define CX231XX_BOARD_CNXT_RDE_253S 3
+#define CX231XX_BOARD_CNXT_RDU_253S 4
+#define CX231XX_BOARD_CNXT_VIDEO_GRABBER 5
+#define CX231XX_BOARD_CNXT_RDE_250 6
+#define CX231XX_BOARD_CNXT_RDU_250 7
+#define CX231XX_BOARD_HAUPPAUGE_EXETER 8
+#define CX231XX_BOARD_HAUPPAUGE_USBLIVE2 9
+#define CX231XX_BOARD_PV_PLAYTV_USB_HYBRID 10
/* Limits minimum and default number of buffers */
#define CX231XX_MIN_BUF 4
@@ -95,6 +104,24 @@
#define CX231XX_URB_TIMEOUT \
msecs_to_jiffies(CX231XX_NUM_BUFS * CX231XX_NUM_PACKETS)
+#define CX231xx_NORMS (\
+ V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443 | \
+ V4L2_STD_PAL_BG | V4L2_STD_PAL_DK | V4L2_STD_PAL_I | \
+ V4L2_STD_PAL_M | V4L2_STD_PAL_N | V4L2_STD_PAL_Nc | \
+ V4L2_STD_PAL_60 | V4L2_STD_SECAM_L | V4L2_STD_SECAM_DK)
+#define CX231xx_VERSION_CODE KERNEL_VERSION(0, 0, 2)
+
+#define SLEEP_S5H1432 30
+#define CX23417_OSC_EN 8
+#define CX23417_RESET 9
+
+struct cx23417_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+ int depth;
+ int flags;
+ u32 cxformat;
+};
enum cx231xx_mode {
CX231XX_SUSPEND,
CX231XX_ANALOG_MODE,
@@ -114,7 +141,7 @@ enum cx231xx_stream_state {
struct cx231xx;
-struct cx231xx_usb_isoc_ctl {
+struct cx231xx_isoc_ctl {
/* max packet size of isoc transaction */
int max_pkt_size;
@@ -148,6 +175,40 @@ struct cx231xx_usb_isoc_ctl {
int (*isoc_copy) (struct cx231xx *dev, struct urb *urb);
};
+struct cx231xx_bulk_ctl {
+ /* max packet size of bulk transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for bulk transfers */
+ struct urb **urb;
+
+ /* transfer buffers for bulk transfer */
+ char **transfer_buffer;
+
+ /* Last buffer command and region */
+ u8 cmd;
+ int pos, size, pktsize;
+
+ /* Last field: ODD or EVEN? */
+ int field;
+
+ /* Stores incomplete commands */
+ u32 tmp_buf;
+ int tmp_buf_len;
+
+ /* Stores already requested buffers */
+ struct cx231xx_buffer *buf;
+
+ /* Stores the number of received fields */
+ int nfields;
+
+ /* bulk urb callback */
+ int (*bulk_copy) (struct cx231xx *dev, struct urb *urb);
+};
+
struct cx231xx_fmt {
char *name;
u32 fourcc; /* v4l2 format id */
@@ -165,6 +226,11 @@ struct cx231xx_buffer {
int receiving;
};
+enum ps_package_head {
+ CX231XX_NEED_ADD_PS_PACKAGE_HEAD = 0,
+ CX231XX_NONEED_PS_PACKAGE_HEAD
+};
+
struct cx231xx_dmaqueue {
struct list_head active;
struct list_head queued;
@@ -181,6 +247,14 @@ struct cx231xx_dmaqueue {
u32 lines_completed;
u8 field1_done;
u32 lines_per_field;
+
+ /*Mpeg2 control buffer*/
+ u8 *p_left_data;
+ u32 left_data_count;
+ u8 mpeg_buffer_done;
+ u32 mpeg_buffer_completed;
+ enum ps_package_head add_ps_package_head;
+ char ps_head[10];
};
/* inputs */
@@ -259,9 +333,10 @@ struct cx231xx_board {
struct cx231xx_reg_seq *dvb_gpio;
struct cx231xx_reg_seq *suspend_gpio;
struct cx231xx_reg_seq *tuner_gpio;
- u8 tuner_sif_gpio;
- u8 tuner_scl_gpio;
- u8 tuner_sda_gpio;
+ /* Negative means don't use it */
+ s8 tuner_sif_gpio;
+ s8 tuner_scl_gpio;
+ s8 tuner_sda_gpio;
/* PIN ctrl */
u32 ctl_pin_status_mask;
@@ -271,6 +346,10 @@ struct cx231xx_board {
/* i2c masters */
u8 tuner_i2c_master;
u8 demod_i2c_master;
+ u8 ir_i2c_master;
+
+ /* for devices with I2C chips for IR */
+ char *rc_map_name;
unsigned int max_range_640_480:1;
unsigned int has_dvb:1;
@@ -279,10 +358,11 @@ struct cx231xx_board {
unsigned char xclk, i2c_speed;
enum cx231xx_decoder decoder;
+ int output_mode;
struct cx231xx_input input[MAX_CX231XX_INPUT];
struct cx231xx_input radio;
- struct ir_scancode_table *ir_codes;
+ struct rc_map *ir_codes;
};
/* device states */
@@ -309,10 +389,8 @@ enum AUDIO_INPUT {
};
#define CX231XX_AUDIO_BUFS 5
-#define CX231XX_NUM_AUDIO_PACKETS 64
-#define CX231XX_CAPTURE_STREAM_EN 1
-#define CX231XX_STOP_AUDIO 0
-#define CX231XX_START_AUDIO 1
+#define CX231XX_NUM_AUDIO_PACKETS 16
+#define CX231XX_ISO_NUM_AUDIO_PACKETS 64
/* cx231xx extensions */
#define CX231XX_AUDIO 0x10
@@ -330,7 +408,7 @@ struct cx231xx_audio {
struct snd_card *sndcard;
int users, shutdown;
- enum cx231xx_stream_state capture_stream;
+ /* locks */
spinlock_t slock;
int alt; /* alternate */
@@ -350,6 +428,28 @@ struct cx231xx_fh {
struct videobuf_queue vb_vidq;
enum v4l2_buf_type type;
+
+
+
+/*following is copyed from cx23885.h*/
+ u32 resources;
+
+ /* video overlay */
+ struct v4l2_window win;
+ struct v4l2_clip *clips;
+ unsigned int nclips;
+
+ /* video capture */
+ struct cx23417_fmt *fmt;
+ unsigned int width, height;
+
+ /* vbi capture */
+ struct videobuf_queue vidq;
+ struct videobuf_queue vbiq;
+
+ /* MPEG Encoder specifics ONLY */
+
+ atomic_t v4l_reading;
};
/*****************************************************************/
@@ -403,6 +503,13 @@ struct VENDOR_REQUEST_IN {
u8 *pBuff;
};
+struct cx231xx_tvnorm {
+ char *name;
+ v4l2_std_id id;
+ u32 cxiformat;
+ u32 cxoformat;
+};
+
struct cx231xx_ctrl {
struct v4l2_queryctrl v;
u32 off;
@@ -424,7 +531,9 @@ enum TRANSFER_TYPE {
struct cx231xx_video_mode {
/* Isoc control struct */
struct cx231xx_dmaqueue vidq;
- struct cx231xx_usb_isoc_ctl isoc_ctl;
+ struct cx231xx_isoc_ctl isoc_ctl;
+ struct cx231xx_bulk_ctl bulk_ctl;
+ /* locks */
spinlock_t slock;
/* usb transfer */
@@ -434,6 +543,64 @@ struct cx231xx_video_mode {
unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
u16 end_point_addr;
};
+/*
+struct cx23885_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+ struct timer_list timeout;
+ struct btcx_riscmem stopper;
+ u32 count;
+};
+*/
+struct cx231xx_tsport {
+ struct cx231xx *dev;
+
+ int nr;
+ int sram_chno;
+
+ struct videobuf_dvb_frontends frontends;
+
+ /* dma queues */
+
+ u32 ts_packet_size;
+ u32 ts_packet_count;
+
+ int width;
+ int height;
+
+ /* locks */
+ spinlock_t slock;
+
+ /* registers */
+ u32 reg_gpcnt;
+ u32 reg_gpcnt_ctl;
+ u32 reg_dma_ctl;
+ u32 reg_lngth;
+ u32 reg_hw_sop_ctrl;
+ u32 reg_gen_ctrl;
+ u32 reg_bd_pkt_status;
+ u32 reg_sop_status;
+ u32 reg_fifo_ovfl_stat;
+ u32 reg_vld_misc;
+ u32 reg_ts_clk_en;
+ u32 reg_ts_int_msk;
+ u32 reg_ts_int_stat;
+ u32 reg_src_sel;
+
+ /* Default register vals */
+ int pci_irqmask;
+ u32 dma_ctl_val;
+ u32 ts_int_msk_val;
+ u32 gen_ctrl_val;
+ u32 ts_clk_en_val;
+ u32 src_sel_val;
+ u32 vld_misc_val;
+ u32 hw_sop_ctrl_val;
+
+ /* Allow a single tsport to have multiple frontends */
+ u32 num_frontends;
+ void *port_priv;
+};
/* main device struct */
struct cx231xx {
@@ -444,6 +611,9 @@ struct cx231xx {
struct cx231xx_board board;
+ /* For I2C IR support */
+ struct IR_i2c_init_data init_data;
+
unsigned int stream_on:1; /* Locks streams */
unsigned int vbi_stream_on:1; /* Locks streams for VBI */
unsigned int has_audio_class:1;
@@ -455,7 +625,8 @@ struct cx231xx {
struct v4l2_subdev *sd_cx25840;
struct v4l2_subdev *sd_tuner;
- struct cx231xx_IR *ir;
+ struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
+ atomic_t stream_started; /* stream should be running if true */
struct list_head devlist;
@@ -465,7 +636,9 @@ struct cx231xx {
/* I2C adapters: Master 1 & 2 (External) & Master 3 (Internal only) */
struct cx231xx_i2c i2c_bus[3];
unsigned int xc_fw_load_done:1;
+ /* locks */
struct mutex gpio_i2c_lock;
+ struct mutex i2c_lock;
/* video for linux */
int users; /* user count for exclusive use */
@@ -479,8 +652,6 @@ struct cx231xx {
/* frame properties */
int width; /* current frame width */
int height; /* current frame height */
- unsigned hscale; /* horizontal scale factor (see datasheet) */
- unsigned vscale; /* vertical scale factor (see datasheet) */
int interlaced; /* 1=interlace fileds, 0=just top fileds */
struct cx231xx_audio adev;
@@ -505,6 +676,8 @@ struct cx231xx {
struct cx231xx_video_mode sliced_cc_mode;
struct cx231xx_video_mode ts1_mode;
+ atomic_t devlist_count;
+
struct usb_device *udev; /* the usb device */
char urb_buf[URB_MAX_CTRL_SIZE]; /* urb control msg buffer */
@@ -550,8 +723,24 @@ struct cx231xx {
u8 vbi_or_sliced_cc_mode; /* 0 - vbi ; 1 - sliced cc mode */
enum cx231xx_std_mode std_mode; /* 0 - Air; 1 - cable */
+ /*mode: digital=1 or analog=0*/
+ u8 mode_tv;
+
+ u8 USE_ISO;
+ struct cx231xx_tvnorm encodernorm;
+ struct cx231xx_tsport ts1, ts2;
+ struct cx2341x_mpeg_params mpeg_params;
+ struct video_device *v4l_device;
+ atomic_t v4l_reader_count;
+ u32 freq;
+ unsigned int input;
+ u32 cx23417_mailbox;
+ u32 __iomem *lmmio;
+ u8 __iomem *bmmio;
};
+extern struct list_head cx231xx_devlist;
+
#define cx25840_call(cx231xx, o, f, args...) \
v4l2_subdev_call(cx231xx->sd_cx25840, o, f, ##args)
#define tuner_call(cx231xx, o, f, args...) \
@@ -577,6 +766,10 @@ int cx231xx_i2c_register(struct cx231xx_i2c *bus);
int cx231xx_i2c_unregister(struct cx231xx_i2c *bus);
/* Internal block control functions */
+int cx231xx_read_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+ u8 saddr_len, u32 *data, u8 data_len, int master);
+int cx231xx_write_i2c_master(struct cx231xx *dev, u8 dev_addr, u16 saddr,
+ u8 saddr_len, u32 data, u8 data_len, int master);
int cx231xx_read_i2c_data(struct cx231xx *dev, u8 dev_addr,
u16 saddr, u8 saddr_len, u32 *data, u8 data_len);
int cx231xx_write_i2c_data(struct cx231xx *dev, u8 dev_addr,
@@ -588,6 +781,9 @@ int cx231xx_read_modify_write_i2c_dword(struct cx231xx *dev, u8 dev_addr,
u16 saddr, u32 mask, u32 value);
u32 cx231xx_set_field(u32 field_mask, u32 data);
+/*verve r/w*/
+void initGPIO(struct cx231xx *dev);
+void uninitGPIO(struct cx231xx *dev);
/* afe related functions */
int cx231xx_afe_init_super_block(struct cx231xx *dev, u32 ref_count);
int cx231xx_afe_init_channels(struct cx231xx *dev);
@@ -607,6 +803,19 @@ int cx231xx_i2s_blk_set_audio_input(struct cx231xx *dev, u8 audio_input);
/* DIF related functions */
int cx231xx_dif_configure_C2HH_for_low_IF(struct cx231xx *dev, u32 mode,
u32 function_mode, u32 standard);
+void cx231xx_set_Colibri_For_LowIF(struct cx231xx *dev, u32 if_freq,
+ u8 spectral_invert, u32 mode);
+u32 cx231xx_Get_Colibri_CarrierOffset(u32 mode, u32 standerd);
+void cx231xx_set_DIF_bandpass(struct cx231xx *dev, u32 if_freq,
+ u8 spectral_invert, u32 mode);
+void cx231xx_Setup_AFE_for_LowIF(struct cx231xx *dev);
+void reset_s5h1432_demod(struct cx231xx *dev);
+void cx231xx_dump_HH_reg(struct cx231xx *dev);
+void update_HH_register_after_set_DIF(struct cx231xx *dev);
+void cx231xx_dump_SC_reg(struct cx231xx *dev);
+
+
+
int cx231xx_dif_set_standard(struct cx231xx *dev, u32 standard);
int cx231xx_tuner_pre_channel_change(struct cx231xx *dev);
int cx231xx_tuner_post_channel_change(struct cx231xx *dev);
@@ -672,15 +881,28 @@ int cx231xx_set_audio_decoder_input(struct cx231xx *dev,
enum AUDIO_INPUT audio_input);
int cx231xx_capture_start(struct cx231xx *dev, int start, u8 media_type);
-int cx231xx_resolution_set(struct cx231xx *dev);
int cx231xx_set_video_alternate(struct cx231xx *dev);
int cx231xx_set_alt_setting(struct cx231xx *dev, u8 index, u8 alt);
+int is_fw_load(struct cx231xx *dev);
+int cx231xx_check_fw(struct cx231xx *dev);
int cx231xx_init_isoc(struct cx231xx *dev, int max_packets,
int num_bufs, int max_pkt_size,
int (*isoc_copy) (struct cx231xx *dev,
struct urb *urb));
+int cx231xx_init_bulk(struct cx231xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*bulk_copy) (struct cx231xx *dev,
+ struct urb *urb));
+void cx231xx_stop_TS1(struct cx231xx *dev);
+void cx231xx_start_TS1(struct cx231xx *dev);
void cx231xx_uninit_isoc(struct cx231xx *dev);
+void cx231xx_uninit_bulk(struct cx231xx *dev);
int cx231xx_set_mode(struct cx231xx *dev, enum cx231xx_mode set_mode);
+int cx231xx_unmute_audio(struct cx231xx *dev);
+int cx231xx_ep5_bulkout(struct cx231xx *dev, u8 *firmware, u16 size);
+void cx231xx_disable656(struct cx231xx *dev);
+void cx231xx_enable656(struct cx231xx *dev);
+int cx231xx_demod_reset(struct cx231xx *dev);
int cx231xx_gpio_set(struct cx231xx *dev, struct cx231xx_reg_seq *gpio);
/* Device list functions */
@@ -712,7 +934,7 @@ int cx231xx_power_suspend(struct cx231xx *dev);
int cx231xx_init_ctrl_pin_status(struct cx231xx *dev);
int cx231xx_set_agc_analog_digital_mux_select(struct cx231xx *dev,
u8 analog_or_digital);
-int cx231xx_enable_i2c_for_tuner(struct cx231xx *dev, u8 I2CIndex);
+int cx231xx_enable_i2c_port_3(struct cx231xx *dev, bool is_port_3);
/* video audio decoder related functions */
void video_mux(struct cx231xx *dev, int index);
@@ -733,12 +955,22 @@ extern void cx231xx_card_setup(struct cx231xx *dev);
extern struct cx231xx_board cx231xx_boards[];
extern struct usb_device_id cx231xx_id_table[];
extern const unsigned int cx231xx_bcount;
-void cx231xx_register_i2c_ir(struct cx231xx *dev);
int cx231xx_tuner_callback(void *ptr, int component, int command, int arg);
-/* Provided by cx231xx-input.c */
+/* cx23885-417.c */
+extern int cx231xx_417_register(struct cx231xx *dev);
+extern void cx231xx_417_unregister(struct cx231xx *dev);
+
+/* cx23885-input.c */
+
+#if defined(CONFIG_VIDEO_CX231XX_RC)
int cx231xx_ir_init(struct cx231xx *dev);
-int cx231xx_ir_fini(struct cx231xx *dev);
+void cx231xx_ir_exit(struct cx231xx *dev);
+#else
+#define cx231xx_ir_init(dev) (0)
+#define cx231xx_ir_exit(dev) (0)
+#endif
+
/* printk macros */
diff --git a/drivers/media/video/cx2341x.c b/drivers/media/video/cx2341x.c
index 022b480918cd..103ef6bad2e2 100644
--- a/drivers/media/video/cx2341x.c
+++ b/drivers/media/video/cx2341x.c
@@ -38,6 +38,145 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
+/********************** COMMON CODE *********************/
+
+/* definitions for audio properties bits 29-28 */
+#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0
+#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1
+#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2
+
+static const char *cx2341x_get_name(u32 id)
+{
+ switch (id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return "Spatial Filter Mode";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ return "Spatial Filter";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ return "Spatial Luma Filter Type";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ return "Spatial Chroma Filter Type";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return "Temporal Filter Mode";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ return "Temporal Filter";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return "Median Filter Type";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ return "Median Luma Filter Maximum";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ return "Median Luma Filter Minimum";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ return "Median Chroma Filter Maximum";
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ return "Median Chroma Filter Minimum";
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ return "Insert Navigation Packets";
+ }
+ return NULL;
+}
+
+static const char **cx2341x_get_menu(u32 id)
+{
+ static const char *cx2341x_video_spatial_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ "1D Vertical",
+ "2D H/V Separable",
+ "2D Symmetric non-separable",
+ NULL
+ };
+
+ static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
+ "Off",
+ "1D Horizontal",
+ NULL
+ };
+
+ static const char *cx2341x_video_temporal_filter_mode_menu[] = {
+ "Manual",
+ "Auto",
+ NULL
+ };
+
+ static const char *cx2341x_video_median_filter_type_menu[] = {
+ "Off",
+ "Horizontal",
+ "Vertical",
+ "Horizontal/Vertical",
+ "Diagonal",
+ NULL
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ return cx2341x_video_spatial_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_luma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ return cx2341x_video_chroma_spatial_filter_type_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ return cx2341x_video_temporal_filter_mode_menu;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ return cx2341x_video_median_filter_type_menu;
+ }
+ return NULL;
+}
+
+static void cx2341x_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
+ s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags)
+{
+ *name = cx2341x_get_name(id);
+ *flags = 0;
+
+ switch (id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ *type = V4L2_CTRL_TYPE_MENU;
+ *min = 0;
+ *step = 0;
+ break;
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ *type = V4L2_CTRL_TYPE_BOOLEAN;
+ *min = 0;
+ *max = *step = 1;
+ break;
+ default:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (id) {
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
+ *flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
+ case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
+ *flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ break;
+ }
+}
+
+
+/********************** OLD CODE *********************/
+
/* Must be sorted from low to high control ID! */
const u32 cx2341x_mpeg_ctrls[] = {
V4L2_CID_MPEG_CLASS,
@@ -134,8 +273,6 @@ static const struct cx2341x_mpeg_params default_params = {
.video_chroma_median_filter_top = 255,
.video_chroma_median_filter_bottom = 0,
};
-
-
/* Map the control ID to the correct field in the cx2341x_mpeg_params
struct. Return -EINVAL if the ID is unknown, else return 0. */
static int cx2341x_get_ctrl(const struct cx2341x_mpeg_params *params,
@@ -415,83 +552,33 @@ static int cx2341x_ctrl_query_fill(struct v4l2_queryctrl *qctrl,
{
const char *name;
- qctrl->flags = 0;
switch (qctrl->id) {
/* MPEG controls */
case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
- name = "Spatial Filter Mode";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
- name = "Spatial Filter";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
- name = "Spatial Luma Filter Type";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
- name = "Spatial Chroma Filter Type";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
- name = "Temporal Filter Mode";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER:
- name = "Temporal Filter";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
- name = "Median Filter Type";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
- name = "Median Luma Filter Maximum";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM:
- name = "Median Luma Filter Minimum";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP:
- name = "Median Chroma Filter Maximum";
- break;
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM:
- name = "Median Chroma Filter Minimum";
- break;
case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
- name = "Insert Navigation Packets";
- break;
+ cx2341x_ctrl_fill(qctrl->id, &name, &qctrl->type,
+ &min, &max, &step, &def, &qctrl->flags);
+ qctrl->minimum = min;
+ qctrl->maximum = max;
+ qctrl->step = step;
+ qctrl->default_value = def;
+ qctrl->reserved[0] = qctrl->reserved[1] = 0;
+ strlcpy(qctrl->name, name, sizeof(qctrl->name));
+ return 0;
default:
return v4l2_ctrl_query_fill(qctrl, min, max, step, def);
}
- switch (qctrl->id) {
- case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
- case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
- case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
- case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
- case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
- qctrl->type = V4L2_CTRL_TYPE_MENU;
- min = 0;
- step = 1;
- break;
- case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
- qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
- min = 0;
- max = 1;
- step = 1;
- break;
- default:
- qctrl->type = V4L2_CTRL_TYPE_INTEGER;
- break;
- }
- switch (qctrl->id) {
- case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
- case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
- case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
- qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
- break;
- }
- qctrl->minimum = min;
- qctrl->maximum = max;
- qctrl->step = step;
- qctrl->default_value = def;
- qctrl->reserved[0] = qctrl->reserved[1] = 0;
- snprintf(qctrl->name, sizeof(qctrl->name), name);
- return 0;
}
int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
@@ -766,9 +853,9 @@ int cx2341x_ctrl_query(const struct cx2341x_mpeg_params *params,
}
EXPORT_SYMBOL(cx2341x_ctrl_query);
-const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
+const char * const *cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
{
- static const char *mpeg_stream_type_without_ts[] = {
+ static const char * const mpeg_stream_type_without_ts[] = {
"MPEG-2 Program Stream",
"",
"MPEG-1 System Stream",
@@ -797,42 +884,6 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
NULL
};
- static const char *cx2341x_video_spatial_filter_mode_menu[] = {
- "Manual",
- "Auto",
- NULL
- };
-
- static const char *cx2341x_video_luma_spatial_filter_type_menu[] = {
- "Off",
- "1D Horizontal",
- "1D Vertical",
- "2D H/V Separable",
- "2D Symmetric non-separable",
- NULL
- };
-
- static const char *cx2341x_video_chroma_spatial_filter_type_menu[] = {
- "Off",
- "1D Horizontal",
- NULL
- };
-
- static const char *cx2341x_video_temporal_filter_mode_menu[] = {
- "Manual",
- "Auto",
- NULL
- };
-
- static const char *cx2341x_video_median_filter_type_menu[] = {
- "Off",
- "Horizontal",
- "Vertical",
- "Horizontal/Vertical",
- "Diagonal",
- NULL
- };
-
switch (id) {
case V4L2_CID_MPEG_STREAM_TYPE:
return (p->capabilities & CX2341X_CAP_HAS_TS) ?
@@ -844,26 +895,17 @@ const char **cx2341x_ctrl_get_menu(const struct cx2341x_mpeg_params *p, u32 id)
case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
return NULL;
case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE:
- return cx2341x_video_spatial_filter_mode_menu;
case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
- return cx2341x_video_luma_spatial_filter_type_menu;
case V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE:
- return cx2341x_video_chroma_spatial_filter_type_menu;
case V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE:
- return cx2341x_video_temporal_filter_mode_menu;
case V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE:
- return cx2341x_video_median_filter_type_menu;
+ return cx2341x_get_menu(id);
default:
return v4l2_ctrl_get_menu(id);
}
}
EXPORT_SYMBOL(cx2341x_ctrl_get_menu);
-/* definitions for audio properties bits 29-28 */
-#define CX2341X_AUDIO_ENCODING_METHOD_MPEG 0
-#define CX2341X_AUDIO_ENCODING_METHOD_AC3 1
-#define CX2341X_AUDIO_ENCODING_METHOD_LPCM 2
-
static void cx2341x_calc_audio_properties(struct cx2341x_mpeg_params *params)
{
params->audio_properties =
@@ -910,7 +952,7 @@ int cx2341x_ext_ctrls(struct cx2341x_mpeg_params *params, int busy,
for (i = 0; i < ctrls->count; i++) {
struct v4l2_ext_control *ctrl = ctrls->controls + i;
struct v4l2_queryctrl qctrl;
- const char **menu_items = NULL;
+ const char * const *menu_items = NULL;
qctrl.id = ctrl->id;
err = cx2341x_ctrl_query(params, &qctrl);
@@ -1093,7 +1135,7 @@ EXPORT_SYMBOL(cx2341x_update);
static const char *cx2341x_menu_item(const struct cx2341x_mpeg_params *p, u32 id)
{
- const char **menu = cx2341x_ctrl_get_menu(p, id);
+ const char * const *menu = cx2341x_ctrl_get_menu(p, id);
struct v4l2_ext_control ctrl;
if (menu == NULL)
@@ -1113,7 +1155,6 @@ invalid:
void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
{
int is_mpeg1 = p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- int temporal = p->video_temporal_filter;
/* Stream */
printk(KERN_INFO "%s: Stream: %s",
@@ -1179,14 +1220,11 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE),
p->video_spatial_filter);
- if (p->width != 720 || p->height != (p->is_50hz ? 576 : 480))
- temporal = 0;
-
printk(KERN_INFO "%s: Temporal Filter: %s, %d\n",
prefix,
cx2341x_menu_item(p,
V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE),
- temporal);
+ p->video_temporal_filter);
printk(KERN_INFO
"%s: Median Filter: %s, Luma [%d, %d], Chroma [%d, %d]\n",
prefix,
@@ -1199,9 +1237,490 @@ void cx2341x_log_status(const struct cx2341x_mpeg_params *p, const char *prefix)
}
EXPORT_SYMBOL(cx2341x_log_status);
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+
+/********************** NEW CODE *********************/
+
+static inline struct cx2341x_handler *to_cxhdl(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct cx2341x_handler, hdl);
+}
+
+static int cx2341x_hdl_api(struct cx2341x_handler *hdl,
+ u32 cmd, int args, ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i;
+
+ va_start(vargs, args);
+
+ for (i = 0; i < args; i++)
+ data[i] = va_arg(vargs, int);
+ va_end(vargs);
+ return hdl->func(hdl->priv, cmd, args, 0, data);
+}
+
+/* ctrl->handler->lock is held, so it is safe to access cur.val */
+static inline int cx2341x_neq(struct v4l2_ctrl *ctrl)
+{
+ return ctrl && ctrl->val != ctrl->cur.val;
+}
+
+static int cx2341x_try_ctrl(struct v4l2_ctrl *ctrl)
+{
+ struct cx2341x_handler *hdl = to_cxhdl(ctrl);
+ s32 val = ctrl->val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: {
+ /* video gop cluster */
+ int b = val + 1;
+ int gop = hdl->video_gop_size->val;
+
+ gop = b * ((gop + b - 1) / b);
+
+ /* Max GOP size = 34 */
+ while (gop > 34)
+ gop -= b;
+ hdl->video_gop_size->val = gop;
+ break;
+ }
+
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ /* stream type cluster */
+ hdl->video_encoding->val =
+ (hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_SS ||
+ hdl->stream_type->val == V4L2_MPEG_STREAM_TYPE_MPEG1_VCD) ?
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_1 :
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2;
+ if (hdl->video_encoding->val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ /* MPEG-1 implies CBR */
+ hdl->video_bitrate_mode->val =
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ /* peak bitrate shall be >= normal bitrate */
+ if (hdl->video_bitrate_mode->val == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR &&
+ hdl->video_bitrate_peak->val < hdl->video_bitrate->val)
+ hdl->video_bitrate_peak->val = hdl->video_bitrate->val;
+ break;
+ }
+ return 0;
+}
+
+static int cx2341x_s_ctrl(struct v4l2_ctrl *ctrl)
+{
+ static const int mpeg_stream_type[] = {
+ 0, /* MPEG-2 PS */
+ 1, /* MPEG-2 TS */
+ 2, /* MPEG-1 SS */
+ 14, /* DVD */
+ 11, /* VCD */
+ 12, /* SVCD */
+ };
+ struct cx2341x_handler *hdl = to_cxhdl(ctrl);
+ s32 val = ctrl->val;
+ u32 props;
+ int err;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_VBI_FMT:
+ if (hdl->ops && hdl->ops->s_stream_vbi_fmt)
+ return hdl->ops->s_stream_vbi_fmt(hdl, val);
+ return 0;
+
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_ASPECT_RATIO, 1, val + 1);
+
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE:
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_CLOSURE, 1, val);
+
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_AUDIO, 1, val);
+
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION:
+ return cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_FRAME_DROP_RATE, 1, val);
+
+ case V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS:
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_MISC, 2, 7, val);
+
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ /* audio properties cluster */
+ props = (hdl->audio_sampling_freq->val << 0) |
+ (hdl->audio_mode->val << 8) |
+ (hdl->audio_mode_extension->val << 10) |
+ (hdl->audio_crc->val << 14);
+ if (hdl->audio_emphasis->val == V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17)
+ props |= 3 << 12;
+ else
+ props |= hdl->audio_emphasis->val << 12;
+
+ if (hdl->audio_encoding->val == V4L2_MPEG_AUDIO_ENCODING_AC3) {
+ props |=
+#if 1
+ /* Not sure if this MPEG Layer II setting is required */
+ ((3 - V4L2_MPEG_AUDIO_ENCODING_LAYER_2) << 2) |
+#endif
+ (hdl->audio_ac3_bitrate->val << 4) |
+ (CX2341X_AUDIO_ENCODING_METHOD_AC3 << 28);
+ } else {
+ /* Assuming MPEG Layer II */
+ props |=
+ ((3 - hdl->audio_encoding->val) << 2) |
+ ((1 + hdl->audio_l2_bitrate->val) << 4);
+ }
+ err = cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, props);
+ if (err)
+ return err;
+
+ hdl->audio_properties = props;
+ if (hdl->audio_ac3_bitrate) {
+ int is_ac3 = hdl->audio_encoding->val ==
+ V4L2_MPEG_AUDIO_ENCODING_AC3;
+
+ v4l2_ctrl_activate(hdl->audio_ac3_bitrate, is_ac3);
+ v4l2_ctrl_activate(hdl->audio_l2_bitrate, !is_ac3);
+ }
+ v4l2_ctrl_activate(hdl->audio_mode_extension,
+ hdl->audio_mode->val == V4L2_MPEG_AUDIO_MODE_JOINT_STEREO);
+ if (cx2341x_neq(hdl->audio_sampling_freq) &&
+ hdl->ops && hdl->ops->s_audio_sampling_freq)
+ return hdl->ops->s_audio_sampling_freq(hdl, hdl->audio_sampling_freq->val);
+ if (cx2341x_neq(hdl->audio_mode) &&
+ hdl->ops && hdl->ops->s_audio_mode)
+ return hdl->ops->s_audio_mode(hdl, hdl->audio_mode->val);
+ return 0;
+
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ /* video gop cluster */
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_GOP_PROPERTIES, 2,
+ hdl->video_gop_size->val,
+ hdl->video_b_frames->val + 1);
+
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ /* stream type cluster */
+ err = cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_STREAM_TYPE, 1, mpeg_stream_type[val]);
+ if (err)
+ return err;
+
+ err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_BIT_RATE, 5,
+ hdl->video_bitrate_mode->val,
+ hdl->video_bitrate->val,
+ hdl->video_bitrate_peak->val / 400, 0, 0);
+ if (err)
+ return err;
+
+ v4l2_ctrl_activate(hdl->video_bitrate_mode,
+ hdl->video_encoding->val != V4L2_MPEG_VIDEO_ENCODING_MPEG_1);
+ v4l2_ctrl_activate(hdl->video_bitrate_peak,
+ hdl->video_bitrate_mode->val != V4L2_MPEG_VIDEO_BITRATE_MODE_CBR);
+ if (cx2341x_neq(hdl->video_encoding) &&
+ hdl->ops && hdl->ops->s_video_encoding)
+ return hdl->ops->s_video_encoding(hdl, hdl->video_encoding->val);
+ return 0;
+
+ case V4L2_CID_MPEG_VIDEO_MUTE:
+ /* video mute cluster */
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_MUTE_VIDEO, 1,
+ hdl->video_mute->val |
+ (hdl->video_mute_yuv->val << 8));
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE: {
+ int active_filter;
+
+ /* video filter mode */
+ err = cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_MODE, 2,
+ hdl->video_spatial_filter_mode->val |
+ (hdl->video_temporal_filter_mode->val << 1),
+ hdl->video_median_filter_type->val);
+ if (err)
+ return err;
+
+ active_filter = hdl->video_spatial_filter_mode->val !=
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO;
+ v4l2_ctrl_activate(hdl->video_spatial_filter, active_filter);
+ v4l2_ctrl_activate(hdl->video_luma_spatial_filter_type, active_filter);
+ v4l2_ctrl_activate(hdl->video_chroma_spatial_filter_type, active_filter);
+ active_filter = hdl->video_temporal_filter_mode->val !=
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO;
+ v4l2_ctrl_activate(hdl->video_temporal_filter, active_filter);
+ active_filter = hdl->video_median_filter_type->val !=
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF;
+ v4l2_ctrl_activate(hdl->video_luma_median_filter_bottom, active_filter);
+ v4l2_ctrl_activate(hdl->video_luma_median_filter_top, active_filter);
+ v4l2_ctrl_activate(hdl->video_chroma_median_filter_bottom, active_filter);
+ v4l2_ctrl_activate(hdl->video_chroma_median_filter_top, active_filter);
+ return 0;
+ }
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE:
+ /* video filter type cluster */
+ return cx2341x_hdl_api(hdl,
+ CX2341X_ENC_SET_SPATIAL_FILTER_TYPE, 2,
+ hdl->video_luma_spatial_filter_type->val,
+ hdl->video_chroma_spatial_filter_type->val);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER:
+ /* video filter cluster */
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_DNR_FILTER_PROPS, 2,
+ hdl->video_spatial_filter->val,
+ hdl->video_temporal_filter->val);
+
+ case V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP:
+ /* video median cluster */
+ return cx2341x_hdl_api(hdl, CX2341X_ENC_SET_CORING_LEVELS, 4,
+ hdl->video_luma_median_filter_bottom->val,
+ hdl->video_luma_median_filter_top->val,
+ hdl->video_chroma_median_filter_bottom->val,
+ hdl->video_chroma_median_filter_top->val);
+ }
+ return -EINVAL;
+}
+
+static const struct v4l2_ctrl_ops cx2341x_ops = {
+ .try_ctrl = cx2341x_try_ctrl,
+ .s_ctrl = cx2341x_s_ctrl,
+};
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+ u32 id, s32 min, s32 max, s32 step, s32 def)
+{
+ struct v4l2_ctrl_config cfg;
+
+ cx2341x_ctrl_fill(id, &cfg.name, &cfg.type, &min, &max, &step, &def, &cfg.flags);
+ cfg.ops = &cx2341x_ops;
+ cfg.id = id;
+ cfg.min = min;
+ cfg.max = max;
+ cfg.def = def;
+ if (cfg.type == V4L2_CTRL_TYPE_MENU) {
+ cfg.step = 0;
+ cfg.menu_skip_mask = step;
+ cfg.qmenu = cx2341x_get_menu(id);
+ } else {
+ cfg.step = step;
+ cfg.menu_skip_mask = 0;
+ }
+ return v4l2_ctrl_new_custom(hdl, &cfg, NULL);
+}
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+ u32 id, s32 min, s32 max, s32 step, s32 def)
+{
+ return v4l2_ctrl_new_std(hdl, &cx2341x_ops, id, min, max, step, def);
+}
+
+static struct v4l2_ctrl *cx2341x_ctrl_new_menu(struct v4l2_ctrl_handler *hdl,
+ u32 id, s32 max, s32 mask, s32 def)
+{
+ return v4l2_ctrl_new_std_menu(hdl, &cx2341x_ops, id, max, mask, def);
+}
+
+int cx2341x_handler_init(struct cx2341x_handler *cxhdl,
+ unsigned nr_of_controls_hint)
+{
+ struct v4l2_ctrl_handler *hdl = &cxhdl->hdl;
+ u32 caps = cxhdl->capabilities;
+ int has_sliced_vbi = caps & CX2341X_CAP_HAS_SLICED_VBI;
+ int has_ac3 = caps & CX2341X_CAP_HAS_AC3;
+ int has_ts = caps & CX2341X_CAP_HAS_TS;
+
+ cxhdl->width = 720;
+ cxhdl->height = 480;
+
+ v4l2_ctrl_handler_init(hdl, nr_of_controls_hint);
+
+ /* Add controls in ascending control ID order for fastest
+ insertion time. */
+ cxhdl->stream_type = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_SVCD, has_ts ? 0 : 2,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+ cxhdl->stream_vbi_fmt = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_STREAM_VBI_FMT,
+ V4L2_MPEG_STREAM_VBI_FMT_IVTV, has_sliced_vbi ? 0 : 2,
+ V4L2_MPEG_STREAM_VBI_FMT_NONE);
+ cxhdl->audio_sampling_freq = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_32000, 0,
+ V4L2_MPEG_AUDIO_SAMPLING_FREQ_48000);
+ cxhdl->audio_encoding = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_ENCODING,
+ V4L2_MPEG_AUDIO_ENCODING_AC3, has_ac3 ? ~0x12 : ~0x2,
+ V4L2_MPEG_AUDIO_ENCODING_LAYER_2);
+ cxhdl->audio_l2_bitrate = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_L2_BITRATE,
+ V4L2_MPEG_AUDIO_L2_BITRATE_384K, 0x1ff,
+ V4L2_MPEG_AUDIO_L2_BITRATE_224K);
+ cxhdl->audio_mode = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_MODE,
+ V4L2_MPEG_AUDIO_MODE_MONO, 0,
+ V4L2_MPEG_AUDIO_MODE_STEREO);
+ cxhdl->audio_mode_extension = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_MODE_EXTENSION,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_16, 0,
+ V4L2_MPEG_AUDIO_MODE_EXTENSION_BOUND_4);
+ cxhdl->audio_emphasis = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_EMPHASIS,
+ V4L2_MPEG_AUDIO_EMPHASIS_CCITT_J17, 0,
+ V4L2_MPEG_AUDIO_EMPHASIS_NONE);
+ cxhdl->audio_crc = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_CRC,
+ V4L2_MPEG_AUDIO_CRC_CRC16, 0,
+ V4L2_MPEG_AUDIO_CRC_NONE);
+
+ cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_AUDIO_MUTE, 0, 1, 1, 0);
+ if (has_ac3)
+ cxhdl->audio_ac3_bitrate = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_AUDIO_AC3_BITRATE,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_448K, 0x03,
+ V4L2_MPEG_AUDIO_AC3_BITRATE_224K);
+ cxhdl->video_encoding = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_VIDEO_ENCODING,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2, 0,
+ V4L2_MPEG_VIDEO_ENCODING_MPEG_2);
+ cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_MPEG_VIDEO_ASPECT_221x100, 0,
+ V4L2_MPEG_VIDEO_ASPECT_4x3);
+ cxhdl->video_b_frames = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_B_FRAMES, 0, 33, 1, 2);
+ cxhdl->video_gop_size = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ 1, 34, 1, cxhdl->is_50hz ? 12 : 15);
+ cx2341x_ctrl_new_std(hdl, V4L2_CID_MPEG_VIDEO_GOP_CLOSURE, 0, 1, 1, 1);
+ cxhdl->video_bitrate_mode = cx2341x_ctrl_new_menu(hdl,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR, 0,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ cxhdl->video_bitrate = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ 0, 27000000, 1, 6000000);
+ cxhdl->video_bitrate_peak = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ 0, 27000000, 1, 8000000);
+ cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION, 0, 255, 1, 0);
+ cxhdl->video_mute = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_MUTE, 0, 1, 1, 0);
+ cxhdl->video_mute_yuv = cx2341x_ctrl_new_std(hdl,
+ V4L2_CID_MPEG_VIDEO_MUTE_YUV, 0, 0xffffff, 1, 0x008080);
+
+ /* CX23415/6 specific */
+ cxhdl->video_spatial_filter_mode = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_AUTO, 0,
+ V4L2_MPEG_CX2341X_VIDEO_SPATIAL_FILTER_MODE_MANUAL);
+ cxhdl->video_spatial_filter = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_SPATIAL_FILTER,
+ 0, 15, 1, 0);
+ cxhdl->video_luma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_2D_SYM_NON_SEPARABLE,
+ 0,
+ V4L2_MPEG_CX2341X_VIDEO_LUMA_SPATIAL_FILTER_TYPE_1D_HOR);
+ cxhdl->video_chroma_spatial_filter_type = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR,
+ 0,
+ V4L2_MPEG_CX2341X_VIDEO_CHROMA_SPATIAL_FILTER_TYPE_1D_HOR);
+ cxhdl->video_temporal_filter_mode = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_AUTO,
+ 0,
+ V4L2_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER_MODE_MANUAL);
+ cxhdl->video_temporal_filter = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_TEMPORAL_FILTER,
+ 0, 31, 1, 8);
+ cxhdl->video_median_filter_type = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_DIAG,
+ 0,
+ V4L2_MPEG_CX2341X_VIDEO_MEDIAN_FILTER_TYPE_OFF);
+ cxhdl->video_luma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_BOTTOM,
+ 0, 255, 1, 0);
+ cxhdl->video_luma_median_filter_top = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_LUMA_MEDIAN_FILTER_TOP,
+ 0, 255, 1, 255);
+ cxhdl->video_chroma_median_filter_bottom = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_BOTTOM,
+ 0, 255, 1, 0);
+ cxhdl->video_chroma_median_filter_top = cx2341x_ctrl_new_custom(hdl,
+ V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP,
+ 0, 255, 1, 255);
+ cx2341x_ctrl_new_custom(hdl, V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS,
+ 0, 1, 1, 0);
+
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ return err;
+ }
+
+ v4l2_ctrl_cluster(8, &cxhdl->audio_sampling_freq);
+ v4l2_ctrl_cluster(2, &cxhdl->video_b_frames);
+ v4l2_ctrl_cluster(5, &cxhdl->stream_type);
+ v4l2_ctrl_cluster(2, &cxhdl->video_mute);
+ v4l2_ctrl_cluster(3, &cxhdl->video_spatial_filter_mode);
+ v4l2_ctrl_cluster(2, &cxhdl->video_luma_spatial_filter_type);
+ v4l2_ctrl_cluster(2, &cxhdl->video_spatial_filter);
+ v4l2_ctrl_cluster(4, &cxhdl->video_luma_median_filter_top);
+
+ return 0;
+}
+EXPORT_SYMBOL(cx2341x_handler_init);
+
+void cx2341x_handler_set_50hz(struct cx2341x_handler *cxhdl, int is_50hz)
+{
+ cxhdl->is_50hz = is_50hz;
+ cxhdl->video_gop_size->default_value = cxhdl->is_50hz ? 12 : 15;
+}
+EXPORT_SYMBOL(cx2341x_handler_set_50hz);
+
+int cx2341x_handler_setup(struct cx2341x_handler *cxhdl)
+{
+ int h = cxhdl->height;
+ int w = cxhdl->width;
+ int err;
+
+ err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_OUTPUT_PORT, 2, cxhdl->port, 0);
+ if (err)
+ return err;
+ err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_RATE, 1, cxhdl->is_50hz);
+ if (err)
+ return err;
+
+ if (v4l2_ctrl_g_ctrl(cxhdl->video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1) {
+ w /= 2;
+ h /= 2;
+ }
+ err = cx2341x_hdl_api(cxhdl, CX2341X_ENC_SET_FRAME_SIZE, 2, h, w);
+ if (err)
+ return err;
+ return v4l2_ctrl_handler_setup(&cxhdl->hdl);
+}
+EXPORT_SYMBOL(cx2341x_handler_setup);
+
+void cx2341x_handler_set_busy(struct cx2341x_handler *cxhdl, int busy)
+{
+ v4l2_ctrl_grab(cxhdl->audio_sampling_freq, busy);
+ v4l2_ctrl_grab(cxhdl->audio_encoding, busy);
+ v4l2_ctrl_grab(cxhdl->audio_l2_bitrate, busy);
+ v4l2_ctrl_grab(cxhdl->audio_ac3_bitrate, busy);
+ v4l2_ctrl_grab(cxhdl->stream_vbi_fmt, busy);
+ v4l2_ctrl_grab(cxhdl->stream_type, busy);
+ v4l2_ctrl_grab(cxhdl->video_bitrate_mode, busy);
+ v4l2_ctrl_grab(cxhdl->video_bitrate, busy);
+ v4l2_ctrl_grab(cxhdl->video_bitrate_peak, busy);
+}
+EXPORT_SYMBOL(cx2341x_handler_set_busy);
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index bcdda9a9aa96..6b4a516addfe 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -5,7 +5,7 @@ config VIDEO_CX23885
select VIDEO_BTCX
select VIDEO_TUNER
select VIDEO_TVEEPROM
- select VIDEO_IR
+ depends on RC_CORE
select VIDEOBUF_DVB
select VIDEOBUF_DMA_SG
select VIDEO_CX25840
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
index 5787ae243631..e2ee95f660d8 100644
--- a/drivers/media/video/cx23885/Makefile
+++ b/drivers/media/video/cx23885/Makefile
@@ -1,7 +1,8 @@
cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o \
cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o \
- cx23885-ioctl.o cx23885-ir.o cx23885-input.o cx23888-ir.o \
- netup-init.o cimax2.o netup-eeprom.o cx23885-f300.o
+ cx23885-ioctl.o cx23885-ir.o cx23885-av.o cx23885-input.o \
+ cx23888-ir.o netup-init.o cimax2.o netup-eeprom.o \
+ cx23885-f300.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
diff --git a/drivers/media/video/cx23885/cimax2.c b/drivers/media/video/cx23885/cimax2.c
index c95e7bc14745..209b971bd267 100644
--- a/drivers/media/video/cx23885/cimax2.c
+++ b/drivers/media/video/cx23885/cimax2.c
@@ -368,7 +368,7 @@ static void netup_read_ci_status(struct work_struct *work)
DVB_CA_EN50221_POLL_CAM_READY;
else
state->status = 0;
- };
+ }
}
/* CI irq handler */
@@ -377,16 +377,24 @@ int netup_ci_slot_status(struct cx23885_dev *dev, u32 pci_status)
struct cx23885_tsport *port = NULL;
struct netup_ci_state *state = NULL;
- if (pci_status & PCI_MSK_GPIO0)
- port = &dev->ts1;
- else if (pci_status & PCI_MSK_GPIO1)
- port = &dev->ts2;
- else /* who calls ? */
+ ci_dbg_print("%s:\n", __func__);
+
+ if (0 == (pci_status & (PCI_MSK_GPIO0 | PCI_MSK_GPIO1)))
return 0;
- state = port->port_priv;
+ if (pci_status & PCI_MSK_GPIO0) {
+ port = &dev->ts1;
+ state = port->port_priv;
+ schedule_work(&state->work);
+ ci_dbg_print("%s: Wakeup CI0\n", __func__);
+ }
- schedule_work(&state->work);
+ if (pci_status & PCI_MSK_GPIO1) {
+ port = &dev->ts2;
+ state = port->port_priv;
+ schedule_work(&state->work);
+ ci_dbg_print("%s: Wakeup CI1\n", __func__);
+ }
return 1;
}
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
index abd64e89f60f..9a98dc55f657 100644
--- a/drivers/media/video/cx23885/cx23885-417.c
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -7,7 +7,7 @@
* (c) 2008 Steven Toth <stoth@linuxtv.org>
* - CX23885/7/8 support
*
- * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
*
* 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
@@ -31,7 +31,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include <linux/slab.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
@@ -1576,12 +1575,8 @@ static int mpeg_open(struct file *file)
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
- if (NULL == fh) {
- unlock_kernel();
+ if (!fh)
return -ENOMEM;
- }
-
- lock_kernel();
file->private_data = fh;
fh->dev = dev;
@@ -1591,9 +1586,7 @@ static int mpeg_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx23885_buffer),
- fh);
- unlock_kernel();
-
+ fh, NULL);
return 0;
}
diff --git a/drivers/media/video/cx23885/cx23885-av.c b/drivers/media/video/cx23885/cx23885-av.c
new file mode 100644
index 000000000000..134ebddd860f
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-av.c
@@ -0,0 +1,35 @@
+/*
+ * Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ * AV device support routines - non-input, non-vl42_subdev routines
+ *
+ * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include "cx23885.h"
+
+void cx23885_av_work_handler(struct work_struct *work)
+{
+ struct cx23885_dev *dev =
+ container_of(work, struct cx23885_dev, cx25840_work);
+ bool handled;
+
+ v4l2_subdev_call(dev->sd_cx25840, core, interrupt_service_routine,
+ PCI_MSK_AV_CORE, &handled);
+ cx23885_irq_enable(dev, PCI_MSK_AV_CORE);
+}
diff --git a/drivers/media/video/cx23885/cx23885-av.h b/drivers/media/video/cx23885/cx23885-av.h
new file mode 100644
index 000000000000..d2915c3e53a2
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-av.h
@@ -0,0 +1,27 @@
+/*
+ * Driver for the Conexant CX23885/7/8 PCIe bridge
+ *
+ * AV device support routines - non-input, non-vl42_subdev routines
+ *
+ * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#ifndef _CX23885_AV_H_
+#define _CX23885_AV_H_
+void cx23885_av_work_handler(struct work_struct *work);
+#endif
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index d639186f645d..b298b730943c 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -30,6 +30,16 @@
#include "netup-init.h"
#include "cx23888-ir.h"
+static unsigned int enable_885_ir;
+module_param(enable_885_ir, int, 0644);
+MODULE_PARM_DESC(enable_885_ir,
+ "Enable integrated IR controller for supported\n"
+ "\t\t CX2388[57] boards that are wired for it:\n"
+ "\t\t\tHVR-1250 (reported safe)\n"
+ "\t\t\tTeVii S470 (reported unsafe)\n"
+ "\t\t This can cause an interrupt storm with some cards.\n"
+ "\t\t Default: 0 [Disabled]");
+
/* ------------------------------------------------------------------ */
/* board config info */
@@ -299,6 +309,26 @@ struct cx23885_board cx23885_boards[] = {
CX25840_COMPONENT_ON,
} },
},
+ [CX23885_BOARD_GOTVIEW_X5_3D_HYBRID] = {
+ .name = "GoTView X5 3D Hybrid",
+ .tuner_type = TUNER_XC5000,
+ .tuner_addr = 0x64,
+ .porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_DVB,
+ .input = {{
+ .type = CX23885_VMUX_TELEVISION,
+ .vmux = CX25840_VIN2_CH1 |
+ CX25840_VIN5_CH2,
+ .gpio0 = 0x02,
+ }, {
+ .type = CX23885_VMUX_COMPOSITE1,
+ .vmux = CX23885_VMUX_COMPOSITE1,
+ }, {
+ .type = CX23885_VMUX_SVIDEO,
+ .vmux = CX25840_SVIDEO_LUMA3 |
+ CX25840_SVIDEO_CHROMA4,
+ } },
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -408,10 +438,18 @@ struct cx23885_subid cx23885_subids[] = {
.card = CX23885_BOARD_HAUPPAUGE_HVR1275,
}, {
.subvendor = 0x0070,
+ .subdevice = 0x221d,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
+ }, {
+ .subvendor = 0x0070,
.subdevice = 0x2251,
.card = CX23885_BOARD_HAUPPAUGE_HVR1255,
}, {
.subvendor = 0x0070,
+ .subdevice = 0x2259,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
+ }, {
+ .subvendor = 0x0070,
.subdevice = 0x2291,
.card = CX23885_BOARD_HAUPPAUGE_HVR1210,
}, {
@@ -419,6 +457,38 @@ struct cx23885_subid cx23885_subids[] = {
.subdevice = 0x2295,
.card = CX23885_BOARD_HAUPPAUGE_HVR1210,
}, {
+ .subvendor = 0x0070,
+ .subdevice = 0x2299,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x229d,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f0,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f1,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1255,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f2,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1275,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f3,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f4,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x22f5,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1210, /* HVR1215 */
+ }, {
.subvendor = 0x14f1,
.subdevice = 0x8651,
.card = CX23885_BOARD_MYGICA_X8506,
@@ -446,6 +516,10 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x107d,
.subdevice = 0x6f22,
.card = CX23885_BOARD_LEADTEK_WINFAST_PXTV1200,
+ }, {
+ .subvendor = 0x5654,
+ .subdevice = 0x2390,
+ .card = CX23885_BOARD_GOTVIEW_X5_3D_HYBRID,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -586,6 +660,9 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
case 79101:
/* WinTV-HVR1250 (PCIe, Retail, IR, half height,
ATSC and Basic analog */
+ case 79501:
+ /* WinTV-HVR1250 (PCIe, No IR, half height,
+ ATSC [at least] and Basic analog) */
case 79561:
/* WinTV-HVR1250 (PCIe, OEM, No IR, half height,
ATSC and Basic analog */
@@ -659,6 +736,10 @@ int cx23885_tuner_callback(void *priv, int component, int command, int arg)
else if (port->nr == 2)
bitmask = 0x04;
break;
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+ /* Tuner Reset Command */
+ bitmask = 0x02;
+ break;
}
if (bitmask) {
@@ -914,14 +995,45 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
/* CX24228 GPIO */
/* Connected to IF / Mux */
break;
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
+ cx_set(GP0_IO, 0x00010001); /* Bring the part out of reset */
+ break;
}
}
int cx23885_ir_init(struct cx23885_dev *dev)
{
+ static struct v4l2_subdev_io_pin_config ir_rxtx_pin_cfg[] = {
+ {
+ .flags = V4L2_SUBDEV_IO_PIN_INPUT,
+ .pin = CX23885_PIN_IR_RX_GPIO19,
+ .function = CX23885_PAD_IR_RX,
+ .value = 0,
+ .strength = CX25840_PIN_DRIVE_MEDIUM,
+ }, {
+ .flags = V4L2_SUBDEV_IO_PIN_OUTPUT,
+ .pin = CX23885_PIN_IR_TX_GPIO20,
+ .function = CX23885_PAD_IR_TX,
+ .value = 0,
+ .strength = CX25840_PIN_DRIVE_MEDIUM,
+ }
+ };
+ const size_t ir_rxtx_pin_cfg_count = ARRAY_SIZE(ir_rxtx_pin_cfg);
+
+ static struct v4l2_subdev_io_pin_config ir_rx_pin_cfg[] = {
+ {
+ .flags = V4L2_SUBDEV_IO_PIN_INPUT,
+ .pin = CX23885_PIN_IR_RX_GPIO19,
+ .function = CX23885_PAD_IR_RX,
+ .value = 0,
+ .strength = CX25840_PIN_DRIVE_MEDIUM,
+ }
+ };
+ const size_t ir_rx_pin_cfg_count = ARRAY_SIZE(ir_rx_pin_cfg);
+
+ struct v4l2_subdev_ir_parameters params;
int ret = 0;
switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
case CX23885_BOARD_HAUPPAUGE_HVR1800:
@@ -939,7 +1051,41 @@ int cx23885_ir_init(struct cx23885_dev *dev)
if (ret)
break;
dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_888_IR);
- dev->pci_irqmask |= PCI_MSK_IR;
+ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+ ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
+ /*
+ * For these boards we need to invert the Tx output via the
+ * IR controller to have the LED off while idle
+ */
+ v4l2_subdev_call(dev->sd_ir, ir, tx_g_parameters, &params);
+ params.enable = false;
+ params.shutdown = false;
+ params.invert_level = true;
+ v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
+ params.shutdown = true;
+ v4l2_subdev_call(dev->sd_ir, ir, tx_s_parameters, &params);
+ break;
+ case CX23885_BOARD_TEVII_S470:
+ if (!enable_885_ir)
+ break;
+ dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+ if (dev->sd_ir == NULL) {
+ ret = -ENODEV;
+ break;
+ }
+ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+ ir_rx_pin_cfg_count, ir_rx_pin_cfg);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ if (!enable_885_ir)
+ break;
+ dev->sd_ir = cx23885_find_hw(dev, CX23885_HW_AV_CORE);
+ if (dev->sd_ir == NULL) {
+ ret = -ENODEV;
+ break;
+ }
+ v4l2_subdev_call(dev->sd_cx25840, core, s_io_pin_config,
+ ir_rxtx_pin_cfg_count, ir_rxtx_pin_cfg);
break;
case CX23885_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL_EXP:
request_module("ir-kbd-i2c");
@@ -954,11 +1100,16 @@ void cx23885_ir_fini(struct cx23885_dev *dev)
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
- dev->pci_irqmask &= ~PCI_MSK_IR;
- cx_clear(PCI_INT_MSK, PCI_MSK_IR);
+ cx23885_irq_remove(dev, PCI_MSK_IR);
cx23888_ir_remove(dev);
dev->sd_ir = NULL;
break;
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ cx23885_irq_remove(dev, PCI_MSK_AV_CORE);
+ /* sd_ir is a duplicate pointer to the AV Core, just clear it */
+ dev->sd_ir = NULL;
+ break;
}
}
@@ -967,8 +1118,13 @@ void cx23885_ir_pci_int_enable(struct cx23885_dev *dev)
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
- if (dev->sd_ir && (dev->pci_irqmask & PCI_MSK_IR))
- cx_set(PCI_INT_MSK, PCI_MSK_IR);
+ if (dev->sd_ir)
+ cx23885_irq_add_enable(dev, PCI_MSK_IR);
+ break;
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ if (dev->sd_ir)
+ cx23885_irq_add_enable(dev, PCI_MSK_AV_CORE);
break;
}
}
@@ -988,6 +1144,13 @@ void cx23885_card_setup(struct cx23885_dev *dev)
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ if (dev->i2c_bus[0].i2c_rc == 0) {
+ if (eeprom[0x80] != 0x84)
+ hauppauge_eeprom(dev, eeprom+0xc0);
+ else
+ hauppauge_eeprom(dev, eeprom+0x80);
+ }
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
case CX23885_BOARD_HAUPPAUGE_HVR1400:
@@ -1086,6 +1249,7 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_COMPRO_VIDEOMATE_E800:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
default:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
@@ -1096,6 +1260,11 @@ void cx23885_card_setup(struct cx23885_dev *dev)
* loaded, ensure this happens.
*/
switch (dev->board) {
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ /* Currently only enabled for the integrated IR controller */
+ if (!enable_885_ir)
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1800:
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
case CX23885_BOARD_HAUPPAUGE_HVR1700:
@@ -1108,10 +1277,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_MAGICPRO_PROHDTVE2:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
case CX23885_BOARD_LEADTEK_WINFAST_PXTV1200:
+ case CX23885_BOARD_GOTVIEW_X5_3D_HYBRID:
dev->sd_cx25840 = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[2].i2c_adap,
- "cx25840", "cx25840", 0x88 >> 1, NULL);
- v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
+ "cx25840", 0x88 >> 1, NULL);
+ if (dev->sd_cx25840) {
+ dev->sd_cx25840->grp_id = CX23885_HW_AV_CORE;
+ v4l2_subdev_call(dev->sd_cx25840, core, load_fw);
+ }
break;
}
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 0dde57e96d30..359882419b7f 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -34,6 +34,7 @@
#include "cimax2.h"
#include "cx23888-ir.h"
#include "cx23885-ir.h"
+#include "cx23885-av.h"
#include "cx23885-input.h"
MODULE_DESCRIPTION("Driver for cx23885 based TV cards");
@@ -299,6 +300,83 @@ static struct sram_channel cx23887_sram_channels[] = {
},
};
+void cx23885_irq_add(struct cx23885_dev *dev, u32 mask)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+ dev->pci_irqmask |= mask;
+
+ spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+ dev->pci_irqmask |= mask;
+ cx_set(PCI_INT_MSK, mask);
+
+ spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask)
+{
+ u32 v;
+ unsigned long flags;
+ spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+ v = mask & dev->pci_irqmask;
+ if (v)
+ cx_set(PCI_INT_MSK, v);
+
+ spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+static inline void cx23885_irq_enable_all(struct cx23885_dev *dev)
+{
+ cx23885_irq_enable(dev, 0xffffffff);
+}
+
+void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+ cx_clear(PCI_INT_MSK, mask);
+
+ spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+static inline void cx23885_irq_disable_all(struct cx23885_dev *dev)
+{
+ cx23885_irq_disable(dev, 0xffffffff);
+}
+
+void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask)
+{
+ unsigned long flags;
+ spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+ dev->pci_irqmask &= ~mask;
+ cx_clear(PCI_INT_MSK, mask);
+
+ spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+}
+
+static u32 cx23885_irq_get_mask(struct cx23885_dev *dev)
+{
+ u32 v;
+ unsigned long flags;
+ spin_lock_irqsave(&dev->pci_irqmask_lock, flags);
+
+ v = cx_read(PCI_INT_MSK);
+
+ spin_unlock_irqrestore(&dev->pci_irqmask_lock, flags);
+ return v;
+}
+
static int cx23885_risc_decode(u32 risc)
{
static char *instr[16] = {
@@ -548,7 +626,7 @@ static void cx23885_shutdown(struct cx23885_dev *dev)
cx_write(UART_CTL, 0);
/* Disable Interrupts */
- cx_write(PCI_INT_MSK, 0);
+ cx23885_irq_disable_all(dev);
cx_write(VID_A_INT_MSK, 0);
cx_write(VID_B_INT_MSK, 0);
cx_write(VID_C_INT_MSK, 0);
@@ -737,6 +815,7 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
case 0x0e:
/* CX23887-15Z */
dev->hwrevision = 0xc0;
+ break;
case 0x0f:
/* CX23887-14Z */
dev->hwrevision = 0xb1;
@@ -774,6 +853,8 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
{
int i;
+ spin_lock_init(&dev->pci_irqmask_lock);
+
mutex_init(&dev->lock);
mutex_init(&dev->gpio_lock);
@@ -820,9 +901,9 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dev->pci_bus = dev->pci->bus->number;
dev->pci_slot = PCI_SLOT(dev->pci->devfn);
- dev->pci_irqmask = 0x001f00;
+ cx23885_irq_add(dev, 0x001f00);
if (cx23885_boards[dev->board].cimax > 0)
- dev->pci_irqmask |= 0x01800000; /* for CiMaxes */
+ cx23885_irq_add(dev, 0x01800000); /* for CiMaxes */
/* External Master 1 Bus */
dev->i2c_bus[0].nr = 0;
@@ -1141,8 +1222,8 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb, 0, 0);
- videobuf_dma_unmap(q, dma);
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -1156,7 +1237,7 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__,
cx_read(DEV_CNTRL2));
dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__,
- cx_read(PCI_INT_MSK));
+ cx23885_irq_get_mask(dev));
dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__,
cx_read(AUDIO_INT_INT_MSK));
dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__,
@@ -1292,7 +1373,8 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
dprintk(1, "%s() enabling TS int's and DMA\n", __func__);
cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_set(port->reg_dma_ctl, port->dma_ctl_val);
- cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
+ cx23885_irq_add(dev, port->pci_irqmask);
+ cx23885_irq_enable_all(dev);
break;
default:
BUG();
@@ -1650,10 +1732,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
u32 ts1_status, ts1_mask;
u32 ts2_status, ts2_mask;
int vida_count = 0, ts1_count = 0, ts2_count = 0, handled = 0;
- bool ir_handled = false;
+ bool subdev_handled;
pci_status = cx_read(PCI_INT_STAT);
- pci_mask = cx_read(PCI_INT_MSK);
+ pci_mask = cx23885_irq_get_mask(dev);
vida_status = cx_read(VID_A_INT_STAT);
vida_mask = cx_read(VID_A_INT_MSK);
ts1_status = cx_read(VID_B_INT_STAT);
@@ -1681,7 +1763,7 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
PCI_MSK_VID_C | PCI_MSK_VID_B | PCI_MSK_VID_A |
PCI_MSK_AUD_INT | PCI_MSK_AUD_EXT |
PCI_MSK_GPIO0 | PCI_MSK_GPIO1 |
- PCI_MSK_IR)) {
+ PCI_MSK_AV_CORE | PCI_MSK_IR)) {
if (pci_status & PCI_MSK_RISC_RD)
dprintk(7, " (PCI_MSK_RISC_RD 0x%08x)\n",
@@ -1731,6 +1813,10 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
dprintk(7, " (PCI_MSK_GPIO1 0x%08x)\n",
PCI_MSK_GPIO1);
+ if (pci_status & PCI_MSK_AV_CORE)
+ dprintk(7, " (PCI_MSK_AV_CORE 0x%08x)\n",
+ PCI_MSK_AV_CORE);
+
if (pci_status & PCI_MSK_IR)
dprintk(7, " (PCI_MSK_IR 0x%08x)\n",
PCI_MSK_IR);
@@ -1765,12 +1851,22 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
handled += cx23885_video_irq(dev, vida_status);
if (pci_status & PCI_MSK_IR) {
- v4l2_subdev_call(dev->sd_ir, ir, interrupt_service_routine,
- pci_status, &ir_handled);
- if (ir_handled)
+ subdev_handled = false;
+ v4l2_subdev_call(dev->sd_ir, core, interrupt_service_routine,
+ pci_status, &subdev_handled);
+ if (subdev_handled)
handled++;
}
+ if ((pci_status & pci_mask) & PCI_MSK_AV_CORE) {
+ cx23885_irq_disable(dev, PCI_MSK_AV_CORE);
+ if (!schedule_work(&dev->cx25840_work))
+ printk(KERN_ERR "%s: failed to set up deferred work for"
+ " AV Core/IR interrupt. Interrupt is disabled"
+ " and won't be re-enabled\n", dev->name);
+ handled++;
+ }
+
if (handled)
cx_write(PCI_INT_STAT, pci_status);
out:
@@ -1788,11 +1884,11 @@ static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
dev = to_cx23885(sd->v4l2_dev);
switch (notification) {
- case V4L2_SUBDEV_IR_RX_NOTIFY: /* Called in an IRQ context */
+ case V4L2_SUBDEV_IR_RX_NOTIFY: /* Possibly called in an IRQ context */
if (sd == dev->sd_ir)
cx23885_ir_rx_v4l2_dev_notify(sd, *(u32 *)arg);
break;
- case V4L2_SUBDEV_IR_TX_NOTIFY: /* Called in an IRQ context */
+ case V4L2_SUBDEV_IR_TX_NOTIFY: /* Possibly called in an IRQ context */
if (sd == dev->sd_ir)
cx23885_ir_tx_v4l2_dev_notify(sd, *(u32 *)arg);
break;
@@ -1801,6 +1897,7 @@ static void cx23885_v4l2_dev_notify(struct v4l2_subdev *sd,
static void cx23885_v4l2_dev_notify_init(struct cx23885_dev *dev)
{
+ INIT_WORK(&dev->cx25840_work, cx23885_av_work_handler);
INIT_WORK(&dev->ir_rx_work, cx23885_ir_rx_work_handler);
INIT_WORK(&dev->ir_tx_work, cx23885_ir_tx_work_handler);
dev->v4l2_dev.notify = cx23885_v4l2_dev_notify;
@@ -1953,8 +2050,12 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
goto fail_irq;
}
- err = request_irq(pci_dev->irq, cx23885_irq,
- IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
+ if (!pci_enable_msi(pci_dev))
+ err = request_irq(pci_dev->irq, cx23885_irq,
+ IRQF_DISABLED, dev->name, dev);
+ else
+ err = request_irq(pci_dev->irq, cx23885_irq,
+ IRQF_SHARED | IRQF_DISABLED, dev->name, dev);
if (err < 0) {
printk(KERN_ERR "%s: can't get IRQ %d\n",
dev->name, pci_dev->irq);
@@ -1963,7 +2064,7 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
switch (dev->board) {
case CX23885_BOARD_NETUP_DUAL_DVBS2_CI:
- cx_set(PCI_INT_MSK, 0x01800000); /* for NetUP */
+ cx23885_irq_add_enable(dev, 0x01800000); /* for NetUP */
break;
}
@@ -2000,6 +2101,7 @@ static void __devexit cx23885_finidev(struct pci_dev *pci_dev)
/* unregister stuff */
free_irq(pci_dev->irq, dev);
+ pci_disable_msi(pci_dev);
cx23885_dev_unregister(dev);
v4l2_device_unregister(v4l2_dev);
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index 9e1460828b2f..5958cb882e93 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -991,6 +991,8 @@ static int dvb_register(struct cx23885_tsport *port)
ret = videobuf_dvb_register_bus(&port->frontends, THIS_MODULE, port,
&dev->pci->dev, adapter_nr, 0,
cx23885_dvb_fe_ioctl_override);
+ if (ret)
+ return ret;
/* init CI & MAC */
switch (dev->board) {
@@ -1015,10 +1017,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* Read entire EEPROM */
dev->i2c_bus[0].i2c_client.addr = 0xa0 >> 1;
tveeprom_read(&dev->i2c_bus[0].i2c_client, eeprom, sizeof(eeprom));
- printk(KERN_INFO "TeVii S470 MAC= "
- "%02X:%02X:%02X:%02X:%02X:%02X\n",
- eeprom[0xa0], eeprom[0xa1], eeprom[0xa2],
- eeprom[0xa3], eeprom[0xa4], eeprom[0xa5]);
+ printk(KERN_INFO "TeVii S470 MAC= %pM\n", eeprom + 0xa0);
memcpy(port->frontends.adapter.proposed_mac, eeprom + 0xa0, 6);
break;
}
@@ -1072,7 +1071,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
videobuf_queue_sg_init(&fe0->dvb.dvbq, &dvb_qops,
&dev->pci->dev, &port->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
- sizeof(struct cx23885_buffer), port);
+ sizeof(struct cx23885_buffer), port, NULL);
}
err = dvb_register(port);
if (err != 0)
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 4172cb387420..ed3d8f55029b 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -99,7 +99,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
if (!i2c_wait_done(i2c_adap))
return -EIO;
if (!i2c_slave_did_ack(i2c_adap))
- return -EIO;
+ return -ENXIO;
dprintk(1, "%s() returns 0\n", __func__);
return 0;
@@ -120,11 +120,12 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
cx_write(bus->reg_wdata, wdata);
cx_write(bus->reg_ctrl, ctrl);
- retval = i2c_wait_done(i2c_adap);
- if (retval < 0)
- goto err;
- if (retval == 0)
+ if (!i2c_wait_done(i2c_adap))
goto eio;
+ if (!i2c_slave_did_ack(i2c_adap)) {
+ retval = -ENXIO;
+ goto err;
+ }
if (i2c_debug) {
printk(" <W %02x %02x", msg->addr << 1, msg->buf[0]);
if (!(ctrl & I2C_NOSTOP))
@@ -145,10 +146,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
cx_write(bus->reg_wdata, wdata);
cx_write(bus->reg_ctrl, ctrl);
- retval = i2c_wait_done(i2c_adap);
- if (retval < 0)
- goto err;
- if (retval == 0)
+ if (!i2c_wait_done(i2c_adap))
goto eio;
if (i2c_debug) {
dprintk(1, " %02x", msg->buf[cnt]);
@@ -185,7 +183,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
if (!i2c_wait_done(i2c_adap))
return -EIO;
if (!i2c_slave_did_ack(i2c_adap))
- return -EIO;
+ return -ENXIO;
dprintk(1, "%s() returns 0\n", __func__);
@@ -209,11 +207,12 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
cx_write(bus->reg_addr, msg->addr << 25);
cx_write(bus->reg_ctrl, ctrl);
- retval = i2c_wait_done(i2c_adap);
- if (retval < 0)
- goto err;
- if (retval == 0)
+ if (!i2c_wait_done(i2c_adap))
goto eio;
+ if (cnt == 0 && !i2c_slave_did_ack(i2c_adap)) {
+ retval = -ENXIO;
+ goto err;
+ }
msg->buf[cnt] = cx_read(bus->reg_rdata) & 0xff;
if (i2c_debug) {
dprintk(1, " %02x", msg->buf[cnt]);
@@ -365,7 +364,10 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- i2c_new_probed_device(&bus->i2c_adap, &info, addr_list);
+ /* Use quick read command for probe, some IR chips don't
+ * support writes */
+ i2c_new_probed_device(&bus->i2c_adap, &info, addr_list,
+ i2c_probe_func_quick_read);
}
return bus->i2c_rc;
diff --git a/drivers/media/video/cx23885/cx23885-input.c b/drivers/media/video/cx23885/cx23885-input.c
index 8d306d8bb61c..199b9964bbe5 100644
--- a/drivers/media/video/cx23885/cx23885-input.c
+++ b/drivers/media/video/cx23885/cx23885-input.c
@@ -5,7 +5,7 @@
*
* Most of this file is
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* However, the cx23885_input_{init,fini} functions contained herein are
* derived from Linux kernel files linux/media/video/.../...-input.c marked as:
@@ -35,163 +35,42 @@
* 02110-1301, USA.
*/
-#include <linux/input.h>
#include <linux/slab.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#include <media/v4l2-subdev.h>
#include "cx23885.h"
-#define RC5_BITS 14
-#define RC5_HALF_BITS (2*RC5_BITS)
-#define RC5_HALF_BITS_MASK ((1 << RC5_HALF_BITS) - 1)
-
-#define RC5_START_BITS_NORMAL 0x3 /* Command range 0 - 63 */
-#define RC5_START_BITS_EXTENDED 0x2 /* Command range 64 - 127 */
-
-#define RC5_EXTENDED_COMMAND_OFFSET 64
-
#define MODULE_NAME "cx23885"
-static inline unsigned int rc5_command(u32 rc5_baseband)
-{
- return RC5_INSTR(rc5_baseband) +
- ((RC5_START(rc5_baseband) == RC5_START_BITS_EXTENDED)
- ? RC5_EXTENDED_COMMAND_OFFSET : 0);
-}
-
-static void cx23885_input_process_raw_rc5(struct cx23885_dev *dev)
-{
- struct card_ir *ir_input = dev->ir_input;
- unsigned int code, command;
- u32 rc5;
-
- /* Ignore codes that are too short to be valid RC-5 */
- if (ir_input->last_bit < (RC5_HALF_BITS - 1))
- return;
-
- /* The library has the manchester coding backwards; XOR to adapt. */
- code = (ir_input->code & RC5_HALF_BITS_MASK) ^ RC5_HALF_BITS_MASK;
- rc5 = ir_rc5_decode(code);
-
- switch (RC5_START(rc5)) {
- case RC5_START_BITS_NORMAL:
- break;
- case RC5_START_BITS_EXTENDED:
- /* Don't allow if the remote only emits standard commands */
- if (ir_input->start == RC5_START_BITS_NORMAL)
- return;
- break;
- default:
- return;
- }
-
- if (ir_input->addr != RC5_ADDR(rc5))
- return;
-
- /* Don't generate a keypress for RC-5 auto-repeated keypresses */
- command = rc5_command(rc5);
- if (RC5_TOGGLE(rc5) != RC5_TOGGLE(ir_input->last_rc5) ||
- command != rc5_command(ir_input->last_rc5) ||
- /* Catch T == 0, CMD == 0 (e.g. '0') as first keypress after init */
- RC5_START(ir_input->last_rc5) == 0) {
- /* This keypress is differnet: not an auto repeat */
- ir_input_nokey(ir_input->dev, &ir_input->ir);
- ir_input_keydown(ir_input->dev, &ir_input->ir, command);
- }
- ir_input->last_rc5 = rc5;
-
- /* Schedule when we should do the key up event: ir_input_nokey() */
- mod_timer(&ir_input->timer_keyup,
- jiffies + msecs_to_jiffies(ir_input->rc5_key_timeout));
-}
-
-static void cx23885_input_next_pulse_width_rc5(struct cx23885_dev *dev,
- u32 ns_pulse)
+static void cx23885_input_process_measurements(struct cx23885_dev *dev,
+ bool overrun)
{
- const int rc5_quarterbit_ns = 444444; /* 32 cycles/36 kHz/2 = 444 us */
- struct card_ir *ir_input = dev->ir_input;
- int i, level, quarterbits, halfbits;
-
- if (!ir_input->active) {
- ir_input->active = 1;
- /* assume an initial space that we may not detect or measure */
- ir_input->code = 0;
- ir_input->last_bit = 0;
- }
+ struct cx23885_kernel_ir *kernel_ir = dev->kernel_ir;
- if (ns_pulse == V4L2_SUBDEV_IR_PULSE_RX_SEQ_END) {
- ir_input->last_bit++; /* Account for the final space */
- ir_input->active = 0;
- cx23885_input_process_raw_rc5(dev);
- return;
- }
-
- level = (ns_pulse & V4L2_SUBDEV_IR_PULSE_LEVEL_MASK) ? 1 : 0;
-
- /* Skip any leading space to sync to the start bit */
- if (ir_input->last_bit == 0 && level == 0)
- return;
-
- /*
- * With valid RC-5 we can get up to two consecutive half-bits in a
- * single pulse measurment. Experiments have shown that the duration
- * of a half-bit can vary. Make sure we always end up with an even
- * number of quarter bits at the same level (mark or space).
- */
- ns_pulse &= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
- quarterbits = ns_pulse / rc5_quarterbit_ns;
- if (quarterbits & 1)
- quarterbits++;
- halfbits = quarterbits / 2;
-
- for (i = 0; i < halfbits; i++) {
- ir_input->last_bit++;
- ir_input->code |= (level << ir_input->last_bit);
-
- if (ir_input->last_bit >= RC5_HALF_BITS-1) {
- ir_input->active = 0;
- cx23885_input_process_raw_rc5(dev);
- /*
- * If level is 1, a leading mark is invalid for RC5.
- * If level is 0, we scan past extra intial space.
- * Either way we don't want to reactivate collecting
- * marks or spaces here with any left over half-bits.
- */
- break;
- }
- }
-}
-
-static void cx23885_input_process_pulse_widths_rc5(struct cx23885_dev *dev,
- bool add_eom)
-{
- struct card_ir *ir_input = dev->ir_input;
- struct ir_input_state *ir_input_state = &ir_input->ir;
-
- u32 ns_pulse[RC5_HALF_BITS+1];
- ssize_t num = 0;
+ ssize_t num;
int count, i;
+ bool handle = false;
+ struct ir_raw_event ir_core_event[64];
do {
- v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ns_pulse,
- sizeof(ns_pulse), &num);
+ num = 0;
+ v4l2_subdev_call(dev->sd_ir, ir, rx_read, (u8 *) ir_core_event,
+ sizeof(ir_core_event), &num);
- count = num / sizeof(u32);
+ count = num / sizeof(struct ir_raw_event);
- /* Append an end of Rx seq, if the caller requested */
- if (add_eom && count < ARRAY_SIZE(ns_pulse)) {
- ns_pulse[count] = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END;
- count++;
+ for (i = 0; i < count; i++) {
+ ir_raw_event_store(kernel_ir->rc,
+ &ir_core_event[i]);
+ handle = true;
}
-
- /* Just drain the Rx FIFO, if we're called, but not RC-5 */
- if (ir_input_state->ir_type != IR_TYPE_RC5)
- continue;
-
- for (i = 0; i < count; i++)
- cx23885_input_next_pulse_width_rc5(dev, ns_pulse[i]);
} while (num != 0);
+
+ if (overrun)
+ ir_raw_event_reset(kernel_ir->rc);
+ else if (handle)
+ ir_raw_event_handle(kernel_ir->rc);
}
void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
@@ -205,8 +84,10 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_TEVII_S470:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
/*
- * The only board we handle right now. However other boards
+ * The only boards we handle right now. However other boards
* using the CX2388x integrated IR controller should be similar
*/
break;
@@ -230,7 +111,7 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
}
if (data_available)
- cx23885_input_process_pulse_widths_rc5(dev, overrun);
+ cx23885_input_process_measurements(dev, overrun);
if (overrun) {
/* If there was a FIFO overrun, clear & restart the device */
@@ -241,38 +122,20 @@ void cx23885_input_rx_work_handler(struct cx23885_dev *dev, u32 events)
}
}
-static void cx23885_input_ir_start(struct cx23885_dev *dev)
+static int cx23885_input_ir_start(struct cx23885_dev *dev)
{
- struct card_ir *ir_input = dev->ir_input;
- struct ir_input_state *ir_input_state = &ir_input->ir;
struct v4l2_subdev_ir_parameters params;
if (dev->sd_ir == NULL)
- return;
+ return -ENODEV;
atomic_set(&dev->ir_input_stopping, 0);
- /* keyup timer set up, if needed */
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- setup_timer(&ir_input->timer_keyup,
- ir_rc5_timer_keyup, /* Not actually RC-5 specific */
- (unsigned long) ir_input);
- if (ir_input_state->ir_type == IR_TYPE_RC5) {
- /*
- * RC-5 repeats a held key every
- * 64 bits * (2 * 32/36000) sec/bit = 113.778 ms
- */
- ir_input->rc5_key_timeout = 115;
- }
- break;
- }
-
v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
/*
* The IR controller on this board only returns pulse widths.
* Any other mode setting will fail to set up the device.
@@ -295,15 +158,56 @@ static void cx23885_input_ir_start(struct cx23885_dev *dev)
* mark is received as low logic level;
* falling edges are detected as rising edges; etc.
*/
- params.invert = true;
+ params.invert_level = true;
+ break;
+ case CX23885_BOARD_TEVII_S470:
+ /*
+ * The IR controller on this board only returns pulse widths.
+ * Any other mode setting will fail to set up the device.
+ */
+ params.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+ params.enable = true;
+ params.interrupt_enable = true;
+ params.shutdown = false;
+
+ /* Setup for a standard NEC protocol */
+ params.carrier_freq = 37917; /* Hz, 455 kHz/12 for NEC */
+ params.carrier_range_lower = 33000; /* Hz */
+ params.carrier_range_upper = 43000; /* Hz */
+ params.duty_cycle = 33; /* percent, 33 percent for NEC */
+
+ /*
+ * NEC max pulse width: (64/3)/(455 kHz/12) * 16 nec_units
+ * (64/3)/(455 kHz/12) * 16 nec_units * 1.375 = 12378022 ns
+ */
+ params.max_pulse_width = 12378022; /* ns */
+
+ /*
+ * NEC noise filter min width: (64/3)/(455 kHz/12) * 1 nec_unit
+ * (64/3)/(455 kHz/12) * 1 nec_units * 0.625 = 351648 ns
+ */
+ params.noise_filter_min_width = 351648; /* ns */
+
+ params.modulation = false;
+ params.invert_level = true;
break;
}
v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
+ return 0;
+}
+
+static int cx23885_input_ir_open(struct rc_dev *rc)
+{
+ struct cx23885_kernel_ir *kernel_ir = rc->priv;
+
+ if (kernel_ir->cx == NULL)
+ return -ENODEV;
+
+ return cx23885_input_ir_start(kernel_ir->cx);
}
static void cx23885_input_ir_stop(struct cx23885_dev *dev)
{
- struct card_ir *ir_input = dev->ir_input;
struct v4l2_subdev_ir_parameters params;
if (dev->sd_ir == NULL)
@@ -325,23 +229,24 @@ static void cx23885_input_ir_stop(struct cx23885_dev *dev)
v4l2_subdev_call(dev->sd_ir, ir, rx_s_parameters, &params);
v4l2_subdev_call(dev->sd_ir, ir, rx_g_parameters, &params);
}
+}
- flush_scheduled_work();
+static void cx23885_input_ir_close(struct rc_dev *rc)
+{
+ struct cx23885_kernel_ir *kernel_ir = rc->priv;
- switch (dev->board) {
- case CX23885_BOARD_HAUPPAUGE_HVR1850:
- case CX23885_BOARD_HAUPPAUGE_HVR1290:
- del_timer_sync(&ir_input->timer_keyup);
- break;
- }
+ if (kernel_ir->cx != NULL)
+ cx23885_input_ir_stop(kernel_ir->cx);
}
int cx23885_input_init(struct cx23885_dev *dev)
{
- struct card_ir *ir;
- struct input_dev *input_dev;
- char *ir_codes = NULL;
- int ir_type, ir_addr, ir_start;
+ struct cx23885_kernel_ir *kernel_ir;
+ struct rc_dev *rc;
+ char *rc_map;
+ enum rc_driver_type driver_type;
+ unsigned long allowed_protos;
+
int ret;
/*
@@ -354,53 +259,66 @@ int cx23885_input_init(struct cx23885_dev *dev)
switch (dev->board) {
case CX23885_BOARD_HAUPPAUGE_HVR1850:
case CX23885_BOARD_HAUPPAUGE_HVR1290:
- /* Parameters for the grey Hauppauge remote for the HVR-1850 */
- ir_codes = RC_MAP_HAUPPAUGE_NEW;
- ir_type = IR_TYPE_RC5;
- ir_addr = 0x1e; /* RC-5 system bits emitted by the remote */
- ir_start = RC5_START_BITS_NORMAL; /* A basic RC-5 remote */
+ case CX23885_BOARD_HAUPPAUGE_HVR1250:
+ /* Integrated CX2388[58] IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = RC_TYPE_ALL;
+ /* The grey Hauppauge RC-5 remote */
+ rc_map = RC_MAP_RC5_HAUPPAUGE_NEW;
break;
- }
- if (ir_codes == NULL)
+ case CX23885_BOARD_TEVII_S470:
+ /* Integrated CX23885 IR controller */
+ driver_type = RC_DRIVER_IR_RAW;
+ allowed_protos = RC_TYPE_ALL;
+ /* A guess at the remote */
+ rc_map = RC_MAP_TEVII_NEC;
+ break;
+ default:
return -ENODEV;
-
- ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev) {
- ret = -ENOMEM;
- goto err_out_free;
}
- ir->dev = input_dev;
- ir->addr = ir_addr;
- ir->start = ir_start;
+ /* cx23885 board instance kernel IR state */
+ kernel_ir = kzalloc(sizeof(struct cx23885_kernel_ir), GFP_KERNEL);
+ if (kernel_ir == NULL)
+ return -ENOMEM;
- /* init input device */
- snprintf(ir->name, sizeof(ir->name), "cx23885 IR (%s)",
- cx23885_boards[dev->board].name);
- snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(dev->pci));
+ kernel_ir->cx = dev;
+ kernel_ir->name = kasprintf(GFP_KERNEL, "cx23885 IR (%s)",
+ cx23885_boards[dev->board].name);
+ kernel_ir->phys = kasprintf(GFP_KERNEL, "pci-%s/ir0",
+ pci_name(dev->pci));
- ret = ir_input_init(input_dev, &ir->ir, ir_type);
- if (ret < 0)
+ /* input device */
+ rc = rc_allocate_device();
+ if (!rc) {
+ ret = -ENOMEM;
goto err_out_free;
+ }
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ kernel_ir->rc = rc;
+ rc->input_name = kernel_ir->name;
+ rc->input_phys = kernel_ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
if (dev->pci->subsystem_vendor) {
- input_dev->id.vendor = dev->pci->subsystem_vendor;
- input_dev->id.product = dev->pci->subsystem_device;
+ rc->input_id.vendor = dev->pci->subsystem_vendor;
+ rc->input_id.product = dev->pci->subsystem_device;
} else {
- input_dev->id.vendor = dev->pci->vendor;
- input_dev->id.product = dev->pci->device;
+ rc->input_id.vendor = dev->pci->vendor;
+ rc->input_id.product = dev->pci->device;
}
- input_dev->dev.parent = &dev->pci->dev;
-
- dev->ir_input = ir;
- cx23885_input_ir_start(dev);
-
- ret = ir_input_register(ir->dev, ir_codes, NULL, MODULE_NAME);
+ rc->dev.parent = &dev->pci->dev;
+ rc->driver_type = driver_type;
+ rc->allowed_protos = allowed_protos;
+ rc->priv = kernel_ir;
+ rc->open = cx23885_input_ir_open;
+ rc->close = cx23885_input_ir_close;
+ rc->map_name = rc_map;
+ rc->driver_name = MODULE_NAME;
+
+ /* Go */
+ dev->kernel_ir = kernel_ir;
+ ret = rc_register_device(rc);
if (ret)
goto err_out_stop;
@@ -408,9 +326,12 @@ int cx23885_input_init(struct cx23885_dev *dev)
err_out_stop:
cx23885_input_ir_stop(dev);
- dev->ir_input = NULL;
+ dev->kernel_ir = NULL;
+ rc_free_device(rc);
err_out_free:
- kfree(ir);
+ kfree(kernel_ir->phys);
+ kfree(kernel_ir->name);
+ kfree(kernel_ir);
return ret;
}
@@ -419,9 +340,11 @@ void cx23885_input_fini(struct cx23885_dev *dev)
/* Always stop the IR hardware from generating interrupts */
cx23885_input_ir_stop(dev);
- if (dev->ir_input == NULL)
+ if (dev->kernel_ir == NULL)
return;
- ir_input_unregister(dev->ir_input->dev);
- kfree(dev->ir_input);
- dev->ir_input = NULL;
+ rc_unregister_device(dev->kernel_ir->rc);
+ kfree(dev->kernel_ir->phys);
+ kfree(dev->kernel_ir->name);
+ kfree(dev->kernel_ir);
+ dev->kernel_ir = NULL;
}
diff --git a/drivers/media/video/cx23885/cx23885-input.h b/drivers/media/video/cx23885/cx23885-input.h
index 3572cb1ecfc2..75ef15d3f523 100644
--- a/drivers/media/video/cx23885/cx23885-input.h
+++ b/drivers/media/video/cx23885/cx23885-input.h
@@ -3,7 +3,7 @@
*
* Infrared remote control input device
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.c b/drivers/media/video/cx23885/cx23885-ioctl.c
index dfb4627fb340..44812ca78899 100644
--- a/drivers/media/video/cx23885/cx23885-ioctl.c
+++ b/drivers/media/video/cx23885/cx23885-ioctl.c
@@ -3,7 +3,7 @@
*
* Various common ioctl() support functions
*
- * Copyright (c) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx23885/cx23885-ioctl.h b/drivers/media/video/cx23885/cx23885-ioctl.h
index 80b0f4923c6a..315be0ca5a04 100644
--- a/drivers/media/video/cx23885/cx23885-ioctl.h
+++ b/drivers/media/video/cx23885/cx23885-ioctl.h
@@ -3,7 +3,7 @@
*
* Various common ioctl() support functions
*
- * Copyright (c) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (c) 2009 Andy Walls <awalls@md.metrocast.net>
*
* 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
diff --git a/drivers/media/video/cx23885/cx23885-ir.c b/drivers/media/video/cx23885/cx23885-ir.c
index 6ae982cc9856..7125247dd255 100644
--- a/drivers/media/video/cx23885/cx23885-ir.c
+++ b/drivers/media/video/cx23885/cx23885-ir.c
@@ -3,7 +3,7 @@
*
* Infrared device support routines - non-input, non-vl42_subdev routines
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -53,7 +53,7 @@ void cx23885_ir_rx_work_handler(struct work_struct *work)
if (events == 0)
return;
- if (dev->ir_input)
+ if (dev->kernel_ir)
cx23885_input_rx_work_handler(dev, events);
}
@@ -72,7 +72,7 @@ void cx23885_ir_tx_work_handler(struct work_struct *work)
}
-/* Called in an IRQ context */
+/* Possibly called in an IRQ context */
void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
{
struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
@@ -86,10 +86,18 @@ void cx23885_ir_rx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
set_bit(CX23885_IR_RX_HW_FIFO_OVERRUN, notifications);
if (events & V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN)
set_bit(CX23885_IR_RX_SW_FIFO_OVERRUN, notifications);
- schedule_work(&dev->ir_rx_work);
+
+ /*
+ * For the integrated AV core, we are already in a workqueue context.
+ * For the CX23888 integrated IR, we are in an interrupt context.
+ */
+ if (sd == dev->sd_cx25840)
+ cx23885_ir_rx_work_handler(&dev->ir_rx_work);
+ else
+ schedule_work(&dev->ir_rx_work);
}
-/* Called in an IRQ context */
+/* Possibly called in an IRQ context */
void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
{
struct cx23885_dev *dev = to_cx23885(sd->v4l2_dev);
@@ -97,5 +105,13 @@ void cx23885_ir_tx_v4l2_dev_notify(struct v4l2_subdev *sd, u32 events)
if (events & V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ)
set_bit(CX23885_IR_TX_FIFO_SERVICE_REQ, notifications);
- schedule_work(&dev->ir_tx_work);
+
+ /*
+ * For the integrated AV core, we are already in a workqueue context.
+ * For the CX23888 integrated IR, we are in an interrupt context.
+ */
+ if (sd == dev->sd_cx25840)
+ cx23885_ir_tx_work_handler(&dev->ir_tx_work);
+ else
+ schedule_work(&dev->ir_tx_work);
}
diff --git a/drivers/media/video/cx23885/cx23885-ir.h b/drivers/media/video/cx23885/cx23885-ir.h
index 9b8a6d5d1ef6..0c9d8bda9e28 100644
--- a/drivers/media/video/cx23885/cx23885-ir.h
+++ b/drivers/media/video/cx23885/cx23885-ir.h
@@ -3,7 +3,7 @@
*
* Infrared device support routines - non-input, non-vl42_subdev routines
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx23885/cx23885-reg.h b/drivers/media/video/cx23885/cx23885-reg.h
index c0bc9a068954..a28772db11f0 100644
--- a/drivers/media/video/cx23885/cx23885-reg.h
+++ b/drivers/media/video/cx23885/cx23885-reg.h
@@ -213,6 +213,7 @@ Channel manager Data Structure entry = 20 DWORD
#define DEV_CNTRL2 0x00040000
#define PCI_MSK_IR (1 << 28)
+#define PCI_MSK_AV_CORE (1 << 27)
#define PCI_MSK_GPIO1 (1 << 24)
#define PCI_MSK_GPIO0 (1 << 23)
#define PCI_MSK_APB_DMA (1 << 12)
diff --git a/drivers/media/video/cx23885/cx23885-vbi.c b/drivers/media/video/cx23885/cx23885-vbi.c
index 708a8c766d1a..c0b60382ad13 100644
--- a/drivers/media/video/cx23885/cx23885-vbi.c
+++ b/drivers/media/video/cx23885/cx23885-vbi.c
@@ -74,7 +74,7 @@ static int cx23885_start_vbi_dma(struct cx23885_dev *dev,
q->count = 1;
/* enable irqs */
- cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
+ cx23885_irq_add_enable(dev, 0x01);
cx_set(VID_A_INT_MSK, 0x000022);
/* start dma */
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index 543b854f6a62..644fcb808c0b 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -26,7 +26,6 @@
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/delay.h>
#include <linux/kthread.h>
@@ -441,7 +440,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
q->count = 1;
/* enable irq */
- cx_set(PCI_INT_MSK, cx_read(PCI_INT_MSK) | 0x01);
+ cx23885_irq_add_enable(dev, 0x01);
cx_set(VID_A_INT_MSK, 0x000011);
/* start dma */
@@ -743,8 +742,6 @@ static int video_open(struct file *file)
if (NULL == fh)
return -ENOMEM;
- lock_kernel();
-
file->private_data = fh;
fh->dev = dev;
fh->radio = radio;
@@ -758,12 +755,10 @@ static int video_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx23885_buffer),
- fh);
+ fh, NULL);
dprintk(1, "post videobuf_queue_init()\n");
- unlock_kernel();
-
return 0;
}
@@ -976,6 +971,7 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
{
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
+ struct v4l2_mbus_framefmt mbus_fmt;
int err;
dprintk(2, "%s()\n", __func__);
@@ -989,7 +985,9 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
fh->vidq.field = f->fmt.pix.field;
dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
fh->width, fh->height, fh->vidq.field);
- call_all(dev, video, s_fmt, f);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
return 0;
}
@@ -1026,35 +1024,6 @@ static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv,
- struct video_mbuf *mbuf)
-{
- struct cx23885_fh *fh = priv;
- struct videobuf_queue *q;
- struct v4l2_requestbuffers req;
- unsigned int i;
- int err;
-
- q = get_queue(fh);
- memset(&req, 0, sizeof(req));
- req.type = q->type;
- req.count = 8;
- req.memory = V4L2_MEMORY_MMAP;
- err = videobuf_reqbufs(q, &req);
- if (err < 0)
- return err;
-
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += q->bufs[i]->bsize;
- }
- return 0;
-}
-#endif
-
static int vidioc_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
@@ -1157,14 +1126,14 @@ static int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
if (0 == INPUT(n)->type)
return -EINVAL;
- memset(i, 0, sizeof(*i));
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
strcpy(i->name, iname[INPUT(n)->type]);
if ((CX23885_VMUX_TELEVISION == INPUT(n)->type) ||
- (CX23885_VMUX_CABLE == INPUT(n)->type))
+ (CX23885_VMUX_CABLE == INPUT(n)->type)) {
i->type = V4L2_INPUT_TYPE_TUNER;
i->std = CX23885_NORMS;
+ }
return 0;
}
@@ -1202,6 +1171,21 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
return 0;
}
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ struct cx23885_fh *fh = priv;
+ struct cx23885_dev *dev = fh->dev;
+
+ printk(KERN_INFO
+ "%s/0: ============ START LOG STATUS ============\n",
+ dev->name);
+ call_all(dev, core, log_status);
+ printk(KERN_INFO
+ "%s/0: ============= END LOG STATUS =============\n",
+ dev->name);
+ return 0;
+}
+
static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qctrl)
{
@@ -1407,14 +1391,12 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_enum_input = vidioc_enum_input,
.vidioc_g_input = vidioc_g_input,
.vidioc_s_input = vidioc_s_input,
+ .vidioc_log_status = vidioc_log_status,
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
@@ -1446,7 +1428,7 @@ static const struct v4l2_file_operations radio_fops = {
void cx23885_video_unregister(struct cx23885_dev *dev)
{
dprintk(1, "%s()\n", __func__);
- cx_clear(PCI_INT_MSK, 1);
+ cx23885_irq_remove(dev, 0x01);
if (dev->video_dev) {
if (video_is_registered(dev->video_dev))
@@ -1483,7 +1465,8 @@ int cx23885_video_register(struct cx23885_dev *dev)
VID_A_DMA_CTL, 0x11, 0x00);
/* Don't enable VBI yet */
- cx_set(PCI_INT_MSK, 1);
+
+ cx23885_irq_add_enable(dev, 0x01);
if (TUNER_ABSENT != dev->tuner_type) {
struct v4l2_subdev *sd = NULL;
@@ -1491,11 +1474,11 @@ int cx23885_video_register(struct cx23885_dev *dev)
if (dev->tuner_addr)
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", dev->tuner_addr, NULL);
+ "tuner", dev->tuner_addr, NULL);
else
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
&dev->i2c_bus[1].i2c_adap,
- "tuner", "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
+ "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_TV));
if (sd) {
struct tuner_setup tun_setup;
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 8d6a55e54ee7..62e41ab65810 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -30,6 +30,7 @@
#include <media/tveeprom.h>
#include <media/videobuf-dma-sg.h>
#include <media/videobuf-dvb.h>
+#include <media/rc-core.h>
#include "btcx-risc.h"
#include "cx23885-reg.h"
@@ -83,6 +84,7 @@
#define CX23885_BOARD_HAUPPAUGE_HVR1290 26
#define CX23885_BOARD_MYGICA_X8558PRO 27
#define CX23885_BOARD_LEADTEK_WINFAST_PXTV1200 28
+#define CX23885_BOARD_GOTVIEW_X5_3D_HYBRID 29
#define GPIO_0 0x00000001
#define GPIO_1 0x00000002
@@ -304,6 +306,14 @@ struct cx23885_tsport {
void *port_priv;
};
+struct cx23885_kernel_ir {
+ struct cx23885_dev *cx;
+ char *name;
+ char *phys;
+
+ struct rc_dev *rc;
+};
+
struct cx23885_dev {
atomic_t refcount;
struct v4l2_device v4l2_dev;
@@ -315,6 +325,7 @@ struct cx23885_dev {
u32 __iomem *lmmio;
u8 __iomem *bmmio;
int pci_irqmask;
+ spinlock_t pci_irqmask_lock; /* protects mask reg too */
int hwrevision;
/* This valud is board specific and is used to configure the
@@ -355,6 +366,7 @@ struct cx23885_dev {
unsigned char radio_addr;
unsigned int has_radio;
struct v4l2_subdev *sd_cx25840;
+ struct work_struct cx25840_work;
/* Infrared */
struct v4l2_subdev *sd_ir;
@@ -363,7 +375,7 @@ struct cx23885_dev {
struct work_struct ir_tx_work;
unsigned long ir_tx_notifications;
- struct card_ir *ir_input;
+ struct cx23885_kernel_ir *kernel_ir;
atomic_t ir_input_stopping;
/* V4l */
@@ -393,7 +405,8 @@ static inline struct cx23885_dev *to_cx23885(struct v4l2_device *v4l2_dev)
#define call_all(dev, o, f, args...) \
v4l2_device_call_all(&dev->v4l2_dev, 0, o, f, ##args)
-#define CX23885_HW_888_IR (1 << 0)
+#define CX23885_HW_888_IR (1 << 0)
+#define CX23885_HW_AV_CORE (1 << 1)
#define call_hw(dev, grpid, o, f, args...) \
v4l2_device_call_all(&dev->v4l2_dev, grpid, o, f, ##args)
@@ -474,6 +487,10 @@ extern u32 cx23885_gpio_get(struct cx23885_dev *dev, u32 mask);
extern void cx23885_gpio_enable(struct cx23885_dev *dev, u32 mask,
int asoutput);
+extern void cx23885_irq_add_enable(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_irq_enable(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_irq_disable(struct cx23885_dev *dev, u32 mask);
+extern void cx23885_irq_remove(struct cx23885_dev *dev, u32 mask);
/* ----------------------------------------------------------- */
/* cx23885-cards.c */
diff --git a/drivers/media/video/cx23885/cx23888-ir.c b/drivers/media/video/cx23885/cx23888-ir.c
index ad728d767d69..e37be6fcf67d 100644
--- a/drivers/media/video/cx23885/cx23888-ir.c
+++ b/drivers/media/video/cx23885/cx23888-ir.c
@@ -3,7 +3,7 @@
*
* CX23888 Integrated Consumer Infrared Controller
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
@@ -26,6 +26,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
+#include <media/rc-core.h>
#include "cx23885.h"
@@ -60,6 +61,8 @@ MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");
#define CNTRL_CPL 0x00001000
#define CNTRL_LBM 0x00002000
#define CNTRL_R 0x00004000
+/* CX23888 specific control flag */
+#define CNTRL_IVO 0x00008000
#define CX23888_IR_TXCLK_REG 0x170004
#define TXCLK_TCD 0x0000FFFF
@@ -111,8 +114,18 @@ MODULE_PARM_DESC(ir_888_debug, "enable debug messages [CX23888 IR controller]");
#define CX23888_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */
#define CX23888_IR_REFCLK_FREQ (CX23888_VIDCLK_FREQ / 2)
-#define CX23888_IR_RX_KFIFO_SIZE (512 * sizeof(u32))
-#define CX23888_IR_TX_KFIFO_SIZE (512 * sizeof(u32))
+/*
+ * We use this union internally for convenience, but callers to tx_write
+ * and rx_read will be expecting records of type struct ir_raw_event.
+ * Always ensure the size of this union is dictated by struct ir_raw_event.
+ */
+union cx23888_ir_fifo_rec {
+ u32 hw_fifo_data;
+ struct ir_raw_event ir_core_data;
+};
+
+#define CX23888_IR_RX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec))
+#define CX23888_IR_TX_KFIFO_SIZE (256 * sizeof(union cx23888_ir_fifo_rec))
struct cx23888_ir_state {
struct v4l2_subdev sd;
@@ -423,6 +436,13 @@ static inline void control_tx_polarity_invert(struct cx23885_dev *dev,
invert ? CNTRL_CPL : 0);
}
+static inline void control_tx_level_invert(struct cx23885_dev *dev,
+ bool invert)
+{
+ cx23888_ir_and_or4(dev, CX23888_IR_CNTRL_REG, ~CNTRL_IVO,
+ invert ? CNTRL_IVO : 0);
+}
+
/*
* IR Rx & Tx Clock Register helpers
*/
@@ -449,8 +469,8 @@ static u32 txclk_tx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns,
{
u64 pulse_clocks;
- if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
- ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
+ if (ns > IR_MAX_DURATION)
+ ns = IR_MAX_DURATION;
pulse_clocks = ns_to_pulse_clocks(ns);
*divider = pulse_clocks_to_clock_divider(pulse_clocks);
cx23888_ir_write4(dev, CX23888_IR_TXCLK_REG, *divider);
@@ -462,8 +482,8 @@ static u32 rxclk_rx_s_max_pulse_width(struct cx23885_dev *dev, u32 ns,
{
u64 pulse_clocks;
- if (ns > V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
- ns = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS;
+ if (ns > IR_MAX_DURATION)
+ ns = IR_MAX_DURATION;
pulse_clocks = ns_to_pulse_clocks(ns);
*divider = pulse_clocks_to_clock_divider(pulse_clocks);
cx23888_ir_write4(dev, CX23888_IR_RXCLK_REG, *divider);
@@ -526,8 +546,8 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
u32 irqen = cx23888_ir_read4(dev, CX23888_IR_IRQEN_REG);
u32 stats = cx23888_ir_read4(dev, CX23888_IR_STATS_REG);
- u32 rx_data[FIFO_RX_DEPTH];
- int i, j, k;
+ union cx23888_ir_fifo_rec rx_data[FIFO_RX_DEPTH];
+ unsigned int i, j, k;
u32 events, v;
int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
@@ -588,11 +608,12 @@ static int cx23888_ir_irq_handler(struct v4l2_subdev *sd, u32 status,
for (j = 0;
(v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
v = cx23888_ir_read4(dev, CX23888_IR_FIFO_REG);
- rx_data[i++] = v & ~FIFO_RX_NDV;
+ rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV;
+ i++;
}
if (i == 0)
break;
- j = i * sizeof(u32);
+ j = i * sizeof(union cx23888_ir_fifo_rec);
k = kfifo_in_locked(&state->rx_kfifo,
(unsigned char *) rx_data, j,
&state->rx_kfifo_lock);
@@ -651,10 +672,11 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
u16 divider = (u16) atomic_read(&state->rxclk_divider);
unsigned int i, n;
- u32 *p;
- u32 u, v;
+ union cx23888_ir_fifo_rec *p;
+ unsigned u, v;
- n = count / sizeof(u32) * sizeof(u32);
+ n = count / sizeof(union cx23888_ir_fifo_rec)
+ * sizeof(union cx23888_ir_fifo_rec);
if (n == 0) {
*num = 0;
return 0;
@@ -662,26 +684,29 @@ static int cx23888_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
n = kfifo_out_locked(&state->rx_kfifo, buf, n, &state->rx_kfifo_lock);
- n /= sizeof(u32);
- *num = n * sizeof(u32);
+ n /= sizeof(union cx23888_ir_fifo_rec);
+ *num = n * sizeof(union cx23888_ir_fifo_rec);
+
+ for (p = (union cx23888_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
- for (p = (u32 *) buf, i = 0; i < n; p++, i++) {
- if ((*p & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
- *p = V4L2_SUBDEV_IR_PULSE_RX_SEQ_END;
+ if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+ /* Assume RTO was because of no IR light input */
+ u = 0;
v4l2_dbg(2, ir_888_debug, sd, "rx read: end of rx\n");
- continue;
+ } else {
+ u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
+ if (invert)
+ u = u ? 0 : 1;
}
- u = (*p & FIFO_RXTX_LVL) ? V4L2_SUBDEV_IR_PULSE_LEVEL_MASK : 0;
- if (invert)
- u = u ? 0 : V4L2_SUBDEV_IR_PULSE_LEVEL_MASK;
+ v = (unsigned) pulse_width_count_to_ns(
+ (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
+ if (v > IR_MAX_DURATION)
+ v = IR_MAX_DURATION;
- v = (u32) pulse_width_count_to_ns((u16) (*p & FIFO_RXTX),
- divider);
- if (v >= V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS)
- v = V4L2_SUBDEV_IR_PULSE_MAX_WIDTH_NS - 1;
-
- *p = u | v;
+ init_ir_raw_event(&p->ir_core_data);
+ p->ir_core_data.pulse = u;
+ p->ir_core_data.duration = v;
v4l2_dbg(2, ir_888_debug, sd, "rx read: %10u ns %s\n",
v, u ? "mark" : "space");
@@ -740,7 +765,8 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
- o->bytes_per_data_element = p->bytes_per_data_element = sizeof(u32);
+ o->bytes_per_data_element = p->bytes_per_data_element
+ = sizeof(union cx23888_ir_fifo_rec);
/* Before we tweak the hardware, we have to disable the receiver */
irqenable_rx(dev, 0);
@@ -762,12 +788,15 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
&p->carrier_range_upper);
o->carrier_range_lower = p->carrier_range_lower;
o->carrier_range_upper = p->carrier_range_upper;
+
+ p->max_pulse_width =
+ (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider);
} else {
p->max_pulse_width =
rxclk_rx_s_max_pulse_width(dev, p->max_pulse_width,
&rxclk_divider);
- o->max_pulse_width = p->max_pulse_width;
}
+ o->max_pulse_width = p->max_pulse_width;
atomic_set(&state->rxclk_divider, rxclk_divider);
p->noise_filter_min_width =
@@ -782,8 +811,8 @@ static int cx23888_ir_rx_s_parameters(struct v4l2_subdev *sd,
control_rx_s_edge_detection(dev, CNTRL_EDG_BOTH);
- o->invert = p->invert;
- atomic_set(&state->rx_invert, p->invert);
+ o->invert_level = p->invert_level;
+ atomic_set(&state->rx_invert, p->invert_level);
o->interrupt_enable = p->interrupt_enable;
o->enable = p->enable;
@@ -864,7 +893,8 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
o->mode = p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
- o->bytes_per_data_element = p->bytes_per_data_element = sizeof(u32);
+ o->bytes_per_data_element = p->bytes_per_data_element
+ = sizeof(union cx23888_ir_fifo_rec);
/* Before we tweak the hardware, we have to disable the transmitter */
irqenable_tx(dev, 0);
@@ -880,12 +910,15 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
p->duty_cycle = cduty_tx_s_duty_cycle(dev, p->duty_cycle);
o->duty_cycle = p->duty_cycle;
+
+ p->max_pulse_width =
+ (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider);
} else {
p->max_pulse_width =
txclk_tx_s_max_pulse_width(dev, p->max_pulse_width,
&txclk_divider);
- o->max_pulse_width = p->max_pulse_width;
}
+ o->max_pulse_width = p->max_pulse_width;
atomic_set(&state->txclk_divider, txclk_divider);
p->resolution = clock_divider_to_resolution(txclk_divider);
@@ -894,8 +927,11 @@ static int cx23888_ir_tx_s_parameters(struct v4l2_subdev *sd,
/* FIXME - make this dependent on resolution for better performance */
control_tx_irq_watermark(dev, TX_FIFO_HALF_EMPTY);
- control_tx_polarity_invert(dev, p->invert);
- o->invert = p->invert;
+ control_tx_polarity_invert(dev, p->invert_carrier_sense);
+ o->invert_carrier_sense = p->invert_carrier_sense;
+
+ control_tx_level_invert(dev, p->invert_level);
+ o->invert_level = p->invert_level;
o->interrupt_enable = p->interrupt_enable;
o->enable = p->enable;
@@ -988,12 +1024,10 @@ static int cx23888_ir_log_status(struct v4l2_subdev *sd)
"-%1d/+%1d, %u to %u Hz\n", i, j,
clock_divider_to_freq(rxclk, 16 + j),
clock_divider_to_freq(rxclk, 16 - i));
- } else {
- v4l2_info(sd, "\tMax measurable pulse width: %u us, "
- "%llu ns\n",
- pulse_width_count_to_us(FIFO_RXTX, rxclk),
- pulse_width_count_to_ns(FIFO_RXTX, rxclk));
}
+ v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n",
+ pulse_width_count_to_us(FIFO_RXTX, rxclk),
+ pulse_width_count_to_ns(FIFO_RXTX, rxclk));
v4l2_info(sd, "\tLow pass filter: %s\n",
filtr ? "enabled" : "disabled");
if (filtr)
@@ -1025,19 +1059,20 @@ static int cx23888_ir_log_status(struct v4l2_subdev *sd)
cntrl & CNTRL_TFE ? "enabled" : "disabled");
v4l2_info(sd, "\tFIFO interrupt watermark: %s\n",
cntrl & CNTRL_TIC ? "not empty" : "half full or less");
- v4l2_info(sd, "\tSignal polarity: %s\n",
- cntrl & CNTRL_CPL ? "0:mark 1:space" : "0:space 1:mark");
+ v4l2_info(sd, "\tOutput pin level inversion %s\n",
+ cntrl & CNTRL_IVO ? "yes" : "no");
+ v4l2_info(sd, "\tCarrier polarity: %s\n",
+ cntrl & CNTRL_CPL ? "space:burst mark:noburst"
+ : "space:noburst mark:burst");
if (cntrl & CNTRL_MOD) {
v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n",
clock_divider_to_carrier_freq(txclk));
v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n",
cduty + 1);
- } else {
- v4l2_info(sd, "\tMax pulse width: %u us, "
- "%llu ns\n",
- pulse_width_count_to_us(FIFO_RXTX, txclk),
- pulse_width_count_to_ns(FIFO_RXTX, txclk));
}
+ v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n",
+ pulse_width_count_to_us(FIFO_RXTX, txclk),
+ pulse_width_count_to_ns(FIFO_RXTX, txclk));
v4l2_info(sd, "\tBusy: %s\n",
stats & STATS_TBY ? "yes" : "no");
v4l2_info(sd, "\tFIFO service requested: %s\n",
@@ -1111,11 +1146,10 @@ static const struct v4l2_subdev_core_ops cx23888_ir_core_ops = {
.g_register = cx23888_ir_g_register,
.s_register = cx23888_ir_s_register,
#endif
+ .interrupt_service_routine = cx23888_ir_irq_handler,
};
static const struct v4l2_subdev_ir_ops cx23888_ir_ir_ops = {
- .interrupt_service_routine = cx23888_ir_irq_handler,
-
.rx_read = cx23888_ir_rx_read,
.rx_g_parameters = cx23888_ir_rx_g_parameters,
.rx_s_parameters = cx23888_ir_rx_s_parameters,
@@ -1131,7 +1165,7 @@ static const struct v4l2_subdev_ops cx23888_ir_controller_ops = {
};
static const struct v4l2_subdev_ir_parameters default_rx_params = {
- .bytes_per_data_element = sizeof(u32),
+ .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec),
.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
.enable = false,
@@ -1146,11 +1180,11 @@ static const struct v4l2_subdev_ir_parameters default_rx_params = {
.noise_filter_min_width = 333333, /* ns */
.carrier_range_lower = 35000,
.carrier_range_upper = 37000,
- .invert = false,
+ .invert_level = false,
};
static const struct v4l2_subdev_ir_parameters default_tx_params = {
- .bytes_per_data_element = sizeof(u32),
+ .bytes_per_data_element = sizeof(union cx23888_ir_fifo_rec),
.mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
.enable = false,
@@ -1160,7 +1194,8 @@ static const struct v4l2_subdev_ir_parameters default_tx_params = {
.modulation = true,
.carrier_freq = 36000, /* 36 kHz - RC-5 carrier */
.duty_cycle = 25, /* 25 % - RC-5 carrier */
- .invert = false,
+ .invert_level = false,
+ .invert_carrier_sense = false,
};
int cx23888_ir_probe(struct cx23885_dev *dev)
diff --git a/drivers/media/video/cx23885/cx23888-ir.h b/drivers/media/video/cx23885/cx23888-ir.h
index 3d446f9eb94b..d2de41caaf1d 100644
--- a/drivers/media/video/cx23885/cx23888-ir.h
+++ b/drivers/media/video/cx23885/cx23888-ir.h
@@ -3,7 +3,7 @@
*
* CX23888 Integrated Consumer Infrared Controller
*
- * Copyright (C) 2009 Andy Walls <awalls@radix.net>
+ * Copyright (C) 2009 Andy Walls <awalls@md.metrocast.net>
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
diff --git a/drivers/media/video/cx25840/Makefile b/drivers/media/video/cx25840/Makefile
index 6e8665be8954..2ee96d3973b8 100644
--- a/drivers/media/video/cx25840/Makefile
+++ b/drivers/media/video/cx25840/Makefile
@@ -1,5 +1,5 @@
cx25840-objs := cx25840-core.o cx25840-audio.o cx25840-firmware.o \
- cx25840-vbi.o
+ cx25840-vbi.o cx25840-ir.o
obj-$(CONFIG_VIDEO_CX25840) += cx25840.o
diff --git a/drivers/media/video/cx25840/cx25840-audio.c b/drivers/media/video/cx25840/cx25840-audio.c
index 45608d50529c..34b96c7cfd62 100644
--- a/drivers/media/video/cx25840/cx25840-audio.c
+++ b/drivers/media/video/cx25840/cx25840-audio.c
@@ -437,70 +437,51 @@ void cx25840_audio_set_path(struct i2c_client *client)
{
struct cx25840_state *state = to_state(i2c_get_clientdata(client));
- /* assert soft reset */
- cx25840_and_or(client, 0x810, ~0x1, 0x01);
+ if (!is_cx2583x(state)) {
+ /* assert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x01);
- /* stop microcontroller */
- cx25840_and_or(client, 0x803, ~0x10, 0);
+ /* stop microcontroller */
+ cx25840_and_or(client, 0x803, ~0x10, 0);
- /* Mute everything to prevent the PFFT! */
- cx25840_write(client, 0x8d3, 0x1f);
+ /* Mute everything to prevent the PFFT! */
+ cx25840_write(client, 0x8d3, 0x1f);
- if (state->aud_input == CX25840_AUDIO_SERIAL) {
- /* Set Path1 to Serial Audio Input */
- cx25840_write4(client, 0x8d0, 0x01011012);
+ if (state->aud_input == CX25840_AUDIO_SERIAL) {
+ /* Set Path1 to Serial Audio Input */
+ cx25840_write4(client, 0x8d0, 0x01011012);
- /* The microcontroller should not be started for the
- * non-tuner inputs: autodetection is specific for
- * TV audio. */
- } else {
- /* Set Path1 to Analog Demod Main Channel */
- cx25840_write4(client, 0x8d0, 0x1f063870);
+ /* The microcontroller should not be started for the
+ * non-tuner inputs: autodetection is specific for
+ * TV audio. */
+ } else {
+ /* Set Path1 to Analog Demod Main Channel */
+ cx25840_write4(client, 0x8d0, 0x1f063870);
+ }
}
set_audclk_freq(client, state->audclk_freq);
- if (state->aud_input != CX25840_AUDIO_SERIAL) {
- /* When the microcontroller detects the
- * audio format, it will unmute the lines */
- cx25840_and_or(client, 0x803, ~0x10, 0x10);
- }
-
- /* deassert soft reset */
- cx25840_and_or(client, 0x810, ~0x1, 0x00);
-
- /* Ensure the controller is running when we exit */
- if (is_cx2388x(state) || is_cx231xx(state))
- cx25840_and_or(client, 0x803, ~0x10, 0x10);
-}
-
-static int get_volume(struct i2c_client *client)
-{
- struct cx25840_state *state = to_state(i2c_get_clientdata(client));
- int vol;
-
- if (state->unmute_volume >= 0)
- return state->unmute_volume;
+ if (!is_cx2583x(state)) {
+ if (state->aud_input != CX25840_AUDIO_SERIAL) {
+ /* When the microcontroller detects the
+ * audio format, it will unmute the lines */
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
- /* Volume runs +18dB to -96dB in 1/2dB steps
- * change to fit the msp3400 -114dB to +12dB range */
+ /* deassert soft reset */
+ cx25840_and_or(client, 0x810, ~0x1, 0x00);
- /* check PATH1_VOLUME */
- vol = 228 - cx25840_read(client, 0x8d4);
- vol = (vol / 2) + 23;
- return vol << 9;
+ /* Ensure the controller is running when we exit */
+ if (is_cx2388x(state) || is_cx231xx(state))
+ cx25840_and_or(client, 0x803, ~0x10, 0x10);
+ }
}
static void set_volume(struct i2c_client *client, int volume)
{
- struct cx25840_state *state = to_state(i2c_get_clientdata(client));
int vol;
- if (state->unmute_volume >= 0) {
- state->unmute_volume = volume;
- return;
- }
-
/* Convert the volume to msp3400 values (0-127) */
vol = volume >> 9;
@@ -517,52 +498,6 @@ static void set_volume(struct i2c_client *client, int volume)
cx25840_write(client, 0x8d4, 228 - (vol * 2));
}
-static int get_bass(struct i2c_client *client)
-{
- /* bass is 49 steps +12dB to -12dB */
-
- /* check PATH1_EQ_BASS_VOL */
- int bass = cx25840_read(client, 0x8d9) & 0x3f;
- bass = (((48 - bass) * 0xffff) + 47) / 48;
- return bass;
-}
-
-static void set_bass(struct i2c_client *client, int bass)
-{
- /* PATH1_EQ_BASS_VOL */
- cx25840_and_or(client, 0x8d9, ~0x3f, 48 - (bass * 48 / 0xffff));
-}
-
-static int get_treble(struct i2c_client *client)
-{
- /* treble is 49 steps +12dB to -12dB */
-
- /* check PATH1_EQ_TREBLE_VOL */
- int treble = cx25840_read(client, 0x8db) & 0x3f;
- treble = (((48 - treble) * 0xffff) + 47) / 48;
- return treble;
-}
-
-static void set_treble(struct i2c_client *client, int treble)
-{
- /* PATH1_EQ_TREBLE_VOL */
- cx25840_and_or(client, 0x8db, ~0x3f, 48 - (treble * 48 / 0xffff));
-}
-
-static int get_balance(struct i2c_client *client)
-{
- /* balance is 7 bit, 0 to -96dB */
-
- /* check PATH1_BAL_LEVEL */
- int balance = cx25840_read(client, 0x8d5) & 0x7f;
- /* check PATH1_BAL_LEFT */
- if ((cx25840_read(client, 0x8d5) & 0x80) == 0)
- balance = 0x80 - balance;
- else
- balance = 0x80 + balance;
- return balance << 8;
-}
-
static void set_balance(struct i2c_client *client, int balance)
{
int bal = balance >> 8;
@@ -579,31 +514,6 @@ static void set_balance(struct i2c_client *client, int balance)
}
}
-static int get_mute(struct i2c_client *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 = to_state(i2c_get_clientdata(client));
-
- if (mute && state->unmute_volume == -1) {
- int vol = get_volume(client);
-
- set_volume(client, 0);
- state->unmute_volume = vol;
- }
- else if (!mute && state->unmute_volume != -1) {
- int vol = state->unmute_volume;
-
- state->unmute_volume = -1;
- set_volume(client, vol);
- }
-}
-
int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -624,25 +534,31 @@ int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
return retval;
}
-int cx25840_audio_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int cx25840_audio_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
+ struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = get_volume(client);
+ if (state->mute->val)
+ set_volume(client, 0);
+ else
+ set_volume(client, state->volume->val);
break;
case V4L2_CID_AUDIO_BASS:
- ctrl->value = get_bass(client);
+ /* PATH1_EQ_BASS_VOL */
+ cx25840_and_or(client, 0x8d9, ~0x3f,
+ 48 - (ctrl->val * 48 / 0xffff));
break;
case V4L2_CID_AUDIO_TREBLE:
- ctrl->value = get_treble(client);
+ /* PATH1_EQ_TREBLE_VOL */
+ cx25840_and_or(client, 0x8db, ~0x3f,
+ 48 - (ctrl->val * 48 / 0xffff));
break;
case V4L2_CID_AUDIO_BALANCE:
- ctrl->value = get_balance(client);
- break;
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = get_mute(client);
+ set_balance(client, ctrl->val);
break;
default:
return -EINVAL;
@@ -650,28 +566,6 @@ int cx25840_audio_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return 0;
}
-int cx25840_audio_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- set_volume(client, ctrl->value);
- break;
- case V4L2_CID_AUDIO_BASS:
- set_bass(client, ctrl->value);
- break;
- case V4L2_CID_AUDIO_TREBLE:
- set_treble(client, ctrl->value);
- break;
- case V4L2_CID_AUDIO_BALANCE:
- set_balance(client, ctrl->value);
- break;
- case V4L2_CID_AUDIO_MUTE:
- set_mute(client, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
+const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops = {
+ .s_ctrl = cx25840_audio_s_ctrl,
+};
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 8b6fb3544376..6fc09dd41b9d 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -15,6 +15,9 @@
*
* CX23885 support by Steven Toth <stoth@linuxtv.org>.
*
+ * CX2388[578] IRQ handling, IO Pin mux configuration and other small fixes are
+ * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
+ *
* 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
@@ -39,7 +42,6 @@
#include <linux/delay.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/cx25840.h>
#include "cx25840-core.h"
@@ -48,6 +50,28 @@ MODULE_DESCRIPTION("Conexant CX25840 audio/video decoder driver");
MODULE_AUTHOR("Ulf Eklund, Chris Kennedy, Hans Verkuil, Tyler Trafford");
MODULE_LICENSE("GPL");
+#define CX25840_VID_INT_STAT_REG 0x410
+#define CX25840_VID_INT_STAT_BITS 0x0000ffff
+#define CX25840_VID_INT_MASK_BITS 0xffff0000
+#define CX25840_VID_INT_MASK_SHFT 16
+#define CX25840_VID_INT_MASK_REG 0x412
+
+#define CX23885_AUD_MC_INT_MASK_REG 0x80c
+#define CX23885_AUD_MC_INT_STAT_BITS 0xffff0000
+#define CX23885_AUD_MC_INT_CTRL_BITS 0x0000ffff
+#define CX23885_AUD_MC_INT_STAT_SHFT 16
+
+#define CX25840_AUD_INT_CTRL_REG 0x812
+#define CX25840_AUD_INT_STAT_REG 0x813
+
+#define CX23885_PIN_CTRL_IRQ_REG 0x123
+#define CX23885_PIN_CTRL_IRQ_IR_STAT 0x40
+#define CX23885_PIN_CTRL_IRQ_AUD_STAT 0x20
+#define CX23885_PIN_CTRL_IRQ_VID_STAT 0x10
+
+#define CX25840_IR_STATS_REG 0x210
+#define CX25840_IR_IRQEN_REG 0x214
+
static int cx25840_debug;
module_param_named(debug,cx25840_debug, int, 0644);
@@ -80,33 +104,53 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value)
u8 cx25840_read(struct i2c_client * client, u16 addr)
{
- u8 buffer[2];
- buffer[0] = addr >> 8;
- buffer[1] = addr & 0xff;
-
- if (i2c_master_send(client, buffer, 2) < 2)
+ struct i2c_msg msgs[2];
+ u8 tx_buf[2], rx_buf[1];
+
+ /* Write register address */
+ tx_buf[0] = addr >> 8;
+ tx_buf[1] = addr & 0xff;
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (char *) tx_buf;
+
+ /* Read data from register */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = 1;
+ msgs[1].buf = (char *) rx_buf;
+
+ if (i2c_transfer(client->adapter, msgs, 2) < 2)
return 0;
- if (i2c_master_recv(client, buffer, 1) < 1)
- return 0;
-
- return buffer[0];
+ return rx_buf[0];
}
u32 cx25840_read4(struct i2c_client * client, u16 addr)
{
- u8 buffer[4];
- buffer[0] = addr >> 8;
- buffer[1] = addr & 0xff;
-
- if (i2c_master_send(client, buffer, 2) < 2)
- return 0;
-
- if (i2c_master_recv(client, buffer, 4) < 4)
+ struct i2c_msg msgs[2];
+ u8 tx_buf[2], rx_buf[4];
+
+ /* Write register address */
+ tx_buf[0] = addr >> 8;
+ tx_buf[1] = addr & 0xff;
+ msgs[0].addr = client->addr;
+ msgs[0].flags = 0;
+ msgs[0].len = 2;
+ msgs[0].buf = (char *) tx_buf;
+
+ /* Read data from registers */
+ msgs[1].addr = client->addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = 4;
+ msgs[1].buf = (char *) rx_buf;
+
+ if (i2c_transfer(client->adapter, msgs, 2) < 2)
return 0;
- return (buffer[3] << 24) | (buffer[2] << 16) |
- (buffer[1] << 8) | buffer[0];
+ return (rx_buf[3] << 24) | (rx_buf[2] << 16) | (rx_buf[1] << 8) |
+ rx_buf[0];
}
int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
@@ -117,6 +161,14 @@ int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned and_mask,
or_value);
}
+int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
+ u32 or_value)
+{
+ return cx25840_write4(client, addr,
+ (cx25840_read4(client, addr) & and_mask) |
+ or_value);
+}
+
/* ----------------------------------------------------------------------- */
static int set_input(struct i2c_client *client, enum cx25840_video_input vid_input,
@@ -124,6 +176,158 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
/* ----------------------------------------------------------------------- */
+static int cx23885_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
+ struct v4l2_subdev_io_pin_config *p)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int i;
+ u32 pin_ctrl;
+ u8 gpio_oe, gpio_data, strength;
+
+ pin_ctrl = cx25840_read4(client, 0x120);
+ gpio_oe = cx25840_read(client, 0x160);
+ gpio_data = cx25840_read(client, 0x164);
+
+ for (i = 0; i < n; i++) {
+ strength = p[i].strength;
+ if (strength > CX25840_PIN_DRIVE_FAST)
+ strength = CX25840_PIN_DRIVE_FAST;
+
+ switch (p[i].pin) {
+ case CX23885_PIN_IRQ_N_GPIO16:
+ if (p[i].function != CX23885_PAD_IRQ_N) {
+ /* GPIO16 */
+ pin_ctrl &= ~(0x1 << 25);
+ } else {
+ /* IRQ_N */
+ if (p[i].flags &
+ (V4L2_SUBDEV_IO_PIN_DISABLE |
+ V4L2_SUBDEV_IO_PIN_INPUT)) {
+ pin_ctrl &= ~(0x1 << 25);
+ } else {
+ pin_ctrl |= (0x1 << 25);
+ }
+ if (p[i].flags &
+ V4L2_SUBDEV_IO_PIN_ACTIVE_LOW) {
+ pin_ctrl &= ~(0x1 << 24);
+ } else {
+ pin_ctrl |= (0x1 << 24);
+ }
+ }
+ break;
+ case CX23885_PIN_IR_RX_GPIO19:
+ if (p[i].function != CX23885_PAD_GPIO19) {
+ /* IR_RX */
+ gpio_oe |= (0x1 << 0);
+ pin_ctrl &= ~(0x3 << 18);
+ pin_ctrl |= (strength << 18);
+ } else {
+ /* GPIO19 */
+ gpio_oe &= ~(0x1 << 0);
+ if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+ gpio_data &= ~(0x1 << 0);
+ gpio_data |= ((p[i].value & 0x1) << 0);
+ }
+ pin_ctrl &= ~(0x3 << 12);
+ pin_ctrl |= (strength << 12);
+ }
+ break;
+ case CX23885_PIN_IR_TX_GPIO20:
+ if (p[i].function != CX23885_PAD_GPIO20) {
+ /* IR_TX */
+ gpio_oe |= (0x1 << 1);
+ if (p[i].flags & V4L2_SUBDEV_IO_PIN_DISABLE)
+ pin_ctrl &= ~(0x1 << 10);
+ else
+ pin_ctrl |= (0x1 << 10);
+ pin_ctrl &= ~(0x3 << 18);
+ pin_ctrl |= (strength << 18);
+ } else {
+ /* GPIO20 */
+ gpio_oe &= ~(0x1 << 1);
+ if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+ gpio_data &= ~(0x1 << 1);
+ gpio_data |= ((p[i].value & 0x1) << 1);
+ }
+ pin_ctrl &= ~(0x3 << 12);
+ pin_ctrl |= (strength << 12);
+ }
+ break;
+ case CX23885_PIN_I2S_SDAT_GPIO21:
+ if (p[i].function != CX23885_PAD_GPIO21) {
+ /* I2S_SDAT */
+ /* TODO: Input or Output config */
+ gpio_oe |= (0x1 << 2);
+ pin_ctrl &= ~(0x3 << 22);
+ pin_ctrl |= (strength << 22);
+ } else {
+ /* GPIO21 */
+ gpio_oe &= ~(0x1 << 2);
+ if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+ gpio_data &= ~(0x1 << 2);
+ gpio_data |= ((p[i].value & 0x1) << 2);
+ }
+ pin_ctrl &= ~(0x3 << 12);
+ pin_ctrl |= (strength << 12);
+ }
+ break;
+ case CX23885_PIN_I2S_WCLK_GPIO22:
+ if (p[i].function != CX23885_PAD_GPIO22) {
+ /* I2S_WCLK */
+ /* TODO: Input or Output config */
+ gpio_oe |= (0x1 << 3);
+ pin_ctrl &= ~(0x3 << 22);
+ pin_ctrl |= (strength << 22);
+ } else {
+ /* GPIO22 */
+ gpio_oe &= ~(0x1 << 3);
+ if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+ gpio_data &= ~(0x1 << 3);
+ gpio_data |= ((p[i].value & 0x1) << 3);
+ }
+ pin_ctrl &= ~(0x3 << 12);
+ pin_ctrl |= (strength << 12);
+ }
+ break;
+ case CX23885_PIN_I2S_BCLK_GPIO23:
+ if (p[i].function != CX23885_PAD_GPIO23) {
+ /* I2S_BCLK */
+ /* TODO: Input or Output config */
+ gpio_oe |= (0x1 << 4);
+ pin_ctrl &= ~(0x3 << 22);
+ pin_ctrl |= (strength << 22);
+ } else {
+ /* GPIO23 */
+ gpio_oe &= ~(0x1 << 4);
+ if (p[i].flags & V4L2_SUBDEV_IO_PIN_SET_VALUE) {
+ gpio_data &= ~(0x1 << 4);
+ gpio_data |= ((p[i].value & 0x1) << 4);
+ }
+ pin_ctrl &= ~(0x3 << 12);
+ pin_ctrl |= (strength << 12);
+ }
+ break;
+ }
+ }
+
+ cx25840_write(client, 0x164, gpio_data);
+ cx25840_write(client, 0x160, gpio_oe);
+ cx25840_write4(client, 0x120, pin_ctrl);
+ return 0;
+}
+
+static int common_s_io_pin_config(struct v4l2_subdev *sd, size_t n,
+ struct v4l2_subdev_io_pin_config *pincfg)
+{
+ struct cx25840_state *state = to_state(sd);
+
+ if (is_cx2388x(state))
+ return cx23885_s_io_pin_config(sd, n, pincfg);
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
static void init_dll1(struct i2c_client *client)
{
/* This is the Hauppauge sequence used to
@@ -420,6 +624,13 @@ static void cx23885_initialize(struct i2c_client *client)
/* start microcontroller */
cx25840_and_or(client, 0x803, ~0x10, 0x10);
+
+ /* Disable and clear video interrupts - we don't use them */
+ cx25840_write4(client, CX25840_VID_INT_STAT_REG, 0xffffffff);
+
+ /* Disable and clear audio interrupts - we don't use them */
+ cx25840_write(client, CX25840_AUD_INT_CTRL_REG, 0xff);
+ cx25840_write(client, CX25840_AUD_INT_STAT_REG, 0xff);
}
/* ----------------------------------------------------------------------- */
@@ -659,6 +870,11 @@ static void input_change(struct i2c_client *client)
}
cx25840_and_or(client, 0x401, ~0x60, 0);
cx25840_and_or(client, 0x401, ~0x60, 0x60);
+
+ /* Don't write into audio registers on cx2583x chips */
+ if (is_cx2583x(state))
+ return;
+
cx25840_and_or(client, 0x810, ~0x01, 1);
if (state->radio) {
@@ -817,10 +1033,8 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
state->vid_input = vid_input;
state->aud_input = aud_input;
- if (!is_cx2583x(state)) {
- cx25840_audio_set_path(client);
- input_change(client);
- }
+ cx25840_audio_set_path(client);
+ input_change(client);
if (is_cx2388x(state)) {
/* Audio channel 1 src : Parallel 1 */
@@ -909,102 +1123,29 @@ static int set_v4lstd(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
-static int cx25840_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int cx25840_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct cx25840_state *state = to_state(sd);
+ struct v4l2_subdev *sd = to_sd(ctrl);
struct i2c_client *client = v4l2_get_subdevdata(sd);
switch (ctrl->id) {
- case CX25840_CID_ENABLE_PVR150_WORKAROUND:
- state->pvr150_workaround = ctrl->value;
- set_input(client, state->vid_input, state->aud_input);
- break;
-
case V4L2_CID_BRIGHTNESS:
- if (ctrl->value < 0 || ctrl->value > 255) {
- v4l_err(client, "invalid brightness setting %d\n",
- ctrl->value);
- return -ERANGE;
- }
-
- cx25840_write(client, 0x414, ctrl->value - 128);
+ cx25840_write(client, 0x414, ctrl->val - 128);
break;
case V4L2_CID_CONTRAST:
- if (ctrl->value < 0 || ctrl->value > 127) {
- v4l_err(client, "invalid contrast setting %d\n",
- ctrl->value);
- return -ERANGE;
- }
-
- cx25840_write(client, 0x415, ctrl->value << 1);
+ cx25840_write(client, 0x415, ctrl->val << 1);
break;
case V4L2_CID_SATURATION:
- if (ctrl->value < 0 || ctrl->value > 127) {
- v4l_err(client, "invalid saturation setting %d\n",
- ctrl->value);
- return -ERANGE;
- }
-
- cx25840_write(client, 0x420, ctrl->value << 1);
- cx25840_write(client, 0x421, ctrl->value << 1);
+ cx25840_write(client, 0x420, ctrl->val << 1);
+ cx25840_write(client, 0x421, ctrl->val << 1);
break;
case V4L2_CID_HUE:
- if (ctrl->value < -128 || ctrl->value > 127) {
- v4l_err(client, "invalid hue setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- cx25840_write(client, 0x422, ctrl->value);
+ cx25840_write(client, 0x422, ctrl->val);
break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_MUTE:
- if (is_cx2583x(state))
- return -EINVAL;
- return cx25840_audio_s_ctrl(sd, ctrl);
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct cx25840_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- switch (ctrl->id) {
- case CX25840_CID_ENABLE_PVR150_WORKAROUND:
- ctrl->value = state->pvr150_workaround;
- break;
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = (s8)cx25840_read(client, 0x414) + 128;
- break;
- case V4L2_CID_CONTRAST:
- ctrl->value = cx25840_read(client, 0x415) >> 1;
- break;
- case V4L2_CID_SATURATION:
- ctrl->value = cx25840_read(client, 0x420) >> 1;
- break;
- case V4L2_CID_HUE:
- ctrl->value = (s8)cx25840_read(client, 0x422);
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_MUTE:
- if (is_cx2583x(state))
- return -EINVAL;
- return cx25840_audio_g_ctrl(sd, ctrl);
default:
return -EINVAL;
}
@@ -1014,75 +1155,59 @@ static int cx25840_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
/* ----------------------------------------------------------------------- */
-static int cx25840_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- return cx25840_g_sliced_fmt(sd, &fmt->fmt.sliced);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int cx25840_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int cx25840_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
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);
- switch (fmt->type) {
- case V4L2_BUF_TYPE_VIDEO_CAPTURE:
- pix = &(fmt->fmt.pix);
-
- Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
- Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
+ if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
- Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
- Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
- Vlines = pix->height + (is_50Hz ? 4 : 7);
+ Vsrc = (cx25840_read(client, 0x476) & 0x3f) << 4;
+ Vsrc |= (cx25840_read(client, 0x475) & 0xf0) >> 4;
- if ((pix->width * 16 < Hsrc) || (Hsrc < pix->width) ||
- (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
- v4l_err(client, "%dx%d is not a valid size!\n",
- pix->width, pix->height);
- return -ERANGE;
- }
+ Hsrc = (cx25840_read(client, 0x472) & 0x3f) << 4;
+ Hsrc |= (cx25840_read(client, 0x471) & 0xf0) >> 4;
- HSC = (Hsrc * (1 << 20)) / pix->width - (1 << 20);
- VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
- VSC &= 0x1fff;
+ Vlines = fmt->height + (is_50Hz ? 4 : 7);
- if (pix->width >= 385)
- filter = 0;
- else if (pix->width > 192)
- filter = 1;
- else if (pix->width > 96)
- filter = 2;
- else
- filter = 3;
-
- v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n",
- pix->width, pix->height, HSC, VSC);
-
- /* HSCALE=HSC */
- cx25840_write(client, 0x418, HSC & 0xff);
- cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
- cx25840_write(client, 0x41a, HSC >> 16);
- /* VSCALE=VSC */
- cx25840_write(client, 0x41c, VSC & 0xff);
- cx25840_write(client, 0x41d, VSC >> 8);
- /* VS_INTRLACE=1 VFILT=filter */
- cx25840_write(client, 0x41e, 0x8 | filter);
- break;
-
- default:
- return -EINVAL;
+ if ((fmt->width * 16 < Hsrc) || (Hsrc < fmt->width) ||
+ (Vlines * 8 < Vsrc) || (Vsrc < Vlines)) {
+ v4l_err(client, "%dx%d is not a valid size!\n",
+ fmt->width, fmt->height);
+ return -ERANGE;
}
+ HSC = (Hsrc * (1 << 20)) / fmt->width - (1 << 20);
+ VSC = (1 << 16) - (Vsrc * (1 << 9) / Vlines - (1 << 9));
+ VSC &= 0x1fff;
+
+ if (fmt->width >= 385)
+ filter = 0;
+ else if (fmt->width > 192)
+ filter = 1;
+ else if (fmt->width > 96)
+ filter = 2;
+ else
+ filter = 3;
+
+ v4l_dbg(1, cx25840_debug, client, "decoder set size %dx%d -> scale %ux%u\n",
+ fmt->width, fmt->height, HSC, VSC);
+
+ /* HSCALE=HSC */
+ cx25840_write(client, 0x418, HSC & 0xff);
+ cx25840_write(client, 0x419, (HSC >> 8) & 0xff);
+ cx25840_write(client, 0x41a, HSC >> 16);
+ /* VSCALE=VSC */
+ cx25840_write(client, 0x41c, VSC & 0xff);
+ cx25840_write(client, 0x41d, VSC >> 8);
+ /* VS_INTRLACE=1 VFILT=filter */
+ cx25840_write(client, 0x41e, 0x8 | filter);
return 0;
}
@@ -1179,8 +1304,6 @@ static void log_audio_status(struct i2c_client *client)
default: p = "not defined";
}
v4l_info(client, "Detected audio standard: %s\n", p);
- v4l_info(client, "Audio muted: %s\n",
- (state->unmute_volume >= 0) ? "yes" : "no");
v4l_info(client, "Audio microcontroller: %s\n",
(download_ctl & 0x10) ?
((mute_ctl & 0x2) ? "detecting" : "running") : "stopped");
@@ -1397,40 +1520,6 @@ static int cx25840_s_stream(struct v4l2_subdev *sd, int enable)
return 0;
}
-static int cx25840_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- struct cx25840_state *state = to_state(sd);
-
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
- default:
- break;
- }
- if (is_cx2583x(state))
- return -EINVAL;
-
- 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:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
- default:
- return -EINVAL;
- }
- return -EINVAL;
-}
-
static int cx25840_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct cx25840_state *state = to_state(sd);
@@ -1466,18 +1555,14 @@ static int cx25840_s_audio_routing(struct v4l2_subdev *sd,
struct cx25840_state *state = to_state(sd);
struct i2c_client *client = v4l2_get_subdevdata(sd);
- if (is_cx2583x(state))
- return -EINVAL;
return set_input(client, state->vid_input, input);
}
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);
- if (!is_cx2583x(state))
- input_change(client);
+ input_change(client);
return 0;
}
@@ -1592,24 +1677,119 @@ static int cx25840_log_status(struct v4l2_subdev *sd)
log_video_status(client);
if (!is_cx2583x(state))
log_audio_status(client);
+ cx25840_ir_log_status(sd);
+ v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
return 0;
}
+static int cx23885_irq_handler(struct v4l2_subdev *sd, u32 status,
+ bool *handled)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *c = v4l2_get_subdevdata(sd);
+ u8 irq_stat, aud_stat, aud_en, ir_stat, ir_en;
+ u32 vid_stat, aud_mc_stat;
+ bool block_handled;
+ int ret = 0;
+
+ irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
+ v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (entry): %s %s %s\n",
+ irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ",
+ irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ",
+ irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " ");
+
+ if ((is_cx23885(state) || is_cx23887(state))) {
+ ir_stat = cx25840_read(c, CX25840_IR_STATS_REG);
+ ir_en = cx25840_read(c, CX25840_IR_IRQEN_REG);
+ v4l_dbg(2, cx25840_debug, c,
+ "AV Core ir IRQ status: %#04x disables: %#04x\n",
+ ir_stat, ir_en);
+ if (irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT) {
+ block_handled = false;
+ ret = cx25840_ir_irq_handler(sd,
+ status, &block_handled);
+ if (block_handled)
+ *handled = true;
+ }
+ }
+
+ aud_stat = cx25840_read(c, CX25840_AUD_INT_STAT_REG);
+ aud_en = cx25840_read(c, CX25840_AUD_INT_CTRL_REG);
+ v4l_dbg(2, cx25840_debug, c,
+ "AV Core audio IRQ status: %#04x disables: %#04x\n",
+ aud_stat, aud_en);
+ aud_mc_stat = cx25840_read4(c, CX23885_AUD_MC_INT_MASK_REG);
+ v4l_dbg(2, cx25840_debug, c,
+ "AV Core audio MC IRQ status: %#06x enables: %#06x\n",
+ aud_mc_stat >> CX23885_AUD_MC_INT_STAT_SHFT,
+ aud_mc_stat & CX23885_AUD_MC_INT_CTRL_BITS);
+ if (irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT) {
+ if (aud_stat) {
+ cx25840_write(c, CX25840_AUD_INT_STAT_REG, aud_stat);
+ *handled = true;
+ }
+ }
+
+ vid_stat = cx25840_read4(c, CX25840_VID_INT_STAT_REG);
+ v4l_dbg(2, cx25840_debug, c,
+ "AV Core video IRQ status: %#06x disables: %#06x\n",
+ vid_stat & CX25840_VID_INT_STAT_BITS,
+ vid_stat >> CX25840_VID_INT_MASK_SHFT);
+ if (irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT) {
+ if (vid_stat & CX25840_VID_INT_STAT_BITS) {
+ cx25840_write4(c, CX25840_VID_INT_STAT_REG, vid_stat);
+ *handled = true;
+ }
+ }
+
+ irq_stat = cx25840_read(c, CX23885_PIN_CTRL_IRQ_REG);
+ v4l_dbg(2, cx25840_debug, c, "AV Core IRQ status (exit): %s %s %s\n",
+ irq_stat & CX23885_PIN_CTRL_IRQ_IR_STAT ? "ir" : " ",
+ irq_stat & CX23885_PIN_CTRL_IRQ_AUD_STAT ? "aud" : " ",
+ irq_stat & CX23885_PIN_CTRL_IRQ_VID_STAT ? "vid" : " ");
+
+ return ret;
+}
+
+static int cx25840_irq_handler(struct v4l2_subdev *sd, u32 status,
+ bool *handled)
+{
+ struct cx25840_state *state = to_state(sd);
+
+ *handled = false;
+
+ /* Only support the CX2388[578] AV Core for now */
+ if (is_cx2388x(state))
+ return cx23885_irq_handler(sd, status, handled);
+
+ return -ENODEV;
+}
+
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops cx25840_ctrl_ops = {
+ .s_ctrl = cx25840_s_ctrl,
+};
+
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,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
.s_std = cx25840_s_std,
.reset = cx25840_reset,
.load_fw = cx25840_load_fw,
+ .s_io_pin_config = common_s_io_pin_config,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = cx25840_g_register,
.s_register = cx25840_s_register,
#endif
+ .interrupt_service_routine = cx25840_irq_handler,
};
static const struct v4l2_subdev_tuner_ops cx25840_tuner_ops = {
@@ -1627,8 +1807,7 @@ static const struct v4l2_subdev_audio_ops cx25840_audio_ops = {
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,
+ .s_mbus_fmt = cx25840_s_mbus_fmt,
.s_stream = cx25840_s_stream,
};
@@ -1645,6 +1824,7 @@ static const struct v4l2_subdev_ops cx25840_ops = {
.audio = &cx25840_audio_ops,
.video = &cx25840_video_ops,
.vbi = &cx25840_vbi_ops,
+ .ir = &cx25840_ir_ops,
};
/* ----------------------------------------------------------------------- */
@@ -1692,6 +1872,7 @@ static int cx25840_probe(struct i2c_client *client,
{
struct cx25840_state *state;
struct v4l2_subdev *sd;
+ int default_volume;
u32 id = V4L2_IDENT_NONE;
u16 device_id;
@@ -1735,6 +1916,7 @@ static int cx25840_probe(struct i2c_client *client,
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &cx25840_ops);
+
switch (id) {
case V4L2_IDENT_CX23885_AV:
v4l_info(client, "cx23885 A/V decoder found @ 0x%x (%s)\n",
@@ -1777,24 +1959,84 @@ static int cx25840_probe(struct i2c_client *client,
state->vid_input = CX25840_COMPOSITE7;
state->aud_input = CX25840_AUDIO8;
state->audclk_freq = 48000;
- state->pvr150_workaround = 0;
state->audmode = V4L2_TUNER_MODE_LANG1;
- state->unmute_volume = -1;
- state->default_volume = 228 - cx25840_read(client, 0x8d4);
- state->default_volume = ((state->default_volume / 2) + 23) << 9;
state->vbi_line_offset = 8;
state->id = id;
state->rev = device_id;
+ v4l2_ctrl_handler_init(&state->hdl, 9);
+ v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(&state->hdl, &cx25840_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ if (!is_cx2583x(state)) {
+ default_volume = cx25840_read(client, 0x8d4);
+ /*
+ * Enforce the legacy PVR-350/MSP3400 to PVR-150/CX25843 volume
+ * scale mapping limits to avoid -ERANGE errors when
+ * initializing the volume control
+ */
+ if (default_volume > 228) {
+ /* Bottom out at -96 dB, v4l2 vol range 0x2e00-0x2fff */
+ default_volume = 228;
+ cx25840_write(client, 0x8d4, 228);
+ }
+ else if (default_volume < 20) {
+ /* Top out at + 8 dB, v4l2 vol range 0xfe00-0xffff */
+ default_volume = 20;
+ cx25840_write(client, 0x8d4, 20);
+ }
+ default_volume = (((228 - default_volume) >> 1) + 23) << 9;
+
+ state->volume = v4l2_ctrl_new_std(&state->hdl,
+ &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_VOLUME,
+ 0, 65535, 65535 / 100, default_volume);
+ state->mute = v4l2_ctrl_new_std(&state->hdl,
+ &cx25840_audio_ctrl_ops, V4L2_CID_AUDIO_MUTE,
+ 0, 1, 1, 0);
+ v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
+ V4L2_CID_AUDIO_BALANCE,
+ 0, 65535, 65535 / 100, 32768);
+ v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
+ V4L2_CID_AUDIO_BASS,
+ 0, 65535, 65535 / 100, 32768);
+ v4l2_ctrl_new_std(&state->hdl, &cx25840_audio_ctrl_ops,
+ V4L2_CID_AUDIO_TREBLE,
+ 0, 65535, 65535 / 100, 32768);
+ }
+ sd->ctrl_handler = &state->hdl;
+ if (state->hdl.error) {
+ int err = state->hdl.error;
+
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return err;
+ }
+ v4l2_ctrl_cluster(2, &state->volume);
+ v4l2_ctrl_handler_setup(&state->hdl);
+ if (client->dev.platform_data) {
+ struct cx25840_platform_data *pdata = client->dev.platform_data;
+
+ state->pvr150_workaround = pdata->pvr150_workaround;
+ }
+
+ cx25840_ir_probe(sd);
return 0;
}
static int cx25840_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct cx25840_state *state = to_state(sd);
+ cx25840_ir_remove(sd);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
return 0;
}
@@ -1804,9 +2046,25 @@ static const struct i2c_device_id cx25840_id[] = {
};
MODULE_DEVICE_TABLE(i2c, cx25840_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "cx25840",
- .probe = cx25840_probe,
- .remove = cx25840_remove,
- .id_table = cx25840_id,
+static struct i2c_driver cx25840_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "cx25840",
+ },
+ .probe = cx25840_probe,
+ .remove = cx25840_remove,
+ .id_table = cx25840_id,
};
+
+static __init int init_cx25840(void)
+{
+ return i2c_add_driver(&cx25840_driver);
+}
+
+static __exit void exit_cx25840(void)
+{
+ i2c_del_driver(&cx25840_driver);
+}
+
+module_init(init_cx25840);
+module_exit(exit_cx25840);
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 04393b971567..bd4ada28b490 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -24,19 +24,20 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-ctrls.h>
#include <linux/i2c.h>
-/* ENABLE_PVR150_WORKAROUND activates a workaround for a hardware bug that is
- present in Hauppauge PVR-150 (and possibly PVR-500) cards that have
- certain NTSC tuners (tveeprom tuner model numbers 85, 99 and 112). The
- audio autodetect fails on some channels for these models and the workaround
- is to select the audio standard explicitly. Many thanks to Hauppauge for
- providing this information. */
-#define CX25840_CID_ENABLE_PVR150_WORKAROUND (V4L2_CID_PRIVATE_BASE+0)
+struct cx25840_ir_state;
struct cx25840_state {
struct i2c_client *c;
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* volume cluster */
+ struct v4l2_ctrl *volume;
+ struct v4l2_ctrl *mute;
+ };
int pvr150_workaround;
int radio;
v4l2_std_id std;
@@ -44,14 +45,13 @@ struct cx25840_state {
enum cx25840_audio_input aud_input;
u32 audclk_freq;
int audmode;
- int unmute_volume; /* -1 if not muted */
- int default_volume;
int vbi_line_offset;
u32 id;
u32 rev;
int is_initialized;
wait_queue_head_t fw_wait; /* wake up when the fw load is finished */
struct work_struct fw_work; /* work entry for fw load */
+ struct cx25840_ir_state *ir_state;
};
static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
@@ -59,6 +59,11 @@ static inline struct cx25840_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct cx25840_state, sd);
}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct cx25840_state, hdl)->sd;
+}
+
static inline bool is_cx2583x(struct cx25840_state *state)
{
return state->id == V4L2_IDENT_CX25836 ||
@@ -77,6 +82,21 @@ static inline bool is_cx2388x(struct cx25840_state *state)
state->id == V4L2_IDENT_CX23888_AV;
}
+static inline bool is_cx23885(struct cx25840_state *state)
+{
+ return state->id == V4L2_IDENT_CX23885_AV;
+}
+
+static inline bool is_cx23887(struct cx25840_state *state)
+{
+ return state->id == V4L2_IDENT_CX23887_AV;
+}
+
+static inline bool is_cx23888(struct cx25840_state *state)
+{
+ return state->id == V4L2_IDENT_CX23888_AV;
+}
+
/* ----------------------------------------------------------------------- */
/* cx25850-core.c */
int cx25840_write(struct i2c_client *client, u16 addr, u8 value);
@@ -84,6 +104,8 @@ int cx25840_write4(struct i2c_client *client, u16 addr, u32 value);
u8 cx25840_read(struct i2c_client *client, u16 addr);
u32 cx25840_read4(struct i2c_client *client, u16 addr);
int cx25840_and_or(struct i2c_client *client, u16 addr, unsigned mask, u8 value);
+int cx25840_and_or4(struct i2c_client *client, u16 addr, u32 and_mask,
+ u32 or_value);
void cx25840_std_setup(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
@@ -94,8 +116,8 @@ int cx25840_loadfw(struct i2c_client *client);
/* cx25850-audio.c */
void cx25840_audio_set_path(struct i2c_client *client);
int cx25840_s_clock_freq(struct v4l2_subdev *sd, u32 freq);
-int cx25840_audio_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
-int cx25840_audio_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl);
+
+extern const struct v4l2_ctrl_ops cx25840_audio_ctrl_ops;
/* ----------------------------------------------------------------------- */
/* cx25850-vbi.c */
@@ -104,4 +126,12 @@ int cx25840_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *
int cx25840_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *fmt);
int cx25840_decode_vbi_line(struct v4l2_subdev *sd, struct v4l2_decode_vbi_line *vbi);
+/* ----------------------------------------------------------------------- */
+/* cx25850-ir.c */
+extern const struct v4l2_subdev_ir_ops cx25840_ir_ops;
+int cx25840_ir_log_status(struct v4l2_subdev *sd);
+int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled);
+int cx25840_ir_probe(struct v4l2_subdev *sd);
+int cx25840_ir_remove(struct v4l2_subdev *sd);
+
#endif
diff --git a/drivers/media/video/cx25840/cx25840-ir.c b/drivers/media/video/cx25840/cx25840-ir.c
new file mode 100644
index 000000000000..7eb79af28aa3
--- /dev/null
+++ b/drivers/media/video/cx25840/cx25840-ir.c
@@ -0,0 +1,1280 @@
+/*
+ * Driver for the Conexant CX2584x Audio/Video decoder chip and related cores
+ *
+ * Integrated Consumer Infrared Controller
+ *
+ * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/slab.h>
+#include <linux/kfifo.h>
+#include <media/cx25840.h>
+#include <media/rc-core.h>
+
+#include "cx25840-core.h"
+
+static unsigned int ir_debug;
+module_param(ir_debug, int, 0644);
+MODULE_PARM_DESC(ir_debug, "enable integrated IR debug messages");
+
+#define CX25840_IR_REG_BASE 0x200
+
+#define CX25840_IR_CNTRL_REG 0x200
+#define CNTRL_WIN_3_3 0x00000000
+#define CNTRL_WIN_4_3 0x00000001
+#define CNTRL_WIN_3_4 0x00000002
+#define CNTRL_WIN_4_4 0x00000003
+#define CNTRL_WIN 0x00000003
+#define CNTRL_EDG_NONE 0x00000000
+#define CNTRL_EDG_FALL 0x00000004
+#define CNTRL_EDG_RISE 0x00000008
+#define CNTRL_EDG_BOTH 0x0000000C
+#define CNTRL_EDG 0x0000000C
+#define CNTRL_DMD 0x00000010
+#define CNTRL_MOD 0x00000020
+#define CNTRL_RFE 0x00000040
+#define CNTRL_TFE 0x00000080
+#define CNTRL_RXE 0x00000100
+#define CNTRL_TXE 0x00000200
+#define CNTRL_RIC 0x00000400
+#define CNTRL_TIC 0x00000800
+#define CNTRL_CPL 0x00001000
+#define CNTRL_LBM 0x00002000
+#define CNTRL_R 0x00004000
+
+#define CX25840_IR_TXCLK_REG 0x204
+#define TXCLK_TCD 0x0000FFFF
+
+#define CX25840_IR_RXCLK_REG 0x208
+#define RXCLK_RCD 0x0000FFFF
+
+#define CX25840_IR_CDUTY_REG 0x20C
+#define CDUTY_CDC 0x0000000F
+
+#define CX25840_IR_STATS_REG 0x210
+#define STATS_RTO 0x00000001
+#define STATS_ROR 0x00000002
+#define STATS_RBY 0x00000004
+#define STATS_TBY 0x00000008
+#define STATS_RSR 0x00000010
+#define STATS_TSR 0x00000020
+
+#define CX25840_IR_IRQEN_REG 0x214
+#define IRQEN_RTE 0x00000001
+#define IRQEN_ROE 0x00000002
+#define IRQEN_RSE 0x00000010
+#define IRQEN_TSE 0x00000020
+#define IRQEN_MSK 0x00000033
+
+#define CX25840_IR_FILTR_REG 0x218
+#define FILTR_LPF 0x0000FFFF
+
+#define CX25840_IR_FIFO_REG 0x23C
+#define FIFO_RXTX 0x0000FFFF
+#define FIFO_RXTX_LVL 0x00010000
+#define FIFO_RXTX_RTO 0x0001FFFF
+#define FIFO_RX_NDV 0x00020000
+#define FIFO_RX_DEPTH 8
+#define FIFO_TX_DEPTH 8
+
+#define CX25840_VIDCLK_FREQ 108000000 /* 108 MHz, BT.656 */
+#define CX25840_IR_REFCLK_FREQ (CX25840_VIDCLK_FREQ / 2)
+
+/*
+ * We use this union internally for convenience, but callers to tx_write
+ * and rx_read will be expecting records of type struct ir_raw_event.
+ * Always ensure the size of this union is dictated by struct ir_raw_event.
+ */
+union cx25840_ir_fifo_rec {
+ u32 hw_fifo_data;
+ struct ir_raw_event ir_core_data;
+};
+
+#define CX25840_IR_RX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec))
+#define CX25840_IR_TX_KFIFO_SIZE (256 * sizeof(union cx25840_ir_fifo_rec))
+
+struct cx25840_ir_state {
+ struct i2c_client *c;
+
+ struct v4l2_subdev_ir_parameters rx_params;
+ struct mutex rx_params_lock; /* protects Rx parameter settings cache */
+ atomic_t rxclk_divider;
+ atomic_t rx_invert;
+
+ struct kfifo rx_kfifo;
+ spinlock_t rx_kfifo_lock; /* protect Rx data kfifo */
+
+ struct v4l2_subdev_ir_parameters tx_params;
+ struct mutex tx_params_lock; /* protects Tx parameter settings cache */
+ atomic_t txclk_divider;
+};
+
+static inline struct cx25840_ir_state *to_ir_state(struct v4l2_subdev *sd)
+{
+ struct cx25840_state *state = to_state(sd);
+ return state ? state->ir_state : NULL;
+}
+
+
+/*
+ * Rx and Tx Clock Divider register computations
+ *
+ * Note the largest clock divider value of 0xffff corresponds to:
+ * (0xffff + 1) * 1000 / 108/2 MHz = 1,213,629.629... ns
+ * which fits in 21 bits, so we'll use unsigned int for time arguments.
+ */
+static inline u16 count_to_clock_divider(unsigned int d)
+{
+ if (d > RXCLK_RCD + 1)
+ d = RXCLK_RCD;
+ else if (d < 2)
+ d = 1;
+ else
+ d--;
+ return (u16) d;
+}
+
+static inline u16 ns_to_clock_divider(unsigned int ns)
+{
+ return count_to_clock_divider(
+ DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
+}
+
+static inline unsigned int clock_divider_to_ns(unsigned int divider)
+{
+ /* Period of the Rx or Tx clock in ns */
+ return DIV_ROUND_CLOSEST((divider + 1) * 1000,
+ CX25840_IR_REFCLK_FREQ / 1000000);
+}
+
+static inline u16 carrier_freq_to_clock_divider(unsigned int freq)
+{
+ return count_to_clock_divider(
+ DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * 16));
+}
+
+static inline unsigned int clock_divider_to_carrier_freq(unsigned int divider)
+{
+ return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, (divider + 1) * 16);
+}
+
+static inline u16 freq_to_clock_divider(unsigned int freq,
+ unsigned int rollovers)
+{
+ return count_to_clock_divider(
+ DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ, freq * rollovers));
+}
+
+static inline unsigned int clock_divider_to_freq(unsigned int divider,
+ unsigned int rollovers)
+{
+ return DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ,
+ (divider + 1) * rollovers);
+}
+
+/*
+ * Low Pass Filter register calculations
+ *
+ * Note the largest count value of 0xffff corresponds to:
+ * 0xffff * 1000 / 108/2 MHz = 1,213,611.11... ns
+ * which fits in 21 bits, so we'll use unsigned int for time arguments.
+ */
+static inline u16 count_to_lpf_count(unsigned int d)
+{
+ if (d > FILTR_LPF)
+ d = FILTR_LPF;
+ else if (d < 4)
+ d = 0;
+ return (u16) d;
+}
+
+static inline u16 ns_to_lpf_count(unsigned int ns)
+{
+ return count_to_lpf_count(
+ DIV_ROUND_CLOSEST(CX25840_IR_REFCLK_FREQ / 1000000 * ns, 1000));
+}
+
+static inline unsigned int lpf_count_to_ns(unsigned int count)
+{
+ /* Duration of the Low Pass Filter rejection window in ns */
+ return DIV_ROUND_CLOSEST(count * 1000,
+ CX25840_IR_REFCLK_FREQ / 1000000);
+}
+
+static inline unsigned int lpf_count_to_us(unsigned int count)
+{
+ /* Duration of the Low Pass Filter rejection window in us */
+ return DIV_ROUND_CLOSEST(count, CX25840_IR_REFCLK_FREQ / 1000000);
+}
+
+/*
+ * FIFO register pulse width count compuations
+ */
+static u32 clock_divider_to_resolution(u16 divider)
+{
+ /*
+ * Resolution is the duration of 1 tick of the readable portion of
+ * of the pulse width counter as read from the FIFO. The two lsb's are
+ * not readable, hence the << 2. This function returns ns.
+ */
+ return DIV_ROUND_CLOSEST((1 << 2) * ((u32) divider + 1) * 1000,
+ CX25840_IR_REFCLK_FREQ / 1000000);
+}
+
+static u64 pulse_width_count_to_ns(u16 count, u16 divider)
+{
+ u64 n;
+ u32 rem;
+
+ /*
+ * The 2 lsb's of the pulse width timer count are not readable, hence
+ * the (count << 2) | 0x3
+ */
+ n = (((u64) count << 2) | 0x3) * (divider + 1) * 1000; /* millicycles */
+ rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => ns */
+ if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2)
+ n++;
+ return n;
+}
+
+#if 0
+/* Keep as we will need this for Transmit functionality */
+static u16 ns_to_pulse_width_count(u32 ns, u16 divider)
+{
+ u64 n;
+ u32 d;
+ u32 rem;
+
+ /*
+ * The 2 lsb's of the pulse width timer count are not accessible, hence
+ * the (1 << 2)
+ */
+ n = ((u64) ns) * CX25840_IR_REFCLK_FREQ / 1000000; /* millicycles */
+ d = (1 << 2) * ((u32) divider + 1) * 1000; /* millicycles/count */
+ rem = do_div(n, d);
+ if (rem >= d / 2)
+ n++;
+
+ if (n > FIFO_RXTX)
+ n = FIFO_RXTX;
+ else if (n == 0)
+ n = 1;
+ return (u16) n;
+}
+
+#endif
+static unsigned int pulse_width_count_to_us(u16 count, u16 divider)
+{
+ u64 n;
+ u32 rem;
+
+ /*
+ * The 2 lsb's of the pulse width timer count are not readable, hence
+ * the (count << 2) | 0x3
+ */
+ n = (((u64) count << 2) | 0x3) * (divider + 1); /* cycles */
+ rem = do_div(n, CX25840_IR_REFCLK_FREQ / 1000000); /* / MHz => us */
+ if (rem >= CX25840_IR_REFCLK_FREQ / 1000000 / 2)
+ n++;
+ return (unsigned int) n;
+}
+
+/*
+ * Pulse Clocks computations: Combined Pulse Width Count & Rx Clock Counts
+ *
+ * The total pulse clock count is an 18 bit pulse width timer count as the most
+ * significant part and (up to) 16 bit clock divider count as a modulus.
+ * When the Rx clock divider ticks down to 0, it increments the 18 bit pulse
+ * width timer count's least significant bit.
+ */
+static u64 ns_to_pulse_clocks(u32 ns)
+{
+ u64 clocks;
+ u32 rem;
+ clocks = CX25840_IR_REFCLK_FREQ / 1000000 * (u64) ns; /* millicycles */
+ rem = do_div(clocks, 1000); /* /1000 = cycles */
+ if (rem >= 1000 / 2)
+ clocks++;
+ return clocks;
+}
+
+static u16 pulse_clocks_to_clock_divider(u64 count)
+{
+ u32 rem;
+
+ rem = do_div(count, (FIFO_RXTX << 2) | 0x3);
+
+ /* net result needs to be rounded down and decremented by 1 */
+ if (count > RXCLK_RCD + 1)
+ count = RXCLK_RCD;
+ else if (count < 2)
+ count = 1;
+ else
+ count--;
+ return (u16) count;
+}
+
+/*
+ * IR Control Register helpers
+ */
+enum tx_fifo_watermark {
+ TX_FIFO_HALF_EMPTY = 0,
+ TX_FIFO_EMPTY = CNTRL_TIC,
+};
+
+enum rx_fifo_watermark {
+ RX_FIFO_HALF_FULL = 0,
+ RX_FIFO_NOT_EMPTY = CNTRL_RIC,
+};
+
+static inline void control_tx_irq_watermark(struct i2c_client *c,
+ enum tx_fifo_watermark level)
+{
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_TIC, level);
+}
+
+static inline void control_rx_irq_watermark(struct i2c_client *c,
+ enum rx_fifo_watermark level)
+{
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_RIC, level);
+}
+
+static inline void control_tx_enable(struct i2c_client *c, bool enable)
+{
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_TXE | CNTRL_TFE),
+ enable ? (CNTRL_TXE | CNTRL_TFE) : 0);
+}
+
+static inline void control_rx_enable(struct i2c_client *c, bool enable)
+{
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~(CNTRL_RXE | CNTRL_RFE),
+ enable ? (CNTRL_RXE | CNTRL_RFE) : 0);
+}
+
+static inline void control_tx_modulation_enable(struct i2c_client *c,
+ bool enable)
+{
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_MOD,
+ enable ? CNTRL_MOD : 0);
+}
+
+static inline void control_rx_demodulation_enable(struct i2c_client *c,
+ bool enable)
+{
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_DMD,
+ enable ? CNTRL_DMD : 0);
+}
+
+static inline void control_rx_s_edge_detection(struct i2c_client *c,
+ u32 edge_types)
+{
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_EDG_BOTH,
+ edge_types & CNTRL_EDG_BOTH);
+}
+
+static void control_rx_s_carrier_window(struct i2c_client *c,
+ unsigned int carrier,
+ unsigned int *carrier_range_low,
+ unsigned int *carrier_range_high)
+{
+ u32 v;
+ unsigned int c16 = carrier * 16;
+
+ if (*carrier_range_low < DIV_ROUND_CLOSEST(c16, 16 + 3)) {
+ v = CNTRL_WIN_3_4;
+ *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 4);
+ } else {
+ v = CNTRL_WIN_3_3;
+ *carrier_range_low = DIV_ROUND_CLOSEST(c16, 16 + 3);
+ }
+
+ if (*carrier_range_high > DIV_ROUND_CLOSEST(c16, 16 - 3)) {
+ v |= CNTRL_WIN_4_3;
+ *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 4);
+ } else {
+ v |= CNTRL_WIN_3_3;
+ *carrier_range_high = DIV_ROUND_CLOSEST(c16, 16 - 3);
+ }
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_WIN, v);
+}
+
+static inline void control_tx_polarity_invert(struct i2c_client *c,
+ bool invert)
+{
+ cx25840_and_or4(c, CX25840_IR_CNTRL_REG, ~CNTRL_CPL,
+ invert ? CNTRL_CPL : 0);
+}
+
+/*
+ * IR Rx & Tx Clock Register helpers
+ */
+static unsigned int txclk_tx_s_carrier(struct i2c_client *c,
+ unsigned int freq,
+ u16 *divider)
+{
+ *divider = carrier_freq_to_clock_divider(freq);
+ cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
+ return clock_divider_to_carrier_freq(*divider);
+}
+
+static unsigned int rxclk_rx_s_carrier(struct i2c_client *c,
+ unsigned int freq,
+ u16 *divider)
+{
+ *divider = carrier_freq_to_clock_divider(freq);
+ cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
+ return clock_divider_to_carrier_freq(*divider);
+}
+
+static u32 txclk_tx_s_max_pulse_width(struct i2c_client *c, u32 ns,
+ u16 *divider)
+{
+ u64 pulse_clocks;
+
+ if (ns > IR_MAX_DURATION)
+ ns = IR_MAX_DURATION;
+ pulse_clocks = ns_to_pulse_clocks(ns);
+ *divider = pulse_clocks_to_clock_divider(pulse_clocks);
+ cx25840_write4(c, CX25840_IR_TXCLK_REG, *divider);
+ return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
+}
+
+static u32 rxclk_rx_s_max_pulse_width(struct i2c_client *c, u32 ns,
+ u16 *divider)
+{
+ u64 pulse_clocks;
+
+ if (ns > IR_MAX_DURATION)
+ ns = IR_MAX_DURATION;
+ pulse_clocks = ns_to_pulse_clocks(ns);
+ *divider = pulse_clocks_to_clock_divider(pulse_clocks);
+ cx25840_write4(c, CX25840_IR_RXCLK_REG, *divider);
+ return (u32) pulse_width_count_to_ns(FIFO_RXTX, *divider);
+}
+
+/*
+ * IR Tx Carrier Duty Cycle register helpers
+ */
+static unsigned int cduty_tx_s_duty_cycle(struct i2c_client *c,
+ unsigned int duty_cycle)
+{
+ u32 n;
+ n = DIV_ROUND_CLOSEST(duty_cycle * 100, 625); /* 16ths of 100% */
+ if (n != 0)
+ n--;
+ if (n > 15)
+ n = 15;
+ cx25840_write4(c, CX25840_IR_CDUTY_REG, n);
+ return DIV_ROUND_CLOSEST((n + 1) * 100, 16);
+}
+
+/*
+ * IR Filter Register helpers
+ */
+static u32 filter_rx_s_min_width(struct i2c_client *c, u32 min_width_ns)
+{
+ u32 count = ns_to_lpf_count(min_width_ns);
+ cx25840_write4(c, CX25840_IR_FILTR_REG, count);
+ return lpf_count_to_ns(count);
+}
+
+/*
+ * IR IRQ Enable Register helpers
+ */
+static inline void irqenable_rx(struct v4l2_subdev *sd, u32 mask)
+{
+ struct cx25840_state *state = to_state(sd);
+
+ if (is_cx23885(state) || is_cx23887(state))
+ mask ^= IRQEN_MSK;
+ mask &= (IRQEN_RTE | IRQEN_ROE | IRQEN_RSE);
+ cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG,
+ ~(IRQEN_RTE | IRQEN_ROE | IRQEN_RSE), mask);
+}
+
+static inline void irqenable_tx(struct v4l2_subdev *sd, u32 mask)
+{
+ struct cx25840_state *state = to_state(sd);
+
+ if (is_cx23885(state) || is_cx23887(state))
+ mask ^= IRQEN_MSK;
+ mask &= IRQEN_TSE;
+ cx25840_and_or4(state->c, CX25840_IR_IRQEN_REG, ~IRQEN_TSE, mask);
+}
+
+/*
+ * V4L2 Subdevice IR Ops
+ */
+int cx25840_ir_irq_handler(struct v4l2_subdev *sd, u32 status, bool *handled)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+ struct i2c_client *c = NULL;
+ unsigned long flags;
+
+ union cx25840_ir_fifo_rec rx_data[FIFO_RX_DEPTH];
+ unsigned int i, j, k;
+ u32 events, v;
+ int tsr, rsr, rto, ror, tse, rse, rte, roe, kror;
+ u32 cntrl, irqen, stats;
+
+ *handled = false;
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ c = ir_state->c;
+
+ /* Only support the IR controller for the CX2388[57] AV Core for now */
+ if (!(is_cx23885(state) || is_cx23887(state)))
+ return -ENODEV;
+
+ cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG);
+ irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG);
+ if (is_cx23885(state) || is_cx23887(state))
+ irqen ^= IRQEN_MSK;
+ stats = cx25840_read4(c, CX25840_IR_STATS_REG);
+
+ tsr = stats & STATS_TSR; /* Tx FIFO Service Request */
+ rsr = stats & STATS_RSR; /* Rx FIFO Service Request */
+ rto = stats & STATS_RTO; /* Rx Pulse Width Timer Time Out */
+ ror = stats & STATS_ROR; /* Rx FIFO Over Run */
+
+ tse = irqen & IRQEN_TSE; /* Tx FIFO Service Request IRQ Enable */
+ rse = irqen & IRQEN_RSE; /* Rx FIFO Service Reuqest IRQ Enable */
+ rte = irqen & IRQEN_RTE; /* Rx Pulse Width Timer Time Out IRQ Enable */
+ roe = irqen & IRQEN_ROE; /* Rx FIFO Over Run IRQ Enable */
+
+ v4l2_dbg(2, ir_debug, sd, "IR IRQ Status: %s %s %s %s %s %s\n",
+ tsr ? "tsr" : " ", rsr ? "rsr" : " ",
+ rto ? "rto" : " ", ror ? "ror" : " ",
+ stats & STATS_TBY ? "tby" : " ",
+ stats & STATS_RBY ? "rby" : " ");
+
+ v4l2_dbg(2, ir_debug, sd, "IR IRQ Enables: %s %s %s %s\n",
+ tse ? "tse" : " ", rse ? "rse" : " ",
+ rte ? "rte" : " ", roe ? "roe" : " ");
+
+ /*
+ * Transmitter interrupt service
+ */
+ if (tse && tsr) {
+ /*
+ * TODO:
+ * Check the watermark threshold setting
+ * Pull FIFO_TX_DEPTH or FIFO_TX_DEPTH/2 entries from tx_kfifo
+ * Push the data to the hardware FIFO.
+ * If there was nothing more to send in the tx_kfifo, disable
+ * the TSR IRQ and notify the v4l2_device.
+ * If there was something in the tx_kfifo, check the tx_kfifo
+ * level and notify the v4l2_device, if it is low.
+ */
+ /* For now, inhibit TSR interrupt until Tx is implemented */
+ irqenable_tx(sd, 0);
+ events = V4L2_SUBDEV_IR_TX_FIFO_SERVICE_REQ;
+ v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_TX_NOTIFY, &events);
+ *handled = true;
+ }
+
+ /*
+ * Receiver interrupt service
+ */
+ kror = 0;
+ if ((rse && rsr) || (rte && rto)) {
+ /*
+ * Receive data on RSR to clear the STATS_RSR.
+ * Receive data on RTO, since we may not have yet hit the RSR
+ * watermark when we receive the RTO.
+ */
+ for (i = 0, v = FIFO_RX_NDV;
+ (v & FIFO_RX_NDV) && !kror; i = 0) {
+ for (j = 0;
+ (v & FIFO_RX_NDV) && j < FIFO_RX_DEPTH; j++) {
+ v = cx25840_read4(c, CX25840_IR_FIFO_REG);
+ rx_data[i].hw_fifo_data = v & ~FIFO_RX_NDV;
+ i++;
+ }
+ if (i == 0)
+ break;
+ j = i * sizeof(union cx25840_ir_fifo_rec);
+ k = kfifo_in_locked(&ir_state->rx_kfifo,
+ (unsigned char *) rx_data, j,
+ &ir_state->rx_kfifo_lock);
+ if (k != j)
+ kror++; /* rx_kfifo over run */
+ }
+ *handled = true;
+ }
+
+ events = 0;
+ v = 0;
+ if (kror) {
+ events |= V4L2_SUBDEV_IR_RX_SW_FIFO_OVERRUN;
+ v4l2_err(sd, "IR receiver software FIFO overrun\n");
+ }
+ if (roe && ror) {
+ /*
+ * The RX FIFO Enable (CNTRL_RFE) must be toggled to clear
+ * the Rx FIFO Over Run status (STATS_ROR)
+ */
+ v |= CNTRL_RFE;
+ events |= V4L2_SUBDEV_IR_RX_HW_FIFO_OVERRUN;
+ v4l2_err(sd, "IR receiver hardware FIFO overrun\n");
+ }
+ if (rte && rto) {
+ /*
+ * The IR Receiver Enable (CNTRL_RXE) must be toggled to clear
+ * the Rx Pulse Width Timer Time Out (STATS_RTO)
+ */
+ v |= CNTRL_RXE;
+ events |= V4L2_SUBDEV_IR_RX_END_OF_RX_DETECTED;
+ }
+ if (v) {
+ /* Clear STATS_ROR & STATS_RTO as needed by reseting hardware */
+ cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl & ~v);
+ cx25840_write4(c, CX25840_IR_CNTRL_REG, cntrl);
+ *handled = true;
+ }
+ spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags);
+ if (kfifo_len(&ir_state->rx_kfifo) >= CX25840_IR_RX_KFIFO_SIZE / 2)
+ events |= V4L2_SUBDEV_IR_RX_FIFO_SERVICE_REQ;
+ spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags);
+
+ if (events)
+ v4l2_subdev_notify(sd, V4L2_SUBDEV_IR_RX_NOTIFY, &events);
+ return 0;
+}
+
+/* Receiver */
+static int cx25840_ir_rx_read(struct v4l2_subdev *sd, u8 *buf, size_t count,
+ ssize_t *num)
+{
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+ bool invert;
+ u16 divider;
+ unsigned int i, n;
+ union cx25840_ir_fifo_rec *p;
+ unsigned u, v;
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ invert = (bool) atomic_read(&ir_state->rx_invert);
+ divider = (u16) atomic_read(&ir_state->rxclk_divider);
+
+ n = count / sizeof(union cx25840_ir_fifo_rec)
+ * sizeof(union cx25840_ir_fifo_rec);
+ if (n == 0) {
+ *num = 0;
+ return 0;
+ }
+
+ n = kfifo_out_locked(&ir_state->rx_kfifo, buf, n,
+ &ir_state->rx_kfifo_lock);
+
+ n /= sizeof(union cx25840_ir_fifo_rec);
+ *num = n * sizeof(union cx25840_ir_fifo_rec);
+
+ for (p = (union cx25840_ir_fifo_rec *) buf, i = 0; i < n; p++, i++) {
+
+ if ((p->hw_fifo_data & FIFO_RXTX_RTO) == FIFO_RXTX_RTO) {
+ /* Assume RTO was because of no IR light input */
+ u = 0;
+ v4l2_dbg(2, ir_debug, sd, "rx read: end of rx\n");
+ } else {
+ u = (p->hw_fifo_data & FIFO_RXTX_LVL) ? 1 : 0;
+ if (invert)
+ u = u ? 0 : 1;
+ }
+
+ v = (unsigned) pulse_width_count_to_ns(
+ (u16) (p->hw_fifo_data & FIFO_RXTX), divider);
+ if (v > IR_MAX_DURATION)
+ v = IR_MAX_DURATION;
+
+ init_ir_raw_event(&p->ir_core_data);
+ p->ir_core_data.pulse = u;
+ p->ir_core_data.duration = v;
+
+ v4l2_dbg(2, ir_debug, sd, "rx read: %10u ns %s\n",
+ v, u ? "mark" : "space");
+ }
+ return 0;
+}
+
+static int cx25840_ir_rx_g_parameters(struct v4l2_subdev *sd,
+ struct v4l2_subdev_ir_parameters *p)
+{
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ mutex_lock(&ir_state->rx_params_lock);
+ memcpy(p, &ir_state->rx_params,
+ sizeof(struct v4l2_subdev_ir_parameters));
+ mutex_unlock(&ir_state->rx_params_lock);
+ return 0;
+}
+
+static int cx25840_ir_rx_shutdown(struct v4l2_subdev *sd)
+{
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+ struct i2c_client *c;
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ c = ir_state->c;
+ mutex_lock(&ir_state->rx_params_lock);
+
+ /* Disable or slow down all IR Rx circuits and counters */
+ irqenable_rx(sd, 0);
+ control_rx_enable(c, false);
+ control_rx_demodulation_enable(c, false);
+ control_rx_s_edge_detection(c, CNTRL_EDG_NONE);
+ filter_rx_s_min_width(c, 0);
+ cx25840_write4(c, CX25840_IR_RXCLK_REG, RXCLK_RCD);
+
+ ir_state->rx_params.shutdown = true;
+
+ mutex_unlock(&ir_state->rx_params_lock);
+ return 0;
+}
+
+static int cx25840_ir_rx_s_parameters(struct v4l2_subdev *sd,
+ struct v4l2_subdev_ir_parameters *p)
+{
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+ struct i2c_client *c;
+ struct v4l2_subdev_ir_parameters *o;
+ u16 rxclk_divider;
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ if (p->shutdown)
+ return cx25840_ir_rx_shutdown(sd);
+
+ if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
+ return -ENOSYS;
+
+ c = ir_state->c;
+ o = &ir_state->rx_params;
+
+ mutex_lock(&ir_state->rx_params_lock);
+
+ o->shutdown = p->shutdown;
+
+ p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+ o->mode = p->mode;
+
+ p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec);
+ o->bytes_per_data_element = p->bytes_per_data_element;
+
+ /* Before we tweak the hardware, we have to disable the receiver */
+ irqenable_rx(sd, 0);
+ control_rx_enable(c, false);
+
+ control_rx_demodulation_enable(c, p->modulation);
+ o->modulation = p->modulation;
+
+ if (p->modulation) {
+ p->carrier_freq = rxclk_rx_s_carrier(c, p->carrier_freq,
+ &rxclk_divider);
+
+ o->carrier_freq = p->carrier_freq;
+
+ p->duty_cycle = 50;
+ o->duty_cycle = p->duty_cycle;
+
+ control_rx_s_carrier_window(c, p->carrier_freq,
+ &p->carrier_range_lower,
+ &p->carrier_range_upper);
+ o->carrier_range_lower = p->carrier_range_lower;
+ o->carrier_range_upper = p->carrier_range_upper;
+
+ p->max_pulse_width =
+ (u32) pulse_width_count_to_ns(FIFO_RXTX, rxclk_divider);
+ } else {
+ p->max_pulse_width =
+ rxclk_rx_s_max_pulse_width(c, p->max_pulse_width,
+ &rxclk_divider);
+ }
+ o->max_pulse_width = p->max_pulse_width;
+ atomic_set(&ir_state->rxclk_divider, rxclk_divider);
+
+ p->noise_filter_min_width =
+ filter_rx_s_min_width(c, p->noise_filter_min_width);
+ o->noise_filter_min_width = p->noise_filter_min_width;
+
+ p->resolution = clock_divider_to_resolution(rxclk_divider);
+ o->resolution = p->resolution;
+
+ /* FIXME - make this dependent on resolution for better performance */
+ control_rx_irq_watermark(c, RX_FIFO_HALF_FULL);
+
+ control_rx_s_edge_detection(c, CNTRL_EDG_BOTH);
+
+ o->invert_level = p->invert_level;
+ atomic_set(&ir_state->rx_invert, p->invert_level);
+
+ o->interrupt_enable = p->interrupt_enable;
+ o->enable = p->enable;
+ if (p->enable) {
+ unsigned long flags;
+
+ spin_lock_irqsave(&ir_state->rx_kfifo_lock, flags);
+ kfifo_reset(&ir_state->rx_kfifo);
+ spin_unlock_irqrestore(&ir_state->rx_kfifo_lock, flags);
+ if (p->interrupt_enable)
+ irqenable_rx(sd, IRQEN_RSE | IRQEN_RTE | IRQEN_ROE);
+ control_rx_enable(c, p->enable);
+ }
+
+ mutex_unlock(&ir_state->rx_params_lock);
+ return 0;
+}
+
+/* Transmitter */
+static int cx25840_ir_tx_write(struct v4l2_subdev *sd, u8 *buf, size_t count,
+ ssize_t *num)
+{
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+ struct i2c_client *c;
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ c = ir_state->c;
+#if 0
+ /*
+ * FIXME - the code below is an incomplete and untested sketch of what
+ * may need to be done. The critical part is to get 4 (or 8) pulses
+ * from the tx_kfifo, or converted from ns to the proper units from the
+ * input, and push them off to the hardware Tx FIFO right away, if the
+ * HW TX fifo needs service. The rest can be pushed to the tx_kfifo in
+ * a less critical timeframe. Also watch out for overruning the
+ * tx_kfifo - don't let it happen and let the caller know not all his
+ * pulses were written.
+ */
+ u32 *ns_pulse = (u32 *) buf;
+ unsigned int n;
+ u32 fifo_pulse[FIFO_TX_DEPTH];
+ u32 mark;
+
+ /* Compute how much we can fit in the tx kfifo */
+ n = CX25840_IR_TX_KFIFO_SIZE - kfifo_len(ir_state->tx_kfifo);
+ n = min(n, (unsigned int) count);
+ n /= sizeof(u32);
+
+ /* FIXME - turn on Tx Fifo service interrupt
+ * check hardware fifo level, and other stuff
+ */
+ for (i = 0; i < n; ) {
+ for (j = 0; j < FIFO_TX_DEPTH / 2 && i < n; j++) {
+ mark = ns_pulse[i] & LEVEL_MASK;
+ fifo_pulse[j] = ns_to_pulse_width_count(
+ ns_pulse[i] &
+ ~LEVEL_MASK,
+ ir_state->txclk_divider);
+ if (mark)
+ fifo_pulse[j] &= FIFO_RXTX_LVL;
+ i++;
+ }
+ kfifo_put(ir_state->tx_kfifo, (u8 *) fifo_pulse,
+ j * sizeof(u32));
+ }
+ *num = n * sizeof(u32);
+#else
+ /* For now enable the Tx FIFO Service interrupt & pretend we did work */
+ irqenable_tx(sd, IRQEN_TSE);
+ *num = count;
+#endif
+ return 0;
+}
+
+static int cx25840_ir_tx_g_parameters(struct v4l2_subdev *sd,
+ struct v4l2_subdev_ir_parameters *p)
+{
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ mutex_lock(&ir_state->tx_params_lock);
+ memcpy(p, &ir_state->tx_params,
+ sizeof(struct v4l2_subdev_ir_parameters));
+ mutex_unlock(&ir_state->tx_params_lock);
+ return 0;
+}
+
+static int cx25840_ir_tx_shutdown(struct v4l2_subdev *sd)
+{
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+ struct i2c_client *c;
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ c = ir_state->c;
+ mutex_lock(&ir_state->tx_params_lock);
+
+ /* Disable or slow down all IR Tx circuits and counters */
+ irqenable_tx(sd, 0);
+ control_tx_enable(c, false);
+ control_tx_modulation_enable(c, false);
+ cx25840_write4(c, CX25840_IR_TXCLK_REG, TXCLK_TCD);
+
+ ir_state->tx_params.shutdown = true;
+
+ mutex_unlock(&ir_state->tx_params_lock);
+ return 0;
+}
+
+static int cx25840_ir_tx_s_parameters(struct v4l2_subdev *sd,
+ struct v4l2_subdev_ir_parameters *p)
+{
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+ struct i2c_client *c;
+ struct v4l2_subdev_ir_parameters *o;
+ u16 txclk_divider;
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ if (p->shutdown)
+ return cx25840_ir_tx_shutdown(sd);
+
+ if (p->mode != V4L2_SUBDEV_IR_MODE_PULSE_WIDTH)
+ return -ENOSYS;
+
+ c = ir_state->c;
+ o = &ir_state->tx_params;
+ mutex_lock(&ir_state->tx_params_lock);
+
+ o->shutdown = p->shutdown;
+
+ p->mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH;
+ o->mode = p->mode;
+
+ p->bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec);
+ o->bytes_per_data_element = p->bytes_per_data_element;
+
+ /* Before we tweak the hardware, we have to disable the transmitter */
+ irqenable_tx(sd, 0);
+ control_tx_enable(c, false);
+
+ control_tx_modulation_enable(c, p->modulation);
+ o->modulation = p->modulation;
+
+ if (p->modulation) {
+ p->carrier_freq = txclk_tx_s_carrier(c, p->carrier_freq,
+ &txclk_divider);
+ o->carrier_freq = p->carrier_freq;
+
+ p->duty_cycle = cduty_tx_s_duty_cycle(c, p->duty_cycle);
+ o->duty_cycle = p->duty_cycle;
+
+ p->max_pulse_width =
+ (u32) pulse_width_count_to_ns(FIFO_RXTX, txclk_divider);
+ } else {
+ p->max_pulse_width =
+ txclk_tx_s_max_pulse_width(c, p->max_pulse_width,
+ &txclk_divider);
+ }
+ o->max_pulse_width = p->max_pulse_width;
+ atomic_set(&ir_state->txclk_divider, txclk_divider);
+
+ p->resolution = clock_divider_to_resolution(txclk_divider);
+ o->resolution = p->resolution;
+
+ /* FIXME - make this dependent on resolution for better performance */
+ control_tx_irq_watermark(c, TX_FIFO_HALF_EMPTY);
+
+ control_tx_polarity_invert(c, p->invert_carrier_sense);
+ o->invert_carrier_sense = p->invert_carrier_sense;
+
+ /*
+ * FIXME: we don't have hardware help for IO pin level inversion
+ * here like we have on the CX23888.
+ * Act on this with some mix of logical inversion of data levels,
+ * carrier polarity, and carrier duty cycle.
+ */
+ o->invert_level = p->invert_level;
+
+ o->interrupt_enable = p->interrupt_enable;
+ o->enable = p->enable;
+ if (p->enable) {
+ /* reset tx_fifo here */
+ if (p->interrupt_enable)
+ irqenable_tx(sd, IRQEN_TSE);
+ control_tx_enable(c, p->enable);
+ }
+
+ mutex_unlock(&ir_state->tx_params_lock);
+ return 0;
+}
+
+
+/*
+ * V4L2 Subdevice Core Ops support
+ */
+int cx25840_ir_log_status(struct v4l2_subdev *sd)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct i2c_client *c = state->c;
+ char *s;
+ int i, j;
+ u32 cntrl, txclk, rxclk, cduty, stats, irqen, filtr;
+
+ /* The CX23888 chip doesn't have an IR controller on the A/V core */
+ if (is_cx23888(state))
+ return 0;
+
+ cntrl = cx25840_read4(c, CX25840_IR_CNTRL_REG);
+ txclk = cx25840_read4(c, CX25840_IR_TXCLK_REG) & TXCLK_TCD;
+ rxclk = cx25840_read4(c, CX25840_IR_RXCLK_REG) & RXCLK_RCD;
+ cduty = cx25840_read4(c, CX25840_IR_CDUTY_REG) & CDUTY_CDC;
+ stats = cx25840_read4(c, CX25840_IR_STATS_REG);
+ irqen = cx25840_read4(c, CX25840_IR_IRQEN_REG);
+ if (is_cx23885(state) || is_cx23887(state))
+ irqen ^= IRQEN_MSK;
+ filtr = cx25840_read4(c, CX25840_IR_FILTR_REG) & FILTR_LPF;
+
+ v4l2_info(sd, "IR Receiver:\n");
+ v4l2_info(sd, "\tEnabled: %s\n",
+ cntrl & CNTRL_RXE ? "yes" : "no");
+ v4l2_info(sd, "\tDemodulation from a carrier: %s\n",
+ cntrl & CNTRL_DMD ? "enabled" : "disabled");
+ v4l2_info(sd, "\tFIFO: %s\n",
+ cntrl & CNTRL_RFE ? "enabled" : "disabled");
+ switch (cntrl & CNTRL_EDG) {
+ case CNTRL_EDG_NONE:
+ s = "disabled";
+ break;
+ case CNTRL_EDG_FALL:
+ s = "falling edge";
+ break;
+ case CNTRL_EDG_RISE:
+ s = "rising edge";
+ break;
+ case CNTRL_EDG_BOTH:
+ s = "rising & falling edges";
+ break;
+ default:
+ s = "??? edge";
+ break;
+ }
+ v4l2_info(sd, "\tPulse timers' start/stop trigger: %s\n", s);
+ v4l2_info(sd, "\tFIFO data on pulse timer overflow: %s\n",
+ cntrl & CNTRL_R ? "not loaded" : "overflow marker");
+ v4l2_info(sd, "\tFIFO interrupt watermark: %s\n",
+ cntrl & CNTRL_RIC ? "not empty" : "half full or greater");
+ v4l2_info(sd, "\tLoopback mode: %s\n",
+ cntrl & CNTRL_LBM ? "loopback active" : "normal receive");
+ if (cntrl & CNTRL_DMD) {
+ v4l2_info(sd, "\tExpected carrier (16 clocks): %u Hz\n",
+ clock_divider_to_carrier_freq(rxclk));
+ switch (cntrl & CNTRL_WIN) {
+ case CNTRL_WIN_3_3:
+ i = 3;
+ j = 3;
+ break;
+ case CNTRL_WIN_4_3:
+ i = 4;
+ j = 3;
+ break;
+ case CNTRL_WIN_3_4:
+ i = 3;
+ j = 4;
+ break;
+ case CNTRL_WIN_4_4:
+ i = 4;
+ j = 4;
+ break;
+ default:
+ i = 0;
+ j = 0;
+ break;
+ }
+ v4l2_info(sd, "\tNext carrier edge window: 16 clocks "
+ "-%1d/+%1d, %u to %u Hz\n", i, j,
+ clock_divider_to_freq(rxclk, 16 + j),
+ clock_divider_to_freq(rxclk, 16 - i));
+ }
+ v4l2_info(sd, "\tMax measurable pulse width: %u us, %llu ns\n",
+ pulse_width_count_to_us(FIFO_RXTX, rxclk),
+ pulse_width_count_to_ns(FIFO_RXTX, rxclk));
+ v4l2_info(sd, "\tLow pass filter: %s\n",
+ filtr ? "enabled" : "disabled");
+ if (filtr)
+ v4l2_info(sd, "\tMin acceptable pulse width (LPF): %u us, "
+ "%u ns\n",
+ lpf_count_to_us(filtr),
+ lpf_count_to_ns(filtr));
+ v4l2_info(sd, "\tPulse width timer timed-out: %s\n",
+ stats & STATS_RTO ? "yes" : "no");
+ v4l2_info(sd, "\tPulse width timer time-out intr: %s\n",
+ irqen & IRQEN_RTE ? "enabled" : "disabled");
+ v4l2_info(sd, "\tFIFO overrun: %s\n",
+ stats & STATS_ROR ? "yes" : "no");
+ v4l2_info(sd, "\tFIFO overrun interrupt: %s\n",
+ irqen & IRQEN_ROE ? "enabled" : "disabled");
+ v4l2_info(sd, "\tBusy: %s\n",
+ stats & STATS_RBY ? "yes" : "no");
+ v4l2_info(sd, "\tFIFO service requested: %s\n",
+ stats & STATS_RSR ? "yes" : "no");
+ v4l2_info(sd, "\tFIFO service request interrupt: %s\n",
+ irqen & IRQEN_RSE ? "enabled" : "disabled");
+
+ v4l2_info(sd, "IR Transmitter:\n");
+ v4l2_info(sd, "\tEnabled: %s\n",
+ cntrl & CNTRL_TXE ? "yes" : "no");
+ v4l2_info(sd, "\tModulation onto a carrier: %s\n",
+ cntrl & CNTRL_MOD ? "enabled" : "disabled");
+ v4l2_info(sd, "\tFIFO: %s\n",
+ cntrl & CNTRL_TFE ? "enabled" : "disabled");
+ v4l2_info(sd, "\tFIFO interrupt watermark: %s\n",
+ cntrl & CNTRL_TIC ? "not empty" : "half full or less");
+ v4l2_info(sd, "\tCarrier polarity: %s\n",
+ cntrl & CNTRL_CPL ? "space:burst mark:noburst"
+ : "space:noburst mark:burst");
+ if (cntrl & CNTRL_MOD) {
+ v4l2_info(sd, "\tCarrier (16 clocks): %u Hz\n",
+ clock_divider_to_carrier_freq(txclk));
+ v4l2_info(sd, "\tCarrier duty cycle: %2u/16\n",
+ cduty + 1);
+ }
+ v4l2_info(sd, "\tMax pulse width: %u us, %llu ns\n",
+ pulse_width_count_to_us(FIFO_RXTX, txclk),
+ pulse_width_count_to_ns(FIFO_RXTX, txclk));
+ v4l2_info(sd, "\tBusy: %s\n",
+ stats & STATS_TBY ? "yes" : "no");
+ v4l2_info(sd, "\tFIFO service requested: %s\n",
+ stats & STATS_TSR ? "yes" : "no");
+ v4l2_info(sd, "\tFIFO service request interrupt: %s\n",
+ irqen & IRQEN_TSE ? "enabled" : "disabled");
+
+ return 0;
+}
+
+
+const struct v4l2_subdev_ir_ops cx25840_ir_ops = {
+ .rx_read = cx25840_ir_rx_read,
+ .rx_g_parameters = cx25840_ir_rx_g_parameters,
+ .rx_s_parameters = cx25840_ir_rx_s_parameters,
+
+ .tx_write = cx25840_ir_tx_write,
+ .tx_g_parameters = cx25840_ir_tx_g_parameters,
+ .tx_s_parameters = cx25840_ir_tx_s_parameters,
+};
+
+
+static const struct v4l2_subdev_ir_parameters default_rx_params = {
+ .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec),
+ .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
+
+ .enable = false,
+ .interrupt_enable = false,
+ .shutdown = true,
+
+ .modulation = true,
+ .carrier_freq = 36000, /* 36 kHz - RC-5, and RC-6 carrier */
+
+ /* RC-5: 666,667 ns = 1/36 kHz * 32 cycles * 1 mark * 0.75 */
+ /* RC-6: 333,333 ns = 1/36 kHz * 16 cycles * 1 mark * 0.75 */
+ .noise_filter_min_width = 333333, /* ns */
+ .carrier_range_lower = 35000,
+ .carrier_range_upper = 37000,
+ .invert_level = false,
+};
+
+static const struct v4l2_subdev_ir_parameters default_tx_params = {
+ .bytes_per_data_element = sizeof(union cx25840_ir_fifo_rec),
+ .mode = V4L2_SUBDEV_IR_MODE_PULSE_WIDTH,
+
+ .enable = false,
+ .interrupt_enable = false,
+ .shutdown = true,
+
+ .modulation = true,
+ .carrier_freq = 36000, /* 36 kHz - RC-5 carrier */
+ .duty_cycle = 25, /* 25 % - RC-5 carrier */
+ .invert_level = false,
+ .invert_carrier_sense = false,
+};
+
+int cx25840_ir_probe(struct v4l2_subdev *sd)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct cx25840_ir_state *ir_state;
+ struct v4l2_subdev_ir_parameters default_params;
+
+ /* Only init the IR controller for the CX2388[57] AV Core for now */
+ if (!(is_cx23885(state) || is_cx23887(state)))
+ return 0;
+
+ ir_state = kzalloc(sizeof(struct cx25840_ir_state), GFP_KERNEL);
+ if (ir_state == NULL)
+ return -ENOMEM;
+
+ spin_lock_init(&ir_state->rx_kfifo_lock);
+ if (kfifo_alloc(&ir_state->rx_kfifo,
+ CX25840_IR_RX_KFIFO_SIZE, GFP_KERNEL)) {
+ kfree(ir_state);
+ return -ENOMEM;
+ }
+
+ ir_state->c = state->c;
+ state->ir_state = ir_state;
+
+ /* Ensure no interrupts arrive yet */
+ if (is_cx23885(state) || is_cx23887(state))
+ cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, IRQEN_MSK);
+ else
+ cx25840_write4(ir_state->c, CX25840_IR_IRQEN_REG, 0);
+
+ mutex_init(&ir_state->rx_params_lock);
+ memcpy(&default_params, &default_rx_params,
+ sizeof(struct v4l2_subdev_ir_parameters));
+ v4l2_subdev_call(sd, ir, rx_s_parameters, &default_params);
+
+ mutex_init(&ir_state->tx_params_lock);
+ memcpy(&default_params, &default_tx_params,
+ sizeof(struct v4l2_subdev_ir_parameters));
+ v4l2_subdev_call(sd, ir, tx_s_parameters, &default_params);
+
+ return 0;
+}
+
+int cx25840_ir_remove(struct v4l2_subdev *sd)
+{
+ struct cx25840_state *state = to_state(sd);
+ struct cx25840_ir_state *ir_state = to_ir_state(sd);
+
+ if (ir_state == NULL)
+ return -ENODEV;
+
+ cx25840_ir_rx_shutdown(sd);
+ cx25840_ir_tx_shutdown(sd);
+
+ kfifo_free(&ir_state->rx_kfifo);
+ kfree(ir_state);
+ state->ir_state = NULL;
+ return 0;
+}
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index c7e5851d3486..5c42abdf422f 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -1,12 +1,11 @@
config VIDEO_CX88
tristate "Conexant 2388x (bt878 successor) support"
- depends on VIDEO_DEV && PCI && I2C && INPUT
+ depends on VIDEO_DEV && PCI && I2C && RC_CORE
select I2C_ALGOBIT
select VIDEO_BTCX
select VIDEOBUF_DMA_SG
select VIDEO_TUNER
select VIDEO_TVEEPROM
- select VIDEO_IR
select VIDEO_WM8775 if VIDEO_HELPER_CHIPS_AUTO
---help---
This is a video4linux driver for Conexant 2388x based
@@ -17,7 +16,7 @@ config VIDEO_CX88
config VIDEO_CX88_ALSA
tristate "Conexant 2388x DMA audio support"
- depends on VIDEO_CX88 && SND && EXPERIMENTAL
+ depends on VIDEO_CX88 && SND
select SND_PCM
---help---
This is a video4linux driver for direct (DMA) audio on
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 33082c96745e..54b7fcd469a8 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -54,6 +54,12 @@
Data type declarations - Can be moded to a header file later
****************************************************************************/
+struct cx88_audio_buffer {
+ unsigned int bpl;
+ struct btcx_riscmem risc;
+ struct videobuf_dmabuf dma;
+};
+
struct cx88_audio_dev {
struct cx88_core *core;
struct cx88_dmaqueue q;
@@ -75,7 +81,7 @@ struct cx88_audio_dev {
struct videobuf_dmabuf *dma_risc;
- struct cx88_buffer *buf;
+ struct cx88_audio_buffer *buf;
struct snd_pcm_substream *substream;
};
@@ -88,7 +94,7 @@ typedef struct cx88_audio_dev snd_cx88_card_t;
****************************************************************************/
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */
-static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
+static const char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */
static int enable[SNDRV_CARDS] = {1, [1 ... (SNDRV_CARDS - 1)] = 1};
module_param_array(enable, bool, NULL, 0444);
@@ -123,9 +129,9 @@ MODULE_PARM_DESC(debug,"enable debug messages");
static int _cx88_start_audio_dma(snd_cx88_card_t *chip)
{
- struct cx88_buffer *buf = chip->buf;
+ struct cx88_audio_buffer *buf = chip->buf;
struct cx88_core *core=chip->core;
- struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
+ const struct sram_channel *audio_ch = &cx88_sram_channels[SRAM_CH25];
/* Make sure RISC/FIFO are off before changing FIFO/RISC settings */
cx_clear(MO_AUD_DMACNTRL, 0x11);
@@ -191,7 +197,7 @@ static int _cx88_stop_audio_dma(snd_cx88_card_t *chip)
/*
* BOARD Specific: IRQ dma bits
*/
-static char *cx88_aud_irqs[32] = {
+static const char *cx88_aud_irqs[32] = {
"dn_risci1", "up_risci1", "rds_dn_risc1", /* 0-2 */
NULL, /* reserved */
"dn_risci2", "up_risci2", "rds_dn_risc2", /* 4-6 */
@@ -283,7 +289,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
BUG_ON(!chip->dma_size);
dprintk(2,"Freeing buffer\n");
- videobuf_sg_dma_unmap(&chip->pci->dev, chip->dma_risc);
+ videobuf_dma_unmap(&chip->pci->dev, chip->dma_risc);
videobuf_dma_free(chip->dma_risc);
btcx_riscmem_free(chip->pci,&chip->buf->risc);
kfree(chip->buf);
@@ -302,7 +308,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
* Digital hardware definition
*/
#define DEFAULT_FIFO_SIZE 4096
-static struct snd_pcm_hardware snd_cx88_digital_hw = {
+static const struct snd_pcm_hardware snd_cx88_digital_hw = {
.info = SNDRV_PCM_INFO_MMAP |
SNDRV_PCM_INFO_INTERLEAVED |
SNDRV_PCM_INFO_BLOCK_TRANSFER |
@@ -376,7 +382,7 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
snd_cx88_card_t *chip = snd_pcm_substream_chip(substream);
struct videobuf_dmabuf *dma;
- struct cx88_buffer *buf;
+ struct cx88_audio_buffer *buf;
int ret;
if (substream->runtime->dma_area) {
@@ -391,30 +397,25 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
BUG_ON(!chip->dma_size);
BUG_ON(chip->num_periods & (chip->num_periods-1));
- buf = videobuf_sg_alloc(sizeof(*buf));
+ buf = kzalloc(sizeof(*buf), GFP_KERNEL);
if (NULL == buf)
return -ENOMEM;
- buf->vb.memory = V4L2_MEMORY_MMAP;
- buf->vb.field = V4L2_FIELD_NONE;
- buf->vb.width = chip->period_size;
- buf->bpl = chip->period_size;
- buf->vb.height = chip->num_periods;
- buf->vb.size = chip->dma_size;
+ buf->bpl = chip->period_size;
- dma = videobuf_to_dma(&buf->vb);
+ dma = &buf->dma;
videobuf_dma_init(dma);
ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
- (PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
+ (PAGE_ALIGN(chip->dma_size) >> PAGE_SHIFT));
if (ret < 0)
goto error;
- ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
+ ret = videobuf_dma_map(&chip->pci->dev, dma);
if (ret < 0)
goto error;
ret = cx88_risc_databuffer(chip->pci, &buf->risc, dma->sglist,
- buf->vb.width, buf->vb.height, 1);
+ chip->period_size, chip->num_periods, 1);
if (ret < 0)
goto error;
@@ -422,12 +423,10 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
buf->risc.jmp[0] = cpu_to_le32(RISC_JUMP|RISC_IRQ1|RISC_CNT_INC);
buf->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
- buf->vb.state = VIDEOBUF_PREPARED;
-
chip->buf = buf;
chip->dma_risc = dma;
- substream->runtime->dma_area = chip->dma_risc->vmalloc;
+ substream->runtime->dma_area = chip->dma_risc->vaddr;
substream->runtime->dma_bytes = chip->dma_size;
substream->runtime->dma_addr = 0;
return 0;
@@ -534,7 +533,7 @@ static struct snd_pcm_ops snd_cx88_pcm_ops = {
/*
* create a PCM device
*/
-static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, char *name)
+static int __devinit snd_cx88_pcm(snd_cx88_card_t *chip, int device, const char *name)
{
int err;
struct snd_pcm *pcm;
@@ -615,7 +614,7 @@ static int snd_cx88_volume_put(struct snd_kcontrol *kcontrol,
static const DECLARE_TLV_DB_SCALE(snd_cx88_db_scale, -6300, 100, 0);
-static struct snd_kcontrol_new snd_cx88_volume = {
+static const struct snd_kcontrol_new snd_cx88_volume = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.access = SNDRV_CTL_ELEM_ACCESS_READWRITE |
SNDRV_CTL_ELEM_ACCESS_TLV_READ,
@@ -657,7 +656,7 @@ static int snd_cx88_switch_put(struct snd_kcontrol *kcontrol,
return ret;
}
-static struct snd_kcontrol_new snd_cx88_dac_switch = {
+static const struct snd_kcontrol_new snd_cx88_dac_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Playback Switch",
.info = snd_ctl_boolean_mono_info,
@@ -666,7 +665,7 @@ static struct snd_kcontrol_new snd_cx88_dac_switch = {
.private_value = (1<<8),
};
-static struct snd_kcontrol_new snd_cx88_source_switch = {
+static const struct snd_kcontrol_new snd_cx88_source_switch = {
.iface = SNDRV_CTL_ELEM_IFACE_MIXER,
.name = "Capture Switch",
.info = snd_ctl_boolean_mono_info,
@@ -684,7 +683,7 @@ static struct snd_kcontrol_new snd_cx88_source_switch = {
* Only boards with eeprom and byte 1 at eeprom=1 have it
*/
-static struct pci_device_id cx88_audio_pci_tbl[] __devinitdata = {
+static const struct pci_device_id const cx88_audio_pci_tbl[] __devinitdata = {
{0x14f1,0x8801,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
{0x14f1,0x8811,PCI_ANY_ID,PCI_ANY_ID,0,0,0},
{0, }
@@ -740,7 +739,7 @@ static int __devinit snd_cx88_create(struct snd_card *card,
pci_set_master(pci);
- chip = (snd_cx88_card_t *) card->private_data;
+ chip = card->private_data;
core = cx88_core_get(pci);
if (NULL == core) {
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index e46e1ceef72c..bca307eb1e24 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -9,7 +9,7 @@
* (c) 2005-2006 Mauro Carvalho Chehab <mchehab@infradead.org>
* - video_ioctl2 conversion
*
- * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ * Includes parts from the ivtv driver <http://sourceforge.net/projects/ivtv/>
*
* 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
@@ -33,7 +33,6 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#include <media/cx2341x.h>
@@ -1057,7 +1056,7 @@ static int mpeg_open(struct file *file)
dprintk( 1, "%s\n", __func__);
- lock_kernel();
+ mutex_lock(&dev->core->lock);
/* Make sure we can acquire the hardware */
drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
@@ -1065,7 +1064,7 @@ static int mpeg_open(struct file *file)
err = drv->request_acquire(drv);
if(err != 0) {
dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
- unlock_kernel();
+ mutex_unlock(&dev->core->lock);
return err;
}
}
@@ -1073,7 +1072,7 @@ static int mpeg_open(struct file *file)
if (!atomic_read(&dev->core->mpeg_users) && blackbird_initialize_codec(dev) < 0) {
if (drv)
drv->request_release(drv);
- unlock_kernel();
+ mutex_unlock(&dev->core->lock);
return -EINVAL;
}
dprintk(1, "open dev=%s\n", video_device_node_name(vdev));
@@ -1083,7 +1082,7 @@ static int mpeg_open(struct file *file)
if (NULL == fh) {
if (drv)
drv->request_release(drv);
- unlock_kernel();
+ mutex_unlock(&dev->core->lock);
return -ENOMEM;
}
file->private_data = fh;
@@ -1094,15 +1093,14 @@ static int mpeg_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx88_buffer),
- fh);
+ fh, NULL);
/* FIXME: locking against other video device */
cx88_set_scale(dev->core, dev->width, dev->height,
fh->mpegq.field);
- unlock_kernel();
atomic_inc(&dev->core->mpeg_users);
-
+ mutex_unlock(&dev->core->lock);
return 0;
}
@@ -1120,8 +1118,11 @@ static int mpeg_release(struct file *file)
videobuf_stop(&fh->mpegq);
videobuf_mmap_free(&fh->mpegq);
+
+ mutex_lock(&dev->core->lock);
file->private_data = NULL;
kfree(fh);
+ mutex_unlock(&dev->core->lock);
/* Make sure we release the hardware */
drv = cx8802_get_driver(dev, CX88_MPEG_BLACKBIRD);
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 2918a6e38fe8..4e6ee5584cb3 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -45,6 +45,10 @@ static unsigned int latency = UNSET;
module_param(latency,int,0444);
MODULE_PARM_DESC(latency,"pci latency timer");
+static int disable_ir;
+module_param(disable_ir, int, 0444);
+MODULE_PARM_DESC(disable_ir, "Disable IR support");
+
#define info_printk(core, fmt, arg...) \
printk(KERN_INFO "%s: " fmt, core->name , ## arg)
@@ -966,15 +970,22 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .audio_chip = V4L2_IDENT_WM8775,
.input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
+ /* 2: Line-In */
+ .audioroute = 2,
}},
.mpeg = CX88_MPEG_DVB,
},
@@ -996,15 +1007,22 @@ static const struct cx88_board cx88_boards[] = {
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .audio_chip = V4L2_IDENT_WM8775,
.input = {{
.type = CX88_VMUX_DVB,
.vmux = 0,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_COMPOSITE1,
.vmux = 1,
+ /* 2: Line-In */
+ .audioroute = 2,
},{
.type = CX88_VMUX_SVIDEO,
.vmux = 2,
+ /* 2: Line-In */
+ .audioroute = 2,
}},
.mpeg = CX88_MPEG_DVB,
},
@@ -2100,6 +2118,18 @@ static const struct cx88_board cx88_boards[] = {
} },
.mpeg = CX88_MPEG_DVB,
},
+ [CX88_BOARD_TWINHAN_VP1027_DVBS] = {
+ .name = "Twinhan VP-1027 DVB-S",
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_DVB,
+ .vmux = 0,
+ } },
+ .mpeg = CX88_MPEG_DVB,
+ },
};
/* ------------------------------------------------------------------ */
@@ -2572,6 +2602,10 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0xb034,
.subdevice = 0x3034,
.card = CX88_BOARD_PROF_7301,
+ }, {
+ .subvendor = 0x1822,
+ .subdevice = 0x0023,
+ .card = CX88_BOARD_TWINHAN_VP1027_DVBS,
},
};
@@ -2669,10 +2703,10 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
/* ----------------------------------------------------------------------- */
/* some GDI (was: Modular Technology) specific stuff */
-static struct {
+static const struct {
int id;
int fm;
- char *name;
+ const char *name;
} gdi_tuner[] = {
[ 0x01 ] = { .id = TUNER_ABSENT,
.name = "NTSC_M" },
@@ -2706,7 +2740,7 @@ static struct {
static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
{
- char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
+ const char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
? gdi_tuner[eeprom_data[0x0d]].name : NULL;
info_printk(core, "GDI: tuner=%s\n", name ? name : "unknown");
@@ -3066,6 +3100,13 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
cx_set(MO_GP1_IO, 0x10);
mdelay(50);
break;
+
+ case CX88_BOARD_TWINHAN_VP1027_DVBS:
+ cx_write(MO_GP0_IO, 0x00003230);
+ cx_write(MO_GP0_IO, 0x00003210);
+ msleep(1);
+ cx_write(MO_GP0_IO, 0x00001230);
+ break;
}
}
@@ -3481,24 +3522,26 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
later code configures a tea5767.
*/
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- "tuner", "tuner",
- 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
+ "tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_RADIO));
if (has_demod)
v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap, "tuner", "tuner",
+ &core->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (core->board.tuner_addr == ADDR_UNSET) {
v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap, "tuner", "tuner",
+ &core->i2c_adap, "tuner",
0, has_demod ? tv_addrs + 4 : tv_addrs);
} else {
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- "tuner", "tuner", core->board.tuner_addr, NULL);
+ "tuner", core->board.tuner_addr, NULL);
}
}
cx88_card_setup(core);
- cx88_ir_init(core, pci);
+ if (!disable_ir) {
+ cx88_i2c_init_ir(core);
+ cx88_ir_init(core, pci);
+ }
return core;
}
diff --git a/drivers/media/video/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 8b21457111b1..2e145f0a5fd9 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -217,8 +217,8 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -253,7 +253,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
* 0x0c00 - FIFOs
*/
-struct sram_channel cx88_sram_channels[] = {
+const struct sram_channel const cx88_sram_channels[] = {
[SRAM_CH21] = {
.name = "video y / packed",
.cmds_start = 0x180040,
@@ -353,7 +353,7 @@ struct sram_channel cx88_sram_channels[] = {
};
int cx88_sram_channel_setup(struct cx88_core *core,
- struct sram_channel *ch,
+ const struct sram_channel *ch,
unsigned int bpl, u32 risc)
{
unsigned int i,lines;
@@ -394,7 +394,7 @@ int cx88_sram_channel_setup(struct cx88_core *core,
static int cx88_risc_decode(u32 risc)
{
- static char *instr[16] = {
+ static const char * const instr[16] = {
[ RISC_SYNC >> 28 ] = "sync",
[ RISC_WRITE >> 28 ] = "write",
[ RISC_WRITEC >> 28 ] = "writec",
@@ -406,14 +406,14 @@ static int cx88_risc_decode(u32 risc)
[ RISC_WRITECM >> 28 ] = "writecm",
[ RISC_WRITECR >> 28 ] = "writecr",
};
- static int incr[16] = {
+ static int const incr[16] = {
[ RISC_WRITE >> 28 ] = 2,
[ RISC_JUMP >> 28 ] = 2,
[ RISC_WRITERM >> 28 ] = 3,
[ RISC_WRITECM >> 28 ] = 3,
[ RISC_WRITECR >> 28 ] = 4,
};
- static char *bits[] = {
+ static const char * const bits[] = {
"12", "13", "14", "resync",
"cnt0", "cnt1", "18", "19",
"20", "21", "22", "23",
@@ -432,9 +432,9 @@ static int cx88_risc_decode(u32 risc)
void cx88_sram_channel_dump(struct cx88_core *core,
- struct sram_channel *ch)
+ const struct sram_channel *ch)
{
- static char *name[] = {
+ static const char * const name[] = {
"initial risc",
"cdt base",
"cdt size",
@@ -489,14 +489,14 @@ void cx88_sram_channel_dump(struct cx88_core *core,
core->name,cx_read(ch->cnt2_reg));
}
-static char *cx88_pci_irqs[32] = {
+static const char *cx88_pci_irqs[32] = {
"vid", "aud", "ts", "vip", "hst", "5", "6", "tm1",
"src_dma", "dst_dma", "risc_rd_err", "risc_wr_err",
"brdg_err", "src_dma_err", "dst_dma_err", "ipb_dma_err",
"i2c", "i2c_rack", "ir_smp", "gpio0", "gpio1"
};
-void cx88_print_irqbits(char *name, char *tag, char **strings,
+void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
int len, u32 bits, u32 mask)
{
unsigned int i;
@@ -770,7 +770,7 @@ static const u32 xtal = 28636363;
static int set_pll(struct cx88_core *core, int prescale, u32 ofreq)
{
- static u32 pre[] = { 0, 0, 0, 3, 2, 1 };
+ static const u32 pre[] = { 0, 0, 0, 3, 2, 1 };
u64 pll;
u32 reg;
int i;
@@ -879,7 +879,7 @@ static int set_tvaudio(struct cx88_core *core)
} else {
printk("%s/0: tvaudio support needs work for this tv norm [%s], sorry\n",
core->name, v4l2_norm_to_name(core->tvnorm));
- core->tvaudio = 0;
+ core->tvaudio = WW_NONE;
return 0;
}
@@ -1020,15 +1020,15 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
- struct video_device *template,
- char *type)
+ const struct video_device *template_,
+ const char *type)
{
struct video_device *vfd;
vfd = video_device_alloc();
if (NULL == vfd)
return NULL;
- *vfd = *template;
+ *vfd = *template_;
vfd->v4l2_dev = &core->v4l2_dev;
vfd->parent = &pci->dev;
vfd->release = video_device_release;
diff --git a/drivers/media/video/cx88/cx88-dsp.c b/drivers/media/video/cx88/cx88-dsp.c
index a94e00a4ac5d..a9907265ff66 100644
--- a/drivers/media/video/cx88/cx88-dsp.c
+++ b/drivers/media/video/cx88/cx88-dsp.c
@@ -230,7 +230,7 @@ static s32 detect_btsc(struct cx88_core *core, s16 x[], u32 N)
static s16 *read_rds_samples(struct cx88_core *core, u32 *N)
{
- struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27];
+ const struct sram_channel *srch = &cx88_sram_channels[SRAM_CH27];
s16 *samples;
unsigned int i;
@@ -292,11 +292,20 @@ s32 cx88_dsp_detect_stereo_sap(struct cx88_core *core)
switch (core->tvaudio) {
case WW_BG:
case WW_DK:
+ case WW_EIAJ:
+ case WW_M:
ret = detect_a2_a2m_eiaj(core, samples, N);
break;
case WW_BTSC:
ret = detect_btsc(core, samples, N);
break;
+ case WW_NONE:
+ case WW_I:
+ case WW_L:
+ case WW_I2SPT:
+ case WW_FM:
+ case WW_I2SADC:
+ break;
}
kfree(samples);
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index faa8e8163a4a..90717ee944ec 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -56,6 +56,7 @@
#include "stv0900.h"
#include "stb6100.h"
#include "stb6100_proc.h"
+#include "mb86a16.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
@@ -66,6 +67,10 @@ static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
+static unsigned int dvb_buf_tscnt = 32;
+module_param(dvb_buf_tscnt, int, 0644);
+MODULE_PARM_DESC(dvb_buf_tscnt, "DVB Buffer TS count [dvb]");
+
DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
#define dprintk(level,fmt, arg...) if (debug >= level) \
@@ -79,10 +84,10 @@ static int dvb_buf_setup(struct videobuf_queue *q,
struct cx8802_dev *dev = q->priv_data;
dev->ts_packet_size = 188 * 4;
- dev->ts_packet_count = 32;
+ dev->ts_packet_count = dvb_buf_tscnt;
*size = dev->ts_packet_size * dev->ts_packet_count;
- *count = 32;
+ *count = dvb_buf_tscnt;
return 0;
}
@@ -105,7 +110,7 @@ static void dvb_buf_release(struct videobuf_queue *q,
cx88_free_buffer(q, (struct cx88_buffer*)vb);
}
-static struct videobuf_queue_ops dvb_qops = {
+static const struct videobuf_queue_ops dvb_qops = {
.buf_setup = dvb_buf_setup,
.buf_prepare = dvb_buf_prepare,
.buf_queue = dvb_buf_queue,
@@ -167,12 +172,12 @@ static void cx88_dvb_gate_ctrl(struct cx88_core *core, int open)
static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
{
- static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 };
- static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
- static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+ static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x39 };
+ static const u8 reset [] = { RESET, 0x80 };
+ static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static const u8 agc_cfg [] = { AGC_TARGET, 0x24, 0x20 };
+ static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+ static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
mt352_write(fe, clock_config, sizeof(clock_config));
udelay(200);
@@ -187,12 +192,12 @@ static int dvico_fusionhdtv_demod_init(struct dvb_frontend* fe)
static int dvico_dual_demod_init(struct dvb_frontend *fe)
{
- static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 };
- static u8 reset [] = { RESET, 0x80 };
- static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
- static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
- static u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
- static u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
+ static const u8 clock_config [] = { CLOCK_CTL, 0x38, 0x38 };
+ static const u8 reset [] = { RESET, 0x80 };
+ static const u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static const u8 agc_cfg [] = { AGC_TARGET, 0x28, 0x20 };
+ static const u8 gpp_ctl_cfg [] = { GPP_CTL, 0x33 };
+ static const u8 capt_range_cfg[] = { CAPT_RANGE, 0x32 };
mt352_write(fe, clock_config, sizeof(clock_config));
udelay(200);
@@ -208,13 +213,13 @@ static int dvico_dual_demod_init(struct dvb_frontend *fe)
static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
{
- static u8 clock_config [] = { 0x89, 0x38, 0x39 };
- static u8 reset [] = { 0x50, 0x80 };
- static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
- static u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
+ static const u8 clock_config [] = { 0x89, 0x38, 0x39 };
+ static const u8 reset [] = { 0x50, 0x80 };
+ static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+ static const u8 agc_cfg [] = { 0x67, 0x10, 0x23, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0x40, 0x40 };
- static u8 dntv_extra[] = { 0xB5, 0x7A };
- static u8 capt_range_cfg[] = { 0x75, 0x32 };
+ static const u8 dntv_extra[] = { 0xB5, 0x7A };
+ static const u8 capt_range_cfg[] = { 0x75, 0x32 };
mt352_write(fe, clock_config, sizeof(clock_config));
udelay(2000);
@@ -229,37 +234,41 @@ static int dntv_live_dvbt_demod_init(struct dvb_frontend* fe)
return 0;
}
-static struct mt352_config dvico_fusionhdtv = {
+static const struct mt352_config dvico_fusionhdtv = {
.demod_address = 0x0f,
.demod_init = dvico_fusionhdtv_demod_init,
};
-static struct mt352_config dntv_live_dvbt_config = {
+static const struct mt352_config dntv_live_dvbt_config = {
.demod_address = 0x0f,
.demod_init = dntv_live_dvbt_demod_init,
};
-static struct mt352_config dvico_fusionhdtv_dual = {
+static const struct mt352_config dvico_fusionhdtv_dual = {
.demod_address = 0x0f,
.demod_init = dvico_dual_demod_init,
};
-static struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
+static const struct zl10353_config cx88_terratec_cinergy_ht_pci_mkii_config = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
.if2 = 45600,
};
+static struct mb86a16_config twinhan_vp1027 = {
+ .demod_address = 0x08,
+};
+
#if defined(CONFIG_VIDEO_CX88_VP3054) || (defined(CONFIG_VIDEO_CX88_VP3054_MODULE) && defined(MODULE))
static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
{
- static u8 clock_config [] = { 0x89, 0x38, 0x38 };
- static u8 reset [] = { 0x50, 0x80 };
- static u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
- static u8 agc_cfg [] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
+ static const u8 clock_config [] = { 0x89, 0x38, 0x38 };
+ static const u8 reset [] = { 0x50, 0x80 };
+ static const u8 adc_ctl_1_cfg [] = { 0x8E, 0x40 };
+ static const u8 agc_cfg [] = { 0x67, 0x10, 0x20, 0x00, 0xFF, 0xFF,
0x00, 0xFF, 0x00, 0x40, 0x40 };
- static u8 dntv_extra[] = { 0xB5, 0x7A };
- static u8 capt_range_cfg[] = { 0x75, 0x32 };
+ static const u8 dntv_extra[] = { 0xB5, 0x7A };
+ static const u8 capt_range_cfg[] = { 0x75, 0x32 };
mt352_write(fe, clock_config, sizeof(clock_config));
udelay(2000);
@@ -274,41 +283,41 @@ static int dntv_live_dvbt_pro_demod_init(struct dvb_frontend* fe)
return 0;
}
-static struct mt352_config dntv_live_dvbt_pro_config = {
+static const struct mt352_config dntv_live_dvbt_pro_config = {
.demod_address = 0x0f,
.no_tuner = 1,
.demod_init = dntv_live_dvbt_pro_demod_init,
};
#endif
-static struct zl10353_config dvico_fusionhdtv_hybrid = {
+static const struct zl10353_config dvico_fusionhdtv_hybrid = {
.demod_address = 0x0f,
.no_tuner = 1,
};
-static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+static const struct zl10353_config dvico_fusionhdtv_xc3028 = {
.demod_address = 0x0f,
.if2 = 45600,
.no_tuner = 1,
};
-static struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
+static const struct mt352_config dvico_fusionhdtv_mt352_xc3028 = {
.demod_address = 0x0f,
.if2 = 4560,
.no_tuner = 1,
.demod_init = dvico_fusionhdtv_demod_init,
};
-static struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
+static const struct zl10353_config dvico_fusionhdtv_plus_v1_1 = {
.demod_address = 0x0f,
};
-static struct cx22702_config connexant_refboard_config = {
+static const struct cx22702_config connexant_refboard_config = {
.demod_address = 0x43,
.output_mode = CX22702_SERIAL_OUTPUT,
};
-static struct cx22702_config hauppauge_hvr_config = {
+static const struct cx22702_config hauppauge_hvr_config = {
.demod_address = 0x63,
.output_mode = CX22702_SERIAL_OUTPUT,
};
@@ -320,7 +329,7 @@ static int or51132_set_ts_param(struct dvb_frontend* fe, int is_punctured)
return 0;
}
-static struct or51132_config pchdtv_hd3000 = {
+static const struct or51132_config pchdtv_hd3000 = {
.demod_address = 0x15,
.set_ts_params = or51132_set_ts_param,
};
@@ -355,14 +364,14 @@ static struct lgdt330x_config fusionhdtv_3_gold = {
.set_ts_params = lgdt330x_set_ts_param,
};
-static struct lgdt330x_config fusionhdtv_5_gold = {
+static const struct lgdt330x_config fusionhdtv_5_gold = {
.demod_address = 0x0e,
.demod_chip = LGDT3303,
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
.set_ts_params = lgdt330x_set_ts_param,
};
-static struct lgdt330x_config pchdtv_hd5500 = {
+static const struct lgdt330x_config pchdtv_hd5500 = {
.demod_address = 0x59,
.demod_chip = LGDT3303,
.serial_mpeg = 0x40, /* TPSERIAL for 3303 in TOP_CONTROL */
@@ -376,7 +385,7 @@ static int nxt200x_set_ts_param(struct dvb_frontend* fe, int is_punctured)
return 0;
}
-static struct nxt200x_config ati_hdtvwonder = {
+static const struct nxt200x_config ati_hdtvwonder = {
.demod_address = 0x0a,
.set_ts_params = nxt200x_set_ts_param,
};
@@ -429,15 +438,41 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
cx_set(MO_GP0_IO, 0x6040);
switch (voltage) {
- case SEC_VOLTAGE_13:
- cx_clear(MO_GP0_IO, 0x20);
- break;
- case SEC_VOLTAGE_18:
- cx_set(MO_GP0_IO, 0x20);
- break;
- case SEC_VOLTAGE_OFF:
- cx_clear(MO_GP0_IO, 0x20);
- break;
+ case SEC_VOLTAGE_13:
+ cx_clear(MO_GP0_IO, 0x20);
+ break;
+ case SEC_VOLTAGE_18:
+ cx_set(MO_GP0_IO, 0x20);
+ break;
+ case SEC_VOLTAGE_OFF:
+ cx_clear(MO_GP0_IO, 0x20);
+ break;
+ }
+
+ if (core->prev_set_voltage)
+ return core->prev_set_voltage(fe, voltage);
+ return 0;
+}
+
+static int vp1027_set_voltage(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage)
+{
+ struct cx8802_dev *dev = fe->dvb->priv;
+ struct cx88_core *core = dev->core;
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13:
+ dprintk(1, "LNB SEC Voltage=13\n");
+ cx_write(MO_GP0_IO, 0x00001220);
+ break;
+ case SEC_VOLTAGE_18:
+ dprintk(1, "LNB SEC Voltage=18\n");
+ cx_write(MO_GP0_IO, 0x00001222);
+ break;
+ case SEC_VOLTAGE_OFF:
+ dprintk(1, "LNB Voltage OFF\n");
+ cx_write(MO_GP0_IO, 0x00001230);
+ break;
}
if (core->prev_set_voltage)
@@ -445,23 +480,23 @@ static int tevii_dvbs_set_voltage(struct dvb_frontend *fe,
return 0;
}
-static struct cx24123_config geniatech_dvbs_config = {
+static const struct cx24123_config geniatech_dvbs_config = {
.demod_address = 0x55,
.set_ts_params = cx24123_set_ts_param,
};
-static struct cx24123_config hauppauge_novas_config = {
+static const struct cx24123_config hauppauge_novas_config = {
.demod_address = 0x55,
.set_ts_params = cx24123_set_ts_param,
};
-static struct cx24123_config kworld_dvbs_100_config = {
+static const struct cx24123_config kworld_dvbs_100_config = {
.demod_address = 0x15,
.set_ts_params = cx24123_set_ts_param,
.lnb_polarity = 1,
};
-static struct s5h1409_config pinnacle_pctv_hd_800i_config = {
+static const struct s5h1409_config pinnacle_pctv_hd_800i_config = {
.demod_address = 0x32 >> 1,
.output_mode = S5H1409_PARALLEL_OUTPUT,
.gpio = S5H1409_GPIO_ON,
@@ -471,7 +506,7 @@ static struct s5h1409_config pinnacle_pctv_hd_800i_config = {
.mpeg_timing = S5H1409_MPEGTIMING_NONCONTINOUS_NONINVERTING_CLOCK,
};
-static struct s5h1409_config dvico_hdtv5_pci_nano_config = {
+static const struct s5h1409_config dvico_hdtv5_pci_nano_config = {
.demod_address = 0x32 >> 1,
.output_mode = S5H1409_SERIAL_OUTPUT,
.gpio = S5H1409_GPIO_OFF,
@@ -480,7 +515,7 @@ static struct s5h1409_config dvico_hdtv5_pci_nano_config = {
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
};
-static struct s5h1409_config kworld_atsc_120_config = {
+static const struct s5h1409_config kworld_atsc_120_config = {
.demod_address = 0x32 >> 1,
.output_mode = S5H1409_SERIAL_OUTPUT,
.gpio = S5H1409_GPIO_OFF,
@@ -489,24 +524,24 @@ static struct s5h1409_config kworld_atsc_120_config = {
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
};
-static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
+static const struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
.i2c_address = 0x64,
.if_khz = 5380,
};
-static struct zl10353_config cx88_pinnacle_hybrid_pctv = {
+static const struct zl10353_config cx88_pinnacle_hybrid_pctv = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
.if2 = 45600,
};
-static struct zl10353_config cx88_geniatech_x8000_mt = {
+static const struct zl10353_config cx88_geniatech_x8000_mt = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
.disable_i2c_gate_ctrl = 1,
};
-static struct s5h1411_config dvico_fusionhdtv7_config = {
+static const struct s5h1411_config dvico_fusionhdtv7_config = {
.output_mode = S5H1411_SERIAL_OUTPUT,
.gpio = S5H1411_GPIO_ON,
.mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
@@ -516,7 +551,7 @@ static struct s5h1411_config dvico_fusionhdtv7_config = {
.status_mode = S5H1411_DEMODLOCKING
};
-static struct xc5000_config dvico_fusionhdtv7_tuner_config = {
+static const struct xc5000_config dvico_fusionhdtv7_tuner_config = {
.i2c_address = 0xc2 >> 1,
.if_khz = 5380,
};
@@ -601,19 +636,19 @@ static int cx24116_reset_device(struct dvb_frontend *fe)
return 0;
}
-static struct cx24116_config hauppauge_hvr4000_config = {
+static const struct cx24116_config hauppauge_hvr4000_config = {
.demod_address = 0x05,
.set_ts_params = cx24116_set_ts_param,
.reset_device = cx24116_reset_device,
};
-static struct cx24116_config tevii_s460_config = {
+static const struct cx24116_config tevii_s460_config = {
.demod_address = 0x55,
.set_ts_params = cx24116_set_ts_param,
.reset_device = cx24116_reset_device,
};
-static struct stv0900_config prof_7301_stv0900_config = {
+static const struct stv0900_config prof_7301_stv0900_config = {
.demod_address = 0x6a,
/* demod_mode = 0,*/
.xtal = 27000000,
@@ -625,12 +660,12 @@ static struct stv0900_config prof_7301_stv0900_config = {
.set_ts_params = stv0900_set_ts_param,
};
-static struct stb6100_config prof_7301_stb6100_config = {
+static const struct stb6100_config prof_7301_stb6100_config = {
.tuner_address = 0x60,
.refclock = 27000000,
};
-static struct stv0299_config tevii_tuner_sharp_config = {
+static const struct stv0299_config tevii_tuner_sharp_config = {
.demod_address = 0x68,
.inittab = sharp_z0194a_inittab,
.mclk = 88000000UL,
@@ -643,7 +678,7 @@ static struct stv0299_config tevii_tuner_sharp_config = {
.set_ts_params = cx24116_set_ts_param,
};
-static struct stv0288_config tevii_tuner_earda_config = {
+static const struct stv0288_config tevii_tuner_earda_config = {
.demod_address = 0x68,
.min_delay_ms = 100,
.set_ts_params = cx24116_set_ts_param,
@@ -676,7 +711,7 @@ static int cx8802_alloc_frontends(struct cx8802_dev *dev)
-static u8 samsung_smt_7020_inittab[] = {
+static const u8 samsung_smt_7020_inittab[] = {
0x01, 0x15,
0x02, 0x00,
0x03, 0x00,
@@ -850,7 +885,7 @@ static int samsung_smt_7020_stv0299_set_symbol_rate(struct dvb_frontend *fe,
}
-static struct stv0299_config samsung_stv0299_config = {
+static const struct stv0299_config samsung_stv0299_config = {
.demod_address = 0x68,
.inittab = samsung_smt_7020_inittab,
.mclk = 88000000UL,
@@ -1416,6 +1451,18 @@ static int dvb_register(struct cx8802_dev *dev)
}
break;
+ case CX88_BOARD_TWINHAN_VP1027_DVBS:
+ dev->ts_gen_cntrl = 0x00;
+ fe0->dvb.frontend = dvb_attach(mb86a16_attach,
+ &twinhan_vp1027,
+ &core->i2c_adap);
+ if (fe0->dvb.frontend) {
+ core->prev_set_voltage =
+ fe0->dvb.frontend->ops.set_voltage;
+ fe0->dvb.frontend->ops.set_voltage =
+ vp1027_set_voltage;
+ }
+ break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
@@ -1576,7 +1623,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_TOP,
sizeof(struct cx88_buffer),
- dev);
+ dev, NULL);
/* init struct videobuf_dvb */
fe->dvb.name = dev->core->name;
}
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index ee1ca39db06a..a1fe0abb6e43 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -108,7 +108,7 @@ static const struct i2c_algo_bit_data cx8800_i2c_algo_template = {
/* ----------------------------------------------------------------------- */
-static char *i2c_devs[128] = {
+static const char * const i2c_devs[128] = {
[ 0x1c >> 1 ] = "lgdt330x",
[ 0x86 >> 1 ] = "tda9887/cx22702",
[ 0xa0 >> 1 ] = "eeprom",
@@ -117,7 +117,7 @@ static char *i2c_devs[128] = {
[ 0xc8 >> 1 ] = "xc5000",
};
-static void do_i2c_scan(char *name, struct i2c_client *c)
+static void do_i2c_scan(const char *name, struct i2c_client *c)
{
unsigned char buf;
int i,rc;
@@ -146,7 +146,6 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
core->i2c_adap.dev.parent = &pci->dev;
strlcpy(core->i2c_adap.name,core->name,sizeof(core->i2c_adap.name));
core->i2c_adap.owner = THIS_MODULE;
- core->i2c_adap.id = I2C_HW_B_CX2388x;
core->i2c_algo.udelay = i2c_udelay;
core->i2c_algo.data = core;
i2c_set_adapdata(&core->i2c_adap, &core->v4l2_dev);
@@ -181,25 +180,5 @@ int cx88_i2c_init(struct cx88_core *core, struct pci_dev *pci)
} else
printk("%s: i2c register FAILED\n", core->name);
- /* Instantiate the IR receiver device, if present */
- if (0 == core->i2c_rc) {
- struct i2c_board_info info;
- const unsigned short addr_list[] = {
- 0x18, 0x6b, 0x71,
- I2C_CLIENT_END
- };
-
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- i2c_new_probed_device(&core->i2c_adap, &info, addr_list);
- }
return core->i2c_rc;
}
-
-/* ----------------------------------------------------------------------- */
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index e185289e446c..06f7d1d00944 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -24,13 +24,12 @@
#include <linux/init.h>
#include <linux/hrtimer.h>
-#include <linux/input.h>
#include <linux/pci.h>
#include <linux/slab.h>
#include <linux/module.h>
#include "cx88.h"
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#define MODULE_NAME "cx88xx"
@@ -38,9 +37,7 @@
struct cx88_IR {
struct cx88_core *core;
- struct input_dev *input;
- struct ir_input_state ir;
- struct ir_dev_props props;
+ struct rc_dev *dev;
int users;
@@ -49,9 +46,6 @@ struct cx88_IR {
/* sample from gpio pin 16 */
u32 sampling;
- u32 samples[16];
- int scount;
- unsigned long release;
/* poll external decoder */
int polling;
@@ -63,6 +57,10 @@ struct cx88_IR {
u32 mask_keyup;
};
+static unsigned ir_samplerate = 4;
+module_param(ir_samplerate, uint, 0444);
+MODULE_PARM_DESC(ir_samplerate, "IR samplerate in kHz, 1 - 20, default 4");
+
static int ir_debug;
module_param(ir_debug, int, 0644); /* debug level [IR] */
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
@@ -70,6 +68,9 @@ MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
#define ir_dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s IR: " fmt , ir->core->name , ##arg)
+#define dprintk(fmt, arg...) if (ir_debug) \
+ printk(KERN_DEBUG "cx88 IR: " fmt , ##arg)
+
/* ---------------------------------------------------------------------- */
static void cx88_ir_handle_key(struct cx88_IR *ir)
@@ -125,29 +126,26 @@ static void cx88_ir_handle_key(struct cx88_IR *ir)
data = (data << 4) | ((gpio_key & 0xf0) >> 4);
- ir_input_keydown(ir->input, &ir->ir, data);
- ir_input_nokey(ir->input, &ir->ir);
+ rc_keydown(ir->dev, data, 0);
} else if (ir->mask_keydown) {
/* bit set on keydown */
- if (gpio & ir->mask_keydown) {
- ir_input_keydown(ir->input, &ir->ir, data);
- } else {
- ir_input_nokey(ir->input, &ir->ir);
- }
+ if (gpio & ir->mask_keydown)
+ rc_keydown_notimeout(ir->dev, data, 0);
+ else
+ rc_keyup(ir->dev);
} else if (ir->mask_keyup) {
/* bit cleared on keydown */
- if (0 == (gpio & ir->mask_keyup)) {
- ir_input_keydown(ir->input, &ir->ir, data);
- } else {
- ir_input_nokey(ir->input, &ir->ir);
- }
+ if (0 == (gpio & ir->mask_keyup))
+ rc_keydown_notimeout(ir->dev, data, 0);
+ else
+ rc_keyup(ir->dev);
} else {
/* can't distinguish keydown/up :-/ */
- ir_input_keydown(ir->input, &ir->ir, data);
- ir_input_nokey(ir->input, &ir->ir);
+ rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keyup(ir->dev);
}
}
@@ -184,8 +182,8 @@ static int __cx88_ir_start(void *priv)
}
if (ir->sampling) {
core->pci_irqmask |= PCI_INT_IR_SMPINT;
- cx_write(MO_DDS_IO, 0xa80a80); /* 4 kHz sample rate */
- cx_write(MO_DDSCFG_IO, 0x5); /* enable */
+ cx_write(MO_DDS_IO, 0x33F286 * ir_samplerate); /* samplerate */
+ cx_write(MO_DDSCFG_IO, 0x5); /* enable */
}
return 0;
}
@@ -222,17 +220,17 @@ void cx88_ir_stop(struct cx88_core *core)
__cx88_ir_stop(core);
}
-static int cx88_ir_open(void *priv)
+static int cx88_ir_open(struct rc_dev *rc)
{
- struct cx88_core *core = priv;
+ struct cx88_core *core = rc->priv;
core->ir->users++;
return __cx88_ir_start(core);
}
-static void cx88_ir_close(void *priv)
+static void cx88_ir_close(struct rc_dev *rc)
{
- struct cx88_core *core = priv;
+ struct cx88_core *core = rc->priv;
core->ir->users--;
if (!core->ir->users)
@@ -244,20 +242,20 @@ static void cx88_ir_close(void *priv)
int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
{
struct cx88_IR *ir;
- struct input_dev *input_dev;
+ struct rc_dev *dev;
char *ir_codes = NULL;
- u64 ir_type = IR_TYPE_OTHER;
+ u64 rc_type = RC_TYPE_OTHER;
int err = -ENOMEM;
u32 hardware_mask = 0; /* For devices with a hardware mask, when
* used with a full-code IR table
*/
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
+ dev = rc_allocate_device();
+ if (!ir || !dev)
goto err_out_free;
- ir->input = input_dev;
+ ir->dev = dev;
/* detect & configure */
switch (core->boardnr) {
@@ -272,7 +270,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
ir_codes = RC_MAP_CINERGY_1400;
- ir_type = IR_TYPE_NEC;
ir->sampling = 0xeb04; /* address */
break;
case CX88_BOARD_HAUPPAUGE:
@@ -287,7 +284,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_PCHDTV_HD5500:
case CX88_BOARD_HAUPPAUGE_IRONLY:
ir_codes = RC_MAP_HAUPPAUGE_NEW;
- ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
case CX88_BOARD_WINFAST_DTV2000H:
@@ -375,18 +371,15 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
case CX88_BOARD_PROF_7301:
case CX88_BOARD_PROF_6200:
ir_codes = RC_MAP_TBS_NEC;
- ir_type = IR_TYPE_NEC;
ir->sampling = 0xff00; /* address */
break;
case CX88_BOARD_TEVII_S460:
case CX88_BOARD_TEVII_S420:
ir_codes = RC_MAP_TEVII_NEC;
- ir_type = IR_TYPE_NEC;
ir->sampling = 0xff00; /* address */
break;
case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
ir_codes = RC_MAP_DNTV_LIVE_DVBT_PRO;
- ir_type = IR_TYPE_NEC;
ir->sampling = 0xff00; /* address */
break;
case CX88_BOARD_NORWOOD_MICRO:
@@ -404,7 +397,6 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
break;
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
ir_codes = RC_MAP_PINNACLE_PCTV_HD;
- ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
@@ -413,9 +405,14 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->mask_keycode = 0x7e;
ir->polling = 100; /* ms */
break;
+ case CX88_BOARD_TWINHAN_VP1027_DVBS:
+ ir_codes = RC_MAP_TWINHAN_VP1027_DVBS;
+ rc_type = RC_TYPE_NEC;
+ ir->sampling = 0xff00; /* address */
+ break;
}
- if (NULL == ir_codes) {
+ if (!ir_codes) {
err = -ENODEV;
goto err_out_free;
}
@@ -439,39 +436,45 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
snprintf(ir->name, sizeof(ir->name), "cx88 IR (%s)", core->board.name);
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0", pci_name(pci));
- err = ir_input_init(input_dev, &ir->ir, ir_type);
- if (err < 0)
- goto err_out_free;
-
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ dev->input_name = ir->name;
+ dev->input_phys = ir->phys;
+ dev->input_id.bustype = BUS_PCI;
+ dev->input_id.version = 1;
if (pci->subsystem_vendor) {
- input_dev->id.vendor = pci->subsystem_vendor;
- input_dev->id.product = pci->subsystem_device;
+ dev->input_id.vendor = pci->subsystem_vendor;
+ dev->input_id.product = pci->subsystem_device;
} else {
- input_dev->id.vendor = pci->vendor;
- input_dev->id.product = pci->device;
+ dev->input_id.vendor = pci->vendor;
+ dev->input_id.product = pci->device;
}
- input_dev->dev.parent = &pci->dev;
- /* record handles to ourself */
+ dev->dev.parent = &pci->dev;
+ dev->map_name = ir_codes;
+ dev->driver_name = MODULE_NAME;
+ dev->priv = core;
+ dev->open = cx88_ir_open;
+ dev->close = cx88_ir_close;
+ dev->scanmask = hardware_mask;
+
+ if (ir->sampling) {
+ dev->driver_type = RC_DRIVER_IR_RAW;
+ dev->timeout = 10 * 1000 * 1000; /* 10 ms */
+ } else {
+ dev->driver_type = RC_DRIVER_SCANCODE;
+ dev->allowed_protos = rc_type;
+ }
+
ir->core = core;
core->ir = ir;
- ir->props.priv = core;
- ir->props.open = cx88_ir_open;
- ir->props.close = cx88_ir_close;
- ir->props.scanmask = hardware_mask;
-
/* all done */
- err = ir_input_register(ir->input, ir_codes, &ir->props, MODULE_NAME);
+ err = rc_register_device(dev);
if (err)
goto err_out_free;
return 0;
- err_out_free:
+err_out_free:
+ rc_free_device(dev);
core->ir = NULL;
kfree(ir);
return err;
@@ -486,7 +489,7 @@ int cx88_ir_fini(struct cx88_core *core)
return 0;
cx88_ir_stop(core);
- ir_input_unregister(ir->input);
+ rc_unregister_device(ir->dev);
kfree(ir);
/* done */
@@ -499,128 +502,121 @@ int cx88_ir_fini(struct cx88_core *core)
void cx88_ir_irq(struct cx88_core *core)
{
struct cx88_IR *ir = core->ir;
- u32 samples, ircode;
- int i, start, range, toggle, dev, code;
+ u32 samples;
+ unsigned todo, bits;
+ struct ir_raw_event ev;
- if (NULL == ir)
- return;
- if (!ir->sampling)
+ if (!ir || !ir->sampling)
return;
+ /*
+ * Samples are stored in a 32 bit register, oldest sample in
+ * the msb. A set bit represents space and an unset bit
+ * represents a pulse.
+ */
samples = cx_read(MO_SAMPLE_IO);
- if (0 != samples && 0xffffffff != samples) {
- /* record sample data */
- if (ir->scount < ARRAY_SIZE(ir->samples))
- ir->samples[ir->scount++] = samples;
- return;
- }
- if (!ir->scount) {
- /* nothing to sample */
- if (ir->ir.keypressed && time_after(jiffies, ir->release))
- ir_input_nokey(ir->input, &ir->ir);
+
+ if (samples == 0xff && ir->dev->idle)
return;
- }
- /* have a complete sample */
- if (ir->scount < ARRAY_SIZE(ir->samples))
- ir->samples[ir->scount++] = samples;
- for (i = 0; i < ir->scount; i++)
- ir->samples[i] = ~ir->samples[i];
- if (ir_debug)
- ir_dump_samples(ir->samples, ir->scount);
+ init_ir_raw_event(&ev);
+ for (todo = 32; todo > 0; todo -= bits) {
+ ev.pulse = samples & 0x80000000 ? false : true;
+ bits = min(todo, 32U - fls(ev.pulse ? samples : ~samples));
+ ev.duration = (bits * NSEC_PER_SEC) / (1000 * ir_samplerate);
+ ir_raw_event_store_with_filter(ir->dev, &ev);
+ samples <<= bits;
+ }
+ ir_raw_event_handle(ir->dev);
+}
- /* decode it */
- switch (core->boardnr) {
- case CX88_BOARD_TEVII_S460:
- case CX88_BOARD_TEVII_S420:
- case CX88_BOARD_TERRATEC_CINERGY_1400_DVB_T1:
- case CX88_BOARD_DNTV_LIVE_DVB_T_PRO:
- case CX88_BOARD_OMICOM_SS4_PCI:
- case CX88_BOARD_SATTRADE_ST4200:
- case CX88_BOARD_TBS_8920:
- case CX88_BOARD_TBS_8910:
- case CX88_BOARD_PROF_7300:
- case CX88_BOARD_PROF_7301:
- case CX88_BOARD_PROF_6200:
- ircode = ir_decode_pulsedistance(ir->samples, ir->scount, 1, 4);
+static int get_key_pvr2000(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ int flags, code;
- if (ircode == 0xffffffff) { /* decoding error */
- ir_dprintk("pulse distance decoding error\n");
- break;
- }
+ /* poll IR chip */
+ flags = i2c_smbus_read_byte_data(ir->c, 0x10);
+ if (flags < 0) {
+ dprintk("read error\n");
+ return 0;
+ }
+ /* key pressed ? */
+ if (0 == (flags & 0x80))
+ return 0;
- ir_dprintk("pulse distance decoded: %x\n", ircode);
+ /* read actual key code */
+ code = i2c_smbus_read_byte_data(ir->c, 0x00);
+ if (code < 0) {
+ dprintk("read error\n");
+ return 0;
+ }
- if (ircode == 0) { /* key still pressed */
- ir_dprintk("pulse distance decoded repeat code\n");
- ir->release = jiffies + msecs_to_jiffies(120);
- break;
- }
+ dprintk("IR Key/Flags: (0x%02x/0x%02x)\n",
+ code & 0xff, flags & 0xff);
- if ((ircode & 0xffff) != (ir->sampling & 0xffff)) { /* wrong address */
- ir_dprintk("pulse distance decoded wrong address\n");
- break;
- }
+ *ir_key = code & 0xff;
+ *ir_raw = code;
+ return 1;
+}
- if (((~ircode >> 24) & 0xff) != ((ircode >> 16) & 0xff)) { /* wrong checksum */
- ir_dprintk("pulse distance decoded wrong check sum\n");
- break;
- }
+void cx88_i2c_init_ir(struct cx88_core *core)
+{
+ struct i2c_board_info info;
+ const unsigned short default_addr_list[] = {
+ 0x18, 0x6b, 0x71,
+ I2C_CLIENT_END
+ };
+ const unsigned short pvr2000_addr_list[] = {
+ 0x18, 0x1a,
+ I2C_CLIENT_END
+ };
+ const unsigned short *addr_list = default_addr_list;
+ const unsigned short *addrp;
+ /* Instantiate the IR receiver device, if present */
+ if (0 != core->i2c_rc)
+ return;
- ir_dprintk("Key Code: %x\n", (ircode >> 16) & 0x7f);
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- ir_input_keydown(ir->input, &ir->ir, (ircode >> 16) & 0x7f);
- ir->release = jiffies + msecs_to_jiffies(120);
- break;
- case CX88_BOARD_HAUPPAUGE:
- case CX88_BOARD_HAUPPAUGE_DVB_T1:
- case CX88_BOARD_HAUPPAUGE_NOVASE2_S1:
- case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
- case CX88_BOARD_HAUPPAUGE_HVR1100:
- case CX88_BOARD_HAUPPAUGE_HVR3000:
- case CX88_BOARD_HAUPPAUGE_HVR4000:
- case CX88_BOARD_HAUPPAUGE_HVR4000LITE:
- case CX88_BOARD_PCHDTV_HD3000:
- case CX88_BOARD_PCHDTV_HD5500:
- case CX88_BOARD_HAUPPAUGE_IRONLY:
- ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
- ir_dprintk("biphase decoded: %x\n", ircode);
- /*
- * RC5 has an extension bit which adds a new range
- * of available codes, this is detected here. Also
- * hauppauge remotes (black/silver) always use
- * specific device ids. If we do not filter the
- * device ids then messages destined for devices
- * such as TVs (id=0) will get through to the
- * device causing mis-fired events.
- */
- /* split rc5 data block ... */
- start = (ircode & 0x2000) >> 13;
- range = (ircode & 0x1000) >> 12;
- toggle= (ircode & 0x0800) >> 11;
- dev = (ircode & 0x07c0) >> 6;
- code = (ircode & 0x003f) | ((range << 6) ^ 0x0040);
- if( start != 1)
- /* no key pressed */
- break;
- if ( dev != 0x1e && dev != 0x1f )
- /* not a hauppauge remote */
- break;
- ir_input_keydown(ir->input, &ir->ir, code);
- ir->release = jiffies + msecs_to_jiffies(120);
- break;
- case CX88_BOARD_PINNACLE_PCTV_HD_800i:
- ircode = ir_decode_biphase(ir->samples, ir->scount, 5, 7);
- ir_dprintk("biphase decoded: %x\n", ircode);
- if ((ircode & 0xfffff000) != 0x3000)
- break;
- ir_input_keydown(ir->input, &ir->ir, ircode & 0x3f);
- ir->release = jiffies + msecs_to_jiffies(120);
+ switch (core->boardnr) {
+ case CX88_BOARD_LEADTEK_PVR2000:
+ addr_list = pvr2000_addr_list;
+ core->init_data.name = "cx88 Leadtek PVR 2000 remote";
+ core->init_data.type = RC_TYPE_UNKNOWN;
+ core->init_data.get_key = get_key_pvr2000;
+ core->init_data.ir_codes = RC_MAP_EMPTY;
break;
}
- ir->scount = 0;
- return;
+ /*
+ * We can't call i2c_new_probed_device() because it uses
+ * quick writes for probing and at least some RC receiver
+ * devices only reply to reads.
+ * Also, Hauppauge XVR needs to be specified, as address 0x71
+ * conflicts with another remote type used with saa7134
+ */
+ for (addrp = addr_list; *addrp != I2C_CLIENT_END; addrp++) {
+ info.platform_data = NULL;
+ memset(&core->init_data, 0, sizeof(core->init_data));
+
+ if (*addrp == 0x71) {
+ /* Hauppauge XVR */
+ core->init_data.name = "cx88 Hauppauge XVR remote";
+ core->init_data.ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ core->init_data.type = RC_TYPE_RC5;
+ core->init_data.internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+
+ info.platform_data = &core->init_data;
+ }
+ if (i2c_smbus_xfer(&core->i2c_adap, *addrp, 0,
+ I2C_SMBUS_READ, 0,
+ I2C_SMBUS_QUICK, NULL) >= 0) {
+ info.addr = *addrp;
+ i2c_new_device(&core->i2c_adap, &info);
+ break;
+ }
+ }
}
/* ---------------------------------------------------------------------- */
@@ -628,8 +624,3 @@ void cx88_ir_irq(struct cx88_core *core)
MODULE_AUTHOR("Gerd Knorr, Pavel Machek, Chris Pascoe");
MODULE_DESCRIPTION("input driver for cx88 GPIO-based IR remote controls");
MODULE_LICENSE("GPL");
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index 499f8d512ad6..addf9545e9bf 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -66,8 +66,14 @@ static void request_modules(struct cx8802_dev *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct cx8802_dev *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
@@ -313,7 +319,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
/* ----------------------------------------------------------- */
-static void do_cancel_buffers(struct cx8802_dev *dev, char *reason, int restart)
+static void do_cancel_buffers(struct cx8802_dev *dev, const char *reason, int restart)
{
struct cx88_dmaqueue *q = &dev->mpegq;
struct cx88_buffer *buf;
@@ -358,7 +364,7 @@ static void cx8802_timeout(unsigned long data)
do_cancel_buffers(dev,"timeout",1);
}
-static char *cx88_mpeg_irqs[32] = {
+static const char * cx88_mpeg_irqs[32] = {
"ts_risci1", NULL, NULL, NULL,
"ts_risci2", NULL, NULL, NULL,
"ts_oflow", NULL, NULL, NULL,
@@ -819,6 +825,8 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
dprintk( 1, "%s\n", __func__);
+ flush_request_modules(dev);
+
if (!list_empty(&dev->drvlist)) {
struct cx8802_driver *drv, *tmp;
int err;
@@ -849,7 +857,7 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
kfree(dev);
}
-static struct pci_device_id cx8802_pci_tbl[] = {
+static const struct pci_device_id cx8802_pci_tbl[] = {
{
.vendor = 0x14f1,
.device = 0x8802,
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 239631568f3b..08220de3d74d 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -70,7 +70,7 @@ MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
/* ----------------------------------------------------------- */
-static char *aud_ctl_names[64] = {
+static const char * const aud_ctl_names[64] = {
[EN_BTSC_FORCE_MONO] = "BTSC_FORCE_MONO",
[EN_BTSC_FORCE_STEREO] = "BTSC_FORCE_STEREO",
[EN_BTSC_FORCE_SAP] = "BTSC_FORCE_SAP",
@@ -360,7 +360,15 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
set_audio_registers(core, nicam_bgdki_common);
set_audio_registers(core, nicam_i);
break;
- default:
+ case WW_NONE:
+ case WW_BTSC:
+ case WW_BG:
+ case WW_DK:
+ case WW_EIAJ:
+ case WW_I2SPT:
+ case WW_FM:
+ case WW_I2SADC:
+ case WW_M:
dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__);
set_audio_registers(core, nicam_bgdki_common);
set_audio_registers(core, nicam_default);
@@ -621,7 +629,13 @@ static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
dprintk("%s AM-L (status: devel)\n", __func__);
set_audio_registers(core, am_l);
break;
- default:
+ case WW_NONE:
+ case WW_BTSC:
+ case WW_EIAJ:
+ case WW_I2SPT:
+ case WW_FM:
+ case WW_I2SADC:
+ case WW_M:
dprintk("%s Warning: wrong value\n", __func__);
return;
break;
@@ -779,7 +793,7 @@ void cx88_set_tvaudio(struct cx88_core *core)
set_audio_finish(core, EN_I2SIN_ENABLE);
break;
case WW_NONE:
- default:
+ case WW_I2SPT:
printk("%s/0: unknown tv audio mode [%d]\n",
core->name, core->tvaudio);
break;
@@ -795,8 +809,8 @@ void cx88_newstation(struct cx88_core *core)
void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
{
- static char *m[] = { "stereo", "dual mono", "mono", "sap" };
- static char *p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
+ static const char * const m[] = { "stereo", "dual mono", "mono", "sap" };
+ static const char * const p[] = { "no pilot", "pilot c1", "pilot c2", "?" };
u32 reg, mode, pilot;
reg = cx_read(AUD_STATUS);
@@ -840,7 +854,12 @@ void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t)
break;
}
break;
- default:
+ case WW_NONE:
+ case WW_I:
+ case WW_L:
+ case WW_I2SPT:
+ case WW_FM:
+ case WW_I2SADC:
/* nothing */
break;
}
@@ -945,6 +964,9 @@ void cx88_set_stereo(struct cx88_core *core, u32 mode, int manual)
}
break;
case WW_I2SADC:
+ case WW_NONE:
+ case WW_EIAJ:
+ case WW_I2SPT:
/* DO NOTHING */
break;
}
@@ -1000,7 +1022,12 @@ int cx88_audio_thread(void *data)
/* automatically switch to best available mode */
cx88_set_stereo(core, mode, 0);
break;
- default:
+ case WW_NONE:
+ case WW_BTSC:
+ case WW_EIAJ:
+ case WW_I2SPT:
+ case WW_FM:
+ case WW_I2SADC:
hw_autodetect:
/* stereo autodetection is supported by hardware so
we don't need to do it manually. Do nothing. */
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index d9445b0e7ab2..f8f8389c0362 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -230,7 +230,7 @@ static void vbi_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
cx88_free_buffer(q,buf);
}
-struct videobuf_queue_ops cx8800_vbi_qops = {
+const struct videobuf_queue_ops cx8800_vbi_qops = {
.buf_setup = vbi_setup,
.buf_prepare = vbi_prepare,
.buf_queue = vbi_queue,
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 0fab65c3ab39..508dabbed986 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -31,7 +31,6 @@
#include <linux/kmod.h>
#include <linux/kernel.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/interrupt.h>
#include <linux/dma-mapping.h>
#include <linux/delay.h>
@@ -78,7 +77,7 @@ MODULE_PARM_DESC(vid_limit,"capture memory limit in megabytes");
/* ------------------------------------------------------------------- */
/* static data */
-static struct cx8800_fmt formats[] = {
+static const struct cx8800_fmt formats[] = {
{
.name = "8 bpp, gray",
.fourcc = V4L2_PIX_FMT_GREY,
@@ -142,7 +141,7 @@ static struct cx8800_fmt formats[] = {
},
};
-static struct cx8800_fmt* format_by_fourcc(unsigned int fourcc)
+static const struct cx8800_fmt* format_by_fourcc(unsigned int fourcc)
{
unsigned int i;
@@ -159,7 +158,7 @@ static const struct v4l2_queryctrl no_ctl = {
.flags = V4L2_CTRL_FLAG_DISABLED,
};
-static struct cx88_ctrl cx8800_ctls[] = {
+static const struct cx88_ctrl cx8800_ctls[] = {
/* --- video --- */
{
.v = {
@@ -288,7 +287,7 @@ static struct cx88_ctrl cx8800_ctls[] = {
.shift = 0,
}
};
-static const int CX8800_CTLS = ARRAY_SIZE(cx8800_ctls);
+enum { CX8800_CTLS = ARRAY_SIZE(cx8800_ctls) };
/* Must be sorted from low to high control ID! */
const u32 cx88_user_ctrls[] = {
@@ -306,7 +305,7 @@ const u32 cx88_user_ctrls[] = {
};
EXPORT_SYMBOL(cx88_user_ctrls);
-static const u32 *ctrl_classes[] = {
+static const u32 * const ctrl_classes[] = {
cx88_user_ctrls,
NULL
};
@@ -710,7 +709,7 @@ static void buffer_release(struct videobuf_queue *q, struct videobuf_buffer *vb)
cx88_free_buffer(q,buf);
}
-static struct videobuf_queue_ops cx8800_video_qops = {
+static const struct videobuf_queue_ops cx8800_video_qops = {
.buf_setup = buffer_setup,
.buf_prepare = buffer_prepare,
.buf_queue = buffer_queue,
@@ -752,7 +751,7 @@ static int video_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
struct cx8800_dev *dev = video_drvdata(file);
- struct cx88_core *core;
+ struct cx88_core *core = dev->core;
struct cx8800_fh *fh;
enum v4l2_buf_type type = 0;
int radio = 0;
@@ -769,19 +768,14 @@ static int video_open(struct file *file)
break;
}
- lock_kernel();
-
- core = dev->core;
-
dprintk(1, "open dev=%s radio=%d type=%s\n",
video_device_node_name(vdev), radio, v4l2_type_names[type]);
/* allocate + initialize per filehandle data */
fh = kzalloc(sizeof(*fh),GFP_KERNEL);
- if (NULL == fh) {
- unlock_kernel();
+ if (unlikely(!fh))
return -ENOMEM;
- }
+
file->private_data = fh;
fh->dev = dev;
fh->radio = radio;
@@ -790,18 +784,20 @@ static int video_open(struct file *file)
fh->height = 240;
fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
+ mutex_lock(&core->lock);
+
videobuf_queue_sg_init(&fh->vidq, &cx8800_video_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx88_buffer),
- fh);
+ fh, NULL);
videobuf_queue_sg_init(&fh->vbiq, &cx8800_vbi_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct cx88_buffer),
- fh);
+ fh, NULL);
if (fh->radio) {
dprintk(1,"video_open: setting radio device\n");
@@ -826,9 +822,9 @@ static int video_open(struct file *file)
}
call_all(core, tuner, s_radio);
}
- unlock_kernel();
atomic_inc(&core->users);
+ mutex_unlock(&core->lock);
return 0;
}
@@ -920,10 +916,11 @@ static int video_release(struct file *file)
videobuf_mmap_free(&fh->vidq);
videobuf_mmap_free(&fh->vbiq);
+
+ mutex_lock(&dev->core->lock);
file->private_data = NULL;
kfree(fh);
- mutex_lock(&dev->core->lock);
if(atomic_dec_and_test(&dev->core->users))
call_all(dev->core, core, s_power, 0);
mutex_unlock(&dev->core->lock);
@@ -944,7 +941,7 @@ video_mmap(struct file *file, struct vm_area_struct * vma)
int cx88_get_control (struct cx88_core *core, struct v4l2_control *ctl)
{
- struct cx88_ctrl *c = NULL;
+ const struct cx88_ctrl *c = NULL;
u32 value;
int i;
@@ -976,7 +973,7 @@ EXPORT_SYMBOL(cx88_get_control);
int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
{
- struct cx88_ctrl *c = NULL;
+ const struct cx88_ctrl *c = NULL;
u32 value,mask;
int i;
@@ -1072,7 +1069,7 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
- struct cx8800_fmt *fmt;
+ const struct cx8800_fmt *fmt;
enum v4l2_field field;
unsigned int maxw, maxh;
@@ -1159,15 +1156,6 @@ static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf (struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct cx8800_fh *fh = priv;
-
- return videobuf_cgmbuf (get_queue(fh), mbuf, 8);
-}
-#endif
-
static int vidioc_reqbufs (struct file *file, void *priv, struct v4l2_requestbuffers *p)
{
struct cx8800_fh *fh = priv;
@@ -1247,7 +1235,7 @@ static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *tvnorms)
/* only one input in this sample driver */
int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
{
- static const char *iname[] = {
+ static const char * const iname[] = {
[ CX88_VMUX_COMPOSITE1 ] = "Composite1",
[ CX88_VMUX_COMPOSITE2 ] = "Composite2",
[ CX88_VMUX_COMPOSITE3 ] = "Composite3",
@@ -1267,9 +1255,10 @@ int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i)
i->type = V4L2_INPUT_TYPE_CAMERA;
strcpy(i->name,iname[INPUT(n).type]);
if ((CX88_VMUX_TELEVISION == INPUT(n).type) ||
- (CX88_VMUX_CABLE == INPUT(n).type))
+ (CX88_VMUX_CABLE == INPUT(n).type)) {
i->type = V4L2_INPUT_TYPE_TUNER;
i->std = CX88_NORMS;
+ }
return 0;
}
EXPORT_SYMBOL(cx88_enum_input);
@@ -1578,7 +1567,7 @@ static void cx8800_vid_timeout(unsigned long data)
spin_unlock_irqrestore(&dev->slock,flags);
}
-static char *cx88_vid_irqs[32] = {
+static const char *cx88_vid_irqs[32] = {
"y_risci1", "u_risci1", "v_risci1", "vbi_risc1",
"y_risci2", "u_risci2", "v_risci2", "vbi_risc2",
"y_oflow", "u_oflow", "v_oflow", "vbi_oflow",
@@ -1708,9 +1697,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
@@ -1723,7 +1709,7 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
static struct video_device cx8800_vbi_template;
-static struct video_device cx8800_video_template = {
+static const struct video_device cx8800_video_template = {
.name = "cx8800-video",
.fops = &video_fops,
.ioctl_ops = &video_ioctl_ops,
@@ -1758,7 +1744,7 @@ static const struct v4l2_ioctl_ops radio_ioctl_ops = {
#endif
};
-static struct video_device cx8800_radio_template = {
+static const struct video_device cx8800_radio_template = {
.name = "cx8800-radio",
.fops = &radio_fops,
.ioctl_ops = &radio_ioctl_ops,
@@ -1872,20 +1858,19 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
if (core->board.audio_chip == V4L2_IDENT_WM8775)
v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
- "wm8775", "wm8775", 0x36 >> 1, NULL);
+ "wm8775", 0x36 >> 1, NULL);
if (core->board.audio_chip == V4L2_IDENT_TVAUDIO) {
/* This probes for a tda9874 as is used on some
Pixelview Ultra boards. */
- v4l2_i2c_new_subdev(&core->v4l2_dev,
- &core->i2c_adap,
- "tvaudio", "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
+ v4l2_i2c_new_subdev(&core->v4l2_dev, &core->i2c_adap,
+ "tvaudio", 0, I2C_ADDRS(0xb0 >> 1));
}
switch (core->boardnr) {
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD: {
- static struct i2c_board_info rtc_info = {
+ static const struct i2c_board_info rtc_info = {
I2C_BOARD_INFO("isl1208", 0x6f)
};
@@ -2082,7 +2067,7 @@ static int cx8800_resume(struct pci_dev *pci_dev)
/* ----------------------------------------------------------- */
-static struct pci_device_id cx8800_pci_tbl[] = {
+static const struct pci_device_id cx8800_pci_tbl[] = {
{
.vendor = 0x14f1,
.device = 0x8800,
diff --git a/drivers/media/video/cx88/cx88-vp3054-i2c.c b/drivers/media/video/cx88/cx88-vp3054-i2c.c
index 794f2932b755..d77f8ecab9d7 100644
--- a/drivers/media/video/cx88/cx88-vp3054-i2c.c
+++ b/drivers/media/video/cx88/cx88-vp3054-i2c.c
@@ -121,13 +121,10 @@ int vp3054_i2c_probe(struct cx8802_dev *dev)
memcpy(&vp3054_i2c->algo, &vp3054_i2c_algo_template,
sizeof(vp3054_i2c->algo));
- vp3054_i2c->adap.class |= I2C_CLASS_TV_DIGITAL;
-
vp3054_i2c->adap.dev.parent = &dev->pci->dev;
strlcpy(vp3054_i2c->adap.name, core->name,
sizeof(vp3054_i2c->adap.name));
vp3054_i2c->adap.owner = THIS_MODULE;
- vp3054_i2c->adap.id = I2C_HW_B_CX2388x;
vp3054_i2c->algo.data = dev;
i2c_set_adapdata(&vp3054_i2c->adap, dev);
vp3054_i2c->adap.algo_data = &vp3054_i2c->algo;
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index bdb03d336536..c9981e77416a 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -31,9 +31,8 @@
#include <media/videobuf-dma-sg.h>
#include <media/v4l2-chip-ident.h>
#include <media/cx2341x.h>
-#if defined(CONFIG_VIDEO_CX88_DVB) || defined(CONFIG_VIDEO_CX88_DVB_MODULE)
#include <media/videobuf-dvb.h>
-#endif
+#include <media/ir-kbd-i2c.h>
#include "btcx-risc.h"
#include "cx88-reg.h"
@@ -108,7 +107,7 @@ static unsigned int inline norm_maxh(v4l2_std_id norm)
/* static data */
struct cx8800_fmt {
- char *name;
+ const char *name;
u32 fourcc; /* v4l2 format id */
int depth;
int flags;
@@ -138,7 +137,7 @@ struct cx88_ctrl {
/* more */
struct sram_channel {
- char *name;
+ const char *name;
u32 cmds_start;
u32 ctrl_start;
u32 cdt;
@@ -149,7 +148,7 @@ struct sram_channel {
u32 cnt1_reg;
u32 cnt2_reg;
};
-extern struct sram_channel cx88_sram_channels[];
+extern const struct sram_channel const cx88_sram_channels[];
/* ----------------------------------------------------------- */
/* card configuration */
@@ -240,6 +239,7 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_WINFAST_DTV2000H_J 82
#define CX88_BOARD_PROF_7301 83
#define CX88_BOARD_SAMSUNG_SMT_7020 84
+#define CX88_BOARD_TWINHAN_VP1027_DVBS 85
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -262,7 +262,7 @@ struct cx88_input {
};
struct cx88_board {
- char *name;
+ const char *name;
unsigned int tuner_type;
unsigned int radio_type;
unsigned char tuner_addr;
@@ -281,6 +281,20 @@ struct cx88_subid {
u32 card;
};
+enum cx88_tvaudio {
+ WW_NONE = 1,
+ WW_BTSC,
+ WW_BG,
+ WW_DK,
+ WW_I,
+ WW_L,
+ WW_EIAJ,
+ WW_I2SPT,
+ WW_FM,
+ WW_I2SADC,
+ WW_M
+};
+
#define INPUT(nr) (core->board.input[nr])
/* ----------------------------------------------------------- */
@@ -300,7 +314,7 @@ struct cx88_buffer {
/* cx88 specific */
unsigned int bpl;
struct btcx_riscmem risc;
- struct cx8800_fmt *fmt;
+ const struct cx8800_fmt *fmt;
u32 count;
};
@@ -352,7 +366,7 @@ struct cx88_core {
/* state info */
struct task_struct *kthread;
v4l2_std_id tvnorm;
- u32 tvaudio;
+ enum cx88_tvaudio tvaudio;
u32 audiomode_manual;
u32 audiomode_current;
u32 input;
@@ -363,6 +377,9 @@ struct cx88_core {
/* IR remote control state */
struct cx88_IR *ir;
+ /* I2C remote data */
+ struct IR_i2c_init_data init_data;
+
struct mutex lock;
/* various v4l controls */
u32 freq;
@@ -410,7 +427,7 @@ struct cx8800_fh {
unsigned int nclips;
/* video capture */
- struct cx8800_fmt *fmt;
+ const struct cx8800_fmt *fmt;
unsigned int width,height;
struct videobuf_queue vidq;
@@ -565,7 +582,7 @@ struct cx8802_dev {
/* ----------------------------------------------------------- */
/* cx88-core.c */
-extern void cx88_print_irqbits(char *name, char *tag, char **strings,
+extern void cx88_print_irqbits(const char *name, const char *tag, const char *strings[],
int len, u32 bits, u32 mask);
extern int cx88_core_irq(struct cx88_core *core, u32 status);
@@ -592,10 +609,10 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf);
extern void cx88_risc_disasm(struct cx88_core *core,
struct btcx_riscmem *risc);
extern int cx88_sram_channel_setup(struct cx88_core *core,
- struct sram_channel *ch,
+ const struct sram_channel *ch,
unsigned int bpl, u32 risc);
extern void cx88_sram_channel_dump(struct cx88_core *core,
- struct sram_channel *ch);
+ const struct sram_channel *ch);
extern int cx88_set_scale(struct cx88_core *core, unsigned int width,
unsigned int height, enum v4l2_field field);
@@ -603,8 +620,8 @@ extern int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm);
extern struct video_device *cx88_vdev_init(struct cx88_core *core,
struct pci_dev *pci,
- struct video_device *template,
- char *type);
+ const struct video_device *template_,
+ const char *type);
extern struct cx88_core* cx88_core_get(struct pci_dev *pci);
extern void cx88_core_put(struct cx88_core *core,
struct pci_dev *pci);
@@ -630,7 +647,7 @@ int cx8800_restart_vbi_queue(struct cx8800_dev *dev,
struct cx88_dmaqueue *q);
void cx8800_vbi_timeout(unsigned long data);
-extern struct videobuf_queue_ops cx8800_vbi_qops;
+extern const struct videobuf_queue_ops cx8800_vbi_qops;
/* ----------------------------------------------------------- */
/* cx88-i2c.c */
@@ -650,18 +667,6 @@ extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
/* ----------------------------------------------------------- */
/* cx88-tvaudio.c */
-#define WW_NONE 1
-#define WW_BTSC 2
-#define WW_BG 3
-#define WW_DK 4
-#define WW_I 5
-#define WW_L 6
-#define WW_EIAJ 7
-#define WW_I2SPT 8
-#define WW_FM 9
-#define WW_I2SADC 10
-#define WW_M 11
-
void cx88_set_tvaudio(struct cx88_core *core);
void cx88_newstation(struct cx88_core *core);
void cx88_get_stereo(struct cx88_core *core, struct v4l2_tuner *t);
@@ -685,6 +690,7 @@ int cx88_ir_fini(struct cx88_core *core);
void cx88_ir_irq(struct cx88_core *core);
int cx88_ir_start(struct cx88_core *core);
void cx88_ir_stop(struct cx88_core *core);
+extern void cx88_i2c_init_ir(struct cx88_core *core);
/* ----------------------------------------------------------- */
/* cx88-mpeg.c */
@@ -704,10 +710,3 @@ int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl);
int cx88_video_mux(struct cx88_core *core, unsigned int input);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- * kate: eol "unix"; indent-width 3; remove-trailing-space on; replace-trailing-space-save on; tab-width 8; replace-tabs off; space-indent off; mixed-indent off
- */
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
deleted file mode 100644
index 0f505086774c..000000000000
--- a/drivers/media/video/dabusb.c
+++ /dev/null
@@ -1,931 +0,0 @@
-/*****************************************************************************/
-
-/*
- * dabusb.c -- dab usb driver.
- *
- * Copyright (C) 1999 Deti Fliegl (deti@fliegl.de)
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- *
- * $Id: dabusb.c,v 1.54 2000/07/24 21:39:39 deti Exp $
- *
- */
-
-/*****************************************************************************/
-
-#include <linux/module.h>
-#include <linux/socket.h>
-#include <linux/list.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/init.h>
-#include <asm/uaccess.h>
-#include <asm/atomic.h>
-#include <linux/delay.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-#include <linux/firmware.h>
-#include <linux/ihex.h>
-
-#include "dabusb.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.54"
-#define DRIVER_AUTHOR "Deti Fliegl, deti@fliegl.de"
-#define DRIVER_DESC "DAB-USB Interface Driver for Linux (c)1999"
-
-/* --------------------------------------------------------------------- */
-
-#ifdef CONFIG_USB_DYNAMIC_MINORS
-#define NRDABUSB 256
-#else
-#define NRDABUSB 4
-#endif
-
-/*-------------------------------------------------------------------*/
-
-static dabusb_t dabusb[NRDABUSB];
-static int buffers = 256;
-static struct usb_driver dabusb_driver;
-
-/*-------------------------------------------------------------------*/
-
-static int dabusb_add_buf_tail (pdabusb_t s, struct list_head *dst, struct list_head *src)
-{
- unsigned long flags;
- struct list_head *tmp;
- int ret = 0;
-
- spin_lock_irqsave (&s->lock, flags);
-
- if (list_empty (src)) {
- // no elements in source buffer
- ret = -1;
- goto err;
- }
- tmp = src->next;
- list_move_tail (tmp, dst);
-
- err: spin_unlock_irqrestore (&s->lock, flags);
- return ret;
-}
-/*-------------------------------------------------------------------*/
-#ifdef DEBUG
-static void dump_urb (struct urb *urb)
-{
- dbg("urb :%p", urb);
- dbg("dev :%p", urb->dev);
- dbg("pipe :%08X", urb->pipe);
- dbg("status :%d", urb->status);
- dbg("transfer_flags :%08X", urb->transfer_flags);
- dbg("transfer_buffer :%p", urb->transfer_buffer);
- dbg("transfer_buffer_length:%d", urb->transfer_buffer_length);
- dbg("actual_length :%d", urb->actual_length);
- dbg("setup_packet :%p", urb->setup_packet);
- dbg("start_frame :%d", urb->start_frame);
- dbg("number_of_packets :%d", urb->number_of_packets);
- dbg("interval :%d", urb->interval);
- dbg("error_count :%d", urb->error_count);
- dbg("context :%p", urb->context);
- dbg("complete :%p", urb->complete);
-}
-#endif
-/*-------------------------------------------------------------------*/
-static int dabusb_cancel_queue (pdabusb_t s, struct list_head *q)
-{
- unsigned long flags;
- pbuff_t b;
-
- dbg("dabusb_cancel_queue");
-
- spin_lock_irqsave (&s->lock, flags);
-
- list_for_each_entry(b, q, buff_list) {
-#ifdef DEBUG
- dump_urb(b->purb);
-#endif
- usb_unlink_urb (b->purb);
- }
- spin_unlock_irqrestore (&s->lock, flags);
- return 0;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_free_queue (struct list_head *q)
-{
- struct list_head *tmp;
- struct list_head *p;
- pbuff_t b;
-
- dbg("dabusb_free_queue");
- for (p = q->next; p != q;) {
- b = list_entry (p, buff_t, buff_list);
-
-#ifdef DEBUG
- dump_urb(b->purb);
-#endif
- kfree(b->purb->transfer_buffer);
- usb_free_urb(b->purb);
- tmp = p->next;
- list_del (p);
- kfree (b);
- p = tmp;
- }
-
- return 0;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_free_buffers (pdabusb_t s)
-{
- unsigned long flags;
- dbg("dabusb_free_buffers");
-
- spin_lock_irqsave(&s->lock, flags);
-
- dabusb_free_queue (&s->free_buff_list);
- dabusb_free_queue (&s->rec_buff_list);
-
- spin_unlock_irqrestore(&s->lock, flags);
-
- s->got_mem = 0;
- return 0;
-}
-/*-------------------------------------------------------------------*/
-static void dabusb_iso_complete (struct urb *purb)
-{
- pbuff_t b = purb->context;
- pdabusb_t s = b->s;
- int i;
- int len;
- int dst = 0;
- void *buf = purb->transfer_buffer;
-
- dbg("dabusb_iso_complete");
-
- // process if URB was not killed
- if (purb->status != -ENOENT) {
- unsigned int pipe = usb_rcvisocpipe (purb->dev, _DABUSB_ISOPIPE);
- int pipesize = usb_maxpacket (purb->dev, pipe, usb_pipeout (pipe));
- for (i = 0; i < purb->number_of_packets; i++)
- if (!purb->iso_frame_desc[i].status) {
- len = purb->iso_frame_desc[i].actual_length;
- if (len <= pipesize) {
- memcpy (buf + dst, buf + purb->iso_frame_desc[i].offset, len);
- dst += len;
- }
- else
- dev_err(&purb->dev->dev,
- "dabusb_iso_complete: invalid len %d\n", len);
- }
- else
- dev_warn(&purb->dev->dev, "dabusb_iso_complete: corrupted packet status: %d\n", purb->iso_frame_desc[i].status);
- if (dst != purb->actual_length)
- dev_err(&purb->dev->dev,
- "dst!=purb->actual_length:%d!=%d\n",
- dst, purb->actual_length);
- }
-
- if (atomic_dec_and_test (&s->pending_io) && !s->remove_pending && s->state != _stopped) {
- s->overruns++;
- dev_err(&purb->dev->dev, "overrun (%d)\n", s->overruns);
- }
- wake_up (&s->wait);
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_alloc_buffers (pdabusb_t s)
-{
- int transfer_len = 0;
- pbuff_t b;
- unsigned int pipe = usb_rcvisocpipe (s->usbdev, _DABUSB_ISOPIPE);
- int pipesize = usb_maxpacket (s->usbdev, pipe, usb_pipeout (pipe));
- int packets = _ISOPIPESIZE / pipesize;
- int transfer_buffer_length = packets * pipesize;
- int i;
-
- dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
- pipesize, packets, transfer_buffer_length);
-
- while (transfer_len < (s->total_buffer_size << 10)) {
- b = kzalloc(sizeof (buff_t), GFP_KERNEL);
- if (!b) {
- dev_err(&s->usbdev->dev,
- "kzalloc(sizeof(buff_t))==NULL\n");
- goto err;
- }
- b->s = s;
- b->purb = usb_alloc_urb(packets, GFP_KERNEL);
- if (!b->purb) {
- dev_err(&s->usbdev->dev, "usb_alloc_urb == NULL\n");
- kfree (b);
- goto err;
- }
-
- b->purb->transfer_buffer = kmalloc (transfer_buffer_length, GFP_KERNEL);
- if (!b->purb->transfer_buffer) {
- kfree (b->purb);
- kfree (b);
- dev_err(&s->usbdev->dev,
- "kmalloc(%d)==NULL\n", transfer_buffer_length);
- goto err;
- }
-
- b->purb->transfer_buffer_length = transfer_buffer_length;
- b->purb->number_of_packets = packets;
- b->purb->complete = dabusb_iso_complete;
- b->purb->context = b;
- b->purb->dev = s->usbdev;
- b->purb->pipe = pipe;
- b->purb->transfer_flags = URB_ISO_ASAP;
-
- for (i = 0; i < packets; i++) {
- b->purb->iso_frame_desc[i].offset = i * pipesize;
- b->purb->iso_frame_desc[i].length = pipesize;
- }
-
- transfer_len += transfer_buffer_length;
- list_add_tail (&b->buff_list, &s->free_buff_list);
- }
- s->got_mem = transfer_len;
-
- return 0;
-
- err:
- dabusb_free_buffers (s);
- return -ENOMEM;
-}
-/*-------------------------------------------------------------------*/
-static int dabusb_bulk (pdabusb_t s, pbulk_transfer_t pb)
-{
- int ret;
- unsigned int pipe;
- int actual_length;
-
- dbg("dabusb_bulk");
-
- if (!pb->pipe)
- pipe = usb_rcvbulkpipe (s->usbdev, 2);
- else
- pipe = usb_sndbulkpipe (s->usbdev, 2);
-
- ret=usb_bulk_msg(s->usbdev, pipe, pb->data, pb->size, &actual_length, 100);
- if(ret<0) {
- dev_err(&s->usbdev->dev,
- "usb_bulk_msg failed(%d)\n", ret);
-
- if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
- dev_err(&s->usbdev->dev, "set_interface failed\n");
- return -EINVAL;
- }
-
- }
-
- if( ret == -EPIPE ) {
- dev_warn(&s->usbdev->dev, "CLEAR_FEATURE request to remove STALL condition.\n");
- if(usb_clear_halt(s->usbdev, usb_pipeendpoint(pipe)))
- dev_err(&s->usbdev->dev, "request failed\n");
- }
-
- pb->size = actual_length;
- return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_writemem (pdabusb_t s, int pos, const unsigned char *data,
- int len)
-{
- int ret;
- unsigned char *transfer_buffer = kmalloc (len, GFP_KERNEL);
-
- if (!transfer_buffer) {
- dev_err(&s->usbdev->dev,
- "dabusb_writemem: kmalloc(%d) failed.\n", len);
- return -ENOMEM;
- }
-
- memcpy (transfer_buffer, data, len);
-
- ret=usb_control_msg(s->usbdev, usb_sndctrlpipe( s->usbdev, 0 ), 0xa0, 0x40, pos, 0, transfer_buffer, len, 300);
-
- kfree (transfer_buffer);
- return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_8051_reset (pdabusb_t s, unsigned char reset_bit)
-{
- dbg("dabusb_8051_reset: %d",reset_bit);
- return dabusb_writemem (s, CPUCS_REG, &reset_bit, 1);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_loadmem (pdabusb_t s, const char *fname)
-{
- int ret;
- const struct ihex_binrec *rec;
- const struct firmware *uninitialized_var(fw);
-
- dbg("Enter dabusb_loadmem (internal)");
-
- ret = request_ihex_firmware(&fw, "dabusb/firmware.fw", &s->usbdev->dev);
- if (ret) {
- dev_err(&s->usbdev->dev,
- "Failed to load \"dabusb/firmware.fw\": %d\n", ret);
- goto out;
- }
- ret = dabusb_8051_reset (s, 1);
-
- for (rec = (const struct ihex_binrec *)fw->data; rec;
- rec = ihex_next_binrec(rec)) {
- dbg("dabusb_writemem: %04X %p %d)", be32_to_cpu(rec->addr),
- rec->data, be16_to_cpu(rec->len));
-
- ret = dabusb_writemem(s, be32_to_cpu(rec->addr), rec->data,
- be16_to_cpu(rec->len));
- if (ret < 0) {
- dev_err(&s->usbdev->dev,
- "dabusb_writemem failed (%d %04X %p %d)\n",
- ret, be32_to_cpu(rec->addr),
- rec->data, be16_to_cpu(rec->len));
- break;
- }
- }
- ret = dabusb_8051_reset (s, 0);
- release_firmware(fw);
- out:
- dbg("dabusb_loadmem: exit");
-
- return ret;
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_clear (pdabusb_t s, pbulk_transfer_t b)
-{
- b->size = 4;
- b->data[0] = 0x2a;
- b->data[1] = 0;
- b->data[2] = 0;
- b->data[3] = 0;
-
- dbg("dabusb_fpga_clear");
-
- return dabusb_bulk (s, b);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_init (pdabusb_t s, pbulk_transfer_t b)
-{
- b->size = 4;
- b->data[0] = 0x2c;
- b->data[1] = 0;
- b->data[2] = 0;
- b->data[3] = 0;
-
- dbg("dabusb_fpga_init");
-
- return dabusb_bulk (s, b);
-}
-/* --------------------------------------------------------------------- */
-static int dabusb_fpga_download (pdabusb_t s, const char *fname)
-{
- pbulk_transfer_t b = kmalloc (sizeof (bulk_transfer_t), GFP_KERNEL);
- const struct firmware *fw;
- unsigned int blen, n;
- int ret;
-
- dbg("Enter dabusb_fpga_download (internal)");
-
- if (!b) {
- dev_err(&s->usbdev->dev,
- "kmalloc(sizeof(bulk_transfer_t))==NULL\n");
- return -ENOMEM;
- }
-
- ret = request_firmware(&fw, "dabusb/bitstream.bin", &s->usbdev->dev);
- if (ret) {
- dev_err(&s->usbdev->dev,
- "Failed to load \"dabusb/bitstream.bin\": %d\n", ret);
- kfree(b);
- return ret;
- }
-
- b->pipe = 1;
- ret = dabusb_fpga_clear (s, b);
- mdelay (10);
- blen = fw->data[73] + (fw->data[72] << 8);
-
- dbg("Bitstream len: %i", blen);
-
- b->data[0] = 0x2b;
- b->data[1] = 0;
- b->data[2] = 0;
- b->data[3] = 60;
-
- for (n = 0; n <= blen + 60; n += 60) {
- // some cclks for startup
- b->size = 64;
- memcpy (b->data + 4, fw->data + 74 + n, 60);
- ret = dabusb_bulk (s, b);
- if (ret < 0) {
- dev_err(&s->usbdev->dev, "dabusb_bulk failed.\n");
- break;
- }
- mdelay (1);
- }
-
- ret = dabusb_fpga_init (s, b);
- kfree (b);
- release_firmware(fw);
-
- dbg("exit dabusb_fpga_download");
-
- return ret;
-}
-
-static int dabusb_stop (pdabusb_t s)
-{
- dbg("dabusb_stop");
-
- s->state = _stopped;
- dabusb_cancel_queue (s, &s->rec_buff_list);
-
- dbg("pending_io: %d", s->pending_io.counter);
-
- s->pending_io.counter = 0;
- return 0;
-}
-
-static int dabusb_startrek (pdabusb_t s)
-{
- if (!s->got_mem && s->state != _started) {
-
- dbg("dabusb_startrek");
-
- if (dabusb_alloc_buffers (s) < 0)
- return -ENOMEM;
- dabusb_stop (s);
- s->state = _started;
- s->readptr = 0;
- }
-
- if (!list_empty (&s->free_buff_list)) {
- pbuff_t end;
- int ret;
-
- while (!dabusb_add_buf_tail (s, &s->rec_buff_list, &s->free_buff_list)) {
-
- dbg("submitting: end:%p s->rec_buff_list:%p", s->rec_buff_list.prev, &s->rec_buff_list);
-
- end = list_entry (s->rec_buff_list.prev, buff_t, buff_list);
-
- ret = usb_submit_urb (end->purb, GFP_KERNEL);
- if (ret) {
- dev_err(&s->usbdev->dev,
- "usb_submit_urb returned:%d\n", ret);
- if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
- dev_err(&s->usbdev->dev,
- "startrek: dabusb_add_buf_tail failed\n");
- break;
- }
- else
- atomic_inc (&s->pending_io);
- }
- dbg("pending_io: %d",s->pending_io.counter);
- }
-
- return 0;
-}
-
-static ssize_t dabusb_read (struct file *file, char __user *buf, size_t count, loff_t * ppos)
-{
- pdabusb_t s = (pdabusb_t) file->private_data;
- unsigned long flags;
- unsigned ret = 0;
- int rem;
- int cnt;
- pbuff_t b;
- struct urb *purb = NULL;
-
- dbg("dabusb_read");
-
- if (*ppos)
- return -ESPIPE;
-
- if (s->remove_pending)
- return -EIO;
-
-
- if (!s->usbdev)
- return -EIO;
-
- while (count > 0) {
- dabusb_startrek (s);
-
- spin_lock_irqsave (&s->lock, flags);
-
- if (list_empty (&s->rec_buff_list)) {
-
- spin_unlock_irqrestore(&s->lock, flags);
-
- dev_err(&s->usbdev->dev,
- "error: rec_buf_list is empty\n");
- goto err;
- }
-
- b = list_entry (s->rec_buff_list.next, buff_t, buff_list);
- purb = b->purb;
-
- spin_unlock_irqrestore(&s->lock, flags);
-
- if (purb->status == -EINPROGRESS) {
- if (file->f_flags & O_NONBLOCK) // return nonblocking
- {
- if (!ret)
- ret = -EAGAIN;
- goto err;
- }
-
- interruptible_sleep_on (&s->wait);
-
- if (signal_pending (current)) {
- if (!ret)
- ret = -ERESTARTSYS;
- goto err;
- }
-
- spin_lock_irqsave (&s->lock, flags);
-
- if (list_empty (&s->rec_buff_list)) {
- spin_unlock_irqrestore(&s->lock, flags);
- dev_err(&s->usbdev->dev,
- "error: still no buffer available.\n");
- goto err;
- }
- spin_unlock_irqrestore(&s->lock, flags);
- s->readptr = 0;
- }
- if (s->remove_pending) {
- ret = -EIO;
- goto err;
- }
-
- rem = purb->actual_length - s->readptr; // set remaining bytes to copy
-
- if (count >= rem)
- cnt = rem;
- else
- cnt = count;
-
- dbg("copy_to_user:%p %p %d",buf, purb->transfer_buffer + s->readptr, cnt);
-
- if (copy_to_user (buf, purb->transfer_buffer + s->readptr, cnt)) {
- dev_err(&s->usbdev->dev, "read: copy_to_user failed\n");
- if (!ret)
- ret = -EFAULT;
- goto err;
- }
-
- s->readptr += cnt;
- count -= cnt;
- buf += cnt;
- ret += cnt;
-
- if (s->readptr == purb->actual_length) {
- // finished, take next buffer
- if (dabusb_add_buf_tail (s, &s->free_buff_list, &s->rec_buff_list))
- dev_err(&s->usbdev->dev,
- "read: dabusb_add_buf_tail failed\n");
- s->readptr = 0;
- }
- }
- err: //mutex_unlock(&s->mutex);
- return ret;
-}
-
-static int dabusb_open (struct inode *inode, struct file *file)
-{
- int devnum = iminor(inode);
- pdabusb_t s;
- int r;
-
- if (devnum < DABUSB_MINOR || devnum >= (DABUSB_MINOR + NRDABUSB))
- return -EIO;
-
- lock_kernel();
- s = &dabusb[devnum - DABUSB_MINOR];
-
- dbg("dabusb_open");
- mutex_lock(&s->mutex);
-
- while (!s->usbdev || s->opened) {
- mutex_unlock(&s->mutex);
-
- if (file->f_flags & O_NONBLOCK) {
- return -EBUSY;
- }
- msleep_interruptible(500);
-
- if (signal_pending (current)) {
- unlock_kernel();
- return -EAGAIN;
- }
- mutex_lock(&s->mutex);
- }
- if (usb_set_interface (s->usbdev, _DABUSB_IF, 1) < 0) {
- mutex_unlock(&s->mutex);
- dev_err(&s->usbdev->dev, "set_interface failed\n");
- unlock_kernel();
- return -EINVAL;
- }
- s->opened = 1;
- mutex_unlock(&s->mutex);
-
- file->f_pos = 0;
- file->private_data = s;
-
- r = nonseekable_open(inode, file);
- unlock_kernel();
- return r;
-}
-
-static int dabusb_release (struct inode *inode, struct file *file)
-{
- pdabusb_t s = (pdabusb_t) file->private_data;
-
- dbg("dabusb_release");
-
- mutex_lock(&s->mutex);
- dabusb_stop (s);
- dabusb_free_buffers (s);
- mutex_unlock(&s->mutex);
-
- if (!s->remove_pending) {
- if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0)
- dev_err(&s->usbdev->dev, "set_interface failed\n");
- }
- else
- wake_up (&s->remove_ok);
-
- s->opened = 0;
- return 0;
-}
-
-static long dabusb_ioctl (struct file *file, unsigned int cmd, unsigned long arg)
-{
- pdabusb_t s = (pdabusb_t) file->private_data;
- pbulk_transfer_t pbulk;
- int ret = 0;
- int version = DABUSB_VERSION;
-
- dbg("dabusb_ioctl");
-
- lock_kernel();
- if (s->remove_pending) {
- unlock_kernel();
- return -EIO;
- }
-
- mutex_lock(&s->mutex);
-
- if (!s->usbdev) {
- mutex_unlock(&s->mutex);
- unlock_kernel();
- return -EIO;
- }
-
- switch (cmd) {
-
- case IOCTL_DAB_BULK:
- pbulk = kmalloc(sizeof (bulk_transfer_t), GFP_KERNEL);
-
- if (!pbulk) {
- ret = -ENOMEM;
- break;
- }
-
- if (copy_from_user (pbulk, (void __user *) arg, sizeof (bulk_transfer_t))) {
- ret = -EFAULT;
- kfree (pbulk);
- break;
- }
-
- ret=dabusb_bulk (s, pbulk);
- if(ret==0)
- if (copy_to_user((void __user *)arg, pbulk,
- sizeof(bulk_transfer_t)))
- ret = -EFAULT;
- kfree (pbulk);
- break;
-
- case IOCTL_DAB_OVERRUNS:
- ret = put_user (s->overruns, (unsigned int __user *) arg);
- break;
-
- case IOCTL_DAB_VERSION:
- ret = put_user (version, (unsigned int __user *) arg);
- break;
-
- default:
- ret = -ENOIOCTLCMD;
- break;
- }
- mutex_unlock(&s->mutex);
- unlock_kernel();
- return ret;
-}
-
-static const struct file_operations dabusb_fops =
-{
- .owner = THIS_MODULE,
- .llseek = no_llseek,
- .read = dabusb_read,
- .unlocked_ioctl = dabusb_ioctl,
- .open = dabusb_open,
- .release = dabusb_release,
-};
-
-static char *dabusb_devnode(struct device *dev, mode_t *mode)
-{
- return kasprintf(GFP_KERNEL, "usb/%s", dev_name(dev));
-}
-
-static struct usb_class_driver dabusb_class = {
- .name = "dabusb%d",
- .devnode = dabusb_devnode,
- .fops = &dabusb_fops,
- .minor_base = DABUSB_MINOR,
-};
-
-
-/* --------------------------------------------------------------------- */
-static int dabusb_probe (struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *usbdev = interface_to_usbdev(intf);
- int retval;
- pdabusb_t s;
-
- dbg("dabusb: probe: vendor id 0x%x, device id 0x%x ifnum:%d",
- le16_to_cpu(usbdev->descriptor.idVendor),
- le16_to_cpu(usbdev->descriptor.idProduct),
- intf->altsetting->desc.bInterfaceNumber);
-
- /* We don't handle multiple configurations */
- if (usbdev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- if (intf->altsetting->desc.bInterfaceNumber != _DABUSB_IF &&
- le16_to_cpu(usbdev->descriptor.idProduct) == 0x9999)
- return -ENODEV;
-
-
-
- s = &dabusb[intf->minor];
-
- mutex_lock(&s->mutex);
- s->remove_pending = 0;
- s->usbdev = usbdev;
- s->devnum = intf->minor;
-
- if (usb_reset_configuration (usbdev) < 0) {
- dev_err(&intf->dev, "reset_configuration failed\n");
- goto reject;
- }
- if (le16_to_cpu(usbdev->descriptor.idProduct) == 0x2131) {
- dabusb_loadmem (s, NULL);
- goto reject;
- }
- else {
- dabusb_fpga_download (s, NULL);
-
- if (usb_set_interface (s->usbdev, _DABUSB_IF, 0) < 0) {
- dev_err(&intf->dev, "set_interface failed\n");
- goto reject;
- }
- }
- dbg("bound to interface: %d", intf->altsetting->desc.bInterfaceNumber);
- usb_set_intfdata (intf, s);
- mutex_unlock(&s->mutex);
-
- retval = usb_register_dev(intf, &dabusb_class);
- if (retval) {
- usb_set_intfdata (intf, NULL);
- return -ENOMEM;
- }
-
- return 0;
-
- reject:
- mutex_unlock(&s->mutex);
- s->usbdev = NULL;
- return -ENODEV;
-}
-
-static void dabusb_disconnect (struct usb_interface *intf)
-{
- wait_queue_t __wait;
- pdabusb_t s = usb_get_intfdata (intf);
-
- dbg("dabusb_disconnect");
-
- init_waitqueue_entry(&__wait, current);
-
- usb_set_intfdata (intf, NULL);
- if (s) {
- usb_deregister_dev (intf, &dabusb_class);
- s->remove_pending = 1;
- wake_up (&s->wait);
- add_wait_queue(&s->remove_ok, &__wait);
- set_current_state(TASK_UNINTERRUPTIBLE);
- if (s->state == _started)
- schedule();
- current->state = TASK_RUNNING;
- remove_wait_queue(&s->remove_ok, &__wait);
-
- s->usbdev = NULL;
- s->overruns = 0;
- }
-}
-
-static struct usb_device_id dabusb_ids [] = {
- // { USB_DEVICE(0x0547, 0x2131) }, /* An2131 chip, no boot ROM */
- { USB_DEVICE(0x0547, 0x9999) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, dabusb_ids);
-
-static struct usb_driver dabusb_driver = {
- .name = "dabusb",
- .probe = dabusb_probe,
- .disconnect = dabusb_disconnect,
- .id_table = dabusb_ids,
-};
-
-/* --------------------------------------------------------------------- */
-
-static int __init dabusb_init (void)
-{
- int retval;
- unsigned u;
-
- /* initialize struct */
- for (u = 0; u < NRDABUSB; u++) {
- pdabusb_t s = &dabusb[u];
- memset (s, 0, sizeof (dabusb_t));
- mutex_init (&s->mutex);
- s->usbdev = NULL;
- s->total_buffer_size = buffers;
- init_waitqueue_head (&s->wait);
- init_waitqueue_head (&s->remove_ok);
- spin_lock_init (&s->lock);
- INIT_LIST_HEAD (&s->free_buff_list);
- INIT_LIST_HEAD (&s->rec_buff_list);
- }
-
- /* register misc device */
- retval = usb_register(&dabusb_driver);
- if (retval)
- goto out;
-
- dbg("dabusb_init: driver registered");
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
-out:
- return retval;
-}
-
-static void __exit dabusb_cleanup (void)
-{
- dbg("dabusb_cleanup");
-
- usb_deregister (&dabusb_driver);
-}
-
-/* --------------------------------------------------------------------- */
-
-MODULE_AUTHOR( DRIVER_AUTHOR );
-MODULE_DESCRIPTION( DRIVER_DESC );
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("dabusb/firmware.fw");
-MODULE_FIRMWARE("dabusb/bitstream.bin");
-
-module_param(buffers, int, 0);
-MODULE_PARM_DESC (buffers, "Number of buffers (default=256)");
-
-module_init (dabusb_init);
-module_exit (dabusb_cleanup);
-
-/* --------------------------------------------------------------------- */
diff --git a/drivers/media/video/dabusb.h b/drivers/media/video/dabusb.h
deleted file mode 100644
index 00eb34c863eb..000000000000
--- a/drivers/media/video/dabusb.h
+++ /dev/null
@@ -1,85 +0,0 @@
-#define _BULK_DATA_LEN 64
-typedef struct
-{
- unsigned char data[_BULK_DATA_LEN];
- unsigned int size;
- unsigned int pipe;
-}bulk_transfer_t,*pbulk_transfer_t;
-
-#define DABUSB_MINOR 240 /* some unassigned USB minor */
-#define DABUSB_VERSION 0x1000
-#define IOCTL_DAB_BULK _IOWR('d', 0x30, bulk_transfer_t)
-#define IOCTL_DAB_OVERRUNS _IOR('d', 0x15, int)
-#define IOCTL_DAB_VERSION _IOR('d', 0x3f, int)
-
-#ifdef __KERNEL__
-
-typedef enum { _stopped=0, _started } driver_state_t;
-
-typedef struct
-{
- struct mutex mutex;
- struct usb_device *usbdev;
- wait_queue_head_t wait;
- wait_queue_head_t remove_ok;
- spinlock_t lock;
- atomic_t pending_io;
- driver_state_t state;
- int remove_pending;
- int got_mem;
- int total_buffer_size;
- unsigned int overruns;
- int readptr;
- int opened;
- int devnum;
- struct list_head free_buff_list;
- struct list_head rec_buff_list;
-} dabusb_t,*pdabusb_t;
-
-typedef struct
-{
- pdabusb_t s;
- struct urb *purb;
- struct list_head buff_list;
-} buff_t,*pbuff_t;
-
-typedef struct
-{
- wait_queue_head_t wait;
-} bulk_completion_context_t, *pbulk_completion_context_t;
-
-
-#define _DABUSB_IF 2
-#define _DABUSB_ISOPIPE 0x09
-#define _ISOPIPESIZE 16384
-
-#define _BULK_DATA_LEN 64
-// Vendor specific request code for Anchor Upload/Download
-// This one is implemented in the core
-#define ANCHOR_LOAD_INTERNAL 0xA0
-
-// EZ-USB Control and Status Register. Bit 0 controls 8051 reset
-#define CPUCS_REG 0x7F92
-#define _TOTAL_BUFFERS 384
-
-#define MAX_INTEL_HEX_RECORD_LENGTH 16
-
-#ifndef _BYTE_DEFINED
-#define _BYTE_DEFINED
-typedef unsigned char BYTE;
-#endif // !_BYTE_DEFINED
-
-#ifndef _WORD_DEFINED
-#define _WORD_DEFINED
-typedef unsigned short WORD;
-#endif // !_WORD_DEFINED
-
-typedef struct _INTEL_HEX_RECORD
-{
- BYTE Length;
- WORD Address;
- BYTE Type;
- BYTE Data[MAX_INTEL_HEX_RECORD_LENGTH];
-} INTEL_HEX_RECORD, *PINTEL_HEX_RECORD;
-
-#endif
diff --git a/drivers/media/video/davinci/Kconfig b/drivers/media/video/davinci/Kconfig
new file mode 100644
index 000000000000..6b1954035649
--- /dev/null
+++ b/drivers/media/video/davinci/Kconfig
@@ -0,0 +1,93 @@
+config DISPLAY_DAVINCI_DM646X_EVM
+ tristate "DM646x EVM Video Display"
+ depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEO_DAVINCI_VPIF
+ select VIDEO_ADV7343
+ select VIDEO_THS7303
+ help
+ Support for DM6467 based display device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif_display.
+
+config CAPTURE_DAVINCI_DM646X_EVM
+ tristate "DM646x EVM Video Capture"
+ depends on VIDEO_DEV && MACH_DAVINCI_DM6467_EVM
+ select VIDEOBUF_DMA_CONTIG
+ select VIDEO_DAVINCI_VPIF
+ help
+ Support for DM6467 based capture device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif_capture.
+
+config VIDEO_DAVINCI_VPIF
+ tristate "DaVinci VPIF Driver"
+ depends on DISPLAY_DAVINCI_DM646X_EVM
+ help
+ Support for DaVinci VPIF Driver.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpif.
+
+config VIDEO_VPSS_SYSTEM
+ tristate "VPSS System module driver"
+ depends on ARCH_DAVINCI
+ help
+ Support for vpss system module for video driver
+
+config VIDEO_VPFE_CAPTURE
+ tristate "VPFE Video Capture Driver"
+ depends on VIDEO_V4L2 && (ARCH_DAVINCI || ARCH_OMAP3)
+ select VIDEOBUF_DMA_CONTIG
+ help
+ Support for DMx/AMx VPFE based frame grabber. This is the
+ common V4L2 module for following DMx/AMx SoCs from Texas
+ Instruments:- DM6446, DM365, DM355 & AM3517/05.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe-capture.
+
+config VIDEO_DM6446_CCDC
+ tristate "DM6446 CCDC HW module"
+ depends on VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DaVinci CCD hw module. DaVinci CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from slave decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_DM355_CCDC
+ tristate "DM355 CCDC HW module"
+ depends on ARCH_DAVINCI_DM355 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables DM355 CCD hw module. DM355 CCDC hw interfaces
+ with decoder modules such as TVP5146 over BT656 or
+ sensor module such as MT9T001 over a raw interface. This
+ module configures the interface and CCDC/ISIF to do
+ video frame capture from a slave decoders
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
+
+config VIDEO_ISIF
+ tristate "ISIF HW module"
+ depends on ARCH_DAVINCI_DM365 && VIDEO_VPFE_CAPTURE
+ select VIDEO_VPSS_SYSTEM
+ default y
+ help
+ Enables ISIF hw module. This is the hardware module for
+ configuring ISIF in VPFE to capture Raw Bayer RGB data from
+ a image sensor or YUV data from a YUV source.
+
+ To compile this driver as a module, choose M here: the
+ module will be called vpfe.
diff --git a/drivers/media/video/davinci/vpfe_capture.c b/drivers/media/video/davinci/vpfe_capture.c
index 1c2588247289..353eadaa823e 100644
--- a/drivers/media/video/davinci/vpfe_capture.c
+++ b/drivers/media/video/davinci/vpfe_capture.c
@@ -370,7 +370,7 @@ static int vpfe_config_ccdc_image_format(struct vpfe_device *vpfe_dev)
* For a given standard, this functions sets up the default
* pix format & crop values in the vpfe device and ccdc. It first
* starts with defaults based values from the standard table.
- * It then checks if sub device support g_fmt and then override the
+ * It then checks if sub device support g_mbus_fmt and then override the
* values based on that.Sets crop values to match with scan resolution
* starting at 0,0. It calls vpfe_config_ccdc_image_format() set the
* values in ccdc
@@ -379,6 +379,8 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
const v4l2_std_id *std_id)
{
struct vpfe_subdev_info *sdinfo = vpfe_dev->current_subdev;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct v4l2_pix_format *pix = &vpfe_dev->fmt.fmt.pix;
int i, ret = 0;
for (i = 0; i < ARRAY_SIZE(vpfe_standards); i++) {
@@ -403,29 +405,36 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
vpfe_dev->crop.left = 0;
vpfe_dev->crop.width = vpfe_dev->std_info.active_pixels;
vpfe_dev->crop.height = vpfe_dev->std_info.active_lines;
- vpfe_dev->fmt.fmt.pix.width = vpfe_dev->crop.width;
- vpfe_dev->fmt.fmt.pix.height = vpfe_dev->crop.height;
+ pix->width = vpfe_dev->crop.width;
+ pix->height = vpfe_dev->crop.height;
/* first field and frame format based on standard frame format */
if (vpfe_dev->std_info.frame_format) {
- vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_INTERLACED;
+ pix->field = V4L2_FIELD_INTERLACED;
/* assume V4L2_PIX_FMT_UYVY as default */
- vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ pix->pixelformat = V4L2_PIX_FMT_UYVY;
+ v4l2_fill_mbus_format(&mbus_fmt, pix,
+ V4L2_MBUS_FMT_YUYV10_2X10);
} else {
- vpfe_dev->fmt.fmt.pix.field = V4L2_FIELD_NONE;
+ pix->field = V4L2_FIELD_NONE;
/* assume V4L2_PIX_FMT_SBGGR8 */
- vpfe_dev->fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_SBGGR8;
+ pix->pixelformat = V4L2_PIX_FMT_SBGGR8;
+ v4l2_fill_mbus_format(&mbus_fmt, pix,
+ V4L2_MBUS_FMT_SBGGR8_1X8);
}
- /* if sub device supports g_fmt, override the defaults */
+ /* if sub device supports g_mbus_fmt, override the defaults */
ret = v4l2_device_call_until_err(&vpfe_dev->v4l2_dev,
- sdinfo->grp_id, video, g_fmt, &vpfe_dev->fmt);
+ sdinfo->grp_id, video, g_mbus_fmt, &mbus_fmt);
if (ret && ret != -ENOIOCTLCMD) {
v4l2_err(&vpfe_dev->v4l2_dev,
- "error in getting g_fmt from sub device\n");
+ "error in getting g_mbus_fmt from sub device\n");
return ret;
}
+ v4l2_fill_pix_format(pix, &mbus_fmt);
+ pix->bytesperline = pix->width * 2;
+ pix->sizeimage = pix->bytesperline * pix->height;
/* Sets the values in CCDC */
ret = vpfe_config_ccdc_image_format(vpfe_dev);
@@ -434,11 +443,8 @@ static int vpfe_config_image_format(struct vpfe_device *vpfe_dev,
/* Update the values of sizeimage and bytesperline */
if (!ret) {
- vpfe_dev->fmt.fmt.pix.bytesperline =
- ccdc_dev->hw_ops.get_line_length();
- vpfe_dev->fmt.fmt.pix.sizeimage =
- vpfe_dev->fmt.fmt.pix.bytesperline *
- vpfe_dev->fmt.fmt.pix.height;
+ pix->bytesperline = ccdc_dev->hw_ops.get_line_length();
+ pix->sizeimage = pix->bytesperline * pix->height;
}
return ret;
}
@@ -1270,7 +1276,7 @@ static int vpfe_videobuf_prepare(struct videobuf_queue *vq,
vb->size = vpfe_dev->fmt.fmt.pix.sizeimage;
vb->field = field;
- ret = videobuf_iolock(vq, vb, NULL);;
+ ret = videobuf_iolock(vq, vb, NULL);
if (ret < 0)
return ret;
@@ -1366,7 +1372,7 @@ static int vpfe_reqbufs(struct file *file, void *priv,
req_buf->type,
vpfe_dev->fmt.fmt.pix.field,
sizeof(struct videobuf_buffer),
- fh);
+ fh, NULL);
fh->io_allowed = 1;
vpfe_dev->io_usrs = 1;
@@ -1980,7 +1986,6 @@ static __init int vpfe_probe(struct platform_device *pdev)
vpfe_dev->sd[i] =
v4l2_i2c_new_subdev_board(&vpfe_dev->v4l2_dev,
i2c_adap,
- sdinfo->name,
&sdinfo->board_info,
NULL);
if (vpfe_dev->sd[i]) {
diff --git a/drivers/media/video/davinci/vpif.c b/drivers/media/video/davinci/vpif.c
index 1f532e31cd49..9f3bfc1eb240 100644
--- a/drivers/media/video/davinci/vpif.c
+++ b/drivers/media/video/davinci/vpif.c
@@ -41,6 +41,183 @@ spinlock_t vpif_lock;
void __iomem *vpif_base;
+/**
+ * ch_params: video standard configuration parameters for vpif
+ * The table must include all presets from supported subdevices.
+ */
+const struct vpif_channel_config_params ch_params[] = {
+ /* HDTV formats */
+ {
+ .name = "480p59_94",
+ .width = 720,
+ .height = 480,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 138-8,
+ .sav2eav = 720,
+ .l1 = 1,
+ .l3 = 43,
+ .l5 = 523,
+ .vsize = 525,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_480P59_94,
+ },
+ {
+ .name = "576p50",
+ .width = 720,
+ .height = 576,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 144-8,
+ .sav2eav = 720,
+ .l1 = 1,
+ .l3 = 45,
+ .l5 = 621,
+ .vsize = 625,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_576P50,
+ },
+ {
+ .name = "720p50",
+ .width = 1280,
+ .height = 720,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 700-8,
+ .sav2eav = 1280,
+ .l1 = 1,
+ .l3 = 26,
+ .l5 = 746,
+ .vsize = 750,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_720P50,
+ },
+ {
+ .name = "720p60",
+ .width = 1280,
+ .height = 720,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 370 - 8,
+ .sav2eav = 1280,
+ .l1 = 1,
+ .l3 = 26,
+ .l5 = 746,
+ .vsize = 750,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_720P60,
+ },
+ {
+ .name = "1080I50",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 0,
+ .ycmux_mode = 0,
+ .eav2sav = 720 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 21,
+ .l5 = 561,
+ .l7 = 563,
+ .l9 = 584,
+ .l11 = 1124,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080I50,
+ },
+ {
+ .name = "1080I60",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 0,
+ .ycmux_mode = 0,
+ .eav2sav = 280 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 21,
+ .l5 = 561,
+ .l7 = 563,
+ .l9 = 584,
+ .l11 = 1124,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080I60,
+ },
+ {
+ .name = "1080p60",
+ .width = 1920,
+ .height = 1080,
+ .frm_fmt = 1,
+ .ycmux_mode = 0,
+ .eav2sav = 280 - 8,
+ .sav2eav = 1920,
+ .l1 = 1,
+ .l3 = 42,
+ .l5 = 1122,
+ .vsize = 1125,
+ .capture_format = 0,
+ .vbi_supported = 0,
+ .hd_sd = 1,
+ .dv_preset = V4L2_DV_1080P60,
+ },
+
+ /* SDTV formats */
+ {
+ .name = "NTSC_M",
+ .width = 720,
+ .height = 480,
+ .frm_fmt = 0,
+ .ycmux_mode = 1,
+ .eav2sav = 268,
+ .sav2eav = 1440,
+ .l1 = 1,
+ .l3 = 23,
+ .l5 = 263,
+ .l7 = 266,
+ .l9 = 286,
+ .l11 = 525,
+ .vsize = 525,
+ .capture_format = 0,
+ .vbi_supported = 1,
+ .hd_sd = 0,
+ .stdid = V4L2_STD_525_60,
+ },
+ {
+ .name = "PAL_BDGHIK",
+ .width = 720,
+ .height = 576,
+ .frm_fmt = 0,
+ .ycmux_mode = 1,
+ .eav2sav = 280,
+ .sav2eav = 1440,
+ .l1 = 1,
+ .l3 = 23,
+ .l5 = 311,
+ .l7 = 313,
+ .l9 = 336,
+ .l11 = 624,
+ .vsize = 625,
+ .capture_format = 0,
+ .vbi_supported = 1,
+ .hd_sd = 0,
+ .stdid = V4L2_STD_625_50,
+ },
+};
+
+const unsigned int vpif_ch_params_count = ARRAY_SIZE(ch_params);
+
static inline void vpif_wr_bit(u32 reg, u32 bit, u32 val)
{
if (val)
diff --git a/drivers/media/video/davinci/vpif.h b/drivers/media/video/davinci/vpif.h
index 188841b476e0..10550bd93b06 100644
--- a/drivers/media/video/davinci/vpif.h
+++ b/drivers/media/video/davinci/vpif.h
@@ -33,7 +33,7 @@ extern spinlock_t vpif_lock;
#define regr(reg) readl((reg) + vpif_base)
#define regw(value, reg) writel(value, (reg + vpif_base))
-/* Register Addresss Offsets */
+/* Register Address Offsets */
#define VPIF_PID (0x0000)
#define VPIF_CH0_CTRL (0x0004)
#define VPIF_CH1_CTRL (0x0008)
@@ -577,12 +577,10 @@ struct vpif_channel_config_params {
char name[VPIF_MAX_NAME]; /* Name of the mode */
u16 width; /* Indicates width of the image */
u16 height; /* Indicates height of the image */
- u8 fps;
- u8 frm_fmt; /* Indicates whether this is interlaced
- * or progressive format */
- u8 ycmux_mode; /* Indicates whether this mode requires
- * single or two channels */
- u16 eav2sav; /* length of sav 2 eav */
+ u8 frm_fmt; /* Interlaced (0) or progressive (1) */
+ u8 ycmux_mode; /* This mode requires one (0) or two (1)
+ channels */
+ u16 eav2sav; /* length of eav 2 sav */
u16 sav2eav; /* length of sav 2 eav */
u16 l1, l3, l5, l7, l9, l11; /* Other parameter configurations */
u16 vsize; /* Vertical size of the image */
@@ -590,10 +588,14 @@ struct vpif_channel_config_params {
* is in BT or in CCD/CMOS */
u8 vbi_supported; /* Indicates whether this mode
* supports capturing vbi or not */
- u8 hd_sd;
- v4l2_std_id stdid;
+ u8 hd_sd; /* HDTV (1) or SDTV (0) format */
+ v4l2_std_id stdid; /* SDTV format */
+ u32 dv_preset; /* HDTV format */
};
+extern const unsigned int vpif_ch_params_count;
+extern const struct vpif_channel_config_params ch_params[];
+
struct vpif_video_params;
struct vpif_params;
struct vpif_vbi_params;
diff --git a/drivers/media/video/davinci/vpif_capture.c b/drivers/media/video/davinci/vpif_capture.c
index a7f48b53d3fc..d93ad74a34c5 100644
--- a/drivers/media/video/davinci/vpif_capture.c
+++ b/drivers/media/video/davinci/vpif_capture.c
@@ -37,6 +37,7 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
#include "vpif_capture.h"
#include "vpif.h"
@@ -81,20 +82,6 @@ static struct vpif_device vpif_obj = { {NULL} };
static struct device *vpif_dev;
/**
- * ch_params: video standard configuration parameters for vpif
- */
-static const struct vpif_channel_config_params ch_params[] = {
- {
- "NTSC_M", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266,
- 286, 525, 525, 0, 1, 0, V4L2_STD_525_60,
- },
- {
- "PAL_BDGHIK", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313,
- 336, 624, 625, 0, 1, 0, V4L2_STD_625_50,
- },
-};
-
-/**
* vpif_uservirt_to_phys : translate user/virtual address to phy address
* @virtp: user/virtual address
*
@@ -342,7 +329,7 @@ static void vpif_schedule_next_buffer(struct common_obj *common)
* @dev_id: dev_id ptr
*
* It changes status of the captured buffer, takes next buffer from the queue
- * and sets its address in VPIF registers
+ * and sets its address in VPIF registers
*/
static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
{
@@ -435,24 +422,31 @@ static int vpif_update_std_info(struct channel_obj *ch)
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct vpif_params *vpifparams = &ch->vpifparams;
const struct vpif_channel_config_params *config;
- struct vpif_channel_config_params *std_info;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
struct video_obj *vid_ch = &ch->video;
int index;
vpif_dbg(2, debug, "vpif_update_std_info\n");
- std_info = &vpifparams->std_info;
-
- for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
+ for (index = 0; index < vpif_ch_params_count; index++) {
config = &ch_params[index];
- if (config->stdid & vid_ch->stdid) {
- memcpy(std_info, config, sizeof(*config));
- break;
+ if (config->hd_sd == 0) {
+ vpif_dbg(2, debug, "SD format\n");
+ if (config->stdid & vid_ch->stdid) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ } else {
+ vpif_dbg(2, debug, "HD format\n");
+ if (config->dv_preset == vid_ch->dv_preset) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
}
}
/* standard not found */
- if (index == ARRAY_SIZE(ch_params))
+ if (index == vpif_ch_params_count)
return -EINVAL;
common->fmt.fmt.pix.width = std_info->width;
@@ -462,6 +456,7 @@ static int vpif_update_std_info(struct channel_obj *ch)
common->fmt.fmt.pix.bytesperline = std_info->width;
vpifparams->video_params.hpitch = std_info->width;
vpifparams->video_params.storage_mode = std_info->frm_fmt;
+
return 0;
}
@@ -731,7 +726,6 @@ static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
*/
static unsigned int vpif_poll(struct file *filep, poll_table * wait)
{
- int err = 0;
struct vpif_fh *fh = filep->private_data;
struct channel_obj *channel = fh->channel;
struct common_obj *common = &(channel->common[VPIF_VIDEO_INDEX]);
@@ -739,8 +733,7 @@ static unsigned int vpif_poll(struct file *filep, poll_table * wait)
vpif_dbg(2, debug, "vpif_poll\n");
if (common->started)
- err = videobuf_poll_stream(filep, &common->buffer_queue, wait);
-
+ return videobuf_poll_stream(filep, &common->buffer_queue, wait);
return 0;
}
@@ -759,7 +752,7 @@ static int vpif_open(struct file *filep)
struct video_obj *vid_ch;
struct channel_obj *ch;
struct vpif_fh *fh;
- int i, ret = 0;
+ int i;
vpif_dbg(2, debug, "vpif_open\n");
@@ -768,9 +761,6 @@ static int vpif_open(struct file *filep)
vid_ch = &ch->video;
common = &ch->common[VPIF_VIDEO_INDEX];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
if (NULL == ch->curr_subdev_info) {
/**
* search through the sub device to see a registered
@@ -787,17 +777,15 @@ static int vpif_open(struct file *filep)
}
if (i == config->subdev_count) {
vpif_err("No sub device registered\n");
- ret = -ENOENT;
- goto exit;
+ return -ENOENT;
}
}
/* Allocate memory for the file handle object */
- fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+ fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
if (NULL == fh) {
vpif_err("unable to allocate memory for file handle object\n");
- ret = -ENOMEM;
- goto exit;
+ return -ENOMEM;
}
/* store pointer to fh in private_data member of filep */
@@ -817,9 +805,7 @@ static int vpif_open(struct file *filep)
/* Initialize priority of this instance to default priority */
fh->prio = V4L2_PRIORITY_UNSET;
v4l2_prio_open(&ch->prio, &fh->prio);
-exit:
- mutex_unlock(&common->lock);
- return ret;
+ return 0;
}
/**
@@ -839,9 +825,6 @@ static int vpif_release(struct file *filep)
common = &ch->common[VPIF_VIDEO_INDEX];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* if this instance is doing IO */
if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
/* Reset io_usrs member of channel object */
@@ -865,9 +848,6 @@ static int vpif_release(struct file *filep)
/* Decrement channel usrs counter */
ch->usrs--;
- /* unlock mutex on channel object */
- mutex_unlock(&common->lock);
-
/* Close the priority */
v4l2_prio_close(&ch->prio, fh->prio);
@@ -892,7 +872,6 @@ static int vpif_reqbufs(struct file *file, void *priv,
struct channel_obj *ch = fh->channel;
struct common_obj *common;
u8 index = 0;
- int ret = 0;
vpif_dbg(2, debug, "vpif_reqbufs\n");
@@ -915,13 +894,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
common = &ch->common[index];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
- if (0 != common->io_usrs) {
- ret = -EBUSY;
- goto reqbuf_exit;
- }
+ if (0 != common->io_usrs)
+ return -EBUSY;
/* Initialize videobuf queue as per the buffer type */
videobuf_queue_dma_contig_init(&common->buffer_queue,
@@ -929,7 +903,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
&common->irqlock,
reqbuf->type,
common->fmt.fmt.pix.field,
- sizeof(struct videobuf_buffer), fh);
+ sizeof(struct videobuf_buffer), fh,
+ &common->lock);
/* Set io allowed member of file handle to TRUE */
fh->io_allowed[index] = 1;
@@ -940,11 +915,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
INIT_LIST_HEAD(&common->dma_queue);
/* Allocate buffers */
- ret = videobuf_reqbufs(&common->buffer_queue, reqbuf);
-
-reqbuf_exit:
- mutex_unlock(&common->lock);
- return ret;
+ return videobuf_reqbufs(&common->buffer_queue, reqbuf);
}
/**
@@ -1030,9 +1001,10 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
goto qbuf_exit;
if ((VIDEOBUF_NEEDS_INIT != buf1->state)
- && (buf1->baddr != tbuf.m.userptr))
+ && (buf1->baddr != tbuf.m.userptr)) {
vpif_buffer_release(&common->buffer_queue, buf1);
buf1->baddr = tbuf.m.userptr;
+ }
break;
default:
@@ -1157,11 +1129,6 @@ static int vpif_streamon(struct file *file, void *priv,
return ret;
}
- if (mutex_lock_interruptible(&common->lock)) {
- ret = -ERESTARTSYS;
- goto streamoff_exit;
- }
-
/* If buffer queue is empty, return error */
if (list_empty(&common->dma_queue)) {
vpif_dbg(1, debug, "buffer queue is empty\n");
@@ -1240,13 +1207,10 @@ static int vpif_streamon(struct file *file, void *priv,
enable_channel1(1);
}
channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
- mutex_unlock(&common->lock);
return ret;
exit:
- mutex_unlock(&common->lock);
-streamoff_exit:
- ret = videobuf_streamoff(&common->buffer_queue);
+ videobuf_streamoff(&common->buffer_queue);
return ret;
}
@@ -1284,9 +1248,6 @@ static int vpif_streamoff(struct file *file, void *priv,
return -EINVAL;
}
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* disable channel */
if (VPIF_CHANNEL0_VIDEO == ch->channel_id) {
enable_channel0(0);
@@ -1304,8 +1265,6 @@ static int vpif_streamoff(struct file *file, void *priv,
if (ret && (ret != -ENOIOCTLCMD))
vpif_dbg(1, debug, "stream off failed in subdev\n");
- mutex_unlock(&common->lock);
-
return videobuf_streamoff(&common->buffer_queue);
}
@@ -1381,21 +1340,16 @@ static int vpif_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
{
struct vpif_fh *fh = priv;
struct channel_obj *ch = fh->channel;
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
int ret = 0;
vpif_dbg(2, debug, "vpif_querystd\n");
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* Call querystd function of decoder device */
ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], video,
querystd, std_id);
if (ret < 0)
vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
- mutex_unlock(&common->lock);
return ret;
}
@@ -1451,16 +1405,14 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
fh->initialized = 1;
/* Call encoder subdevice function to set the standard */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
ch->video.stdid = *std_id;
+ ch->video.dv_preset = V4L2_DV_INVALID;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
/* Get the information about the standard */
if (vpif_update_std_info(ch)) {
- ret = -EINVAL;
vpif_err("Error getting the standard info\n");
- goto s_std_exit;
+ return -EINVAL;
}
/* Configure the default format information */
@@ -1471,9 +1423,6 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
s_std, *std_id);
if (ret < 0)
vpif_dbg(1, debug, "Failed to set standard for sub devices\n");
-
-s_std_exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1567,9 +1516,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
return -EINVAL;
}
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* first setup input path from sub device to vpif */
if (config->setup_input_path) {
ret = config->setup_input_path(ch->channel_id,
@@ -1578,7 +1524,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
vpif_dbg(1, debug, "couldn't setup input path for the"
" sub device %s, for input index %d\n",
subdev_info->name, index);
- goto exit;
+ return ret;
}
}
@@ -1589,7 +1535,7 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
input, output, 0);
if (ret < 0) {
vpif_dbg(1, debug, "Failed to set input\n");
- goto exit;
+ return ret;
}
}
vid_ch->input_idx = index;
@@ -1600,9 +1546,6 @@ static int vpif_s_input(struct file *file, void *priv, unsigned int index)
/* update tvnorms from the sub device input info */
ch->video_dev->tvnorms = chan_cfg->inputs[index].input.std;
-
-exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1671,11 +1614,7 @@ static int vpif_g_fmt_vid_cap(struct file *file, void *priv,
return -EINVAL;
/* Fill in the information about format */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
*fmt = common->fmt;
- mutex_unlock(&common->lock);
return 0;
}
@@ -1694,7 +1633,7 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_pix_format *pixfmt;
int ret = 0;
- vpif_dbg(2, debug, "VIDIOC_S_FMT\n");
+ vpif_dbg(2, debug, "%s\n", __func__);
/* If streaming is started, return error */
if (common->started) {
@@ -1723,12 +1662,7 @@ static int vpif_s_fmt_vid_cap(struct file *file, void *priv,
if (ret)
return ret;
/* store the format in the channel object */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
common->fmt = *fmt;
- mutex_unlock(&common->lock);
-
return 0;
}
@@ -1807,6 +1741,306 @@ static int vpif_cropcap(struct file *file, void *priv,
return 0;
}
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_query_dv_presets() - QUERY_DV_PRESET handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_query_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, query_dv_preset, preset);
+}
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ int ret = 0;
+
+ if (common->started) {
+ vpif_dbg(1, debug, "streaming in progress\n");
+ return -EBUSY;
+ }
+
+ if ((VPIF_CHANNEL0_VIDEO == ch->channel_id) ||
+ (VPIF_CHANNEL1_VIDEO == ch->channel_id)) {
+ if (!fh->initialized) {
+ vpif_dbg(1, debug, "Channel Busy\n");
+ return -EBUSY;
+ }
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (ret)
+ return ret;
+
+ fh->initialized = 1;
+
+ /* Call encoder subdevice function to set the standard */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ ch->video.dv_preset = preset->preset;
+ ch->video.stdid = V4L2_STD_UNKNOWN;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+ /* Get the information about the standard */
+ if (vpif_update_std_info(ch)) {
+ vpif_dbg(1, debug, "Error getting the standard info\n");
+ ret = -EINVAL;
+ } else {
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, s_dv_preset, preset);
+ }
+
+ mutex_unlock(&common->lock);
+
+ return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ preset->preset = ch->video.dv_preset;
+
+ return 0;
+}
+
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+ int ret;
+
+ if (timings->type != V4L2_DV_BT_656_1120) {
+ vpif_dbg(2, debug, "Timing type not defined\n");
+ return -EINVAL;
+ }
+
+ /* Configure subdevice timings, if any */
+ ret = v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index],
+ video, s_dv_timings, timings);
+ if (ret == -ENOIOCTLCMD) {
+ vpif_dbg(2, debug, "Custom DV timings not supported by "
+ "subdevice\n");
+ return -EINVAL;
+ }
+ if (ret < 0) {
+ vpif_dbg(2, debug, "Error setting custom DV timings\n");
+ return ret;
+ }
+
+ if (!(timings->bt.width && timings->bt.height &&
+ (timings->bt.hbackporch ||
+ timings->bt.hfrontporch ||
+ timings->bt.hsync) &&
+ timings->bt.vfrontporch &&
+ (timings->bt.vbackporch ||
+ timings->bt.vsync))) {
+ vpif_dbg(2, debug, "Timings for width, height, "
+ "horizontal back porch, horizontal sync, "
+ "horizontal front porch, vertical back porch, "
+ "vertical sync and vertical back porch "
+ "must be defined\n");
+ return -EINVAL;
+ }
+
+ *bt = timings->bt;
+
+ /* Configure video port timings */
+
+ std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+ bt->hsync - 8;
+ std_info->sav2eav = bt->width;
+
+ std_info->l1 = 1;
+ std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+ if (bt->interlaced) {
+ if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+ std_info->vsize = bt->height * 2 +
+ bt->vfrontporch + bt->vsync + bt->vbackporch +
+ bt->il_vfrontporch + bt->il_vsync +
+ bt->il_vbackporch;
+ std_info->l5 = std_info->vsize/2 -
+ (bt->vfrontporch - 1);
+ std_info->l7 = std_info->vsize/2 + 1;
+ std_info->l9 = std_info->l7 + bt->il_vsync +
+ bt->il_vbackporch + 1;
+ std_info->l11 = std_info->vsize -
+ (bt->il_vfrontporch - 1);
+ } else {
+ vpif_dbg(2, debug, "Required timing values for "
+ "interlaced BT format missing\n");
+ return -EINVAL;
+ }
+ } else {
+ std_info->vsize = bt->height + bt->vfrontporch +
+ bt->vsync + bt->vbackporch;
+ std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+ }
+ strncpy(std_info->name, "Custom timings BT656/1120", VPIF_MAX_NAME);
+ std_info->width = bt->width;
+ std_info->height = bt->height;
+ std_info->frm_fmt = bt->interlaced ? 0 : 1;
+ std_info->ycmux_mode = 0;
+ std_info->capture_format = 0;
+ std_info->vbi_supported = 0;
+ std_info->hd_sd = 1;
+ std_info->stdid = 0;
+ std_info->dv_preset = V4L2_DV_INVALID;
+
+ vid_ch->stdid = 0;
+ vid_ch->dv_preset = V4L2_DV_INVALID;
+ return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+ timings->bt = *bt;
+
+ return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
+ vpif_dbg(2, debug, "match_type is invalid.\n");
+ return -EINVAL;
+ }
+
+ return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+ g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+ g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ return v4l2_subdev_call(vpif_obj.sd[ch->curr_sd_index], core,
+ s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+ /* status for sub devices */
+ v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+ return 0;
+}
+
/* vpif capture ioctl operations */
static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_querycap = vpif_querycap,
@@ -1829,6 +2063,18 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_streamon = vpif_streamon,
.vidioc_streamoff = vpif_streamoff,
.vidioc_cropcap = vpif_cropcap,
+ .vidioc_enum_dv_presets = vpif_enum_dv_presets,
+ .vidioc_s_dv_preset = vpif_s_dv_preset,
+ .vidioc_g_dv_preset = vpif_g_dv_preset,
+ .vidioc_query_dv_preset = vpif_query_dv_preset,
+ .vidioc_s_dv_timings = vpif_s_dv_timings,
+ .vidioc_g_dv_timings = vpif_g_dv_timings,
+ .vidioc_g_chip_ident = vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vpif_dbg_g_register,
+ .vidioc_s_register = vpif_dbg_s_register,
+#endif
+ .vidioc_log_status = vpif_log_status,
};
/* vpif file operations */
@@ -1836,7 +2082,7 @@ static struct v4l2_file_operations vpif_fops = {
.owner = THIS_MODULE,
.open = vpif_open,
.release = vpif_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = vpif_mmap,
.poll = vpif_poll
};
@@ -1979,6 +2225,7 @@ static __init int vpif_probe(struct platform_device *pdev)
common = &(ch->common[VPIF_VIDEO_INDEX]);
spin_lock_init(&common->irqlock);
mutex_init(&common->lock);
+ ch->video_dev->lock = &common->lock;
/* Initialize prio member of channel object */
v4l2_prio_init(&ch->prio);
err = video_register_device(ch->video_dev,
@@ -1994,7 +2241,7 @@ static __init int vpif_probe(struct platform_device *pdev)
config = pdev->dev.platform_data;
subdev_count = config->subdev_count;
- vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+ vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
GFP_KERNEL);
if (vpif_obj.sd == NULL) {
vpif_err("unable to allocate memory for subdevice pointers\n");
@@ -2013,7 +2260,6 @@ static __init int vpif_probe(struct platform_device *pdev)
vpif_obj.sd[i] =
v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
i2c_adap,
- subdevdata->name,
&subdevdata->board_info,
NULL);
@@ -2027,9 +2273,9 @@ static __init int vpif_probe(struct platform_device *pdev)
if (vpif_obj.sd[i])
vpif_obj.sd[i]->grp_id = 1 << i;
}
- v4l2_info(&vpif_obj.v4l2_dev, "DM646x VPIF Capture driver"
- " initialized\n");
+ v4l2_info(&vpif_obj.v4l2_dev,
+ "DM646x VPIF capture driver initialized\n");
return 0;
probe_subdev_out:
@@ -2113,7 +2359,7 @@ static const struct dev_pm_ops vpif_dev_pm_ops = {
.resume = vpif_resume,
};
-static struct platform_driver vpif_driver = {
+static __refdata struct platform_driver vpif_driver = {
.driver = {
.name = "vpif_capture",
.owner = THIS_MODULE,
diff --git a/drivers/media/video/davinci/vpif_capture.h b/drivers/media/video/davinci/vpif_capture.h
index 4e12ec8cac6f..7a4196dfdce1 100644
--- a/drivers/media/video/davinci/vpif_capture.h
+++ b/drivers/media/video/davinci/vpif_capture.h
@@ -59,6 +59,8 @@ struct video_obj {
enum v4l2_field buf_field;
/* Currently selected or default standard */
v4l2_std_id stdid;
+ u32 dv_preset;
+ struct v4l2_bt_timings bt_timings;
/* This is to track the last input that is passed to application */
u32 input_idx;
};
diff --git a/drivers/media/video/davinci/vpif_display.c b/drivers/media/video/davinci/vpif_display.c
index da07607cbc55..cdf659abdc2a 100644
--- a/drivers/media/video/davinci/vpif_display.c
+++ b/drivers/media/video/davinci/vpif_display.c
@@ -38,6 +38,7 @@
#include <media/adv7343.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
#include <mach/dm646x.h>
@@ -84,17 +85,6 @@ static struct vpif_config_params config_params = {
static struct vpif_device vpif_obj = { {NULL} };
static struct device *vpif_dev;
-static const struct vpif_channel_config_params ch_params[] = {
- {
- "NTSC", 720, 480, 30, 0, 1, 268, 1440, 1, 23, 263, 266,
- 286, 525, 525, 0, 1, 0, V4L2_STD_525_60,
- },
- {
- "PAL", 720, 576, 25, 0, 1, 280, 1440, 1, 23, 311, 313,
- 336, 624, 625, 0, 1, 0, V4L2_STD_625_50,
- },
-};
-
/*
* vpif_uservirt_to_phys: This function is used to convert user
* space virtual address to physical address.
@@ -373,30 +363,54 @@ static irqreturn_t vpif_channel_isr(int irq, void *dev_id)
return IRQ_HANDLED;
}
-static int vpif_get_std_info(struct channel_obj *ch)
+static int vpif_update_std_info(struct channel_obj *ch)
{
- struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
struct video_obj *vid_ch = &ch->video;
struct vpif_params *vpifparams = &ch->vpifparams;
struct vpif_channel_config_params *std_info = &vpifparams->std_info;
const struct vpif_channel_config_params *config;
- int index;
-
- std_info->stdid = vid_ch->stdid;
- if (!std_info->stdid)
- return -1;
+ int i;
- for (index = 0; index < ARRAY_SIZE(ch_params); index++) {
- config = &ch_params[index];
- if (config->stdid & std_info->stdid) {
- memcpy(std_info, config, sizeof(*config));
- break;
+ for (i = 0; i < vpif_ch_params_count; i++) {
+ config = &ch_params[i];
+ if (config->hd_sd == 0) {
+ vpif_dbg(2, debug, "SD format\n");
+ if (config->stdid & vid_ch->stdid) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
+ } else {
+ vpif_dbg(2, debug, "HD format\n");
+ if (config->dv_preset == vid_ch->dv_preset) {
+ memcpy(std_info, config, sizeof(*config));
+ break;
+ }
}
}
- if (index == ARRAY_SIZE(ch_params))
- return -1;
+ if (i == vpif_ch_params_count) {
+ vpif_dbg(1, debug, "Format not found\n");
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vpif_update_resolution(struct channel_obj *ch)
+{
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+
+ if (!vid_ch->stdid && !vid_ch->dv_preset && !vid_ch->bt_timings.height)
+ return -EINVAL;
+
+ if (vid_ch->stdid || vid_ch->dv_preset) {
+ if (vpif_update_std_info(ch))
+ return -EINVAL;
+ }
common->fmt.fmt.pix.width = std_info->width;
common->fmt.fmt.pix.height = std_info->height;
@@ -404,8 +418,8 @@ static int vpif_get_std_info(struct channel_obj *ch)
common->fmt.fmt.pix.width, common->fmt.fmt.pix.height);
/* Set height and width paramateres */
- ch->common[VPIF_VIDEO_INDEX].height = std_info->height;
- ch->common[VPIF_VIDEO_INDEX].width = std_info->width;
+ common->height = std_info->height;
+ common->width = std_info->width;
return 0;
}
@@ -516,10 +530,8 @@ static int vpif_check_format(struct channel_obj *ch,
else
sizeimage = config_params.channel_bufsize[ch->channel_id];
- if (vpif_get_std_info(ch)) {
- vpif_err("Error getting the standard info\n");
+ if (vpif_update_resolution(ch))
return -EINVAL;
- }
hpitch = pixfmt->bytesperline;
vpitch = sizeimage / (hpitch * 2);
@@ -568,7 +580,10 @@ static void vpif_config_addr(struct channel_obj *ch, int muxmode)
static int vpif_mmap(struct file *filep, struct vm_area_struct *vma)
{
struct vpif_fh *fh = filep->private_data;
- struct common_obj *common = &fh->channel->common[VPIF_VIDEO_INDEX];
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &(ch->common[VPIF_VIDEO_INDEX]);
+
+ vpif_dbg(2, debug, "vpif_mmap\n");
return videobuf_mmap_mapper(&common->buffer_queue, vma);
}
@@ -600,7 +615,7 @@ static int vpif_open(struct file *filep)
ch = video_get_drvdata(vdev);
/* Allocate memory for the file handle object */
- fh = kmalloc(sizeof(struct vpif_fh), GFP_KERNEL);
+ fh = kzalloc(sizeof(struct vpif_fh), GFP_KERNEL);
if (fh == NULL) {
vpif_err("unable to allocate memory for file handle object\n");
return -ENOMEM;
@@ -637,9 +652,6 @@ static int vpif_release(struct file *filep)
struct channel_obj *ch = fh->channel;
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* if this instance is doing IO */
if (fh->io_allowed[VPIF_VIDEO_INDEX]) {
/* Reset io_usrs member of channel object */
@@ -662,8 +674,6 @@ static int vpif_release(struct file *filep)
config_params.numbuffers[ch->channel_id];
}
- mutex_unlock(&common->lock);
-
/* Decrement channel usrs counter */
atomic_dec(&ch->usrs);
/* If this file handle has initialize encoder device, reset it */
@@ -680,7 +690,12 @@ static int vpif_release(struct file *filep)
}
/* functions implementing ioctls */
-
+/**
+ * vpif_querycap() - QUERYCAP handler
+ * @file: file ptr
+ * @priv: file handle
+ * @cap: ptr to v4l2_capability structure
+ */
static int vpif_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
@@ -722,17 +737,9 @@ static int vpif_g_fmt_vid_out(struct file *file, void *priv,
if (common->fmt.type != fmt->type)
return -EINVAL;
- /* Fill in the information about format */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
- if (vpif_get_std_info(ch)) {
- vpif_err("Error getting the standard info\n");
+ if (vpif_update_resolution(ch))
return -EINVAL;
- }
-
*fmt = common->fmt;
- mutex_unlock(&common->lock);
return 0;
}
@@ -773,12 +780,7 @@ static int vpif_s_fmt_vid_out(struct file *file, void *priv,
/* store the pix format in the channel object */
common->fmt.fmt.pix = *pixfmt;
/* store the format in the channel object */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
common->fmt = *fmt;
- mutex_unlock(&common->lock);
-
return 0;
}
@@ -808,7 +810,6 @@ static int vpif_reqbufs(struct file *file, void *priv,
struct common_obj *common;
enum v4l2_field field;
u8 index = 0;
- int ret = 0;
/* This file handle has not initialized the channel,
It is not allowed to do settings */
@@ -826,18 +827,12 @@ static int vpif_reqbufs(struct file *file, void *priv,
index = VPIF_VIDEO_INDEX;
common = &ch->common[index];
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
- if (common->fmt.type != reqbuf->type) {
- ret = -EINVAL;
- goto reqbuf_exit;
- }
+ if (common->fmt.type != reqbuf->type)
+ return -EINVAL;
- if (0 != common->io_usrs) {
- ret = -EBUSY;
- goto reqbuf_exit;
- }
+ if (0 != common->io_usrs)
+ return -EBUSY;
if (reqbuf->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
if (common->fmt.fmt.pix.field == V4L2_FIELD_ANY)
@@ -853,7 +848,8 @@ static int vpif_reqbufs(struct file *file, void *priv,
&video_qops, NULL,
&common->irqlock,
reqbuf->type, field,
- sizeof(struct videobuf_buffer), fh);
+ sizeof(struct videobuf_buffer), fh,
+ &common->lock);
/* Set io allowed member of file handle to TRUE */
fh->io_allowed[index] = 1;
@@ -864,11 +860,7 @@ static int vpif_reqbufs(struct file *file, void *priv,
INIT_LIST_HEAD(&common->dma_queue);
/* Allocate buffers */
- ret = videobuf_reqbufs(&common->buffer_queue, reqbuf);
-
-reqbuf_exit:
- mutex_unlock(&common->lock);
- return ret;
+ return videobuf_reqbufs(&common->buffer_queue, reqbuf);
}
static int vpif_querybuf(struct file *file, void *priv,
@@ -935,9 +927,10 @@ static int vpif_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
goto qbuf_exit;
if ((VIDEOBUF_NEEDS_INIT != buf1->state)
- && (buf1->baddr != tbuf.m.userptr))
+ && (buf1->baddr != tbuf.m.userptr)) {
vpif_buffer_release(&common->buffer_queue, buf1);
buf1->baddr = tbuf.m.userptr;
+ }
break;
default:
@@ -988,22 +981,19 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
}
/* Call encoder subdevice function to set the standard */
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
ch->video.stdid = *std_id;
+ ch->video.dv_preset = V4L2_DV_INVALID;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
/* Get the information about the standard */
- if (vpif_get_std_info(ch)) {
- vpif_err("Error getting the standard info\n");
+ if (vpif_update_resolution(ch))
return -EINVAL;
- }
if ((ch->vpifparams.std_info.width *
ch->vpifparams.std_info.height * 2) >
config_params.channel_bufsize[ch->channel_id]) {
vpif_err("invalid std for this size\n");
- ret = -EINVAL;
- goto s_std_exit;
+ return -EINVAL;
}
common->fmt.fmt.pix.bytesperline = common->fmt.fmt.pix.width;
@@ -1014,16 +1004,13 @@ static int vpif_s_std(struct file *file, void *priv, v4l2_std_id *std_id)
s_std_output, *std_id);
if (ret < 0) {
vpif_err("Failed to set output standard\n");
- goto s_std_exit;
+ return ret;
}
ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, core,
s_std, *std_id);
if (ret < 0)
vpif_err("Failed to set standard for sub devices\n");
-
-s_std_exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1088,21 +1075,17 @@ static int vpif_streamon(struct file *file, void *priv,
if (ret < 0)
return ret;
- /* Call videobuf_streamon to start streaming in videobuf */
+ /* Call videobuf_streamon to start streaming in videobuf */
ret = videobuf_streamon(&common->buffer_queue);
if (ret < 0) {
vpif_err("videobuf_streamon\n");
return ret;
}
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
/* If buffer queue is empty, return error */
if (list_empty(&common->dma_queue)) {
vpif_err("buffer queue is empty\n");
- ret = -EIO;
- goto streamon_exit;
+ return -EIO;
}
/* Get the next frame from the buffer queue */
@@ -1128,8 +1111,7 @@ static int vpif_streamon(struct file *file, void *priv,
|| (!ch->vpifparams.std_info.frm_fmt
&& (common->fmt.fmt.pix.field == V4L2_FIELD_NONE))) {
vpif_err("conflict in field format and std format\n");
- ret = -EINVAL;
- goto streamon_exit;
+ return -EINVAL;
}
/* clock settings */
@@ -1138,13 +1120,13 @@ static int vpif_streamon(struct file *file, void *priv,
ch->vpifparams.std_info.hd_sd);
if (ret < 0) {
vpif_err("can't set clock\n");
- goto streamon_exit;
+ return ret;
}
/* set the parameters and addresses */
ret = vpif_set_video_params(vpif, ch->channel_id + 2);
if (ret < 0)
- goto streamon_exit;
+ return ret;
common->started = ret;
vpif_config_addr(ch, ret);
@@ -1169,9 +1151,6 @@ static int vpif_streamon(struct file *file, void *priv,
}
channel_first_int[VPIF_VIDEO_INDEX][ch->channel_id] = 1;
}
-
-streamon_exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1197,9 +1176,6 @@ static int vpif_streamoff(struct file *file, void *priv,
return -EINVAL;
}
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
if (buftype == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
/* disable channel */
if (VPIF_CHANNEL2_VIDEO == ch->channel_id) {
@@ -1214,8 +1190,6 @@ static int vpif_streamoff(struct file *file, void *priv,
}
common->started = 0;
- mutex_unlock(&common->lock);
-
return videobuf_streamoff(&common->buffer_queue);
}
@@ -1262,13 +1236,9 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i)
struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
int ret = 0;
- if (mutex_lock_interruptible(&common->lock))
- return -ERESTARTSYS;
-
if (common->started) {
vpif_err("Streaming in progress\n");
- ret = -EBUSY;
- goto s_output_exit;
+ return -EBUSY;
}
ret = v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 1, video,
@@ -1278,9 +1248,6 @@ static int vpif_s_output(struct file *file, void *priv, unsigned int i)
vpif_err("Failed to set output standard\n");
vid_ch->output_id = i;
-
-s_output_exit:
- mutex_unlock(&common->lock);
return ret;
}
@@ -1313,6 +1280,287 @@ static int vpif_s_priority(struct file *file, void *priv, enum v4l2_priority p)
return v4l2_prio_change(&ch->prio, &fh->prio, p);
}
+/**
+ * vpif_enum_dv_presets() - ENUM_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_enum_dv_presets(struct file *file, void *priv,
+ struct v4l2_dv_enum_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, enum_dv_presets, preset);
+}
+
+/**
+ * vpif_s_dv_presets() - S_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_s_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct common_obj *common = &ch->common[VPIF_VIDEO_INDEX];
+ struct video_obj *vid_ch = &ch->video;
+ int ret = 0;
+
+ if (common->started) {
+ vpif_dbg(1, debug, "streaming in progress\n");
+ return -EBUSY;
+ }
+
+ ret = v4l2_prio_check(&ch->prio, fh->prio);
+ if (ret != 0)
+ return ret;
+
+ fh->initialized = 1;
+
+ /* Call encoder subdevice function to set the standard */
+ if (mutex_lock_interruptible(&common->lock))
+ return -ERESTARTSYS;
+
+ ch->video.dv_preset = preset->preset;
+ ch->video.stdid = V4L2_STD_UNKNOWN;
+ memset(&ch->video.bt_timings, 0, sizeof(ch->video.bt_timings));
+
+ /* Get the information about the standard */
+ if (vpif_update_resolution(ch)) {
+ ret = -EINVAL;
+ } else {
+ /* Configure the default format information */
+ vpif_config_format(ch);
+
+ ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, s_dv_preset, preset);
+ }
+
+ mutex_unlock(&common->lock);
+
+ return ret;
+}
+/**
+ * vpif_g_dv_presets() - G_DV_PRESETS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @preset: input preset
+ */
+static int vpif_g_dv_preset(struct file *file, void *priv,
+ struct v4l2_dv_preset *preset)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+
+ preset->preset = ch->video.dv_preset;
+
+ return 0;
+}
+/**
+ * vpif_s_dv_timings() - S_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_s_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct vpif_params *vpifparams = &ch->vpifparams;
+ struct vpif_channel_config_params *std_info = &vpifparams->std_info;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+ int ret;
+
+ if (timings->type != V4L2_DV_BT_656_1120) {
+ vpif_dbg(2, debug, "Timing type not defined\n");
+ return -EINVAL;
+ }
+
+ /* Configure subdevice timings, if any */
+ ret = v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id],
+ video, s_dv_timings, timings);
+ if (ret == -ENOIOCTLCMD) {
+ vpif_dbg(2, debug, "Custom DV timings not supported by "
+ "subdevice\n");
+ return -EINVAL;
+ }
+ if (ret < 0) {
+ vpif_dbg(2, debug, "Error setting custom DV timings\n");
+ return ret;
+ }
+
+ if (!(timings->bt.width && timings->bt.height &&
+ (timings->bt.hbackporch ||
+ timings->bt.hfrontporch ||
+ timings->bt.hsync) &&
+ timings->bt.vfrontporch &&
+ (timings->bt.vbackporch ||
+ timings->bt.vsync))) {
+ vpif_dbg(2, debug, "Timings for width, height, "
+ "horizontal back porch, horizontal sync, "
+ "horizontal front porch, vertical back porch, "
+ "vertical sync and vertical back porch "
+ "must be defined\n");
+ return -EINVAL;
+ }
+
+ *bt = timings->bt;
+
+ /* Configure video port timings */
+
+ std_info->eav2sav = bt->hbackporch + bt->hfrontporch +
+ bt->hsync - 8;
+ std_info->sav2eav = bt->width;
+
+ std_info->l1 = 1;
+ std_info->l3 = bt->vsync + bt->vbackporch + 1;
+
+ if (bt->interlaced) {
+ if (bt->il_vbackporch || bt->il_vfrontporch || bt->il_vsync) {
+ std_info->vsize = bt->height * 2 +
+ bt->vfrontporch + bt->vsync + bt->vbackporch +
+ bt->il_vfrontporch + bt->il_vsync +
+ bt->il_vbackporch;
+ std_info->l5 = std_info->vsize/2 -
+ (bt->vfrontporch - 1);
+ std_info->l7 = std_info->vsize/2 + 1;
+ std_info->l9 = std_info->l7 + bt->il_vsync +
+ bt->il_vbackporch + 1;
+ std_info->l11 = std_info->vsize -
+ (bt->il_vfrontporch - 1);
+ } else {
+ vpif_dbg(2, debug, "Required timing values for "
+ "interlaced BT format missing\n");
+ return -EINVAL;
+ }
+ } else {
+ std_info->vsize = bt->height + bt->vfrontporch +
+ bt->vsync + bt->vbackporch;
+ std_info->l5 = std_info->vsize - (bt->vfrontporch - 1);
+ }
+ strncpy(std_info->name, "Custom timings BT656/1120",
+ VPIF_MAX_NAME);
+ std_info->width = bt->width;
+ std_info->height = bt->height;
+ std_info->frm_fmt = bt->interlaced ? 0 : 1;
+ std_info->ycmux_mode = 0;
+ std_info->capture_format = 0;
+ std_info->vbi_supported = 0;
+ std_info->hd_sd = 1;
+ std_info->stdid = 0;
+ std_info->dv_preset = V4L2_DV_INVALID;
+
+ vid_ch->stdid = 0;
+ vid_ch->dv_preset = V4L2_DV_INVALID;
+
+ return 0;
+}
+
+/**
+ * vpif_g_dv_timings() - G_DV_TIMINGS handler
+ * @file: file ptr
+ * @priv: file handle
+ * @timings: digital video timings
+ */
+static int vpif_g_dv_timings(struct file *file, void *priv,
+ struct v4l2_dv_timings *timings)
+{
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+ struct v4l2_bt_timings *bt = &vid_ch->bt_timings;
+
+ timings->bt = *bt;
+
+ return 0;
+}
+
+/*
+ * vpif_g_chip_ident() - Identify the chip
+ * @file: file ptr
+ * @priv: file handle
+ * @chip: chip identity
+ *
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ chip->ident = V4L2_IDENT_NONE;
+ chip->revision = 0;
+ if (chip->match.type != V4L2_CHIP_MATCH_I2C_DRIVER &&
+ chip->match.type != V4L2_CHIP_MATCH_I2C_ADDR) {
+ vpif_dbg(2, debug, "match_type is invalid.\n");
+ return -EINVAL;
+ }
+
+ return v4l2_device_call_until_err(&vpif_obj.v4l2_dev, 0, core,
+ g_chip_ident, chip);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+/*
+ * vpif_dbg_g_register() - Read register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be read
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if read operations fails.
+ */
+static int vpif_dbg_g_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+ g_register, reg);
+}
+
+/*
+ * vpif_dbg_s_register() - Write to register
+ * @file: file ptr
+ * @priv: file handle
+ * @reg: register to be modified
+ *
+ * Debugging only
+ * Returns zero or -EINVAL if write operations fails.
+ */
+static int vpif_dbg_s_register(struct file *file, void *priv,
+ struct v4l2_dbg_register *reg){
+ struct vpif_fh *fh = priv;
+ struct channel_obj *ch = fh->channel;
+ struct video_obj *vid_ch = &ch->video;
+
+ return v4l2_subdev_call(vpif_obj.sd[vid_ch->output_id], core,
+ s_register, reg);
+}
+#endif
+
+/*
+ * vpif_log_status() - Status information
+ * @file: file ptr
+ * @priv: file handle
+ *
+ * Returns zero.
+ */
+static int vpif_log_status(struct file *filep, void *priv)
+{
+ /* status for sub devices */
+ v4l2_device_call_all(&vpif_obj.v4l2_dev, 0, core, log_status);
+
+ return 0;
+}
+
/* vpif display ioctl operations */
static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_querycap = vpif_querycap,
@@ -1334,13 +1582,24 @@ static const struct v4l2_ioctl_ops vpif_ioctl_ops = {
.vidioc_s_output = vpif_s_output,
.vidioc_g_output = vpif_g_output,
.vidioc_cropcap = vpif_cropcap,
+ .vidioc_enum_dv_presets = vpif_enum_dv_presets,
+ .vidioc_s_dv_preset = vpif_s_dv_preset,
+ .vidioc_g_dv_preset = vpif_g_dv_preset,
+ .vidioc_s_dv_timings = vpif_s_dv_timings,
+ .vidioc_g_dv_timings = vpif_g_dv_timings,
+ .vidioc_g_chip_ident = vpif_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = vpif_dbg_g_register,
+ .vidioc_s_register = vpif_dbg_s_register,
+#endif
+ .vidioc_log_status = vpif_log_status,
};
static const struct v4l2_file_operations vpif_fops = {
.owner = THIS_MODULE,
.open = vpif_open,
.release = vpif_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = vpif_mmap,
.poll = vpif_poll
};
@@ -1395,7 +1654,7 @@ static int initialize_vpif(void)
/* Allocate memory for six channel objects */
for (i = 0; i < VPIF_DISPLAY_MAX_DEVICES; i++) {
vpif_obj.dev[i] =
- kmalloc(sizeof(struct channel_obj), GFP_KERNEL);
+ kzalloc(sizeof(struct channel_obj), GFP_KERNEL);
/* If memory allocation fails, return error */
if (!vpif_obj.dev[i]) {
free_channel_objects_index = i;
@@ -1524,6 +1783,7 @@ static __init int vpif_probe(struct platform_device *pdev)
v4l2_prio_init(&ch->prio);
ch->common[VPIF_VIDEO_INDEX].fmt.type =
V4L2_BUF_TYPE_VIDEO_OUTPUT;
+ ch->video_dev->lock = &common->lock;
/* register video device */
vpif_dbg(1, debug, "channel=%x,channel->video_dev=%x\n",
@@ -1541,7 +1801,7 @@ static __init int vpif_probe(struct platform_device *pdev)
config = pdev->dev.platform_data;
subdev_count = config->subdev_count;
subdevdata = config->subdevinfo;
- vpif_obj.sd = kmalloc(sizeof(struct v4l2_subdev *) * subdev_count,
+ vpif_obj.sd = kzalloc(sizeof(struct v4l2_subdev *) * subdev_count,
GFP_KERNEL);
if (vpif_obj.sd == NULL) {
vpif_err("unable to allocate memory for subdevice pointers\n");
@@ -1551,7 +1811,7 @@ static __init int vpif_probe(struct platform_device *pdev)
for (i = 0; i < subdev_count; i++) {
vpif_obj.sd[i] = v4l2_i2c_new_subdev_board(&vpif_obj.v4l2_dev,
- i2c_adap, subdevdata[i].name,
+ i2c_adap,
&subdevdata[i].board_info,
NULL);
if (!vpif_obj.sd[i]) {
@@ -1563,6 +1823,8 @@ static __init int vpif_probe(struct platform_device *pdev)
vpif_obj.sd[i]->grp_id = 1 << i;
}
+ v4l2_info(&vpif_obj.v4l2_dev,
+ "DM646x VPIF display driver initialized\n");
return 0;
probe_subdev_out:
@@ -1610,7 +1872,7 @@ static int vpif_remove(struct platform_device *device)
return 0;
}
-static struct platform_driver vpif_driver = {
+static __refdata struct platform_driver vpif_driver = {
.driver = {
.name = "vpif_display",
.owner = THIS_MODULE,
diff --git a/drivers/media/video/davinci/vpif_display.h b/drivers/media/video/davinci/vpif_display.h
index a2a7cd166bbf..b53aaa883075 100644
--- a/drivers/media/video/davinci/vpif_display.h
+++ b/drivers/media/video/davinci/vpif_display.h
@@ -67,6 +67,8 @@ struct video_obj {
* most recent displayed frame only */
v4l2_std_id stdid; /* Currently selected or default
* standard */
+ u32 dv_preset;
+ struct v4l2_bt_timings bt_timings;
u32 output_id; /* Current output id */
};
diff --git a/drivers/media/video/davinci/vpss.c b/drivers/media/video/davinci/vpss.c
index 7918680917d0..3e5cf27ec2b2 100644
--- a/drivers/media/video/davinci/vpss.c
+++ b/drivers/media/video/davinci/vpss.c
@@ -85,7 +85,7 @@ enum vpss_platform_type {
/*
* vpss operations. Depends on platform. Not all functions are available
* on all platforms. The api, first check if a functio is available before
- * invoking it. In the probe, the function ptrs are intialized based on
+ * invoking it. In the probe, the function ptrs are initialized based on
* vpss name. vpss name can be "dm355_vpss", "dm644x_vpss" etc.
*/
struct vpss_hw_ops {
diff --git a/drivers/media/video/em28xx/Kconfig b/drivers/media/video/em28xx/Kconfig
index c7be0e097828..985100ea17a4 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,9 +1,9 @@
config VIDEO_EM28XX
tristate "Empia EM28xx USB video capture support"
- depends on VIDEO_DEV && I2C && INPUT
+ depends on VIDEO_DEV && I2C
select VIDEO_TUNER
select VIDEO_TVEEPROM
- select VIDEO_IR
+ depends on RC_CORE
select VIDEOBUF_VMALLOC
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
@@ -37,6 +37,7 @@ config VIDEO_EM28XX_DVB
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
select DVB_TDA10023 if !DVB_FE_CUSTOMISE
+ select DVB_S921 if !DVB_FE_CUSTOMISE
select VIDEOBUF_DVB
---help---
This adds support for DVB cards based on the
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index e182abf476c9..3c48a72eb7de 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -102,6 +102,9 @@ static void em28xx_audio_isocirq(struct urb *urb)
break;
}
+ if (atomic_read(&dev->stream_started) == 0)
+ return;
+
if (dev->adev.capture_pcm_substream) {
substream = dev->adev.capture_pcm_substream;
runtime = substream->runtime;
@@ -217,31 +220,6 @@ static int em28xx_init_audio_isoc(struct em28xx *dev)
return 0;
}
-static int em28xx_cmd(struct em28xx *dev, int cmd, int arg)
-{
- 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 == EM28XX_START_AUDIO) {
- dev->adev.capture_stream = STREAM_ON;
- em28xx_init_audio_isoc(dev);
- } else if (dev->adev.capture_stream == STREAM_ON &&
- arg == EM28XX_STOP_AUDIO) {
- dev->adev.capture_stream = STREAM_OFF;
- em28xx_deinit_isoc_audio(dev);
- } else {
- em28xx_errdev("An underrun very likely occurred. "
- "Ignoring it.\n");
- }
- return 0;
- default:
- return -EINVAL;
- }
-}
-
static int snd_pcm_alloc_vmalloc_buffer(struct snd_pcm_substream *subs,
size_t size)
{
@@ -303,7 +281,6 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
dev->mute = 0;
mutex_lock(&dev->lock);
ret = em28xx_audio_analog_set(dev);
- mutex_unlock(&dev->lock);
if (ret < 0)
goto err;
@@ -311,11 +288,10 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
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");
+ errCode = usb_set_interface(dev->udev, 0, 7);
}
- mutex_lock(&dev->lock);
dev->adev.users++;
mutex_unlock(&dev->lock);
@@ -325,6 +301,8 @@ static int snd_em28xx_capture_open(struct snd_pcm_substream *substream)
return 0;
err:
+ mutex_unlock(&dev->lock);
+
em28xx_err("Error while configuring em28xx mixer\n");
return ret;
}
@@ -338,6 +316,11 @@ static int snd_em28xx_pcm_close(struct snd_pcm_substream *substream)
dev->mute = 1;
mutex_lock(&dev->lock);
dev->adev.users--;
+ if (atomic_read(&dev->stream_started) > 0) {
+ atomic_set(&dev->stream_started, 0);
+ schedule_work(&dev->wq_trigger);
+ }
+
em28xx_audio_analog_set(dev);
if (substream->runtime->dma_area) {
dprintk("freeing\n");
@@ -375,8 +358,10 @@ 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)
- em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_STOP_AUDIO);
+ if (atomic_read(&dev->stream_started) > 0) {
+ atomic_set(&dev->stream_started, 0);
+ schedule_work(&dev->wq_trigger);
+ }
return 0;
}
@@ -391,31 +376,37 @@ static int snd_em28xx_prepare(struct snd_pcm_substream *substream)
return 0;
}
+static void audio_trigger(struct work_struct *work)
+{
+ struct em28xx *dev = container_of(work, struct em28xx, wq_trigger);
+
+ if (atomic_read(&dev->stream_started)) {
+ dprintk("starting capture");
+ em28xx_init_audio_isoc(dev);
+ } else {
+ dprintk("stopping capture");
+ em28xx_deinit_isoc_audio(dev);
+ }
+}
+
static int snd_em28xx_capture_trigger(struct snd_pcm_substream *substream,
int cmd)
{
struct em28xx *dev = snd_pcm_substream_chip(substream);
int retval;
- dprintk("Should %s capture\n", (cmd == SNDRV_PCM_TRIGGER_START) ?
- "start" : "stop");
-
- spin_lock(&dev->adev.slock);
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_START_AUDIO);
- retval = 0;
+ atomic_set(&dev->stream_started, 1);
break;
case SNDRV_PCM_TRIGGER_STOP:
- em28xx_cmd(dev, EM28XX_CAPTURE_STREAM_EN, EM28XX_STOP_AUDIO);
- retval = 0;
+ atomic_set(&dev->stream_started, 1);
break;
default:
retval = -EINVAL;
}
-
- spin_unlock(&dev->adev.slock);
- return retval;
+ schedule_work(&dev->wq_trigger);
+ return 0;
}
static snd_pcm_uframes_t snd_em28xx_capture_pointer(struct snd_pcm_substream
@@ -495,6 +486,8 @@ static int em28xx_audio_init(struct em28xx *dev)
strcpy(card->shortname, "Em28xx Audio");
strcpy(card->longname, "Empia Em28xx Audio");
+ INIT_WORK(&dev->wq_trigger, audio_trigger);
+
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index 3a4fd8514511..87f77a34eeab 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -33,6 +33,7 @@
#include <media/saa7115.h>
#include <media/tvp5150.h>
#include <media/tvaudio.h>
+#include <media/mt9v011.h>
#include <media/i2c-addr.h>
#include <media/tveeprom.h>
#include <media/v4l2-common.h>
@@ -158,6 +159,22 @@ static struct em28xx_reg_seq evga_indtube_digital[] = {
{ -1, -1, -1, -1},
};
+/*
+ * KWorld PlusTV 340U and UB435-Q (ATSC) GPIOs map:
+ * EM_GPIO_0 - currently unknown
+ * EM_GPIO_1 - LED disable/enable (1 = off, 0 = on)
+ * EM_GPIO_2 - currently unknown
+ * EM_GPIO_3 - currently unknown
+ * EM_GPIO_4 - TDA18271HD/C1 tuner (1 = active, 0 = in reset)
+ * EM_GPIO_5 - LGDT3304 ATSC/QAM demod (1 = active, 0 = in reset)
+ * EM_GPIO_6 - currently unknown
+ * EM_GPIO_7 - currently unknown
+ */
+static struct em28xx_reg_seq kworld_a340_digital[] = {
+ {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
/* Pinnacle Hybrid Pro eb1a:2881 */
static struct em28xx_reg_seq pinnacle_hybrid_pro_analog[] = {
{EM28XX_R08_GPIO, 0xfd, ~EM_GPIO_4, 10},
@@ -171,6 +188,18 @@ static struct em28xx_reg_seq pinnacle_hybrid_pro_digital[] = {
{ -1, -1, -1, -1},
};
+static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_analog[] = {
+ {EM28XX_R08_GPIO, 0x6d, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x00, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq terratec_cinergy_USB_XS_FR_digital[] = {
+ {EM28XX_R08_GPIO, 0x6e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x08, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
/* eb1a:2868 Reddo DVB-C USB TV Box
GPIO4 - CU1216L NIM
Other GPIOs seems to be don't care. */
@@ -240,6 +269,20 @@ static struct em28xx_reg_seq dikom_dk300_digital[] = {
};
+/* Reset for the most [digital] boards */
+static struct em28xx_reg_seq leadership_digital[] = {
+ {EM2874_R80_GPIO, 0x70, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
+static struct em28xx_reg_seq leadership_reset[] = {
+ {EM2874_R80_GPIO, 0xf0, 0xff, 10},
+ {EM2874_R80_GPIO, 0xb0, 0xff, 10},
+ {EM2874_R80_GPIO, 0xf0, 0xff, 10},
+ { -1, -1, -1, -1},
+};
+
+
/*
* Board definitions
*/
@@ -765,22 +808,22 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = default_tuner_gpio,
.decoder = EM28XX_TVP5150,
.has_dvb = 1,
- .dvb_gpio = default_digital,
+ .dvb_gpio = terratec_cinergy_USB_XS_FR_digital,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
.vmux = TVP5150_COMPOSITE0,
.amux = EM28XX_AMUX_VIDEO,
- .gpio = default_analog,
+ .gpio = terratec_cinergy_USB_XS_FR_analog,
}, {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = TVP5150_COMPOSITE1,
.amux = EM28XX_AMUX_LINE_IN,
- .gpio = default_analog,
+ .gpio = terratec_cinergy_USB_XS_FR_analog,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = TVP5150_SVIDEO,
.amux = EM28XX_AMUX_LINE_IN,
- .gpio = default_analog,
+ .gpio = terratec_cinergy_USB_XS_FR_analog,
} },
},
[EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900] = {
@@ -1196,6 +1239,19 @@ struct em28xx_board em28xx_boards[] = {
.vmux = SAA7115_COMPOSITE0,
} },
},
+
+ [EM2874_LEADERSHIP_ISDBT] = {
+ .i2c_speed = EM2874_I2C_SECONDARY_BUS_SELECT |
+ EM28XX_I2C_CLK_WAIT_ENABLE |
+ EM28XX_I2C_FREQ_100_KHZ,
+ .xclk = EM28XX_XCLK_FREQUENCY_10MHZ,
+ .name = "EM2874 Leadership ISDBT",
+ .tuner_type = TUNER_ABSENT,
+ .tuner_gpio = leadership_reset,
+ .dvb_gpio = leadership_digital,
+ .has_dvb = 1,
+ },
+
[EM2880_BOARD_MSI_DIGIVOX_AD] = {
.name = "MSI DigiVox A/D",
.valid = EM28XX_BOARD_NOT_VALIDATED,
@@ -1441,7 +1497,7 @@ struct em28xx_board em28xx_boards[] = {
} },
},
[EM2882_BOARD_TERRATEC_HYBRID_XS] = {
- .name = "Terratec Hybrid XS (em2882)",
+ .name = "Terratec Cinnergy Hybrid T USB XS (em2882)",
.tuner_type = TUNER_XC2028,
.tuner_gpio = default_tuner_gpio,
.mts_firmware = 1,
@@ -1605,11 +1661,11 @@ struct em28xx_board em28xx_boards[] = {
.input = { {
.type = EM28XX_VMUX_COMPOSITE1,
.vmux = SAA7115_COMPOSITE0,
- .amux = EM28XX_AMUX_VIDEO2,
+ .amux = EM28XX_AMUX_LINE_IN,
}, {
.type = EM28XX_VMUX_SVIDEO,
.vmux = SAA7115_SVIDEO3,
- .amux = EM28XX_AMUX_VIDEO2,
+ .amux = EM28XX_AMUX_LINE_IN,
} },
},
[EM2860_BOARD_TERRATEC_AV350] = {
@@ -1632,6 +1688,22 @@ struct em28xx_board em28xx_boards[] = {
.gpio = terratec_av350_unmute_gpio,
} },
},
+
+ [EM2860_BOARD_ELGATO_VIDEO_CAPTURE] = {
+ .name = "Elgato Video Capture",
+ .decoder = EM28XX_SAA711X,
+ .tuner_type = TUNER_ABSENT, /* Capture only device */
+ .input = { {
+ .type = EM28XX_VMUX_COMPOSITE1,
+ .vmux = SAA7115_COMPOSITE0,
+ .amux = EM28XX_AMUX_LINE_IN,
+ }, {
+ .type = EM28XX_VMUX_SVIDEO,
+ .vmux = SAA7115_SVIDEO3,
+ .amux = EM28XX_AMUX_LINE_IN,
+ } },
+ },
+
[EM2882_BOARD_EVGA_INDTUBE] = {
.name = "Evga inDtube",
.tuner_type = TUNER_XC2028,
@@ -1667,6 +1739,16 @@ struct em28xx_board em28xx_boards[] = {
.tuner_gpio = reddo_dvb_c_usb_box,
.has_dvb = 1,
},
+ /* 1b80:a340 - Empia EM2870, NXP TDA18271HD and LG DT3304, sold
+ * initially as the KWorld PlusTV 340U, then as the UB435-Q.
+ * Early variants have a TDA18271HD/C1, later ones a TDA18271HD/C2 */
+ [EM2870_BOARD_KWORLD_A340] = {
+ .name = "KWorld PlusTV 340U or UB435-Q (ATSC)",
+ .tuner_type = TUNER_ABSENT, /* Digital-only TDA18271HD */
+ .has_dvb = 1,
+ .dvb_gpio = kworld_a340_digital,
+ .tuner_gpio = default_tuner_gpio,
+ },
};
const unsigned int em28xx_bcount = ARRAY_SIZE(em28xx_boards);
@@ -1700,6 +1782,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0x2868),
.driver_info = EM2820_BOARD_UNKNOWN },
+ { USB_DEVICE(0xeb1a, 0x2875),
+ .driver_info = EM2820_BOARD_UNKNOWN },
{ USB_DEVICE(0xeb1a, 0xe300),
.driver_info = EM2861_BOARD_KWORLD_PVRTV_300U },
{ USB_DEVICE(0xeb1a, 0xe303),
@@ -1737,7 +1821,7 @@ struct usb_device_id em28xx_id_table[] = {
{ USB_DEVICE(0x0ccd, 0x005e),
.driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
{ USB_DEVICE(0x0ccd, 0x0042),
- .driver_info = EM2880_BOARD_TERRATEC_HYBRID_XS },
+ .driver_info = EM2882_BOARD_TERRATEC_HYBRID_XS },
{ USB_DEVICE(0x0ccd, 0x0043),
.driver_info = EM2870_BOARD_TERRATEC_XS },
{ USB_DEVICE(0x0ccd, 0x0047),
@@ -1746,6 +1830,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2860_BOARD_TERRATEC_AV350 },
{ USB_DEVICE(0x0ccd, 0x0096),
.driver_info = EM2860_BOARD_TERRATEC_GRABBY },
+ { USB_DEVICE(0x0fd9, 0x0033),
+ .driver_info = EM2860_BOARD_ELGATO_VIDEO_CAPTURE},
{ USB_DEVICE(0x185b, 0x2870),
.driver_info = EM2870_BOARD_COMPRO_VIDEOMATE },
{ USB_DEVICE(0x185b, 0x2041),
@@ -1788,6 +1874,8 @@ struct usb_device_id em28xx_id_table[] = {
.driver_info = EM2820_BOARD_IODATA_GVMVP_SZ },
{ USB_DEVICE(0xeb1a, 0x50a6),
.driver_info = EM2860_BOARD_GADMEI_UTV330 },
+ { USB_DEVICE(0x1b80, 0xa340),
+ .driver_info = EM2870_BOARD_KWORLD_A340 },
{ },
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
@@ -1815,6 +1903,7 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0x77800080, EM2860_BOARD_TVP5150_REFERENCE_DESIGN, TUNER_ABSENT},
{0xc51200e3, EM2820_BOARD_GADMEI_TVR200, TUNER_LG_PAL_NEW_TAPC},
{0x4ba50080, EM2861_BOARD_GADMEI_UTV330PLUS, TUNER_TNF_5335MF},
+ {0x6b800080, EM2874_LEADERSHIP_ISDBT, TUNER_ABSENT},
};
/* I2C possible address to saa7115, tvp5150, msp3400, tvaudio */
@@ -1829,11 +1918,6 @@ static unsigned short tvp5150_addrs[] = {
I2C_CLIENT_END
};
-static unsigned short mt9v011_addrs[] = {
- 0xba >> 1,
- I2C_CLIENT_END
-};
-
static unsigned short msp3400_addrs[] = {
0x80 >> 1,
0x88 >> 1,
@@ -2140,6 +2224,7 @@ static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
ctl->demod = XC3028_FE_ZARLINK456;
break;
case EM2880_BOARD_TERRATEC_HYBRID_XS:
+ case EM2880_BOARD_TERRATEC_HYBRID_XS_FR:
case EM2881_BOARD_PINNACLE_HYBRID_PRO:
ctl->demod = XC3028_FE_ZARLINK456;
break;
@@ -2348,8 +2433,9 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
dev->init_data.ir_codes = RC_MAP_RC5_HAUPPAUGE_NEW;
dev->init_data.get_key = em28xx_get_key_em_haup;
dev->init_data.name = "i2c IR (EM2840 Hauppauge)";
+ break;
case EM2820_BOARD_LEADTEK_WINFAST_USBII_DELUXE:
- dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;;
+ dev->init_data.ir_codes = RC_MAP_WINFAST_USBII_DELUXE;
dev->init_data.get_key = em28xx_get_key_winfast_usbii_deluxe;
dev->init_data.name = "i2c IR (EM2820 Winfast TV USBII Deluxe)";
break;
@@ -2357,7 +2443,7 @@ void em28xx_register_i2c_ir(struct em28xx *dev)
if (dev->init_data.name)
info.platform_data = &dev->init_data;
- i2c_new_probed_device(&dev->i2c_adap, &info, addr_list);
+ i2c_new_probed_device(&dev->i2c_adap, &info, addr_list, NULL);
}
void em28xx_card_setup(struct em28xx *dev)
@@ -2371,8 +2457,36 @@ void em28xx_card_setup(struct em28xx *dev)
dev->board.is_webcam = 0;
else
dev->progressive = 1;
- } else
- em28xx_set_model(dev);
+ }
+
+ if (!dev->board.is_webcam) {
+ switch (dev->model) {
+ case EM2820_BOARD_UNKNOWN:
+ case EM2800_BOARD_UNKNOWN:
+ /*
+ * The K-WORLD DVB-T 310U is detected as an MSI Digivox AD.
+ *
+ * This occurs because they share identical USB vendor and
+ * product IDs.
+ *
+ * What we do here is look up the EEPROM hash of the K-WORLD
+ * and if it is found then we decide that we do not have
+ * a DIGIVOX and reset the device to the K-WORLD instead.
+ *
+ * This solution is only valid if they do not share eeprom
+ * hash identities which has not been determined as yet.
+ */
+ if (em28xx_hint_board(dev) < 0)
+ em28xx_errdev("Board not discovered\n");
+ else {
+ em28xx_set_model(dev);
+ em28xx_pre_card_setup(dev);
+ }
+ break;
+ default:
+ em28xx_set_model(dev);
+ }
+ }
em28xx_info("Identified as %s (card=%d)\n",
dev->board.name, dev->model);
@@ -2495,39 +2609,45 @@ void em28xx_card_setup(struct em28xx *dev)
/* request some modules */
if (dev->board.has_msp34xx)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "msp3400", "msp3400", 0, msp3400_addrs);
+ "msp3400", 0, msp3400_addrs);
if (dev->board.decoder == EM28XX_SAA711X)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "saa7115", "saa7115_auto", 0, saa711x_addrs);
+ "saa7115_auto", 0, saa711x_addrs);
if (dev->board.decoder == EM28XX_TVP5150)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvp5150", "tvp5150", 0, tvp5150_addrs);
+ "tvp5150", 0, tvp5150_addrs);
if (dev->em28xx_sensor == EM28XX_MT9V011) {
+ struct mt9v011_platform_data pdata;
+ struct i2c_board_info mt9v011_info = {
+ .type = "mt9v011",
+ .addr = 0xba >> 1,
+ .platform_data = &pdata,
+ };
struct v4l2_subdev *sd;
- sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "mt9v011", "mt9v011", 0, mt9v011_addrs);
- v4l2_subdev_call(sd, core, s_config, 0, &dev->sensor_xtal);
+ pdata.xtal = dev->sensor_xtal;
+ sd = v4l2_i2c_new_subdev_board(&dev->v4l2_dev, &dev->i2c_adap,
+ &mt9v011_info, NULL);
}
if (dev->board.adecoder == EM28XX_TVAUDIO)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tvaudio", "tvaudio", dev->board.tvaudio_addr, NULL);
+ "tvaudio", dev->board.tvaudio_addr, NULL);
if (dev->board.tuner_type != TUNER_ABSENT) {
int has_demod = (dev->tda9887_conf & TDA9887_PRESENT);
if (dev->board.radio.type)
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->board.radio_addr, NULL);
+ "tuner", dev->board.radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == 0) {
enum v4l2_i2c_tuner_type type =
@@ -2535,14 +2655,14 @@ void em28xx_card_setup(struct em28xx *dev)
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(type));
if (sd)
dev->tuner_addr = v4l2_i2c_subdev_addr(sd);
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "tuner", "tuner", dev->tuner_addr, NULL);
+ "tuner", dev->tuner_addr, NULL);
}
}
@@ -2573,8 +2693,14 @@ static void request_modules(struct em28xx *dev)
INIT_WORK(&dev->request_module_wk, request_module_async);
schedule_work(&dev->request_module_wk);
}
+
+static void flush_request_modules(struct em28xx *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
#else
#define request_modules(dev)
+#define flush_request_modules(dev)
#endif /* CONFIG_MODULES */
/*
@@ -2690,8 +2816,8 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
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);
+ /* Resets I2C speed */
+ em28xx_write_reg(dev, EM28XX_R06_I2C_CLK, dev->board.i2c_speed);
if (retval < 0) {
em28xx_errdev("%s: em28xx_write_regs_req failed!"
" retval [%d]\n",
@@ -3001,6 +3127,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_info("disconnecting %s\n", dev->vdev->name);
+ flush_request_modules(dev);
+
/* wait until all current v4l2 io is finished then deallocate
resources */
mutex_lock(&dev->lock);
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index 331e1cac4272..44c63cbd6dda 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -1186,8 +1186,7 @@ int em28xx_register_extension(struct em28xx_ops *ops)
mutex_lock(&em28xx_devlist_mutex);
list_add_tail(&ops->next, &em28xx_extension_devlist);
list_for_each_entry(dev, &em28xx_devlist, devlist) {
- if (dev)
- ops->init(dev);
+ ops->init(dev);
}
printk(KERN_INFO "Em28xx: Initialized (%s) extension\n", ops->name);
mutex_unlock(&em28xx_devlist_mutex);
@@ -1201,10 +1200,8 @@ void em28xx_unregister_extension(struct em28xx_ops *ops)
mutex_lock(&em28xx_devlist_mutex);
list_for_each_entry(dev, &em28xx_devlist, devlist) {
- if (dev)
- ops->fini(dev);
+ ops->fini(dev);
}
-
printk(KERN_INFO "Em28xx: Removed (%s) extension\n", ops->name);
list_del(&ops->next);
mutex_unlock(&em28xx_devlist_mutex);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
index cf1d8c3655fc..c7c04bf712aa 100644
--- a/drivers/media/video/em28xx/em28xx-dvb.c
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -30,11 +30,14 @@
#include "tuner-simple.h"
#include "lgdt330x.h"
+#include "lgdt3305.h"
#include "zl10353.h"
#include "s5h1409.h"
#include "mt352.h"
#include "mt352_priv.h" /* FIXME */
#include "tda1002x.h"
+#include "tda18271.h"
+#include "s921.h"
MODULE_DESCRIPTION("driver for em28xx based DVB cards");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
@@ -231,6 +234,22 @@ static struct lgdt330x_config em2880_lgdt3303_dev = {
.demod_chip = LGDT3303,
};
+static struct lgdt3305_config em2870_lgdt3304_dev = {
+ .i2c_addr = 0x0e,
+ .demod_chip = LGDT3304,
+ .spectral_inversion = 1,
+ .deny_i2c_rptr = 1,
+ .mpeg_mode = LGDT3305_MPEG_PARALLEL,
+ .tpclk_edge = LGDT3305_TPCLK_FALLING_EDGE,
+ .tpvalid_polarity = LGDT3305_TP_VALID_HIGH,
+ .vsb_if_khz = 3250,
+ .qam_if_khz = 4000,
+};
+
+static struct s921_config sharp_isdbt = {
+ .demod_address = 0x30 >> 1
+};
+
static struct zl10353_config em28xx_zl10353_with_xc3028 = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
@@ -247,6 +266,17 @@ static struct s5h1409_config em28xx_s5h1409_with_xc3028 = {
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK
};
+static struct tda18271_std_map kworld_a340_std_map = {
+ .atsc_6 = { .if_freq = 3250, .agc_mode = 3, .std = 0,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 1,
+ .if_lvl = 1, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_a340_config = {
+ .std_map = &kworld_a340_std_map,
+};
+
static struct zl10353_config em28xx_zl10353_xc3028_no_i2c_gate = {
.demod_address = (0x1e >> 1),
.no_tuner = 1,
@@ -456,6 +486,7 @@ static int dvb_init(struct em28xx *dev)
if (!dev->board.has_dvb) {
/* This device does not support the extension */
+ printk(KERN_INFO "em28xx_dvb: This device does not support the extension\n");
return 0;
}
@@ -471,6 +502,16 @@ static int dvb_init(struct em28xx *dev)
em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
/* init frontend */
switch (dev->model) {
+ case EM2874_LEADERSHIP_ISDBT:
+ dvb->frontend = dvb_attach(s921_attach,
+ &sharp_isdbt, &dev->i2c_adap);
+
+ if (!dvb->frontend) {
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ break;
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_850:
case EM2883_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_PINNACLE_PCTV_HD_PRO:
@@ -572,6 +613,14 @@ static int dvb_init(struct em28xx *dev)
}
}
break;
+ case EM2870_BOARD_KWORLD_A340:
+ dvb->frontend = dvb_attach(lgdt3305_attach,
+ &em2870_lgdt3304_dev,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL)
+ dvb_attach(tda18271_attach, dvb->frontend, 0x60,
+ &dev->i2c_adap, &kworld_a340_config);
+ break;
default:
em28xx_errdev("/2: The frontend of your DVB/ATSC card"
" isn't supported yet\n");
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 5c3fd9411b1f..ba1ba8648c81 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -25,7 +25,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/input.h>
#include <linux/usb.h>
#include <linux/slab.h>
@@ -64,24 +63,17 @@ struct em28xx_ir_poll_result {
struct em28xx_IR {
struct em28xx *dev;
- struct input_dev *input;
- struct ir_input_state ir;
+ struct rc_dev *rc;
char name[32];
char phys[32];
/* poll external decoder */
int polling;
struct delayed_work work;
- unsigned int last_toggle:1;
unsigned int full_code:1;
unsigned int last_readcount;
- unsigned int repeat_interval;
int (*get_key)(struct em28xx_IR *, struct em28xx_ir_poll_result *);
-
- /* IR device properties */
-
- struct ir_dev_props props;
};
/**********************************************************
@@ -291,67 +283,39 @@ static int em2874_polling_getkey(struct em28xx_IR *ir,
static void em28xx_ir_handle_key(struct em28xx_IR *ir)
{
int result;
- int do_sendkey = 0;
struct em28xx_ir_poll_result poll_result;
/* read the registers containing the IR status */
result = ir->get_key(ir, &poll_result);
- if (result < 0) {
+ if (unlikely(result < 0)) {
dprintk("ir->get_key() failed %d\n", result);
return;
}
- dprintk("ir->get_key result tb=%02x rc=%02x lr=%02x data=%02x%02x\n",
- poll_result.toggle_bit, poll_result.read_count,
- ir->last_readcount, poll_result.rc_address,
- poll_result.rc_data[0]);
-
- if (ir->dev->chip_id == CHIP_ID_EM2874) {
- /* The em2874 clears the readcount field every time the
- register is read. The em2860/2880 datasheet says that it
- is supposed to clear the readcount, but it doesn't. So with
- the em2874, we are looking for a non-zero read count as
- opposed to a readcount that is incrementing */
- ir->last_readcount = 0;
- }
-
- if (poll_result.read_count == 0) {
- /* The button has not been pressed since the last read */
- } else if (ir->last_toggle != poll_result.toggle_bit) {
- /* A button has been pressed */
- dprintk("button has been pressed\n");
- ir->last_toggle = poll_result.toggle_bit;
- ir->repeat_interval = 0;
- do_sendkey = 1;
- } else if (poll_result.toggle_bit == ir->last_toggle &&
- poll_result.read_count > 0 &&
- poll_result.read_count != ir->last_readcount) {
- /* The button is still being held down */
- dprintk("button being held down\n");
-
- /* Debouncer for first keypress */
- if (ir->repeat_interval++ > 9) {
- /* Start repeating after 1 second */
- do_sendkey = 1;
- }
- }
-
- if (do_sendkey) {
- dprintk("sending keypress\n");
-
+ if (unlikely(poll_result.read_count != ir->last_readcount)) {
+ dprintk("%s: toggle: %d, count: %d, key 0x%02x%02x\n", __func__,
+ poll_result.toggle_bit, poll_result.read_count,
+ poll_result.rc_address, poll_result.rc_data[0]);
if (ir->full_code)
- ir_input_keydown(ir->input, &ir->ir,
- poll_result.rc_address << 8 |
- poll_result.rc_data[0]);
+ rc_keydown(ir->rc,
+ poll_result.rc_address << 8 |
+ poll_result.rc_data[0],
+ poll_result.toggle_bit);
else
- ir_input_keydown(ir->input, &ir->ir,
- poll_result.rc_data[0]);
-
- ir_input_nokey(ir->input, &ir->ir);
+ rc_keydown(ir->rc,
+ poll_result.rc_data[0],
+ poll_result.toggle_bit);
+
+ if (ir->dev->chip_id == CHIP_ID_EM2874)
+ /* The em2874 clears the readcount field every time the
+ register is read. The em2860/2880 datasheet says that it
+ is supposed to clear the readcount, but it doesn't. So with
+ the em2874, we are looking for a non-zero read count as
+ opposed to a readcount that is incrementing */
+ ir->last_readcount = 0;
+ else
+ ir->last_readcount = poll_result.read_count;
}
-
- ir->last_readcount = poll_result.read_count;
- return;
}
static void em28xx_ir_work(struct work_struct *work)
@@ -362,9 +326,9 @@ static void em28xx_ir_work(struct work_struct *work)
schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling));
}
-static int em28xx_ir_start(void *priv)
+static int em28xx_ir_start(struct rc_dev *rc)
{
- struct em28xx_IR *ir = priv;
+ struct em28xx_IR *ir = rc->priv;
INIT_DELAYED_WORK(&ir->work, em28xx_ir_work);
schedule_delayed_work(&ir->work, 0);
@@ -372,30 +336,30 @@ static int em28xx_ir_start(void *priv)
return 0;
}
-static void em28xx_ir_stop(void *priv)
+static void em28xx_ir_stop(struct rc_dev *rc)
{
- struct em28xx_IR *ir = priv;
+ struct em28xx_IR *ir = rc->priv;
cancel_delayed_work_sync(&ir->work);
}
-int em28xx_ir_change_protocol(void *priv, u64 ir_type)
+int em28xx_ir_change_protocol(struct rc_dev *rc_dev, u64 rc_type)
{
int rc = 0;
- struct em28xx_IR *ir = priv;
+ struct em28xx_IR *ir = rc_dev->priv;
struct em28xx *dev = ir->dev;
u8 ir_config = EM2874_IR_RC5;
/* Adjust xclk based o IR table for RC5/NEC tables */
- if (ir_type == IR_TYPE_RC5) {
+ if (rc_type == RC_TYPE_RC5) {
dev->board.xclk |= EM28XX_XCLK_IR_RC5_MODE;
ir->full_code = 1;
- } else if (ir_type == IR_TYPE_NEC) {
+ } else if (rc_type == RC_TYPE_NEC) {
dev->board.xclk &= ~EM28XX_XCLK_IR_RC5_MODE;
ir_config = EM2874_IR_NEC;
ir->full_code = 1;
- } else if (ir_type != IR_TYPE_UNKNOWN)
+ } else if (rc_type != RC_TYPE_UNKNOWN)
rc = -EINVAL;
em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, dev->board.xclk,
@@ -422,7 +386,7 @@ int em28xx_ir_change_protocol(void *priv, u64 ir_type)
int em28xx_ir_init(struct em28xx *dev)
{
struct em28xx_IR *ir;
- struct input_dev *input_dev;
+ struct rc_dev *rc;
int err = -ENOMEM;
if (dev->board.ir_codes == NULL) {
@@ -431,28 +395,27 @@ int em28xx_ir_init(struct em28xx *dev)
}
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev)
+ rc = rc_allocate_device();
+ if (!ir || !rc)
goto err_out_free;
/* record handles to ourself */
ir->dev = dev;
dev->ir = ir;
-
- ir->input = input_dev;
+ ir->rc = rc;
/*
* em2874 supports more protocols. For now, let's just announce
* the two protocols that were already tested
*/
- ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
- ir->props.priv = ir;
- ir->props.change_protocol = em28xx_ir_change_protocol;
- ir->props.open = em28xx_ir_start;
- ir->props.close = em28xx_ir_stop;
+ rc->allowed_protos = RC_TYPE_RC5 | RC_TYPE_NEC;
+ rc->priv = ir;
+ rc->change_protocol = em28xx_ir_change_protocol;
+ rc->open = em28xx_ir_start;
+ rc->close = em28xx_ir_stop;
/* By default, keep protocol field untouched */
- err = em28xx_ir_change_protocol(ir, IR_TYPE_UNKNOWN);
+ err = em28xx_ir_change_protocol(rc, RC_TYPE_UNKNOWN);
if (err)
goto err_out_free;
@@ -466,32 +429,27 @@ int em28xx_ir_init(struct em28xx *dev)
usb_make_path(dev->udev, ir->phys, sizeof(ir->phys));
strlcat(ir->phys, "/input0", sizeof(ir->phys));
- /* Set IR protocol */
- err = ir_input_init(input_dev, &ir->ir, IR_TYPE_OTHER);
- if (err < 0)
- goto err_out_free;
-
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_USB;
- input_dev->id.version = 1;
- input_dev->id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
- input_dev->id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
-
- input_dev->dev.parent = &dev->udev->dev;
-
-
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_USB;
+ rc->input_id.version = 1;
+ rc->input_id.vendor = le16_to_cpu(dev->udev->descriptor.idVendor);
+ rc->input_id.product = le16_to_cpu(dev->udev->descriptor.idProduct);
+ rc->dev.parent = &dev->udev->dev;
+ rc->map_name = dev->board.ir_codes;
+ rc->driver_name = MODULE_NAME;
/* all done */
- err = ir_input_register(ir->input, dev->board.ir_codes,
- &ir->props, MODULE_NAME);
+ err = rc_register_device(rc);
if (err)
goto err_out_stop;
return 0;
+
err_out_stop:
dev->ir = NULL;
err_out_free:
+ rc_free_device(rc);
kfree(ir);
return err;
}
@@ -504,8 +462,8 @@ int em28xx_ir_fini(struct em28xx *dev)
if (!ir)
return 0;
- em28xx_ir_stop(ir);
- ir_input_unregister(ir->input);
+ em28xx_ir_stop(ir->rc);
+ rc_unregister_device(ir->rc);
kfree(ir);
/* done */
@@ -593,7 +551,7 @@ void em28xx_deregister_snapshot_button(struct em28xx *dev)
{
if (dev->sbutton_input_dev != NULL) {
em28xx_info("Deregistering snapshot button\n");
- cancel_rearming_delayed_work(&dev->sbutton_query_work);
+ cancel_delayed_work_sync(&dev->sbutton_query_work);
input_unregister_device(dev->sbutton_input_dev);
dev->sbutton_input_dev = NULL;
}
diff --git a/drivers/media/video/em28xx/em28xx-vbi.c b/drivers/media/video/em28xx/em28xx-vbi.c
index 7f1c4a2173b6..2b4c9cba2d67 100644
--- a/drivers/media/video/em28xx/em28xx-vbi.c
+++ b/drivers/media/video/em28xx/em28xx-vbi.c
@@ -23,6 +23,7 @@
#include <linux/kernel.h>
#include <linux/module.h>
+#include <linux/hardirq.h>
#include <linux/init.h>
#include "em28xx.h"
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 20090e34173a..f34d524ccb09 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -277,12 +277,13 @@ static void em28xx_copy_vbi(struct em28xx *dev,
{
void *startwrite, *startread;
int offset;
- int bytesperline = dev->vbi_width;
+ int bytesperline;
if (dev == NULL) {
em28xx_isocdbg("dev is null\n");
return;
}
+ bytesperline = dev->vbi_width;
if (dma_q == NULL) {
em28xx_isocdbg("dma_q is null\n");
@@ -654,12 +655,12 @@ static inline int em28xx_isoc_copy_vbi(struct em28xx *dev, struct urb *urb)
}
if (buf != NULL && dev->capture_type == 2) {
- if (len > 4 && p[0] == 0x88 && p[1] == 0x88 &&
+ if (len >= 4 && p[0] == 0x88 && p[1] == 0x88 &&
p[2] == 0x88 && p[3] == 0x88) {
p += 4;
len -= 4;
}
- if (len > 4 && p[0] == 0x22 && p[1] == 0x5a) {
+ if (len >= 4 && p[0] == 0x22 && p[1] == 0x5a) {
em28xx_isocdbg("Video frame %d, len=%i, %s\n",
p[2], len, (p[2] & 1) ?
"odd" : "even");
@@ -862,17 +863,14 @@ static int res_get(struct em28xx_fh *fh, unsigned int bit)
return 1;
/* is it free? */
- mutex_lock(&dev->lock);
if (dev->resources & bit) {
/* no, someone else uses it */
- mutex_unlock(&dev->lock);
return 0;
}
/* it's free, grab it */
fh->resources |= bit;
dev->resources |= bit;
em28xx_videodbg("res: get %d\n", bit);
- mutex_unlock(&dev->lock);
return 1;
}
@@ -892,11 +890,9 @@ static void res_free(struct em28xx_fh *fh, unsigned int bits)
BUG_ON((fh->resources & bits) != bits);
- mutex_lock(&dev->lock);
fh->resources &= ~bits;
dev->resources &= ~bits;
em28xx_videodbg("res: put %d\n", bits);
- mutex_unlock(&dev->lock);
}
static int get_ressource(struct em28xx_fh *fh)
@@ -1023,8 +1019,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- mutex_lock(&dev->lock);
-
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
f->fmt.pix.pixelformat = dev->format->fourcc;
@@ -1038,8 +1032,6 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
else
f->fmt.pix.field = dev->interlaced ?
V4L2_FIELD_INTERLACED : V4L2_FIELD_TOP;
-
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1137,22 +1129,15 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
-
vidioc_try_fmt_vid_cap(file, priv, f);
if (videobuf_queue_is_busy(&fh->vb_vidq)) {
em28xx_errdev("%s queue busy\n", __func__);
- rc = -EBUSY;
- goto out;
+ return -EBUSY;
}
- rc = em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
+ return em28xx_set_video_format(dev, f->fmt.pix.pixelformat,
f->fmt.pix.width, f->fmt.pix.height);
-
-out:
- mutex_unlock(&dev->lock);
- return rc;
}
static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *norm)
@@ -1181,7 +1166,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
dev->norm = *norm;
/* Adjusts width/height, if needed */
@@ -1197,7 +1181,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
em28xx_resolution_set(dev);
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1302,9 +1285,7 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
dev->ctl_input = i;
- mutex_lock(&dev->lock);
video_mux(dev, dev->ctl_input);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1365,15 +1346,12 @@ static int vidioc_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
if (0 == INPUT(a->index)->type)
return -EINVAL;
- 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);
return 0;
}
@@ -1393,17 +1371,15 @@ static int vidioc_queryctrl(struct file *file, void *priv,
qc->id = id;
- /* enumberate AC97 controls */
+ /* enumerate AC97 controls */
if (dev->audio_mode.ac97 != EM28XX_NO_AC97) {
rc = ac97_queryctrl(qc);
if (!rc)
return 0;
}
- /* enumberate V4L2 device controls */
- mutex_lock(&dev->lock);
+ /* enumerate V4L2 device controls */
v4l2_device_call_all(&dev->v4l2_dev, 0, core, queryctrl, qc);
- mutex_unlock(&dev->lock);
if (qc->type)
return 0;
@@ -1423,7 +1399,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
return rc;
rc = 0;
- mutex_lock(&dev->lock);
/* Set an AC97 control */
if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
@@ -1437,7 +1412,6 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
rc = 0;
}
- mutex_unlock(&dev->lock);
return rc;
}
@@ -1452,8 +1426,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
-
/* Set an AC97 control */
if (dev->audio_mode.ac97 != EM28XX_NO_AC97)
rc = ac97_set_ctrl(dev, ctrl);
@@ -1462,7 +1434,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
/* It isn't an AC97 control. Sends it to the v4l2 dev interface */
if (rc == 1) {
- v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
+ rc = v4l2_device_call_until_err(&dev->v4l2_dev, 0, core, s_ctrl, ctrl);
/*
* In the case of non-AC97 volume controls, we still need
@@ -1480,8 +1452,6 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
rc = em28xx_audio_analog_set(dev);
}
}
-
- mutex_unlock(&dev->lock);
return rc;
}
@@ -1502,10 +1472,7 @@ static int vidioc_g_tuner(struct file *file, void *priv,
strcpy(t->name, "Tuner");
t->type = V4L2_TUNER_ANALOG_TV;
- mutex_lock(&dev->lock);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
- mutex_unlock(&dev->lock);
-
return 0;
}
@@ -1523,10 +1490,7 @@ static int vidioc_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- mutex_lock(&dev->lock);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
- mutex_unlock(&dev->lock);
-
return 0;
}
@@ -1536,11 +1500,8 @@ 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;
}
@@ -1563,13 +1524,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
if (unlikely(1 == fh->radio && f->type != V4L2_TUNER_RADIO))
return -EINVAL;
- mutex_lock(&dev->lock);
-
dev->ctl_freq = f->frequency;
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_frequency, f);
- mutex_unlock(&dev->lock);
-
return 0;
}
@@ -1610,9 +1567,7 @@ static int vidioc_g_register(struct file *file, void *priv,
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;
@@ -1634,9 +1589,7 @@ static int vidioc_g_register(struct file *file, void *priv,
/* 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;
@@ -1644,10 +1597,8 @@ static int vidioc_g_register(struct file *file, void *priv,
reg->val = ret;
} else {
__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;
@@ -1663,15 +1614,10 @@ static int vidioc_s_register(struct file *file, void *priv,
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
__le16 buf;
- int rc;
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 rc;
+ return em28xx_write_ac97(dev, reg->reg, reg->val);
case V4L2_CHIP_MATCH_I2C_DRIVER:
v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_register, reg);
return 0;
@@ -1687,12 +1633,8 @@ static int vidioc_s_register(struct file *file, void *priv,
/* Match host */
buf = cpu_to_le16(reg->val);
- mutex_lock(&dev->lock);
- rc = em28xx_write_regs(dev, reg->reg, (char *)&buf,
+ return em28xx_write_regs(dev, reg->reg, (char *)&buf,
em28xx_reg_len(reg->reg));
- mutex_unlock(&dev->lock);
-
- return rc;
}
#endif
@@ -1766,11 +1708,15 @@ static int vidioc_streamoff(struct file *file, void *priv,
fh, type, fh->resources, dev->resources);
if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
- videobuf_streamoff(&fh->vb_vidq);
- res_free(fh, EM28XX_RESOURCE_VIDEO);
+ if (res_check(fh, EM28XX_RESOURCE_VIDEO)) {
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh, EM28XX_RESOURCE_VIDEO);
+ }
} else if (fh->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- videobuf_streamoff(&fh->vb_vbiq);
- res_free(fh, EM28XX_RESOURCE_VBI);
+ if (res_check(fh, EM28XX_RESOURCE_VBI)) {
+ videobuf_streamoff(&fh->vb_vbiq);
+ res_free(fh, EM28XX_RESOURCE_VBI);
+ }
}
return 0;
@@ -1829,16 +1775,12 @@ static int vidioc_g_fmt_sliced_vbi_cap(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
-
f->fmt.sliced.service_set = 0;
v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
if (f->fmt.sliced.service_set == 0)
rc = -EINVAL;
- mutex_unlock(&dev->lock);
-
return rc;
}
@@ -1853,9 +1795,7 @@ static int vidioc_try_set_sliced_vbi_cap(struct file *file, void *priv,
if (rc < 0)
return rc;
- mutex_lock(&dev->lock);
v4l2_device_call_all(&dev->v4l2_dev, 0, vbi, g_sliced_fmt, &f->fmt.sliced);
- mutex_unlock(&dev->lock);
if (f->fmt.sliced.service_set == 0)
return -EINVAL;
@@ -1998,19 +1938,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct em28xx_fh *fh = priv;
-
- if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
- else
- return videobuf_cgmbuf(&fh->vb_vbiq, mbuf, 8);
-}
-#endif
-
-
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
/* ----------------------------------------------------------- */
@@ -2040,9 +1967,7 @@ static int radio_g_tuner(struct file *file, void *priv,
strcpy(t->name, "Radio");
t->type = V4L2_TUNER_RADIO;
- mutex_lock(&dev->lock);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, g_tuner, t);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -2075,9 +2000,7 @@ static int radio_s_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
- mutex_lock(&dev->lock);
v4l2_device_call_all(&dev->v4l2_dev, 0, tuner, s_tuner, t);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -2137,8 +2060,6 @@ static int em28xx_v4l2_open(struct file *filp)
break;
}
- mutex_lock(&dev->lock);
-
em28xx_videodbg("open dev=%s type=%s users=%d\n",
video_device_node_name(vdev), v4l2_type_names[fh_type],
dev->users);
@@ -2147,7 +2068,6 @@ static int em28xx_v4l2_open(struct file *filp)
fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
if (!fh) {
em28xx_errdev("em28xx-video.c: Out of memory?!\n");
- mutex_unlock(&dev->lock);
return -ENOMEM;
}
fh->dev = dev;
@@ -2181,15 +2101,13 @@ static int em28xx_v4l2_open(struct file *filp)
videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
NULL, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, field,
- sizeof(struct em28xx_buffer), fh);
+ sizeof(struct em28xx_buffer), fh, &dev->lock);
videobuf_queue_vmalloc_init(&fh->vb_vbiq, &em28xx_vbi_qops,
NULL, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
- sizeof(struct em28xx_buffer), fh);
-
- mutex_unlock(&dev->lock);
+ sizeof(struct em28xx_buffer), fh, &dev->lock);
return errCode;
}
@@ -2388,7 +2306,7 @@ static const struct v4l2_file_operations em28xx_v4l_fops = {
.read = em28xx_v4l2_read,
.poll = em28xx_v4l2_poll,
.mmap = em28xx_v4l2_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops video_ioctl_ops = {
@@ -2432,9 +2350,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
.vidioc_g_chip_ident = vidioc_g_chip_ident,
#endif
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static const struct video_device em28xx_video_template = {
@@ -2450,7 +2365,7 @@ static const struct v4l2_file_operations radio_fops = {
.owner = THIS_MODULE,
.open = em28xx_v4l2_open,
.release = em28xx_v4l2_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops radio_ioctl_ops = {
@@ -2496,6 +2411,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
vfd->v4l2_dev = &dev->v4l2_dev;
vfd->release = video_device_release;
vfd->debug = video_debug;
+ vfd->lock = &dev->lock;
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
dev->name, type_name);
@@ -2516,6 +2432,7 @@ int em28xx_register_analog_devices(struct em28xx *dev)
/* set default norm */
dev->norm = em28xx_video_template.current_norm;
+ v4l2_device_call_all(&dev->v4l2_dev, 0, core, s_std, dev->norm);
dev->interlaced = EM28XX_INTERLACED_DEFAULT;
dev->ctl_input = 0;
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index b252d1b1b2a7..6f2795a3d4b7 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -25,13 +25,15 @@
#ifndef _EM28XX_H
#define _EM28XX_H
+#include <linux/workqueue.h>
+#include <linux/i2c.h>
+#include <linux/mutex.h>
#include <linux/videodev2.h>
+
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-device.h>
-
-#include <linux/i2c.h>
-#include <linux/mutex.h>
#include <media/ir-kbd-i2c.h>
+#include <media/rc-core.h>
#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
#include <media/videobuf-dvb.h>
#endif
@@ -72,6 +74,7 @@
#define EM2820_BOARD_VIDEOLOGY_20K14XUSB 30
#define EM2821_BOARD_USBGEAR_VD204 31
#define EM2821_BOARD_SUPERCOMP_USB_2 32
+#define EM2860_BOARD_ELGATO_VIDEO_CAPTURE 33
#define EM2860_BOARD_TERRATEC_HYBRID_XS 34
#define EM2860_BOARD_TYPHOON_DVD_MAKER 35
#define EM2860_BOARD_NETGMBH_CAM 36
@@ -113,6 +116,9 @@
#define EM2870_BOARD_REDDO_DVB_C_USB_BOX 73
#define EM2800_BOARD_VC211A 74
#define EM2882_BOARD_DIKOM_DK300 75
+#define EM2870_BOARD_KWORLD_A340 76
+#define EM2874_LEADERSHIP_ISDBT 77
+
/* Limits minimum and default number of buffers */
#define EM28XX_MIN_BUF 4
@@ -182,11 +188,6 @@ enum em28xx_mode {
EM28XX_DIGITAL_MODE,
};
-enum em28xx_stream_state {
- STREAM_OFF,
- STREAM_INTERRUPT,
- STREAM_ON,
-};
struct em28xx;
@@ -461,7 +462,6 @@ struct em28xx_audio {
struct snd_card *sndcard;
int users;
- enum em28xx_stream_state capture_stream;
spinlock_t slock;
};
@@ -503,6 +503,10 @@ struct em28xx {
unsigned int has_audio_class:1;
unsigned int has_alsa_audio:1;
+ /* Controls audio streaming */
+ struct work_struct wq_trigger; /* Trigger to start/stop audio for alsa module */
+ atomic_t stream_started; /* stream should be running if true */
+
struct em28xx_fmt *format;
struct em28xx_IR *ir;
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index cc77d144df3c..bf66189cb26d 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -59,31 +59,7 @@
/*****************************************************************************/
static const struct usb_device_id et61x251_id_table[] = {
- { USB_DEVICE(0x102c, 0x6151), },
{ USB_DEVICE(0x102c, 0x6251), },
- { USB_DEVICE(0x102c, 0x6253), },
- { USB_DEVICE(0x102c, 0x6254), },
- { USB_DEVICE(0x102c, 0x6255), },
- { USB_DEVICE(0x102c, 0x6256), },
- { USB_DEVICE(0x102c, 0x6257), },
- { USB_DEVICE(0x102c, 0x6258), },
- { USB_DEVICE(0x102c, 0x6259), },
- { USB_DEVICE(0x102c, 0x625a), },
- { USB_DEVICE(0x102c, 0x625b), },
- { USB_DEVICE(0x102c, 0x625c), },
- { USB_DEVICE(0x102c, 0x625d), },
- { USB_DEVICE(0x102c, 0x625e), },
- { USB_DEVICE(0x102c, 0x625f), },
- { USB_DEVICE(0x102c, 0x6260), },
- { USB_DEVICE(0x102c, 0x6261), },
- { USB_DEVICE(0x102c, 0x6262), },
- { USB_DEVICE(0x102c, 0x6263), },
- { USB_DEVICE(0x102c, 0x6264), },
- { USB_DEVICE(0x102c, 0x6265), },
- { USB_DEVICE(0x102c, 0x6266), },
- { USB_DEVICE(0x102c, 0x6267), },
- { USB_DEVICE(0x102c, 0x6268), },
- { USB_DEVICE(0x102c, 0x6269), },
{ }
};
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index a5cfc76b40b7..a982750dcef1 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -1610,6 +1610,7 @@ et61x251_vidioc_enuminput(struct et61x251_device* cam, void __user * arg)
memset(&i, 0, sizeof(i));
strcpy(i.name, "Camera");
i.type = V4L2_INPUT_TYPE_CAMERA;
+ i.capabilities = V4L2_IN_CAP_STD;
if (copy_to_user(arg, &i, sizeof(i)))
return -EFAULT;
@@ -2530,7 +2531,7 @@ static const struct v4l2_file_operations et61x251_fops = {
.owner = THIS_MODULE,
.open = et61x251_open,
.release = et61x251_release,
- .ioctl = et61x251_ioctl,
+ .unlocked_ioctl = et61x251_ioctl,
.read = et61x251_read,
.poll = et61x251_poll,
.mmap = et61x251_mmap,
diff --git a/drivers/media/video/fsl-viu.c b/drivers/media/video/fsl-viu.c
new file mode 100644
index 000000000000..e4bba88254c7
--- /dev/null
+++ b/drivers/media/video/fsl-viu.c
@@ -0,0 +1,1659 @@
+/*
+ * Copyright 2008-2010 Freescale Semiconductor, Inc. All Rights Reserved.
+ *
+ * Freescale VIU video driver
+ *
+ * Authors: Hongjun Chen <hong-jun.chen@freescale.com>
+ * Porting to 2.6.35 by DENX Software Engineering,
+ * Anatolij Gustschin <agust@denx.de>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the
+ * Free Software Foundation; either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/clk.h>
+#include <linux/kernel.h>
+#include <linux/i2c.h>
+#include <linux/init.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_platform.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#define DRV_NAME "fsl_viu"
+#define VIU_MAJOR_VERSION 0
+#define VIU_MINOR_VERSION 5
+#define VIU_RELEASE 0
+#define VIU_VERSION KERNEL_VERSION(VIU_MAJOR_VERSION, \
+ VIU_MINOR_VERSION, \
+ VIU_RELEASE)
+
+#define BUFFER_TIMEOUT msecs_to_jiffies(500) /* 0.5 seconds */
+
+#define VIU_VID_MEM_LIMIT 4 /* Video memory limit, in Mb */
+
+/* I2C address of video decoder chip is 0x4A */
+#define VIU_VIDEO_DECODER_ADDR 0x25
+
+/* supported controls */
+static struct v4l2_queryctrl viu_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 127,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 0x10,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 0x1,
+ .default_value = 127,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 0x1,
+ .default_value = 0,
+ .flags = 0,
+ }
+};
+
+static int qctl_regs[ARRAY_SIZE(viu_qctrl)];
+
+static int info_level;
+
+#define dprintk(level, fmt, arg...) \
+ do { \
+ if (level <= info_level) \
+ printk(KERN_DEBUG "viu: " fmt , ## arg); \
+ } while (0)
+
+/*
+ * Basic structures
+ */
+struct viu_fmt {
+ char name[32];
+ u32 fourcc; /* v4l2 format id */
+ u32 pixelformat;
+ int depth;
+};
+
+static struct viu_fmt formats[] = {
+ {
+ .name = "RGB-16 (5/B-6/G-5/R)",
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .depth = 16,
+ }, {
+ .name = "RGB-32 (A-R-G-B)",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .pixelformat = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ }
+};
+
+struct viu_dev;
+struct viu_buf;
+
+/* buffer for one video frame */
+struct viu_buf {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ struct viu_fmt *fmt;
+};
+
+struct viu_dmaqueue {
+ struct viu_dev *dev;
+ struct list_head active;
+ struct list_head queued;
+ struct timer_list timeout;
+};
+
+struct viu_status {
+ u32 field_irq;
+ u32 vsync_irq;
+ u32 hsync_irq;
+ u32 vstart_irq;
+ u32 dma_end_irq;
+ u32 error_irq;
+};
+
+struct viu_reg {
+ u32 status_cfg;
+ u32 luminance;
+ u32 chroma_r;
+ u32 chroma_g;
+ u32 chroma_b;
+ u32 field_base_addr;
+ u32 dma_inc;
+ u32 picture_count;
+ u32 req_alarm;
+ u32 alpha;
+} __attribute__ ((packed));
+
+struct viu_dev {
+ struct v4l2_device v4l2_dev;
+ struct mutex lock;
+ spinlock_t slock;
+ int users;
+
+ struct device *dev;
+ /* various device info */
+ struct video_device *vdev;
+ struct viu_dmaqueue vidq;
+ enum v4l2_field capfield;
+ int field;
+ int first;
+ int dma_done;
+
+ /* Hardware register area */
+ struct viu_reg *vr;
+
+ /* Interrupt vector */
+ int irq;
+ struct viu_status irqs;
+
+ /* video overlay */
+ struct v4l2_framebuffer ovbuf;
+ struct viu_fmt *ovfmt;
+ unsigned int ovenable;
+ enum v4l2_field ovfield;
+
+ /* crop */
+ struct v4l2_rect crop_current;
+
+ /* clock pointer */
+ struct clk *clk;
+
+ /* decoder */
+ struct v4l2_subdev *decoder;
+
+ v4l2_std_id std;
+};
+
+struct viu_fh {
+ struct viu_dev *dev;
+
+ /* video capture */
+ struct videobuf_queue vb_vidq;
+ spinlock_t vbq_lock; /* spinlock for the videobuf queue */
+
+ /* video overlay */
+ struct v4l2_window win;
+ struct v4l2_clip clips[1];
+
+ /* video capture */
+ struct viu_fmt *fmt;
+ int width, height, sizeimage;
+ enum v4l2_buf_type type;
+};
+
+static struct viu_reg reg_val;
+
+/*
+ * Macro definitions of VIU registers
+ */
+
+/* STATUS_CONFIG register */
+enum status_config {
+ SOFT_RST = 1 << 0,
+
+ ERR_MASK = 0x0f << 4, /* Error code mask */
+ ERR_NO = 0x00, /* No error */
+ ERR_DMA_V = 0x01 << 4, /* DMA in vertical active */
+ ERR_DMA_VB = 0x02 << 4, /* DMA in vertical blanking */
+ ERR_LINE_TOO_LONG = 0x04 << 4, /* Line too long */
+ ERR_TOO_MANG_LINES = 0x05 << 4, /* Too many lines in field */
+ ERR_LINE_TOO_SHORT = 0x06 << 4, /* Line too short */
+ ERR_NOT_ENOUGH_LINE = 0x07 << 4, /* Not enough lines in field */
+ ERR_FIFO_OVERFLOW = 0x08 << 4, /* FIFO overflow */
+ ERR_FIFO_UNDERFLOW = 0x09 << 4, /* FIFO underflow */
+ ERR_1bit_ECC = 0x0a << 4, /* One bit ECC error */
+ ERR_MORE_ECC = 0x0b << 4, /* Two/more bits ECC error */
+
+ INT_FIELD_EN = 0x01 << 8, /* Enable field interrupt */
+ INT_VSYNC_EN = 0x01 << 9, /* Enable vsync interrupt */
+ INT_HSYNC_EN = 0x01 << 10, /* Enable hsync interrupt */
+ INT_VSTART_EN = 0x01 << 11, /* Enable vstart interrupt */
+ INT_DMA_END_EN = 0x01 << 12, /* Enable DMA end interrupt */
+ INT_ERROR_EN = 0x01 << 13, /* Enable error interrupt */
+ INT_ECC_EN = 0x01 << 14, /* Enable ECC interrupt */
+
+ INT_FIELD_STATUS = 0x01 << 16, /* field interrupt status */
+ INT_VSYNC_STATUS = 0x01 << 17, /* vsync interrupt status */
+ INT_HSYNC_STATUS = 0x01 << 18, /* hsync interrupt status */
+ INT_VSTART_STATUS = 0x01 << 19, /* vstart interrupt status */
+ INT_DMA_END_STATUS = 0x01 << 20, /* DMA end interrupt status */
+ INT_ERROR_STATUS = 0x01 << 21, /* error interrupt status */
+
+ DMA_ACT = 0x01 << 27, /* Enable DMA transfer */
+ FIELD_NO = 0x01 << 28, /* Field number */
+ DITHER_ON = 0x01 << 29, /* Dithering is on */
+ ROUND_ON = 0x01 << 30, /* Round is on */
+ MODE_32BIT = 0x01 << 31, /* Data in RGBa888,
+ * 0 in RGB565
+ */
+};
+
+#define norm_maxw() 720
+#define norm_maxh() 576
+
+#define INT_ALL_STATUS (INT_FIELD_STATUS | INT_VSYNC_STATUS | \
+ INT_HSYNC_STATUS | INT_VSTART_STATUS | \
+ INT_DMA_END_STATUS | INT_ERROR_STATUS)
+
+#define NUM_FORMATS ARRAY_SIZE(formats)
+
+static irqreturn_t viu_intr(int irq, void *dev_id);
+
+struct viu_fmt *format_by_fourcc(int fourcc)
+{
+ int i;
+
+ for (i = 0; i < NUM_FORMATS; i++) {
+ if (formats[i].pixelformat == fourcc)
+ return formats + i;
+ }
+
+ dprintk(0, "unknown pixelformat:'%4.4s'\n", (char *)&fourcc);
+ return NULL;
+}
+
+void viu_start_dma(struct viu_dev *dev)
+{
+ struct viu_reg *vr = dev->vr;
+
+ dev->field = 0;
+
+ /* Enable DMA operation */
+ out_be32(&vr->status_cfg, SOFT_RST);
+ out_be32(&vr->status_cfg, INT_FIELD_EN);
+}
+
+void viu_stop_dma(struct viu_dev *dev)
+{
+ struct viu_reg *vr = dev->vr;
+ int cnt = 100;
+ u32 status_cfg;
+
+ out_be32(&vr->status_cfg, 0);
+
+ /* Clear pending interrupts */
+ status_cfg = in_be32(&vr->status_cfg);
+ if (status_cfg & 0x3f0000)
+ out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+
+ if (status_cfg & DMA_ACT) {
+ do {
+ status_cfg = in_be32(&vr->status_cfg);
+ if (status_cfg & INT_DMA_END_STATUS)
+ break;
+ } while (cnt--);
+
+ if (cnt < 0) {
+ /* timed out, issue soft reset */
+ out_be32(&vr->status_cfg, SOFT_RST);
+ out_be32(&vr->status_cfg, 0);
+ } else {
+ /* clear DMA_END and other pending irqs */
+ out_be32(&vr->status_cfg, status_cfg & 0x3f0000);
+ }
+ }
+
+ dev->field = 0;
+}
+
+static int restart_video_queue(struct viu_dmaqueue *vidq)
+{
+ struct viu_buf *buf, *prev;
+
+ dprintk(1, "%s vidq=0x%08lx\n", __func__, (unsigned long)vidq);
+ if (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+ dprintk(2, "restart_queue [%p/%d]: restart dma\n",
+ buf, buf->vb.i);
+
+ viu_stop_dma(vidq->dev);
+
+ /* cancel all outstanding capture requests */
+ list_for_each_entry_safe(buf, prev, &vidq->active, vb.queue) {
+ list_del(&buf->vb.queue);
+ buf->vb.state = VIDEOBUF_ERROR;
+ wake_up(&buf->vb.done);
+ }
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ return 0;
+ }
+
+ prev = NULL;
+ for (;;) {
+ if (list_empty(&vidq->queued))
+ return 0;
+ buf = list_entry(vidq->queued.next, struct viu_buf, vb.queue);
+ if (prev == NULL) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+ dprintk(1, "Restarting video dma\n");
+ viu_stop_dma(vidq->dev);
+ viu_start_dma(vidq->dev);
+
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(2, "[%p/%d] restart_queue - first active\n",
+ buf, buf->vb.i);
+
+ } else if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_del(&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dprintk(2, "[%p/%d] restart_queue - move to active\n",
+ buf, buf->vb.i);
+ } else {
+ return 0;
+ }
+ prev = buf;
+ }
+}
+
+static void viu_vid_timeout(unsigned long data)
+{
+ struct viu_dev *dev = (struct viu_dev *)data;
+ struct viu_buf *buf;
+ struct viu_dmaqueue *vidq = &dev->vidq;
+
+ while (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf, vb.queue);
+ list_del(&buf->vb.queue);
+ buf->vb.state = VIDEOBUF_ERROR;
+ wake_up(&buf->vb.done);
+ dprintk(1, "viu/0: [%p/%d] timeout\n", buf, buf->vb.i);
+ }
+
+ restart_video_queue(vidq);
+}
+
+/*
+ * Videobuf operations
+ */
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct viu_fh *fh = vq->priv_data;
+
+ *size = fh->width * fh->height * fh->fmt->depth >> 3;
+ if (*count == 0)
+ *count = 32;
+
+ while (*size * *count > VIU_VID_MEM_LIMIT * 1024 * 1024)
+ (*count)--;
+
+ dprintk(1, "%s, count=%d, size=%d\n", __func__, *count, *size);
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct viu_buf *buf)
+{
+ struct videobuf_buffer *vb = &buf->vb;
+ void *vaddr = NULL;
+
+ BUG_ON(in_interrupt());
+
+ videobuf_waiton(vq, &buf->vb, 0, 0);
+
+ if (vq->int_ops && vq->int_ops->vaddr)
+ vaddr = vq->int_ops->vaddr(vb);
+
+ if (vaddr)
+ videobuf_dma_contig_free(vq, &buf->vb);
+
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+inline int buffer_activate(struct viu_dev *dev, struct viu_buf *buf)
+{
+ struct viu_reg *vr = dev->vr;
+ int bpp;
+
+ /* setup the DMA base address */
+ reg_val.field_base_addr = videobuf_to_dma_contig(&buf->vb);
+
+ dprintk(1, "buffer_activate [%p/%d]: dma addr 0x%lx\n",
+ buf, buf->vb.i, (unsigned long)reg_val.field_base_addr);
+
+ /* interlace is on by default, set horizontal DMA increment */
+ reg_val.status_cfg = 0;
+ bpp = buf->fmt->depth >> 3;
+ switch (bpp) {
+ case 2:
+ reg_val.status_cfg &= ~MODE_32BIT;
+ reg_val.dma_inc = buf->vb.width * 2;
+ break;
+ case 4:
+ reg_val.status_cfg |= MODE_32BIT;
+ reg_val.dma_inc = buf->vb.width * 4;
+ break;
+ default:
+ dprintk(0, "doesn't support color depth(%d)\n",
+ bpp * 8);
+ return -EINVAL;
+ }
+
+ /* setup picture_count register */
+ reg_val.picture_count = (buf->vb.height / 2) << 16 |
+ buf->vb.width;
+
+ reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dev->capfield = buf->vb.field;
+
+ /* reset dma increment if needed */
+ if (!V4L2_FIELD_HAS_BOTH(buf->vb.field))
+ reg_val.dma_inc = 0;
+
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->picture_count, reg_val.picture_count);
+ out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+ mod_timer(&dev->vidq.timeout, jiffies + BUFFER_TIMEOUT);
+ return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ int rc;
+
+ BUG_ON(fh->fmt == NULL);
+
+ if (fh->width < 48 || fh->width > norm_maxw() ||
+ fh->height < 32 || fh->height > norm_maxh())
+ return -EINVAL;
+ buf->vb.size = (fh->width * fh->height * fh->fmt->depth) >> 3;
+ if (buf->vb.baddr != 0 && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ if (buf->fmt != fh->fmt ||
+ buf->vb.width != fh->width ||
+ buf->vb.height != fh->height ||
+ buf->vb.field != field) {
+ buf->fmt = fh->fmt;
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
+ }
+
+ if (buf->vb.state == VIDEOBUF_NEEDS_INIT) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc != 0)
+ goto fail;
+
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
+ buf->fmt = fh->fmt;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_dev *dev = fh->dev;
+ struct viu_dmaqueue *vidq = &dev->vidq;
+ struct viu_buf *prev;
+
+ if (!list_empty(&vidq->queued)) {
+ dprintk(1, "adding vb queue=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ dprintk(1, "vidq pointer 0x%p, queued 0x%p\n",
+ vidq, &vidq->queued);
+ dprintk(1, "dev %p, queued: self %p, next %p, head %p\n",
+ dev, &vidq->queued, vidq->queued.next,
+ vidq->queued.prev);
+ list_add_tail(&buf->vb.queue, &vidq->queued);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ dprintk(2, "[%p/%d] buffer_queue - append to queued\n",
+ buf, buf->vb.i);
+ } else if (list_empty(&vidq->active)) {
+ dprintk(1, "adding vb active=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
+ dprintk(2, "[%p/%d] buffer_queue - first active\n",
+ buf, buf->vb.i);
+
+ buffer_activate(dev, buf);
+ } else {
+ dprintk(1, "adding vb queue2=0x%08lx\n",
+ (unsigned long)&buf->vb.queue);
+ prev = list_entry(vidq->active.prev, struct viu_buf, vb.queue);
+ if (prev->vb.width == buf->vb.width &&
+ prev->vb.height == buf->vb.height &&
+ prev->fmt == buf->fmt) {
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ dprintk(2, "[%p/%d] buffer_queue - append to active\n",
+ buf, buf->vb.i);
+ } else {
+ list_add_tail(&buf->vb.queue, &vidq->queued);
+ buf->vb.state = VIDEOBUF_QUEUED;
+ dprintk(2, "[%p/%d] buffer_queue - first queued\n",
+ buf, buf->vb.i);
+ }
+ }
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct viu_buf *buf = container_of(vb, struct viu_buf, vb);
+ struct viu_fh *fh = vq->priv_data;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+
+ viu_stop_dma(dev);
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops viu_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/*
+ * IOCTL vidioc handling
+ */
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "viu");
+ strcpy(cap->card, "viu");
+ cap->version = VIU_VERSION;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_OVERLAY |
+ V4L2_CAP_READWRITE;
+ return 0;
+}
+
+static int vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ int index = f->index;
+
+ if (f->index > NUM_FORMATS)
+ return -EINVAL;
+
+ strlcpy(f->description, formats[index].name, sizeof(f->description));
+ f->pixelformat = formats[index].fourcc;
+ return 0;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+
+ f->fmt.pix.width = fh->width;
+ f->fmt.pix.height = fh->height;
+ f->fmt.pix.field = fh->vb_vidq.field;
+ f->fmt.pix.pixelformat = fh->fmt->pixelformat;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fh->fmt->depth) >> 3;
+ f->fmt.pix.sizeimage = fh->sizeimage;
+ return 0;
+}
+
+static int vidioc_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fmt *fmt;
+ enum v4l2_field field;
+ unsigned int maxw, maxh;
+
+ fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ if (!fmt) {
+ dprintk(1, "Fourcc format (0x%08x) invalid.",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ field = f->fmt.pix.field;
+
+ if (field == V4L2_FIELD_ANY) {
+ field = V4L2_FIELD_INTERLACED;
+ } else if (field != V4L2_FIELD_INTERLACED) {
+ dprintk(1, "Field type invalid.\n");
+ return -EINVAL;
+ }
+
+ maxw = norm_maxw();
+ maxh = norm_maxh();
+
+ f->fmt.pix.field = field;
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.height > maxh)
+ f->fmt.pix.height = maxh;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > maxw)
+ f->fmt.pix.width = maxw;
+ f->fmt.pix.width &= ~0x03;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+ int ret;
+
+ ret = vidioc_try_fmt_cap(file, fh, f);
+ if (ret < 0)
+ return ret;
+
+ fh->fmt = format_by_fourcc(f->fmt.pix.pixelformat);
+ fh->width = f->fmt.pix.width;
+ fh->height = f->fmt.pix.height;
+ fh->sizeimage = f->fmt.pix.sizeimage;
+ fh->vb_vidq.field = f->fmt.pix.field;
+ fh->type = f->type;
+ dprintk(1, "set to pixelformat '%4.6s'\n", (char *)&fh->fmt->name);
+ return 0;
+}
+
+static int vidioc_g_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+
+ f->fmt.win = fh->win;
+ return 0;
+}
+
+static int verify_preview(struct viu_dev *dev, struct v4l2_window *win)
+{
+ enum v4l2_field field;
+ int maxw, maxh;
+
+ if (dev->ovbuf.base == NULL)
+ return -EINVAL;
+ if (dev->ovfmt == NULL)
+ return -EINVAL;
+ if (win->w.width < 48 || win->w.height < 32)
+ return -EINVAL;
+
+ field = win->field;
+ maxw = dev->crop_current.width;
+ maxh = dev->crop_current.height;
+
+ if (field == V4L2_FIELD_ANY) {
+ field = (win->w.height > maxh/2)
+ ? V4L2_FIELD_INTERLACED
+ : V4L2_FIELD_TOP;
+ }
+ switch (field) {
+ case V4L2_FIELD_TOP:
+ case V4L2_FIELD_BOTTOM:
+ maxh = maxh / 2;
+ break;
+ case V4L2_FIELD_INTERLACED:
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ win->field = field;
+ if (win->w.width > maxw)
+ win->w.width = maxw;
+ if (win->w.height > maxh)
+ win->w.height = maxh;
+ return 0;
+}
+
+inline void viu_activate_overlay(struct viu_reg *viu_reg)
+{
+ struct viu_reg *vr = viu_reg;
+
+ out_be32(&vr->field_base_addr, reg_val.field_base_addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->picture_count, reg_val.picture_count);
+}
+
+static int viu_start_preview(struct viu_dev *dev, struct viu_fh *fh)
+{
+ int bpp;
+
+ dprintk(1, "%s %dx%d %s\n", __func__,
+ fh->win.w.width, fh->win.w.height, dev->ovfmt->name);
+
+ reg_val.status_cfg = 0;
+
+ /* setup window */
+ reg_val.picture_count = (fh->win.w.height / 2) << 16 |
+ fh->win.w.width;
+
+ /* setup color depth and dma increment */
+ bpp = dev->ovfmt->depth / 8;
+ switch (bpp) {
+ case 2:
+ reg_val.status_cfg &= ~MODE_32BIT;
+ reg_val.dma_inc = fh->win.w.width * 2;
+ break;
+ case 4:
+ reg_val.status_cfg |= MODE_32BIT;
+ reg_val.dma_inc = fh->win.w.width * 4;
+ break;
+ default:
+ dprintk(0, "device doesn't support color depth(%d)\n",
+ bpp * 8);
+ return -EINVAL;
+ }
+
+ dev->ovfield = fh->win.field;
+ if (!V4L2_FIELD_HAS_BOTH(dev->ovfield))
+ reg_val.dma_inc = 0;
+
+ reg_val.status_cfg |= DMA_ACT | INT_DMA_END_EN | INT_FIELD_EN;
+
+ /* setup the base address of the overlay buffer */
+ reg_val.field_base_addr = (u32)dev->ovbuf.base;
+
+ dev->ovenable = 1;
+ viu_activate_overlay(dev->vr);
+
+ /* start dma */
+ viu_start_dma(dev);
+ return 0;
+}
+
+static int vidioc_s_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = (struct viu_dev *)fh->dev;
+ unsigned long flags;
+ int err;
+
+ err = verify_preview(dev, &f->fmt.win);
+ if (err)
+ return err;
+
+ mutex_lock(&dev->lock);
+ fh->win = f->fmt.win;
+
+ spin_lock_irqsave(&dev->slock, flags);
+ viu_start_preview(dev, fh);
+ spin_unlock_irqrestore(&dev->slock, flags);
+ mutex_unlock(&dev->lock);
+ return 0;
+}
+
+static int vidioc_try_fmt_overlay(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ return 0;
+}
+
+int vidioc_g_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
+ struct v4l2_framebuffer *fb = arg;
+
+ *fb = dev->ovbuf;
+ fb->capability = V4L2_FBUF_CAP_LIST_CLIPPING;
+ return 0;
+}
+
+int vidioc_s_fbuf(struct file *file, void *priv, struct v4l2_framebuffer *arg)
+{
+ struct viu_fh *fh = priv;
+ struct viu_dev *dev = fh->dev;
+ struct v4l2_framebuffer *fb = arg;
+ struct viu_fmt *fmt;
+
+ if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RAWIO))
+ return -EPERM;
+
+ /* check args */
+ fmt = format_by_fourcc(fb->fmt.pixelformat);
+ if (fmt == NULL)
+ return -EINVAL;
+
+ /* ok, accept it */
+ dev->ovbuf = *fb;
+ dev->ovfmt = fmt;
+ if (dev->ovbuf.fmt.bytesperline == 0) {
+ dev->ovbuf.fmt.bytesperline =
+ dev->ovbuf.fmt.width * fmt->depth / 8;
+ }
+ return 0;
+}
+
+static int vidioc_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_reqbufs(&fh->vb_vidq, p);
+}
+
+static int vidioc_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_querybuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_qbuf(&fh->vb_vidq, p);
+}
+
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
+{
+ struct viu_fh *fh = priv;
+
+ return videobuf_dqbuf(&fh->vb_vidq, p,
+ file->f_flags & O_NONBLOCK);
+}
+
+static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct viu_fh *fh = priv;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (fh->type != i)
+ return -EINVAL;
+
+ viu_start_dma(fh->dev);
+
+ return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
+{
+ struct viu_fh *fh = priv;
+
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (fh->type != i)
+ return -EINVAL;
+
+ viu_stop_dma(fh->dev);
+
+ return videobuf_streamoff(&fh->vb_vidq);
+}
+
+#define decoder_call(viu, o, f, args...) \
+ v4l2_subdev_call(viu->decoder, o, f, ##args)
+
+static int vidioc_querystd(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct viu_fh *fh = priv;
+
+ decoder_call(fh->dev, video, querystd, std_id);
+ return 0;
+}
+
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct viu_fh *fh = priv;
+
+ fh->dev->std = *id;
+ decoder_call(fh->dev, core, s_std, *id);
+ return 0;
+}
+
+static int vidioc_g_std(struct file *file, void *priv, v4l2_std_id *std_id)
+{
+ struct viu_fh *fh = priv;
+
+ *std_id = fh->dev->std;
+ return 0;
+}
+
+/* only one input in this driver */
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct viu_fh *fh = priv;
+
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = fh->dev->vdev->tvnorms;
+ strcpy(inp->name, "Camera");
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct viu_fh *fh = priv;
+
+ if (i > 1)
+ return -EINVAL;
+
+ decoder_call(fh->dev, video, s_routing, i, 0, 0);
+ return 0;
+}
+
+/* Controls */
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (qc->id && qc->id == viu_qctrl[i].id) {
+ memcpy(qc, &(viu_qctrl[i]), sizeof(*qc));
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (ctrl->id == viu_qctrl[i].id) {
+ ctrl->value = qctl_regs[i];
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++) {
+ if (ctrl->id == viu_qctrl[i].id) {
+ if (ctrl->value < viu_qctrl[i].minimum
+ || ctrl->value > viu_qctrl[i].maximum)
+ return -ERANGE;
+ qctl_regs[i] = ctrl->value;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
+inline void viu_activate_next_buf(struct viu_dev *dev,
+ struct viu_dmaqueue *viuq)
+{
+ struct viu_dmaqueue *vidq = viuq;
+ struct viu_buf *buf;
+
+ /* launch another DMA operation for an active/queued buffer */
+ if (!list_empty(&vidq->active)) {
+ buf = list_entry(vidq->active.next, struct viu_buf,
+ vb.queue);
+ dprintk(1, "start another queued buffer: 0x%p\n", buf);
+ buffer_activate(dev, buf);
+ } else if (!list_empty(&vidq->queued)) {
+ buf = list_entry(vidq->queued.next, struct viu_buf,
+ vb.queue);
+ list_del(&buf->vb.queue);
+
+ dprintk(1, "start another queued buffer: 0x%p\n", buf);
+ list_add_tail(&buf->vb.queue, &vidq->active);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ buffer_activate(dev, buf);
+ }
+}
+
+inline void viu_default_settings(struct viu_reg *viu_reg)
+{
+ struct viu_reg *vr = viu_reg;
+
+ out_be32(&vr->luminance, 0x9512A254);
+ out_be32(&vr->chroma_r, 0x03310000);
+ out_be32(&vr->chroma_g, 0x06600F38);
+ out_be32(&vr->chroma_b, 0x00000409);
+ out_be32(&vr->alpha, 0x000000ff);
+ out_be32(&vr->req_alarm, 0x00000090);
+ dprintk(1, "status reg: 0x%08x, field base: 0x%08x\n",
+ in_be32(&vr->status_cfg), in_be32(&vr->field_base_addr));
+}
+
+static void viu_overlay_intr(struct viu_dev *dev, u32 status)
+{
+ struct viu_reg *vr = dev->vr;
+
+ if (status & INT_DMA_END_STATUS)
+ dev->dma_done = 1;
+
+ if (status & INT_FIELD_STATUS) {
+ if (dev->dma_done) {
+ u32 addr = reg_val.field_base_addr;
+
+ dev->dma_done = 0;
+ if (status & FIELD_NO)
+ addr += reg_val.dma_inc;
+
+ out_be32(&vr->field_base_addr, addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ } else if (status & INT_VSYNC_STATUS) {
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ }
+ }
+}
+
+static void viu_capture_intr(struct viu_dev *dev, u32 status)
+{
+ struct viu_dmaqueue *vidq = &dev->vidq;
+ struct viu_reg *vr = dev->vr;
+ struct viu_buf *buf;
+ int field_num;
+ int need_two;
+ int dma_done = 0;
+
+ field_num = status & FIELD_NO;
+ need_two = V4L2_FIELD_HAS_BOTH(dev->capfield);
+
+ if (status & INT_DMA_END_STATUS) {
+ dma_done = 1;
+ if (((field_num == 0) && (dev->field == 0)) ||
+ (field_num && (dev->field == 1)))
+ dev->field++;
+ }
+
+ if (status & INT_FIELD_STATUS) {
+ dprintk(1, "irq: field %d, done %d\n",
+ !!field_num, dma_done);
+ if (unlikely(dev->first)) {
+ if (field_num == 0) {
+ dev->first = 0;
+ dprintk(1, "activate first buf\n");
+ viu_activate_next_buf(dev, vidq);
+ } else
+ dprintk(1, "wait field 0\n");
+ return;
+ }
+
+ /* setup buffer address for next dma operation */
+ if (!list_empty(&vidq->active)) {
+ u32 addr = reg_val.field_base_addr;
+
+ if (field_num && need_two) {
+ addr += reg_val.dma_inc;
+ dprintk(1, "field 1, 0x%lx, dev field %d\n",
+ (unsigned long)addr, dev->field);
+ }
+ out_be32(&vr->field_base_addr, addr);
+ out_be32(&vr->dma_inc, reg_val.dma_inc);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) |
+ (status & INT_ALL_STATUS) |
+ reg_val.status_cfg);
+ return;
+ }
+ }
+
+ if (dma_done && field_num && (dev->field == 2)) {
+ dev->field = 0;
+ buf = list_entry(vidq->active.next,
+ struct viu_buf, vb.queue);
+ dprintk(1, "viu/0: [%p/%d] 0x%lx/0x%lx: dma complete\n",
+ buf, buf->vb.i,
+ (unsigned long)videobuf_to_dma_contig(&buf->vb),
+ (unsigned long)in_be32(&vr->field_base_addr));
+
+ if (waitqueue_active(&buf->vb.done)) {
+ list_del(&buf->vb.queue);
+ do_gettimeofday(&buf->vb.ts);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ wake_up(&buf->vb.done);
+ }
+ /* activate next dma buffer */
+ viu_activate_next_buf(dev, vidq);
+ }
+}
+
+static irqreturn_t viu_intr(int irq, void *dev_id)
+{
+ struct viu_dev *dev = (struct viu_dev *)dev_id;
+ struct viu_reg *vr = dev->vr;
+ u32 status;
+ u32 error;
+
+ status = in_be32(&vr->status_cfg);
+
+ if (status & INT_ERROR_STATUS) {
+ dev->irqs.error_irq++;
+ error = status & ERR_MASK;
+ if (error)
+ dprintk(1, "Err: error(%d), times:%d!\n",
+ error >> 4, dev->irqs.error_irq);
+ /* Clear interrupt error bit and error flags */
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) | INT_ERROR_STATUS);
+ }
+
+ if (status & INT_DMA_END_STATUS) {
+ dev->irqs.dma_end_irq++;
+ dev->dma_done = 1;
+ dprintk(2, "VIU DMA end interrupt times: %d\n",
+ dev->irqs.dma_end_irq);
+ }
+
+ if (status & INT_HSYNC_STATUS)
+ dev->irqs.hsync_irq++;
+
+ if (status & INT_FIELD_STATUS) {
+ dev->irqs.field_irq++;
+ dprintk(2, "VIU field interrupt times: %d\n",
+ dev->irqs.field_irq);
+ }
+
+ if (status & INT_VSTART_STATUS)
+ dev->irqs.vstart_irq++;
+
+ if (status & INT_VSYNC_STATUS) {
+ dev->irqs.vsync_irq++;
+ dprintk(2, "VIU vsync interrupt times: %d\n",
+ dev->irqs.vsync_irq);
+ }
+
+ /* clear all pending irqs */
+ status = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg,
+ (status & 0xffc0ffff) | (status & INT_ALL_STATUS));
+
+ if (dev->ovenable) {
+ viu_overlay_intr(dev, status);
+ return IRQ_HANDLED;
+ }
+
+ /* Capture mode */
+ viu_capture_intr(dev, status);
+ return IRQ_HANDLED;
+}
+
+/*
+ * File operations for the device
+ */
+static int viu_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct viu_dev *dev = video_get_drvdata(vdev);
+ struct viu_fh *fh;
+ struct viu_reg *vr;
+ int minor = vdev->minor;
+ u32 status_cfg;
+ int i;
+
+ dprintk(1, "viu: open (minor=%d)\n", minor);
+
+ dev->users++;
+ if (dev->users > 1) {
+ dev->users--;
+ return -EBUSY;
+ }
+
+ vr = dev->vr;
+
+ dprintk(1, "open minor=%d type=%s users=%d\n", minor,
+ v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
+
+ /* allocate and initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh) {
+ dev->users--;
+ return -ENOMEM;
+ }
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+ fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fh->fmt = format_by_fourcc(V4L2_PIX_FMT_RGB32);
+ fh->width = norm_maxw();
+ fh->height = norm_maxh();
+ dev->crop_current.width = fh->width;
+ dev->crop_current.height = fh->height;
+
+ /* Put all controls at a sane state */
+ for (i = 0; i < ARRAY_SIZE(viu_qctrl); i++)
+ qctl_regs[i] = viu_qctrl[i].default_value;
+
+ dprintk(1, "Open: fh=0x%08lx, dev=0x%08lx, dev->vidq=0x%08lx\n",
+ (unsigned long)fh, (unsigned long)dev,
+ (unsigned long)&dev->vidq);
+ dprintk(1, "Open: list_empty queued=%d\n",
+ list_empty(&dev->vidq.queued));
+ dprintk(1, "Open: list_empty active=%d\n",
+ list_empty(&dev->vidq.active));
+
+ viu_default_settings(vr);
+
+ status_cfg = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg,
+ status_cfg & ~(INT_VSYNC_EN | INT_HSYNC_EN |
+ INT_FIELD_EN | INT_VSTART_EN |
+ INT_DMA_END_EN | INT_ERROR_EN | INT_ECC_EN));
+
+ status_cfg = in_be32(&vr->status_cfg);
+ out_be32(&vr->status_cfg, status_cfg | INT_ALL_STATUS);
+
+ spin_lock_init(&fh->vbq_lock);
+ videobuf_queue_dma_contig_init(&fh->vb_vidq, &viu_video_qops,
+ dev->dev, &fh->vbq_lock,
+ fh->type, V4L2_FIELD_INTERLACED,
+ sizeof(struct viu_buf), fh, NULL);
+ return 0;
+}
+
+static ssize_t viu_read(struct file *file, char __user *data, size_t count,
+ loff_t *ppos)
+{
+ struct viu_fh *fh = file->private_data;
+ struct viu_dev *dev = fh->dev;
+ int ret = 0;
+
+ dprintk(2, "%s\n", __func__);
+ if (dev->ovenable)
+ dev->ovenable = 0;
+
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ viu_start_dma(dev);
+ ret = videobuf_read_stream(&fh->vb_vidq, data, count,
+ ppos, 0, file->f_flags & O_NONBLOCK);
+ return ret;
+ }
+ return 0;
+}
+
+static unsigned int viu_poll(struct file *file, struct poll_table_struct *wait)
+{
+ struct viu_fh *fh = file->private_data;
+ struct videobuf_queue *q = &fh->vb_vidq;
+
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
+
+ return videobuf_poll_stream(file, q, wait);
+}
+
+static int viu_release(struct file *file)
+{
+ struct viu_fh *fh = file->private_data;
+ struct viu_dev *dev = fh->dev;
+ int minor = video_devdata(file)->minor;
+
+ viu_stop_dma(dev);
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ kfree(fh);
+
+ dev->users--;
+ dprintk(1, "close (minor=%d, users=%d)\n",
+ minor, dev->users);
+ return 0;
+}
+
+void viu_reset(struct viu_reg *reg)
+{
+ out_be32(&reg->status_cfg, 0);
+ out_be32(&reg->luminance, 0x9512a254);
+ out_be32(&reg->chroma_r, 0x03310000);
+ out_be32(&reg->chroma_g, 0x06600f38);
+ out_be32(&reg->chroma_b, 0x00000409);
+ out_be32(&reg->field_base_addr, 0);
+ out_be32(&reg->dma_inc, 0);
+ out_be32(&reg->picture_count, 0x01e002d0);
+ out_be32(&reg->req_alarm, 0x00000090);
+ out_be32(&reg->alpha, 0x000000ff);
+}
+
+static int viu_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct viu_fh *fh = file->private_data;
+ int ret;
+
+ dprintk(1, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+ ret = videobuf_mmap_mapper(&fh->vb_vidq, vma);
+
+ dprintk(1, "vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ ret);
+
+ return ret;
+}
+
+static struct v4l2_file_operations viu_fops = {
+ .owner = THIS_MODULE,
+ .open = viu_open,
+ .release = viu_release,
+ .read = viu_read,
+ .poll = viu_poll,
+ .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = viu_mmap,
+};
+
+static const struct v4l2_ioctl_ops viu_ioctl_ops = {
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_cap,
+ .vidioc_enum_fmt_vid_overlay = vidioc_enum_fmt,
+ .vidioc_g_fmt_vid_overlay = vidioc_g_fmt_overlay,
+ .vidioc_try_fmt_vid_overlay = vidioc_try_fmt_overlay,
+ .vidioc_s_fmt_vid_overlay = vidioc_s_fmt_overlay,
+ .vidioc_g_fbuf = vidioc_g_fbuf,
+ .vidioc_s_fbuf = vidioc_s_fbuf,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_g_std = vidioc_g_std,
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_querystd = vidioc_querystd,
+ .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_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+};
+
+static struct video_device viu_template = {
+ .name = "FSL viu",
+ .fops = &viu_fops,
+ .minor = -1,
+ .ioctl_ops = &viu_ioctl_ops,
+ .release = video_device_release,
+
+ .tvnorms = V4L2_STD_NTSC_M | V4L2_STD_PAL,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static int __devinit viu_of_probe(struct platform_device *op,
+ const struct of_device_id *match)
+{
+ struct viu_dev *viu_dev;
+ struct video_device *vdev;
+ struct resource r;
+ struct viu_reg __iomem *viu_regs;
+ struct i2c_adapter *ad;
+ int ret, viu_irq;
+
+ ret = of_address_to_resource(op->dev.of_node, 0, &r);
+ if (ret) {
+ dev_err(&op->dev, "Can't parse device node resource\n");
+ return -ENODEV;
+ }
+
+ viu_irq = irq_of_parse_and_map(op->dev.of_node, 0);
+ if (viu_irq == NO_IRQ) {
+ dev_err(&op->dev, "Error while mapping the irq\n");
+ return -EINVAL;
+ }
+
+ /* request mem region */
+ if (!devm_request_mem_region(&op->dev, r.start,
+ sizeof(struct viu_reg), DRV_NAME)) {
+ dev_err(&op->dev, "Error while requesting mem region\n");
+ ret = -EBUSY;
+ goto err;
+ }
+
+ /* remap registers */
+ viu_regs = devm_ioremap(&op->dev, r.start, sizeof(struct viu_reg));
+ if (!viu_regs) {
+ dev_err(&op->dev, "Can't map register set\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ /* Prepare our private structure */
+ viu_dev = devm_kzalloc(&op->dev, sizeof(struct viu_dev), GFP_ATOMIC);
+ if (!viu_dev) {
+ dev_err(&op->dev, "Can't allocate private structure\n");
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ viu_dev->vr = viu_regs;
+ viu_dev->irq = viu_irq;
+ viu_dev->dev = &op->dev;
+
+ /* init video dma queues */
+ INIT_LIST_HEAD(&viu_dev->vidq.active);
+ INIT_LIST_HEAD(&viu_dev->vidq.queued);
+
+ /* initialize locks */
+ mutex_init(&viu_dev->lock);
+
+ snprintf(viu_dev->v4l2_dev.name,
+ sizeof(viu_dev->v4l2_dev.name), "%s", "VIU");
+ ret = v4l2_device_register(viu_dev->dev, &viu_dev->v4l2_dev);
+ if (ret < 0) {
+ dev_err(&op->dev, "v4l2_device_register() failed: %d\n", ret);
+ goto err;
+ }
+
+ ad = i2c_get_adapter(0);
+ viu_dev->decoder = v4l2_i2c_new_subdev(&viu_dev->v4l2_dev, ad,
+ "saa7113", VIU_VIDEO_DECODER_ADDR, NULL);
+
+ viu_dev->vidq.timeout.function = viu_vid_timeout;
+ viu_dev->vidq.timeout.data = (unsigned long)viu_dev;
+ init_timer(&viu_dev->vidq.timeout);
+ viu_dev->first = 1;
+
+ /* Allocate memory for video device */
+ vdev = video_device_alloc();
+ if (vdev == NULL) {
+ ret = -ENOMEM;
+ goto err_vdev;
+ }
+
+ memcpy(vdev, &viu_template, sizeof(viu_template));
+
+ vdev->v4l2_dev = &viu_dev->v4l2_dev;
+
+ viu_dev->vdev = vdev;
+
+ video_set_drvdata(viu_dev->vdev, viu_dev);
+
+ ret = video_register_device(viu_dev->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret < 0) {
+ video_device_release(viu_dev->vdev);
+ goto err_vdev;
+ }
+
+ /* enable VIU clock */
+ viu_dev->clk = clk_get(&op->dev, "viu_clk");
+ if (IS_ERR(viu_dev->clk)) {
+ dev_err(&op->dev, "failed to find the clock module!\n");
+ ret = -ENODEV;
+ goto err_clk;
+ } else {
+ clk_enable(viu_dev->clk);
+ }
+
+ /* reset VIU module */
+ viu_reset(viu_dev->vr);
+
+ /* install interrupt handler */
+ if (request_irq(viu_dev->irq, viu_intr, 0, "viu", (void *)viu_dev)) {
+ dev_err(&op->dev, "Request VIU IRQ failed.\n");
+ ret = -ENODEV;
+ goto err_irq;
+ }
+
+ dev_info(&op->dev, "Freescale VIU Video Capture Board\n");
+ return ret;
+
+err_irq:
+ clk_disable(viu_dev->clk);
+ clk_put(viu_dev->clk);
+err_clk:
+ video_unregister_device(viu_dev->vdev);
+err_vdev:
+ i2c_put_adapter(ad);
+ v4l2_device_unregister(&viu_dev->v4l2_dev);
+err:
+ irq_dispose_mapping(viu_irq);
+ return ret;
+}
+
+static int __devexit viu_of_remove(struct platform_device *op)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+ struct v4l2_subdev *sdev = list_entry(v4l2_dev->subdevs.next,
+ struct v4l2_subdev, list);
+ struct i2c_client *client = v4l2_get_subdevdata(sdev);
+
+ free_irq(dev->irq, (void *)dev);
+ irq_dispose_mapping(dev->irq);
+
+ clk_disable(dev->clk);
+ clk_put(dev->clk);
+
+ video_unregister_device(dev->vdev);
+ i2c_put_adapter(client->adapter);
+ v4l2_device_unregister(&dev->v4l2_dev);
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int viu_suspend(struct platform_device *op, pm_message_t state)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+ clk_disable(dev->clk);
+ return 0;
+}
+
+static int viu_resume(struct platform_device *op)
+{
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(&op->dev);
+ struct viu_dev *dev = container_of(v4l2_dev, struct viu_dev, v4l2_dev);
+
+ clk_enable(dev->clk);
+ return 0;
+}
+#endif
+
+/*
+ * Initialization and module stuff
+ */
+static struct of_device_id mpc512x_viu_of_match[] = {
+ {
+ .compatible = "fsl,mpc5121-viu",
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(of, mpc512x_viu_of_match);
+
+static struct of_platform_driver viu_of_platform_driver = {
+ .probe = viu_of_probe,
+ .remove = __devexit_p(viu_of_remove),
+#ifdef CONFIG_PM
+ .suspend = viu_suspend,
+ .resume = viu_resume,
+#endif
+ .driver = {
+ .name = DRV_NAME,
+ .owner = THIS_MODULE,
+ .of_match_table = mpc512x_viu_of_match,
+ },
+};
+
+static int __init viu_init(void)
+{
+ return of_register_platform_driver(&viu_of_platform_driver);
+}
+
+static void __exit viu_exit(void)
+{
+ of_unregister_platform_driver(&viu_of_platform_driver);
+}
+
+module_init(viu_init);
+module_exit(viu_exit);
+
+MODULE_DESCRIPTION("Freescale Video-In(VIU)");
+MODULE_AUTHOR("Hongjun Chen");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/gspca/Kconfig b/drivers/media/video/gspca/Kconfig
index 5d920e584de7..dda56ff834f4 100644
--- a/drivers/media/video/gspca/Kconfig
+++ b/drivers/media/video/gspca/Kconfig
@@ -77,6 +77,15 @@ config USB_GSPCA_JEILINJ
To compile this driver as a module, choose M here: the
module will be called gspca_jeilinj.
+config USB_GSPCA_KONICA
+ tristate "Konica USB Camera V4L2 driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the Konica chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_konica.
+
config USB_GSPCA_MARS
tristate "Mars USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -246,6 +255,15 @@ config USB_GSPCA_SPCA561
To compile this driver as a module, choose M here: the
module will be called gspca_spca561.
+config USB_GSPCA_SPCA1528
+ tristate "SPCA1528 USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SPCA1528 chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_spca1528.
+
config USB_GSPCA_SQ905
tristate "SQ Technologies SQ905 based USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -264,6 +282,15 @@ config USB_GSPCA_SQ905C
To compile this driver as a module, choose M here: the
module will be called gspca_sq905c.
+config USB_GSPCA_SQ930X
+ tristate "SQ Technologies SQ930X based USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for cameras based on the SQ930X chip.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_sq930x.
+
config USB_GSPCA_STK014
tristate "Syntek DV4000 (STK014) USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
@@ -319,6 +346,15 @@ config USB_GSPCA_VC032X
To compile this driver as a module, choose M here: the
module will be called gspca_vc032x.
+config USB_GSPCA_XIRLINK_CIT
+ tristate "Xirlink C-It USB Camera Driver"
+ depends on VIDEO_V4L2 && USB_GSPCA
+ help
+ Say Y here if you want support for Xirlink C-It bases cameras.
+
+ To compile this driver as a module, choose M here: the
+ module will be called gspca_xirlink_cit.
+
config USB_GSPCA_ZC3XX
tristate "ZC3XX USB Camera Driver"
depends on VIDEO_V4L2 && USB_GSPCA
diff --git a/drivers/media/video/gspca/Makefile b/drivers/media/video/gspca/Makefile
index 6e4cf1ce01c9..24e695b8b077 100644
--- a/drivers/media/video/gspca/Makefile
+++ b/drivers/media/video/gspca/Makefile
@@ -5,6 +5,7 @@ obj-$(CONFIG_USB_GSPCA_CPIA1) += gspca_cpia1.o
obj-$(CONFIG_USB_GSPCA_ETOMS) += gspca_etoms.o
obj-$(CONFIG_USB_GSPCA_FINEPIX) += gspca_finepix.o
obj-$(CONFIG_USB_GSPCA_JEILINJ) += gspca_jeilinj.o
+obj-$(CONFIG_USB_GSPCA_KONICA) += gspca_konica.o
obj-$(CONFIG_USB_GSPCA_MARS) += gspca_mars.o
obj-$(CONFIG_USB_GSPCA_MR97310A) += gspca_mr97310a.o
obj-$(CONFIG_USB_GSPCA_OV519) += gspca_ov519.o
@@ -23,14 +24,17 @@ obj-$(CONFIG_USB_GSPCA_SPCA505) += gspca_spca505.o
obj-$(CONFIG_USB_GSPCA_SPCA506) += gspca_spca506.o
obj-$(CONFIG_USB_GSPCA_SPCA508) += gspca_spca508.o
obj-$(CONFIG_USB_GSPCA_SPCA561) += gspca_spca561.o
+obj-$(CONFIG_USB_GSPCA_SPCA1528) += gspca_spca1528.o
obj-$(CONFIG_USB_GSPCA_SQ905) += gspca_sq905.o
obj-$(CONFIG_USB_GSPCA_SQ905C) += gspca_sq905c.o
+obj-$(CONFIG_USB_GSPCA_SQ930X) += gspca_sq930x.o
obj-$(CONFIG_USB_GSPCA_SUNPLUS) += gspca_sunplus.o
obj-$(CONFIG_USB_GSPCA_STK014) += gspca_stk014.o
obj-$(CONFIG_USB_GSPCA_STV0680) += gspca_stv0680.o
obj-$(CONFIG_USB_GSPCA_T613) += gspca_t613.o
obj-$(CONFIG_USB_GSPCA_TV8532) += gspca_tv8532.o
obj-$(CONFIG_USB_GSPCA_VC032X) += gspca_vc032x.o
+obj-$(CONFIG_USB_GSPCA_XIRLINK_CIT) += gspca_xirlink_cit.o
obj-$(CONFIG_USB_GSPCA_ZC3XX) += gspca_zc3xx.o
gspca_main-objs := gspca.o
@@ -40,6 +44,7 @@ gspca_cpia1-objs := cpia1.o
gspca_etoms-objs := etoms.o
gspca_finepix-objs := finepix.o
gspca_jeilinj-objs := jeilinj.o
+gspca_konica-objs := konica.o
gspca_mars-objs := mars.o
gspca_mr97310a-objs := mr97310a.o
gspca_ov519-objs := ov519.o
@@ -58,14 +63,17 @@ gspca_spca505-objs := spca505.o
gspca_spca506-objs := spca506.o
gspca_spca508-objs := spca508.o
gspca_spca561-objs := spca561.o
+gspca_spca1528-objs := spca1528.o
gspca_sq905-objs := sq905.o
gspca_sq905c-objs := sq905c.o
+gspca_sq930x-objs := sq930x.o
gspca_stk014-objs := stk014.o
gspca_stv0680-objs := stv0680.o
gspca_sunplus-objs := sunplus.o
gspca_t613-objs := t613.o
gspca_tv8532-objs := tv8532.o
gspca_vc032x-objs := vc032x.o
+gspca_xirlink_cit-objs := xirlink_cit.o
gspca_zc3xx-objs := zc3xx.o
obj-$(CONFIG_USB_M5602) += m5602/
diff --git a/drivers/media/video/gspca/benq.c b/drivers/media/video/gspca/benq.c
index fce8d9492641..a09c4709d613 100644
--- a/drivers/media/video/gspca/benq.c
+++ b/drivers/media/video/gspca/benq.c
@@ -62,7 +62,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
0,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w err %d", ret);
+ err("reg_w err %d", ret);
gspca_dev->usb_err = ret;
}
}
@@ -152,7 +152,8 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0x003c, 0x0005);
reg_w(gspca_dev, 0x003c, 0x0006);
reg_w(gspca_dev, 0x003c, 0x0007);
- usb_set_interface(gspca_dev->dev, gspca_dev->iface, gspca_dev->nbalt - 1);
+ usb_set_interface(gspca_dev->dev, gspca_dev->iface,
+ gspca_dev->nbalt - 1);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -180,7 +181,7 @@ static void sd_isoc_irq(struct urb *urb)
if (gspca_dev->frozen)
return;
#endif
- PDEBUG(D_ERR|D_PACK, "urb status: %d", urb->status);
+ err("urb status: %d", urb->status);
return;
}
@@ -208,8 +209,7 @@ static void sd_isoc_irq(struct urb *urb)
if (st == 0)
st = urb->iso_frame_desc[i].status;
if (st) {
- PDEBUG(D_ERR,
- "ISOC data error: [%d] status=%d",
+ err("ISOC data error: [%d] status=%d",
i, st);
gspca_dev->last_packet_type = DISCARD_PACKET;
continue;
@@ -256,10 +256,10 @@ static void sd_isoc_irq(struct urb *urb)
/* resubmit the URBs */
st = usb_submit_urb(urb0, GFP_ATOMIC);
if (st < 0)
- PDEBUG(D_ERR|D_PACK, "usb_submit_urb(0) ret %d", st);
+ err("usb_submit_urb(0) ret %d", st);
st = usb_submit_urb(urb, GFP_ATOMIC);
if (st < 0)
- PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+ err("usb_submit_urb() ret %d", st);
}
/* sub-driver description */
@@ -276,7 +276,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x04a5, 0x3035)},
{}
};
@@ -304,18 +304,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- info("registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- info("deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/conex.c b/drivers/media/video/gspca/conex.c
index 19fe6b24c9a3..8b398493f96b 100644
--- a/drivers/media/video/gspca/conex.c
+++ b/drivers/media/video/gspca/conex.c
@@ -41,7 +41,7 @@ struct sd {
#define QUALITY_MAX 60
#define QUALITY_DEF 40
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
@@ -687,7 +687,7 @@ static void cx11646_jpeg(struct gspca_dev*gspca_dev)
reg_w_val(gspca_dev, 0x00c0, 0x00);
reg_r(gspca_dev, 0x0001, 1);
length = 8;
- switch (gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv) {
+ switch (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv) {
case 0:
for (i = 0; i < 27; i++) {
if (i == 26)
@@ -845,9 +845,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -862,11 +859,8 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev)
{
- struct sd *sd = (struct sd *) gspca_dev;
int retry = 50;
- kfree(sd->jpeg_hdr);
-
if (!gspca_dev->present)
return;
reg_w_val(gspca_dev, 0x0000, 0x00);
@@ -907,7 +901,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static void setbrightness(struct gspca_dev*gspca_dev)
+static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 regE5cbx[] = { 0x88, 0x00, 0xd4, 0x01, 0x88, 0x01, 0x01, 0x01 };
@@ -930,7 +924,7 @@ static void setbrightness(struct gspca_dev*gspca_dev)
reg_w_val(gspca_dev, 0x0070, reg70);
}
-static void setcontrast(struct gspca_dev*gspca_dev)
+static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 regE5acx[] = { 0x88, 0x0a, 0x0c, 0x01 }; /* seem MSB */
@@ -1046,14 +1040,14 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0572, 0x0041)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
@@ -1074,17 +1068,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/cpia1.c b/drivers/media/video/gspca/cpia1.c
index 58b696f455be..4bf2cab98d64 100644
--- a/drivers/media/video/gspca/cpia1.c
+++ b/drivers/media/video/gspca/cpia1.c
@@ -1,7 +1,7 @@
/*
* cpia CPiA (1) gspca driver
*
- * Copyright (C) 2010 Hans de Goede <hdgoede@redhat.com>
+ * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
*
* This module is adapted from the in kernel v4l1 cpia driver which is :
*
@@ -30,14 +30,14 @@
#include "gspca.h"
-MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Vision CPiA");
MODULE_LICENSE("GPL");
/* constant value's */
#define MAGIC_0 0x19
#define MAGIC_1 0x68
-#define DATA_IN 0xC0
+#define DATA_IN 0xc0
#define DATA_OUT 0x40
#define VIDEOSIZE_QCIF 0 /* 176x144 */
#define VIDEOSIZE_CIF 1 /* 352x288 */
@@ -373,9 +373,14 @@ 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_setcomptarget(struct gspca_dev *gspca_dev, __s32 val);
static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val);
static const struct ctrl sd_ctrls[] = {
{
+#define BRIGHTNESS_IDX 0
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -390,6 +395,7 @@ static const struct ctrl sd_ctrls[] = {
.set = sd_setbrightness,
.get = sd_getbrightness,
},
+#define CONTRAST_IDX 1
{
{
.id = V4L2_CID_CONTRAST,
@@ -404,6 +410,7 @@ static const struct ctrl sd_ctrls[] = {
.set = sd_setcontrast,
.get = sd_getcontrast,
},
+#define SATURATION_IDX 2
{
{
.id = V4L2_CID_SATURATION,
@@ -418,6 +425,7 @@ static const struct ctrl sd_ctrls[] = {
.set = sd_setsaturation,
.get = sd_getsaturation,
},
+#define POWER_LINE_FREQUENCY_IDX 3
{
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
@@ -432,6 +440,37 @@ static const struct ctrl sd_ctrls[] = {
.set = sd_setfreq,
.get = sd_getfreq,
},
+#define ILLUMINATORS_1_IDX 4
+ {
+ {
+ .id = V4L2_CID_ILLUMINATORS_1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Illuminator 1",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define ILLUMINATORS_1_DEF 0
+ .default_value = ILLUMINATORS_1_DEF,
+ },
+ .set = sd_setilluminator1,
+ .get = sd_getilluminator1,
+ },
+#define ILLUMINATORS_2_IDX 5
+ {
+ {
+ .id = V4L2_CID_ILLUMINATORS_2,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Illuminator 2",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define ILLUMINATORS_2_DEF 0
+ .default_value = ILLUMINATORS_2_DEF,
+ },
+ .set = sd_setilluminator2,
+ .get = sd_getilluminator2,
+ },
+#define COMP_TARGET_IDX 6
{
{
#define V4L2_CID_COMP_TARGET V4L2_CID_PRIVATE_BASE
@@ -510,7 +549,7 @@ retry:
gspca_dev->usb_buf, databytes, 1000);
if (ret < 0)
- PDEBUG(D_ERR, "usb_control_msg %02x, error %d", command[1],
+ err("usb_control_msg %02x, error %d", command[1],
ret);
if (ret == -EPIPE && retries > 0) {
@@ -621,9 +660,9 @@ static int do_command(struct gspca_dev *gspca_dev, u16 command,
if (sd->params.qx3.button) {
/* button pressed - unlock the latch */
do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
- 3, 0xDF, 0xDF, 0);
+ 3, 0xdf, 0xdf, 0);
do_command(gspca_dev, CPIA_COMMAND_WriteMCPort,
- 3, 0xFF, 0xFF, 0);
+ 3, 0xff, 0xff, 0);
}
/* test whether microscope is cradled */
@@ -790,7 +829,7 @@ static int goto_low_power(struct gspca_dev *gspca_dev)
if (ret)
return ret;
- do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
+ ret = do_command(gspca_dev, CPIA_COMMAND_GetCameraStatus, 0, 0, 0, 0);
if (ret)
return ret;
@@ -1059,7 +1098,6 @@ static int command_resume(struct gspca_dev *gspca_dev)
0, sd->params.streamStartLine, 0, 0);
}
-#if 0 /* Currently unused */
static int command_setlights(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1072,14 +1110,13 @@ static int command_setlights(struct gspca_dev *gspca_dev)
p2 = (sd->params.qx3.toplight == 0) << 3;
ret = do_command(gspca_dev, CPIA_COMMAND_WriteVCReg,
- 0x90, 0x8F, 0x50, 0);
+ 0x90, 0x8f, 0x50, 0);
if (ret)
return ret;
return do_command(gspca_dev, CPIA_COMMAND_WriteMCPort, 2, 0,
- p1 | p2 | 0xE0, 0);
+ p1 | p2 | 0xe0, 0);
}
-#endif
static int set_flicker(struct gspca_dev *gspca_dev, int on, int apply)
{
@@ -1236,7 +1273,7 @@ static void monitor_exposure(struct gspca_dev *gspca_dev)
cmd[7] = 0;
ret = cpia_usb_transferCmd(gspca_dev, cmd);
if (ret) {
- PDEBUG(D_ERR, "ReadVPRegs(30,4,9,8) - failed: %d", ret);
+ err("ReadVPRegs(30,4,9,8) - failed: %d", ret);
return;
}
exp_acc = gspca_dev->usb_buf[0];
@@ -1716,7 +1753,9 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
+#ifdef GSPCA_DEBUG
struct sd *sd = (struct sd *) gspca_dev;
+#endif
int ret;
/* Start / Stop the camera to make sure we are talking to
@@ -1726,6 +1765,14 @@ static int sd_init(struct gspca_dev *gspca_dev)
if (ret)
return ret;
+ /* Ensure the QX3 illuminators' states are restored upon resume,
+ or disable the illuminator controls, if this isn't a QX3 */
+ if (sd->params.qx3.qx3_detected)
+ command_setlights(gspca_dev);
+ else
+ gspca_dev->ctrl_dis |=
+ ((1 << ILLUMINATORS_1_IDX) | (1 << ILLUMINATORS_2_IDX));
+
sd_stopN(gspca_dev);
PDEBUG(D_PROBE, "CPIA Version: %d.%02d (%d.%d)",
@@ -1760,22 +1807,19 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data[25] == sd->params.roi.colEnd &&
data[26] == sd->params.roi.rowStart &&
data[27] == sd->params.roi.rowEnd) {
- struct gspca_frame *frame = gspca_get_i_frame(gspca_dev);
+ u8 *image;
atomic_set(&sd->cam_exposure, data[39] * 2);
atomic_set(&sd->fps, data[41]);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
/* Check for proper EOF for last frame */
- if ((frame->data_end - frame->data) > 4 &&
- frame->data_end[-4] == 0xff &&
- frame->data_end[-3] == 0xff &&
- frame->data_end[-2] == 0xff &&
- frame->data_end[-1] == 0xff)
+ image = gspca_dev->image;
+ if (image != NULL &&
+ gspca_dev->image_len > 4 &&
+ image[gspca_dev->image_len - 4] == 0xff &&
+ image[gspca_dev->image_len - 3] == 0xff &&
+ image[gspca_dev->image_len - 2] == 0xff &&
+ image[gspca_dev->image_len - 1] == 0xff)
gspca_frame_add(gspca_dev, LAST_PACKET,
NULL, 0);
@@ -1932,6 +1976,72 @@ static int sd_getcomptarget(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_setilluminator(struct gspca_dev *gspca_dev, __s32 val, int n)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ if (!sd->params.qx3.qx3_detected)
+ return -EINVAL;
+
+ switch (n) {
+ case 1:
+ sd->params.qx3.bottomlight = val ? 1 : 0;
+ break;
+ case 2:
+ sd->params.qx3.toplight = val ? 1 : 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ ret = command_setlights(gspca_dev);
+ if (ret && ret != -EINVAL)
+ ret = -EBUSY;
+
+ return ret;
+}
+
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
+{
+ return sd_setilluminator(gspca_dev, val, 1);
+}
+
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
+{
+ return sd_setilluminator(gspca_dev, val, 2);
+}
+
+static int sd_getilluminator(struct gspca_dev *gspca_dev, __s32 *val, int n)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (!sd->params.qx3.qx3_detected)
+ return -EINVAL;
+
+ switch (n) {
+ case 1:
+ *val = sd->params.qx3.bottomlight;
+ break;
+ case 2:
+ *val = sd->params.qx3.toplight;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sd_getilluminator1(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ return sd_getilluminator(gspca_dev, val, 1);
+}
+
+static int sd_getilluminator2(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ return sd_getilluminator(gspca_dev, val, 2);
+}
+
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
@@ -1978,7 +2088,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0553, 0x0002)},
{USB_DEVICE(0x0813, 0x0001)},
{}
@@ -2007,17 +2117,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/etoms.c b/drivers/media/video/gspca/etoms.c
index ecd4d743d2bc..4b2c483fce6f 100644
--- a/drivers/media/video/gspca/etoms.c
+++ b/drivers/media/video/gspca/etoms.c
@@ -710,9 +710,9 @@ static void Et_setgainG(struct gspca_dev *gspca_dev, __u8 gain)
}
#define BLIMIT(bright) \
- (__u8)((bright > 0x1f)?0x1f:((bright < 4)?3:bright))
+ (u8)((bright > 0x1f) ? 0x1f : ((bright < 4) ? 3 : bright))
#define LIMIT(color) \
- (unsigned char)((color > 0xff)?0xff:((color < 0)?0:color))
+ (u8)((color > 0xff) ? 0xff : ((color < 0) ? 0 : color))
static void do_autogain(struct gspca_dev *gspca_dev)
{
@@ -864,7 +864,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x102c, 0x6151), .driver_info = SENSOR_PAS106},
#if !defined CONFIG_USB_ET61X251 && !defined CONFIG_USB_ET61X251_MODULE
{USB_DEVICE(0x102c, 0x6251), .driver_info = SENSOR_TAS5130CXX},
@@ -875,7 +875,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
@@ -896,18 +896,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/finepix.c b/drivers/media/video/gspca/finepix.c
index 5d90e7448579..987b4b69d7ab 100644
--- a/drivers/media/video/gspca/finepix.c
+++ b/drivers/media/video/gspca/finepix.c
@@ -182,7 +182,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* Init the device */
ret = command(gspca_dev, 0);
if (ret < 0) {
- PDEBUG(D_STREAM, "init failed %d", ret);
+ err("init failed %d", ret);
return ret;
}
@@ -194,14 +194,14 @@ static int sd_start(struct gspca_dev *gspca_dev)
FPIX_MAX_TRANSFER, &len,
FPIX_TIMEOUT);
if (ret < 0) {
- PDEBUG(D_STREAM, "usb_bulk_msg failed %d", ret);
+ err("usb_bulk_msg failed %d", ret);
return ret;
}
/* Request a frame, but don't read it */
ret = command(gspca_dev, 1);
if (ret < 0) {
- PDEBUG(D_STREAM, "frame request failed %d", ret);
+ err("frame request failed %d", ret);
return ret;
}
@@ -229,7 +229,7 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
}
/* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x04cb, 0x0104)},
{USB_DEVICE(0x04cb, 0x0109)},
{USB_DEVICE(0x04cb, 0x010b)},
@@ -291,19 +291,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/gl860/gl860-mi2020.c b/drivers/media/video/gspca/gl860/gl860-mi2020.c
index 7c31b4f2abea..2edda6b7d653 100644
--- a/drivers/media/video/gspca/gl860/gl860-mi2020.c
+++ b/drivers/media/video/gspca/gl860/gl860-mi2020.c
@@ -1,6 +1,7 @@
/* Subdriver for the GL860 chip with the MI2020 sensor
- * Author Olivier LORIN, from Ice/Soro2005's logs(A), Fret_saw/Hulkie's
- * logs(B) and Tricid"s logs(C). With the help of Kytrix/BUGabundo/Blazercist.
+ * Author Olivier LORIN, from logs by Iceman/Soro2005 + Fret_saw/Hulkie/Tricid
+ * with the help of Kytrix/BUGabundo/Blazercist.
+ * Driver achieved thanks to a webcam gift by Kytrix.
*
* 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
@@ -20,47 +21,70 @@
#include "gl860.h"
+static u8 dat_wbal1[] = {0x8c, 0xa2, 0x0c};
+
static u8 dat_bright1[] = {0x8c, 0xa2, 0x06};
static u8 dat_bright3[] = {0x8c, 0xa1, 0x02};
static u8 dat_bright4[] = {0x90, 0x00, 0x0f};
static u8 dat_bright5[] = {0x8c, 0xa1, 0x03};
static u8 dat_bright6[] = {0x90, 0x00, 0x05};
-static u8 dat_dummy1[] = {0x90, 0x00, 0x06};
-/*static u8 dummy2[] = {0x8c, 0xa1, 0x02};*/
-/*static u8 dummy3[] = {0x90, 0x00, 0x1f};*/
-
static u8 dat_hvflip1[] = {0x8c, 0x27, 0x19};
static u8 dat_hvflip3[] = {0x8c, 0x27, 0x3b};
static u8 dat_hvflip5[] = {0x8c, 0xa1, 0x03};
static u8 dat_hvflip6[] = {0x90, 0x00, 0x06};
+static struct idxdata tbl_middle_hvflip_low[] = {
+ {0x33, "\x90\x00\x06"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x90\x00\x06"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x90\x00\x06"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x90\x00\x06"},
+ {6, "\xff\xff\xff"},
+};
+
+static struct idxdata tbl_middle_hvflip_big[] = {
+ {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa1\x20"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+ {102, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa1\x20"},
+ {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+};
+
+static struct idxdata tbl_end_hvflip[] = {
+ {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+ {6, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
+};
+
static u8 dat_freq1[] = { 0x8c, 0xa4, 0x04 };
static u8 dat_multi5[] = { 0x8c, 0xa1, 0x03 };
static u8 dat_multi6[] = { 0x90, 0x00, 0x05 };
-static struct validx tbl_common1[] = {
- {0x0000, 0x0000},
- {1, 0xffff}, /* msleep(35); */
- {0x006a, 0x0007}, {0x0063, 0x0006}, {0x006a, 0x000d}, {0x0000, 0x00c0},
- {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2}, {0x0004, 0x00d8},
- {0x0000, 0x0058}, {0x0002, 0x0004}, {0x0041, 0x0000},
+static struct validx tbl_init_at_startup[] = {
+ {0x0000, 0x0000}, {0x0010, 0x0010}, {0x0008, 0x00c0}, {0x0001, 0x00c1},
+ {0x0001, 0x00c2}, {0x0020, 0x0006}, {0x006a, 0x000d},
+ {53, 0xffff},
+ {0x0040, 0x0000}, {0x0063, 0x0006},
};
-static struct validx tbl_common2[] = {
- {0x006a, 0x0007},
- {35, 0xffff},
- {0x00ef, 0x0006},
- {35, 0xffff},
- {0x006a, 0x000d},
- {35, 0xffff},
+static struct validx tbl_common_0B[] = {
+ {0x0002, 0x0004}, {0x006a, 0x0007}, {0x00ef, 0x0006}, {0x006a, 0x000d},
{0x0000, 0x00c0}, {0x0010, 0x0010}, {0x0003, 0x00c1}, {0x0042, 0x00c2},
{0x0004, 0x00d8}, {0x0000, 0x0058}, {0x0041, 0x0000},
};
-static struct idxdata tbl_common3[] = {
- {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
+static struct idxdata tbl_common_3B[] = {
+ {0x33, "\x86\x25\x01"}, {0x33, "\x86\x25\x00"},
+ {2, "\xff\xff\xff"},
+ {0x30, "\x1a\x0a\xcc"}, {0x32, "\x02\x00\x08"}, {0x33, "\xf4\x03\x1d"},
{6, "\xff\xff\xff"}, /* 12 */
{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
{2, "\xff\xff\xff"}, /* - */
@@ -98,85 +122,58 @@ static struct idxdata tbl_common3[] = {
{0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
{0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
- {1, "\xff\xff\xff"},
{0x33, "\x78\x00\x00"},
- {1, "\xff\xff\xff"},
+ {2, "\xff\xff\xff"},
{0x35, "\xb8\x1f\x20"}, {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x10"},
{0x33, "\x8c\xa2\x07"}, {0x33, "\x90\x00\x08"}, {0x33, "\x8c\xa2\x42"},
{0x33, "\x90\x00\x0b"}, {0x33, "\x8c\xa2\x4a"}, {0x33, "\x90\x00\x8c"},
{0x35, "\xba\xfa\x08"}, {0x33, "\x8c\xa2\x02"}, {0x33, "\x90\x00\x22"},
- {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"},
-};
-
-static struct idxdata tbl_common4[] = {
- {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\xa4\x08"},
+ {0x33, "\x8c\xa2\x03"}, {0x33, "\x90\x00\xbb"}, {0x33, "\x8c\xa4\x04"},
+ {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"}, {0x33, "\x90\x00\x00"},
+ {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa2\x0c"},
+ {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"}, {0x33, "\x90\x00\x04"},
+ {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"}, {0x33, "\x8c\xa1\x03"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+ {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x25"},
+ {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"},
+ {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x47"},
+ {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"}, {0x33, "\x90\x02\x84"},
+ {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"}, {0x33, "\x8c\x27\x07"},
+ {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"}, {0x33, "\x90\x04\xb0"},
+ {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x0f"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"}, {0x33, "\x90\x04\xbd"},
+ {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"}, {0x33, "\x8c\x27\x15"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"}, {0x33, "\x90\x21\x11"},
+ {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"}, {0x33, "\x8c\x27\x1b"},
+ {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"}, {0x33, "\x90\x01\x02"},
+ {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"}, {0x33, "\x8c\x27\x21"},
+ {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"}, {0x33, "\x90\x02\x85"},
+ {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x27"},
+ {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"}, {0x33, "\x90\x20\x20"},
+ {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"}, {0x33, "\x8c\x27\x2d"},
+ {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"}, {0x33, "\x90\x00\x04"},
+ {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x33"},
+ {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"}, {0x33, "\x90\x06\x4b"},
+ {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x39"},
+ {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"},
+ {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"}, {0x33, "\x8c\x27\x41"},
+ {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"}, {0x33, "\x90\x04\xed"},
+ {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x51"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"}, {0x33, "\x90\x03\x20"},
+ {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x57"},
+ {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"}, {0x33, "\x90\x00\x00"},
+ {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x63"},
+ {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"}, {0x33, "\x90\x04\xb0"},
+ {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\xa4\x08"},
{0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"}, {0x33, "\x90\x00\x21"},
{0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"}, {0x33, "\x8c\xa4\x0b"},
- {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa0"},
- {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc0"}, {0x33, "\x8c\x24\x15"},
- {0x33, "\x90\x00\xa0"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\xc0"},
-};
-
-static struct idxdata tbl_common5[] = {
- {0x33, "\x8c\xa4\x04"}, {0x33, "\x90\x00\x80"}, {0x33, "\x8c\xa7\x9d"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa7\x9e"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\xa2\x0c"}, {0x33, "\x90\x00\x17"}, {0x33, "\x8c\xa2\x15"},
- {0x33, "\x90\x00\x04"}, {0x33, "\x8c\xa2\x14"}, {0x33, "\x90\x00\x20"},
- {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
- /* msleep(53); */
- {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"},
- {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"}, {0x33, "\x8c\x27\x39"},
- {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
- {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"}, {0x33, "\x8c\x27\x03"},
- {0x33, "\x90\x02\x84"}, {0x33, "\x8c\x27\x05"}, {0x33, "\x90\x01\xe2"},
- {0x33, "\x8c\x27\x07"}, {0x33, "\x90\x06\x40"}, {0x33, "\x8c\x27\x09"},
- {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x27\x0d"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\x27\x0f"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x11"},
- {0x33, "\x90\x04\xbd"}, {0x33, "\x8c\x27\x13"}, {0x33, "\x90\x06\x4d"},
- {0x33, "\x8c\x27\x15"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x17"},
- {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
- {0x33, "\x8c\x27\x1b"}, {0x33, "\x90\x02\x4f"}, {0x33, "\x8c\x27\x1d"},
- {0x33, "\x90\x01\x02"}, {0x33, "\x8c\x27\x1f"}, {0x33, "\x90\x02\x79"},
- {0x33, "\x8c\x27\x21"}, {0x33, "\x90\x01\x55"}, {0x33, "\x8c\x27\x23"},
- {0x33, "\x90\x02\x85"}, {0x33, "\x8c\x27\x25"}, {0x33, "\x90\x06\x0f"},
- {0x33, "\x8c\x27\x27"}, {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x29"},
- {0x33, "\x90\x20\x20"}, {0x33, "\x8c\x27\x2b"}, {0x33, "\x90\x10\x20"},
- {0x33, "\x8c\x27\x2d"}, {0x33, "\x90\x20\x07"}, {0x33, "\x8c\x27\x2f"},
- {0x33, "\x90\x00\x04"}, {0x33, "\x8c\x27\x31"}, {0x33, "\x90\x00\x04"},
- {0x33, "\x8c\x27\x33"}, {0x33, "\x90\x04\xbb"}, {0x33, "\x8c\x27\x35"},
- {0x33, "\x90\x06\x4b"}, {0x33, "\x8c\x27\x37"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\x27\x39"}, {0x33, "\x90\x21\x11"}, {0x33, "\x8c\x27\x3b"},
- {0x33, "\x90\x00\x24"}, {0x33, "\x8c\x27\x3d"}, {0x33, "\x90\x01\x20"},
- {0x33, "\x8c\x27\x41"}, {0x33, "\x90\x01\x69"}, {0x33, "\x8c\x27\x45"},
- {0x33, "\x90\x04\xed"}, {0x33, "\x8c\x27\x47"}, {0x33, "\x90\x09\x4c"},
- {0x33, "\x8c\x27\x51"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x53"},
- {0x33, "\x90\x03\x20"}, {0x33, "\x8c\x27\x55"}, {0x33, "\x90\x00\x00"},
- {0x33, "\x8c\x27\x57"}, {0x33, "\x90\x02\x58"}, {0x33, "\x8c\x27\x5f"},
- {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x61"}, {0x33, "\x90\x06\x40"},
- {0x33, "\x8c\x27\x63"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\x27\x65"},
- {0x33, "\x90\x04\xb0"}, {0x33, "\x8c\x22\x2e"}, {0x33, "\x90\x00\xa1"},
- {0x33, "\x8c\xa4\x08"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa4\x09"},
- {0x33, "\x90\x00\x21"}, {0x33, "\x8c\xa4\x0a"}, {0x33, "\x90\x00\x25"},
- {0x33, "\x8c\xa4\x0b"}, {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"},
- {0x33, "\x90\x00\xa1"}, {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"},
- {0x33, "\x8c\x24\x15"},
-};
-
-static struct validx tbl_init_at_startup[] = {
- {0x0000, 0x0000},
- {53, 0xffff},
- {0x0010, 0x0010},
- {53, 0xffff},
- {0x0008, 0x00c0},
- {53, 0xffff},
- {0x0001, 0x00c1},
- {53, 0xffff},
- {0x0001, 0x00c2},
- {53, 0xffff},
- {0x0020, 0x0006},
- {53, 0xffff},
- {0x006a, 0x000d},
- {53, 0xffff},
+ {0x33, "\x90\x00\x27"}, {0x33, "\x8c\x24\x11"}, {0x33, "\x90\x00\xa1"},
+ {0x33, "\x8c\x24\x13"}, {0x33, "\x90\x00\xc1"}, {0x33, "\x8c\x24\x15"},
+ {0x33, "\x90\x00\x6a"}, {0x33, "\x8c\x24\x17"}, {0x33, "\x90\x00\x80"},
+ {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
+ {2, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
+ {3, "\xff\xff\xff"},
};
static struct idxdata tbl_init_post_alt_low1[] = {
@@ -209,7 +206,7 @@ static struct idxdata tbl_init_post_alt_low3[] = {
{2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
{0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
- {2, "\xff\xff\xff"}, /* - * */
+ {2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
{2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
@@ -217,61 +214,15 @@ static struct idxdata tbl_init_post_alt_low3[] = {
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
{2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
- {1, "\xff\xff\xff"},
-};
-
-static struct idxdata tbl_init_post_alt_low4[] = {
- {0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
- {0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
- {0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
- {0x34, "\xde\x01\x5b"}, {0x34, "\xe6\x01\x13"}, {0x34, "\xee\x0b\xf0"},
- {0x34, "\xf6\x0b\xa4"}, {0x35, "\x00\xf6\xe7"}, {0x35, "\x08\x0d\xfd"},
- {0x35, "\x10\x25\x63"}, {0x35, "\x18\x35\x6c"}, {0x35, "\x20\x42\x7e"},
- {0x35, "\x28\x19\x44"}, {0x35, "\x30\x39\xd4"}, {0x35, "\x38\xf5\xa8"},
- {0x35, "\x4c\x07\x90"}, {0x35, "\x44\x07\xb8"}, {0x35, "\x5c\x06\x88"},
- {0x35, "\x54\x07\xff"}, {0x34, "\xe0\x01\x52"}, {0x34, "\xe8\x00\xcc"},
- {0x34, "\xf0\x0d\x83"}, {0x34, "\xf8\x0c\xb3"}, {0x35, "\x02\xfe\xba"},
- {0x35, "\x0a\x04\xe0"}, {0x35, "\x12\x1c\x63"}, {0x35, "\x1a\x2b\x5a"},
- {0x35, "\x22\x32\x5e"}, {0x35, "\x2a\x0d\x28"}, {0x35, "\x32\x2c\x02"},
- {0x35, "\x3a\xf4\xfa"}, {0x35, "\x4e\x07\xef"}, {0x35, "\x46\x07\x88"},
- {0x35, "\x5e\x07\xc1"}, {0x35, "\x56\x04\x64"}, {0x34, "\xe4\x01\x15"},
- {0x34, "\xec\x00\x82"}, {0x34, "\xf4\x0c\xce"}, {0x34, "\xfc\x0c\xba"},
- {0x35, "\x06\x1f\x02"}, {0x35, "\x0e\x02\xe3"}, {0x35, "\x16\x1a\x50"},
- {0x35, "\x1e\x24\x39"}, {0x35, "\x26\x23\x4c"}, {0x35, "\x2e\xf9\x1b"},
- {0x35, "\x36\x23\x19"}, {0x35, "\x3e\x12\x08"}, {0x35, "\x52\x07\x22"},
- {0x35, "\x4a\x03\xd3"}, {0x35, "\x62\x06\x54"}, {0x35, "\x5a\x04\x5d"},
- {0x34, "\xe2\x01\x04"}, {0x34, "\xea\x00\xa0"}, {0x34, "\xf2\x0c\xbc"},
- {0x34, "\xfa\x0c\x5b"}, {0x35, "\x04\x17\xf2"}, {0x35, "\x0c\x02\x08"},
- {0x35, "\x14\x28\x43"}, {0x35, "\x1c\x28\x62"}, {0x35, "\x24\x2b\x60"},
- {0x35, "\x2c\x07\x33"}, {0x35, "\x34\x1f\xb0"}, {0x35, "\x3c\xed\xcd"},
- {0x35, "\x50\x00\x06"}, {0x35, "\x48\x07\xff"}, {0x35, "\x60\x05\x89"},
- {0x35, "\x58\x07\xff"}, {0x35, "\x40\x00\xa0"}, {0x35, "\x42\x00\x00"},
- {0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"},
- /* Flip/Mirror h/v=1 */
- {0x33, "\x90\x00\x3c"}, {0x33, "\x8c\x27\x19"}, {0x33, "\x90\x04\x6c"},
- {0x33, "\x8c\x27\x3b"}, {0x33, "\x90\x00\x24"}, {0x33, "\x8c\xa1\x03"},
- {0x33, "\x90\x00\x06"},
- {130, "\xff\xff\xff"},
- {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
- {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"}, {0x33, "\x90\x00\x06"},
- {100, "\xff\xff\xff"},
- /* ?? */
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"}, {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- {0x33, "\x8c\xa1\x02"}, {0x33, "\x90\x00\x1f"},
- /* Brigthness=70 */
- {0x33, "\x8c\xa2\x06"}, {0x33, "\x90\x00\x46"}, {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x0f"}, {0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
- /* Sharpness=20 */
- {0x32, "\x6c\x14\x08"},
};
-static struct idxdata tbl_init_post_alt_big1[] = {
+static struct idxdata tbl_init_post_alt_big[] = {
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x05"},
{2, "\xff\xff\xff"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x06"},
{2, "\xff\xff\xff"},
{0x34, "\x1e\x8f\x09"}, {0x34, "\x1c\x01\x28"}, {0x34, "\x1e\x8f\x09"},
+ {2, "\xff\xff\xff"},
{0x34, "\x1e\x8f\x09"}, {0x32, "\x14\x06\xe6"}, {0x33, "\x8c\xa1\x03"},
{0x33, "\x90\x00\x05"},
{2, "\xff\xff\xff"},
@@ -285,9 +236,17 @@ static struct idxdata tbl_init_post_alt_big1[] = {
{0x33, "\x90\x00\x03"}, {0x33, "\x8c\xa1\x34"}, {0x33, "\x90\x00\x03"},
{0x33, "\x8c\xa1\x03"}, {0x33, "\x90\x00\x02"}, {0x33, "\x2e\x01\x00"},
{0x34, "\x04\x00\x2a"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+ {0x33, "\x8c\x27\x97"}, {0x33, "\x90\x01\x00"},
+ {51, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x00"}, {0x33, "\x8c\xa1\x03"},
+ {0x33, "\x90\x00\x01"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x00"},
+ {51, "\xff\xff\xff"},
+ {0x33, "\x8c\xa1\x20"}, {0x33, "\x90\x00\x72"}, {0x33, "\x8c\xa1\x03"},
+ {0x33, "\x90\x00\x02"}, {0x33, "\x8c\xa7\x02"}, {0x33, "\x90\x00\x01"},
+ {51, "\xff\xff\xff"},
};
-static struct idxdata tbl_init_post_alt_big2[] = {
+static struct idxdata tbl_init_post_alt_3B[] = {
{0x32, "\x10\x01\xf8"}, {0x34, "\xce\x01\xa8"}, {0x34, "\xd0\x66\x33"},
{0x34, "\xd2\x31\x9a"}, {0x34, "\xd4\x94\x63"}, {0x34, "\xd6\x4b\x25"},
{0x34, "\xd8\x26\x70"}, {0x34, "\xda\x72\x4c"}, {0x34, "\xdc\xff\x04"},
@@ -316,17 +275,6 @@ static struct idxdata tbl_init_post_alt_big2[] = {
{0x32, "\x10\x01\xfc"}, {0x33, "\x8c\xa1\x18"}, {0x33, "\x90\x00\x3c"},
};
-static struct idxdata tbl_init_post_alt_big3[] = {
- {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"},
- {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"},
- {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"},
- {0x33, "\x8c\xa1\x02"},
- {0x33, "\x90\x00\x1f"},
-};
-
static u8 *dat_640 = "\xd0\x02\xd1\x08\xd2\xe1\xd3\x02\xd4\x10\xd5\x81";
static u8 *dat_800 = "\xd0\x02\xd1\x10\xd2\x57\xd3\x02\xd4\x18\xd5\x21";
static u8 *dat_1280 = "\xd0\x02\xd1\x20\xd2\x01\xd3\x02\xd4\x28\xd5\x01";
@@ -351,7 +299,7 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
sd->vcur.gamma = 0;
sd->vcur.hue = 0;
sd->vcur.saturation = 60;
- sd->vcur.whitebal = 50;
+ sd->vcur.whitebal = 0; /* 50, not done by hardware */
sd->vcur.mirror = 0;
sd->vcur.flip = 0;
sd->vcur.AC50Hz = 1;
@@ -361,17 +309,12 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
sd->vmax.sharpness = 40;
sd->vmax.contrast = 3;
sd->vmax.gamma = 2;
- sd->vmax.hue = 0 + 1; /* 200 */
- sd->vmax.saturation = 0; /* 100 */
- sd->vmax.whitebal = 0; /* 100 */
+ sd->vmax.hue = 0 + 1; /* 200, not done by hardware */
+ sd->vmax.saturation = 0; /* 100, not done by hardware */
+ sd->vmax.whitebal = 2; /* 100, not done by hardware */
sd->vmax.mirror = 1;
sd->vmax.flip = 1;
sd->vmax.AC50Hz = 1;
- if (_MI2020b_) {
- sd->vmax.contrast = 0;
- sd->vmax.gamma = 0;
- sd->vmax.backlight = 0;
- }
sd->dev_camera_settings = mi2020_camera_settings;
sd->dev_init_at_startup = mi2020_init_at_startup;
@@ -384,51 +327,9 @@ void mi2020_init_settings(struct gspca_dev *gspca_dev)
static void common(struct gspca_dev *gspca_dev)
{
- s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
-
- if (_MI2020b_) {
- fetch_validx(gspca_dev, tbl_common1, ARRAY_SIZE(tbl_common1));
- } else {
- if (_MI2020_)
- ctrl_out(gspca_dev, 0x40, 1, 0x0008, 0x0004, 0, NULL);
- else
- ctrl_out(gspca_dev, 0x40, 1, 0x0002, 0x0004, 0, NULL);
- msleep(35);
- fetch_validx(gspca_dev, tbl_common2, ARRAY_SIZE(tbl_common2));
- }
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x01");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x86\x25\x00");
- msleep(2); /* - * */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0030, 3, "\x1a\x0a\xcc");
- if (reso == IMAGE_1600)
- msleep(2); /* 1600 */
- fetch_idxdata(gspca_dev, tbl_common3, ARRAY_SIZE(tbl_common3));
-
- if (_MI2020b_ || _MI2020_)
- fetch_idxdata(gspca_dev, tbl_common4,
- ARRAY_SIZE(tbl_common4));
-
- fetch_idxdata(gspca_dev, tbl_common5, ARRAY_SIZE(tbl_common5));
- if (_MI2020b_ || _MI2020_) {
- /* Different from fret */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x78");
- /* Same as fret */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
- /* Different from fret */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x90");
- } else {
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x6a");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x24\x17");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x80");
- }
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x05");
- msleep(2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- if (reso == IMAGE_1600)
- msleep(14); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x06");
- msleep(2);
+ fetch_validx(gspca_dev, tbl_common_0B, ARRAY_SIZE(tbl_common_0B));
+ fetch_idxdata(gspca_dev, tbl_common_3B, ARRAY_SIZE(tbl_common_3B));
+ ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
}
static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
@@ -441,8 +342,16 @@ static int mi2020_init_at_startup(struct gspca_dev *gspca_dev)
fetch_validx(gspca_dev, tbl_init_at_startup,
ARRAY_SIZE(tbl_init_at_startup));
+ ctrl_out(gspca_dev, 0x40, 1, 0x7a00, 0x8030, 0, NULL);
+ ctrl_in(gspca_dev, 0xc0, 2, 0x7a00, 0x8030, 1, &c);
+
common(gspca_dev);
+ msleep(61);
+/* ctrl_out(gspca_dev, 0x40, 11, 0x0000, 0x0000, 0, NULL); */
+/* msleep(36); */
+ ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
+
return 0;
}
@@ -450,17 +359,17 @@ static int mi2020_init_pre_alt(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->mirrorMask = 0;
+ sd->mirrorMask = 0;
+ sd->vold.hue = -1;
- sd->vold.backlight = -1;
+ /* These controls need to be reset */
sd->vold.brightness = -1;
sd->vold.sharpness = -1;
- sd->vold.contrast = -1;
- sd->vold.gamma = -1;
- sd->vold.hue = -1;
- sd->vold.mirror = -1;
- sd->vold.flip = -1;
- sd->vold.AC50Hz = -1;
+
+ /* If not different from default, they do not need to be set */
+ sd->vold.contrast = 0;
+ sd->vold.gamma = 0;
+ sd->vold.backlight = 0;
mi2020_init_post_alt(gspca_dev);
@@ -472,10 +381,10 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
- s32 backlight = sd->vcur.backlight;
s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0);
s32 freq = (sd->vcur.AC50Hz > 0);
+ s32 wbal = sd->vcur.whitebal;
u8 dat_freq2[] = {0x90, 0x00, 0x80};
u8 dat_multi1[] = {0x8c, 0xa7, 0x00};
@@ -484,6 +393,7 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
u8 dat_multi4[] = {0x90, 0x00, 0x00};
u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+ u8 dat_wbal2[] = {0x90, 0x00, 0x00};
u8 c;
sd->nbIm = -1;
@@ -491,23 +401,26 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
dat_freq2[2] = freq ? 0xc0 : 0x80;
dat_multi1[2] = 0x9d;
dat_multi3[2] = dat_multi1[2] + 1;
- dat_multi4[2] = dat_multi2[2] = backlight;
+ if (wbal == 0) {
+ dat_multi4[2] = dat_multi2[2] = 0;
+ dat_wbal2[2] = 0x17;
+ } else if (wbal == 1) {
+ dat_multi4[2] = dat_multi2[2] = 0;
+ dat_wbal2[2] = 0x35;
+ } else if (wbal == 2) {
+ dat_multi4[2] = dat_multi2[2] = 0x20;
+ dat_wbal2[2] = 0x17;
+ }
dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
msleep(200);
-
ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
- msleep(3); /* 35 * */
+ msleep(2);
common(gspca_dev);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
- msleep(70);
-
- if (_MI2020b_)
- ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
-
+ msleep(142);
ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
ctrl_out(gspca_dev, 0x40, 1, 0x0003, 0x00c1, 0, NULL);
ctrl_out(gspca_dev, 0x40, 1, 0x0042, 0x00c2, 0, NULL);
@@ -523,8 +436,7 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
12, dat_800);
- if (_MI2020c_)
- fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
+ fetch_idxdata(gspca_dev, tbl_init_post_alt_low1,
ARRAY_SIZE(tbl_init_post_alt_low1));
if (reso == IMAGE_800)
@@ -534,87 +446,10 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
fetch_idxdata(gspca_dev, tbl_init_post_alt_low3,
ARRAY_SIZE(tbl_init_post_alt_low3));
- if (_MI2020b_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(150);
- } else if (_MI2020c_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(120);
- ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
- msleep(30);
- } else if (_MI2020_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(120);
- ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
- msleep(30);
- }
-
- /* AC power frequency */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
- msleep(20);
- /* backlight */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
- /* at init time but not after */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
- /* finish the backlight */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
- msleep(5);/* " */
-
- if (_MI2020c_) {
- fetch_idxdata(gspca_dev, tbl_init_post_alt_low4,
- ARRAY_SIZE(tbl_init_post_alt_low4));
- } else {
- ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
- msleep(14); /* 0xd8 */
-
- /* flip/mirror */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip4);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_hvflip6);
- msleep(21);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- msleep(5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033,
- 3, dat_dummy1);
- /* end of flip/mirror main part */
- msleep(246); /* 146 */
-
- sd->nbIm = 0;
- }
+ ctrl_out(gspca_dev, 0x40, 1, 0x0010, 0x0010, 0, NULL);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+ msleep(120);
break;
case IMAGE_1280:
@@ -643,108 +478,62 @@ static int mi2020_init_post_alt(struct gspca_dev *gspca_dev)
3, "\x90\x04\xb0");
}
- fetch_idxdata(gspca_dev, tbl_init_post_alt_big1,
- ARRAY_SIZE(tbl_init_post_alt_big1));
-
- if (reso == IMAGE_1600)
- msleep(13); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\x27\x97");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x01\x00");
- msleep(53);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
- if (reso == IMAGE_1600)
- msleep(13); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
- msleep(53);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
- if (reso == IMAGE_1600)
- msleep(13); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
- msleep(53);
-
- if (_MI2020b_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
- if (reso == IMAGE_1600)
- msleep(500); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(1850);
- } else if (_MI2020c_ || _MI2020_) {
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
- msleep(1850);
- ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
- msleep(30);
- }
+ fetch_idxdata(gspca_dev, tbl_init_post_alt_big,
+ ARRAY_SIZE(tbl_init_post_alt_big));
- /* AC power frequency */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
- msleep(20);
- /* backlight */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
- /* at init time but not after */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa2\x0c");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x17");
- /* finish the backlight */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
- msleep(6); /* " */
+ ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0010, 0, NULL);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0000, 0x00c1, 0, NULL);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x00c2, 0, NULL);
+ msleep(1850);
+ }
- ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
- msleep(14);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0040, 0x0000, 0, NULL);
+ msleep(40);
+
+ /* AC power frequency */
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_freq2);
+ msleep(33);
+ /* light source */
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+ msleep(7);
+ ctrl_in(gspca_dev, 0xc0, 2, 0x0000, 0x0000, 1, &c);
+
+ fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+ ARRAY_SIZE(tbl_init_post_alt_3B));
+
+ /* hvflip */
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
+ msleep(250);
+
+ if (reso == IMAGE_640 || reso == IMAGE_800)
+ fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+ ARRAY_SIZE(tbl_middle_hvflip_low));
+ else
+ fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+ ARRAY_SIZE(tbl_middle_hvflip_big));
- if (_MI2020c_)
- fetch_idxdata(gspca_dev, tbl_init_post_alt_big2,
- ARRAY_SIZE(tbl_init_post_alt_big2));
+ fetch_idxdata(gspca_dev, tbl_end_hvflip,
+ ARRAY_SIZE(tbl_end_hvflip));
- /* flip/mirror */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
- /* end of flip/mirror main part */
- msleep(16);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
- if (reso == IMAGE_1600)
- msleep(25); /* 1600 */
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x00");
- msleep(103);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x03");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa1\x20");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x72");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x8c\xa7\x02");
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, "\x90\x00\x01");
- sd->nbIm = 0;
-
- if (_MI2020c_)
- fetch_idxdata(gspca_dev, tbl_init_post_alt_big3,
- ARRAY_SIZE(tbl_init_post_alt_big3));
- }
+ sd->nbIm = 0;
sd->vold.mirror = mirror;
sd->vold.flip = flip;
sd->vold.AC50Hz = freq;
- sd->vold.backlight = backlight;
+ sd->vold.whitebal = wbal;
mi2020_camera_settings(gspca_dev);
@@ -772,6 +561,7 @@ static int mi2020_configure_alt(struct gspca_dev *gspca_dev)
static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ s32 reso = gspca_dev->cam.cam_mode[(s32) gspca_dev->curr_mode].priv;
s32 backlight = sd->vcur.backlight;
s32 bright = sd->vcur.brightness;
@@ -782,6 +572,7 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
s32 mirror = (((sd->vcur.mirror > 0) ^ sd->mirrorMask) > 0);
s32 flip = (((sd->vcur.flip > 0) ^ sd->mirrorMask) > 0);
s32 freq = (sd->vcur.AC50Hz > 0);
+ s32 wbal = sd->vcur.whitebal;
u8 dat_sharp[] = {0x6c, 0x00, 0x08};
u8 dat_bright2[] = {0x90, 0x00, 0x00};
@@ -792,6 +583,7 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
u8 dat_multi4[] = {0x90, 0x00, 0x00};
u8 dat_hvflip2[] = {0x90, 0x04, 0x6c};
u8 dat_hvflip4[] = {0x90, 0x00, 0x24};
+ u8 dat_wbal2[] = {0x90, 0x00, 0x00};
/* Less than 4 images received -> too early to set the settings */
if (sd->nbIm < 4) {
@@ -809,67 +601,89 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
msleep(20);
}
+ if (wbal != sd->vold.whitebal) {
+ sd->vold.whitebal = wbal;
+ if (wbal < 0 || wbal > sd->vmax.whitebal)
+ wbal = 0;
+
+ dat_multi1[2] = 0x9d;
+ dat_multi3[2] = dat_multi1[2] + 1;
+ if (wbal == 0) {
+ dat_multi4[2] = dat_multi2[2] = 0;
+ dat_wbal2[2] = 0x17;
+ } else if (wbal == 1) {
+ dat_multi4[2] = dat_multi2[2] = 0;
+ dat_wbal2[2] = 0x35;
+ } else if (wbal == 2) {
+ dat_multi4[2] = dat_multi2[2] = 0x20;
+ dat_wbal2[2] = 0x17;
+ }
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_wbal2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+ }
+
if (mirror != sd->vold.mirror || flip != sd->vold.flip) {
sd->vold.mirror = mirror;
sd->vold.flip = flip;
dat_hvflip2[2] = 0x6c + 2 * (1 - flip) + (1 - mirror);
dat_hvflip4[2] = 0x24 + 2 * (1 - flip) + (1 - mirror);
+
+ fetch_idxdata(gspca_dev, tbl_init_post_alt_3B,
+ ARRAY_SIZE(tbl_init_post_alt_3B));
+
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip1);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip2);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip3);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip4);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip5);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_hvflip6);
- msleep(130);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_dummy1);
- msleep(6);
-
- /* Sometimes present, sometimes not, useful? */
- /* ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy2);
- * ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dummy3);*/
+ msleep(40);
+
+ if (reso == IMAGE_640 || reso == IMAGE_800)
+ fetch_idxdata(gspca_dev, tbl_middle_hvflip_low,
+ ARRAY_SIZE(tbl_middle_hvflip_low));
+ else
+ fetch_idxdata(gspca_dev, tbl_middle_hvflip_big,
+ ARRAY_SIZE(tbl_middle_hvflip_big));
+
+ fetch_idxdata(gspca_dev, tbl_end_hvflip,
+ ARRAY_SIZE(tbl_end_hvflip));
}
- if (backlight != sd->vold.backlight) {
- sd->vold.backlight = backlight;
- if (backlight < 0 || backlight > sd->vmax.backlight)
- backlight = 0;
+ if (bright != sd->vold.brightness) {
+ sd->vold.brightness = bright;
+ if (bright < 0 || bright > sd->vmax.brightness)
+ bright = 0;
- dat_multi1[2] = 0x9d;
- dat_multi3[2] = dat_multi1[2] + 1;
- dat_multi4[2] = dat_multi2[2] = backlight;
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi4);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
+ dat_bright2[2] = bright;
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
+ ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
}
- if (gam != sd->vold.gamma) {
+ if (cntr != sd->vold.contrast || gam != sd->vold.gamma) {
+ sd->vold.contrast = cntr;
+ if (cntr < 0 || cntr > sd->vmax.contrast)
+ cntr = 0;
sd->vold.gamma = gam;
if (gam < 0 || gam > sd->vmax.gamma)
gam = 0;
dat_multi1[2] = 0x6d;
dat_multi3[2] = dat_multi1[2] + 1;
- dat_multi4[2] = dat_multi2[2] = 0x40 + gam;
+ if (cntr == 0)
+ cntr = 4;
+ dat_multi4[2] = dat_multi2[2] = cntr * 0x10 + 2 - gam;
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
@@ -878,14 +692,14 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
}
- if (cntr != sd->vold.contrast) {
- sd->vold.contrast = cntr;
- if (cntr < 0 || cntr > sd->vmax.contrast)
- cntr = 0;
+ if (backlight != sd->vold.backlight) {
+ sd->vold.backlight = backlight;
+ if (backlight < 0 || backlight > sd->vmax.backlight)
+ backlight = 0;
- dat_multi1[2] = 0x6d;
+ dat_multi1[2] = 0x9d;
dat_multi3[2] = dat_multi1[2] + 1;
- dat_multi4[2] = dat_multi2[2] = 0x12 + 16 * cntr;
+ dat_multi4[2] = dat_multi2[2] = backlight;
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi1);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi2);
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi3);
@@ -894,20 +708,6 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_multi6);
}
- if (bright != sd->vold.brightness) {
- sd->vold.brightness = bright;
- if (bright < 0 || bright > sd->vmax.brightness)
- bright = 0;
-
- dat_bright2[2] = bright;
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright1);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright2);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright3);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright4);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright5);
- ctrl_out(gspca_dev, 0x40, 3, 0x7a00, 0x0033, 3, dat_bright6);
- }
-
if (sharp != sd->vold.sharpness) {
sd->vold.sharpness = sharp;
if (sharp < 0 || sharp > sd->vmax.sharpness)
@@ -928,9 +728,6 @@ static int mi2020_camera_settings(struct gspca_dev *gspca_dev)
static void mi2020_post_unset_alt(struct gspca_dev *gspca_dev)
{
ctrl_out(gspca_dev, 0x40, 5, 0x0000, 0x0000, 0, NULL);
- msleep(20);
- if (_MI2020c_ || _MI2020_)
- ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
- else
- ctrl_out(gspca_dev, 0x40, 1, 0x0041, 0x0000, 0, NULL);
+ msleep(40);
+ ctrl_out(gspca_dev, 0x40, 1, 0x0001, 0x0000, 0, NULL);
}
diff --git a/drivers/media/video/gspca/gl860/gl860-ov9655.c b/drivers/media/video/gspca/gl860/gl860-ov9655.c
index d412694c50af..5ae9619d72a5 100644
--- a/drivers/media/video/gspca/gl860/gl860-ov9655.c
+++ b/drivers/media/video/gspca/gl860/gl860-ov9655.c
@@ -69,7 +69,7 @@ static u8 *tbl_640[] = {
"\xd0\x01\xd1\x08\xd2\xe0\xd3\x01" "\xd4\x10\xd5\x80"
};
-static u8 *tbl_800[] = {
+static u8 *tbl_1280[] = {
"\x00\x40\x07\x6a\x06\xf3\x0d\x6a" "\x10\x10\xc1\x01"
,
"\x12\x80\x00\x00\x01\x98\x02\x80" "\x03\x12\x04\x01\x0b\x57\x0e\x61"
@@ -217,7 +217,7 @@ static int ov9655_init_post_alt(struct gspca_dev *gspca_dev)
ctrl_out(gspca_dev, 0x40, 5, 0x0001, 0x0000, 0, NULL);
- tbl = (reso == IMAGE_640) ? tbl_640 : tbl_800;
+ tbl = (reso == IMAGE_640) ? tbl_640 : tbl_1280;
ctrl_out(gspca_dev, 0x40, 3, 0x0000, 0x0200,
tbl_length[0], tbl[0]);
diff --git a/drivers/media/video/gspca/gl860/gl860.c b/drivers/media/video/gspca/gl860/gl860.c
index 9e42476c0eaf..99083038cec3 100644
--- a/drivers/media/video/gspca/gl860/gl860.c
+++ b/drivers/media/video/gspca/gl860/gl860.c
@@ -63,7 +63,7 @@ static int sd_set_##thename(struct gspca_dev *gspca_dev, s32 val)\
\
sd->vcur.thename = val;\
if (gspca_dev->streaming)\
- sd->dev_camera_settings(gspca_dev);\
+ sd->waitSet = 1;\
return 0;\
} \
static int sd_get_##thename(struct gspca_dev *gspca_dev, s32 *val)\
@@ -91,7 +91,6 @@ SD_SETGET(contrast)
/* control table */
static struct ctrl sd_ctrls_mi1320[GL860_NCTRLS];
static struct ctrl sd_ctrls_mi2020[GL860_NCTRLS];
-static struct ctrl sd_ctrls_mi2020b[GL860_NCTRLS];
static struct ctrl sd_ctrls_ov2640[GL860_NCTRLS];
static struct ctrl sd_ctrls_ov9655[GL860_NCTRLS];
@@ -121,8 +120,6 @@ static int gl860_build_control_table(struct gspca_dev *gspca_dev)
sd_ctrls = sd_ctrls_mi1320;
else if (_MI2020_)
sd_ctrls = sd_ctrls_mi2020;
- else if (_MI2020b_)
- sd_ctrls = sd_ctrls_mi2020b;
else if (_OV2640_)
sd_ctrls = sd_ctrls_ov2640;
else if (_OV9655_)
@@ -187,19 +184,6 @@ static const struct sd_desc sd_desc_mi2020 = {
.dq_callback = sd_callback,
};
-static const struct sd_desc sd_desc_mi2020b = {
- .name = MODULE_NAME,
- .ctrls = sd_ctrls_mi2020b,
- .nctrls = GL860_NCTRLS,
- .config = sd_config,
- .init = sd_init,
- .isoc_init = sd_isoc_init,
- .start = sd_start,
- .stop0 = sd_stop0,
- .pkt_scan = sd_pkt_scan,
- .dq_callback = sd_callback,
-};
-
static const struct sd_desc sd_desc_ov2640 = {
.name = MODULE_NAME,
.ctrls = sd_ctrls_ov2640,
@@ -235,9 +219,9 @@ static struct v4l2_pix_format mi2020_mode[] = {
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 0
},
- { 800, 600, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ { 800, 598, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 800,
- .sizeimage = 800 * 600,
+ .sizeimage = 800 * 598,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 1
},
@@ -247,9 +231,9 @@ static struct v4l2_pix_format mi2020_mode[] = {
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 2
},
- {1600, 1200, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
+ {1600, 1198, V4L2_PIX_FMT_SGBRG8, V4L2_FIELD_NONE,
.bytesperline = 1600,
- .sizeimage = 1600 * 1200,
+ .sizeimage = 1600 * 1198,
.colorspace = V4L2_COLORSPACE_SRGB,
.priv = 3
},
@@ -344,8 +328,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = ID_OV9655;
else if (strcmp(sensor, "MI2020") == 0)
sd->sensor = ID_MI2020;
- else if (strcmp(sensor, "MI2020b") == 0)
- sd->sensor = ID_MI2020b;
/* Get sensor and set the suitable init/start/../stop functions */
if (gl860_guess_sensor(gspca_dev, vendor_id, product_id) == -1)
@@ -369,13 +351,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
dev_init_settings = mi2020_init_settings;
break;
- case ID_MI2020b:
- gspca_dev->sd_desc = &sd_desc_mi2020b;
- cam->cam_mode = mi2020_mode;
- cam->nmodes = ARRAY_SIZE(mi2020_mode);
- dev_init_settings = mi2020_init_settings;
- break;
-
case ID_OV2640:
gspca_dev->sd_desc = &sd_desc_ov2640;
cam->cam_mode = ov2640_mode;
@@ -513,7 +488,7 @@ static void sd_callback(struct gspca_dev *gspca_dev)
/*=================== USB driver structure initialisation ==================*/
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x05e3, 0x0503)},
{USB_DEVICE(0x05e3, 0xf191)},
{}
@@ -565,15 +540,12 @@ static int __init sd_mod_init(void)
if (usb_register(&sd_driver) < 0)
return -1;
- PDEBUG(D_PROBE, "driver registered");
-
return 0;
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "driver deregistered");
}
module_init(sd_mod_init);
@@ -613,17 +585,13 @@ int gl860_RTx(struct gspca_dev *gspca_dev,
}
if (r < 0)
- PDEBUG(D_ERR,
- "ctrl transfer failed %4d "
+ err("ctrl transfer failed %4d "
"[p%02x r%d v%04x i%04x len%d]",
r, pref, req, val, index, len);
else if (len > 1 && r < len)
PDEBUG(D_ERR, "short ctrl transfer %d/%d", r, len);
- if ((_MI2020_ || _MI2020b_ || _MI2020c_) && (val || index))
- msleep(1);
- if (_OV2640_)
- msleep(1);
+ msleep(1);
return r;
}
@@ -767,8 +735,6 @@ static int gl860_guess_sensor(struct gspca_dev *gspca_dev,
PDEBUG(D_PROBE, "05e3:f191 sensor MI1320 (1.3M)");
} else if (_MI2020_) {
PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 (2.0M)");
- } else if (_MI2020b_) {
- PDEBUG(D_PROBE, "05e3:0503 sensor MI2020 alt. driver (2.0M)");
} else if (_OV9655_) {
PDEBUG(D_PROBE, "05e3:0503 sensor OV9655 (1.3M)");
} else if (_OV2640_) {
diff --git a/drivers/media/video/gspca/gl860/gl860.h b/drivers/media/video/gspca/gl860/gl860.h
index 305061ff8387..49ad4acbf602 100644
--- a/drivers/media/video/gspca/gl860/gl860.h
+++ b/drivers/media/video/gspca/gl860/gl860.h
@@ -32,19 +32,16 @@
#define ID_OV2640 2
#define ID_OV9655 4
#define ID_MI2020 8
-#define ID_MI2020b 16
#define _MI1320_ (((struct sd *) gspca_dev)->sensor == ID_MI1320)
#define _MI2020_ (((struct sd *) gspca_dev)->sensor == ID_MI2020)
-#define _MI2020b_ (((struct sd *) gspca_dev)->sensor == ID_MI2020b)
-#define _MI2020c_ 0
#define _OV2640_ (((struct sd *) gspca_dev)->sensor == ID_OV2640)
#define _OV9655_ (((struct sd *) gspca_dev)->sensor == ID_OV9655)
#define IMAGE_640 0
#define IMAGE_800 1
#define IMAGE_1280 2
-#define IMAGE_1600 3
+#define IMAGE_1600 3
struct sd_gl860 {
u16 backlight;
@@ -75,10 +72,10 @@ struct sd {
int (*dev_camera_settings)(struct gspca_dev *);
u8 swapRB;
- u8 mirrorMask;
- u8 sensor;
- s32 nbIm;
- s32 nbRightUp;
+ u8 mirrorMask;
+ u8 sensor;
+ s32 nbIm;
+ s32 nbRightUp;
u8 waitSet;
};
diff --git a/drivers/media/video/gspca/gspca.c b/drivers/media/video/gspca/gspca.c
index 678675bb3652..f21f2a258ae0 100644
--- a/drivers/media/video/gspca/gspca.c
+++ b/drivers/media/video/gspca/gspca.c
@@ -55,7 +55,7 @@ MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA USB Camera Driver");
MODULE_LICENSE("GPL");
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 9, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(2, 12, 0)
#ifdef GSPCA_DEBUG
int gspca_debug = D_ERR | D_PROBE;
@@ -148,7 +148,7 @@ static void int_irq(struct urb *urb)
if (ret == 0) {
ret = usb_submit_urb(urb, GFP_ATOMIC);
if (ret < 0)
- PDEBUG(D_ERR, "Resubmit URB failed with error %i", ret);
+ err("Resubmit URB failed with error %i", ret);
}
}
@@ -177,8 +177,8 @@ static int gspca_input_connect(struct gspca_dev *dev)
err = input_register_device(input_dev);
if (err) {
- PDEBUG(D_ERR, "Input device registration failed "
- "with error %i", err);
+ err("Input device registration failed with error %i",
+ err);
input_dev->dev.parent = NULL;
input_free_device(input_dev);
} else {
@@ -201,7 +201,7 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
buffer_len = le16_to_cpu(ep->wMaxPacketSize);
interval = ep->bInterval;
- PDEBUG(D_PROBE, "found int in endpoint: 0x%x, "
+ PDEBUG(D_CONF, "found int in endpoint: 0x%x, "
"buffer_len=%u, interval=%u",
ep->bEndpointAddress, buffer_len, interval);
@@ -223,12 +223,13 @@ static int alloc_and_submit_int_urb(struct gspca_dev *gspca_dev,
usb_rcvintpipe(dev, ep->bEndpointAddress),
buffer, buffer_len,
int_irq, (void *)gspca_dev, interval);
- gspca_dev->int_urb = urb;
+ urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
ret = usb_submit_urb(urb, GFP_KERNEL);
if (ret < 0) {
- PDEBUG(D_ERR, "submit URB failed with error %i", ret);
+ PDEBUG(D_ERR, "submit int URB failed with error %i", ret);
goto error_submit;
}
+ gspca_dev->int_urb = urb;
return ret;
error_submit:
@@ -294,19 +295,6 @@ static inline int gspca_input_connect(struct gspca_dev *dev)
}
#endif
-/* get the current input frame buffer */
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev)
-{
- struct gspca_frame *frame;
-
- frame = gspca_dev->cur_frame;
- if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
- != V4L2_BUF_FLAG_QUEUED)
- return NULL;
- return frame;
-}
-EXPORT_SYMBOL(gspca_get_i_frame);
-
/*
* fill a video frame from an URB and resubmit
*/
@@ -330,22 +318,21 @@ static void fill_frame(struct gspca_dev *gspca_dev,
}
pkt_scan = gspca_dev->sd_desc->pkt_scan;
for (i = 0; i < urb->number_of_packets; i++) {
+ len = urb->iso_frame_desc[i].actual_length;
/* check the packet status and length */
- len = urb->iso_frame_desc[i].actual_length;
- if (len == 0) {
- if (gspca_dev->empty_packet == 0)
- gspca_dev->empty_packet = 1;
- continue;
- }
st = urb->iso_frame_desc[i].status;
if (st) {
- PDEBUG(D_ERR,
- "ISOC data error: [%d] len=%d, status=%d",
+ err("ISOC data error: [%d] len=%d, status=%d",
i, len, st);
gspca_dev->last_packet_type = DISCARD_PACKET;
continue;
}
+ if (len == 0) {
+ if (gspca_dev->empty_packet == 0)
+ gspca_dev->empty_packet = 1;
+ continue;
+ }
/* let the packet be analyzed by the subdriver */
PDEBUG(D_PACK, "packet [%d] o:%d l:%d",
@@ -359,7 +346,7 @@ resubmit:
/* resubmit the URB */
st = usb_submit_urb(urb, GFP_ATOMIC);
if (st < 0)
- PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+ err("usb_submit_urb() ret %d", st);
}
/*
@@ -413,7 +400,7 @@ resubmit:
if (gspca_dev->cam.bulk_nurbs != 0) {
st = usb_submit_urb(urb, GFP_ATOMIC);
if (st < 0)
- PDEBUG(D_ERR|D_PACK, "usb_submit_urb() ret %d", st);
+ err("usb_submit_urb() ret %d", st);
}
}
@@ -439,56 +426,71 @@ void gspca_frame_add(struct gspca_dev *gspca_dev,
PDEBUG(D_PACK, "add t:%d l:%d", packet_type, len);
- /* check the availability of the frame buffer */
- frame = gspca_dev->cur_frame;
- if ((frame->v4l2_buf.flags & BUF_ALL_FLAGS)
- != V4L2_BUF_FLAG_QUEUED) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
- /* when start of a new frame, if the current frame buffer
- * is not queued, discard the whole frame */
if (packet_type == FIRST_PACKET) {
- frame->data_end = frame->data;
+ i = atomic_read(&gspca_dev->fr_i);
+
+ /* if there are no queued buffer, discard the whole frame */
+ if (i == atomic_read(&gspca_dev->fr_q)) {
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_dev->sequence++;
+ return;
+ }
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
frame->v4l2_buf.timestamp = ktime_to_timeval(ktime_get());
- frame->v4l2_buf.sequence = ++gspca_dev->sequence;
- } else if (gspca_dev->last_packet_type == DISCARD_PACKET) {
- if (packet_type == LAST_PACKET)
- gspca_dev->last_packet_type = packet_type;
- return;
+ frame->v4l2_buf.sequence = gspca_dev->sequence++;
+ gspca_dev->image = frame->data;
+ gspca_dev->image_len = 0;
+ } else {
+ switch (gspca_dev->last_packet_type) {
+ case DISCARD_PACKET:
+ if (packet_type == LAST_PACKET)
+ gspca_dev->last_packet_type = packet_type;
+ return;
+ case LAST_PACKET:
+ return;
+ }
}
/* append the packet to the frame buffer */
if (len > 0) {
- if (frame->data_end - frame->data + len
- > frame->v4l2_buf.length) {
- PDEBUG(D_ERR|D_PACK, "frame overflow %zd > %d",
- frame->data_end - frame->data + len,
- frame->v4l2_buf.length);
+ if (gspca_dev->image_len + len > gspca_dev->frsz) {
+ PDEBUG(D_ERR|D_PACK, "frame overflow %d > %d",
+ gspca_dev->image_len + len,
+ gspca_dev->frsz);
packet_type = DISCARD_PACKET;
} else {
- memcpy(frame->data_end, data, len);
- frame->data_end += len;
+/* !! image is NULL only when last pkt is LAST or DISCARD
+ if (gspca_dev->image == NULL) {
+ err("gspca_frame_add() image == NULL");
+ return;
+ }
+ */
+ memcpy(gspca_dev->image + gspca_dev->image_len,
+ data, len);
+ gspca_dev->image_len += len;
}
}
gspca_dev->last_packet_type = packet_type;
- /* if last packet, wake up the application and advance in the queue */
+ /* if last packet, invalidate packet concatenation until
+ * next first packet, wake up the application and advance
+ * in the queue */
if (packet_type == LAST_PACKET) {
- frame->v4l2_buf.bytesused = frame->data_end - frame->data;
- frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_QUEUED;
- frame->v4l2_buf.flags |= V4L2_BUF_FLAG_DONE;
- wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
- i = (gspca_dev->fr_i + 1) % gspca_dev->nframes;
- gspca_dev->fr_i = i;
- PDEBUG(D_FRAM, "frame complete len:%d q:%d i:%d o:%d",
- frame->v4l2_buf.bytesused,
- gspca_dev->fr_q,
- i,
- gspca_dev->fr_o);
+ i = atomic_read(&gspca_dev->fr_i);
j = gspca_dev->fr_queue[i];
- gspca_dev->cur_frame = &gspca_dev->frame[j];
+ frame = &gspca_dev->frame[j];
+ frame->v4l2_buf.bytesused = gspca_dev->image_len;
+ frame->v4l2_buf.flags = (frame->v4l2_buf.flags
+ | V4L2_BUF_FLAG_DONE)
+ & ~V4L2_BUF_FLAG_QUEUED;
+ i = (i + 1) % GSPCA_MAX_FRAMES;
+ atomic_set(&gspca_dev->fr_i, i);
+ wake_up_interruptible(&gspca_dev->wq); /* event = new frame */
+ PDEBUG(D_FRAM, "frame complete len:%d",
+ frame->v4l2_buf.bytesused);
+ gspca_dev->image = NULL;
+ gspca_dev->image_len = 0;
}
}
EXPORT_SYMBOL(gspca_frame_add);
@@ -506,38 +508,8 @@ static int gspca_is_compressed(__u32 format)
return 0;
}
-static void *rvmalloc(long size)
-{
- void *mem;
- unsigned long adr;
-
- mem = vmalloc_32(size);
- if (mem != NULL) {
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *) adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- }
- return mem;
-}
-
-static void rvfree(void *mem, long size)
-{
- unsigned long adr;
-
- adr = (unsigned long) mem;
- while (size > 0) {
- ClearPageReserved(vmalloc_to_page((void *) adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-static int frame_alloc(struct gspca_dev *gspca_dev,
- unsigned int count)
+static int frame_alloc(struct gspca_dev *gspca_dev, struct file *file,
+ enum v4l2_memory memory, unsigned int count)
{
struct gspca_frame *frame;
unsigned int frsz;
@@ -547,14 +519,16 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
frsz = gspca_dev->cam.cam_mode[i].sizeimage;
PDEBUG(D_STREAM, "frame alloc frsz: %d", frsz);
frsz = PAGE_ALIGN(frsz);
- gspca_dev->frsz = frsz;
- if (count > GSPCA_MAX_FRAMES)
- count = GSPCA_MAX_FRAMES;
- gspca_dev->frbuf = rvmalloc(frsz * count);
+ if (count >= GSPCA_MAX_FRAMES)
+ count = GSPCA_MAX_FRAMES - 1;
+ gspca_dev->frbuf = vmalloc_32(frsz * count);
if (!gspca_dev->frbuf) {
err("frame alloc failed");
return -ENOMEM;
}
+ gspca_dev->capt_file = file;
+ gspca_dev->memory = memory;
+ gspca_dev->frsz = frsz;
gspca_dev->nframes = count;
for (i = 0; i < count; i++) {
frame = &gspca_dev->frame[i];
@@ -563,16 +537,14 @@ static int frame_alloc(struct gspca_dev *gspca_dev,
frame->v4l2_buf.flags = 0;
frame->v4l2_buf.field = V4L2_FIELD_NONE;
frame->v4l2_buf.length = frsz;
- frame->v4l2_buf.memory = gspca_dev->memory;
+ frame->v4l2_buf.memory = memory;
frame->v4l2_buf.sequence = 0;
- frame->data = frame->data_end =
- gspca_dev->frbuf + i * frsz;
+ frame->data = gspca_dev->frbuf + i * frsz;
frame->v4l2_buf.m.offset = i * frsz;
}
- gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
- gspca_dev->cur_frame = &gspca_dev->frame[0];
- gspca_dev->last_packet_type = DISCARD_PACKET;
- gspca_dev->sequence = 0;
+ atomic_set(&gspca_dev->fr_q, 0);
+ atomic_set(&gspca_dev->fr_i, 0);
+ gspca_dev->fr_o = 0;
return 0;
}
@@ -582,13 +554,15 @@ static void frame_free(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "frame free");
if (gspca_dev->frbuf != NULL) {
- rvfree(gspca_dev->frbuf,
- gspca_dev->nframes * gspca_dev->frsz);
+ vfree(gspca_dev->frbuf);
gspca_dev->frbuf = NULL;
for (i = 0; i < gspca_dev->nframes; i++)
gspca_dev->frame[i].data = NULL;
}
gspca_dev->nframes = 0;
+ gspca_dev->frsz = 0;
+ gspca_dev->capt_file = NULL;
+ gspca_dev->memory = GSPCA_MEMORY_NO;
}
static void destroy_urbs(struct gspca_dev *gspca_dev)
@@ -621,7 +595,7 @@ static int gspca_set_alt0(struct gspca_dev *gspca_dev)
return 0;
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 0);
if (ret < 0)
- PDEBUG(D_ERR|D_STREAM, "set alt 0 err %d", ret);
+ err("set alt 0 err %d", ret);
return ret;
}
@@ -703,13 +677,11 @@ static struct usb_host_endpoint *get_ep(struct gspca_dev *gspca_dev)
i, ep->desc.bEndpointAddress);
gspca_dev->alt = i; /* memorize the current alt setting */
if (gspca_dev->nbalt > 1) {
- gspca_input_destroy_urb(gspca_dev);
ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, i);
if (ret < 0) {
err("set alt %d err %d", i, ret);
ep = NULL;
}
- gspca_input_create_urb(gspca_dev);
}
return ep;
}
@@ -786,7 +758,7 @@ static int create_urbs(struct gspca_dev *gspca_dev,
}
} else { /* bulk */
urb->pipe = usb_rcvbulkpipe(gspca_dev->dev,
- ep->desc.bEndpointAddress),
+ ep->desc.bEndpointAddress);
urb->transfer_flags = URB_NO_TRANSFER_DMA_MAP;
urb->complete = bulk_irq;
}
@@ -808,9 +780,15 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
if (!gspca_dev->present) {
ret = -ENODEV;
- goto out;
+ goto unlock;
}
+ /* reset the streaming variables */
+ gspca_dev->image = NULL;
+ gspca_dev->image_len = 0;
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ gspca_dev->sequence = 0;
+
gspca_dev->usb_err = 0;
/* set the higher alternate setting and
@@ -823,8 +801,10 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
if (gspca_dev->sd_desc->isoc_init) {
ret = gspca_dev->sd_desc->isoc_init(gspca_dev);
if (ret < 0)
- goto out;
+ goto unlock;
}
+
+ gspca_input_destroy_urb(gspca_dev);
ep = get_ep(gspca_dev);
if (ep == NULL) {
ret = -EIO;
@@ -871,8 +851,7 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
break;
gspca_stream_off(gspca_dev);
if (ret != -ENOSPC) {
- PDEBUG(D_ERR|D_STREAM,
- "usb_submit_urb alt %d err %d",
+ err("usb_submit_urb alt %d err %d",
gspca_dev->alt, ret);
goto out;
}
@@ -895,12 +874,15 @@ static int gspca_init_transfer(struct gspca_dev *gspca_dev)
}
}
out:
+ gspca_input_create_urb(gspca_dev);
+unlock:
mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
{
+ struct gspca_ctrl *ctrl;
int i;
i = gspca_dev->cam.nmodes - 1; /* take the highest mode */
@@ -908,6 +890,16 @@ static void gspca_set_default_mode(struct gspca_dev *gspca_dev)
gspca_dev->width = gspca_dev->cam.cam_mode[i].width;
gspca_dev->height = gspca_dev->cam.cam_mode[i].height;
gspca_dev->pixfmt = gspca_dev->cam.cam_mode[i].pixelformat;
+
+ /* set the current control values to their default values
+ * which may have changed in sd_init() */
+ ctrl = gspca_dev->cam.ctrls;
+ if (ctrl != NULL) {
+ for (i = 0;
+ i < gspca_dev->sd_desc->nctrls;
+ i++, ctrl++)
+ ctrl->val = ctrl->def;
+ }
}
static int wxh_to_mode(struct gspca_dev *gspca_dev,
@@ -1223,29 +1215,15 @@ static void gspca_release(struct video_device *vfd)
static int dev_open(struct file *file)
{
struct gspca_dev *gspca_dev;
- int ret;
PDEBUG(D_STREAM, "[%s] open", current->comm);
gspca_dev = (struct gspca_dev *) video_devdata(file);
- if (mutex_lock_interruptible(&gspca_dev->queue_lock))
- return -ERESTARTSYS;
- if (!gspca_dev->present) {
- ret = -ENODEV;
- goto out;
- }
-
- if (gspca_dev->users > 4) { /* (arbitrary value) */
- ret = -EBUSY;
- goto out;
- }
+ if (!gspca_dev->present)
+ return -ENODEV;
/* protect the subdriver against rmmod */
- if (!try_module_get(gspca_dev->module)) {
- ret = -ENODEV;
- goto out;
- }
-
- gspca_dev->users++;
+ if (!try_module_get(gspca_dev->module))
+ return -ENODEV;
file->private_data = gspca_dev;
#ifdef GSPCA_DEBUG
@@ -1257,14 +1235,7 @@ static int dev_open(struct file *file)
gspca_dev->vdev.debug &= ~(V4L2_DEBUG_IOCTL
| V4L2_DEBUG_IOCTL_ARG);
#endif
- ret = 0;
-out:
- mutex_unlock(&gspca_dev->queue_lock);
- if (ret != 0)
- PDEBUG(D_ERR|D_STREAM, "open failed err %d", ret);
- else
- PDEBUG(D_STREAM, "open done");
- return ret;
+ return 0;
}
static int dev_close(struct file *file)
@@ -1274,7 +1245,6 @@ static int dev_close(struct file *file)
PDEBUG(D_STREAM, "[%s] close", current->comm);
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
- gspca_dev->users--;
/* if the file did the capture, free the streaming resources */
if (gspca_dev->capt_file == file) {
@@ -1285,8 +1255,6 @@ static int dev_close(struct file *file)
mutex_unlock(&gspca_dev->usb_lock);
}
frame_free(gspca_dev);
- gspca_dev->capt_file = NULL;
- gspca_dev->memory = GSPCA_MEMORY_NO;
}
file->private_data = NULL;
module_put(gspca_dev->module);
@@ -1310,17 +1278,19 @@ static int vidioc_querycap(struct file *file, void *priv,
ret = -ENODEV;
goto out;
}
- strncpy(cap->driver, gspca_dev->sd_desc->name, sizeof cap->driver);
+ strncpy((char *) cap->driver, gspca_dev->sd_desc->name,
+ sizeof cap->driver);
if (gspca_dev->dev->product != NULL) {
- strncpy(cap->card, gspca_dev->dev->product,
+ strncpy((char *) cap->card, gspca_dev->dev->product,
sizeof cap->card);
} else {
- snprintf(cap->card, sizeof cap->card,
+ snprintf((char *) cap->card, sizeof cap->card,
"USB Camera (%04x:%04x)",
le16_to_cpu(gspca_dev->dev->descriptor.idVendor),
le16_to_cpu(gspca_dev->dev->descriptor.idProduct));
}
- usb_make_path(gspca_dev->dev, cap->bus_info, sizeof(cap->bus_info));
+ usb_make_path(gspca_dev->dev, (char *) cap->bus_info,
+ sizeof(cap->bus_info));
cap->version = DRIVER_VERSION_NUMBER;
cap->capabilities = V4L2_CAP_VIDEO_CAPTURE
| V4L2_CAP_STREAMING
@@ -1331,7 +1301,7 @@ out:
return ret;
}
-static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
+static int get_ctrl(struct gspca_dev *gspca_dev,
int id)
{
const struct ctrl *ctrls;
@@ -1343,9 +1313,9 @@ static const struct ctrl *get_ctrl(struct gspca_dev *gspca_dev,
if (gspca_dev->ctrl_dis & (1 << i))
continue;
if (id == ctrls->qctrl.id)
- return ctrls;
+ return i;
}
- return NULL;
+ return -1;
}
static int vidioc_queryctrl(struct file *file, void *priv,
@@ -1353,34 +1323,40 @@ static int vidioc_queryctrl(struct file *file, void *priv,
{
struct gspca_dev *gspca_dev = priv;
const struct ctrl *ctrls;
- int i;
+ struct gspca_ctrl *gspca_ctrl;
+ int i, idx;
u32 id;
- ctrls = NULL;
id = q_ctrl->id;
if (id & V4L2_CTRL_FLAG_NEXT_CTRL) {
id &= V4L2_CTRL_ID_MASK;
id++;
+ idx = -1;
for (i = 0; i < gspca_dev->sd_desc->nctrls; i++) {
if (gspca_dev->ctrl_dis & (1 << i))
continue;
if (gspca_dev->sd_desc->ctrls[i].qctrl.id < id)
continue;
- if (ctrls && gspca_dev->sd_desc->ctrls[i].qctrl.id
- > ctrls->qctrl.id)
+ if (idx >= 0
+ && gspca_dev->sd_desc->ctrls[i].qctrl.id
+ > gspca_dev->sd_desc->ctrls[idx].qctrl.id)
continue;
- ctrls = &gspca_dev->sd_desc->ctrls[i];
+ idx = i;
}
- if (ctrls == NULL)
- return -EINVAL;
} else {
- ctrls = get_ctrl(gspca_dev, id);
- if (ctrls == NULL)
- return -EINVAL;
- i = ctrls - gspca_dev->sd_desc->ctrls;
+ idx = get_ctrl(gspca_dev, id);
}
- memcpy(q_ctrl, ctrls, sizeof *q_ctrl);
- if (gspca_dev->ctrl_inac & (1 << i))
+ if (idx < 0)
+ return -EINVAL;
+ ctrls = &gspca_dev->sd_desc->ctrls[idx];
+ memcpy(q_ctrl, &ctrls->qctrl, sizeof *q_ctrl);
+ if (gspca_dev->cam.ctrls != NULL) {
+ gspca_ctrl = &gspca_dev->cam.ctrls[idx];
+ q_ctrl->default_value = gspca_ctrl->def;
+ q_ctrl->minimum = gspca_ctrl->min;
+ q_ctrl->maximum = gspca_ctrl->max;
+ }
+ if (gspca_dev->ctrl_inac & (1 << idx))
q_ctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
return 0;
}
@@ -1390,23 +1366,46 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
{
struct gspca_dev *gspca_dev = priv;
const struct ctrl *ctrls;
- int ret;
+ struct gspca_ctrl *gspca_ctrl;
+ int idx, ret;
- ctrls = get_ctrl(gspca_dev, ctrl->id);
- if (ctrls == NULL)
+ idx = get_ctrl(gspca_dev, ctrl->id);
+ if (idx < 0)
return -EINVAL;
-
- if (ctrl->value < ctrls->qctrl.minimum
- || ctrl->value > ctrls->qctrl.maximum)
- return -ERANGE;
+ if (gspca_dev->ctrl_inac & (1 << idx))
+ return -EINVAL;
+ ctrls = &gspca_dev->sd_desc->ctrls[idx];
+ if (gspca_dev->cam.ctrls != NULL) {
+ gspca_ctrl = &gspca_dev->cam.ctrls[idx];
+ if (ctrl->value < gspca_ctrl->min
+ || ctrl->value > gspca_ctrl->max)
+ return -ERANGE;
+ } else {
+ gspca_ctrl = NULL;
+ if (ctrl->value < ctrls->qctrl.minimum
+ || ctrl->value > ctrls->qctrl.maximum)
+ return -ERANGE;
+ }
PDEBUG(D_CONF, "set ctrl [%08x] = %d", ctrl->id, ctrl->value);
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
+ if (!gspca_dev->present) {
+ ret = -ENODEV;
+ goto out;
+ }
gspca_dev->usb_err = 0;
- if (gspca_dev->present)
+ if (ctrls->set != NULL) {
ret = ctrls->set(gspca_dev, ctrl->value);
- else
- ret = -ENODEV;
+ goto out;
+ }
+ if (gspca_ctrl != NULL) {
+ gspca_ctrl->val = ctrl->value;
+ if (ctrls->set_control != NULL
+ && gspca_dev->streaming)
+ ctrls->set_control(gspca_dev);
+ }
+ ret = gspca_dev->usb_err;
+out:
mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
@@ -1416,51 +1415,32 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
{
struct gspca_dev *gspca_dev = priv;
const struct ctrl *ctrls;
- int ret;
+ int idx, ret;
- ctrls = get_ctrl(gspca_dev, ctrl->id);
- if (ctrls == NULL)
+ idx = get_ctrl(gspca_dev, ctrl->id);
+ if (idx < 0)
return -EINVAL;
+ ctrls = &gspca_dev->sd_desc->ctrls[idx];
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
+ if (!gspca_dev->present) {
+ ret = -ENODEV;
+ goto out;
+ }
gspca_dev->usb_err = 0;
- if (gspca_dev->present)
+ if (ctrls->get != NULL) {
ret = ctrls->get(gspca_dev, &ctrl->value);
- else
- ret = -ENODEV;
+ goto out;
+ }
+ if (gspca_dev->cam.ctrls != NULL)
+ ctrl->value = gspca_dev->cam.ctrls[idx].val;
+ ret = 0;
+out:
mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
-/*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)
-{
- 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)
{
@@ -1504,7 +1484,8 @@ static int vidioc_reqbufs(struct file *file, void *priv,
struct gspca_dev *gspca_dev = priv;
int i, ret = 0, streaming;
- switch (rb->memory) {
+ i = rb->memory; /* (avoid compilation warning) */
+ switch (i) {
case GSPCA_MEMORY_READ: /* (internal call) */
case V4L2_MEMORY_MMAP:
case V4L2_MEMORY_USERPTR:
@@ -1516,6 +1497,7 @@ static int vidioc_reqbufs(struct file *file, void *priv,
return -ERESTARTSYS;
if (gspca_dev->memory != GSPCA_MEMORY_NO
+ && gspca_dev->memory != GSPCA_MEMORY_READ
&& gspca_dev->memory != rb->memory) {
ret = -EBUSY;
goto out;
@@ -1544,19 +1526,18 @@ static int vidioc_reqbufs(struct file *file, void *priv,
gspca_stream_off(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
}
+ /* Don't restart the stream when switching from read to mmap mode */
+ if (gspca_dev->memory == GSPCA_MEMORY_READ)
+ streaming = 0;
/* free the previous allocated buffers, if any */
- if (gspca_dev->nframes != 0) {
+ if (gspca_dev->nframes != 0)
frame_free(gspca_dev);
- gspca_dev->capt_file = NULL;
- }
if (rb->count == 0) /* unrequest */
goto out;
- gspca_dev->memory = rb->memory;
- ret = frame_alloc(gspca_dev, rb->count);
+ ret = frame_alloc(gspca_dev, file, rb->memory, rb->count);
if (ret == 0) {
rb->count = gspca_dev->nframes;
- gspca_dev->capt_file = file;
if (streaming)
ret = gspca_init_transfer(gspca_dev);
}
@@ -1626,15 +1607,19 @@ static int vidioc_streamoff(struct file *file, void *priv,
enum v4l2_buf_type buf_type)
{
struct gspca_dev *gspca_dev = priv;
- int i, ret;
+ int ret;
if (buf_type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if (!gspca_dev->streaming)
- return 0;
+
if (mutex_lock_interruptible(&gspca_dev->queue_lock))
return -ERESTARTSYS;
+ if (!gspca_dev->streaming) {
+ ret = 0;
+ goto out;
+ }
+
/* check the capture file */
if (gspca_dev->capt_file != file) {
ret = -EBUSY;
@@ -1649,13 +1634,13 @@ static int vidioc_streamoff(struct file *file, void *priv,
gspca_dev->usb_err = 0;
gspca_stream_off(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
+ /* In case another thread is waiting in dqbuf */
+ wake_up_interruptible(&gspca_dev->wq);
- /* empty the application queues */
- for (i = 0; i < gspca_dev->nframes; i++)
- gspca_dev->frame[i].v4l2_buf.flags &= ~BUF_ALL_FLAGS;
- gspca_dev->fr_i = gspca_dev->fr_o = gspca_dev->fr_q = 0;
- gspca_dev->last_packet_type = DISCARD_PACKET;
- gspca_dev->sequence = 0;
+ /* empty the transfer queues */
+ atomic_set(&gspca_dev->fr_q, 0);
+ atomic_set(&gspca_dev->fr_i, 0);
+ gspca_dev->fr_o = 0;
ret = 0;
out:
mutex_unlock(&gspca_dev->queue_lock);
@@ -1712,12 +1697,13 @@ static int vidioc_g_parm(struct file *filp, void *priv,
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
- gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->get_streamparm(gspca_dev,
- parm);
- else
+ if (gspca_dev->present) {
+ gspca_dev->usb_err = 0;
+ gspca_dev->sd_desc->get_streamparm(gspca_dev, parm);
+ ret = gspca_dev->usb_err;
+ } else {
ret = -ENODEV;
+ }
mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
@@ -1732,7 +1718,7 @@ static int vidioc_s_parm(struct file *filp, void *priv,
int n;
n = parm->parm.capture.readbuffers;
- if (n == 0 || n > GSPCA_MAX_FRAMES)
+ if (n == 0 || n >= GSPCA_MAX_FRAMES)
parm->parm.capture.readbuffers = gspca_dev->nbufread;
else
gspca_dev->nbufread = n;
@@ -1742,12 +1728,13 @@ static int vidioc_s_parm(struct file *filp, void *priv,
if (mutex_lock_interruptible(&gspca_dev->usb_lock))
return -ERESTARTSYS;
- gspca_dev->usb_err = 0;
- if (gspca_dev->present)
- ret = gspca_dev->sd_desc->set_streamparm(gspca_dev,
- parm);
- else
+ if (gspca_dev->present) {
+ gspca_dev->usb_err = 0;
+ gspca_dev->sd_desc->set_streamparm(gspca_dev, parm);
+ ret = gspca_dev->usb_err;
+ } else {
ret = -ENODEV;
+ }
mutex_unlock(&gspca_dev->usb_lock);
return ret;
}
@@ -1755,49 +1742,6 @@ static int vidioc_s_parm(struct file *filp, void *priv,
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv,
- struct video_mbuf *mbuf)
-{
- struct gspca_dev *gspca_dev = file->private_data;
- int i;
-
- PDEBUG(D_STREAM, "cgmbuf");
- if (gspca_dev->nframes == 0) {
- int ret;
-
- {
- struct v4l2_format fmt;
-
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- i = gspca_dev->cam.nmodes - 1; /* highest mode */
- fmt.fmt.pix.width = gspca_dev->cam.cam_mode[i].width;
- fmt.fmt.pix.height = gspca_dev->cam.cam_mode[i].height;
- fmt.fmt.pix.pixelformat = V4L2_PIX_FMT_BGR24;
- ret = vidioc_s_fmt_vid_cap(file, priv, &fmt);
- if (ret != 0)
- return ret;
- }
- {
- struct v4l2_requestbuffers rb;
-
- memset(&rb, 0, sizeof rb);
- rb.count = 4;
- rb.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- rb.memory = V4L2_MEMORY_MMAP;
- ret = vidioc_reqbufs(file, priv, &rb);
- if (ret != 0)
- return ret;
- }
- }
- mbuf->frames = gspca_dev->nframes;
- mbuf->size = gspca_dev->frsz * gspca_dev->nframes;
- for (i = 0; i < mbuf->frames; i++)
- mbuf->offsets[i] = gspca_dev->frame[i].v4l2_buf.m.offset;
- return 0;
-}
-#endif
-
static int dev_mmap(struct file *file, struct vm_area_struct *vma)
{
struct gspca_dev *gspca_dev = file->private_data;
@@ -1838,12 +1782,7 @@ static int dev_mmap(struct file *file, struct vm_area_struct *vma)
ret = -EINVAL;
goto out;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* v4l1 maps all the buffers */
- if (i != 0
- || size != frame->v4l2_buf.length * gspca_dev->nframes)
-#endif
- if (size != frame->v4l2_buf.length) {
+ if (size != frame->v4l2_buf.length) {
PDEBUG(D_STREAM, "mmap bad size");
ret = -EINVAL;
goto out;
@@ -1875,42 +1814,78 @@ out:
return ret;
}
+static int frame_ready_nolock(struct gspca_dev *gspca_dev, struct file *file,
+ enum v4l2_memory memory)
+{
+ if (!gspca_dev->present)
+ return -ENODEV;
+ if (gspca_dev->capt_file != file || gspca_dev->memory != memory ||
+ !gspca_dev->streaming)
+ return -EINVAL;
+
+ /* check if a frame is ready */
+ return gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i);
+}
+
+static int frame_ready(struct gspca_dev *gspca_dev, struct file *file,
+ enum v4l2_memory memory)
+{
+ int ret;
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
+ ret = frame_ready_nolock(gspca_dev, file, memory);
+ mutex_unlock(&gspca_dev->queue_lock);
+ return ret;
+}
+
/*
- * wait for a video frame
+ * dequeue a video buffer
*
- * If a frame is ready, its index is returned.
+ * If nonblock_ing is false, block until a buffer is available.
*/
-static int frame_wait(struct gspca_dev *gspca_dev,
- int nonblock_ing)
+static int vidioc_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *v4l2_buf)
{
+ struct gspca_dev *gspca_dev = priv;
struct gspca_frame *frame;
int i, j, ret;
- /* check if a frame is ready */
- i = gspca_dev->fr_o;
- j = gspca_dev->fr_queue[i];
- frame = &gspca_dev->frame[j];
+ PDEBUG(D_FRAM, "dqbuf");
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
- if (!(frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE)) {
- if (nonblock_ing)
+ for (;;) {
+ ret = frame_ready_nolock(gspca_dev, file, v4l2_buf->memory);
+ if (ret < 0)
+ goto out;
+ if (ret > 0)
+ break;
+
+ mutex_unlock(&gspca_dev->queue_lock);
+
+ if (file->f_flags & O_NONBLOCK)
return -EAGAIN;
/* wait till a frame is ready */
ret = wait_event_interruptible_timeout(gspca_dev->wq,
- (frame->v4l2_buf.flags & V4L2_BUF_FLAG_DONE) ||
- !gspca_dev->streaming || !gspca_dev->present,
+ frame_ready(gspca_dev, file, v4l2_buf->memory),
msecs_to_jiffies(3000));
if (ret < 0)
return ret;
- if (ret == 0 || !gspca_dev->streaming || !gspca_dev->present)
+ if (ret == 0)
return -EIO;
+
+ if (mutex_lock_interruptible(&gspca_dev->queue_lock))
+ return -ERESTARTSYS;
}
- gspca_dev->fr_o = (i + 1) % gspca_dev->nframes;
- PDEBUG(D_FRAM, "frame wait q:%d i:%d o:%d",
- gspca_dev->fr_q,
- gspca_dev->fr_i,
- gspca_dev->fr_o);
+ i = gspca_dev->fr_o;
+ j = gspca_dev->fr_queue[i];
+ frame = &gspca_dev->frame[j];
+
+ gspca_dev->fr_o = (i + 1) % GSPCA_MAX_FRAMES;
if (gspca_dev->sd_desc->dq_callback) {
mutex_lock(&gspca_dev->usb_lock);
@@ -1919,46 +1894,12 @@ static int frame_wait(struct gspca_dev *gspca_dev,
gspca_dev->sd_desc->dq_callback(gspca_dev);
mutex_unlock(&gspca_dev->usb_lock);
}
- return j;
-}
-/*
- * dequeue a video buffer
- *
- * If nonblock_ing is false, block until a buffer is available.
- */
-static int vidioc_dqbuf(struct file *file, void *priv,
- struct v4l2_buffer *v4l2_buf)
-{
- struct gspca_dev *gspca_dev = priv;
- struct gspca_frame *frame;
- int i, ret;
-
- PDEBUG(D_FRAM, "dqbuf");
- if (v4l2_buf->memory != gspca_dev->memory)
- return -EINVAL;
-
- if (!gspca_dev->present)
- return -ENODEV;
-
- /* if not streaming, be sure the application will not loop forever */
- if (!(file->f_flags & O_NONBLOCK)
- && !gspca_dev->streaming && gspca_dev->users == 1)
- return -EINVAL;
-
- /* only the capturing file may dequeue */
- if (gspca_dev->capt_file != file)
- return -EINVAL;
-
- /* only one dequeue / read at a time */
- if (mutex_lock_interruptible(&gspca_dev->read_lock))
- return -ERESTARTSYS;
+ frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
+ memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
+ PDEBUG(D_FRAM, "dqbuf %d", j);
+ ret = 0;
- ret = frame_wait(gspca_dev, file->f_flags & O_NONBLOCK);
- if (ret < 0)
- goto out;
- i = ret; /* frame index */
- frame = &gspca_dev->frame[i];
if (gspca_dev->memory == V4L2_MEMORY_USERPTR) {
if (copy_to_user((__u8 __user *) frame->v4l2_buf.m.userptr,
frame->data,
@@ -1966,15 +1907,10 @@ static int vidioc_dqbuf(struct file *file, void *priv,
PDEBUG(D_ERR|D_STREAM,
"dqbuf cp to user failed");
ret = -EFAULT;
- goto out;
}
}
- frame->v4l2_buf.flags &= ~V4L2_BUF_FLAG_DONE;
- memcpy(v4l2_buf, &frame->v4l2_buf, sizeof *v4l2_buf);
- PDEBUG(D_FRAM, "dqbuf %d", i);
- ret = 0;
out:
- mutex_unlock(&gspca_dev->read_lock);
+ mutex_unlock(&gspca_dev->queue_lock);
return ret;
}
@@ -2024,15 +1960,9 @@ static int vidioc_qbuf(struct file *file, void *priv,
}
/* put the buffer in the 'queued' queue */
- i = gspca_dev->fr_q;
+ i = atomic_read(&gspca_dev->fr_q);
gspca_dev->fr_queue[i] = index;
- if (gspca_dev->fr_i == i)
- gspca_dev->cur_frame = frame;
- gspca_dev->fr_q = (i + 1) % gspca_dev->nframes;
- PDEBUG(D_FRAM, "qbuf q:%d i:%d o:%d",
- gspca_dev->fr_q,
- gspca_dev->fr_i,
- gspca_dev->fr_o);
+ atomic_set(&gspca_dev->fr_q, (i + 1) % GSPCA_MAX_FRAMES);
v4l2_buf->flags |= V4L2_BUF_FLAG_QUEUED;
v4l2_buf->flags &= ~V4L2_BUF_FLAG_DONE;
@@ -2088,16 +2018,14 @@ static int read_alloc(struct gspca_dev *gspca_dev,
static unsigned int dev_poll(struct file *file, poll_table *wait)
{
struct gspca_dev *gspca_dev = file->private_data;
- int i, ret;
+ int ret;
PDEBUG(D_FRAM, "poll");
poll_wait(file, &gspca_dev->wq, wait);
/* if reqbufs is not done, the user would use read() */
- if (gspca_dev->nframes == 0) {
- if (gspca_dev->memory != GSPCA_MEMORY_NO)
- return POLLERR; /* not the 1st time */
+ if (gspca_dev->memory == GSPCA_MEMORY_NO) {
ret = read_alloc(gspca_dev, file);
if (ret != 0)
return POLLERR;
@@ -2106,11 +2034,9 @@ static unsigned int dev_poll(struct file *file, poll_table *wait)
if (mutex_lock_interruptible(&gspca_dev->queue_lock) != 0)
return POLLERR;
- /* check the next incoming buffer */
- i = gspca_dev->fr_o;
- i = gspca_dev->fr_queue[i];
- if (gspca_dev->frame[i].v4l2_buf.flags & V4L2_BUF_FLAG_DONE)
- ret = POLLIN | POLLRDNORM; /* something to read */
+ /* check if an image has been received */
+ if (gspca_dev->fr_o != atomic_read(&gspca_dev->fr_i))
+ ret = POLLIN | POLLRDNORM; /* yes */
else
ret = 0;
mutex_unlock(&gspca_dev->queue_lock);
@@ -2131,18 +2057,10 @@ static ssize_t dev_read(struct file *file, char __user *data,
PDEBUG(D_FRAM, "read (%zd)", count);
if (!gspca_dev->present)
return -ENODEV;
- switch (gspca_dev->memory) {
- case GSPCA_MEMORY_NO: /* first time */
+ if (gspca_dev->memory == GSPCA_MEMORY_NO) { /* first time ? */
ret = read_alloc(gspca_dev, file);
if (ret != 0)
return ret;
- break;
- case GSPCA_MEMORY_READ:
- if (gspca_dev->capt_file == file)
- break;
- /* fall thru */
- default:
- return -EINVAL;
}
/* get a frame */
@@ -2214,9 +2132,6 @@ 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,
@@ -2235,9 +2150,6 @@ static const struct v4l2_ioctl_ops dev_ioctl_ops = {
.vidioc_s_register = vidioc_s_register,
#endif
.vidioc_g_chip_ident = vidioc_g_chip_ident,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static struct video_device gspca_template = {
@@ -2247,37 +2159,40 @@ static struct video_device gspca_template = {
.release = gspca_release,
};
+/* initialize the controls */
+static void ctrls_init(struct gspca_dev *gspca_dev)
+{
+ struct gspca_ctrl *ctrl;
+ int i;
+
+ for (i = 0, ctrl = gspca_dev->cam.ctrls;
+ i < gspca_dev->sd_desc->nctrls;
+ i++, ctrl++) {
+ ctrl->def = gspca_dev->sd_desc->ctrls[i].qctrl.default_value;
+ ctrl->val = ctrl->def;
+ ctrl->min = gspca_dev->sd_desc->ctrls[i].qctrl.minimum;
+ ctrl->max = gspca_dev->sd_desc->ctrls[i].qctrl.maximum;
+ }
+}
+
/*
* probe and create a new gspca device
*
* This function must be called by the sub-driver when it is
* called for probing a new device.
*/
-int gspca_dev_probe(struct usb_interface *intf,
+int gspca_dev_probe2(struct usb_interface *intf,
const struct usb_device_id *id,
const struct sd_desc *sd_desc,
int dev_size,
struct module *module)
{
- struct usb_interface_descriptor *interface;
struct gspca_dev *gspca_dev;
struct usb_device *dev = interface_to_usbdev(intf);
int ret;
PDEBUG(D_PROBE, "probing %04x:%04x", id->idVendor, id->idProduct);
- /* we don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1) {
- PDEBUG(D_ERR, "Too many config");
- return -ENODEV;
- }
-
- /* the USB video interface must be the first one */
- interface = &intf->cur_altsetting->desc;
- if (dev->config->desc.bNumInterfaces != 1 &&
- interface->bInterfaceNumber != 0)
- return -ENODEV;
-
/* create the device */
if (dev_size < sizeof *gspca_dev)
dev_size = sizeof *gspca_dev;
@@ -2293,8 +2208,26 @@ int gspca_dev_probe(struct usb_interface *intf,
goto out;
}
gspca_dev->dev = dev;
- gspca_dev->iface = interface->bInterfaceNumber;
+ gspca_dev->iface = intf->cur_altsetting->desc.bInterfaceNumber;
gspca_dev->nbalt = intf->num_altsetting;
+
+ /* check if any audio device */
+ if (dev->config->desc.bNumInterfaces != 1) {
+ int i;
+ struct usb_interface *intf2;
+
+ for (i = 0; i < dev->config->desc.bNumInterfaces; i++) {
+ intf2 = dev->config->interface[i];
+ if (intf2 != NULL
+ && intf2->altsetting != NULL
+ && intf2->altsetting->desc.bInterfaceClass ==
+ USB_CLASS_AUDIO) {
+ gspca_dev->audio = 1;
+ break;
+ }
+ }
+ }
+
gspca_dev->sd_desc = sd_desc;
gspca_dev->nbufread = 2;
gspca_dev->empty_packet = -1; /* don't check the empty packets */
@@ -2303,6 +2236,8 @@ int gspca_dev_probe(struct usb_interface *intf,
ret = sd_desc->config(gspca_dev, id);
if (ret < 0)
goto out;
+ if (gspca_dev->cam.ctrls != NULL)
+ ctrls_init(gspca_dev);
ret = sd_desc->init(gspca_dev);
if (ret < 0)
goto out;
@@ -2313,7 +2248,6 @@ int gspca_dev_probe(struct usb_interface *intf,
goto out;
mutex_init(&gspca_dev->usb_lock);
- mutex_init(&gspca_dev->read_lock);
mutex_init(&gspca_dev->queue_lock);
init_waitqueue_head(&gspca_dev->wq);
@@ -2345,6 +2279,31 @@ out:
kfree(gspca_dev);
return ret;
}
+EXPORT_SYMBOL(gspca_dev_probe2);
+
+/* same function as the previous one, but check the interface */
+int gspca_dev_probe(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module)
+{
+ struct usb_device *dev = interface_to_usbdev(intf);
+
+ /* we don't handle multi-config cameras */
+ if (dev->descriptor.bNumConfigurations != 1) {
+ err("%04x:%04x too many config",
+ id->idVendor, id->idProduct);
+ return -ENODEV;
+ }
+
+ /* the USB video interface must be the first one */
+ if (dev->config->desc.bNumInterfaces != 1
+ && intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
+
+ return gspca_dev_probe2(intf, id, sd_desc, dev_size, module);
+}
EXPORT_SYMBOL(gspca_dev_probe);
/*
@@ -2363,12 +2322,11 @@ void gspca_disconnect(struct usb_interface *intf)
PDEBUG(D_PROBE, "%s disconnect",
video_device_node_name(&gspca_dev->vdev));
mutex_lock(&gspca_dev->usb_lock);
+
gspca_dev->present = 0;
+ wake_up_interruptible(&gspca_dev->wq);
- if (gspca_dev->streaming) {
- destroy_urbs(gspca_dev);
- wake_up_interruptible(&gspca_dev->wq);
- }
+ destroy_urbs(gspca_dev);
#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
gspca_input_destroy_urb(gspca_dev);
@@ -2518,7 +2476,7 @@ EXPORT_SYMBOL(gspca_auto_gain_n_exposure);
/* -- module insert / remove -- */
static int __init gspca_init(void)
{
- info("main v%d.%d.%d registered",
+ info("v%d.%d.%d registered",
(DRIVER_VERSION_NUMBER >> 16) & 0xff,
(DRIVER_VERSION_NUMBER >> 8) & 0xff,
DRIVER_VERSION_NUMBER & 0xff);
@@ -2526,7 +2484,6 @@ static int __init gspca_init(void)
}
static void __exit gspca_exit(void)
{
- info("main deregistered");
}
module_init(gspca_init);
diff --git a/drivers/media/video/gspca/gspca.h b/drivers/media/video/gspca/gspca.h
index 8b963dfae861..41755226d389 100644
--- a/drivers/media/video/gspca/gspca.h
+++ b/drivers/media/video/gspca/gspca.h
@@ -7,7 +7,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <linux/mutex.h>
-#include <linux/slab.h>
/* compilation option */
#define GSPCA_DEBUG 1
@@ -53,11 +52,20 @@ struct framerates {
int nrates;
};
+/* control definition */
+struct gspca_ctrl {
+ s16 val; /* current value */
+ s16 def; /* default value */
+ s16 min, max; /* minimum and maximum values */
+};
+
/* device information - set at probe time */
struct cam {
const struct v4l2_pix_format *cam_mode; /* size nmodes */
- const struct framerates *mode_framerates; /* must have size nmode,
+ const struct framerates *mode_framerates; /* must have size nmodes,
* just like cam_mode */
+ struct gspca_ctrl *ctrls; /* control table - size nctrls */
+ /* may be NULL */
u32 bulk_size; /* buffer size when image transfer by bulk */
u32 input_flags; /* value for ENUM_INPUT status flags */
u8 nmodes; /* size of cam_mode */
@@ -85,7 +93,7 @@ typedef int (*cam_reg_op) (struct gspca_dev *,
struct v4l2_dbg_register *);
typedef int (*cam_ident_op) (struct gspca_dev *,
struct v4l2_dbg_chip_ident *);
-typedef int (*cam_streamparm_op) (struct gspca_dev *,
+typedef void (*cam_streamparm_op) (struct gspca_dev *,
struct v4l2_streamparm *);
typedef int (*cam_qmnu_op) (struct gspca_dev *,
struct v4l2_querymenu *);
@@ -100,6 +108,7 @@ struct ctrl {
struct v4l2_queryctrl qctrl;
int (*set)(struct gspca_dev *, __s32);
int (*get)(struct gspca_dev *, __s32 *);
+ cam_v_op set_control;
};
/* subdriver description */
@@ -107,7 +116,7 @@ struct sd_desc {
/* information */
const char *name; /* sub-driver name */
/* controls */
- const struct ctrl *ctrls;
+ const struct ctrl *ctrls; /* static control definition */
int nctrls;
/* mandatory operations */
cam_cf_op config; /* called on probe */
@@ -148,7 +157,6 @@ enum gspca_packet_type {
struct gspca_frame {
__u8 *data; /* frame buffer */
- __u8 *data_end; /* end of frame while filling */
int vma_use_count;
struct v4l2_buffer v4l2_buf;
};
@@ -177,13 +185,14 @@ struct gspca_dev {
__u8 *frbuf; /* buffer for nframes */
struct gspca_frame frame[GSPCA_MAX_FRAMES];
- struct gspca_frame *cur_frame; /* frame beeing filled */
+ u8 *image; /* image beeing filled */
__u32 frsz; /* frame size */
- char nframes; /* number of frames */
- char fr_i; /* frame being filled */
- char fr_q; /* next frame to queue */
- char fr_o; /* next frame to dequeue */
+ u32 image_len; /* current length of image */
+ atomic_t fr_q; /* next frame to queue */
+ atomic_t fr_i; /* frame being filled */
signed char fr_queue[GSPCA_MAX_FRAMES]; /* frame queue */
+ char nframes; /* number of frames */
+ u8 fr_o; /* next frame to dequeue */
__u8 last_packet_type;
__s8 empty_packet; /* if (-1) don't check empty packets */
__u8 streaming;
@@ -196,20 +205,19 @@ struct gspca_dev {
wait_queue_head_t wq; /* wait queue */
struct mutex usb_lock; /* usb exchange protection */
- struct mutex read_lock; /* read protection */
struct mutex queue_lock; /* ISOC queue protection */
int usb_err; /* USB error - protected by usb_lock */
+ u16 pkt_size; /* ISOC packet size */
#ifdef CONFIG_PM
char frozen; /* suspend - resume */
#endif
- char users; /* number of opens */
char present; /* device connected */
char nbufread; /* number of buffers for read() */
char memory; /* memory type (V4L2_MEMORY_xxx) */
__u8 iface; /* USB interface number */
__u8 alt; /* USB alternate setting */
__u8 nbalt; /* number of USB alternate settings */
- u16 pkt_size; /* ISOC packet size */
+ u8 audio; /* presence of audio device */
};
int gspca_dev_probe(struct usb_interface *intf,
@@ -217,12 +225,16 @@ int gspca_dev_probe(struct usb_interface *intf,
const struct sd_desc *sd_desc,
int dev_size,
struct module *module);
+int gspca_dev_probe2(struct usb_interface *intf,
+ const struct usb_device_id *id,
+ const struct sd_desc *sd_desc,
+ int dev_size,
+ struct module *module);
void gspca_disconnect(struct usb_interface *intf);
void gspca_frame_add(struct gspca_dev *gspca_dev,
enum gspca_packet_type packet_type,
const u8 *data,
int len);
-struct gspca_frame *gspca_get_i_frame(struct gspca_dev *gspca_dev);
#ifdef CONFIG_PM
int gspca_suspend(struct usb_interface *intf, pm_message_t message);
int gspca_resume(struct usb_interface *intf);
diff --git a/drivers/media/video/gspca/jeilinj.c b/drivers/media/video/gspca/jeilinj.c
index 84ecd56c6470..06b777f5379e 100644
--- a/drivers/media/video/gspca/jeilinj.c
+++ b/drivers/media/video/gspca/jeilinj.c
@@ -50,7 +50,7 @@ struct sd {
struct workqueue_struct *work_thread;
u8 quality; /* image quality */
u8 jpegqual; /* webcam quality */
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
struct jlj_command {
@@ -82,7 +82,7 @@ static int jlj_write2(struct gspca_dev *gspca_dev, unsigned char *command)
usb_sndbulkpipe(gspca_dev->dev, 3),
gspca_dev->usb_buf, 2, NULL, 500);
if (retval < 0)
- PDEBUG(D_ERR, "command write [%02x] error %d",
+ err("command write [%02x] error %d",
gspca_dev->usb_buf[0], retval);
return retval;
}
@@ -97,7 +97,7 @@ static int jlj_read1(struct gspca_dev *gspca_dev, unsigned char response)
gspca_dev->usb_buf, 1, NULL, 500);
response = gspca_dev->usb_buf[0];
if (retval < 0)
- PDEBUG(D_ERR, "read command [%02x] error %d",
+ err("read command [%02x] error %d",
gspca_dev->usb_buf[0], retval);
return retval;
}
@@ -191,7 +191,7 @@ static void jlj_dostream(struct work_struct *work)
buffer = kmalloc(JEILINJ_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
if (!buffer) {
- PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+ err("Couldn't allocate USB buffer");
goto quit_stream;
}
while (gspca_dev->present && gspca_dev->streaming) {
@@ -282,7 +282,6 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
destroy_workqueue(dev->work_thread);
dev->work_thread = NULL;
mutex_lock(&gspca_dev->usb_lock);
- kfree(dev->jpeg_hdr);
}
/* this function is called at probe and resume time */
@@ -298,9 +297,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int ret;
/* create the JPEG header */
- dev->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (dev->jpeg_hdr == NULL)
- return -ENOMEM;
jpeg_define(dev->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(dev->jpeg_hdr, dev->quality);
@@ -318,7 +314,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0979, 0x0280)},
{}
};
@@ -358,19 +354,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/jpeg.h b/drivers/media/video/gspca/jpeg.h
index de63c36806c0..ab54910418b4 100644
--- a/drivers/media/video/gspca/jpeg.h
+++ b/drivers/media/video/gspca/jpeg.h
@@ -141,9 +141,9 @@ static void jpeg_define(u8 *jpeg_hdr,
memcpy(jpeg_hdr, jpeg_head, sizeof jpeg_head);
#ifndef CONEX_CAM
jpeg_hdr[JPEG_HEIGHT_OFFSET + 0] = height >> 8;
- jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height & 0xff;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 1] = height;
jpeg_hdr[JPEG_HEIGHT_OFFSET + 2] = width >> 8;
- jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width & 0xff;
+ jpeg_hdr[JPEG_HEIGHT_OFFSET + 3] = width;
jpeg_hdr[JPEG_HEIGHT_OFFSET + 6] = samplesY;
#endif
}
diff --git a/drivers/media/video/gspca/konica.c b/drivers/media/video/gspca/konica.c
new file mode 100644
index 000000000000..5964691c0e95
--- /dev/null
+++ b/drivers/media/video/gspca/konica.c
@@ -0,0 +1,646 @@
+/*
+ * Driver for USB webcams based on Konica chipset. This
+ * chipset is used in Intel YC76 camera.
+ *
+ * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
+ *
+ * Based on the usbvideo v4l1 konicawc driver which is:
+ *
+ * Copyright (C) 2002 Simon Evans <spse@secret.org.uk>
+ *
+ * The code for making gspca work with a webcam with 2 isoc endpoints was
+ * taken from the benq gspca subdriver which is:
+ *
+ * Copyright (C) 2009 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * 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
+ */
+
+#define MODULE_NAME "konica"
+
+#include <linux/input.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Konica chipset USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+#define WHITEBAL_REG 0x01
+#define BRIGHTNESS_REG 0x02
+#define SHARPNESS_REG 0x03
+#define CONTRAST_REG 0x04
+#define SATURATION_REG 0x05
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ struct urb *last_data_urb;
+ u8 snapshot_pressed;
+ u8 brightness;
+ u8 contrast;
+ u8 saturation;
+ u8 whitebal;
+ u8 sharpness;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getwhitebal(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 const struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 9,
+ .step = 1,
+#define BRIGHTNESS_DEFAULT 4
+ .default_value = BRIGHTNESS_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 9,
+ .step = 4,
+#define CONTRAST_DEFAULT 10
+ .default_value = CONTRAST_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_SATURATION 2
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 9,
+ .step = 1,
+#define SATURATION_DEFAULT 4
+ .default_value = SATURATION_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setsaturation,
+ .get = sd_getsaturation,
+ },
+#define SD_WHITEBAL 3
+ {
+ {
+ .id = V4L2_CID_WHITE_BALANCE_TEMPERATURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "White Balance",
+ .minimum = 0,
+ .maximum = 33,
+ .step = 1,
+#define WHITEBAL_DEFAULT 25
+ .default_value = WHITEBAL_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setwhitebal,
+ .get = sd_getwhitebal,
+ },
+#define SD_SHARPNESS 4
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = 9,
+ .step = 1,
+#define SHARPNESS_DEFAULT 4
+ .default_value = SHARPNESS_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+};
+
+/* .priv is what goes to register 8 for this mode, known working values:
+ 0x00 -> 176x144, cropped
+ 0x01 -> 176x144, cropped
+ 0x02 -> 176x144, cropped
+ 0x03 -> 176x144, cropped
+ 0x04 -> 176x144, binned
+ 0x05 -> 320x240
+ 0x06 -> 320x240
+ 0x07 -> 160x120, cropped
+ 0x08 -> 160x120, cropped
+ 0x09 -> 160x120, binned (note has 136 lines)
+ 0x0a -> 160x120, binned (note has 136 lines)
+ 0x0b -> 160x120, cropped
+*/
+static const struct v4l2_pix_format vga_mode[] = {
+ {160, 120, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 136 * 3 / 2 + 960,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0x0a},
+ {176, 144, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 2 + 960,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0x04},
+ {320, 240, V4L2_PIX_FMT_KONICA420, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 2 + 960,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0x05},
+};
+
+static void sd_isoc_irq(struct urb *urb);
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ 0x02,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ NULL,
+ 0,
+ 1000);
+ if (ret < 0) {
+ err("reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_r(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ 0x03,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value,
+ index,
+ gspca_dev->usb_buf,
+ 2,
+ 1000);
+ if (ret < 0) {
+ err("reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void konica_stream_on(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 1, 0x0b);
+}
+
+static void konica_stream_off(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0, 0x0b);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->cam.cam_mode = vga_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+ gspca_dev->cam.no_urb_create = 1;
+ /* The highest alt setting has an isoc packetsize of 0, so we
+ don't want to use it */
+ gspca_dev->nbalt--;
+
+ sd->brightness = BRIGHTNESS_DEFAULT;
+ sd->contrast = CONTRAST_DEFAULT;
+ sd->saturation = SATURATION_DEFAULT;
+ sd->whitebal = WHITEBAL_DEFAULT;
+ sd->sharpness = SHARPNESS_DEFAULT;
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ /* HDG not sure if these 2 reads are needed */
+ reg_r(gspca_dev, 0, 0x10);
+ PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x",
+ gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+ reg_r(gspca_dev, 0, 0x10);
+ PDEBUG(D_PROBE, "Reg 0x10 reads: %02x %02x",
+ gspca_dev->usb_buf[0], gspca_dev->usb_buf[1]);
+ reg_w(gspca_dev, 0, 0x0d);
+
+ return 0;
+}
+
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct urb *urb;
+ int i, n, packet_size;
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
+
+ intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+ alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ if (!alt) {
+ err("Couldn't get altsetting");
+ return -EIO;
+ }
+
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+
+ reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG);
+ reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG);
+ reg_w(gspca_dev, sd->contrast, CONTRAST_REG);
+ reg_w(gspca_dev, sd->saturation, SATURATION_REG);
+ reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG);
+
+ n = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ reg_w(gspca_dev, n, 0x08);
+
+ konica_stream_on(gspca_dev);
+
+ if (gspca_dev->usb_err)
+ return gspca_dev->usb_err;
+
+ /* create 4 URBs - 2 on endpoint 0x83 and 2 on 0x082 */
+#if MAX_NURBS < 4
+#error "Not enough URBs in the gspca table"
+#endif
+#define SD_NPKT 32
+ for (n = 0; n < 4; n++) {
+ i = n & 1 ? 0 : 1;
+ packet_size =
+ le16_to_cpu(alt->endpoint[i].desc.wMaxPacketSize);
+ urb = usb_alloc_urb(SD_NPKT, GFP_KERNEL);
+ if (!urb) {
+ err("usb_alloc_urb failed");
+ return -ENOMEM;
+ }
+ gspca_dev->urb[n] = urb;
+ urb->transfer_buffer = usb_alloc_coherent(gspca_dev->dev,
+ packet_size * SD_NPKT,
+ GFP_KERNEL,
+ &urb->transfer_dma);
+ if (urb->transfer_buffer == NULL) {
+ err("usb_buffer_alloc failed");
+ return -ENOMEM;
+ }
+
+ urb->dev = gspca_dev->dev;
+ urb->context = gspca_dev;
+ urb->transfer_buffer_length = packet_size * SD_NPKT;
+ urb->pipe = usb_rcvisocpipe(gspca_dev->dev,
+ n & 1 ? 0x81 : 0x82);
+ urb->transfer_flags = URB_ISO_ASAP
+ | URB_NO_TRANSFER_DMA_MAP;
+ urb->interval = 1;
+ urb->complete = sd_isoc_irq;
+ urb->number_of_packets = SD_NPKT;
+ for (i = 0; i < SD_NPKT; i++) {
+ urb->iso_frame_desc[i].length = packet_size;
+ urb->iso_frame_desc[i].offset = packet_size * i;
+ }
+ }
+
+ return 0;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ konica_stream_off(gspca_dev);
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ /* Don't keep the button in the pressed state "forever" if it was
+ pressed when streaming is stopped */
+ if (sd->snapshot_pressed) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ sd->snapshot_pressed = 0;
+ }
+#endif
+}
+
+/* reception of an URB */
+static void sd_isoc_irq(struct urb *urb)
+{
+ struct gspca_dev *gspca_dev = (struct gspca_dev *) urb->context;
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct urb *data_urb, *status_urb;
+ u8 *data;
+ int i, st;
+
+ PDEBUG(D_PACK, "sd isoc irq");
+ if (!gspca_dev->streaming)
+ return;
+
+ if (urb->status != 0) {
+ if (urb->status == -ESHUTDOWN)
+ return; /* disconnection */
+#ifdef CONFIG_PM
+ if (gspca_dev->frozen)
+ return;
+#endif
+ PDEBUG(D_ERR, "urb status: %d", urb->status);
+ st = usb_submit_urb(urb, GFP_ATOMIC);
+ if (st < 0)
+ err("resubmit urb error %d", st);
+ return;
+ }
+
+ /* if this is a data URB (ep 0x82), wait */
+ if (urb->transfer_buffer_length > 32) {
+ sd->last_data_urb = urb;
+ return;
+ }
+
+ status_urb = urb;
+ data_urb = sd->last_data_urb;
+ sd->last_data_urb = NULL;
+
+ if (!data_urb || data_urb->start_frame != status_urb->start_frame) {
+ PDEBUG(D_ERR|D_PACK, "lost sync on frames");
+ goto resubmit;
+ }
+
+ if (data_urb->number_of_packets != status_urb->number_of_packets) {
+ PDEBUG(D_ERR|D_PACK,
+ "no packets does not match, data: %d, status: %d",
+ data_urb->number_of_packets,
+ status_urb->number_of_packets);
+ goto resubmit;
+ }
+
+ for (i = 0; i < status_urb->number_of_packets; i++) {
+ if (data_urb->iso_frame_desc[i].status ||
+ status_urb->iso_frame_desc[i].status) {
+ PDEBUG(D_ERR|D_PACK,
+ "pkt %d data-status %d, status-status %d", i,
+ data_urb->iso_frame_desc[i].status,
+ status_urb->iso_frame_desc[i].status);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ continue;
+ }
+
+ if (status_urb->iso_frame_desc[i].actual_length != 1) {
+ PDEBUG(D_ERR|D_PACK,
+ "bad status packet length %d",
+ status_urb->iso_frame_desc[i].actual_length);
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ continue;
+ }
+
+ st = *((u8 *)status_urb->transfer_buffer
+ + status_urb->iso_frame_desc[i].offset);
+
+ data = (u8 *)data_urb->transfer_buffer
+ + data_urb->iso_frame_desc[i].offset;
+
+ /* st: 0x80-0xff: frame start with frame number (ie 0-7f)
+ * otherwise:
+ * bit 0 0: keep packet
+ * 1: drop packet (padding data)
+ *
+ * bit 4 0 button not clicked
+ * 1 button clicked
+ * button is used to `take a picture' (in software)
+ */
+ if (st & 0x80) {
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+ } else {
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ u8 button_state = st & 0x40 ? 1 : 0;
+ if (sd->snapshot_pressed != button_state) {
+ input_report_key(gspca_dev->input_dev,
+ KEY_CAMERA,
+ button_state);
+ input_sync(gspca_dev->input_dev);
+ sd->snapshot_pressed = button_state;
+ }
+#endif
+ if (st & 0x01)
+ continue;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, data,
+ data_urb->iso_frame_desc[i].actual_length);
+ }
+
+resubmit:
+ if (data_urb) {
+ st = usb_submit_urb(data_urb, GFP_ATOMIC);
+ if (st < 0)
+ PDEBUG(D_ERR|D_PACK,
+ "usb_submit_urb(data_urb) ret %d", st);
+ }
+ st = usb_submit_urb(status_urb, GFP_ATOMIC);
+ if (st < 0)
+ err("usb_submit_urb(status_urb) ret %d", st);
+}
+
+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) {
+ konica_stream_off(gspca_dev);
+ reg_w(gspca_dev, sd->brightness, BRIGHTNESS_REG);
+ konica_stream_on(gspca_dev);
+ }
+
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming) {
+ konica_stream_off(gspca_dev);
+ reg_w(gspca_dev, sd->contrast, CONTRAST_REG);
+ konica_stream_on(gspca_dev);
+ }
+
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+
+ return 0;
+}
+
+static int sd_setsaturation(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->saturation = val;
+ if (gspca_dev->streaming) {
+ konica_stream_off(gspca_dev);
+ reg_w(gspca_dev, sd->saturation, SATURATION_REG);
+ konica_stream_on(gspca_dev);
+ }
+ return 0;
+}
+
+static int sd_getsaturation(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->saturation;
+
+ return 0;
+}
+
+static int sd_setwhitebal(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->whitebal = val;
+ if (gspca_dev->streaming) {
+ konica_stream_off(gspca_dev);
+ reg_w(gspca_dev, sd->whitebal, WHITEBAL_REG);
+ konica_stream_on(gspca_dev);
+ }
+ return 0;
+}
+
+static int sd_getwhitebal(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->whitebal;
+
+ 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) {
+ konica_stream_off(gspca_dev);
+ reg_w(gspca_dev, sd->sharpness, SHARPNESS_REG);
+ konica_stream_on(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;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ .other_input = 1,
+#endif
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x04c8, 0x0720)}, /* Intel YC 76 */
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/m5602/m5602_bridge.h b/drivers/media/video/gspca/m5602/m5602_bridge.h
index 1127a405c9b2..51af3ee3ab85 100644
--- a/drivers/media/video/gspca/m5602/m5602_bridge.h
+++ b/drivers/media/video/gspca/m5602/m5602_bridge.h
@@ -19,6 +19,7 @@
#ifndef M5602_BRIDGE_H_
#define M5602_BRIDGE_H_
+#include <linux/slab.h>
#include "gspca.h"
#define MODULE_NAME "ALi m5602"
diff --git a/drivers/media/video/gspca/m5602/m5602_core.c b/drivers/media/video/gspca/m5602/m5602_core.c
index 4294c75e3b11..a7722b1aef9b 100644
--- a/drivers/media/video/gspca/m5602/m5602_core.c
+++ b/drivers/media/video/gspca/m5602/m5602_core.c
@@ -28,7 +28,7 @@ int force_sensor;
static int dump_bridge;
int dump_sensor;
-static const __devinitdata struct usb_device_id m5602_table[] = {
+static const struct usb_device_id m5602_table[] = {
{USB_DEVICE(0x0402, 0x5602)},
{}
};
@@ -305,30 +305,23 @@ static void m5602_urb_complete(struct gspca_dev *gspca_dev,
sd->frame_count);
} else {
- struct gspca_frame *frame;
int cur_frame_len;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
- cur_frame_len = frame->data_end - frame->data;
+ cur_frame_len = gspca_dev->image_len;
/* Remove urb header */
data += 4;
len -= 4;
- if (cur_frame_len + len <= frame->v4l2_buf.length) {
+ if (cur_frame_len + len <= gspca_dev->frsz) {
PDEBUG(D_FRAM, "Continuing frame %d copying %d bytes",
sd->frame_count, len);
gspca_frame_add(gspca_dev, INTER_PACKET,
data, len);
- } else if (frame->v4l2_buf.length - cur_frame_len > 0) {
+ } else {
/* Add the remaining data up to frame size */
gspca_frame_add(gspca_dev, INTER_PACKET, data,
- frame->v4l2_buf.length - cur_frame_len);
+ gspca_dev->frsz - cur_frame_len);
}
}
}
@@ -413,18 +406,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init mod_m5602_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit mod_m5602_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(mod_m5602_init);
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.c b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
index c0722fa64606..0d605a52b924 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.c
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.c
@@ -109,14 +109,14 @@ static const struct ctrl mt9m111_ctrls[] = {
#define GREEN_BALANCE_IDX 4
{
{
- .id = M5602_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_GREEN_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .id = M5602_V4L2_CID_GREEN_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "green balance",
+ .minimum = 0x00,
+ .maximum = 0x7ff,
+ .step = 0x1,
+ .default_value = MT9M111_GREEN_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = mt9m111_set_green_balance,
.get = mt9m111_get_green_balance
@@ -124,14 +124,14 @@ static const struct ctrl mt9m111_ctrls[] = {
#define BLUE_BALANCE_IDX 5
{
{
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0x7ff,
+ .step = 0x1,
+ .default_value = MT9M111_BLUE_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = mt9m111_set_blue_balance,
.get = mt9m111_get_blue_balance
@@ -139,14 +139,14 @@ static const struct ctrl mt9m111_ctrls[] = {
#define RED_BALANCE_IDX 5
{
{
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x7ff,
- .step = 0x1,
- .default_value = MT9M111_RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0x7ff,
+ .step = 0x1,
+ .default_value = MT9M111_RED_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = mt9m111_set_red_balance,
.get = mt9m111_get_red_balance
diff --git a/drivers/media/video/gspca/m5602/m5602_mt9m111.h b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
index b3de77823091..b1f0c492036a 100644
--- a/drivers/media/video/gspca/m5602/m5602_mt9m111.h
+++ b/drivers/media/video/gspca/m5602/m5602_mt9m111.h
@@ -70,7 +70,7 @@
#define MT9M111_COLORPIPE 0x01
#define MT9M111_CAMERA_CONTROL 0x02
-#define MT9M111_RESET (1 << 0)
+#define MT9M111_RESET (1 << 0)
#define MT9M111_RESTART (1 << 1)
#define MT9M111_ANALOG_STANDBY (1 << 2)
#define MT9M111_CHIP_ENABLE (1 << 3)
@@ -97,7 +97,7 @@
#define MT9M111_2D_DEFECT_CORRECTION_ENABLE (1 << 0)
#define INITIAL_MAX_GAIN 64
-#define MT9M111_DEFAULT_GAIN 283
+#define MT9M111_DEFAULT_GAIN 283
#define MT9M111_GREEN_GAIN_DEFAULT 0x20
#define MT9M111_BLUE_GAIN_DEFAULT 0x20
#define MT9M111_RED_GAIN_DEFAULT 0x20
@@ -125,8 +125,7 @@ static const struct m5602_sensor mt9m111 = {
.start = mt9m111_start,
};
-static const unsigned char preinit_mt9m111[][4] =
-{
+static const unsigned char preinit_mt9m111[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -165,8 +164,7 @@ static const unsigned char preinit_mt9m111[][4] =
{BRIDGE, M5602_XB_I2C_CLK_DIV, 0x0a, 0x00}
};
-static const unsigned char init_mt9m111[][4] =
-{
+static const unsigned char init_mt9m111[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -257,8 +255,7 @@ static const unsigned char init_mt9m111[][4] =
{SENSOR, MT9M111_SC_SHUTTER_WIDTH, 0x01, 0x90},
};
-static const unsigned char start_mt9m111[][4] =
-{
+static const unsigned char start_mt9m111[][4] = {
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -271,5 +268,4 @@ static const unsigned char start_mt9m111[][4] =
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
{BRIDGE, M5602_XB_VSYNC_PARA, 0x00, 0x00},
};
-
#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.c b/drivers/media/video/gspca/m5602/m5602_ov7660.c
index 62c1cbf06666..b12f60464b3b 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov7660.c
+++ b/drivers/media/video/gspca/m5602/m5602_ov7660.c
@@ -54,13 +54,13 @@ static const struct ctrl ov7660_ctrls[] = {
#define AUTO_WHITE_BALANCE_IDX 4
{
{
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto white balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
},
.set = ov7660_set_auto_white_balance,
.get = ov7660_get_auto_white_balance
@@ -68,13 +68,13 @@ static const struct ctrl ov7660_ctrls[] = {
#define AUTO_GAIN_CTRL_IDX 5
{
{
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto gain control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto gain control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
},
.set = ov7660_set_auto_gain,
.get = ov7660_get_auto_gain
@@ -82,13 +82,13 @@ static const struct ctrl ov7660_ctrls[] = {
#define AUTO_EXPOSURE_IDX 6
{
{
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
},
.set = ov7660_set_auto_exposure,
.get = ov7660_get_auto_exposure
@@ -96,13 +96,13 @@ static const struct ctrl ov7660_ctrls[] = {
#define HFLIP_IDX 7
{
{
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
},
.set = ov7660_set_hflip,
.get = ov7660_get_hflip
@@ -110,13 +110,13 @@ static const struct ctrl ov7660_ctrls[] = {
#define VFLIP_IDX 8
{
{
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
},
.set = ov7660_set_vflip,
.get = ov7660_get_vflip
diff --git a/drivers/media/video/gspca/m5602/m5602_ov7660.h b/drivers/media/video/gspca/m5602/m5602_ov7660.h
index 4d9dcf29da2e..2efd607987ec 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov7660.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov7660.h
@@ -80,7 +80,7 @@
#define OV7660_DEFAULT_GAIN 0x0e
#define OV7660_DEFAULT_RED_GAIN 0x80
-#define OV7660_DEFAULT_BLUE_GAIN 0x80
+#define OV7660_DEFAULT_BLUE_GAIN 0x80
#define OV7660_DEFAULT_SATURATION 0x00
#define OV7660_DEFAULT_EXPOSURE 0x20
@@ -105,8 +105,7 @@ static const struct m5602_sensor ov7660 = {
.disconnect = ov7660_disconnect,
};
-static const unsigned char preinit_ov7660[][4] =
-{
+static const unsigned char preinit_ov7660[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
@@ -140,8 +139,7 @@ static const unsigned char preinit_ov7660[][4] =
{BRIDGE, M5602_XB_GPIO_EN_L, 0x00}
};
-static const unsigned char init_ov7660[][4] =
-{
+static const unsigned char init_ov7660[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
@@ -259,5 +257,4 @@ static const unsigned char init_ov7660[][4] =
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0},
};
-
#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.c b/drivers/media/video/gspca/m5602/m5602_ov9650.c
index 069ba0044f8b..703d48670a24 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.c
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.c
@@ -121,8 +121,8 @@ static const struct ctrl ov9650_ctrls[] = {
.minimum = 0x00,
.maximum = 0x1ff,
.step = 0x4,
- .default_value = EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .default_value = EXPOSURE_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = ov9650_set_exposure,
.get = ov9650_get_exposure
@@ -146,13 +146,13 @@ static const struct ctrl ov9650_ctrls[] = {
{
{
.id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = RED_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = ov9650_set_red_balance,
.get = ov9650_get_red_balance
@@ -161,13 +161,13 @@ static const struct ctrl ov9650_ctrls[] = {
{
{
.id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = BLUE_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = ov9650_set_blue_balance,
.get = ov9650_get_blue_balance
@@ -175,13 +175,13 @@ static const struct ctrl ov9650_ctrls[] = {
#define HFLIP_IDX 4
{
{
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
},
.set = ov9650_set_hflip,
.get = ov9650_get_hflip
@@ -189,13 +189,13 @@ static const struct ctrl ov9650_ctrls[] = {
#define VFLIP_IDX 5
{
{
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
},
.set = ov9650_set_vflip,
.get = ov9650_get_vflip
@@ -203,13 +203,13 @@ static const struct ctrl ov9650_ctrls[] = {
#define AUTO_WHITE_BALANCE_IDX 6
{
{
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto white balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
},
.set = ov9650_set_auto_white_balance,
.get = ov9650_get_auto_white_balance
@@ -217,13 +217,13 @@ static const struct ctrl ov9650_ctrls[] = {
#define AUTO_GAIN_CTRL_IDX 7
{
{
- .id = V4L2_CID_AUTOGAIN,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto gain control",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto gain control",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
},
.set = ov9650_set_auto_gain,
.get = ov9650_get_auto_gain
@@ -231,13 +231,13 @@ static const struct ctrl ov9650_ctrls[] = {
#define AUTO_EXPOSURE_IDX 8
{
{
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1
},
.set = ov9650_set_auto_exposure,
.get = ov9650_get_auto_exposure
@@ -624,7 +624,7 @@ static int ov9650_set_gain(struct gspca_dev *gspca_dev, __s32 val)
/* Mask away all uninteresting bits */
i2c_data = ((val & 0x0300) >> 2) |
- (i2c_data & 0x3F);
+ (i2c_data & 0x3f);
err = m5602_write_sensor(sd, OV9650_VREF, &i2c_data, 1);
if (err < 0)
return err;
diff --git a/drivers/media/video/gspca/m5602/m5602_ov9650.h b/drivers/media/video/gspca/m5602/m5602_ov9650.h
index c98c40d69e05..da9a129b739d 100644
--- a/drivers/media/video/gspca/m5602/m5602_ov9650.h
+++ b/drivers/media/video/gspca/m5602/m5602_ov9650.h
@@ -110,7 +110,7 @@
#define OV9650_VARIOPIXEL (1 << 2)
#define OV9650_SYSTEM_CLK_SEL (1 << 7)
-#define OV9650_SLAM_MODE (1 << 4)
+#define OV9650_SLAM_MODE (1 << 4)
#define OV9650_QVGA_VARIOPIXEL (1 << 7)
@@ -154,8 +154,7 @@ static const struct m5602_sensor ov9650 = {
.disconnect = ov9650_disconnect,
};
-static const unsigned char preinit_ov9650[][3] =
-{
+static const unsigned char preinit_ov9650[][3] = {
/* [INITCAM] */
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
@@ -180,8 +179,7 @@ static const unsigned char preinit_ov9650[][3] =
{SENSOR, OV9650_OFON, 0x40}
};
-static const unsigned char init_ov9650[][3] =
-{
+static const unsigned char init_ov9650[][3] = {
/* [INITCAM] */
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
@@ -297,8 +295,7 @@ static const unsigned char init_ov9650[][3] =
{SENSOR, OV9650_COM2, OV9650_SOFT_SLEEP | OV9650_OUTPUT_DRIVE_2X},
};
-static const unsigned char res_init_ov9650[][3] =
-{
+static const unsigned char res_init_ov9650[][3] = {
{SENSOR, OV9650_COM2, OV9650_OUTPUT_DRIVE_2X},
{BRIDGE, M5602_XB_LINE_OF_FRAME_H, 0x82},
@@ -307,5 +304,4 @@ static const unsigned char res_init_ov9650[][3] =
{BRIDGE, M5602_XB_PIX_OF_LINE_L, 0x00},
{BRIDGE, M5602_XB_SIG_INI, 0x01}
};
-
#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.c b/drivers/media/video/gspca/m5602/m5602_po1030.c
index 925b87d66f40..1febd34c2f05 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.c
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.c
@@ -58,14 +58,14 @@ static const struct ctrl po1030_ctrls[] = {
#define GAIN_IDX 0
{
{
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "gain",
- .minimum = 0x00,
- .maximum = 0x4f,
- .step = 0x1,
- .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0x4f,
+ .step = 0x1,
+ .default_value = PO1030_GLOBAL_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_gain,
.get = po1030_get_gain
@@ -73,14 +73,14 @@ static const struct ctrl po1030_ctrls[] = {
#define EXPOSURE_IDX 1
{
{
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x00,
- .maximum = 0x02ff,
- .step = 0x1,
- .default_value = PO1030_EXPOSURE_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0x02ff,
+ .step = 0x1,
+ .default_value = PO1030_EXPOSURE_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_exposure,
.get = po1030_get_exposure
@@ -88,14 +88,14 @@ static const struct ctrl po1030_ctrls[] = {
#define RED_BALANCE_IDX 2
{
{
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_RED_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "red balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = PO1030_RED_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_red_balance,
.get = po1030_get_red_balance
@@ -103,14 +103,14 @@ static const struct ctrl po1030_ctrls[] = {
#define BLUE_BALANCE_IDX 3
{
{
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_BLUE_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "blue balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = PO1030_BLUE_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_blue_balance,
.get = po1030_get_blue_balance
@@ -118,13 +118,13 @@ static const struct ctrl po1030_ctrls[] = {
#define HFLIP_IDX 4
{
{
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
},
.set = po1030_set_hflip,
.get = po1030_get_hflip
@@ -132,13 +132,13 @@ static const struct ctrl po1030_ctrls[] = {
#define VFLIP_IDX 5
{
{
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
},
.set = po1030_set_vflip,
.get = po1030_get_vflip
@@ -146,13 +146,13 @@ static const struct ctrl po1030_ctrls[] = {
#define AUTO_WHITE_BALANCE_IDX 6
{
{
- .id = V4L2_CID_AUTO_WHITE_BALANCE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto white balance",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto white balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
},
.set = po1030_set_auto_white_balance,
.get = po1030_get_auto_white_balance
@@ -160,13 +160,13 @@ static const struct ctrl po1030_ctrls[] = {
#define AUTO_EXPOSURE_IDX 7
{
{
- .id = V4L2_CID_EXPOSURE_AUTO,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "auto exposure",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0,
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "auto exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
},
.set = po1030_set_auto_exposure,
.get = po1030_get_auto_exposure
@@ -174,14 +174,14 @@ static const struct ctrl po1030_ctrls[] = {
#define GREEN_BALANCE_IDX 8
{
{
- .id = M5602_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x1,
- .default_value = PO1030_GREEN_GAIN_DEFAULT,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .id = M5602_V4L2_CID_GREEN_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "green balance",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = PO1030_GREEN_GAIN_DEFAULT,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = po1030_set_green_balance,
.get = po1030_get_green_balance
diff --git a/drivers/media/video/gspca/m5602/m5602_po1030.h b/drivers/media/video/gspca/m5602/m5602_po1030.h
index 1ea380b2bbe7..338359596398 100644
--- a/drivers/media/video/gspca/m5602/m5602_po1030.h
+++ b/drivers/media/video/gspca/m5602/m5602_po1030.h
@@ -139,9 +139,9 @@
#define PO1030_GLOBAL_GAIN_DEFAULT 0x12
#define PO1030_EXPOSURE_DEFAULT 0x0085
-#define PO1030_BLUE_GAIN_DEFAULT 0x36
-#define PO1030_RED_GAIN_DEFAULT 0x36
-#define PO1030_GREEN_GAIN_DEFAULT 0x40
+#define PO1030_BLUE_GAIN_DEFAULT 0x36
+#define PO1030_RED_GAIN_DEFAULT 0x36
+#define PO1030_GREEN_GAIN_DEFAULT 0x40
/*****************************************************************************/
@@ -166,8 +166,7 @@ static const struct m5602_sensor po1030 = {
.disconnect = po1030_disconnect,
};
-static const unsigned char preinit_po1030[][3] =
-{
+static const unsigned char preinit_po1030[][3] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
@@ -193,8 +192,7 @@ static const unsigned char preinit_po1030[][3] =
{BRIDGE, M5602_XB_GPIO_DAT, 0x00}
};
-static const unsigned char init_po1030[][3] =
-{
+static const unsigned char init_po1030[][3] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00},
@@ -271,5 +269,4 @@ static const unsigned char init_po1030[][3] =
{BRIDGE, M5602_XB_GPIO_EN_H, 0x06},
{BRIDGE, M5602_XB_GPIO_EN_L, 0x00},
};
-
#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
index da0a38c78708..d27280be9852 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.c
@@ -143,13 +143,13 @@ static const struct ctrl s5k4aa_ctrls[] = {
#define VFLIP_IDX 0
{
{
- .id = V4L2_CID_VFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "vertical flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
},
.set = s5k4aa_set_vflip,
.get = s5k4aa_get_vflip
@@ -157,13 +157,13 @@ static const struct ctrl s5k4aa_ctrls[] = {
#define HFLIP_IDX 1
{
{
- .id = V4L2_CID_HFLIP,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "horizontal flip",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 0
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0
},
.set = s5k4aa_set_hflip,
.get = s5k4aa_get_hflip
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
index 4440da4e7f0f..8cc7a3f6da72 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k4aa.h
@@ -83,8 +83,7 @@ static const struct m5602_sensor s5k4aa = {
.disconnect = s5k4aa_disconnect,
};
-static const unsigned char preinit_s5k4aa[][4] =
-{
+static const unsigned char preinit_s5k4aa[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -127,8 +126,7 @@ static const unsigned char preinit_s5k4aa[][4] =
{SENSOR, S5K4AA_PAGE_MAP, 0x00, 0x00}
};
-static const unsigned char init_s5k4aa[][4] =
-{
+static const unsigned char init_s5k4aa[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -179,8 +177,7 @@ static const unsigned char init_s5k4aa[][4] =
{SENSOR, 0x37, 0x00, 0x00},
};
-static const unsigned char VGA_s5k4aa[][4] =
-{
+static const unsigned char VGA_s5k4aa[][4] = {
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -235,8 +232,7 @@ static const unsigned char VGA_s5k4aa[][4] =
{SENSOR, 0x02, 0x0e, 0x00},
};
-static const unsigned char SXGA_s5k4aa[][4] =
-{
+static const unsigned char SXGA_s5k4aa[][4] = {
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -284,6 +280,4 @@ static const unsigned char SXGA_s5k4aa[][4] =
{SENSOR, S5K4AA_PAGE_MAP, 0x02, 0x00},
{SENSOR, 0x02, 0x0e, 0x00},
};
-
-
#endif
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.c b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
index 6b3be4fa2c06..fbd91545497a 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.c
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.c
@@ -17,7 +17,6 @@
*/
#include <linux/kthread.h>
-#include <linux/slab.h>
#include "m5602_s5k83a.h"
static int s5k83a_set_gain(struct gspca_dev *gspca_dev, __s32 val);
diff --git a/drivers/media/video/gspca/m5602/m5602_s5k83a.h b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
index 7814b078acde..80a63a236e24 100644
--- a/drivers/media/video/gspca/m5602/m5602_s5k83a.h
+++ b/drivers/media/video/gspca/m5602/m5602_s5k83a.h
@@ -35,7 +35,7 @@
#define S5K83A_MAXIMUM_EXPOSURE 0x3c
#define S5K83A_FLIP_MASK 0x10
#define S5K83A_GPIO_LED_MASK 0x10
-#define S5K83A_GPIO_ROTATION_MASK 0x40
+#define S5K83A_GPIO_ROTATION_MASK 0x40
/*****************************************************************************/
@@ -67,8 +67,7 @@ struct s5k83a_priv {
s32 *settings;
};
-static const unsigned char preinit_s5k83a[][4] =
-{
+static const unsigned char preinit_s5k83a[][4] = {
{BRIDGE, M5602_XB_MCU_CLK_DIV, 0x02, 0x00},
{BRIDGE, M5602_XB_MCU_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
@@ -108,8 +107,7 @@ static const unsigned char preinit_s5k83a[][4] =
/* This could probably be considerably shortened.
I don't have the hardware to experiment with it, patches welcome
*/
-static const unsigned char init_s5k83a[][4] =
-{
+static const unsigned char init_s5k83a[][4] = {
/* The following sequence is useless after a clean boot
but is necessary after resume from suspend */
{BRIDGE, M5602_XB_GPIO_DIR, 0x1d, 0x00},
@@ -166,8 +164,7 @@ static const unsigned char init_s5k83a[][4] =
{SENSOR, 0x00, 0x06, 0x00},
};
-static const unsigned char start_s5k83a[][4] =
-{
+static const unsigned char start_s5k83a[][4] = {
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x06, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
{BRIDGE, M5602_XB_ADC_CTRL, 0xc0, 0x00},
@@ -193,5 +190,4 @@ static const unsigned char start_s5k83a[][4] =
{BRIDGE, M5602_XB_SEN_CLK_DIV, 0x00, 0x00},
{BRIDGE, M5602_XB_SEN_CLK_CTRL, 0xb0, 0x00},
};
-
#endif
diff --git a/drivers/media/video/gspca/mars.c b/drivers/media/video/gspca/mars.c
index 3d9229e22b25..cb4d0bf0d784 100644
--- a/drivers/media/video/gspca/mars.c
+++ b/drivers/media/video/gspca/mars.c
@@ -28,34 +28,41 @@ MODULE_AUTHOR("Michel Xhaard <mxhaard@users.sourceforge.net>");
MODULE_DESCRIPTION("GSPCA/Mars USB Camera Driver");
MODULE_LICENSE("GPL");
+/* controls */
+enum e_ctrl {
+ BRIGHTNESS,
+ COLORS,
+ GAMMA,
+ SHARPNESS,
+ ILLUM_TOP,
+ ILLUM_BOT,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- u8 brightness;
- u8 colors;
- u8 gamma;
- u8 sharpness;
+ struct gspca_ctrl ctrls[NCTRLS];
+
u8 quality;
#define QUALITY_MIN 40
#define QUALITY_MAX 70
#define QUALITY_DEF 50
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgamma(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 const struct ctrl sd_ctrls[] = {
- {
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setgamma(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -63,13 +70,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 30,
.step = 1,
-#define BRIGHTNESS_DEF 15
- .default_value = BRIGHTNESS_DEF,
+ .default_value = 15,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = setbrightness
},
- {
+[COLORS] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -77,13 +82,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 1,
.maximum = 255,
.step = 1,
-#define COLOR_DEF 200
- .default_value = COLOR_DEF,
+ .default_value = 200,
},
- .set = sd_setcolors,
- .get = sd_getcolors,
+ .set_control = setcolors
},
- {
+[GAMMA] = {
{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -91,13 +94,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 3,
.step = 1,
-#define GAMMA_DEF 1
- .default_value = GAMMA_DEF,
+ .default_value = 1,
},
- .set = sd_setgamma,
- .get = sd_getgamma,
+ .set_control = setgamma
},
- {
+[SHARPNESS] = {
{
.id = V4L2_CID_SHARPNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -105,11 +106,35 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 2,
.step = 1,
-#define SHARPNESS_DEF 1
- .default_value = SHARPNESS_DEF,
+ .default_value = 1,
+ },
+ .set_control = setsharpness
+ },
+[ILLUM_TOP] = {
+ {
+ .id = V4L2_CID_ILLUMINATORS_1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Top illuminator",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_UPDATE,
},
- .set = sd_setsharpness,
- .get = sd_getsharpness,
+ .set = sd_setilluminator1
+ },
+[ILLUM_BOT] = {
+ {
+ .id = V4L2_CID_ILLUMINATORS_2,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Bottom illuminator",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ .flags = V4L2_CTRL_FLAG_UPDATE,
+ },
+ .set = sd_setilluminator2
},
};
@@ -138,21 +163,25 @@ static const __u8 mi_data[0x20] = {
};
/* write <len> bytes from gspca_dev->usb_buf */
-static int reg_w(struct gspca_dev *gspca_dev,
+static void reg_w(struct gspca_dev *gspca_dev,
int len)
{
int alen, ret;
+ if (gspca_dev->usb_err < 0)
+ return;
+
ret = usb_bulk_msg(gspca_dev->dev,
usb_sndbulkpipe(gspca_dev->dev, 4),
gspca_dev->usb_buf,
len,
&alen,
500); /* timeout in milliseconds */
- if (ret < 0)
- PDEBUG(D_ERR, "reg write [%02x] error %d",
+ if (ret < 0) {
+ err("reg write [%02x] error %d",
gspca_dev->usb_buf[0], ret);
- return ret;
+ gspca_dev->usb_err = ret;
+ }
}
static void mi_w(struct gspca_dev *gspca_dev,
@@ -167,6 +196,59 @@ static void mi_w(struct gspca_dev *gspca_dev,
reg_w(gspca_dev, 4);
}
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->usb_buf[0] = 0x61;
+ gspca_dev->usb_buf[1] = sd->ctrls[BRIGHTNESS].val;
+ reg_w(gspca_dev, 2);
+}
+
+static void setcolors(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ s16 val;
+
+ val = sd->ctrls[COLORS].val;
+ gspca_dev->usb_buf[0] = 0x5f;
+ gspca_dev->usb_buf[1] = val << 3;
+ gspca_dev->usb_buf[2] = ((val >> 2) & 0xf8) | 0x04;
+ reg_w(gspca_dev, 3);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->usb_buf[0] = 0x06;
+ gspca_dev->usb_buf[1] = sd->ctrls[GAMMA].val * 0x40;
+ reg_w(gspca_dev, 2);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->usb_buf[0] = 0x67;
+ gspca_dev->usb_buf[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
+ reg_w(gspca_dev, 2);
+}
+
+static void setilluminators(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->usb_buf[0] = 0x22;
+ if (sd->ctrls[ILLUM_TOP].val)
+ gspca_dev->usb_buf[1] = 0x76;
+ else if (sd->ctrls[ILLUM_BOT].val)
+ gspca_dev->usb_buf[1] = 0x7a;
+ else
+ gspca_dev->usb_buf[1] = 0x7e;
+ reg_w(gspca_dev, 2);
+}
+
/* this function is called at probe time */
static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
@@ -177,10 +259,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam = &gspca_dev->cam;
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
- sd->brightness = BRIGHTNESS_DEF;
- sd->colors = COLOR_DEF;
- sd->gamma = GAMMA_DEF;
- sd->sharpness = SHARPNESS_DEF;
+ cam->ctrls = sd->ctrls;
sd->quality = QUALITY_DEF;
gspca_dev->nbalt = 9; /* use the altsetting 08 */
return 0;
@@ -189,20 +268,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
+ gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
return 0;
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int err_code;
u8 *data;
int i;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -211,9 +287,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
data[0] = 0x01; /* address */
data[1] = 0x01;
- err_code = reg_w(gspca_dev, 2);
- if (err_code < 0)
- return err_code;
+ reg_w(gspca_dev, 2);
/*
Initialize the MR97113 chip register
@@ -226,7 +300,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
data[5] = 0x30; /* reg 4, MI, PAS5101 :
* 0x30 for 24mhz , 0x28 for 12mhz */
data[6] = 0x02; /* reg 5, H start - was 0x04 */
- data[7] = sd->gamma * 0x40; /* reg 0x06: gamma */
+ data[7] = sd->ctrls[GAMMA].val * 0x40; /* reg 0x06: gamma */
data[8] = 0x01; /* reg 7, V start - was 0x03 */
/* if (h_size == 320 ) */
/* data[9]= 0x56; * reg 8, 24MHz, 2:1 scale down */
@@ -235,16 +309,12 @@ static int sd_start(struct gspca_dev *gspca_dev)
/*jfm: from win trace*/
data[10] = 0x18;
- err_code = reg_w(gspca_dev, 11);
- if (err_code < 0)
- return err_code;
+ reg_w(gspca_dev, 11);
data[0] = 0x23; /* address */
data[1] = 0x09; /* reg 35, append frame header */
- err_code = reg_w(gspca_dev, 2);
- if (err_code < 0)
- return err_code;
+ reg_w(gspca_dev, 2);
data[0] = 0x3c; /* address */
/* if (gspca_dev->width == 1280) */
@@ -253,9 +323,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* else */
data[1] = 50; /* 50 reg 60, pc-cam frame size
* (unit: 4KB) 200KB */
- err_code = reg_w(gspca_dev, 2);
- if (err_code < 0)
- return err_code;
+ reg_w(gspca_dev, 2);
/* auto dark-gain */
data[0] = 0x5e; /* address */
@@ -264,37 +332,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* reg 0x5f/0x60 (LE) = saturation */
/* h (60): xxxx x100
* l (5f): xxxx x000 */
- data[2] = sd->colors << 3;
- data[3] = ((sd->colors >> 2) & 0xf8) | 0x04;
- data[4] = sd->brightness; /* reg 0x61 = brightness */
+ data[2] = sd->ctrls[COLORS].val << 3;
+ data[3] = ((sd->ctrls[COLORS].val >> 2) & 0xf8) | 0x04;
+ data[4] = sd->ctrls[BRIGHTNESS].val; /* reg 0x61 = brightness */
data[5] = 0x00;
- err_code = reg_w(gspca_dev, 6);
- if (err_code < 0)
- return err_code;
+ reg_w(gspca_dev, 6);
data[0] = 0x67;
/*jfm: from win trace*/
- data[1] = sd->sharpness * 4 + 3;
+ data[1] = sd->ctrls[SHARPNESS].val * 4 + 3;
data[2] = 0x14;
- err_code = reg_w(gspca_dev, 3);
- if (err_code < 0)
- return err_code;
+ reg_w(gspca_dev, 3);
data[0] = 0x69;
data[1] = 0x2f;
data[2] = 0x28;
data[3] = 0x42;
- err_code = reg_w(gspca_dev, 4);
- if (err_code < 0)
- return err_code;
+ reg_w(gspca_dev, 4);
data[0] = 0x63;
data[1] = 0x07;
- err_code = reg_w(gspca_dev, 2);
+ reg_w(gspca_dev, 2);
/*jfm: win trace - many writes here to reg 0x64*/
- if (err_code < 0)
- return err_code;
/* initialize the MI sensor */
for (i = 0; i < sizeof mi_data; i++)
@@ -303,25 +363,26 @@ static int sd_start(struct gspca_dev *gspca_dev)
data[0] = 0x00;
data[1] = 0x4d; /* ISOC transfering enable... */
reg_w(gspca_dev, 2);
- return 0;
+
+ gspca_dev->ctrl_inac = 0; /* activate the illuminator controls */
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- int result;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->ctrl_inac = (1 << ILLUM_TOP) | (1 << ILLUM_BOT);
+ if (sd->ctrls[ILLUM_TOP].val || sd->ctrls[ILLUM_BOT].val) {
+ sd->ctrls[ILLUM_TOP].val = 0;
+ sd->ctrls[ILLUM_BOT].val = 0;
+ setilluminators(gspca_dev);
+ msleep(20);
+ }
gspca_dev->usb_buf[0] = 1;
gspca_dev->usb_buf[1] = 0;
- result = reg_w(gspca_dev, 2);
- if (result < 0)
- PDEBUG(D_ERR, "Camera Stop failed");
-}
-
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- kfree(sd->jpeg_hdr);
+ reg_w(gspca_dev, 2);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -362,91 +423,28 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setilluminator1(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->brightness = val;
- if (gspca_dev->streaming) {
- gspca_dev->usb_buf[0] = 0x61;
- gspca_dev->usb_buf[1] = val;
- reg_w(gspca_dev, 2);
- }
- return 0;
+ /* only one illuminator may be on */
+ sd->ctrls[ILLUM_TOP].val = val;
+ if (val)
+ sd->ctrls[ILLUM_BOT].val = 0;
+ setilluminators(gspca_dev);
+ return gspca_dev->usb_err;
}
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_setilluminator2(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->brightness;
- return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->colors = val;
- if (gspca_dev->streaming) {
-
- /* see sd_start */
- gspca_dev->usb_buf[0] = 0x5f;
- gspca_dev->usb_buf[1] = sd->colors << 3;
- gspca_dev->usb_buf[2] = ((sd->colors >> 2) & 0xf8) | 0x04;
- reg_w(gspca_dev, 3);
- }
- return 0;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->colors;
- return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gamma = val;
- if (gspca_dev->streaming) {
- gspca_dev->usb_buf[0] = 0x06;
- gspca_dev->usb_buf[1] = val * 0x40;
- reg_w(gspca_dev, 2);
- }
- return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->gamma;
- 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) {
- gspca_dev->usb_buf[0] = 0x67;
- gspca_dev->usb_buf[1] = val * 4 + 3;
- reg_w(gspca_dev, 2);
- }
- 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;
+ /* only one illuminator may be on */
+ sd->ctrls[ILLUM_BOT].val = val;
+ if (val)
+ sd->ctrls[ILLUM_TOP].val = 0;
+ setilluminators(gspca_dev);
+ return gspca_dev->usb_err;
}
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
@@ -481,19 +479,18 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
+ .nctrls = NCTRLS,
.config = sd_config,
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x050f)},
{}
};
@@ -521,18 +518,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/mr97310a.c b/drivers/media/video/gspca/mr97310a.c
index 33744e724eaa..3884c9d300c5 100644
--- a/drivers/media/video/gspca/mr97310a.c
+++ b/drivers/media/video/gspca/mr97310a.c
@@ -9,14 +9,14 @@
* is Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
*
* Support for the control settings for the CIF cameras is
- * Copyright (C) 2009 Hans de Goede <hdgoede@redhat.com> and
+ * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com> and
* Thomas Kaiser <thomas@kaiser-linux.li>
*
* Support for the control settings for the VGA cameras is
* Copyright (C) 2009 Theodore Kilgore <kilgota@auburn.edu>
*
* Several previously unsupported cameras are owned and have been tested by
- * Hans de Goede <hdgoede@redhat.com> and
+ * Hans de Goede <hdegoede@redhat.com> and
* Thomas Kaiser <thomas@kaiser-linux.li> and
* Theodore Kilgore <kilgota@auburn.edu> and
* Edmond Rodriguez <erodrig_97@yahoo.com> and
@@ -267,7 +267,7 @@ static int mr_write(struct gspca_dev *gspca_dev, int len)
usb_sndbulkpipe(gspca_dev->dev, 4),
gspca_dev->usb_buf, len, NULL, 500);
if (rc < 0)
- PDEBUG(D_ERR, "reg write [%02x] error %d",
+ err("reg write [%02x] error %d",
gspca_dev->usb_buf[0], rc);
return rc;
}
@@ -281,7 +281,7 @@ static int mr_read(struct gspca_dev *gspca_dev, int len)
usb_rcvbulkpipe(gspca_dev->dev, 3),
gspca_dev->usb_buf, len, NULL, 500);
if (rc < 0)
- PDEBUG(D_ERR, "reg read [%02x] error %d",
+ err("reg read [%02x] error %d",
gspca_dev->usb_buf[0], rc);
return rc;
}
@@ -540,7 +540,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor_type = 1;
break;
default:
- PDEBUG(D_ERR, "Unknown CIF Sensor id : %02x",
+ err("Unknown CIF Sensor id : %02x",
gspca_dev->usb_buf[1]);
return -ENODEV;
}
@@ -575,10 +575,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor_type = 2;
} else if ((gspca_dev->usb_buf[0] != 0x03) &&
(gspca_dev->usb_buf[0] != 0x04)) {
- PDEBUG(D_ERR, "Unknown VGA Sensor id Byte 0: %02x",
+ err("Unknown VGA Sensor id Byte 0: %02x",
gspca_dev->usb_buf[0]);
- PDEBUG(D_ERR, "Defaults assumed, may not work");
- PDEBUG(D_ERR, "Please report this");
+ err("Defaults assumed, may not work");
+ err("Please report this");
}
/* Sakar Digital color needs to be adjusted. */
if ((gspca_dev->usb_buf[0] == 0x03) &&
@@ -595,12 +595,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* Nothing to do here. */
break;
default:
- PDEBUG(D_ERR,
- "Unknown VGA Sensor id Byte 1: %02x",
+ err("Unknown VGA Sensor id Byte 1: %02x",
gspca_dev->usb_buf[1]);
- PDEBUG(D_ERR,
- "Defaults assumed, may not work");
- PDEBUG(D_ERR, "Please report this");
+ err("Defaults assumed, may not work");
+ err("Please report this");
}
}
PDEBUG(D_PROBE, "MR97310A VGA camera detected, sensor: %d",
@@ -675,7 +673,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
__u8 *data = gspca_dev->usb_buf;
int err_code;
- const __u8 startup_string[] = {
+ static const __u8 startup_string[] = {
0x00,
0x0d,
0x01,
@@ -721,7 +719,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
return err_code;
if (!sd->sensor_type) {
- const struct sensor_w_data cif_sensor0_init_data[] = {
+ static const struct sensor_w_data cif_sensor0_init_data[] = {
{0x02, 0x00, {0x03, 0x5a, 0xb5, 0x01,
0x0f, 0x14, 0x0f, 0x10}, 8},
{0x0c, 0x00, {0x04, 0x01, 0x01, 0x00, 0x1f}, 5},
@@ -742,7 +740,7 @@ static int start_cif_cam(struct gspca_dev *gspca_dev)
err_code = sensor_write_regs(gspca_dev, cif_sensor0_init_data,
ARRAY_SIZE(cif_sensor0_init_data));
} else { /* sd->sensor_type = 1 */
- const struct sensor_w_data cif_sensor1_init_data[] = {
+ static const struct sensor_w_data cif_sensor1_init_data[] = {
/* Reg 3,4, 7,8 get set by the controls */
{0x02, 0x00, {0x10}, 1},
{0x05, 0x01, {0x22}, 1}, /* 5/6 also seen as 65h/32h */
@@ -777,8 +775,9 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
__u8 *data = gspca_dev->usb_buf;
int err_code;
- const __u8 startup_string[] = {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b,
- 0x00, 0x00, 0x00, 0x50, 0xc0};
+ static const __u8 startup_string[] =
+ {0x00, 0x0d, 0x01, 0x00, 0x00, 0x2b, 0x00, 0x00,
+ 0x00, 0x50, 0xc0};
/* What some of these mean is explained in start_cif_cam(), above */
memcpy(data, startup_string, 11);
@@ -830,7 +829,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
return err_code;
if (!sd->sensor_type) {
- const struct sensor_w_data vga_sensor0_init_data[] = {
+ static const struct sensor_w_data vga_sensor0_init_data[] = {
{0x01, 0x00, {0x0c, 0x00, 0x04}, 3},
{0x14, 0x00, {0x01, 0xe4, 0x02, 0x84}, 4},
{0x20, 0x00, {0x00, 0x80, 0x00, 0x08}, 4},
@@ -841,20 +840,20 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
err_code = sensor_write_regs(gspca_dev, vga_sensor0_init_data,
ARRAY_SIZE(vga_sensor0_init_data));
} else if (sd->sensor_type == 1) {
- const struct sensor_w_data color_adj[] = {
+ static const struct sensor_w_data color_adj[] = {
{0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
/* adjusted blue, green, red gain correct
too much blue from the Sakar Digital */
0x05, 0x01, 0x04}, 8}
};
- const struct sensor_w_data color_no_adj[] = {
+ static const struct sensor_w_data color_no_adj[] = {
{0x02, 0x00, {0x06, 0x59, 0x0c, 0x16, 0x00,
/* default blue, green, red gain settings */
0x07, 0x00, 0x01}, 8}
};
- const struct sensor_w_data vga_sensor1_init_data[] = {
+ static const struct sensor_w_data vga_sensor1_init_data[] = {
{0x11, 0x04, {0x01}, 1},
{0x0a, 0x00, {0x00, 0x01, 0x00, 0x00, 0x01,
/* These settings may be better for some cameras */
@@ -879,7 +878,7 @@ static int start_vga_cam(struct gspca_dev *gspca_dev)
err_code = sensor_write_regs(gspca_dev, vga_sensor1_init_data,
ARRAY_SIZE(vga_sensor1_init_data));
} else { /* sensor type == 2 */
- const struct sensor_w_data vga_sensor2_init_data[] = {
+ static const struct sensor_w_data vga_sensor2_init_data[] = {
{0x01, 0x00, {0x48}, 1},
{0x02, 0x00, {0x22}, 1},
@@ -976,7 +975,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
u8 val;
u8 sign_reg = 7; /* This reg and the next one used on CIF cams. */
u8 value_reg = 8; /* VGA cams seem to use regs 0x0b and 0x0c */
- const u8 quick_clix_table[] =
+ static const u8 quick_clix_table[] =
/* 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 */
{ 0, 4, 8, 12, 1, 2, 3, 5, 6, 9, 7, 10, 13, 11, 14, 15};
/*
@@ -1230,7 +1229,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x08ca, 0x0110)}, /* Trust Spyc@m 100 */
{USB_DEVICE(0x08ca, 0x0111)}, /* Aiptek Pencam VGA+ */
{USB_DEVICE(0x093a, 0x010f)}, /* All other known MR97310A VGA cams */
@@ -1261,18 +1260,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/ov519.c b/drivers/media/video/gspca/ov519.c
index f36e11a0458d..8ab2c452c25e 100644
--- a/drivers/media/video/gspca/ov519.c
+++ b/drivers/media/video/gspca/ov519.c
@@ -41,6 +41,11 @@
#include <linux/input.h>
#include "gspca.h"
+/* The jpeg_hdr is used by w996Xcf only */
+/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
+#define CONEX_CAM
+#include "jpeg.h"
+
MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("OV519 USB Camera Driver");
MODULE_LICENSE("GPL");
@@ -52,18 +57,32 @@ static int frame_rate;
* are getting "Failed to read sensor ID..." */
static int i2c_detect_tries = 10;
+/* controls */
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ COLORS,
+ HFLIP,
+ VFLIP,
+ AUTOBRIGHT,
+ FREQ,
+ NCTRL /* number of controls */
+};
+
/* ov519 device descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u8 packet_nr;
+ struct gspca_ctrl ctrls[NCTRL];
+
+ u8 packet_nr;
char bridge;
#define BRIDGE_OV511 0
#define BRIDGE_OV511PLUS 1
#define BRIDGE_OV518 2
#define BRIDGE_OV518PLUS 3
-#define BRIDGE_OV519 4
+#define BRIDGE_OV519 4 /* = ov530 */
#define BRIDGE_OVFX2 5
#define BRIDGE_W9968CF 6
#define BRIDGE_MASK 7
@@ -75,47 +94,43 @@ struct sd {
char snapshot_needs_reset;
/* Determined by sensor type */
- __u8 sif;
-
- __u8 brightness;
- __u8 contrast;
- __u8 colors;
- __u8 hflip;
- __u8 vflip;
- __u8 autobrightness;
- __u8 freq;
- __u8 quality;
+ u8 sif;
+
+ u8 quality;
#define QUALITY_MIN 50
#define QUALITY_MAX 70
#define QUALITY_DEF 50
- __u8 stopped; /* Streaming is temporarily paused */
-
- __u8 frame_rate; /* current Framerate */
- __u8 clockdiv; /* clockdiv override */
-
- char sensor; /* Type of image sensor chip (SEN_*) */
-#define SEN_UNKNOWN 0
-#define SEN_OV2610 1
-#define SEN_OV3610 2
-#define SEN_OV6620 3
-#define SEN_OV6630 4
-#define SEN_OV66308AF 5
-#define SEN_OV7610 6
-#define SEN_OV7620 7
-#define SEN_OV7620AE 8
-#define SEN_OV7640 9
-#define SEN_OV7648 10
-#define SEN_OV7670 11
-#define SEN_OV76BE 12
-#define SEN_OV8610 13
+ u8 stopped; /* Streaming is temporarily paused */
+ u8 first_frame;
+
+ u8 frame_rate; /* current Framerate */
+ u8 clockdiv; /* clockdiv override */
+
+ s8 sensor; /* Type of image sensor chip (SEN_*) */
u8 sensor_addr;
- int sensor_width;
- int sensor_height;
- int sensor_reg_cache[256];
+ u16 sensor_width;
+ u16 sensor_height;
+ s16 sensor_reg_cache[256];
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+enum sensors {
+ SEN_OV2610,
+ SEN_OV3610,
+ SEN_OV6620,
+ SEN_OV6630,
+ SEN_OV66308AF,
+ SEN_OV7610,
+ SEN_OV7620,
+ SEN_OV7620AE,
+ SEN_OV7640,
+ SEN_OV7648,
+ SEN_OV7660,
+ SEN_OV7670,
+ SEN_OV76BE,
+ SEN_OV8610,
};
/* Note this is a bit of a hack, but the w9968cf driver needs the code for all
@@ -124,29 +139,16 @@ struct sd {
#include "w996Xcf.c"
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(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_setautobrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautobrightness(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 void setbrightness(struct gspca_dev *gspca_dev);
static void setcontrast(struct gspca_dev *gspca_dev);
static void setcolors(struct gspca_dev *gspca_dev);
-static void setautobrightness(struct sd *sd);
-static void setfreq(struct sd *sd);
+static void sethvflip(struct gspca_dev *gspca_dev);
+static void setautobright(struct gspca_dev *gspca_dev);
+static void setfreq(struct gspca_dev *gspca_dev);
+static void setfreq_i(struct sd *sd);
static const struct ctrl sd_ctrls[] = {
-#define BRIGHTNESS_IDX 0
- {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -154,14 +156,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define BRIGHTNESS_DEF 127
- .default_value = BRIGHTNESS_DEF,
+ .default_value = 127,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = setbrightness,
},
-#define CONTRAST_IDX 1
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -169,14 +168,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define CONTRAST_DEF 127
- .default_value = CONTRAST_DEF,
+ .default_value = 127,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = setcontrast,
},
-#define COLOR_IDX 2
- {
+[COLORS] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -184,15 +180,12 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define COLOR_DEF 127
- .default_value = COLOR_DEF,
+ .default_value = 127,
},
- .set = sd_setcolors,
- .get = sd_getcolors,
+ .set_control = setcolors,
},
-/* The flip controls work with ov7670 only */
-#define HFLIP_IDX 3
- {
+/* The flip controls work for sensors ov7660 and ov7670 only */
+[HFLIP] = {
{
.id = V4L2_CID_HFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -200,14 +193,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define HFLIP_DEF 0
- .default_value = HFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_sethflip,
- .get = sd_gethflip,
+ .set_control = sethvflip,
},
-#define VFLIP_IDX 4
- {
+[VFLIP] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -215,14 +205,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEF 0
- .default_value = VFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_setvflip,
- .get = sd_getvflip,
+ .set_control = sethvflip,
},
-#define AUTOBRIGHT_IDX 5
- {
+[AUTOBRIGHT] = {
{
.id = V4L2_CID_AUTOBRIGHTNESS,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -230,44 +217,71 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTOBRIGHT_DEF 1
- .default_value = AUTOBRIGHT_DEF,
+ .default_value = 1,
},
- .set = sd_setautobrightness,
- .get = sd_getautobrightness,
+ .set_control = setautobright,
},
-#define FREQ_IDX 6
- {
+[FREQ] = {
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
.name = "Light frequency filter",
.minimum = 0,
- .maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
+ .maximum = 2, /* 0: no flicker, 1: 50Hz, 2:60Hz, 3: auto */
.step = 1,
-#define FREQ_DEF 0
- .default_value = FREQ_DEF,
+ .default_value = 0,
},
- .set = sd_setfreq,
- .get = sd_getfreq,
- },
-#define OV7670_FREQ_IDX 7
- {
- {
- .id = V4L2_CID_POWER_LINE_FREQUENCY,
- .type = V4L2_CTRL_TYPE_MENU,
- .name = "Light frequency filter",
- .minimum = 0,
- .maximum = 3, /* 0: 0, 1: 50Hz, 2:60Hz 3: Auto Hz */
- .step = 1,
-#define OV7670_FREQ_DEF 3
- .default_value = OV7670_FREQ_DEF,
- },
- .set = sd_setfreq,
- .get = sd_getfreq,
+ .set_control = setfreq,
},
};
+/* table of the disabled controls */
+static const unsigned ctrl_dis[] = {
+[SEN_OV2610] = (1 << NCTRL) - 1, /* no control */
+
+[SEN_OV3610] = (1 << NCTRL) - 1, /* no control */
+
+[SEN_OV6620] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV6630] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV66308AF] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV7610] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV7620] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV7620AE] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV7640] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << AUTOBRIGHT) |
+ (1 << CONTRAST),
+
+[SEN_OV7648] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << AUTOBRIGHT) |
+ (1 << CONTRAST),
+
+[SEN_OV7660] = (1 << AUTOBRIGHT),
+
+[SEN_OV7670] = (1 << COLORS) |
+ (1 << AUTOBRIGHT),
+
+[SEN_OV76BE] = (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SEN_OV8610] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+};
+
static const struct v4l2_pix_format ov519_vga_mode[] = {
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 320,
@@ -447,15 +461,14 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
.priv = 0},
};
-
/* Registers common to OV511 / OV518 */
#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */
-#define R51x_SYS_RESET 0x50
+#define R51x_SYS_RESET 0x50
/* Reset type flags */
#define OV511_RESET_OMNICE 0x08
-#define R51x_SYS_INIT 0x53
+#define R51x_SYS_INIT 0x53
#define R51x_SYS_SNAP 0x52
-#define R51x_SYS_CUST_ID 0x5F
+#define R51x_SYS_CUST_ID 0x5f
#define R51x_COMP_LUT_BEGIN 0x80
/* OV511 Camera interface register numbers */
@@ -470,13 +483,12 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define R511_CAM_OPTS 0x18
#define R511_SNAP_FRAME 0x19
-#define R511_SNAP_PXCNT 0x1A
-#define R511_SNAP_LNCNT 0x1B
-#define R511_SNAP_PXDIV 0x1C
-#define R511_SNAP_LNDIV 0x1D
-#define R511_SNAP_UV_EN 0x1E
-#define R511_SNAP_UV_EN 0x1E
-#define R511_SNAP_OPTS 0x1F
+#define R511_SNAP_PXCNT 0x1a
+#define R511_SNAP_LNCNT 0x1b
+#define R511_SNAP_PXDIV 0x1c
+#define R511_SNAP_LNDIV 0x1d
+#define R511_SNAP_UV_EN 0x1e
+#define R511_SNAP_OPTS 0x1f
#define R511_DRAM_FLOW_CTL 0x20
#define R511_FIFO_OPTS 0x31
@@ -501,13 +513,14 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define OV519_R25_FORMAT 0x25
/* OV519 System Controller register numbers */
-#define OV519_SYS_RESET1 0x51
-#define OV519_SYS_EN_CLK1 0x54
+#define OV519_R51_RESET1 0x51
+#define OV519_R54_EN_CLK1 0x54
+#define OV519_R57_SNAPSHOT 0x57
#define OV519_GPIO_DATA_OUT0 0x71
#define OV519_GPIO_IO_CTRL0 0x72
-#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */
+/*#define OV511_ENDPOINT_ADDRESS 1 * Isoc endpoint number */
/*
* The FX2 chip does not give us a zero length read at end of frame.
@@ -561,90 +574,89 @@ static const struct v4l2_pix_format ovfx2_ov3610_mode[] = {
#define OV7610_REG_ID_LOW 0x1d /* manufacturer ID LSB */
#define OV7610_REG_COM_I 0x29 /* misc settings */
-/* OV7670 registers */
-#define OV7670_REG_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
-#define OV7670_REG_BLUE 0x01 /* blue gain */
-#define OV7670_REG_RED 0x02 /* red gain */
-#define OV7670_REG_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
-#define OV7670_REG_COM1 0x04 /* Control 1 */
-#define OV7670_REG_AECHH 0x07 /* AEC MS 5 bits */
-#define OV7670_REG_COM3 0x0c /* Control 3 */
-#define OV7670_REG_COM4 0x0d /* Control 4 */
-#define OV7670_REG_COM5 0x0e /* All "reserved" */
-#define OV7670_REG_COM6 0x0f /* Control 6 */
-#define OV7670_REG_AECH 0x10 /* More bits of AEC value */
-#define OV7670_REG_CLKRC 0x11 /* Clock control */
-#define OV7670_REG_COM7 0x12 /* Control 7 */
-#define OV7670_COM7_FMT_VGA 0x00
-#define OV7670_COM7_YUV 0x00 /* YUV */
-#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */
-#define OV7670_COM7_FMT_MASK 0x38
-#define OV7670_COM7_RESET 0x80 /* Register reset */
-#define OV7670_REG_COM8 0x13 /* Control 8 */
-#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */
-#define OV7670_COM8_AWB 0x02 /* White balance enable */
-#define OV7670_COM8_AGC 0x04 /* Auto gain enable */
-#define OV7670_COM8_BFILT 0x20 /* Band filter enable */
-#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */
-#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
-#define OV7670_REG_COM9 0x14 /* Control 9 - gain ceiling */
-#define OV7670_REG_COM10 0x15 /* Control 10 */
-#define OV7670_REG_HSTART 0x17 /* Horiz start high bits */
-#define OV7670_REG_HSTOP 0x18 /* Horiz stop high bits */
-#define OV7670_REG_VSTART 0x19 /* Vert start high bits */
-#define OV7670_REG_VSTOP 0x1a /* Vert stop high bits */
-#define OV7670_REG_MVFP 0x1e /* Mirror / vflip */
-#define OV7670_MVFP_VFLIP 0x10 /* vertical flip */
-#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */
-#define OV7670_REG_AEW 0x24 /* AGC upper limit */
-#define OV7670_REG_AEB 0x25 /* AGC lower limit */
-#define OV7670_REG_VPT 0x26 /* AGC/AEC fast mode op region */
-#define OV7670_REG_HREF 0x32 /* HREF pieces */
-#define OV7670_REG_TSLB 0x3a /* lots of stuff */
-#define OV7670_REG_COM11 0x3b /* Control 11 */
-#define OV7670_COM11_EXP 0x02
-#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
-#define OV7670_REG_COM12 0x3c /* Control 12 */
-#define OV7670_REG_COM13 0x3d /* Control 13 */
-#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */
-#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */
-#define OV7670_REG_COM14 0x3e /* Control 14 */
-#define OV7670_REG_EDGE 0x3f /* Edge enhancement factor */
-#define OV7670_REG_COM15 0x40 /* Control 15 */
-#define OV7670_COM15_R00FF 0xc0 /* 00 to FF */
-#define OV7670_REG_COM16 0x41 /* Control 16 */
-#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */
-#define OV7670_REG_BRIGHT 0x55 /* Brightness */
-#define OV7670_REG_CONTRAS 0x56 /* Contrast control */
-#define OV7670_REG_GFIX 0x69 /* Fix gain control */
-#define OV7670_REG_RGB444 0x8c /* RGB 444 control */
-#define OV7670_REG_HAECC1 0x9f /* Hist AEC/AGC control 1 */
-#define OV7670_REG_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
-#define OV7670_REG_BD50MAX 0xa5 /* 50hz banding step limit */
-#define OV7670_REG_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
-#define OV7670_REG_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
-#define OV7670_REG_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
-#define OV7670_REG_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
-#define OV7670_REG_HAECC7 0xaa /* Hist AEC/AGC control 7 */
-#define OV7670_REG_BD60MAX 0xab /* 60hz banding step limit */
+/* OV7660 and OV7670 registers */
+#define OV7670_R00_GAIN 0x00 /* Gain lower 8 bits (rest in vref) */
+#define OV7670_R01_BLUE 0x01 /* blue gain */
+#define OV7670_R02_RED 0x02 /* red gain */
+#define OV7670_R03_VREF 0x03 /* Pieces of GAIN, VSTART, VSTOP */
+#define OV7670_R04_COM1 0x04 /* Control 1 */
+/*#define OV7670_R07_AECHH 0x07 * AEC MS 5 bits */
+#define OV7670_R0C_COM3 0x0c /* Control 3 */
+#define OV7670_R0D_COM4 0x0d /* Control 4 */
+#define OV7670_R0E_COM5 0x0e /* All "reserved" */
+#define OV7670_R0F_COM6 0x0f /* Control 6 */
+#define OV7670_R10_AECH 0x10 /* More bits of AEC value */
+#define OV7670_R11_CLKRC 0x11 /* Clock control */
+#define OV7670_R12_COM7 0x12 /* Control 7 */
+#define OV7670_COM7_FMT_VGA 0x00
+/*#define OV7670_COM7_YUV 0x00 * YUV */
+#define OV7670_COM7_FMT_QVGA 0x10 /* QVGA format */
+#define OV7670_COM7_FMT_MASK 0x38
+#define OV7670_COM7_RESET 0x80 /* Register reset */
+#define OV7670_R13_COM8 0x13 /* Control 8 */
+#define OV7670_COM8_AEC 0x01 /* Auto exposure enable */
+#define OV7670_COM8_AWB 0x02 /* White balance enable */
+#define OV7670_COM8_AGC 0x04 /* Auto gain enable */
+#define OV7670_COM8_BFILT 0x20 /* Band filter enable */
+#define OV7670_COM8_AECSTEP 0x40 /* Unlimited AEC step size */
+#define OV7670_COM8_FASTAEC 0x80 /* Enable fast AGC/AEC */
+#define OV7670_R14_COM9 0x14 /* Control 9 - gain ceiling */
+#define OV7670_R15_COM10 0x15 /* Control 10 */
+#define OV7670_R17_HSTART 0x17 /* Horiz start high bits */
+#define OV7670_R18_HSTOP 0x18 /* Horiz stop high bits */
+#define OV7670_R19_VSTART 0x19 /* Vert start high bits */
+#define OV7670_R1A_VSTOP 0x1a /* Vert stop high bits */
+#define OV7670_R1E_MVFP 0x1e /* Mirror / vflip */
+#define OV7670_MVFP_VFLIP 0x10 /* vertical flip */
+#define OV7670_MVFP_MIRROR 0x20 /* Mirror image */
+#define OV7670_R24_AEW 0x24 /* AGC upper limit */
+#define OV7670_R25_AEB 0x25 /* AGC lower limit */
+#define OV7670_R26_VPT 0x26 /* AGC/AEC fast mode op region */
+#define OV7670_R32_HREF 0x32 /* HREF pieces */
+#define OV7670_R3A_TSLB 0x3a /* lots of stuff */
+#define OV7670_R3B_COM11 0x3b /* Control 11 */
+#define OV7670_COM11_EXP 0x02
+#define OV7670_COM11_HZAUTO 0x10 /* Auto detect 50/60 Hz */
+#define OV7670_R3C_COM12 0x3c /* Control 12 */
+#define OV7670_R3D_COM13 0x3d /* Control 13 */
+#define OV7670_COM13_GAMMA 0x80 /* Gamma enable */
+#define OV7670_COM13_UVSAT 0x40 /* UV saturation auto adjustment */
+#define OV7670_R3E_COM14 0x3e /* Control 14 */
+#define OV7670_R3F_EDGE 0x3f /* Edge enhancement factor */
+#define OV7670_R40_COM15 0x40 /* Control 15 */
+/*#define OV7670_COM15_R00FF 0xc0 * 00 to FF */
+#define OV7670_R41_COM16 0x41 /* Control 16 */
+#define OV7670_COM16_AWBGAIN 0x08 /* AWB gain enable */
+/* end of ov7660 common registers */
+#define OV7670_R55_BRIGHT 0x55 /* Brightness */
+#define OV7670_R56_CONTRAS 0x56 /* Contrast control */
+#define OV7670_R69_GFIX 0x69 /* Fix gain control */
+/*#define OV7670_R8C_RGB444 0x8c * RGB 444 control */
+#define OV7670_R9F_HAECC1 0x9f /* Hist AEC/AGC control 1 */
+#define OV7670_RA0_HAECC2 0xa0 /* Hist AEC/AGC control 2 */
+#define OV7670_RA5_BD50MAX 0xa5 /* 50hz banding step limit */
+#define OV7670_RA6_HAECC3 0xa6 /* Hist AEC/AGC control 3 */
+#define OV7670_RA7_HAECC4 0xa7 /* Hist AEC/AGC control 4 */
+#define OV7670_RA8_HAECC5 0xa8 /* Hist AEC/AGC control 5 */
+#define OV7670_RA9_HAECC6 0xa9 /* Hist AEC/AGC control 6 */
+#define OV7670_RAA_HAECC7 0xaa /* Hist AEC/AGC control 7 */
+#define OV7670_RAB_BD60MAX 0xab /* 60hz banding step limit */
struct ov_regvals {
- __u8 reg;
- __u8 val;
+ u8 reg;
+ u8 val;
};
struct ov_i2c_regvals {
- __u8 reg;
- __u8 val;
+ u8 reg;
+ u8 val;
};
/* Settings for OV2610 camera chip */
-static const struct ov_i2c_regvals norm_2610[] =
-{
+static const struct ov_i2c_regvals norm_2610[] = {
{ 0x12, 0x80 }, /* reset */
};
-static const struct ov_i2c_regvals norm_3620b[] =
-{
+static const struct ov_i2c_regvals norm_3620b[] = {
/*
* From the datasheet: "Note that after writing to register COMH
* (0x12) to change the sensor mode, registers related to the
@@ -654,7 +666,6 @@ static const struct ov_i2c_regvals norm_3620b[] =
* "wait 4096 external clock ... to make sure the sensor is
* stable and ready to access registers" i.e. 160us at 24MHz
*/
-
{ 0x12, 0x80 }, /* COMH reset */
{ 0x12, 0x00 }, /* QXGA, master */
@@ -687,7 +698,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* COMI[0] "Exposure control"
* = 0 (0x00) .......0 "Manual"
*/
- { 0x13, 0xC0 },
+ { 0x13, 0xc0 },
/*
* 09 COMC "Common Control C"
@@ -743,7 +754,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* COME[0] "Auto zero circuit select"
* = 1 (0x01) .......1 "On"
*/
- { 0x0d, 0xA1 },
+ { 0x0d, 0xa1 },
/*
* 0E COMF "Common Control F"
@@ -807,7 +818,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* COMJ[0] "Reserved"
* = 0 (0x00) .......0
*/
- { 0x14, 0xC6 },
+ { 0x14, 0xc6 },
/*
* 15 COMK "Common Control K"
@@ -913,7 +924,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* FVOPT[7:0] "Range"
* = 31 (0x1F) 00011111
*/
- { 0x3c, 0x1F },
+ { 0x3c, 0x1f },
/*
* 44 Undocumented = 0 (0x00) 00000000
@@ -962,7 +973,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* 48[7:0] "It's a secret"
* = 192 (0xC0) 11000000
*/
- { 0x48, 0xC0 },
+ { 0x48, 0xc0 },
/*
* 49 Undocumented = 25 (0x19) 00011001
@@ -976,18 +987,18 @@ static const struct ov_i2c_regvals norm_3620b[] =
* 4B[7:0] "It's a secret"
* = 128 (0x80) 10000000
*/
- { 0x4B, 0x80 },
+ { 0x4b, 0x80 },
/*
* 4D Undocumented = 196 (0xC4) 11000100
* 4D[7:0] "It's a secret"
* = 196 (0xC4) 11000100
*/
- { 0x4D, 0xC4 },
+ { 0x4d, 0xc4 },
/*
* 35 VREF "Reference Voltage Control"
- * = 76 (0x4C) 01001100
+ * = 76 (0x4c) 01001100
* VREF[7:5] "Column high reference control"
* = 2 (0x02) 010..... "higher voltage"
* VREF[4:2] "Column low reference control"
@@ -995,21 +1006,21 @@ static const struct ov_i2c_regvals norm_3620b[] =
* VREF[1:0] "Reserved"
* = 0 (0x00) ......00
*/
- { 0x35, 0x4C },
+ { 0x35, 0x4c },
/*
* 3D Undocumented = 0 (0x00) 00000000
* 3D[7:0] "It's a secret"
* = 0 (0x00) 00000000
*/
- { 0x3D, 0x00 },
+ { 0x3d, 0x00 },
/*
* 3E Undocumented = 0 (0x00) 00000000
* 3E[7:0] "It's a secret"
* = 0 (0x00) 00000000
*/
- { 0x3E, 0x00 },
+ { 0x3e, 0x00 },
/*
* 3B FREFB "Internal Reference Adjustment"
@@ -1049,7 +1060,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* VBLM[3:0] "Sensor current control"
* = 10 (0x0A) ....1010
*/
- { 0x34, 0x5A },
+ { 0x34, 0x5a },
/*
* 3B FREFB "Internal Reference Adjustment"
@@ -1115,7 +1126,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* HREFST[7:0] "Horizontal window start, 8 MSBs"
* = 31 (0x1F) 00011111
*/
- { 0x17, 0x1F },
+ { 0x17, 0x1f },
/*
* 18 HREFEND "Horizontal window end"
@@ -1123,7 +1134,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* HREFEND[7:0] "Horizontal Window End, 8 MSBs"
* = 95 (0x5F) 01011111
*/
- { 0x18, 0x5F },
+ { 0x18, 0x5f },
/*
* 19 VSTRT "Vertical window start"
@@ -1163,7 +1174,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* COMA[1:0] "Vertical window start line control 2 LSBs"
* = 2 (0x02) ......10
*/
- { 0x03, 0x4A },
+ { 0x03, 0x4a },
/*
* 11 CLKRC "Clock Rate Control"
@@ -1220,7 +1231,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* HREFST[7:0] "Horizontal window start, 8 MSBs"
* = 31 (0x1F) 00011111
*/
- { 0x17, 0x1F },
+ { 0x17, 0x1f },
/*
* 18 HREFEND "Horizontal window end"
@@ -1228,7 +1239,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* HREFEND[7:0] "Horizontal Window End, 8 MSBs"
* = 95 (0x5F) 01011111
*/
- { 0x18, 0x5F },
+ { 0x18, 0x5f },
/*
* 19 VSTRT "Vertical window start"
@@ -1268,7 +1279,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* COMA[1:0] "Vertical window start line control 2 LSBs"
* = 2 (0x02) ......10
*/
- { 0x03, 0x4A },
+ { 0x03, 0x4a },
/*
* 02 RED "Red Gain Control"
@@ -1278,7 +1289,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* RED[6:0] "Value"
* = 47 (0x2F) .0101111
*/
- { 0x02, 0xAF },
+ { 0x02, 0xaf },
/*
* 2D ADDVSL "VSYNC Pulse Width"
@@ -1286,7 +1297,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* ADDVSL[7:0] "VSYNC pulse width, LSB"
* = 210 (0xD2) 11010010
*/
- { 0x2d, 0xD2 },
+ { 0x2d, 0xd2 },
/*
* 00 GAIN = 24 (0x18) 00011000
@@ -1309,7 +1320,7 @@ static const struct ov_i2c_regvals norm_3620b[] =
* BLUE[6:0] "Value"
* = 112 (0x70) .1110000
*/
- { 0x01, 0xF0 },
+ { 0x01, 0xf0 },
/*
* 10 AEC "Automatic Exposure Control"
@@ -1317,14 +1328,14 @@ static const struct ov_i2c_regvals norm_3620b[] =
* AEC[7:0] "Automatic Exposure Control, 8 MSBs"
* = 10 (0x0A) 00001010
*/
- { 0x10, 0x0A },
-
- { 0xE1, 0x67 },
- { 0xE3, 0x03 },
- { 0xE4, 0x26 },
- { 0xE5, 0x3E },
- { 0xF8, 0x01 },
- { 0xFF, 0x01 },
+ { 0x10, 0x0a },
+
+ { 0xe1, 0x67 },
+ { 0xe3, 0x03 },
+ { 0xe4, 0x26 },
+ { 0xe5, 0x3e },
+ { 0xf8, 0x01 },
+ { 0xff, 0x01 },
};
static const struct ov_i2c_regvals norm_6x20[] = {
@@ -1333,7 +1344,7 @@ static const struct ov_i2c_regvals norm_6x20[] = {
{ 0x03, 0x60 },
{ 0x05, 0x7f }, /* For when autoadjust is off */
{ 0x07, 0xa8 },
- /* The ratio of 0x0c and 0x0d controls the white point */
+ /* The ratio of 0x0c and 0x0d controls the white point */
{ 0x0c, 0x24 },
{ 0x0d, 0x24 },
{ 0x0f, 0x15 }, /* COMS */
@@ -1501,7 +1512,7 @@ static const struct ov_i2c_regvals norm_7620[] = {
{ 0x00, 0x00 }, /* gain */
{ 0x01, 0x80 }, /* blue gain */
{ 0x02, 0x80 }, /* red gain */
- { 0x03, 0xc0 }, /* OV7670_REG_VREF */
+ { 0x03, 0xc0 }, /* OV7670_R03_VREF */
{ 0x06, 0x60 },
{ 0x07, 0x00 },
{ 0x0c, 0x24 },
@@ -1569,33 +1580,177 @@ static const struct ov_i2c_regvals norm_7640[] = {
{ 0x12, 0x14 },
};
+static const struct ov_regvals init_519_ov7660[] = {
+ { 0x5d, 0x03 }, /* Turn off suspend mode */
+ { 0x53, 0x9b }, /* 0x9f enables the (unused) microcontroller */
+ { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { 0xa2, 0x20 }, /* a2-a5 are undocumented */
+ { 0xa3, 0x18 },
+ { 0xa4, 0x04 },
+ { 0xa5, 0x28 },
+ { 0x37, 0x00 }, /* SetUsbInit */
+ { 0x55, 0x02 }, /* 4.096 Mhz audio clock */
+ /* Enable both fields, YUV Input, disable defect comp (why?) */
+ { 0x20, 0x0c }, /* 0x0d does U <-> V swap */
+ { 0x21, 0x38 },
+ { 0x22, 0x1d },
+ { 0x17, 0x50 }, /* undocumented */
+ { 0x37, 0x00 }, /* undocumented */
+ { 0x40, 0xff }, /* I2C timeout counter */
+ { 0x46, 0x00 }, /* I2C clock prescaler */
+};
+static const struct ov_i2c_regvals norm_7660[] = {
+ {OV7670_R12_COM7, OV7670_COM7_RESET},
+ {OV7670_R11_CLKRC, 0x81},
+ {0x92, 0x00}, /* DM_LNL */
+ {0x93, 0x00}, /* DM_LNH */
+ {0x9d, 0x4c}, /* BD50ST */
+ {0x9e, 0x3f}, /* BD60ST */
+ {OV7670_R3B_COM11, 0x02},
+ {OV7670_R13_COM8, 0xf5},
+ {OV7670_R10_AECH, 0x00},
+ {OV7670_R00_GAIN, 0x00},
+ {OV7670_R01_BLUE, 0x7c},
+ {OV7670_R02_RED, 0x9d},
+ {OV7670_R12_COM7, 0x00},
+ {OV7670_R04_COM1, 00},
+ {OV7670_R18_HSTOP, 0x01},
+ {OV7670_R17_HSTART, 0x13},
+ {OV7670_R32_HREF, 0x92},
+ {OV7670_R19_VSTART, 0x02},
+ {OV7670_R1A_VSTOP, 0x7a},
+ {OV7670_R03_VREF, 0x00},
+ {OV7670_R0E_COM5, 0x04},
+ {OV7670_R0F_COM6, 0x62},
+ {OV7670_R15_COM10, 0x00},
+ {0x16, 0x02}, /* RSVD */
+ {0x1b, 0x00}, /* PSHFT */
+ {OV7670_R1E_MVFP, 0x01},
+ {0x29, 0x3c}, /* RSVD */
+ {0x33, 0x00}, /* CHLF */
+ {0x34, 0x07}, /* ARBLM */
+ {0x35, 0x84}, /* RSVD */
+ {0x36, 0x00}, /* RSVD */
+ {0x37, 0x04}, /* ADC */
+ {0x39, 0x43}, /* OFON */
+ {OV7670_R3A_TSLB, 0x00},
+ {OV7670_R3C_COM12, 0x6c},
+ {OV7670_R3D_COM13, 0x98},
+ {OV7670_R3F_EDGE, 0x23},
+ {OV7670_R40_COM15, 0xc1},
+ {OV7670_R41_COM16, 0x22},
+ {0x6b, 0x0a}, /* DBLV */
+ {0xa1, 0x08}, /* RSVD */
+ {0x69, 0x80}, /* HV */
+ {0x43, 0xf0}, /* RSVD.. */
+ {0x44, 0x10},
+ {0x45, 0x78},
+ {0x46, 0xa8},
+ {0x47, 0x60},
+ {0x48, 0x80},
+ {0x59, 0xba},
+ {0x5a, 0x9a},
+ {0x5b, 0x22},
+ {0x5c, 0xb9},
+ {0x5d, 0x9b},
+ {0x5e, 0x10},
+ {0x5f, 0xe0},
+ {0x60, 0x85},
+ {0x61, 0x60},
+ {0x9f, 0x9d}, /* RSVD */
+ {0xa0, 0xa0}, /* DSPC2 */
+ {0x4f, 0x60}, /* matrix */
+ {0x50, 0x64},
+ {0x51, 0x04},
+ {0x52, 0x18},
+ {0x53, 0x3c},
+ {0x54, 0x54},
+ {0x55, 0x40},
+ {0x56, 0x40},
+ {0x57, 0x40},
+ {0x58, 0x0d}, /* matrix sign */
+ {0x8b, 0xcc}, /* RSVD */
+ {0x8c, 0xcc},
+ {0x8d, 0xcf},
+ {0x6c, 0x40}, /* gamma curve */
+ {0x6d, 0xe0},
+ {0x6e, 0xa0},
+ {0x6f, 0x80},
+ {0x70, 0x70},
+ {0x71, 0x80},
+ {0x72, 0x60},
+ {0x73, 0x60},
+ {0x74, 0x50},
+ {0x75, 0x40},
+ {0x76, 0x38},
+ {0x77, 0x3c},
+ {0x78, 0x32},
+ {0x79, 0x1a},
+ {0x7a, 0x28},
+ {0x7b, 0x24},
+ {0x7c, 0x04}, /* gamma curve */
+ {0x7d, 0x12},
+ {0x7e, 0x26},
+ {0x7f, 0x46},
+ {0x80, 0x54},
+ {0x81, 0x64},
+ {0x82, 0x70},
+ {0x83, 0x7c},
+ {0x84, 0x86},
+ {0x85, 0x8e},
+ {0x86, 0x9c},
+ {0x87, 0xab},
+ {0x88, 0xc4},
+ {0x89, 0xd1},
+ {0x8a, 0xe5},
+ {OV7670_R14_COM9, 0x1e},
+ {OV7670_R24_AEW, 0x80},
+ {OV7670_R25_AEB, 0x72},
+ {OV7670_R26_VPT, 0xb3},
+ {0x62, 0x80}, /* LCC1 */
+ {0x63, 0x80}, /* LCC2 */
+ {0x64, 0x06}, /* LCC3 */
+ {0x65, 0x00}, /* LCC4 */
+ {0x66, 0x01}, /* LCC5 */
+ {0x94, 0x0e}, /* RSVD.. */
+ {0x95, 0x14},
+ {OV7670_R13_COM8, OV7670_COM8_FASTAEC
+ | OV7670_COM8_AECSTEP
+ | OV7670_COM8_BFILT
+ | 0x10
+ | OV7670_COM8_AGC
+ | OV7670_COM8_AWB
+ | OV7670_COM8_AEC},
+ {0xa1, 0xc8}
+};
+
/* 7670. Defaults taken from OmniVision provided data,
* as provided by Jonathan Corbet of OLPC */
static const struct ov_i2c_regvals norm_7670[] = {
- { OV7670_REG_COM7, OV7670_COM7_RESET },
- { OV7670_REG_TSLB, 0x04 }, /* OV */
- { OV7670_REG_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
- { OV7670_REG_CLKRC, 0x01 },
+ { OV7670_R12_COM7, OV7670_COM7_RESET },
+ { OV7670_R3A_TSLB, 0x04 }, /* OV */
+ { OV7670_R12_COM7, OV7670_COM7_FMT_VGA }, /* VGA */
+ { OV7670_R11_CLKRC, 0x01 },
/*
* Set the hardware window. These values from OV don't entirely
* make sense - hstop is less than hstart. But they work...
*/
- { OV7670_REG_HSTART, 0x13 },
- { OV7670_REG_HSTOP, 0x01 },
- { OV7670_REG_HREF, 0xb6 },
- { OV7670_REG_VSTART, 0x02 },
- { OV7670_REG_VSTOP, 0x7a },
- { OV7670_REG_VREF, 0x0a },
-
- { OV7670_REG_COM3, 0x00 },
- { OV7670_REG_COM14, 0x00 },
+ { OV7670_R17_HSTART, 0x13 },
+ { OV7670_R18_HSTOP, 0x01 },
+ { OV7670_R32_HREF, 0xb6 },
+ { OV7670_R19_VSTART, 0x02 },
+ { OV7670_R1A_VSTOP, 0x7a },
+ { OV7670_R03_VREF, 0x0a },
+
+ { OV7670_R0C_COM3, 0x00 },
+ { OV7670_R3E_COM14, 0x00 },
/* Mystery scaling numbers */
{ 0x70, 0x3a },
{ 0x71, 0x35 },
{ 0x72, 0x11 },
{ 0x73, 0xf0 },
{ 0xa2, 0x02 },
-/* { OV7670_REG_COM10, 0x0 }, */
+/* { OV7670_R15_COM10, 0x0 }, */
/* Gamma curve values */
{ 0x7a, 0x20 },
@@ -1617,37 +1772,37 @@ static const struct ov_i2c_regvals norm_7670[] = {
/* AGC and AEC parameters. Note we start by disabling those features,
then turn them only after tweaking the values. */
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ { OV7670_R13_COM8, OV7670_COM8_FASTAEC
| OV7670_COM8_AECSTEP
| OV7670_COM8_BFILT },
- { OV7670_REG_GAIN, 0x00 },
- { OV7670_REG_AECH, 0x00 },
- { OV7670_REG_COM4, 0x40 }, /* magic reserved bit */
- { OV7670_REG_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
- { OV7670_REG_BD50MAX, 0x05 },
- { OV7670_REG_BD60MAX, 0x07 },
- { OV7670_REG_AEW, 0x95 },
- { OV7670_REG_AEB, 0x33 },
- { OV7670_REG_VPT, 0xe3 },
- { OV7670_REG_HAECC1, 0x78 },
- { OV7670_REG_HAECC2, 0x68 },
+ { OV7670_R00_GAIN, 0x00 },
+ { OV7670_R10_AECH, 0x00 },
+ { OV7670_R0D_COM4, 0x40 }, /* magic reserved bit */
+ { OV7670_R14_COM9, 0x18 }, /* 4x gain + magic rsvd bit */
+ { OV7670_RA5_BD50MAX, 0x05 },
+ { OV7670_RAB_BD60MAX, 0x07 },
+ { OV7670_R24_AEW, 0x95 },
+ { OV7670_R25_AEB, 0x33 },
+ { OV7670_R26_VPT, 0xe3 },
+ { OV7670_R9F_HAECC1, 0x78 },
+ { OV7670_RA0_HAECC2, 0x68 },
{ 0xa1, 0x03 }, /* magic */
- { OV7670_REG_HAECC3, 0xd8 },
- { OV7670_REG_HAECC4, 0xd8 },
- { OV7670_REG_HAECC5, 0xf0 },
- { OV7670_REG_HAECC6, 0x90 },
- { OV7670_REG_HAECC7, 0x94 },
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ { OV7670_RA6_HAECC3, 0xd8 },
+ { OV7670_RA7_HAECC4, 0xd8 },
+ { OV7670_RA8_HAECC5, 0xf0 },
+ { OV7670_RA9_HAECC6, 0x90 },
+ { OV7670_RAA_HAECC7, 0x94 },
+ { OV7670_R13_COM8, OV7670_COM8_FASTAEC
| OV7670_COM8_AECSTEP
| OV7670_COM8_BFILT
| OV7670_COM8_AGC
| OV7670_COM8_AEC },
/* Almost all of these are magic "reserved" values. */
- { OV7670_REG_COM5, 0x61 },
- { OV7670_REG_COM6, 0x4b },
+ { OV7670_R0E_COM5, 0x61 },
+ { OV7670_R0F_COM6, 0x4b },
{ 0x16, 0x02 },
- { OV7670_REG_MVFP, 0x07 },
+ { OV7670_R1E_MVFP, 0x07 },
{ 0x21, 0x02 },
{ 0x22, 0x91 },
{ 0x29, 0x07 },
@@ -1656,10 +1811,10 @@ static const struct ov_i2c_regvals norm_7670[] = {
{ 0x37, 0x1d },
{ 0x38, 0x71 },
{ 0x39, 0x2a },
- { OV7670_REG_COM12, 0x78 },
+ { OV7670_R3C_COM12, 0x78 },
{ 0x4d, 0x40 },
{ 0x4e, 0x20 },
- { OV7670_REG_GFIX, 0x00 },
+ { OV7670_R69_GFIX, 0x00 },
{ 0x6b, 0x4a },
{ 0x74, 0x10 },
{ 0x8d, 0x4f },
@@ -1691,12 +1846,11 @@ static const struct ov_i2c_regvals norm_7670[] = {
{ 0x6c, 0x0a },
{ 0x6d, 0x55 },
{ 0x6e, 0x11 },
- { 0x6f, 0x9f },
- /* "9e for advance AWB" */
+ { 0x6f, 0x9f }, /* "9e for advance AWB" */
{ 0x6a, 0x40 },
- { OV7670_REG_BLUE, 0x40 },
- { OV7670_REG_RED, 0x60 },
- { OV7670_REG_COM8, OV7670_COM8_FASTAEC
+ { OV7670_R01_BLUE, 0x40 },
+ { OV7670_R02_RED, 0x60 },
+ { OV7670_R13_COM8, OV7670_COM8_FASTAEC
| OV7670_COM8_AECSTEP
| OV7670_COM8_BFILT
| OV7670_COM8_AGC
@@ -1712,22 +1866,22 @@ static const struct ov_i2c_regvals norm_7670[] = {
{ 0x54, 0x80 },
{ 0x58, 0x9e },
- { OV7670_REG_COM16, OV7670_COM16_AWBGAIN },
- { OV7670_REG_EDGE, 0x00 },
+ { OV7670_R41_COM16, OV7670_COM16_AWBGAIN },
+ { OV7670_R3F_EDGE, 0x00 },
{ 0x75, 0x05 },
{ 0x76, 0xe1 },
{ 0x4c, 0x00 },
{ 0x77, 0x01 },
- { OV7670_REG_COM13, OV7670_COM13_GAMMA
+ { OV7670_R3D_COM13, OV7670_COM13_GAMMA
| OV7670_COM13_UVSAT
| 2}, /* was 3 */
{ 0x4b, 0x09 },
{ 0xc9, 0x60 },
- { OV7670_REG_COM16, 0x38 },
+ { OV7670_R41_COM16, 0x38 },
{ 0x56, 0x40 },
{ 0x34, 0x11 },
- { OV7670_REG_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
+ { OV7670_R3B_COM11, OV7670_COM11_EXP|OV7670_COM11_HZAUTO },
{ 0xa4, 0x88 },
{ 0x96, 0x00 },
{ 0x97, 0x30 },
@@ -1862,10 +2016,13 @@ static unsigned char ov7670_abs_to_sm(unsigned char v)
}
/* Write a OV519 register */
-static int reg_w(struct sd *sd, __u16 index, __u16 value)
+static void reg_w(struct sd *sd, u16 index, u16 value)
{
int ret, req = 0;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
@@ -1875,6 +2032,8 @@ static int reg_w(struct sd *sd, __u16 index, __u16 value)
req = 0x0a;
/* fall through */
case BRIDGE_W9968CF:
+ PDEBUG(D_USBO, "SET %02x %04x %04x",
+ req, value, index);
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
req,
@@ -1885,6 +2044,8 @@ static int reg_w(struct sd *sd, __u16 index, __u16 value)
req = 1;
}
+ PDEBUG(D_USBO, "SET %02x 0000 %04x %02x",
+ req, index, value);
sd->gspca_dev.usb_buf[0] = value;
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
@@ -1894,22 +2055,22 @@ static int reg_w(struct sd *sd, __u16 index, __u16 value)
sd->gspca_dev.usb_buf, 1, 500);
leave:
if (ret < 0) {
- PDEBUG(D_ERR, "Write reg 0x%04x -> [0x%02x] failed",
- value, index);
- return ret;
+ err("reg_w %02x failed %d", index, ret);
+ sd->gspca_dev.usb_err = ret;
+ return;
}
-
- PDEBUG(D_USBO, "Write reg 0x%04x -> [0x%02x]", value, index);
- return 0;
}
/* Read from a OV519 register, note not valid for the w9968cf!! */
/* returns: negative is error, pos or zero is data */
-static int reg_r(struct sd *sd, __u16 index)
+static int reg_r(struct sd *sd, u16 index)
{
int ret;
int req;
+ if (sd->gspca_dev.usb_err < 0)
+ return -1;
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
@@ -1930,29 +2091,37 @@ static int reg_r(struct sd *sd, __u16 index)
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
- PDEBUG(D_USBI, "Read reg [0x%02X] -> 0x%04X", index, ret);
- } else
- PDEBUG(D_ERR, "Read reg [0x%02x] failed", index);
+ PDEBUG(D_USBI, "GET %02x 0000 %04x %02x",
+ req, index, ret);
+ } else {
+ err("reg_r %02x failed %d", index, ret);
+ sd->gspca_dev.usb_err = ret;
+ }
return ret;
}
/* Read 8 values from a OV519 register */
static int reg_r8(struct sd *sd,
- __u16 index)
+ u16 index)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return -1;
+
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
1, /* REQ_IO */
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, index, sd->gspca_dev.usb_buf, 8, 500);
- if (ret >= 0)
+ if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
- else
- PDEBUG(D_ERR, "Read reg 8 [0x%02x] failed", index);
+ } else {
+ err("reg_r8 %02x failed %d", index, ret);
+ sd->gspca_dev.usb_err = ret;
+ }
return ret;
}
@@ -1963,34 +2132,37 @@ static int reg_r8(struct sd *sd,
* that are in the same position as 0's in "mask" are preserved, regardless
* of their respective state in "value".
*/
-static int reg_w_mask(struct sd *sd,
- __u16 index,
- __u8 value,
- __u8 mask)
+static void reg_w_mask(struct sd *sd,
+ u16 index,
+ u8 value,
+ u8 mask)
{
int ret;
- __u8 oldval;
+ u8 oldval;
if (mask != 0xff) {
value &= mask; /* Enforce mask on value */
ret = reg_r(sd, index);
if (ret < 0)
- return ret;
+ return;
oldval = ret & ~mask; /* Clear the masked bits */
value |= oldval; /* Set the desired bits */
}
- return reg_w(sd, index, value);
+ reg_w(sd, index, value);
}
/*
* Writes multiple (n) byte value to a single register. Only valid with certain
* registers (0x30 and 0xc4 - 0xce).
*/
-static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
+static void ov518_reg_w32(struct sd *sd, u16 index, u32 value, int n)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
*((__le32 *) sd->gspca_dev.usb_buf) = __cpu_to_le32(value);
ret = usb_control_msg(sd->gspca_dev.dev,
@@ -2000,69 +2172,55 @@ static int ov518_reg_w32(struct sd *sd, __u16 index, u32 value, int n)
0, index,
sd->gspca_dev.usb_buf, n, 500);
if (ret < 0) {
- PDEBUG(D_ERR, "Write reg32 [%02x] %08x failed", index, value);
- return ret;
+ err("reg_w32 %02x failed %d", index, ret);
+ sd->gspca_dev.usb_err = ret;
}
-
- return 0;
}
-static int ov511_i2c_w(struct sd *sd, __u8 reg, __u8 value)
+static void ov511_i2c_w(struct sd *sd, u8 reg, u8 value)
{
int rc, retries;
- PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+ PDEBUG(D_USBO, "ov511_i2c_w %02x %02x", reg, value);
/* Three byte write cycle */
for (retries = 6; ; ) {
/* Select camera register */
- rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_SADDR_3, reg);
/* Write "value" to I2C data port of OV511 */
- rc = reg_w(sd, R51x_I2C_DATA, value);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_DATA, value);
/* Initiate 3-byte write cycle */
- rc = reg_w(sd, R511_I2C_CTL, 0x01);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x01);
do {
rc = reg_r(sd, R511_I2C_CTL);
} while (rc > 0 && ((rc & 1) == 0)); /* Retry until idle */
if (rc < 0)
- return rc;
+ return;
if ((rc & 2) == 0) /* Ack? */
break;
if (--retries < 0) {
PDEBUG(D_USBO, "i2c write retries exhausted");
- return -1;
+ return;
}
}
-
- return 0;
}
-static int ov511_i2c_r(struct sd *sd, __u8 reg)
+static int ov511_i2c_r(struct sd *sd, u8 reg)
{
int rc, value, retries;
/* Two byte write cycle */
for (retries = 6; ; ) {
/* Select camera register */
- rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_SADDR_2, reg);
/* Initiate 2-byte write cycle */
- rc = reg_w(sd, R511_I2C_CTL, 0x03);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x03);
do {
rc = reg_r(sd, R511_I2C_CTL);
@@ -2086,9 +2244,7 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
/* Two byte read cycle */
for (retries = 6; ; ) {
/* Initiate 2-byte read cycle */
- rc = reg_w(sd, R511_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x05);
do {
rc = reg_r(sd, R511_I2C_CTL);
@@ -2101,9 +2257,7 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
break;
/* I2C abort */
- rc = reg_w(sd, R511_I2C_CTL, 0x10);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x10);
if (--retries < 0) {
PDEBUG(D_USBI, "i2c read retries exhausted");
@@ -2113,12 +2267,10 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
value = reg_r(sd, R51x_I2C_DATA);
- PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+ PDEBUG(D_USBI, "ov511_i2c_r %02x %02x", reg, value);
/* This is needed to make i2c_w() work */
- rc = reg_w(sd, R511_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
+ reg_w(sd, R511_I2C_CTL, 0x05);
return value;
}
@@ -2128,32 +2280,24 @@ static int ov511_i2c_r(struct sd *sd, __u8 reg)
* This is normally only called from i2c_w(). Note that this function
* always succeeds regardless of whether the sensor is present and working.
*/
-static int ov518_i2c_w(struct sd *sd,
- __u8 reg,
- __u8 value)
+static void ov518_i2c_w(struct sd *sd,
+ u8 reg,
+ u8 value)
{
- int rc;
-
- PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
+ PDEBUG(D_USBO, "ov518_i2c_w %02x %02x", reg, value);
/* Select camera register */
- rc = reg_w(sd, R51x_I2C_SADDR_3, reg);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_SADDR_3, reg);
/* Write "value" to I2C data port of OV511 */
- rc = reg_w(sd, R51x_I2C_DATA, value);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_DATA, value);
/* Initiate 3-byte write cycle */
- rc = reg_w(sd, R518_I2C_CTL, 0x01);
- if (rc < 0)
- return rc;
+ reg_w(sd, R518_I2C_CTL, 0x01);
/* wait for write complete */
msleep(4);
- return reg_r8(sd, R518_I2C_CTL);
+ reg_r8(sd, R518_I2C_CTL);
}
/*
@@ -2163,105 +2307,102 @@ static int ov518_i2c_w(struct sd *sd,
* This is normally only called from i2c_r(). Note that this function
* always succeeds regardless of whether the sensor is present and working.
*/
-static int ov518_i2c_r(struct sd *sd, __u8 reg)
+static int ov518_i2c_r(struct sd *sd, u8 reg)
{
- int rc, value;
+ int value;
/* Select camera register */
- rc = reg_w(sd, R51x_I2C_SADDR_2, reg);
- if (rc < 0)
- return rc;
+ reg_w(sd, R51x_I2C_SADDR_2, reg);
/* Initiate 2-byte write cycle */
- rc = reg_w(sd, R518_I2C_CTL, 0x03);
- if (rc < 0)
- return rc;
+ reg_w(sd, R518_I2C_CTL, 0x03);
/* Initiate 2-byte read cycle */
- rc = reg_w(sd, R518_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
+ reg_w(sd, R518_I2C_CTL, 0x05);
value = reg_r(sd, R51x_I2C_DATA);
- PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
+ PDEBUG(D_USBI, "ov518_i2c_r %02x %02x", reg, value);
return value;
}
-static int ovfx2_i2c_w(struct sd *sd, __u8 reg, __u8 value)
+static void ovfx2_i2c_w(struct sd *sd, u8 reg, u8 value)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
ret = usb_control_msg(sd->gspca_dev.dev,
usb_sndctrlpipe(sd->gspca_dev.dev, 0),
0x02,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- (__u16)value, (__u16)reg, NULL, 0, 500);
+ (u16) value, (u16) reg, NULL, 0, 500);
if (ret < 0) {
- PDEBUG(D_ERR, "i2c 0x%02x -> [0x%02x] failed", value, reg);
- return ret;
+ err("ovfx2_i2c_w %02x failed %d", reg, ret);
+ sd->gspca_dev.usb_err = ret;
}
- PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
- return 0;
+ PDEBUG(D_USBO, "ovfx2_i2c_w %02x %02x", reg, value);
}
-static int ovfx2_i2c_r(struct sd *sd, __u8 reg)
+static int ovfx2_i2c_r(struct sd *sd, u8 reg)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return -1;
+
ret = usb_control_msg(sd->gspca_dev.dev,
usb_rcvctrlpipe(sd->gspca_dev.dev, 0),
0x03,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, sd->gspca_dev.usb_buf, 1, 500);
+ 0, (u16) reg, sd->gspca_dev.usb_buf, 1, 500);
if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0];
- PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, ret);
- } else
- PDEBUG(D_ERR, "i2c read [0x%02x] failed", reg);
+ PDEBUG(D_USBI, "ovfx2_i2c_r %02x %02x", reg, ret);
+ } else {
+ err("ovfx2_i2c_r %02x failed %d", reg, ret);
+ sd->gspca_dev.usb_err = ret;
+ }
return ret;
}
-static int i2c_w(struct sd *sd, __u8 reg, __u8 value)
+static void i2c_w(struct sd *sd, u8 reg, u8 value)
{
- int ret = -1;
-
if (sd->sensor_reg_cache[reg] == value)
- return 0;
+ return;
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- ret = ov511_i2c_w(sd, reg, value);
+ ov511_i2c_w(sd, reg, value);
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
case BRIDGE_OV519:
- ret = ov518_i2c_w(sd, reg, value);
+ ov518_i2c_w(sd, reg, value);
break;
case BRIDGE_OVFX2:
- ret = ovfx2_i2c_w(sd, reg, value);
+ ovfx2_i2c_w(sd, reg, value);
break;
case BRIDGE_W9968CF:
- ret = w9968cf_i2c_w(sd, reg, value);
+ w9968cf_i2c_w(sd, reg, value);
break;
}
- if (ret >= 0) {
+ if (sd->gspca_dev.usb_err >= 0) {
/* Up on sensor reset empty the register cache */
if (reg == 0x12 && (value & 0x80))
memset(sd->sensor_reg_cache, -1,
- sizeof(sd->sensor_reg_cache));
+ sizeof(sd->sensor_reg_cache));
else
sd->sensor_reg_cache[reg] = value;
}
-
- return ret;
}
-static int i2c_r(struct sd *sd, __u8 reg)
+static int i2c_r(struct sd *sd, u8 reg)
{
int ret = -1;
@@ -2297,95 +2438,99 @@ static int i2c_r(struct sd *sd, __u8 reg)
* that are in the same position as 0's in "mask" are preserved, regardless
* of their respective state in "value".
*/
-static int i2c_w_mask(struct sd *sd,
- __u8 reg,
- __u8 value,
- __u8 mask)
+static void i2c_w_mask(struct sd *sd,
+ u8 reg,
+ u8 value,
+ u8 mask)
{
int rc;
- __u8 oldval;
+ u8 oldval;
value &= mask; /* Enforce mask on value */
rc = i2c_r(sd, reg);
if (rc < 0)
- return rc;
+ return;
oldval = rc & ~mask; /* Clear the masked bits */
value |= oldval; /* Set the desired bits */
- return i2c_w(sd, reg, value);
+ i2c_w(sd, reg, value);
}
/* Temporarily stops OV511 from functioning. Must do this before changing
* registers while the camera is streaming */
-static inline int ov51x_stop(struct sd *sd)
+static inline void ov51x_stop(struct sd *sd)
{
PDEBUG(D_STREAM, "stopping");
sd->stopped = 1;
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- return reg_w(sd, R51x_SYS_RESET, 0x3d);
+ reg_w(sd, R51x_SYS_RESET, 0x3d);
+ break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- return reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
+ reg_w_mask(sd, R51x_SYS_RESET, 0x3a, 0x3a);
+ break;
case BRIDGE_OV519:
- return reg_w(sd, OV519_SYS_RESET1, 0x0f);
+ reg_w(sd, OV519_R51_RESET1, 0x0f);
+ reg_w(sd, OV519_R51_RESET1, 0x00);
+ reg_w(sd, 0x22, 0x00); /* FRAR */
+ break;
case BRIDGE_OVFX2:
- return reg_w_mask(sd, 0x0f, 0x00, 0x02);
+ reg_w_mask(sd, 0x0f, 0x00, 0x02);
+ break;
case BRIDGE_W9968CF:
- return reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */
+ reg_w(sd, 0x3c, 0x0a05); /* stop USB transfer */
+ break;
}
-
- return 0;
}
/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
* actually stopped (for performance). */
-static inline int ov51x_restart(struct sd *sd)
+static inline void ov51x_restart(struct sd *sd)
{
- int rc;
-
PDEBUG(D_STREAM, "restarting");
if (!sd->stopped)
- return 0;
+ return;
sd->stopped = 0;
/* Reinitialize the stream */
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- return reg_w(sd, R51x_SYS_RESET, 0x00);
+ reg_w(sd, R51x_SYS_RESET, 0x00);
+ break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- rc = reg_w(sd, 0x2f, 0x80);
- if (rc < 0)
- return rc;
- return reg_w(sd, R51x_SYS_RESET, 0x00);
+ reg_w(sd, 0x2f, 0x80);
+ reg_w(sd, R51x_SYS_RESET, 0x00);
+ break;
case BRIDGE_OV519:
- return reg_w(sd, OV519_SYS_RESET1, 0x00);
+ reg_w(sd, OV519_R51_RESET1, 0x0f);
+ reg_w(sd, OV519_R51_RESET1, 0x00);
+ reg_w(sd, 0x22, 0x1d); /* FRAR */
+ break;
case BRIDGE_OVFX2:
- return reg_w_mask(sd, 0x0f, 0x02, 0x02);
+ reg_w_mask(sd, 0x0f, 0x02, 0x02);
+ break;
case BRIDGE_W9968CF:
- return reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */
+ reg_w(sd, 0x3c, 0x8a05); /* USB FIFO enable */
+ break;
}
-
- return 0;
}
-static int ov51x_set_slave_ids(struct sd *sd, __u8 slave);
+static void ov51x_set_slave_ids(struct sd *sd, u8 slave);
/* This does an initial reset of an OmniVision sensor and ensures that I2C
* is synchronized. Returns <0 on failure.
*/
-static int init_ov_sensor(struct sd *sd, __u8 slave)
+static int init_ov_sensor(struct sd *sd, u8 slave)
{
int i;
- if (ov51x_set_slave_ids(sd, slave) < 0)
- return -EIO;
+ ov51x_set_slave_ids(sd, slave);
/* Reset the sensor */
- if (i2c_w(sd, 0x12, 0x80) < 0)
- return -EIO;
+ i2c_w(sd, 0x12, 0x80);
/* Wait for it to initialize */
msleep(150);
@@ -2398,15 +2543,16 @@ static int init_ov_sensor(struct sd *sd, __u8 slave)
}
/* Reset the sensor */
- if (i2c_w(sd, 0x12, 0x80) < 0)
- return -EIO;
+ i2c_w(sd, 0x12, 0x80);
+
/* Wait for it to initialize */
msleep(150);
+
/* Dummy read to sync I2C */
if (i2c_r(sd, 0x00) < 0)
- return -EIO;
+ return -1;
}
- return -EIO;
+ return -1;
}
/* Set the read and write slave IDs. The "slave" argument is the write slave,
@@ -2414,53 +2560,40 @@ static int init_ov_sensor(struct sd *sd, __u8 slave)
* This should not be called from outside the i2c I/O functions.
* Sets I2C read and write slave IDs. Returns <0 for error
*/
-static int ov51x_set_slave_ids(struct sd *sd,
- __u8 slave)
+static void ov51x_set_slave_ids(struct sd *sd,
+ u8 slave)
{
- int rc;
-
switch (sd->bridge) {
case BRIDGE_OVFX2:
- return reg_w(sd, OVFX2_I2C_ADDR, slave);
+ reg_w(sd, OVFX2_I2C_ADDR, slave);
+ return;
case BRIDGE_W9968CF:
sd->sensor_addr = slave;
- return 0;
+ return;
}
- rc = reg_w(sd, R51x_I2C_W_SID, slave);
- if (rc < 0)
- return rc;
- return reg_w(sd, R51x_I2C_R_SID, slave + 1);
+ reg_w(sd, R51x_I2C_W_SID, slave);
+ reg_w(sd, R51x_I2C_R_SID, slave + 1);
}
-static int write_regvals(struct sd *sd,
+static void write_regvals(struct sd *sd,
const struct ov_regvals *regvals,
int n)
{
- int rc;
-
while (--n >= 0) {
- rc = reg_w(sd, regvals->reg, regvals->val);
- if (rc < 0)
- return rc;
+ reg_w(sd, regvals->reg, regvals->val);
regvals++;
}
- return 0;
}
-static int write_i2c_regvals(struct sd *sd,
- const struct ov_i2c_regvals *regvals,
- int n)
+static void write_i2c_regvals(struct sd *sd,
+ const struct ov_i2c_regvals *regvals,
+ int n)
{
- int rc;
-
while (--n >= 0) {
- rc = i2c_w(sd, regvals->reg, regvals->val);
- if (rc < 0)
- return rc;
+ i2c_w(sd, regvals->reg, regvals->val);
regvals++;
}
- return 0;
}
/****************************************************************************
@@ -2470,13 +2603,13 @@ static int write_i2c_regvals(struct sd *sd,
***************************************************************************/
/* This initializes the OV2x10 / OV3610 / OV3620 */
-static int ov_hires_configure(struct sd *sd)
+static void ov_hires_configure(struct sd *sd)
{
int high, low;
if (sd->bridge != BRIDGE_OVFX2) {
- PDEBUG(D_ERR, "error hires sensors only supported with ovfx2");
- return -1;
+ err("error hires sensors only supported with ovfx2");
+ return;
}
PDEBUG(D_PROBE, "starting ov hires configuration");
@@ -2492,20 +2625,15 @@ static int ov_hires_configure(struct sd *sd)
PDEBUG(D_PROBE, "Sensor is an OV3610");
sd->sensor = SEN_OV3610;
} else {
- PDEBUG(D_ERR, "Error unknown sensor type: 0x%02x%02x",
- high, low);
- return -1;
+ err("Error unknown sensor type: %02x%02x",
+ high, low);
}
-
- /* Set sensor-specific vars */
- return 0;
}
-
/* This initializes the OV8110, OV8610 sensor. The OV8110 uses
* the same register settings as the OV8610, since they are very similar.
*/
-static int ov8xx0_configure(struct sd *sd)
+static void ov8xx0_configure(struct sd *sd)
{
int rc;
@@ -2515,27 +2643,21 @@ static int ov8xx0_configure(struct sd *sd)
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
PDEBUG(D_ERR, "Error detecting sensor type");
- return -1;
+ return;
}
- if ((rc & 3) == 1) {
+ if ((rc & 3) == 1)
sd->sensor = SEN_OV8610;
- } else {
- PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
- return -1;
- }
-
- /* Set sensor-specific vars */
- return 0;
+ else
+ err("Unknown image sensor version: %d", rc & 3);
}
/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
* the same register settings as the OV7610, since they are very similar.
*/
-static int ov7xx0_configure(struct sd *sd)
+static void ov7xx0_configure(struct sd *sd)
{
int rc, high, low;
-
PDEBUG(D_PROBE, "starting OV7xx0 configuration");
/* Detect sensor (sub)type */
@@ -2545,15 +2667,15 @@ static int ov7xx0_configure(struct sd *sd)
* it appears to be wrongly detected as a 7610 by default */
if (rc < 0) {
PDEBUG(D_ERR, "Error detecting sensor type");
- return -1;
+ return;
}
if ((rc & 3) == 3) {
/* quick hack to make OV7670s work */
high = i2c_r(sd, 0x0a);
low = i2c_r(sd, 0x0b);
/* info("%x, %x", high, low); */
- if (high == 0x76 && low == 0x73) {
- PDEBUG(D_PROBE, "Sensor is an OV7670");
+ if (high == 0x76 && (low & 0xf0) == 0x70) {
+ PDEBUG(D_PROBE, "Sensor is an OV76%02x", low);
sd->sensor = SEN_OV7670;
} else {
PDEBUG(D_PROBE, "Sensor is an OV7610");
@@ -2573,20 +2695,19 @@ static int ov7xx0_configure(struct sd *sd)
high = i2c_r(sd, 0x0a);
if (high < 0) {
PDEBUG(D_ERR, "Error detecting camera chip PID");
- return high;
+ return;
}
low = i2c_r(sd, 0x0b);
if (low < 0) {
PDEBUG(D_ERR, "Error detecting camera chip VER");
- return low;
+ return;
}
if (high == 0x76) {
switch (low) {
case 0x30:
- PDEBUG(D_PROBE, "Sensor is an OV7630/OV7635");
- PDEBUG(D_ERR,
- "7630 is not supported by this driver");
- return -1;
+ err("Sensor is an OV7630/OV7635");
+ err("7630 is not supported by this driver");
+ return;
case 0x40:
PDEBUG(D_PROBE, "Sensor is an OV7645");
sd->sensor = SEN_OV7640; /* FIXME */
@@ -2599,25 +2720,26 @@ static int ov7xx0_configure(struct sd *sd)
PDEBUG(D_PROBE, "Sensor is an OV7648");
sd->sensor = SEN_OV7648;
break;
+ case 0x60:
+ PDEBUG(D_PROBE, "Sensor is a OV7660");
+ sd->sensor = SEN_OV7660;
+ sd->invert_led = 0;
+ break;
default:
PDEBUG(D_PROBE, "Unknown sensor: 0x76%x", low);
- return -1;
+ return;
}
} else {
PDEBUG(D_PROBE, "Sensor is an OV7620");
sd->sensor = SEN_OV7620;
}
} else {
- PDEBUG(D_ERR, "Unknown image sensor version: %d", rc & 3);
- return -1;
+ err("Unknown image sensor version: %d", rc & 3);
}
-
- /* Set sensor-specific vars */
- return 0;
}
/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int ov6xx0_configure(struct sd *sd)
+static void ov6xx0_configure(struct sd *sd)
{
int rc;
PDEBUG(D_PROBE, "starting OV6xx0 configuration");
@@ -2626,7 +2748,7 @@ static int ov6xx0_configure(struct sd *sd)
rc = i2c_r(sd, OV7610_REG_COM_I);
if (rc < 0) {
PDEBUG(D_ERR, "Error detecting sensor type");
- return -1;
+ return;
}
/* Ugh. The first two bits are the version bits, but
@@ -2635,9 +2757,8 @@ static int ov6xx0_configure(struct sd *sd)
switch (rc) {
case 0x00:
sd->sensor = SEN_OV6630;
- PDEBUG(D_ERR,
- "WARNING: Sensor is an OV66308. Your camera may have");
- PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+ warn("WARNING: Sensor is an OV66308. Your camera may have");
+ warn("been misdetected in previous driver versions.");
break;
case 0x01:
sd->sensor = SEN_OV6620;
@@ -2653,19 +2774,16 @@ static int ov6xx0_configure(struct sd *sd)
break;
case 0x90:
sd->sensor = SEN_OV6630;
- PDEBUG(D_ERR,
- "WARNING: Sensor is an OV66307. Your camera may have");
- PDEBUG(D_ERR, "been misdetected in previous driver versions.");
+ warn("WARNING: Sensor is an OV66307. Your camera may have");
+ warn("been misdetected in previous driver versions.");
break;
default:
- PDEBUG(D_ERR, "FATAL: Unknown sensor version: 0x%02x", rc);
- return -1;
+ err("FATAL: Unknown sensor version: 0x%02x", rc);
+ return;
}
/* Set sensor-specific vars */
sd->sif = 1;
-
- return 0;
}
/* Turns on or off the LED. Only has an effect with OV511+/OV518(+)/OV519 */
@@ -2677,14 +2795,14 @@ static void ov51x_led_control(struct sd *sd, int on)
switch (sd->bridge) {
/* OV511 has no LED control */
case BRIDGE_OV511PLUS:
- reg_w(sd, R511_SYS_LED_CTL, on ? 1 : 0);
+ reg_w(sd, R511_SYS_LED_CTL, on);
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- reg_w_mask(sd, R518_GPIO_OUT, on ? 0x02 : 0x00, 0x02);
+ reg_w_mask(sd, R518_GPIO_OUT, 0x02 * on, 0x02);
break;
case BRIDGE_OV519:
- reg_w_mask(sd, OV519_GPIO_DATA_OUT0, !on, 1); /* 0 / 1 */
+ reg_w_mask(sd, OV519_GPIO_DATA_OUT0, on, 1);
break;
}
}
@@ -2719,7 +2837,7 @@ static void sd_reset_snapshot(struct gspca_dev *gspca_dev)
}
}
-static int ov51x_upload_quan_tables(struct sd *sd)
+static void ov51x_upload_quan_tables(struct sd *sd)
{
const unsigned char yQuanTable511[] = {
0, 1, 1, 2, 2, 3, 3, 4,
@@ -2750,7 +2868,6 @@ static int ov51x_upload_quan_tables(struct sd *sd)
6, 6, 6, 6, 7, 7, 7, 8,
7, 7, 6, 7, 7, 7, 8, 8
};
-
const unsigned char uvQuanTable518[] = {
6, 6, 6, 7, 7, 7, 7, 7,
6, 6, 6, 7, 7, 7, 7, 7,
@@ -2760,18 +2877,18 @@ static int ov51x_upload_quan_tables(struct sd *sd)
const unsigned char *pYTable, *pUVTable;
unsigned char val0, val1;
- int i, size, rc, reg = R51x_COMP_LUT_BEGIN;
+ int i, size, reg = R51x_COMP_LUT_BEGIN;
PDEBUG(D_PROBE, "Uploading quantization tables");
if (sd->bridge == BRIDGE_OV511 || sd->bridge == BRIDGE_OV511PLUS) {
pYTable = yQuanTable511;
pUVTable = uvQuanTable511;
- size = 32;
+ size = 32;
} else {
pYTable = yQuanTable518;
pUVTable = uvQuanTable518;
- size = 16;
+ size = 16;
}
for (i = 0; i < size; i++) {
@@ -2780,30 +2897,23 @@ static int ov51x_upload_quan_tables(struct sd *sd)
val0 &= 0x0f;
val1 &= 0x0f;
val0 |= val1 << 4;
- rc = reg_w(sd, reg, val0);
- if (rc < 0)
- return rc;
+ reg_w(sd, reg, val0);
val0 = *pUVTable++;
val1 = *pUVTable++;
val0 &= 0x0f;
val1 &= 0x0f;
val0 |= val1 << 4;
- rc = reg_w(sd, reg + size, val0);
- if (rc < 0)
- return rc;
+ reg_w(sd, reg + size, val0);
reg++;
}
-
- return 0;
}
/* This initializes the OV511/OV511+ and the sensor */
-static int ov511_configure(struct gspca_dev *gspca_dev)
+static void ov511_configure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int rc;
/* For 511 and 511+ */
const struct ov_regvals init_511[] = {
@@ -2817,7 +2927,7 @@ static int ov511_configure(struct gspca_dev *gspca_dev)
};
const struct ov_regvals norm_511[] = {
- { R511_DRAM_FLOW_CTL, 0x01 },
+ { R511_DRAM_FLOW_CTL, 0x01 },
{ R51x_SYS_SNAP, 0x00 },
{ R51x_SYS_SNAP, 0x02 },
{ R51x_SYS_SNAP, 0x00 },
@@ -2849,42 +2959,27 @@ static int ov511_configure(struct gspca_dev *gspca_dev)
PDEBUG(D_PROBE, "Device custom id %x", reg_r(sd, R51x_SYS_CUST_ID));
- rc = write_regvals(sd, init_511, ARRAY_SIZE(init_511));
- if (rc < 0)
- return rc;
+ write_regvals(sd, init_511, ARRAY_SIZE(init_511));
switch (sd->bridge) {
case BRIDGE_OV511:
- rc = write_regvals(sd, norm_511, ARRAY_SIZE(norm_511));
- if (rc < 0)
- return rc;
+ write_regvals(sd, norm_511, ARRAY_SIZE(norm_511));
break;
case BRIDGE_OV511PLUS:
- rc = write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p));
- if (rc < 0)
- return rc;
+ write_regvals(sd, norm_511_p, ARRAY_SIZE(norm_511_p));
break;
}
/* Init compression */
- rc = write_regvals(sd, compress_511, ARRAY_SIZE(compress_511));
- if (rc < 0)
- return rc;
+ write_regvals(sd, compress_511, ARRAY_SIZE(compress_511));
- rc = ov51x_upload_quan_tables(sd);
- if (rc < 0) {
- PDEBUG(D_ERR, "Error uploading quantization tables");
- return rc;
- }
-
- return 0;
+ ov51x_upload_quan_tables(sd);
}
/* This initializes the OV518/OV518+ and the sensor */
-static int ov518_configure(struct gspca_dev *gspca_dev)
+static void ov518_configure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int rc;
/* For 518 and 518+ */
const struct ov_regvals init_518[] = {
@@ -2901,7 +2996,7 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
const struct ov_regvals norm_518[] = {
{ R51x_SYS_SNAP, 0x02 }, /* Reset */
{ R51x_SYS_SNAP, 0x01 }, /* Enable */
- { 0x31, 0x0f },
+ { 0x31, 0x0f },
{ 0x5d, 0x03 },
{ 0x24, 0x9f },
{ 0x25, 0x90 },
@@ -2914,7 +3009,7 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
const struct ov_regvals norm_518_p[] = {
{ R51x_SYS_SNAP, 0x02 }, /* Reset */
{ R51x_SYS_SNAP, 0x01 }, /* Enable */
- { 0x31, 0x0f },
+ { 0x31, 0x0f },
{ 0x5d, 0x03 },
{ 0x24, 0x9f },
{ 0x25, 0x90 },
@@ -2932,65 +3027,49 @@ static int ov518_configure(struct gspca_dev *gspca_dev)
/* First 5 bits of custom ID reg are a revision ID on OV518 */
PDEBUG(D_PROBE, "Device revision %d",
- 0x1F & reg_r(sd, R51x_SYS_CUST_ID));
+ 0x1f & reg_r(sd, R51x_SYS_CUST_ID));
- rc = write_regvals(sd, init_518, ARRAY_SIZE(init_518));
- if (rc < 0)
- return rc;
+ write_regvals(sd, init_518, ARRAY_SIZE(init_518));
/* Set LED GPIO pin to output mode */
- rc = reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
- if (rc < 0)
- return rc;
+ reg_w_mask(sd, R518_GPIO_CTL, 0x00, 0x02);
switch (sd->bridge) {
case BRIDGE_OV518:
- rc = write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
- if (rc < 0)
- return rc;
+ write_regvals(sd, norm_518, ARRAY_SIZE(norm_518));
break;
case BRIDGE_OV518PLUS:
- rc = write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
- if (rc < 0)
- return rc;
+ write_regvals(sd, norm_518_p, ARRAY_SIZE(norm_518_p));
break;
}
- rc = ov51x_upload_quan_tables(sd);
- if (rc < 0) {
- PDEBUG(D_ERR, "Error uploading quantization tables");
- return rc;
- }
-
- rc = reg_w(sd, 0x2f, 0x80);
- if (rc < 0)
- return rc;
+ ov51x_upload_quan_tables(sd);
- return 0;
+ reg_w(sd, 0x2f, 0x80);
}
-static int ov519_configure(struct sd *sd)
+static void ov519_configure(struct sd *sd)
{
static const struct ov_regvals init_519[] = {
- { 0x5a, 0x6d }, /* EnableSystem */
- { 0x53, 0x9b },
- { 0x54, 0xff }, /* set bit2 to enable jpeg */
- { 0x5d, 0x03 },
- { 0x49, 0x01 },
- { 0x48, 0x00 },
+ { 0x5a, 0x6d }, /* EnableSystem */
+ { 0x53, 0x9b }, /* don't enable the microcontroller */
+ { OV519_R54_EN_CLK1, 0xff }, /* set bit2 to enable jpeg */
+ { 0x5d, 0x03 },
+ { 0x49, 0x01 },
+ { 0x48, 0x00 },
/* Set LED pin to output mode. Bit 4 must be cleared or sensor
* detection will fail. This deserves further investigation. */
{ OV519_GPIO_IO_CTRL0, 0xee },
- { 0x51, 0x0f }, /* SetUsbInit */
- { 0x51, 0x00 },
- { 0x22, 0x00 },
+ { OV519_R51_RESET1, 0x0f },
+ { OV519_R51_RESET1, 0x00 },
+ { 0x22, 0x00 },
/* windows reads 0x55 at this point*/
};
- return write_regvals(sd, init_519, ARRAY_SIZE(init_519));
+ write_regvals(sd, init_519, ARRAY_SIZE(init_519));
}
-static int ovfx2_configure(struct sd *sd)
+static void ovfx2_configure(struct sd *sd)
{
static const struct ov_regvals init_fx2[] = {
{ 0x00, 0x60 },
@@ -3004,7 +3083,92 @@ static int ovfx2_configure(struct sd *sd)
sd->stopped = 1;
- return write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2));
+ write_regvals(sd, init_fx2, ARRAY_SIZE(init_fx2));
+}
+
+/* set the mode */
+/* This function works for ov7660 only */
+static void ov519_set_mode(struct sd *sd)
+{
+ static const struct ov_regvals bridge_ov7660[2][10] = {
+ {{0x10, 0x14}, {0x11, 0x1e}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c},
+ {0x25, 0x01}, {0x26, 0x00}},
+ {{0x10, 0x28}, {0x11, 0x3c}, {0x12, 0x00}, {0x13, 0x00},
+ {0x14, 0x00}, {0x15, 0x00}, {0x16, 0x00}, {0x20, 0x0c},
+ {0x25, 0x03}, {0x26, 0x00}}
+ };
+ static const struct ov_i2c_regvals sensor_ov7660[2][3] = {
+ {{0x12, 0x00}, {0x24, 0x00}, {0x0c, 0x0c}},
+ {{0x12, 0x00}, {0x04, 0x00}, {0x0c, 0x00}}
+ };
+ static const struct ov_i2c_regvals sensor_ov7660_2[] = {
+ {OV7670_R17_HSTART, 0x13},
+ {OV7670_R18_HSTOP, 0x01},
+ {OV7670_R32_HREF, 0x92},
+ {OV7670_R19_VSTART, 0x02},
+ {OV7670_R1A_VSTOP, 0x7a},
+ {OV7670_R03_VREF, 0x00},
+/* {0x33, 0x00}, */
+/* {0x34, 0x07}, */
+/* {0x36, 0x00}, */
+/* {0x6b, 0x0a}, */
+ };
+
+ write_regvals(sd, bridge_ov7660[sd->gspca_dev.curr_mode],
+ ARRAY_SIZE(bridge_ov7660[0]));
+ write_i2c_regvals(sd, sensor_ov7660[sd->gspca_dev.curr_mode],
+ ARRAY_SIZE(sensor_ov7660[0]));
+ write_i2c_regvals(sd, sensor_ov7660_2,
+ ARRAY_SIZE(sensor_ov7660_2));
+}
+
+/* set the frame rate */
+/* This function works for sensors ov7640, ov7648 ov7660 and ov7670 only */
+static void ov519_set_fr(struct sd *sd)
+{
+ int fr;
+ u8 clock;
+ /* frame rate table with indices:
+ * - mode = 0: 320x240, 1: 640x480
+ * - fr rate = 0: 30, 1: 25, 2: 20, 3: 15, 4: 10, 5: 5
+ * - reg = 0: bridge a4, 1: bridge 23, 2: sensor 11 (clock)
+ */
+ static const u8 fr_tb[2][6][3] = {
+ {{0x04, 0xff, 0x00},
+ {0x04, 0x1f, 0x00},
+ {0x04, 0x1b, 0x00},
+ {0x04, 0x15, 0x00},
+ {0x04, 0x09, 0x00},
+ {0x04, 0x01, 0x00}},
+ {{0x0c, 0xff, 0x00},
+ {0x0c, 0x1f, 0x00},
+ {0x0c, 0x1b, 0x00},
+ {0x04, 0xff, 0x01},
+ {0x04, 0x1f, 0x01},
+ {0x04, 0x1b, 0x01}},
+ };
+
+ if (frame_rate > 0)
+ sd->frame_rate = frame_rate;
+ if (sd->frame_rate >= 30)
+ fr = 0;
+ else if (sd->frame_rate >= 25)
+ fr = 1;
+ else if (sd->frame_rate >= 20)
+ fr = 2;
+ else if (sd->frame_rate >= 15)
+ fr = 3;
+ else if (sd->frame_rate >= 10)
+ fr = 4;
+ else
+ fr = 5;
+ reg_w(sd, 0xa4, fr_tb[sd->gspca_dev.curr_mode][fr][0]);
+ reg_w(sd, 0x23, fr_tb[sd->gspca_dev.curr_mode][fr][1]);
+ clock = fr_tb[sd->gspca_dev.curr_mode][fr][2];
+ if (sd->sensor == SEN_OV7660)
+ clock |= 0x80; /* enable double clock */
+ ov518_i2c_w(sd, OV7670_R11_CLKRC, clock);
}
/* this function is called at probe time */
@@ -3013,99 +3177,119 @@ static int sd_config(struct gspca_dev *gspca_dev,
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
- int ret = 0;
sd->bridge = id->driver_info & BRIDGE_MASK;
- sd->invert_led = id->driver_info & BRIDGE_INVERT_LED;
+ sd->invert_led = (id->driver_info & BRIDGE_INVERT_LED) != 0;
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- ret = ov511_configure(gspca_dev);
+ cam->cam_mode = ov511_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov511_vga_mode);
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- ret = ov518_configure(gspca_dev);
+ cam->cam_mode = ov518_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
break;
case BRIDGE_OV519:
- ret = ov519_configure(sd);
+ cam->cam_mode = ov519_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
+ sd->invert_led = !sd->invert_led;
break;
case BRIDGE_OVFX2:
- ret = ovfx2_configure(sd);
+ cam->cam_mode = ov519_vga_mode;
+ cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
cam->bulk_size = OVFX2_BULK_SIZE;
cam->bulk_nurbs = MAX_NURBS;
cam->bulk = 1;
break;
case BRIDGE_W9968CF:
- ret = w9968cf_configure(sd);
+ cam->cam_mode = w9968cf_vga_mode;
+ cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
cam->reverse_alts = 1;
break;
}
- if (ret)
- goto error;
+ gspca_dev->cam.ctrls = sd->ctrls;
+ sd->quality = QUALITY_DEF;
- ov51x_led_control(sd, 0); /* turn LED off */
+ 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;
+ struct cam *cam = &gspca_dev->cam;
+
+ switch (sd->bridge) {
+ case BRIDGE_OV511:
+ case BRIDGE_OV511PLUS:
+ ov511_configure(gspca_dev);
+ break;
+ case BRIDGE_OV518:
+ case BRIDGE_OV518PLUS:
+ ov518_configure(gspca_dev);
+ break;
+ case BRIDGE_OV519:
+ ov519_configure(sd);
+ break;
+ case BRIDGE_OVFX2:
+ ovfx2_configure(sd);
+ break;
+ case BRIDGE_W9968CF:
+ w9968cf_configure(sd);
+ break;
+ }
/* The OV519 must be more aggressive about sensor detection since
* I2C write will never fail if the sensor is not present. We have
* to try to initialize the sensor to detect its presence */
+ sd->sensor = -1;
/* Test for 76xx */
if (init_ov_sensor(sd, OV7xx0_SID) >= 0) {
- if (ov7xx0_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure OV7xx0");
- goto error;
- }
+ ov7xx0_configure(sd);
+
/* Test for 6xx0 */
} else if (init_ov_sensor(sd, OV6xx0_SID) >= 0) {
- if (ov6xx0_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure OV6xx0");
- goto error;
- }
+ ov6xx0_configure(sd);
+
/* Test for 8xx0 */
} else if (init_ov_sensor(sd, OV8xx0_SID) >= 0) {
- if (ov8xx0_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure OV8xx0");
- goto error;
- }
+ ov8xx0_configure(sd);
+
/* Test for 3xxx / 2xxx */
} else if (init_ov_sensor(sd, OV_HIRES_SID) >= 0) {
- if (ov_hires_configure(sd) < 0) {
- PDEBUG(D_ERR, "Failed to configure high res OV");
- goto error;
- }
+ ov_hires_configure(sd);
} else {
- PDEBUG(D_ERR, "Can't determine sensor slave IDs");
+ err("Can't determine sensor slave IDs");
goto error;
}
+ if (sd->sensor < 0)
+ goto error;
+
+ ov51x_led_control(sd, 0); /* turn LED off */
+
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- if (!sd->sif) {
- cam->cam_mode = ov511_vga_mode;
- cam->nmodes = ARRAY_SIZE(ov511_vga_mode);
- } else {
+ if (sd->sif) {
cam->cam_mode = ov511_sif_mode;
cam->nmodes = ARRAY_SIZE(ov511_sif_mode);
}
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- if (!sd->sif) {
- cam->cam_mode = ov518_vga_mode;
- cam->nmodes = ARRAY_SIZE(ov518_vga_mode);
- } else {
+ if (sd->sif) {
cam->cam_mode = ov518_sif_mode;
cam->nmodes = ARRAY_SIZE(ov518_sif_mode);
}
break;
case BRIDGE_OV519:
- if (!sd->sif) {
- cam->cam_mode = ov519_vga_mode;
- cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
- } else {
+ if (sd->sif) {
cam->cam_mode = ov519_sif_mode;
cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
}
@@ -3117,127 +3301,107 @@ static int sd_config(struct gspca_dev *gspca_dev,
} else if (sd->sensor == SEN_OV3610) {
cam->cam_mode = ovfx2_ov3610_mode;
cam->nmodes = ARRAY_SIZE(ovfx2_ov3610_mode);
- } else if (!sd->sif) {
- cam->cam_mode = ov519_vga_mode;
- cam->nmodes = ARRAY_SIZE(ov519_vga_mode);
- } else {
+ } else if (sd->sif) {
cam->cam_mode = ov519_sif_mode;
cam->nmodes = ARRAY_SIZE(ov519_sif_mode);
}
break;
case BRIDGE_W9968CF:
- cam->cam_mode = w9968cf_vga_mode;
- cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode);
if (sd->sif)
- cam->nmodes--;
+ cam->nmodes = ARRAY_SIZE(w9968cf_vga_mode) - 1;
/* w9968cf needs initialisation once the sensor is known */
- if (w9968cf_init(sd) < 0)
- goto error;
+ w9968cf_init(sd);
break;
}
- sd->brightness = BRIGHTNESS_DEF;
- if (sd->sensor == SEN_OV6630 || sd->sensor == SEN_OV66308AF)
- sd->contrast = 200; /* The default is too low for the ov6630 */
- else
- sd->contrast = CONTRAST_DEF;
- sd->colors = COLOR_DEF;
- sd->hflip = HFLIP_DEF;
- sd->vflip = VFLIP_DEF;
- sd->autobrightness = AUTOBRIGHT_DEF;
- if (sd->sensor == SEN_OV7670) {
- sd->freq = OV7670_FREQ_DEF;
- gspca_dev->ctrl_dis = 1 << FREQ_IDX;
- } else {
- sd->freq = FREQ_DEF;
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) |
- (1 << OV7670_FREQ_IDX);
- }
- sd->quality = QUALITY_DEF;
- if (sd->sensor == SEN_OV7640 ||
- sd->sensor == SEN_OV7648)
- gspca_dev->ctrl_dis |= (1 << AUTOBRIGHT_IDX) |
- (1 << CONTRAST_IDX);
- if (sd->sensor == SEN_OV7670)
- gspca_dev->ctrl_dis |= 1 << AUTOBRIGHT_IDX;
- /* OV8610 Frequency filter control should work but needs testing */
- if (sd->sensor == SEN_OV8610)
- gspca_dev->ctrl_dis |= 1 << FREQ_IDX;
- /* No controls for the OV2610/OV3610 */
- if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
- gspca_dev->ctrl_dis |= 0xFF;
-
- return 0;
-error:
- PDEBUG(D_ERR, "OV519 Config failed");
- return -EBUSY;
-}
-/* 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;
+ gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
/* initialize the sensor */
switch (sd->sensor) {
case SEN_OV2610:
- if (write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610)))
- return -EIO;
+ write_i2c_regvals(sd, norm_2610, ARRAY_SIZE(norm_2610));
+
/* Enable autogain, autoexpo, awb, bandfilter */
- if (i2c_w_mask(sd, 0x13, 0x27, 0x27) < 0)
- return -EIO;
+ i2c_w_mask(sd, 0x13, 0x27, 0x27);
break;
case SEN_OV3610:
- if (write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b)))
- return -EIO;
+ write_i2c_regvals(sd, norm_3620b, ARRAY_SIZE(norm_3620b));
+
/* Enable autogain, autoexpo, awb, bandfilter */
- if (i2c_w_mask(sd, 0x13, 0x27, 0x27) < 0)
- return -EIO;
+ i2c_w_mask(sd, 0x13, 0x27, 0x27);
break;
case SEN_OV6620:
- if (write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20)))
- return -EIO;
+ write_i2c_regvals(sd, norm_6x20, ARRAY_SIZE(norm_6x20));
break;
case SEN_OV6630:
case SEN_OV66308AF:
- if (write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30)))
- return -EIO;
+ sd->ctrls[CONTRAST].def = 200;
+ /* The default is too low for the ov6630 */
+ write_i2c_regvals(sd, norm_6x30, ARRAY_SIZE(norm_6x30));
break;
default:
/* case SEN_OV7610: */
/* case SEN_OV76BE: */
- if (write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610)))
- return -EIO;
- if (i2c_w_mask(sd, 0x0e, 0x00, 0x40))
- return -EIO;
+ write_i2c_regvals(sd, norm_7610, ARRAY_SIZE(norm_7610));
+ i2c_w_mask(sd, 0x0e, 0x00, 0x40);
break;
case SEN_OV7620:
case SEN_OV7620AE:
- if (write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620)))
- return -EIO;
+ write_i2c_regvals(sd, norm_7620, ARRAY_SIZE(norm_7620));
break;
case SEN_OV7640:
case SEN_OV7648:
- if (write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640)))
- return -EIO;
+ write_i2c_regvals(sd, norm_7640, ARRAY_SIZE(norm_7640));
+ break;
+ case SEN_OV7660:
+ i2c_w(sd, OV7670_R12_COM7, OV7670_COM7_RESET);
+ msleep(14);
+ reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
+ write_regvals(sd, init_519_ov7660,
+ ARRAY_SIZE(init_519_ov7660));
+ write_i2c_regvals(sd, norm_7660, ARRAY_SIZE(norm_7660));
+ sd->gspca_dev.curr_mode = 1; /* 640x480 */
+ sd->frame_rate = 15;
+ ov519_set_mode(sd);
+ ov519_set_fr(sd);
+ sd->ctrls[COLORS].max = 4; /* 0..4 */
+ sd->ctrls[COLORS].val =
+ sd->ctrls[COLORS].def = 2;
+ setcolors(gspca_dev);
+ sd->ctrls[CONTRAST].max = 6; /* 0..6 */
+ sd->ctrls[CONTRAST].val =
+ sd->ctrls[CONTRAST].def = 3;
+ setcontrast(gspca_dev);
+ sd->ctrls[BRIGHTNESS].max = 6; /* 0..6 */
+ sd->ctrls[BRIGHTNESS].val =
+ sd->ctrls[BRIGHTNESS].def = 3;
+ setbrightness(gspca_dev);
+ sd_reset_snapshot(gspca_dev);
+ ov51x_restart(sd);
+ ov51x_stop(sd); /* not in win traces */
+ ov51x_led_control(sd, 0);
break;
case SEN_OV7670:
- if (write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670)))
- return -EIO;
+ sd->ctrls[FREQ].max = 3; /* auto */
+ sd->ctrls[FREQ].def = 3;
+ write_i2c_regvals(sd, norm_7670, ARRAY_SIZE(norm_7670));
break;
case SEN_OV8610:
- if (write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610)))
- return -EIO;
+ write_i2c_regvals(sd, norm_8610, ARRAY_SIZE(norm_8610));
break;
}
- return 0;
+ return gspca_dev->usb_err;
+error:
+ PDEBUG(D_ERR, "OV519 Config failed");
+ return -EINVAL;
}
/* Set up the OV511/OV511+ with the given image parameters.
*
* Do not put any sensor-specific code in here (including I2C I/O functions)
*/
-static int ov511_mode_init_regs(struct sd *sd)
+static void ov511_mode_init_regs(struct sd *sd)
{
int hsegs, vsegs, packet_size, fps, needed;
int interlaced = 0;
@@ -3247,8 +3411,9 @@ static int ov511_mode_init_regs(struct sd *sd)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
- PDEBUG(D_ERR, "Couldn't get altsetting");
- return -EIO;
+ err("Couldn't get altsetting");
+ sd->gspca_dev.usb_err = -EIO;
+ return;
}
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
@@ -3351,8 +3516,6 @@ static int ov511_mode_init_regs(struct sd *sd)
reg_w(sd, R51x_SYS_RESET, OV511_RESET_OMNICE);
reg_w(sd, R51x_SYS_RESET, 0);
-
- return 0;
}
/* Sets up the OV518/OV518+ with the given image parameters
@@ -3362,7 +3525,7 @@ static int ov511_mode_init_regs(struct sd *sd)
*
* Do not put any sensor-specific code in here (including I2C I/O functions)
*/
-static int ov518_mode_init_regs(struct sd *sd)
+static void ov518_mode_init_regs(struct sd *sd)
{
int hsegs, vsegs, packet_size;
struct usb_host_interface *alt;
@@ -3371,15 +3534,15 @@ static int ov518_mode_init_regs(struct sd *sd)
intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
if (!alt) {
- PDEBUG(D_ERR, "Couldn't get altsetting");
- return -EIO;
+ err("Couldn't get altsetting");
+ sd->gspca_dev.usb_err = -EIO;
+ return;
}
packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
ov518_reg_w32(sd, R51x_FIFO_PSIZE, packet_size & ~7, 2);
/******** Set the mode ********/
-
reg_w(sd, 0x2b, 0);
reg_w(sd, 0x2c, 0);
reg_w(sd, 0x2d, 0);
@@ -3413,7 +3576,7 @@ static int ov518_mode_init_regs(struct sd *sd)
/* Windows driver does this here; who knows why */
reg_w(sd, 0x2f, 0x80);
- /******** Set the framerate ********/
+ /******** Set the framerate ********/
sd->clockdiv = 1;
/* Mode independent, but framerate dependent, regs */
@@ -3476,11 +3639,8 @@ static int ov518_mode_init_regs(struct sd *sd)
}
reg_w(sd, 0x2f, 0x80);
-
- return 0;
}
-
/* Sets up the OV519 with the given image parameters
*
* OV519 needs a completely different approach, until we can figure out what
@@ -3488,12 +3648,12 @@ static int ov518_mode_init_regs(struct sd *sd)
*
* Do not put any sensor-specific code in here (including I2C I/O functions)
*/
-static int ov519_mode_init_regs(struct sd *sd)
+static void ov519_mode_init_regs(struct sd *sd)
{
static const struct ov_regvals mode_init_519_ov7670[] = {
{ 0x5d, 0x03 }, /* Turn off suspend mode */
{ 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
- { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */
{ 0xa2, 0x20 }, /* a2-a5 are undocumented */
{ 0xa3, 0x18 },
{ 0xa4, 0x04 },
@@ -3516,7 +3676,7 @@ static int ov519_mode_init_regs(struct sd *sd)
static const struct ov_regvals mode_init_519[] = {
{ 0x5d, 0x03 }, /* Turn off suspend mode */
{ 0x53, 0x9f }, /* was 9b in 1.65-1.08 */
- { 0x54, 0x0f }, /* bit2 (jpeg enable) */
+ { OV519_R54_EN_CLK1, 0x0f }, /* bit2 (jpeg enable) */
{ 0xa2, 0x20 }, /* a2-a5 are undocumented */
{ 0xa3, 0x18 },
{ 0xa4, 0x04 },
@@ -3535,19 +3695,21 @@ static int ov519_mode_init_regs(struct sd *sd)
};
/******** Set the mode ********/
- if (sd->sensor != SEN_OV7670) {
- if (write_regvals(sd, mode_init_519,
- ARRAY_SIZE(mode_init_519)))
- return -EIO;
+ switch (sd->sensor) {
+ default:
+ write_regvals(sd, mode_init_519, ARRAY_SIZE(mode_init_519));
if (sd->sensor == SEN_OV7640 ||
sd->sensor == SEN_OV7648) {
/* Select 8-bit input mode */
reg_w_mask(sd, OV519_R20_DFR, 0x10, 0x10);
}
- } else {
- if (write_regvals(sd, mode_init_519_ov7670,
- ARRAY_SIZE(mode_init_519_ov7670)))
- return -EIO;
+ break;
+ case SEN_OV7660:
+ return; /* done by ov519_set_mode/fr() */
+ case SEN_OV7670:
+ write_regvals(sd, mode_init_519_ov7670,
+ ARRAY_SIZE(mode_init_519_ov7670));
+ break;
}
reg_w(sd, OV519_R10_H_SIZE, sd->gspca_dev.width >> 4);
@@ -3643,17 +3805,16 @@ static int ov519_mode_init_regs(struct sd *sd)
}
break;
}
- return 0;
}
-static int mode_init_ov_sensor_regs(struct sd *sd)
+static void mode_init_ov_sensor_regs(struct sd *sd)
{
struct gspca_dev *gspca_dev;
int qvga, xstart, xend, ystart, yend;
- __u8 v;
+ u8 v;
gspca_dev = &sd->gspca_dev;
- qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
+ qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
/******** Mode (VGA/QVGA) and sensor specific regs ********/
switch (sd->sensor) {
@@ -3665,7 +3826,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
i2c_w_mask(sd, 0x2d, qvga ? 0x40 : 0x00, 0x40);
i2c_w_mask(sd, 0x67, qvga ? 0xf0 : 0x90, 0xf0);
i2c_w_mask(sd, 0x74, qvga ? 0x20 : 0x00, 0x20);
- return 0;
+ return;
case SEN_OV3610:
if (qvga) {
xstart = (1040 - gspca_dev->width) / 2 + (0x1f << 4);
@@ -3689,7 +3850,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
i2c_w(sd, 0x18, xend >> 4);
i2c_w(sd, 0x19, ystart >> 3);
i2c_w(sd, 0x1a, yend >> 3);
- return 0;
+ return;
case SEN_OV8610:
/* For OV8610 qvga means qsvga */
i2c_w_mask(sd, OV7610_REG_COM_C, qvga ? (1 << 5) : 0, 1 << 5);
@@ -3700,7 +3861,7 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
break;
case SEN_OV7610:
i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
- i2c_w(sd, 0x35, qvga?0x1e:0x9e);
+ i2c_w(sd, 0x35, qvga ? 0x1e : 0x9e);
i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
break;
@@ -3736,11 +3897,11 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
/* set COM7_FMT_VGA or COM7_FMT_QVGA
* do we need to set anything else?
* HSTART etc are set in set_ov_sensor_window itself */
- i2c_w_mask(sd, OV7670_REG_COM7,
+ i2c_w_mask(sd, OV7670_R12_COM7,
qvga ? OV7670_COM7_FMT_QVGA : OV7670_COM7_FMT_VGA,
OV7670_COM7_FMT_MASK);
i2c_w_mask(sd, 0x13, 0x00, 0x20); /* Select 16 bit data bus */
- i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_AWB,
+ i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_AWB,
OV7670_COM8_AWB);
if (qvga) { /* QVGA from ov7670.c by
* Jonathan Corbet */
@@ -3756,21 +3917,21 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
}
/* OV7670 hardware window registers are split across
* multiple locations */
- i2c_w(sd, OV7670_REG_HSTART, xstart >> 3);
- i2c_w(sd, OV7670_REG_HSTOP, xend >> 3);
- v = i2c_r(sd, OV7670_REG_HREF);
+ i2c_w(sd, OV7670_R17_HSTART, xstart >> 3);
+ i2c_w(sd, OV7670_R18_HSTOP, xend >> 3);
+ v = i2c_r(sd, OV7670_R32_HREF);
v = (v & 0xc0) | ((xend & 0x7) << 3) | (xstart & 0x07);
msleep(10); /* need to sleep between read and write to
* same reg! */
- i2c_w(sd, OV7670_REG_HREF, v);
+ i2c_w(sd, OV7670_R32_HREF, v);
- i2c_w(sd, OV7670_REG_VSTART, ystart >> 2);
- i2c_w(sd, OV7670_REG_VSTOP, yend >> 2);
- v = i2c_r(sd, OV7670_REG_VREF);
+ i2c_w(sd, OV7670_R19_VSTART, ystart >> 2);
+ i2c_w(sd, OV7670_R1A_VSTOP, yend >> 2);
+ v = i2c_r(sd, OV7670_R03_VREF);
v = (v & 0xc0) | ((yend & 0x3) << 2) | (ystart & 0x03);
msleep(10); /* need to sleep between read and write to
* same reg! */
- i2c_w(sd, OV7670_REG_VREF, v);
+ i2c_w(sd, OV7670_R03_VREF, v);
break;
case SEN_OV6620:
i2c_w_mask(sd, 0x14, qvga ? 0x20 : 0x00, 0x20);
@@ -3783,44 +3944,50 @@ static int mode_init_ov_sensor_regs(struct sd *sd)
i2c_w_mask(sd, 0x12, 0x04, 0x06); /* AWB: 1 Test pattern: 0 */
break;
default:
- return -EINVAL;
+ return;
}
/******** Clock programming ********/
i2c_w(sd, 0x11, sd->clockdiv);
-
- return 0;
}
-static void sethvflip(struct sd *sd)
+/* this function works for bridge ov519 and sensors ov7660 and ov7670 only */
+static void sethvflip(struct gspca_dev *gspca_dev)
{
- if (sd->sensor != SEN_OV7670)
- return;
+ struct sd *sd = (struct sd *) gspca_dev;
+
if (sd->gspca_dev.streaming)
- ov51x_stop(sd);
- i2c_w_mask(sd, OV7670_REG_MVFP,
- OV7670_MVFP_MIRROR * sd->hflip
- | OV7670_MVFP_VFLIP * sd->vflip,
+ reg_w(sd, OV519_R51_RESET1, 0x0f); /* block stream */
+ i2c_w_mask(sd, OV7670_R1E_MVFP,
+ OV7670_MVFP_MIRROR * sd->ctrls[HFLIP].val
+ | OV7670_MVFP_VFLIP * sd->ctrls[VFLIP].val,
OV7670_MVFP_MIRROR | OV7670_MVFP_VFLIP);
if (sd->gspca_dev.streaming)
- ov51x_restart(sd);
+ reg_w(sd, OV519_R51_RESET1, 0x00); /* restart stream */
}
-static int set_ov_sensor_window(struct sd *sd)
+static void set_ov_sensor_window(struct sd *sd)
{
struct gspca_dev *gspca_dev;
int qvga, crop;
int hwsbase, hwebase, vwsbase, vwebase, hwscale, vwscale;
- int ret;
/* mode setup is fully handled in mode_init_ov_sensor_regs for these */
- if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610 ||
- sd->sensor == SEN_OV7670)
- return mode_init_ov_sensor_regs(sd);
+ switch (sd->sensor) {
+ case SEN_OV2610:
+ case SEN_OV3610:
+ case SEN_OV7670:
+ mode_init_ov_sensor_regs(sd);
+ return;
+ case SEN_OV7660:
+ ov519_set_mode(sd);
+ ov519_set_fr(sd);
+ return;
+ }
gspca_dev = &sd->gspca_dev;
- qvga = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 1;
- crop = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv & 2;
+ qvga = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 1;
+ crop = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv & 2;
/* The different sensor ICs handle setting up of window differently.
* IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!! */
@@ -3867,7 +4034,7 @@ static int set_ov_sensor_window(struct sd *sd)
vwsbase = vwebase = 0x03;
break;
default:
- return -EINVAL;
+ return;
}
switch (sd->sensor) {
@@ -3902,23 +4069,18 @@ static int set_ov_sensor_window(struct sd *sd)
}
}
- ret = mode_init_ov_sensor_regs(sd);
- if (ret < 0)
- return ret;
+ mode_init_ov_sensor_regs(sd);
i2c_w(sd, 0x17, hwsbase);
i2c_w(sd, 0x18, hwebase + (sd->sensor_width >> hwscale));
i2c_w(sd, 0x19, vwsbase);
i2c_w(sd, 0x1a, vwebase + (sd->sensor_height >> vwscale));
-
- return 0;
}
/* -- start the camera -- */
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int ret = 0;
/* Default for most bridges, allow bridge_mode_init_regs to override */
sd->sensor_width = sd->gspca_dev.width;
@@ -3927,48 +4089,46 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->bridge) {
case BRIDGE_OV511:
case BRIDGE_OV511PLUS:
- ret = ov511_mode_init_regs(sd);
+ ov511_mode_init_regs(sd);
break;
case BRIDGE_OV518:
case BRIDGE_OV518PLUS:
- ret = ov518_mode_init_regs(sd);
+ ov518_mode_init_regs(sd);
break;
case BRIDGE_OV519:
- ret = ov519_mode_init_regs(sd);
+ ov519_mode_init_regs(sd);
break;
/* case BRIDGE_OVFX2: nothing to do */
case BRIDGE_W9968CF:
- ret = w9968cf_mode_init_regs(sd);
+ w9968cf_mode_init_regs(sd);
break;
}
- if (ret < 0)
- goto out;
- ret = set_ov_sensor_window(sd);
- if (ret < 0)
- goto out;
+ set_ov_sensor_window(sd);
- setcontrast(gspca_dev);
- setbrightness(gspca_dev);
- setcolors(gspca_dev);
- sethvflip(sd);
- setautobrightness(sd);
- setfreq(sd);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << CONTRAST)))
+ setcontrast(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << BRIGHTNESS)))
+ setbrightness(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << COLORS)))
+ setcolors(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & ((1 << HFLIP) | (1 << VFLIP))))
+ sethvflip(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << AUTOBRIGHT)))
+ setautobright(gspca_dev);
+ if (!(sd->gspca_dev.ctrl_dis & (1 << FREQ)))
+ setfreq_i(sd);
/* Force clear snapshot state in case the snapshot button was
pressed while we weren't streaming */
sd->snapshot_needs_reset = 1;
sd_reset_snapshot(gspca_dev);
- sd->snapshot_pressed = 0;
- ret = ov51x_restart(sd);
- if (ret < 0)
- goto out;
+ sd->first_frame = 3;
+
+ ov51x_restart(sd);
ov51x_led_control(sd, 1);
- return 0;
-out:
- PDEBUG(D_ERR, "camera start error:%d", ret);
- return ret;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -3983,8 +4143,21 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ if (!sd->gspca_dev.present)
+ return;
if (sd->bridge == BRIDGE_W9968CF)
w9968cf_stop0(sd);
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ /* If the last button state is pressed, release it now! */
+ if (sd->snapshot_pressed) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ sd->snapshot_pressed = 0;
+ }
+#endif
+ if (sd->bridge == BRIDGE_OV519)
+ reg_w(sd, OV519_R57_SNAPSHOT, 0x23);
}
static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
@@ -3992,7 +4165,7 @@ static void ov51x_handle_button(struct gspca_dev *gspca_dev, u8 state)
struct sd *sd = (struct sd *) gspca_dev;
if (sd->snapshot_pressed != state) {
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
input_report_key(gspca_dev->input_dev, KEY_CAMERA, state);
input_sync(gspca_dev->input_dev);
#endif
@@ -4153,13 +4326,23 @@ static void ovfx2_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+
/* A short read signals EOF */
if (len < OVFX2_BULK_SIZE) {
- gspca_frame_add(gspca_dev, LAST_PACKET, data, len);
+ /* If the frame is short, and it is one of the first ones
+ the sensor and bridge are still syncing, so drop it. */
+ if (sd->first_frame) {
+ sd->first_frame--;
+ if (gspca_dev->image_len <
+ sd->gspca_dev.width * sd->gspca_dev.height)
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+ }
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
- return;
}
- gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -4195,8 +4378,24 @@ static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int val;
+ static const struct ov_i2c_regvals brit_7660[][7] = {
+ {{0x0f, 0x6a}, {0x24, 0x40}, {0x25, 0x2b}, {0x26, 0x90},
+ {0x27, 0xe0}, {0x28, 0xe0}, {0x2c, 0xe0}},
+ {{0x0f, 0x6a}, {0x24, 0x50}, {0x25, 0x40}, {0x26, 0xa1},
+ {0x27, 0xc0}, {0x28, 0xc0}, {0x2c, 0xc0}},
+ {{0x0f, 0x6a}, {0x24, 0x68}, {0x25, 0x58}, {0x26, 0xc2},
+ {0x27, 0xa0}, {0x28, 0xa0}, {0x2c, 0xa0}},
+ {{0x0f, 0x6a}, {0x24, 0x70}, {0x25, 0x68}, {0x26, 0xd3},
+ {0x27, 0x80}, {0x28, 0x80}, {0x2c, 0x80}},
+ {{0x0f, 0x6a}, {0x24, 0x80}, {0x25, 0x70}, {0x26, 0xd3},
+ {0x27, 0x20}, {0x28, 0x20}, {0x2c, 0x20}},
+ {{0x0f, 0x6a}, {0x24, 0x88}, {0x25, 0x78}, {0x26, 0xd3},
+ {0x27, 0x40}, {0x28, 0x40}, {0x2c, 0x40}},
+ {{0x0f, 0x6a}, {0x24, 0x90}, {0x25, 0x80}, {0x26, 0xd4},
+ {0x27, 0x60}, {0x28, 0x60}, {0x2c, 0x60}}
+ };
- val = sd->brightness;
+ val = sd->ctrls[BRIGHTNESS].val;
switch (sd->sensor) {
case SEN_OV8610:
case SEN_OV7610:
@@ -4211,13 +4410,17 @@ static void setbrightness(struct gspca_dev *gspca_dev)
case SEN_OV7620:
case SEN_OV7620AE:
/* 7620 doesn't like manual changes when in auto mode */
- if (!sd->autobrightness)
+ if (!sd->ctrls[AUTOBRIGHT].val)
i2c_w(sd, OV7610_REG_BRT, val);
break;
+ case SEN_OV7660:
+ write_i2c_regvals(sd, brit_7660[val],
+ ARRAY_SIZE(brit_7660[0]));
+ break;
case SEN_OV7670:
/*win trace
- * i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_AEC); */
- i2c_w(sd, OV7670_REG_BRIGHT, ov7670_abs_to_sm(val));
+ * i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_AEC); */
+ i2c_w(sd, OV7670_R55_BRIGHT, ov7670_abs_to_sm(val));
break;
}
}
@@ -4226,8 +4429,66 @@ static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int val;
+ static const struct ov_i2c_regvals contrast_7660[][31] = {
+ {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0xa0},
+ {0x70, 0x58}, {0x71, 0x38}, {0x72, 0x30}, {0x73, 0x30},
+ {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x24}, {0x77, 0x24},
+ {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x34},
+ {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x65},
+ {0x80, 0x70}, {0x81, 0x77}, {0x82, 0x7d}, {0x83, 0x83},
+ {0x84, 0x88}, {0x85, 0x8d}, {0x86, 0x96}, {0x87, 0x9f},
+ {0x88, 0xb0}, {0x89, 0xc4}, {0x8a, 0xd9}},
+ {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf8}, {0x6f, 0x94},
+ {0x70, 0x58}, {0x71, 0x40}, {0x72, 0x30}, {0x73, 0x30},
+ {0x74, 0x30}, {0x75, 0x30}, {0x76, 0x2c}, {0x77, 0x24},
+ {0x78, 0x22}, {0x79, 0x28}, {0x7a, 0x2a}, {0x7b, 0x31},
+ {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3d}, {0x7f, 0x62},
+ {0x80, 0x6d}, {0x81, 0x75}, {0x82, 0x7b}, {0x83, 0x81},
+ {0x84, 0x87}, {0x85, 0x8d}, {0x86, 0x98}, {0x87, 0xa1},
+ {0x88, 0xb2}, {0x89, 0xc6}, {0x8a, 0xdb}},
+ {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x84},
+ {0x70, 0x58}, {0x71, 0x48}, {0x72, 0x40}, {0x73, 0x40},
+ {0x74, 0x28}, {0x75, 0x28}, {0x76, 0x28}, {0x77, 0x24},
+ {0x78, 0x26}, {0x79, 0x28}, {0x7a, 0x28}, {0x7b, 0x34},
+ {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x5d},
+ {0x80, 0x68}, {0x81, 0x71}, {0x82, 0x79}, {0x83, 0x81},
+ {0x84, 0x86}, {0x85, 0x8b}, {0x86, 0x95}, {0x87, 0x9e},
+ {0x88, 0xb1}, {0x89, 0xc5}, {0x8a, 0xd9}},
+ {{0x6c, 0xf0}, {0x6d, 0xf0}, {0x6e, 0xf0}, {0x6f, 0x70},
+ {0x70, 0x58}, {0x71, 0x58}, {0x72, 0x48}, {0x73, 0x48},
+ {0x74, 0x38}, {0x75, 0x40}, {0x76, 0x34}, {0x77, 0x34},
+ {0x78, 0x2e}, {0x79, 0x28}, {0x7a, 0x24}, {0x7b, 0x22},
+ {0x7c, 0x0f}, {0x7d, 0x1e}, {0x7e, 0x3c}, {0x7f, 0x58},
+ {0x80, 0x63}, {0x81, 0x6e}, {0x82, 0x77}, {0x83, 0x80},
+ {0x84, 0x87}, {0x85, 0x8f}, {0x86, 0x9c}, {0x87, 0xa9},
+ {0x88, 0xc0}, {0x89, 0xd4}, {0x8a, 0xe6}},
+ {{0x6c, 0xa0}, {0x6d, 0xf0}, {0x6e, 0x90}, {0x6f, 0x80},
+ {0x70, 0x70}, {0x71, 0x80}, {0x72, 0x60}, {0x73, 0x60},
+ {0x74, 0x58}, {0x75, 0x60}, {0x76, 0x4c}, {0x77, 0x38},
+ {0x78, 0x38}, {0x79, 0x2a}, {0x7a, 0x20}, {0x7b, 0x0e},
+ {0x7c, 0x0a}, {0x7d, 0x14}, {0x7e, 0x26}, {0x7f, 0x46},
+ {0x80, 0x54}, {0x81, 0x64}, {0x82, 0x70}, {0x83, 0x7c},
+ {0x84, 0x87}, {0x85, 0x93}, {0x86, 0xa6}, {0x87, 0xb4},
+ {0x88, 0xd0}, {0x89, 0xe5}, {0x8a, 0xf5}},
+ {{0x6c, 0x60}, {0x6d, 0x80}, {0x6e, 0x60}, {0x6f, 0x80},
+ {0x70, 0x80}, {0x71, 0x80}, {0x72, 0x88}, {0x73, 0x30},
+ {0x74, 0x70}, {0x75, 0x68}, {0x76, 0x64}, {0x77, 0x50},
+ {0x78, 0x3c}, {0x79, 0x22}, {0x7a, 0x10}, {0x7b, 0x08},
+ {0x7c, 0x06}, {0x7d, 0x0e}, {0x7e, 0x1a}, {0x7f, 0x3a},
+ {0x80, 0x4a}, {0x81, 0x5a}, {0x82, 0x6b}, {0x83, 0x7b},
+ {0x84, 0x89}, {0x85, 0x96}, {0x86, 0xaf}, {0x87, 0xc3},
+ {0x88, 0xe1}, {0x89, 0xf2}, {0x8a, 0xfa}},
+ {{0x6c, 0x20}, {0x6d, 0x40}, {0x6e, 0x20}, {0x6f, 0x60},
+ {0x70, 0x88}, {0x71, 0xc8}, {0x72, 0xc0}, {0x73, 0xb8},
+ {0x74, 0xa8}, {0x75, 0xb8}, {0x76, 0x80}, {0x77, 0x5c},
+ {0x78, 0x26}, {0x79, 0x10}, {0x7a, 0x08}, {0x7b, 0x04},
+ {0x7c, 0x02}, {0x7d, 0x06}, {0x7e, 0x0a}, {0x7f, 0x22},
+ {0x80, 0x33}, {0x81, 0x4c}, {0x82, 0x64}, {0x83, 0x7b},
+ {0x84, 0x90}, {0x85, 0xa7}, {0x86, 0xc7}, {0x87, 0xde},
+ {0x88, 0xf1}, {0x89, 0xf9}, {0x8a, 0xfd}},
+ };
- val = sd->contrast;
+ val = sd->ctrls[CONTRAST].val;
switch (sd->sensor) {
case SEN_OV7610:
case SEN_OV6620:
@@ -4238,7 +4499,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
i2c_w_mask(sd, OV7610_REG_CNT, val >> 4, 0x0f);
break;
case SEN_OV8610: {
- static const __u8 ctab[] = {
+ static const u8 ctab[] = {
0x03, 0x09, 0x0b, 0x0f, 0x53, 0x6f, 0x35, 0x7f
};
@@ -4248,7 +4509,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
}
case SEN_OV7620:
case SEN_OV7620AE: {
- static const __u8 ctab[] = {
+ static const u8 ctab[] = {
0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
};
@@ -4257,9 +4518,13 @@ static void setcontrast(struct gspca_dev *gspca_dev)
i2c_w(sd, 0x64, ctab[val >> 4]);
break;
}
+ case SEN_OV7660:
+ write_i2c_regvals(sd, contrast_7660[val],
+ ARRAY_SIZE(contrast_7660[0]));
+ break;
case SEN_OV7670:
/* check that this isn't just the same as ov7610 */
- i2c_w(sd, OV7670_REG_CONTRAS, val >> 1);
+ i2c_w(sd, OV7670_R56_CONTRAS, val >> 1);
break;
}
}
@@ -4268,8 +4533,20 @@ static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int val;
+ static const struct ov_i2c_regvals colors_7660[][6] = {
+ {{0x4f, 0x28}, {0x50, 0x2a}, {0x51, 0x02}, {0x52, 0x0a},
+ {0x53, 0x19}, {0x54, 0x23}},
+ {{0x4f, 0x47}, {0x50, 0x4a}, {0x51, 0x03}, {0x52, 0x11},
+ {0x53, 0x2c}, {0x54, 0x3e}},
+ {{0x4f, 0x66}, {0x50, 0x6b}, {0x51, 0x05}, {0x52, 0x19},
+ {0x53, 0x40}, {0x54, 0x59}},
+ {{0x4f, 0x84}, {0x50, 0x8b}, {0x51, 0x06}, {0x52, 0x20},
+ {0x53, 0x53}, {0x54, 0x73}},
+ {{0x4f, 0xa3}, {0x50, 0xab}, {0x51, 0x08}, {0x52, 0x28},
+ {0x53, 0x66}, {0x54, 0x8e}},
+ };
- val = sd->colors;
+ val = sd->ctrls[COLORS].val;
switch (sd->sensor) {
case SEN_OV8610:
case SEN_OV7610:
@@ -4291,6 +4568,10 @@ static void setcolors(struct gspca_dev *gspca_dev)
case SEN_OV7648:
i2c_w(sd, OV7610_REG_SAT, val & 0xf0);
break;
+ case SEN_OV7660:
+ write_i2c_regvals(sd, colors_7660[val],
+ ARRAY_SIZE(colors_7660[0]));
+ break;
case SEN_OV7670:
/* supported later once I work out how to do it
* transparently fail now! */
@@ -4299,45 +4580,40 @@ static void setcolors(struct gspca_dev *gspca_dev)
}
}
-static void setautobrightness(struct sd *sd)
+static void setautobright(struct gspca_dev *gspca_dev)
{
- if (sd->sensor == SEN_OV7640 || sd->sensor == SEN_OV7648 ||
- sd->sensor == SEN_OV7670 ||
- sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
- return;
+ struct sd *sd = (struct sd *) gspca_dev;
- i2c_w_mask(sd, 0x2d, sd->autobrightness ? 0x10 : 0x00, 0x10);
+ i2c_w_mask(sd, 0x2d, sd->ctrls[AUTOBRIGHT].val ? 0x10 : 0x00, 0x10);
}
-static void setfreq(struct sd *sd)
+static void setfreq_i(struct sd *sd)
{
- if (sd->sensor == SEN_OV2610 || sd->sensor == SEN_OV3610)
- return;
-
- if (sd->sensor == SEN_OV7670) {
- switch (sd->freq) {
+ if (sd->sensor == SEN_OV7660
+ || sd->sensor == SEN_OV7670) {
+ switch (sd->ctrls[FREQ].val) {
case 0: /* Banding filter disabled */
- i2c_w_mask(sd, OV7670_REG_COM8, 0, OV7670_COM8_BFILT);
+ i2c_w_mask(sd, OV7670_R13_COM8, 0, OV7670_COM8_BFILT);
break;
case 1: /* 50 hz */
- i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
- i2c_w_mask(sd, OV7670_REG_COM11, 0x08, 0x18);
+ i2c_w_mask(sd, OV7670_R3B_COM11, 0x08, 0x18);
break;
case 2: /* 60 hz */
- i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
- i2c_w_mask(sd, OV7670_REG_COM11, 0x00, 0x18);
+ i2c_w_mask(sd, OV7670_R3B_COM11, 0x00, 0x18);
break;
- case 3: /* Auto hz */
- i2c_w_mask(sd, OV7670_REG_COM8, OV7670_COM8_BFILT,
+ case 3: /* Auto hz - ov7670 only */
+ i2c_w_mask(sd, OV7670_R13_COM8, OV7670_COM8_BFILT,
OV7670_COM8_BFILT);
- i2c_w_mask(sd, OV7670_REG_COM11, OV7670_COM11_HZAUTO,
+ i2c_w_mask(sd, OV7670_R3B_COM11, OV7670_COM11_HZAUTO,
0x18);
break;
}
} else {
- switch (sd->freq) {
+ switch (sd->ctrls[FREQ].val) {
case 0: /* Banding filter disabled */
i2c_w_mask(sd, 0x2d, 0x00, 0x04);
i2c_w_mask(sd, 0x2a, 0x00, 0x80);
@@ -4369,135 +4645,15 @@ static void setfreq(struct sd *sd)
}
}
}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightness(gspca_dev);
- return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->brightness;
- return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->colors = val;
- if (gspca_dev->streaming)
- setcolors(gspca_dev);
- return 0;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
+static void setfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->colors;
- return 0;
-}
-
-static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
+ setfreq_i(sd);
- sd->hflip = val;
- if (gspca_dev->streaming)
- sethvflip(sd);
- return 0;
-}
-
-static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *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(sd);
- 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;
-}
-
-static int sd_setautobrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->autobrightness = val;
- if (gspca_dev->streaming)
- setautobrightness(sd);
- return 0;
-}
-
-static int sd_getautobrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autobrightness;
- return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->freq = val;
- if (gspca_dev->streaming) {
- setfreq(sd);
- /* Ugly but necessary */
- if (sd->bridge == BRIDGE_W9968CF)
- w9968cf_set_crop_window(sd);
- }
- return 0;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->freq;
- return 0;
+ /* Ugly but necessary */
+ if (sd->bridge == BRIDGE_W9968CF)
+ w9968cf_set_crop_window(sd);
}
static int sd_querymenu(struct gspca_dev *gspca_dev,
@@ -4583,27 +4739,27 @@ static const struct sd_desc sd_desc = {
.querymenu = sd_querymenu,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.other_input = 1,
#endif
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4003), .driver_info = BRIDGE_W9968CF },
{USB_DEVICE(0x041e, 0x4052), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x405f), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4060), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4061), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4064),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x041e, 0x4067), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x041e, 0x4068),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x045e, 0x028c), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x054c, 0x0154), .driver_info = BRIDGE_OV519 },
{USB_DEVICE(0x054c, 0x0155),
- .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
+ .driver_info = BRIDGE_OV519 | BRIDGE_INVERT_LED },
{USB_DEVICE(0x05a9, 0x0511), .driver_info = BRIDGE_OV511 },
{USB_DEVICE(0x05a9, 0x0518), .driver_info = BRIDGE_OV518 },
{USB_DEVICE(0x05a9, 0x0519), .driver_info = BRIDGE_OV519 },
@@ -4617,7 +4773,7 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0b62, 0x0059), .driver_info = BRIDGE_OVFX2 },
{USB_DEVICE(0x0e96, 0xc001), .driver_info = BRIDGE_OVFX2 },
{USB_DEVICE(0x1046, 0x9967), .driver_info = BRIDGE_W9968CF },
- {USB_DEVICE(0x8020, 0xEF04), .driver_info = BRIDGE_OVFX2 },
+ {USB_DEVICE(0x8020, 0xef04), .driver_info = BRIDGE_OVFX2 },
{}
};
@@ -4645,17 +4801,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/ov534.c b/drivers/media/video/gspca/ov534.c
index dc1e4efe30fb..04da22802736 100644
--- a/drivers/media/video/gspca/ov534.c
+++ b/drivers/media/video/gspca/ov534.c
@@ -479,15 +479,20 @@ static void ov534_reg_write(struct gspca_dev *gspca_dev, u16 reg, u8 val)
struct usb_device *udev = gspca_dev->dev;
int ret;
- PDEBUG(D_USBO, "reg=0x%04x, val=0%02x", reg, val);
+ if (gspca_dev->usb_err < 0)
+ return;
+
+ PDEBUG(D_USBO, "SET 01 0000 %04x %02x", reg, val);
gspca_dev->usb_buf[0] = val;
ret = usb_control_msg(udev,
usb_sndctrlpipe(udev, 0),
0x01,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
- if (ret < 0)
- PDEBUG(D_ERR, "write failed");
+ if (ret < 0) {
+ err("write failed %d", ret);
+ gspca_dev->usb_err = ret;
+ }
}
static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -495,14 +500,18 @@ static u8 ov534_reg_read(struct gspca_dev *gspca_dev, u16 reg)
struct usb_device *udev = gspca_dev->dev;
int ret;
+ if (gspca_dev->usb_err < 0)
+ return 0;
ret = usb_control_msg(udev,
usb_rcvctrlpipe(udev, 0),
0x01,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x00, 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");
+ PDEBUG(D_USBI, "GET 01 0000 %04x %02x", reg, gspca_dev->usb_buf[0]);
+ if (ret < 0) {
+ err("read failed %d", ret);
+ gspca_dev->usb_err = ret;
+ }
return gspca_dev->usb_buf[0];
}
@@ -558,13 +567,15 @@ static int sccb_check_status(struct gspca_dev *gspca_dev)
static void sccb_reg_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
{
- PDEBUG(D_USBO, "reg: 0x%02x, val: 0x%02x", reg, val);
+ PDEBUG(D_USBO, "sccb write: %02x %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(gspca_dev))
- PDEBUG(D_ERR, "sccb_reg_write failed");
+ if (!sccb_check_status(gspca_dev)) {
+ err("sccb_reg_write failed");
+ gspca_dev->usb_err = -EIO;
+ }
}
static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -572,11 +583,11 @@ static u8 sccb_reg_read(struct gspca_dev *gspca_dev, u16 reg)
ov534_reg_write(gspca_dev, OV534_REG_SUBADDR, reg);
ov534_reg_write(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
if (!sccb_check_status(gspca_dev))
- PDEBUG(D_ERR, "sccb_reg_read failed 1");
+ 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");
+ err("sccb_reg_read failed 2");
return ov534_reg_read(gspca_dev, OV534_REG_READ);
}
@@ -885,7 +896,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
ov534_set_led(gspca_dev, 0);
set_frame_rate(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_start(struct gspca_dev *gspca_dev)
@@ -920,7 +931,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
ov534_set_led(gspca_dev, 1);
ov534_reg_write(gspca_dev, 0xe0, 0x00);
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -987,13 +998,8 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data + 12, len - 12);
/* If this packet is marked as EOF, end the frame */
} else if (data[1] & UVC_STREAM_EOF) {
- struct gspca_frame *frame;
-
sd->last_pts = 0;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL)
- goto discard;
- if (frame->data_end - frame->data + (len - 12) !=
+ if (gspca_dev->image_len + len - 12 !=
gspca_dev->width * gspca_dev->height * 2) {
PDEBUG(D_PACK, "wrong sized frame");
goto discard;
@@ -1248,34 +1254,26 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
}
/* get stream parameters (framerate) */
-static int sd_get_streamparm(struct gspca_dev *gspca_dev,
+static void 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,
+static void 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;
if (gspca_dev->streaming)
@@ -1284,8 +1282,6 @@ static int sd_set_streamparm(struct gspca_dev *gspca_dev,
/* Return the actual framerate */
tpf->numerator = 1;
tpf->denominator = sd->frame_rate;
-
- return 0;
}
/* sub-driver description */
@@ -1304,7 +1300,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x1415, 0x2000)},
{}
};
@@ -1332,19 +1328,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/ov534_9.c b/drivers/media/video/gspca/ov534_9.c
index bbe5a030e3b4..aaf5428c57f5 100644
--- a/drivers/media/video/gspca/ov534_9.c
+++ b/drivers/media/video/gspca/ov534_9.c
@@ -785,7 +785,7 @@ static void reg_w_i(struct gspca_dev *gspca_dev, u16 reg, u8 val)
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w failed %d", ret);
+ err("reg_w failed %d", ret);
gspca_dev->usb_err = ret;
}
}
@@ -810,7 +810,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev, u16 reg)
0x00, reg, gspca_dev->usb_buf, 1, CTRL_TIMEOUT);
PDEBUG(D_USBI, "reg_r [%04x] -> %02x", reg, gspca_dev->usb_buf[0]);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_r err %d", ret);
+ err("reg_r err %d", ret);
gspca_dev->usb_err = ret;
}
return gspca_dev->usb_buf[0];
@@ -848,7 +848,7 @@ static void sccb_write(struct gspca_dev *gspca_dev, u8 reg, u8 val)
reg_w_i(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_3);
if (!sccb_check_status(gspca_dev))
- PDEBUG(D_ERR, "sccb_write failed");
+ err("sccb_write failed");
}
static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg)
@@ -856,11 +856,11 @@ static u8 sccb_read(struct gspca_dev *gspca_dev, u16 reg)
reg_w(gspca_dev, OV534_REG_SUBADDR, reg);
reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_WRITE_2);
if (!sccb_check_status(gspca_dev))
- PDEBUG(D_ERR, "sccb_read failed 1");
+ err("sccb_read failed 1");
reg_w(gspca_dev, OV534_REG_OPERATION, OV534_OP_READ_2);
if (!sccb_check_status(gspca_dev))
- PDEBUG(D_ERR, "sccb_read failed 2");
+ err("sccb_read failed 2");
return reg_r(gspca_dev, OV534_REG_READ);
}
@@ -945,7 +945,6 @@ static void setautogain(struct gspca_dev *gspca_dev)
u8 val;
/*fixme: should adjust agc/awb/aec by different controls */
- val = sd->autogain;
val = sccb_read(gspca_dev, 0x13); /* com8 */
sccb_write(gspca_dev, 0xff, 0x00);
if (sd->autogain)
@@ -1430,7 +1429,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x06f8, 0x3003)},
{}
};
@@ -1458,19 +1457,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/pac207.c b/drivers/media/video/gspca/pac207.c
index a40f8893310d..81739a2f205e 100644
--- a/drivers/media/video/gspca/pac207.c
+++ b/drivers/media/video/gspca/pac207.c
@@ -1,7 +1,7 @@
/*
* Pixart PAC207BCA library
*
- * Copyright (C) 2008 Hans de Goede <hdgoede@redhat.com>
+ * Copyright (C) 2008 Hans de Goede <hdegoede@redhat.com>
* Copyright (C) 2005 Thomas Kaiser thomas@kaiser-linux.li
* Copyleft (C) 2005 Michel Xhaard mxhaard@magic.fr
*
@@ -28,7 +28,7 @@
#include <linux/input.h>
#include "gspca.h"
-MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("Pixart PAC207");
MODULE_LICENSE("GPL");
@@ -45,7 +45,7 @@ MODULE_LICENSE("GPL");
#define PAC207_GAIN_MIN 0
#define PAC207_GAIN_MAX 31
-#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
+#define PAC207_GAIN_DEFAULT 9 /* power on default: 9 */
#define PAC207_GAIN_KNEE 31
#define PAC207_AUTOGAIN_DEADZONE 30
@@ -162,7 +162,7 @@ static const __u8 pac207_sensor_init[][8] = {
{0x10, 0x12, 0x0d, 0x12, 0x0c, 0x01, 0x29, 0x84},
{0x49, 0x64, 0x64, 0x64, 0x04, 0x10, 0xf0, 0x30},
{0x00, 0x00, 0x00, 0x70, 0xa0, 0xf8, 0x00, 0x00},
- {0x32, 0x00, 0x96, 0x00, 0xA2, 0x02, 0xaf, 0x00},
+ {0x32, 0x00, 0x96, 0x00, 0xa2, 0x02, 0xaf, 0x00},
};
static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
@@ -178,8 +178,7 @@ static int pac207_write_regs(struct gspca_dev *gspca_dev, u16 index,
0x00, index,
gspca_dev->usb_buf, length, PAC207_CTRL_TIMEOUT);
if (err < 0)
- PDEBUG(D_ERR,
- "Failed to write registers to index 0x%04X, error %d)",
+ err("Failed to write registers to index 0x%04X, error %d)",
index, err);
return err;
@@ -195,7 +194,7 @@ static int pac207_write_reg(struct gspca_dev *gspca_dev, u16 index, u16 value)
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
value, index, NULL, 0, PAC207_CTRL_TIMEOUT);
if (err)
- PDEBUG(D_ERR, "Failed to write a register (index 0x%04X,"
+ err("Failed to write a register (index 0x%04X,"
" value 0x%02X, error %d)", index, value, err);
return err;
@@ -211,8 +210,7 @@ static int pac207_read_reg(struct gspca_dev *gspca_dev, u16 index)
0x00, index,
gspca_dev->usb_buf, 1, PAC207_CTRL_TIMEOUT);
if (res < 0) {
- PDEBUG(D_ERR,
- "Failed to read a register (index 0x%04X, error %d)",
+ err("Failed to read a register (index 0x%04X, error %d)",
index, res);
return res;
}
@@ -230,7 +228,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
idreg[0] = pac207_read_reg(gspca_dev, 0x0000);
idreg[1] = pac207_read_reg(gspca_dev, 0x0001);
- idreg[0] = ((idreg[0] & 0x0F) << 4) | ((idreg[1] & 0xf0) >> 4);
+ idreg[0] = ((idreg[0] & 0x0f) << 4) | ((idreg[1] & 0xf0) >> 4);
idreg[1] = idreg[1] & 0x0f;
PDEBUG(D_PROBE, "Pixart Sensor ID 0x%02X Chips ID 0x%02X",
idreg[0], idreg[1]);
@@ -496,7 +494,7 @@ static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrput packet length */
@@ -526,13 +524,13 @@ static const struct sd_desc sd_desc = {
.stopN = sd_stopN,
.dq_callback = pac207_do_auto_gain,
.pkt_scan = sd_pkt_scan,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4028)},
{USB_DEVICE(0x093a, 0x2460)},
{USB_DEVICE(0x093a, 0x2461)},
@@ -572,17 +570,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/pac7302.c b/drivers/media/video/gspca/pac7302.c
index 2a68220d1ada..5615d7bd8304 100644
--- a/drivers/media/video/gspca/pac7302.c
+++ b/drivers/media/video/gspca/pac7302.c
@@ -393,7 +393,7 @@ static const __u8 page3_7302[] = {
static void reg_w_buf(struct gspca_dev *gspca_dev,
__u8 index,
- const char *buffer, int len)
+ const u8 *buffer, int len)
{
int ret;
@@ -402,15 +402,14 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
memcpy(gspca_dev->usb_buf, buffer, len);
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
- 1, /* request */
+ 0, /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, /* value */
index, gspca_dev->usb_buf, len,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w_buf(): "
- "Failed to write registers to index 0x%x, error %i",
- index, ret);
+ err("reg_w_buf failed index 0x%02x, error %d",
+ index, ret);
gspca_dev->usb_err = ret;
}
}
@@ -432,9 +431,8 @@ static void reg_w(struct gspca_dev *gspca_dev,
0, index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w(): "
- "Failed to write register to index 0x%x, value 0x%x, error %i",
- index, value, ret);
+ err("reg_w() failed index 0x%02x, value 0x%02x, error %d",
+ index, value, ret);
gspca_dev->usb_err = ret;
}
}
@@ -468,10 +466,9 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
0, index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w_page(): "
- "Failed to write register to index 0x%x, "
- "value 0x%x, error %i",
- index, page[index], ret);
+ err("reg_w_page() failed index 0x%02x, "
+ "value 0x%02x, error %d",
+ index, page[index], ret);
gspca_dev->usb_err = ret;
break;
}
@@ -804,7 +801,6 @@ static const unsigned char pac_jpeg_header2[] = {
};
static void pac_start_frame(struct gspca_dev *gspca_dev,
- struct gspca_frame *frame,
__u16 lines, __u16 samples_per_line)
{
unsigned char tmpbuf[4];
@@ -829,19 +825,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
- struct gspca_frame *frame;
+ u8 *image;
unsigned char *sof;
sof = pac_find_sof(&sd->sof_read, data, len);
if (sof) {
int n, lum_offset, footer_length;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
/* 6 bytes after the FF D9 EOF marker a number of lumination
bytes are send corresponding to different parts of the
image, the 14th and 15th byte after the EOF seem to
@@ -852,16 +842,17 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Finish decoding current frame */
n = (sof - data) - (footer_length + sizeof pac_sof_marker);
if (n < 0) {
- frame->data_end += n;
+ gspca_dev->image_len += n;
n = 0;
+ } else {
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
}
- gspca_frame_add(gspca_dev, INTER_PACKET,
- data, n);
- if (gspca_dev->last_packet_type != DISCARD_PACKET &&
- frame->data_end[-2] == 0xff &&
- frame->data_end[-1] == 0xd9)
- gspca_frame_add(gspca_dev, LAST_PACKET,
- NULL, 0);
+
+ image = gspca_dev->image;
+ if (image != NULL
+ && image[gspca_dev->image_len - 2] == 0xff
+ && image[gspca_dev->image_len - 1] == 0xd9)
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
n = sof - data;
len -= n;
@@ -877,7 +868,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Start the new frame with the jpeg header */
/* The PAC7302 has the image rotated 90 degrees */
- pac_start_frame(gspca_dev, frame,
+ pac_start_frame(gspca_dev,
gspca_dev->width, gspca_dev->height);
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
@@ -906,9 +897,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) {
+ if (gspca_dev->streaming)
setbrightcont(gspca_dev);
- }
return gspca_dev->usb_err;
}
@@ -1141,7 +1131,7 @@ static int sd_chip_ident(struct gspca_dev *gspca_dev,
}
#endif
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrput packet length */
@@ -1188,18 +1178,19 @@ static const struct sd_desc sd_desc = {
.set_register = sd_dbg_s_register,
.get_chip_ident = sd_chip_ident,
#endif
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
/* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x06f8, 0x3009)},
{USB_DEVICE(0x093a, 0x2620)},
{USB_DEVICE(0x093a, 0x2621)},
{USB_DEVICE(0x093a, 0x2622), .driver_info = FL_VFLIP},
{USB_DEVICE(0x093a, 0x2624), .driver_info = FL_VFLIP},
+ {USB_DEVICE(0x093a, 0x2625)},
{USB_DEVICE(0x093a, 0x2626)},
{USB_DEVICE(0x093a, 0x2628)},
{USB_DEVICE(0x093a, 0x2629), .driver_info = FL_VFLIP},
@@ -1210,7 +1201,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
@@ -1231,17 +1222,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/pac7311.c b/drivers/media/video/gspca/pac7311.c
index 44fed9686729..f8801b50e64f 100644
--- a/drivers/media/video/gspca/pac7311.c
+++ b/drivers/media/video/gspca/pac7311.c
@@ -261,7 +261,7 @@ static const __u8 page4_7311[] = {
static void reg_w_buf(struct gspca_dev *gspca_dev,
__u8 index,
- const char *buffer, int len)
+ const u8 *buffer, int len)
{
int ret;
@@ -270,15 +270,14 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
memcpy(gspca_dev->usb_buf, buffer, len);
ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
- 1, /* request */
+ 0, /* request */
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, /* value */
index, gspca_dev->usb_buf, len,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w_buf(): "
- "Failed to write registers to index 0x%x, error %i",
- index, ret);
+ err("reg_w_buf() failed index 0x%02x, error %d",
+ index, ret);
gspca_dev->usb_err = ret;
}
}
@@ -300,9 +299,8 @@ static void reg_w(struct gspca_dev *gspca_dev,
0, index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w(): "
- "Failed to write register to index 0x%x, value 0x%x, error %i",
- index, value, ret);
+ err("reg_w() failed index 0x%02x, value 0x%02x, error %d",
+ index, value, ret);
gspca_dev->usb_err = ret;
}
}
@@ -336,10 +334,9 @@ static void reg_w_page(struct gspca_dev *gspca_dev,
0, index, gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w_page(): "
- "Failed to write register to index 0x%x, "
- "value 0x%x, error %i",
- index, page[index], ret);
+ err("reg_w_page() failed index 0x%02x, "
+ "value 0x%02x, error %d",
+ index, page[index], ret);
gspca_dev->usb_err = ret;
break;
}
@@ -599,7 +596,6 @@ static const unsigned char pac_jpeg_header2[] = {
};
static void pac_start_frame(struct gspca_dev *gspca_dev,
- struct gspca_frame *frame,
__u16 lines, __u16 samples_per_line)
{
unsigned char tmpbuf[4];
@@ -624,19 +620,13 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
int len) /* iso packet length */
{
struct sd *sd = (struct sd *) gspca_dev;
+ u8 *image;
unsigned char *sof;
- struct gspca_frame *frame;
sof = pac_find_sof(&sd->sof_read, data, len);
if (sof) {
int n, lum_offset, footer_length;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
-
/* 6 bytes after the FF D9 EOF marker a number of lumination
bytes are send corresponding to different parts of the
image, the 14th and 15th byte after the EOF seem to
@@ -647,16 +637,16 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* Finish decoding current frame */
n = (sof - data) - (footer_length + sizeof pac_sof_marker);
if (n < 0) {
- frame->data_end += n;
+ gspca_dev->image_len += n;
n = 0;
+ } else {
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, n);
}
- gspca_frame_add(gspca_dev, INTER_PACKET,
- data, n);
- if (gspca_dev->last_packet_type != DISCARD_PACKET &&
- frame->data_end[-2] == 0xff &&
- frame->data_end[-1] == 0xd9)
- gspca_frame_add(gspca_dev, LAST_PACKET,
- NULL, 0);
+ image = gspca_dev->image;
+ if (image != NULL
+ && image[gspca_dev->image_len - 2] == 0xff
+ && image[gspca_dev->image_len - 1] == 0xd9)
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
n = sof - data;
len -= n;
@@ -671,7 +661,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
atomic_set(&sd->avg_lum, -1);
/* Start the new frame with the jpeg header */
- pac_start_frame(gspca_dev, frame,
+ pac_start_frame(gspca_dev,
gspca_dev->height, gspca_dev->width);
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
@@ -682,9 +672,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) {
+ if (gspca_dev->streaming)
setcontrast(gspca_dev);
- }
return gspca_dev->usb_err;
}
@@ -799,7 +788,7 @@ static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrupt packet length */
@@ -842,13 +831,13 @@ static const struct sd_desc sd_desc = {
.stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
/* -- module initialisation -- */
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x093a, 0x2600)},
{USB_DEVICE(0x093a, 0x2601)},
{USB_DEVICE(0x093a, 0x2603)},
@@ -860,7 +849,7 @@ static const struct usb_device_id device_table[] __devinitconst = {
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
@@ -881,17 +870,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/sn9c2028.c b/drivers/media/video/gspca/sn9c2028.c
index 71d9447a7986..4271f86dfe01 100644
--- a/drivers/media/video/gspca/sn9c2028.c
+++ b/drivers/media/video/gspca/sn9c2028.c
@@ -75,7 +75,7 @@ static int sn9c2028_command(struct gspca_dev *gspca_dev, u8 *command)
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
2, 0, gspca_dev->usb_buf, 6, 500);
if (rc < 0) {
- PDEBUG(D_ERR, "command write [%02x] error %d",
+ err("command write [%02x] error %d",
gspca_dev->usb_buf[0], rc);
return rc;
}
@@ -93,7 +93,7 @@ static int sn9c2028_read1(struct gspca_dev *gspca_dev)
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
1, 0, gspca_dev->usb_buf, 1, 500);
if (rc != 1) {
- PDEBUG(D_ERR, "read1 error %d", rc);
+ err("read1 error %d", rc);
return (rc < 0) ? rc : -EIO;
}
PDEBUG(D_USBI, "read1 response %02x", gspca_dev->usb_buf[0]);
@@ -109,7 +109,7 @@ static int sn9c2028_read4(struct gspca_dev *gspca_dev, u8 *reading)
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
4, 0, gspca_dev->usb_buf, 4, 500);
if (rc != 4) {
- PDEBUG(D_ERR, "read4 error %d", rc);
+ err("read4 error %d", rc);
return (rc < 0) ? rc : -EIO;
}
memcpy(reading, gspca_dev->usb_buf, 4);
@@ -131,7 +131,7 @@ static int sn9c2028_long_command(struct gspca_dev *gspca_dev, u8 *command)
for (i = 0; i < 256 && status < 2; i++)
status = sn9c2028_read1(gspca_dev);
if (status != 2) {
- PDEBUG(D_ERR, "long command status read error %d", status);
+ err("long command status read error %d", status);
return (status < 0) ? status : -EIO;
}
@@ -638,7 +638,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
err_code = start_vivitar_cam(gspca_dev);
break;
default:
- PDEBUG(D_ERR, "Starting unknown camera, please report this");
+ err("Starting unknown camera, please report this");
return -ENXIO;
}
@@ -703,7 +703,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0458, 0x7005)}, /* Genius Smart 300, version 2 */
/* The Genius Smart is untested. I can't find an owner ! */
/* {USB_DEVICE(0x0c45, 0x8000)}, DC31VC, Don't know this camera */
@@ -738,19 +738,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/sn9c20x.c b/drivers/media/video/gspca/sn9c20x.c
index 644a7fd4701a..fcf29897b713 100644
--- a/drivers/media/video/gspca/sn9c20x.c
+++ b/drivers/media/video/gspca/sn9c20x.c
@@ -18,10 +18,7 @@
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
-#ifdef CONFIG_INPUT
#include <linux/input.h>
-#include <linux/slab.h>
-#endif
#include "gspca.h"
#include "jpeg.h"
@@ -36,6 +33,14 @@ MODULE_LICENSE("GPL");
#define MODULE_NAME "sn9c20x"
+/*
+ * Pixel format private data
+ */
+#define SCALE_MASK 0x0f
+#define SCALE_160x120 0
+#define SCALE_320x240 1
+#define SCALE_640x480 2
+#define SCALE_1280x1024 3
#define MODE_RAW 0x10
#define MODE_JPEG 0x20
#define MODE_SXGA 0x80
@@ -89,7 +94,7 @@ struct sd {
u8 hstart;
u8 vstart;
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
u8 quality;
u8 flags;
@@ -348,103 +353,126 @@ static const struct ctrl sd_ctrls[] = {
static const struct v4l2_pix_format vga_mode[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 240,
- .sizeimage = 240 * 120,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 4 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0 | MODE_JPEG},
+ .priv = SCALE_160x120 | MODE_JPEG},
{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0 | MODE_RAW},
+ .priv = SCALE_160x120 | MODE_RAW},
{160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
- .bytesperline = 240,
+ .bytesperline = 160,
.sizeimage = 240 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
+ .priv = SCALE_160x120},
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 480,
- .sizeimage = 480 * 240 ,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 1 | MODE_JPEG},
+ .priv = SCALE_320x240 | MODE_JPEG},
{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 ,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1 | MODE_RAW},
+ .priv = SCALE_320x240 | MODE_RAW},
{320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
- .bytesperline = 480,
+ .bytesperline = 320,
.sizeimage = 480 * 240 ,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
+ .priv = SCALE_320x240},
{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 960,
- .sizeimage = 960 * 480,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 2 | MODE_JPEG},
+ .priv = SCALE_640x480 | MODE_JPEG},
{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2 | MODE_RAW},
+ .priv = SCALE_640x480 | MODE_RAW},
{640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
- .bytesperline = 960,
+ .bytesperline = 640,
.sizeimage = 960 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2},
+ .priv = SCALE_640x480},
};
static const struct v4l2_pix_format sxga_mode[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 240,
- .sizeimage = 240 * 120,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 4 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 0 | MODE_JPEG},
+ .priv = SCALE_160x120 | MODE_JPEG},
{160, 120, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 160,
.sizeimage = 160 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0 | MODE_RAW},
+ .priv = SCALE_160x120 | MODE_RAW},
{160, 120, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
- .bytesperline = 240,
+ .bytesperline = 160,
.sizeimage = 240 * 120,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 0},
+ .priv = SCALE_160x120},
{320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 480,
- .sizeimage = 480 * 240 ,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 1 | MODE_JPEG},
+ .priv = SCALE_320x240 | MODE_JPEG},
{320, 240, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 320,
.sizeimage = 320 * 240 ,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1 | MODE_RAW},
+ .priv = SCALE_320x240 | MODE_RAW},
{320, 240, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
- .bytesperline = 480,
+ .bytesperline = 320,
.sizeimage = 480 * 240 ,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 1},
+ .priv = SCALE_320x240},
{640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
- .bytesperline = 960,
- .sizeimage = 960 * 480,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
.colorspace = V4L2_COLORSPACE_JPEG,
- .priv = 2 | MODE_JPEG},
+ .priv = SCALE_640x480 | MODE_JPEG},
{640, 480, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 640,
.sizeimage = 640 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2 | MODE_RAW},
+ .priv = SCALE_640x480 | MODE_RAW},
{640, 480, V4L2_PIX_FMT_SN9C20X_I420, V4L2_FIELD_NONE,
- .bytesperline = 960,
+ .bytesperline = 640,
.sizeimage = 960 * 480,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 2},
+ .priv = SCALE_640x480},
{1280, 1024, V4L2_PIX_FMT_SBGGR8, V4L2_FIELD_NONE,
.bytesperline = 1280,
- .sizeimage = (1280 * 1024) + 64,
+ .sizeimage = 1280 * 1024,
.colorspace = V4L2_COLORSPACE_SRGB,
- .priv = 3 | MODE_RAW | MODE_SXGA},
+ .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
+};
+
+static const struct v4l2_pix_format mono_mode[] = {
+ {160, 120, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = SCALE_160x120 | MODE_RAW},
+ {320, 240, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 ,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = SCALE_320x240 | MODE_RAW},
+ {640, 480, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = SCALE_640x480 | MODE_RAW},
+ {1280, 1024, V4L2_PIX_FMT_GREY, V4L2_FIELD_NONE,
+ .bytesperline = 1280,
+ .sizeimage = 1280 * 1024,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = SCALE_1280x1024 | MODE_RAW | MODE_SXGA},
};
static const s16 hsv_red_x[] = {
@@ -1032,16 +1060,19 @@ static struct i2c_reg_u16 mt9v011_init[] = {
};
static struct i2c_reg_u16 mt9m001_init[] = {
- {0x0d, 0x0001}, {0x0d, 0x0000}, {0x01, 0x000e},
- {0x02, 0x0014}, {0x03, 0x03c1}, {0x04, 0x0501},
- {0x05, 0x0083}, {0x06, 0x0006}, {0x0d, 0x0002},
- {0x0a, 0x0000}, {0x0c, 0x0000}, {0x11, 0x0000},
- {0x1e, 0x8000}, {0x5f, 0x8904}, {0x60, 0x0000},
- {0x61, 0x0000}, {0x62, 0x0498}, {0x63, 0x0000},
- {0x64, 0x0000}, {0x20, 0x111d}, {0x06, 0x00f2},
- {0x05, 0x0013}, {0x09, 0x10f2}, {0x07, 0x0003},
- {0x2b, 0x002a}, {0x2d, 0x002a}, {0x2c, 0x002a},
- {0x2e, 0x0029}, {0x07, 0x0002},
+ {0x0d, 0x0001},
+ {0x0d, 0x0000},
+ {0x04, 0x0500}, /* hres = 1280 */
+ {0x03, 0x0400}, /* vres = 1024 */
+ {0x20, 0x1100},
+ {0x06, 0x0010},
+ {0x2b, 0x0024},
+ {0x2e, 0x0024},
+ {0x35, 0x0024},
+ {0x2d, 0x0020},
+ {0x2c, 0x0020},
+ {0x09, 0x0ad4},
+ {0x35, 0x0057},
};
static struct i2c_reg_u16 mt9m111_init[] = {
@@ -1227,8 +1258,17 @@ static int i2c_r2(struct gspca_dev *gspca_dev, u8 reg, u16 *val)
static int ov9650_init_sensor(struct gspca_dev *gspca_dev)
{
int i;
+ u16 id;
struct sd *sd = (struct sd *) gspca_dev;
+ if (i2c_r2(gspca_dev, 0x1c, &id) < 0)
+ return -EINVAL;
+
+ if (id != 0x7fa2) {
+ err("sensor id for ov9650 doesn't match (0x%04x)", id);
+ return -ENODEV;
+ }
+
for (i = 0; i < ARRAY_SIZE(ov9650_init); i++) {
if (i2c_w1(gspca_dev, ov9650_init[i].reg,
ov9650_init[i].val) < 0) {
@@ -1273,7 +1313,8 @@ static int soi968_init_sensor(struct gspca_dev *gspca_dev)
}
}
/* disable hflip and vflip */
- gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << EXPOSURE_IDX);
+ gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX)
+ | (1 << EXPOSURE_IDX);
sd->hstart = 60;
sd->vstart = 11;
return 0;
@@ -1352,7 +1393,9 @@ static int mt9v_init_sensor(struct gspca_dev *gspca_dev)
return -ENODEV;
}
}
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
+ gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX)
+ | (1 << GAIN_IDX);
sd->hstart = 2;
sd->vstart = 2;
sd->sensor = SENSOR_MT9V111;
@@ -1396,7 +1439,8 @@ static int mt9m112_init_sensor(struct gspca_dev *gspca_dev)
return -ENODEV;
}
}
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
+ gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
+ | (1 << GAIN_IDX);
sd->hstart = 0;
sd->vstart = 2;
return 0;
@@ -1413,7 +1457,8 @@ static int mt9m111_init_sensor(struct gspca_dev *gspca_dev)
return -ENODEV;
}
}
- gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX) | (1 << GAIN_IDX);
+ gspca_dev->ctrl_dis = (1 << EXPOSURE_IDX) | (1 << AUTOGAIN_IDX)
+ | (1 << GAIN_IDX);
sd->hstart = 0;
sd->vstart = 2;
return 0;
@@ -1423,6 +1468,25 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
+ u16 id;
+
+ if (i2c_r2(gspca_dev, 0x00, &id) < 0)
+ return -EINVAL;
+
+ /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
+ switch (id) {
+ case 0x8411:
+ case 0x8421:
+ info("MT9M001 color sensor detected");
+ break;
+ case 0x8431:
+ info("MT9M001 mono sensor detected");
+ break;
+ default:
+ err("No MT9M001 chip detected, ID = %x\n", id);
+ return -ENODEV;
+ }
+
for (i = 0; i < ARRAY_SIZE(mt9m001_init); i++) {
if (i2c_w2(gspca_dev, mt9m001_init[i].reg,
mt9m001_init[i].val) < 0) {
@@ -1432,8 +1496,8 @@ static int mt9m001_init_sensor(struct gspca_dev *gspca_dev)
}
/* disable hflip and vflip */
gspca_dev->ctrl_dis = (1 << HFLIP_IDX) | (1 << VFLIP_IDX);
- sd->hstart = 2;
- sd->vstart = 2;
+ sd->hstart = 1;
+ sd->vstart = 1;
return 0;
}
@@ -1975,6 +2039,10 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = sxga_mode;
cam->nmodes = ARRAY_SIZE(sxga_mode);
break;
+ case SENSOR_MT9M001:
+ cam->cam_mode = mono_mode;
+ cam->nmodes = ARRAY_SIZE(mono_mode);
+ break;
default:
cam->cam_mode = vga_mode;
cam->nmodes = ARRAY_SIZE(vga_mode);
@@ -2073,7 +2141,6 @@ static int sd_init(struct gspca_dev *gspca_dev)
case SENSOR_MT9M001:
if (mt9m001_init_sensor(gspca_dev) < 0)
return -ENODEV;
- info("MT9M001 sensor detected");
break;
case SENSOR_HV7131R:
if (hv7131r_init_sensor(gspca_dev) < 0)
@@ -2162,10 +2229,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int height = gspca_dev->height;
u8 fmt, scale = 0;
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (sd->jpeg_hdr == NULL)
- return -ENOMEM;
-
jpeg_define(sd->jpeg_hdr, height, width,
0x21);
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -2175,30 +2238,30 @@ static int sd_start(struct gspca_dev *gspca_dev)
else if (mode & MODE_JPEG)
fmt = 0x2c;
else
- fmt = 0x2f;
+ fmt = 0x2f; /* YUV 420 */
- switch (mode & 0x0f) {
- case 3:
+ switch (mode & SCALE_MASK) {
+ case SCALE_1280x1024:
scale = 0xc0;
info("Set 1280x1024");
break;
- case 2:
+ case SCALE_640x480:
scale = 0x80;
info("Set 640x480");
break;
- case 1:
+ case SCALE_320x240:
scale = 0x90;
info("Set 320x240");
break;
- case 0:
+ case SCALE_160x120:
scale = 0xa0;
info("Set 160x120");
break;
}
configure_sensor_output(gspca_dev, mode);
- reg_w(gspca_dev, 0x1100, sd->jpeg_hdr + JPEG_QT0_OFFSET, 64);
- reg_w(gspca_dev, 0x1140, sd->jpeg_hdr + JPEG_QT1_OFFSET, 64);
+ reg_w(gspca_dev, 0x1100, &sd->jpeg_hdr[JPEG_QT0_OFFSET], 64);
+ reg_w(gspca_dev, 0x1140, &sd->jpeg_hdr[JPEG_QT1_OFFSET], 64);
reg_w(gspca_dev, 0x10fb, CLR_WIN(width, height), 5);
reg_w(gspca_dev, 0x1180, HW_WIN(mode, sd->hstart, sd->vstart), 6);
reg_w1(gspca_dev, 0x1189, scale);
@@ -2226,12 +2289,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x1061, gspca_dev->usb_buf[0] & ~0x02);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- kfree(sd->jpeg_hdr);
-}
-
static void do_autoexposure(struct gspca_dev *gspca_dev, u16 avg_lum)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -2315,7 +2372,7 @@ static void sd_dqcallback(struct gspca_dev *gspca_dev)
do_autoexposure(gspca_dev, avg_lum);
}
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet */
int len) /* interrupt packet length */
@@ -2368,8 +2425,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
(data[33] << 10);
avg_lum >>= 9;
atomic_set(&sd->avg_lum, avg_lum);
- gspca_frame_add(gspca_dev, LAST_PACKET,
- data, len);
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
return;
}
if (gspca_dev->last_packet_type == LAST_PACKET) {
@@ -2397,9 +2453,8 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
.dq_callback = sd_dqcallback,
@@ -2415,7 +2470,7 @@ static const struct sd_desc sd_desc = {
| (SENSOR_ ## sensor << 8) \
| (i2c_addr)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x6240), SN9C20X(MT9M001, 0x5d, 0)},
{USB_DEVICE(0x0c45, 0x6242), SN9C20X(MT9M111, 0x5d, 0)},
{USB_DEVICE(0x0c45, 0x6248), SN9C20X(OV9655, 0x30, 0)},
@@ -2480,17 +2535,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- info("registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- info("deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/sonixb.c b/drivers/media/video/gspca/sonixb.c
index 785eeb4c2014..c6cd68d66b53 100644
--- a/drivers/media/video/gspca/sonixb.c
+++ b/drivers/media/video/gspca/sonixb.c
@@ -23,8 +23,15 @@
/* Some documentation on known sonixb registers:
Reg Use
+sn9c101 / sn9c102:
0x10 high nibble red gain low nibble blue gain
0x11 low nibble green gain
+sn9c103:
+0x05 red gain 0-127
+0x06 blue gain 0-127
+0x07 green gain 0-127
+all:
+0x08-0x0f i2c / 3wire registers
0x12 hstart
0x13 vstart
0x15 hsize (hsize = register-value * 16)
@@ -56,6 +63,8 @@ struct sd {
int prev_avg_lum;
int exp_too_low_cnt;
int exp_too_high_cnt;
+ int header_read;
+ u8 header[12]; /* Header without sof marker */
unsigned short exposure;
unsigned char gain;
@@ -71,26 +80,24 @@ struct sd {
#define BRIDGE_103 1
__u8 sensor; /* Type of image sensor chip */
-#define SENSOR_HV7131R 0
-#define SENSOR_OV6650 1
-#define SENSOR_OV7630 2
-#define SENSOR_PAS106 3
-#define SENSOR_PAS202 4
-#define SENSOR_TAS5110C 5
-#define SENSOR_TAS5110D 6
-#define SENSOR_TAS5130CXX 7
+#define SENSOR_HV7131D 0
+#define SENSOR_HV7131R 1
+#define SENSOR_OV6650 2
+#define SENSOR_OV7630 3
+#define SENSOR_PAS106 4
+#define SENSOR_PAS202 5
+#define SENSOR_TAS5110C 6
+#define SENSOR_TAS5110D 7
+#define SENSOR_TAS5130CXX 8
__u8 reg11;
};
typedef const __u8 sensor_init_t[8];
struct sensor_data {
- const __u8 *bridge_init[2];
- int bridge_init_size[2];
+ const __u8 *bridge_init;
sensor_init_t *sensor_init;
int sensor_init_size;
- sensor_init_t *sensor_bridge_init[2];
- int sensor_bridge_init_size[2];
int flags;
unsigned ctrl_dis;
__u8 sensor_addr;
@@ -111,7 +118,6 @@ struct sensor_data {
#define NO_FREQ (1 << FREQ_IDX)
#define NO_BRIGHTNESS (1 << BRIGHTNESS_IDX)
-#define COMP2 0x8f
#define COMP 0xc7 /* 0x87 //0x07 */
#define COMP1 0xc9 /* 0x89 //0x09 */
@@ -120,15 +126,11 @@ struct sensor_data {
#define SYS_CLK 0x04
-#define SENS(bridge_1, bridge_3, sensor, sensor_1, \
- sensor_3, _flags, _ctrl_dis, _sensor_addr) \
+#define SENS(bridge, sensor, _flags, _ctrl_dis, _sensor_addr) \
{ \
- .bridge_init = { bridge_1, bridge_3 }, \
- .bridge_init_size = { sizeof(bridge_1), sizeof(bridge_3) }, \
+ .bridge_init = bridge, \
.sensor_init = sensor, \
.sensor_init_size = sizeof(sensor), \
- .sensor_bridge_init = { sensor_1, sensor_3,}, \
- .sensor_bridge_init_size = { sizeof(sensor_1), sizeof(sensor_3)}, \
.flags = _flags, .ctrl_dis = _ctrl_dis, .sensor_addr = _sensor_addr \
}
@@ -303,14 +305,27 @@ static const struct v4l2_pix_format sif_mode[] = {
.priv = 0},
};
-static const __u8 initHv7131[] = {
+static const __u8 initHv7131d[] = {
+ 0x04, 0x03, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
+ 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x02, 0x02, 0x00,
+ 0x28, 0x1e, 0x60, 0x8e, 0x42,
+};
+static const __u8 hv7131d_sensor_init[][8] = {
+ {0xa0, 0x11, 0x01, 0x04, 0x00, 0x00, 0x00, 0x17},
+ {0xa0, 0x11, 0x02, 0x00, 0x00, 0x00, 0x00, 0x17},
+ {0xa0, 0x11, 0x28, 0x00, 0x00, 0x00, 0x00, 0x17},
+ {0xa0, 0x11, 0x30, 0x30, 0x00, 0x00, 0x00, 0x17}, /* reset level */
+ {0xa0, 0x11, 0x34, 0x02, 0x00, 0x00, 0x00, 0x17}, /* pixel bias volt */
+};
+
+static const __u8 initHv7131r[] = {
0x46, 0x77, 0x00, 0x04, 0x00, 0x00, 0x00, 0x80, 0x11, 0x00, 0x00, 0x00,
0x00, 0x00,
0x00, 0x00, 0x00, 0x02, 0x01, 0x00,
0x28, 0x1e, 0x60, 0x8a, 0x20,
- 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c
};
-static const __u8 hv7131_sensor_init[][8] = {
+static const __u8 hv7131r_sensor_init[][8] = {
{0xc0, 0x11, 0x31, 0x38, 0x2a, 0x2e, 0x00, 0x10},
{0xa0, 0x11, 0x01, 0x08, 0x2a, 0x2e, 0x00, 0x10},
{0xb0, 0x11, 0x20, 0x00, 0xd0, 0x2e, 0x00, 0x10},
@@ -321,12 +336,11 @@ static const __u8 initOv6650[] = {
0x44, 0x44, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x01, 0x01, 0x0a, 0x16, 0x12, 0x68, 0x8b,
- 0x10, 0x1d, 0x10, 0x02, 0x02, 0x09, 0x07
+ 0x10,
};
-static const __u8 ov6650_sensor_init[][8] =
-{
+static const __u8 ov6650_sensor_init[][8] = {
/* Bright, contrast, etc are set through SCBB interface.
- * AVCAP on win2 do not send any data on this controls. */
+ * AVCAP on win2 do not send any data on this controls. */
/* Anyway, some registers appears to alter bright and constrat */
/* Reset sensor */
@@ -341,7 +355,7 @@ static const __u8 ov6650_sensor_init[][8] =
* but blue wont be there. Avoid this data ... */
{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10}, /* format out? */
{0xd0, 0x60, 0x26, 0x01, 0x14, 0xd8, 0xa4, 0x10},
- {0xa0, 0x60, 0x30, 0x3d, 0x0A, 0xd8, 0xa4, 0x10},
+ {0xa0, 0x60, 0x30, 0x3d, 0x0a, 0xd8, 0xa4, 0x10},
/* Enable rgb brightness control */
{0xa0, 0x60, 0x61, 0x08, 0x00, 0x00, 0x00, 0x10},
/* HDG: Note windows uses the line below, which sets both register 0x60
@@ -361,24 +375,13 @@ static const __u8 initOv7630[] = {
0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
0x00, 0x01, 0x01, 0x0a, /* r11 .. r14 */
0x28, 0x1e, /* H & V sizes r15 .. r16 */
- 0x68, COMP2, MCK_INIT1, /* r17 .. r19 */
- 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c /* r1a .. r1f */
-};
-static const __u8 initOv7630_3[] = {
- 0x44, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20, 0x80, /* r01 .. r08 */
- 0x21, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* r09 .. r10 */
- 0x00, 0x02, 0x01, 0x0a, /* r11 .. r14 */
- 0x28, 0x1e, /* H & V sizes r15 .. r16 */
0x68, 0x8f, MCK_INIT1, /* r17 .. r19 */
- 0x1d, 0x10, 0x02, 0x03, 0x0f, 0x0c, 0x00, /* r1a .. r20 */
- 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, 0x80, /* r21 .. r28 */
- 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0, 0xff /* r29 .. r30 */
};
static const __u8 ov7630_sensor_init[][8] = {
{0xa0, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xb0, 0x21, 0x01, 0x77, 0x3a, 0x00, 0x00, 0x10},
/* {0xd0, 0x21, 0x12, 0x7c, 0x01, 0x80, 0x34, 0x10}, jfm */
- {0xd0, 0x21, 0x12, 0x1c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
+ {0xd0, 0x21, 0x12, 0x5c, 0x00, 0x80, 0x34, 0x10}, /* jfm */
{0xa0, 0x21, 0x1b, 0x04, 0x00, 0x80, 0x34, 0x10},
{0xa0, 0x21, 0x20, 0x44, 0x00, 0x80, 0x34, 0x10},
{0xa0, 0x21, 0x23, 0xee, 0x00, 0x80, 0x34, 0x10},
@@ -396,16 +399,11 @@ static const __u8 ov7630_sensor_init[][8] = {
{0xd0, 0x21, 0x17, 0x1c, 0xbd, 0x06, 0xf6, 0x10},
};
-static const __u8 ov7630_sensor_init_3[][8] = {
- {0xa0, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
-};
-
static const __u8 initPas106[] = {
0x04, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0x40, 0x00, 0x00, 0x00,
0x00, 0x00,
0x00, 0x00, 0x00, 0x04, 0x01, 0x00,
0x16, 0x12, 0x24, COMP1, MCK_INIT1,
- 0x18, 0x10, 0x02, 0x02, 0x09, 0x07
};
/* compression 0x86 mckinit1 0x2b */
@@ -479,7 +477,6 @@ static const __u8 initPas202[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x06, 0x03, 0x0a,
0x28, 0x1e, 0x20, 0x89, 0x20,
- 0x00, 0x00, 0x02, 0x03, 0x0f, 0x0c
};
/* "Known" PAS202BCB registers:
@@ -506,7 +503,7 @@ static const __u8 pas202_sensor_init[][8] = {
{0xa0, 0x40, 0x02, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xd0, 0x40, 0x04, 0x07, 0x34, 0x00, 0x09, 0x10},
{0xd0, 0x40, 0x08, 0x01, 0x00, 0x00, 0x01, 0x10},
- {0xd0, 0x40, 0x0C, 0x00, 0x0C, 0x01, 0x32, 0x10},
+ {0xd0, 0x40, 0x0c, 0x00, 0x0c, 0x01, 0x32, 0x10},
{0xd0, 0x40, 0x10, 0x00, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x15, 0x70, 0x01, 0x00, 0x63, 0x10},
{0xa0, 0x40, 0x18, 0x00, 0x01, 0x00, 0x63, 0x10},
@@ -520,7 +517,6 @@ static const __u8 initTas5110c[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x45, 0x09, 0x0a,
0x16, 0x12, 0x60, 0x86, 0x2b,
- 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
};
/* Same as above, except a different hstart */
static const __u8 initTas5110d[] = {
@@ -528,12 +524,19 @@ static const __u8 initTas5110d[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x41, 0x09, 0x0a,
0x16, 0x12, 0x60, 0x86, 0x2b,
- 0x14, 0x0a, 0x02, 0x02, 0x09, 0x07
};
-static const __u8 tas5110_sensor_init[][8] = {
+/* tas5110c is 3 wire, tas5110d is 2 wire (regular i2c) */
+static const __u8 tas5110c_sensor_init[][8] = {
{0x30, 0x11, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x10},
{0x30, 0x11, 0x02, 0x20, 0xa9, 0x00, 0x00, 0x10},
- {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17},
+};
+/* Known TAS5110D registers
+ * reg02: gain, bit order reversed!! 0 == max gain, 255 == min gain
+ * reg03: bit3: vflip, bit4: ~hflip, bit7: ~gainboost (~ == inverted)
+ * Note: writing reg03 seems to only work when written together with 02
+ */
+static const __u8 tas5110d_sensor_init[][8] = {
+ {0xa0, 0x61, 0x9a, 0xca, 0x00, 0x00, 0x00, 0x17}, /* reset */
};
static const __u8 initTas5130[] = {
@@ -541,10 +544,9 @@ static const __u8 initTas5130[] = {
0x00, 0x00,
0x00, 0x00, 0x00, 0x68, 0x0c, 0x0a,
0x28, 0x1e, 0x60, COMP, MCK_INIT,
- 0x18, 0x10, 0x04, 0x03, 0x11, 0x0c
};
static const __u8 tas5130_sensor_init[][8] = {
-/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
+/* {0x30, 0x11, 0x00, 0x40, 0x47, 0x00, 0x00, 0x10},
* shutter 0x47 short exposure? */
{0x30, 0x11, 0x00, 0x40, 0x01, 0x00, 0x00, 0x10},
/* shutter 0x01 long exposure */
@@ -552,20 +554,18 @@ static const __u8 tas5130_sensor_init[][8] = {
};
static struct sensor_data sensor_data[] = {
-SENS(initHv7131, NULL, hv7131_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ, 0),
-SENS(initOv6650, NULL, ov6650_sensor_init, NULL, NULL, F_GAIN|F_SIF, 0, 0x60),
-SENS(initOv7630, initOv7630_3, ov7630_sensor_init, NULL, ov7630_sensor_init_3,
- F_GAIN, 0, 0x21),
-SENS(initPas106, NULL, pas106_sensor_init, NULL, NULL, F_GAIN|F_SIF, NO_FREQ,
- 0),
-SENS(initPas202, initPas202, pas202_sensor_init, NULL, NULL, F_GAIN,
- NO_FREQ, 0),
-SENS(initTas5110c, NULL, tas5110_sensor_init, NULL, NULL,
- F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
-SENS(initTas5110d, NULL, tas5110_sensor_init, NULL, NULL,
- F_GAIN|F_SIF|F_COARSE_EXPO, NO_BRIGHTNESS|NO_FREQ, 0),
-SENS(initTas5130, NULL, tas5130_sensor_init, NULL, NULL, 0, NO_EXPO|NO_FREQ,
- 0),
+SENS(initHv7131d, hv7131d_sensor_init, F_GAIN, NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initHv7131r, hv7131r_sensor_init, 0, NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
+SENS(initOv6650, ov6650_sensor_init, F_GAIN|F_SIF, 0, 0x60),
+SENS(initOv7630, ov7630_sensor_init, F_GAIN, 0, 0x21),
+SENS(initPas106, pas106_sensor_init, F_GAIN|F_SIF, NO_FREQ, 0),
+SENS(initPas202, pas202_sensor_init, F_GAIN, NO_FREQ, 0),
+SENS(initTas5110c, tas5110c_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO,
+ NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5110d, tas5110d_sensor_init, F_GAIN|F_SIF|F_COARSE_EXPO,
+ NO_BRIGHTNESS|NO_FREQ, 0),
+SENS(initTas5130, tas5130_sensor_init, F_GAIN,
+ NO_BRIGHTNESS|NO_EXPO|NO_FREQ, 0),
};
/* get one byte in gspca_dev->usb_buf */
@@ -637,7 +637,6 @@ static void i2c_w_vector(struct gspca_dev *gspca_dev,
static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- __u8 value;
switch (sd->sensor) {
case SENSOR_OV6650:
@@ -679,17 +678,6 @@ static void setbrightness(struct gspca_dev *gspca_dev)
goto err;
break;
}
- case SENSOR_TAS5130CXX: {
- __u8 i2c[] =
- {0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
-
- value = 0xff - sd->brightness;
- i2c[4] = value;
- PDEBUG(D_CONF, "brightness %d : %d", value, i2c[4]);
- if (i2c_w(gspca_dev, i2c) < 0)
- goto err;
- break;
- }
}
return;
err:
@@ -702,9 +690,20 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
unsigned char gain = sd->gain;
switch (sd->sensor) {
+ case SENSOR_HV7131D: {
+ __u8 i2c[] =
+ {0xc0, 0x11, 0x31, 0x00, 0x00, 0x00, 0x00, 0x17};
+ i2c[3] = 0x3f - (sd->gain / 4);
+ i2c[4] = 0x3f - (sd->gain / 4);
+ i2c[5] = 0x3f - (sd->gain / 4);
+
+ if (i2c_w(gspca_dev, i2c) < 0)
+ goto err;
+ break;
+ }
case SENSOR_TAS5110C:
- case SENSOR_TAS5110D: {
+ case SENSOR_TAS5130CXX: {
__u8 i2c[] =
{0x30, 0x11, 0x02, 0x20, 0x70, 0x00, 0x00, 0x10};
@@ -713,6 +712,23 @@ static void setsensorgain(struct gspca_dev *gspca_dev)
goto err;
break;
}
+ case SENSOR_TAS5110D: {
+ __u8 i2c[] = {
+ 0xb0, 0x61, 0x02, 0x00, 0x10, 0x00, 0x00, 0x17 };
+ gain = 255 - gain;
+ /* The bits in the register are the wrong way around!! */
+ i2c[3] |= (gain & 0x80) >> 7;
+ i2c[3] |= (gain & 0x40) >> 5;
+ i2c[3] |= (gain & 0x20) >> 3;
+ i2c[3] |= (gain & 0x10) >> 1;
+ i2c[3] |= (gain & 0x08) << 1;
+ i2c[3] |= (gain & 0x04) << 3;
+ i2c[3] |= (gain & 0x02) << 5;
+ i2c[3] |= (gain & 0x01) << 7;
+ if (i2c_w(gspca_dev, i2c) < 0)
+ goto err;
+ break;
+ }
case SENSOR_OV6650:
gain >>= 1;
@@ -767,7 +783,7 @@ static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
__u8 gain;
- __u8 buf[2] = { 0, 0 };
+ __u8 buf[3] = { 0, 0, 0 };
if (sensor_data[sd->sensor].flags & F_GAIN) {
/* Use the sensor gain to do the actual gain */
@@ -775,13 +791,18 @@ static void setgain(struct gspca_dev *gspca_dev)
return;
}
- gain = sd->gain >> 4;
-
- /* red and blue gain */
- buf[0] = gain << 4 | gain;
- /* green gain */
- buf[1] = gain;
- reg_w(gspca_dev, 0x10, buf, 2);
+ if (sd->bridge == BRIDGE_103) {
+ gain = sd->gain >> 1;
+ buf[0] = gain; /* Red */
+ buf[1] = gain; /* Green */
+ buf[2] = gain; /* Blue */
+ reg_w(gspca_dev, 0x05, buf, 3);
+ } else {
+ gain = sd->gain >> 4;
+ buf[0] = gain << 4 | gain; /* Red and blue */
+ buf[1] = gain; /* Green */
+ reg_w(gspca_dev, 0x10, buf, 2);
+ }
}
static void setexposure(struct gspca_dev *gspca_dev)
@@ -789,6 +810,23 @@ static void setexposure(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
switch (sd->sensor) {
+ case SENSOR_HV7131D: {
+ /* Note the datasheet wrongly says line mode exposure uses reg
+ 0x26 and 0x27, testing has shown 0x25 + 0x26 */
+ __u8 i2c[] = {0xc0, 0x11, 0x25, 0x00, 0x00, 0x00, 0x00, 0x17};
+ /* The HV7131D's exposure goes from 0 - 65535, we scale our
+ exposure of 0-1023 to 0-6138. There are 2 reasons for this:
+ 1) This puts our exposure knee of 200 at approx the point
+ where the framerate starts dropping
+ 2) At 6138 the framerate has already dropped to 2 fps,
+ going any lower makes little sense */
+ __u16 reg = sd->exposure * 6;
+ i2c[3] = reg >> 8;
+ i2c[4] = reg & 0xff;
+ if (i2c_w(gspca_dev, i2c) != 0)
+ goto err;
+ break;
+ }
case SENSOR_TAS5110C:
case SENSOR_TAS5110D: {
/* register 19's high nibble contains the sn9c10x clock divider
@@ -861,7 +899,7 @@ static void setexposure(struct gspca_dev *gspca_dev)
i2c[4] |= reg11 - 1;
/* If register 11 didn't change, don't change it */
- if (sd->reg11 == reg11 )
+ if (sd->reg11 == reg11)
i2c[0] = 0xa0;
if (i2c_w(gspca_dev, i2c) == 0)
@@ -1003,7 +1041,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
desired_avg_lum = 5000;
} else {
deadzone = 1500;
- desired_avg_lum = 18000;
+ desired_avg_lum = 13000;
}
if (sensor_data[sd->sensor].flags & F_COARSE_EXPO)
@@ -1081,53 +1119,91 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam = &gspca_dev->cam;
- int mode, l;
- const __u8 *sn9c10x;
- __u8 reg12_19[8];
+ int i, mode;
+ __u8 regs[0x31];
mode = cam->cam_mode[gspca_dev->curr_mode].priv & 0x07;
- sn9c10x = sensor_data[sd->sensor].bridge_init[sd->bridge];
- l = sensor_data[sd->sensor].bridge_init_size[sd->bridge];
- memcpy(reg12_19, &sn9c10x[0x12 - 1], 8);
- reg12_19[6] = sn9c10x[0x18 - 1] | (mode << 4);
- /* Special cases where reg 17 and or 19 value depends on mode */
+ /* Copy registers 0x01 - 0x19 from the template */
+ memcpy(&regs[0x01], sensor_data[sd->sensor].bridge_init, 0x19);
+ /* Set the mode */
+ regs[0x18] |= mode << 4;
+
+ /* Set bridge gain to 1.0 */
+ if (sd->bridge == BRIDGE_103) {
+ regs[0x05] = 0x20; /* Red */
+ regs[0x06] = 0x20; /* Green */
+ regs[0x07] = 0x20; /* Blue */
+ } else {
+ regs[0x10] = 0x00; /* Red and blue */
+ regs[0x11] = 0x00; /* Green */
+ }
+
+ /* Setup pixel numbers and auto exposure window */
+ if (sensor_data[sd->sensor].flags & F_SIF) {
+ regs[0x1a] = 0x14; /* HO_SIZE 640, makes no sense */
+ regs[0x1b] = 0x0a; /* VO_SIZE 320, makes no sense */
+ regs[0x1c] = 0x02; /* AE H-start 64 */
+ regs[0x1d] = 0x02; /* AE V-start 64 */
+ regs[0x1e] = 0x09; /* AE H-end 288 */
+ regs[0x1f] = 0x07; /* AE V-end 224 */
+ } else {
+ regs[0x1a] = 0x1d; /* HO_SIZE 960, makes no sense */
+ regs[0x1b] = 0x10; /* VO_SIZE 512, makes no sense */
+ regs[0x1c] = 0x05; /* AE H-start 160 */
+ regs[0x1d] = 0x03; /* AE V-start 96 */
+ regs[0x1e] = 0x0f; /* AE H-end 480 */
+ regs[0x1f] = 0x0c; /* AE V-end 384 */
+ }
+
+ /* Setup the gamma table (only used with the sn9c103 bridge) */
+ for (i = 0; i < 16; i++)
+ regs[0x20 + i] = i * 16;
+ regs[0x20 + i] = 255;
+
+ /* Special cases where some regs depend on mode or bridge */
switch (sd->sensor) {
case SENSOR_TAS5130CXX:
- /* probably not mode specific at all most likely the upper
+ /* FIXME / TESTME
+ probably not mode specific at all most likely the upper
nibble of 0x19 is exposure (clock divider) just as with
the tas5110, we need someone to test this. */
- reg12_19[7] = mode ? 0x23 : 0x43;
+ regs[0x19] = mode ? 0x23 : 0x43;
break;
+ case SENSOR_OV7630:
+ /* FIXME / TESTME for some reason with the 101/102 bridge the
+ clock is set to 12 Mhz (reg1 == 0x04), rather then 24.
+ Also the hstart needs to go from 1 to 2 when using a 103,
+ which is likely related. This does not seem right. */
+ if (sd->bridge == BRIDGE_103) {
+ regs[0x01] = 0x44; /* Select 24 Mhz clock */
+ regs[0x12] = 0x02; /* Set hstart to 2 */
+ }
}
/* Disable compression when the raw bayer format has been selected */
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW)
- reg12_19[6] &= ~0x80;
+ regs[0x18] &= ~0x80;
/* Vga mode emulation on SIF sensor? */
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_REDUCED_SIF) {
- reg12_19[0] += 16; /* 0x12: hstart adjust */
- reg12_19[1] += 24; /* 0x13: vstart adjust */
- reg12_19[3] = 320 / 16; /* 0x15: hsize */
- reg12_19[4] = 240 / 16; /* 0x16: vsize */
+ regs[0x12] += 16; /* hstart adjust */
+ regs[0x13] += 24; /* vstart adjust */
+ regs[0x15] = 320 / 16; /* hsize */
+ regs[0x16] = 240 / 16; /* vsize */
}
/* reg 0x01 bit 2 video transfert on */
- reg_w(gspca_dev, 0x01, &sn9c10x[0x01 - 1], 1);
+ reg_w(gspca_dev, 0x01, &regs[0x01], 1);
/* reg 0x17 SensorClk enable inv Clk 0x60 */
- reg_w(gspca_dev, 0x17, &sn9c10x[0x17 - 1], 1);
+ reg_w(gspca_dev, 0x17, &regs[0x17], 1);
/* Set the registers from the template */
- reg_w(gspca_dev, 0x01, sn9c10x, l);
+ reg_w(gspca_dev, 0x01, &regs[0x01],
+ (sd->bridge == BRIDGE_103) ? 0x30 : 0x1f);
/* Init the sensor */
i2c_w_vector(gspca_dev, sensor_data[sd->sensor].sensor_init,
sensor_data[sd->sensor].sensor_init_size);
- if (sensor_data[sd->sensor].sensor_bridge_init[sd->bridge])
- i2c_w_vector(gspca_dev,
- sensor_data[sd->sensor].sensor_bridge_init[sd->bridge],
- sensor_data[sd->sensor].sensor_bridge_init_size[
- sd->bridge]);
- /* Mode specific sensor setup */
+ /* Mode / bridge specific sensor setup */
switch (sd->sensor) {
case SENSOR_PAS202: {
const __u8 i2cpclockdiv[] =
@@ -1135,27 +1211,37 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* clockdiv from 4 to 3 (7.5 -> 10 fps) when in low res mode */
if (mode)
i2c_w(gspca_dev, i2cpclockdiv);
+ break;
}
+ case SENSOR_OV7630:
+ /* FIXME / TESTME We should be able to handle this identical
+ for the 101/102 and the 103 case */
+ if (sd->bridge == BRIDGE_103) {
+ const __u8 i2c[] = { 0xa0, 0x21, 0x13,
+ 0x80, 0x00, 0x00, 0x00, 0x10 };
+ i2c_w(gspca_dev, i2c);
+ }
+ break;
}
/* H_size V_size 0x28, 0x1e -> 640x480. 0x16, 0x12 -> 352x288 */
- reg_w(gspca_dev, 0x15, &reg12_19[3], 2);
+ reg_w(gspca_dev, 0x15, &regs[0x15], 2);
/* compression register */
- reg_w(gspca_dev, 0x18, &reg12_19[6], 1);
+ reg_w(gspca_dev, 0x18, &regs[0x18], 1);
/* H_start */
- reg_w(gspca_dev, 0x12, &reg12_19[0], 1);
+ reg_w(gspca_dev, 0x12, &regs[0x12], 1);
/* V_START */
- reg_w(gspca_dev, 0x13, &reg12_19[1], 1);
+ reg_w(gspca_dev, 0x13, &regs[0x13], 1);
/* reset 0x17 SensorClk enable inv Clk 0x60 */
/*fixme: ov7630 [17]=68 8f (+20 if 102)*/
- reg_w(gspca_dev, 0x17, &reg12_19[5], 1);
+ reg_w(gspca_dev, 0x17, &regs[0x17], 1);
/*MCKSIZE ->3 */ /*fixme: not ov7630*/
- reg_w(gspca_dev, 0x19, &reg12_19[7], 1);
+ reg_w(gspca_dev, 0x19, &regs[0x19], 1);
/* AE_STRX AE_STRY AE_ENDX AE_ENDY */
- reg_w(gspca_dev, 0x1c, &sn9c10x[0x1c - 1], 4);
+ reg_w(gspca_dev, 0x1c, &regs[0x1c], 4);
/* Enable video transfert */
- reg_w(gspca_dev, 0x01, &sn9c10x[0], 1);
+ reg_w(gspca_dev, 0x01, &regs[0x01], 1);
/* Compression */
- reg_w(gspca_dev, 0x18, &reg12_19[6], 2);
+ reg_w(gspca_dev, 0x18, &regs[0x18], 2);
msleep(20);
sd->reg11 = -1;
@@ -1178,13 +1264,10 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
sd_init(gspca_dev);
}
-static void sd_pkt_scan(struct gspca_dev *gspca_dev,
- u8 *data, /* isoc packet */
- int len) /* iso packet length */
+static u8* find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
{
- int i;
struct sd *sd = (struct sd *) gspca_dev;
- struct cam *cam = &gspca_dev->cam;
+ int i, header_size = (sd->bridge == BRIDGE_103) ? 18 : 12;
/* frames start with:
* ff ff 00 c4 c4 96 synchro
@@ -1195,77 +1278,124 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
* ll mm brightness sum outside auto exposure
* (xx xx xx xx xx) audio values for snc103
*/
- if (len > 6 && len < 24) {
- for (i = 0; i < len - 6; i++) {
- if (data[0 + i] == 0xff
- && data[1 + i] == 0xff
- && data[2 + i] == 0x00
- && data[3 + i] == 0xc4
- && data[4 + i] == 0xc4
- && data[5 + i] == 0x96) { /* start of frame */
- int lum = -1;
- int pkt_type = LAST_PACKET;
- int fr_h_sz = (sd->bridge == BRIDGE_103) ?
- 18 : 12;
-
- if (len - i < fr_h_sz) {
- PDEBUG(D_STREAM, "packet too short to"
- " get avg brightness");
- } else if (sd->bridge == BRIDGE_103) {
- lum = data[i + 9] +
- (data[i + 10] << 8);
- } else {
- lum = data[i + 8] + (data[i + 9] << 8);
- }
- /* When exposure changes midway a frame we
- get a lum of 0 in this case drop 2 frames
- as the frames directly after an exposure
- change have an unstable image. Sometimes lum
- *really* is 0 (cam used in low light with
- low exposure setting), so do not drop frames
- if the previous lum was 0 too. */
- if (lum == 0 && sd->prev_avg_lum != 0) {
- lum = -1;
- sd->frames_to_drop = 2;
- sd->prev_avg_lum = 0;
- } else
- sd->prev_avg_lum = lum;
- atomic_set(&sd->avg_lum, lum);
-
- if (sd->frames_to_drop) {
- sd->frames_to_drop--;
- pkt_type = DISCARD_PACKET;
- }
-
- gspca_frame_add(gspca_dev, pkt_type,
- NULL, 0);
- data += i + fr_h_sz;
- len -= i + fr_h_sz;
- gspca_frame_add(gspca_dev, FIRST_PACKET,
- data, len);
- return;
+ for (i = 0; i < len; i++) {
+ switch (sd->header_read) {
+ case 0:
+ if (data[i] == 0xff)
+ sd->header_read++;
+ break;
+ case 1:
+ if (data[i] == 0xff)
+ sd->header_read++;
+ else
+ sd->header_read = 0;
+ break;
+ case 2:
+ if (data[i] == 0x00)
+ sd->header_read++;
+ else if (data[i] != 0xff)
+ sd->header_read = 0;
+ break;
+ case 3:
+ if (data[i] == 0xc4)
+ sd->header_read++;
+ else if (data[i] == 0xff)
+ sd->header_read = 1;
+ else
+ sd->header_read = 0;
+ break;
+ case 4:
+ if (data[i] == 0xc4)
+ sd->header_read++;
+ else if (data[i] == 0xff)
+ sd->header_read = 1;
+ else
+ sd->header_read = 0;
+ break;
+ case 5:
+ if (data[i] == 0x96)
+ sd->header_read++;
+ else if (data[i] == 0xff)
+ sd->header_read = 1;
+ else
+ sd->header_read = 0;
+ break;
+ default:
+ sd->header[sd->header_read - 6] = data[i];
+ sd->header_read++;
+ if (sd->header_read == header_size) {
+ sd->header_read = 0;
+ return data + i + 1;
}
}
}
+ return NULL;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ int fr_h_sz = 0, lum_offset = 0, len_after_sof = 0;
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+ u8 *sof;
+
+ sof = find_sof(gspca_dev, data, len);
+ if (sof) {
+ if (sd->bridge == BRIDGE_103) {
+ fr_h_sz = 18;
+ lum_offset = 3;
+ } else {
+ fr_h_sz = 12;
+ lum_offset = 2;
+ }
+
+ len_after_sof = len - (sof - data);
+ len = (sof - data) - fr_h_sz;
+ if (len < 0)
+ len = 0;
+ }
if (cam->cam_mode[gspca_dev->curr_mode].priv & MODE_RAW) {
/* In raw mode we sometimes get some garbage after the frame
ignore this */
- struct gspca_frame *frame;
int used;
int size = cam->cam_mode[gspca_dev->curr_mode].sizeimage;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
- used = frame->data_end - frame->data;
+ used = gspca_dev->image_len;
if (used + len > size)
len = size - used;
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+
+ if (sof) {
+ int lum = sd->header[lum_offset] +
+ (sd->header[lum_offset + 1] << 8);
+
+ /* When exposure changes midway a frame we
+ get a lum of 0 in this case drop 2 frames
+ as the frames directly after an exposure
+ change have an unstable image. Sometimes lum
+ *really* is 0 (cam used in low light with
+ low exposure setting), so do not drop frames
+ if the previous lum was 0 too. */
+ if (lum == 0 && sd->prev_avg_lum != 0) {
+ lum = -1;
+ sd->frames_to_drop = 2;
+ sd->prev_avg_lum = 0;
+ } else
+ sd->prev_avg_lum = lum;
+ atomic_set(&sd->avg_lum, lum);
+
+ if (sd->frames_to_drop)
+ sd->frames_to_drop--;
+ else
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+
+ gspca_frame_add(gspca_dev, FIRST_PACKET, sof, len_after_sof);
+ }
}
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
@@ -1394,7 +1524,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrupt packet length */
@@ -1425,7 +1555,7 @@ static const struct sd_desc sd_desc = {
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
.dq_callback = do_autogain,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
@@ -1435,38 +1565,41 @@ static const struct sd_desc sd_desc = {
.driver_info = (SENSOR_ ## sensor << 8) | BRIDGE_ ## bridge
-static const struct usb_device_id device_table[] __devinitconst = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x6001), SB(TAS5110C, 102)}, /* TAS5110C1B */
{USB_DEVICE(0x0c45, 0x6005), SB(TAS5110C, 101)}, /* TAS5110C1B */
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6007), SB(TAS5110D, 101)}, /* TAS5110D */
-#endif
{USB_DEVICE(0x0c45, 0x6009), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x600d), SB(PAS106, 101)},
{USB_DEVICE(0x0c45, 0x6011), SB(OV6650, 101)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6019), SB(OV7630, 101)},
+#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6024), SB(TAS5130CXX, 102)},
{USB_DEVICE(0x0c45, 0x6025), SB(TAS5130CXX, 102)},
#endif
{USB_DEVICE(0x0c45, 0x6028), SB(PAS202, 102)},
{USB_DEVICE(0x0c45, 0x6029), SB(PAS106, 102)},
+ {USB_DEVICE(0x0c45, 0x602a), SB(HV7131D, 102)},
+ /* {USB_DEVICE(0x0c45, 0x602b), SB(MI0343, 102)}, */
{USB_DEVICE(0x0c45, 0x602c), SB(OV7630, 102)},
{USB_DEVICE(0x0c45, 0x602d), SB(HV7131R, 102)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x602e), SB(OV7630, 102)},
-#endif
+ /* {USB_DEVICE(0x0c45, 0x6030), SB(MI03XX, 102)}, */ /* MI0343 MI0360 MI0330 */
+ /* {USB_DEVICE(0x0c45, 0x6082), SB(MI03XX, 103)}, */ /* MI0343 MI0360 */
+ {USB_DEVICE(0x0c45, 0x6083), SB(HV7131D, 103)},
+ {USB_DEVICE(0x0c45, 0x608c), SB(HV7131R, 103)},
+ /* {USB_DEVICE(0x0c45, 0x608e), SB(CISVF10, 103)}, */
{USB_DEVICE(0x0c45, 0x608f), SB(OV7630, 103)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ {USB_DEVICE(0x0c45, 0x60a8), SB(PAS106, 103)},
+ {USB_DEVICE(0x0c45, 0x60aa), SB(TAS5130CXX, 103)},
{USB_DEVICE(0x0c45, 0x60af), SB(PAS202, 103)},
-#endif
{USB_DEVICE(0x0c45, 0x60b0), SB(OV7630, 103)},
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
-static int __devinit sd_probe(struct usb_interface *intf,
+static int sd_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
@@ -1487,17 +1620,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/sonixj.c b/drivers/media/video/gspca/sonixj.c
index bb923efb75bd..d6f39ce1b7e1 100644
--- a/drivers/media/video/gspca/sonixj.c
+++ b/drivers/media/video/gspca/sonixj.c
@@ -22,41 +22,51 @@
#define MODULE_NAME "sonixj"
#include <linux/input.h>
-#include <linux/slab.h>
#include "gspca.h"
#include "jpeg.h"
-#define V4L2_CID_INFRARED (V4L2_CID_PRIVATE_BASE + 0)
-
MODULE_AUTHOR("Jean-François Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("GSPCA/SONIX JPEG USB Camera Driver");
MODULE_LICENSE("GPL");
+static int starcam;
+
+/* controls */
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ COLORS,
+ BLUE,
+ RED,
+ GAMMA,
+ AUTOGAIN,
+ HFLIP,
+ VFLIP,
+ SHARPNESS,
+ ILLUM,
+ FREQ,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
+ struct gspca_ctrl ctrls[NCTRLS];
+
atomic_t avg_lum;
u32 exposure;
- u16 brightness;
- u8 contrast;
- u8 colors;
- u8 autogain;
- u8 blue;
- u8 red;
- u8 gamma;
- u8 vflip; /* ov7630/ov7648 only */
- u8 sharpness;
- u8 infrared; /* mt9v111 only */
- u8 freq; /* ov76xx only */
u8 quality; /* image quality */
#define QUALITY_MIN 60
#define QUALITY_MAX 95
#define QUALITY_DEF 80
u8 jpegqual; /* webcam quality */
+ u8 reg01;
+ u8 reg17;
u8 reg18;
+ u8 flags;
s8 ag_cnt;
#define AG_CNT_START 13
@@ -67,11 +77,16 @@ struct sd {
#define BRIDGE_SN9C110 2
#define BRIDGE_SN9C120 3
u8 sensor; /* Type of image sensor chip */
-enum {
+ u8 i2c_addr;
+
+ u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+enum sensors {
SENSOR_ADCM1700,
SENSOR_GC0307,
SENSOR_HV7131R,
SENSOR_MI0360,
+ SENSOR_MI0360B,
SENSOR_MO4000,
SENSOR_MT9V111,
SENSOR_OM6802,
@@ -82,55 +97,51 @@ enum {
SENSOR_PO2030N,
SENSOR_SOI768,
SENSOR_SP80708,
-} sensors;
- u8 i2c_addr;
-
- u8 jpeg_hdr[JPEG_HDR_SZ];
};
+/* device flags */
+#define F_PDN_INV 0x01 /* inverse pin S_PWR_DN / sn_xxx tables */
+#define F_ILLUM 0x02 /* presence of illuminator */
+
+/* sn9c1xx definitions */
+/* register 0x01 */
+#define S_PWR_DN 0x01 /* sensor power down */
+#define S_PDN_INV 0x02 /* inverse pin S_PWR_DN */
+#define V_TX_EN 0x04 /* video transfer enable */
+#define LED 0x08 /* output to pin LED */
+#define SCL_SEL_OD 0x20 /* open-drain mode */
+#define SYS_SEL_48M 0x40 /* system clock 0: 24MHz, 1: 48MHz */
+/* register 0x17 */
+#define MCK_SIZE_MASK 0x1f /* sensor master clock */
+#define SEN_CLK_EN 0x20 /* enable sensor clock */
+#define DEF_EN 0x80 /* defect pixel by 0: soft, 1: hard */
+
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_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_setgamma(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgamma(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);
-static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-
-static const struct ctrl sd_ctrls[] = {
-#define BRIGHTNESS_IDX 0
- {
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setredblue(struct gspca_dev *gspca_dev);
+static void setgamma(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void sethvflip(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+static void setillum(struct gspca_dev *gspca_dev);
+static void setfreq(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Brightness",
.minimum = 0,
-#define BRIGHTNESS_MAX 0xffff
- .maximum = BRIGHTNESS_MAX,
+ .maximum = 0xff,
.step = 1,
-#define BRIGHTNESS_DEF 0x8000
- .default_value = BRIGHTNESS_DEF,
+ .default_value = 0x80,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = setbrightness
},
-#define CONTRAST_IDX 1
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -139,14 +150,11 @@ static const struct ctrl sd_ctrls[] = {
#define CONTRAST_MAX 127
.maximum = CONTRAST_MAX,
.step = 1,
-#define CONTRAST_DEF 63
- .default_value = CONTRAST_DEF,
+ .default_value = 63,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = setcontrast
},
-#define COLOR_IDX 2
- {
+[COLORS] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -154,14 +162,12 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 40,
.step = 1,
-#define COLOR_DEF 25
- .default_value = COLOR_DEF,
+#define COLORS_DEF 25
+ .default_value = COLORS_DEF,
},
- .set = sd_setcolors,
- .get = sd_getcolors,
+ .set_control = setcolors
},
-#define BLUE_BALANCE_IDX 3
- {
+[BLUE] = {
{
.id = V4L2_CID_BLUE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -169,14 +175,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 24,
.maximum = 40,
.step = 1,
-#define BLUE_BALANCE_DEF 32
- .default_value = BLUE_BALANCE_DEF,
+ .default_value = 32,
},
- .set = sd_setblue_balance,
- .get = sd_getblue_balance,
+ .set_control = setredblue
},
-#define RED_BALANCE_IDX 4
- {
+[RED] = {
{
.id = V4L2_CID_RED_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -184,14 +187,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 24,
.maximum = 40,
.step = 1,
-#define RED_BALANCE_DEF 32
- .default_value = RED_BALANCE_DEF,
+ .default_value = 32,
},
- .set = sd_setred_balance,
- .get = sd_getred_balance,
+ .set_control = setredblue
},
-#define GAMMA_IDX 5
- {
+[GAMMA] = {
{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -202,11 +202,9 @@ static const struct ctrl sd_ctrls[] = {
#define GAMMA_DEF 20
.default_value = GAMMA_DEF,
},
- .set = sd_setgamma,
- .get = sd_getgamma,
+ .set_control = setgamma
},
-#define AUTOGAIN_IDX 6
- {
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -214,15 +212,23 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTOGAIN_DEF 1
- .default_value = AUTOGAIN_DEF,
+ .default_value = 1
+ },
+ .set_control = setautogain
+ },
+[HFLIP] = {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
},
- .set = sd_setautogain,
- .get = sd_getautogain,
+ .set_control = sethvflip
},
-/* ov7630/ov7648 only */
-#define VFLIP_IDX 7
- {
+[VFLIP] = {
{
.id = V4L2_CID_VFLIP,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -230,14 +236,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define VFLIP_DEF 0
- .default_value = VFLIP_DEF,
+ .default_value = 0,
},
- .set = sd_setvflip,
- .get = sd_getvflip,
+ .set_control = sethvflip
},
-#define SHARPNESS_IDX 8
- {
+[SHARPNESS] = {
{
.id = V4L2_CID_SHARPNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -245,31 +248,24 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define SHARPNESS_DEF 90
- .default_value = SHARPNESS_DEF,
+ .default_value = 90,
},
- .set = sd_setsharpness,
- .get = sd_getsharpness,
+ .set_control = setsharpness
},
-/* mt9v111 only */
-#define INFRARED_IDX 9
- {
+[ILLUM] = {
{
- .id = V4L2_CID_INFRARED,
+ .id = V4L2_CID_ILLUMINATORS_1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Infrared",
+ .name = "Illuminator / infrared",
.minimum = 0,
.maximum = 1,
.step = 1,
-#define INFRARED_DEF 0
- .default_value = INFRARED_DEF,
+ .default_value = 0,
},
- .set = sd_setinfrared,
- .get = sd_getinfrared,
+ .set_control = setillum
},
/* ov7630/ov7648/ov7660 only */
-#define FREQ_IDX 10
- {
+[FREQ] = {
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
@@ -277,69 +273,71 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
-#define FREQ_DEF 1
- .default_value = FREQ_DEF,
+ .default_value = 1,
},
- .set = sd_setfreq,
- .get = sd_getfreq,
+ .set_control = setfreq
},
};
/* table of the disabled controls */
static const __u32 ctrl_dis[] = {
-[SENSOR_ADCM1700] = (1 << AUTOGAIN_IDX) |
- (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_GC0307] = (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_HV7131R] = (1 << INFRARED_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_MI0360] = (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_MO4000] = (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_MT9V111] = (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_OM6802] = (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_OV7630] = (1 << INFRARED_IDX),
-
-[SENSOR_OV7648] = (1 << INFRARED_IDX),
-
-[SENSOR_OV7660] = (1 << AUTOGAIN_IDX) |
- (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX),
-
-[SENSOR_PO1030] = (1 << AUTOGAIN_IDX) |
- (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_PO2030N] = (1 << AUTOGAIN_IDX) |
- (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-[SENSOR_SOI768] = (1 << AUTOGAIN_IDX) |
- (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
-
-[SENSOR_SP80708] = (1 << AUTOGAIN_IDX) |
- (1 << INFRARED_IDX) |
- (1 << VFLIP_IDX) |
- (1 << FREQ_IDX),
+[SENSOR_ADCM1700] = (1 << AUTOGAIN) |
+ (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_GC0307] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_HV7131R] = (1 << HFLIP) |
+ (1 << FREQ),
+
+[SENSOR_MI0360] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_MI0360B] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_MO4000] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_MT9V111] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_OM6802] = (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_OV7630] = (1 << HFLIP),
+
+[SENSOR_OV7648] = (1 << HFLIP),
+
+[SENSOR_OV7660] = (1 << AUTOGAIN) |
+ (1 << HFLIP) |
+ (1 << VFLIP),
+
+[SENSOR_PO1030] = (1 << AUTOGAIN) |
+ (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_PO2030N] = (1 << AUTOGAIN) |
+ (1 << FREQ),
+
+[SENSOR_SOI768] = (1 << AUTOGAIN) |
+ (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
+
+[SENSOR_SP80708] = (1 << AUTOGAIN) |
+ (1 << HFLIP) |
+ (1 << VFLIP) |
+ (1 << FREQ),
};
static const struct v4l2_pix_format cif_mode[] = {
@@ -392,7 +390,7 @@ static const u8 sn_gc0307[0x1c] = {
static const u8 sn_hv7131[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
- 0x00, 0x03, 0x64, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ 0x00, 0x03, 0x60, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
@@ -403,7 +401,7 @@ static const u8 sn_hv7131[0x1c] = {
static const u8 sn_mi0360[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
- 0x00, 0x61, 0x44, 0x00, 0x1a, 0x20, 0x20, 0x20,
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x20, 0x20, 0x20,
/* reg8 reg9 rega regb regc regd rege regf */
0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
@@ -412,6 +410,17 @@ static const u8 sn_mi0360[0x1c] = {
0x06, 0x00, 0x00, 0x00
};
+static const u8 sn_mi0360b[0x1c] = {
+/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
+ 0x00, 0x61, 0x40, 0x00, 0x1a, 0x00, 0x00, 0x00,
+/* reg8 reg9 rega regb regc regd rege regf */
+ 0x81, 0x5d, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+/* reg10 reg11 reg12 reg13 reg14 reg15 reg16 reg17 */
+ 0x03, 0x00, 0x00, 0x02, 0x0a, 0x28, 0x1e, 0x40,
+/* reg18 reg19 reg1a reg1b */
+ 0x06, 0x00, 0x00, 0x00
+};
+
static const u8 sn_mo4000[0x1c] = {
/* reg0 reg1 reg2 reg3 reg4 reg5 reg6 reg7 */
0x00, 0x23, 0x60, 0x00, 0x1a, 0x00, 0x20, 0x18,
@@ -528,6 +537,7 @@ static const u8 *sn_tb[] = {
[SENSOR_GC0307] = sn_gc0307,
[SENSOR_HV7131R] = sn_hv7131,
[SENSOR_MI0360] = sn_mi0360,
+[SENSOR_MI0360B] = sn_mi0360b,
[SENSOR_MO4000] = sn_mo4000,
[SENSOR_MT9V111] = sn_mt9v111,
[SENSOR_OM6802] = sn_om6802,
@@ -573,20 +583,23 @@ static const u8 reg84[] = {
0x3e, 0x00, 0xcd, 0x0f, 0xf7, 0x0f, /* VR VG VB */
0x00, 0x00, 0x00 /* YUV offsets */
};
+
+#define DELAY 0xdd
+
static const u8 adcm1700_sensor_init[][8] = {
{0xa0, 0x51, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb0, 0x51, 0x04, 0x08, 0x00, 0x00, 0x00, 0x10}, /* reset */
- {0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {DELAY, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xb0, 0x51, 0x04, 0x00, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {DELAY, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xb0, 0x51, 0x0c, 0xe0, 0x2e, 0x00, 0x00, 0x10},
{0xb0, 0x51, 0x10, 0x02, 0x02, 0x00, 0x00, 0x10},
{0xb0, 0x51, 0x14, 0x0e, 0x0e, 0x00, 0x00, 0x10},
{0xb0, 0x51, 0x1c, 0x00, 0x80, 0x00, 0x00, 0x10},
{0xb0, 0x51, 0x20, 0x01, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {DELAY, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xb0, 0x51, 0x04, 0x04, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ {DELAY, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
{0xb0, 0x51, 0x04, 0x01, 0x00, 0x00, 0x00, 0x10},
{0xa0, 0x51, 0xfe, 0x10, 0x00, 0x00, 0x00, 0x10},
{0xb0, 0x51, 0x14, 0x01, 0x00, 0x00, 0x00, 0x10},
@@ -630,7 +643,7 @@ static const u8 gc0307_sensor_init[][8] = {
{0xa0, 0x21, 0x0e, 0x02, 0x00, 0x00, 0x00, 0x10},
{0xa0, 0x21, 0x0f, 0xb2, 0x00, 0x00, 0x00, 0x10},
{0xa0, 0x21, 0x12, 0x70, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 10ms*/
+ {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 10ms*/
{0xa0, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa0, 0x21, 0x15, 0xb8, 0x00, 0x00, 0x00, 0x10},
{0xa0, 0x21, 0x16, 0x13, 0x00, 0x00, 0x00, 0x10},
@@ -748,6 +761,62 @@ static const u8 mi0360_sensor_init[][8] = {
{0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
{}
};
+static const u8 mi0360b_sensor_init[][8] = {
+ {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10},
+ {0xb1, 0x5d, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10},
+ {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 20ms*/
+ {0xb1, 0x5d, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /*delay 20ms*/
+ {0xd1, 0x5d, 0x01, 0x00, 0x08, 0x00, 0x16, 0x10},
+ {0xd1, 0x5d, 0x03, 0x01, 0xe2, 0x02, 0x82, 0x10},
+ {0xd1, 0x5d, 0x05, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x5d, 0x0d, 0x00, 0x02, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x0e, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x10, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x14, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x16, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x18, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x1a, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x1c, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x5d, 0x32, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x22, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x24, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x26, 0x00, 0x00, 0x00, 0x24, 0x10},
+ {0xd1, 0x5d, 0x2f, 0xf7, 0xb0, 0x00, 0x04, 0x10},
+ {0xd1, 0x5d, 0x31, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x33, 0x00, 0x00, 0x01, 0x00, 0x10},
+ {0xb1, 0x5d, 0x3d, 0x06, 0x8f, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x40, 0x01, 0xe0, 0x00, 0xd1, 0x10},
+ {0xb1, 0x5d, 0x44, 0x00, 0x82, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x58, 0x00, 0x78, 0x00, 0x43, 0x10},
+ {0xd1, 0x5d, 0x5a, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x5c, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x5e, 0x00, 0x00, 0xa3, 0x1d, 0x10},
+ {0xb1, 0x5d, 0x62, 0x04, 0x11, 0x00, 0x00, 0x10},
+
+ {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+ {0xb1, 0x5d, 0x20, 0x11, 0x01, 0x00, 0x00, 0x10},
+ {0xb1, 0x5d, 0x09, 0x00, 0x64, 0x00, 0x00, 0x10},
+ {0xd1, 0x5d, 0x2b, 0x00, 0x33, 0x00, 0xa0, 0x10},
+ {0xd1, 0x5d, 0x2d, 0x00, 0xa0, 0x00, 0x33, 0x10},
+ {}
+};
+static const u8 mi0360b_sensor_param1[][8] = {
+ {0xb1, 0x5d, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x10},
+ {0xb1, 0x5d, 0x06, 0x00, 0x53, 0x00, 0x00, 0x10},
+ {0xb1, 0x5d, 0x05, 0x00, 0x09, 0x00, 0x00, 0x10},
+ {0xb1, 0x5d, 0x09, 0x02, 0x35, 0x00, 0x00, 0x10}, /* exposure 2 */
+
+ {0xd1, 0x5d, 0x2b, 0x00, 0xd1, 0x01, 0xc9, 0x10},
+ {0xd1, 0x5d, 0x2d, 0x00, 0xed, 0x00, 0xd1, 0x10},
+ {0xb1, 0x5d, 0x07, 0x00, 0x03, 0x00, 0x00, 0x10}, /* update */
+ {0xb1, 0x5d, 0x07, 0x00, 0x02, 0x00, 0x00, 0x10}, /* sensor on */
+ {}
+};
static const u8 mo4000_sensor_init[][8] = {
{0xa1, 0x21, 0x01, 0x02, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x02, 0x00, 0x00, 0x00, 0x00, 0x10},
@@ -773,7 +842,7 @@ static const u8 mo4000_sensor_init[][8] = {
};
static const u8 mt9v111_sensor_init[][8] = {
{0xb1, 0x5c, 0x0d, 0x00, 0x01, 0x00, 0x00, 0x10}, /* reset? */
- {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+ {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
{0xb1, 0x5c, 0x0d, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xb1, 0x5c, 0x01, 0x00, 0x01, 0x00, 0x00, 0x10}, /* IFP select */
{0xb1, 0x5c, 0x08, 0x04, 0x80, 0x00, 0x00, 0x10}, /* output fmt ctrl */
@@ -861,10 +930,10 @@ static const u8 om6802_sensor_param1[][8] = {
static const u8 ov7630_sensor_init[][8] = {
{0xa1, 0x21, 0x76, 0x01, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+ {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x12, 0xc8, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+ {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
{0xa1, 0x21, 0x12, 0x48, 0x00, 0x00, 0x00, 0x10},
/* win: i2c_r from 00 to 80 */
{0xd1, 0x21, 0x03, 0x80, 0x10, 0x20, 0x80, 0x10},
@@ -918,7 +987,7 @@ static const u8 ov7630_sensor_param1[][8] = {
static const u8 ov7648_sensor_init[][8] = {
{0xa1, 0x21, 0x76, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */
- {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+ {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
{0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x21, 0x03, 0xa4, 0x30, 0x88, 0x00, 0x10},
{0xb1, 0x21, 0x11, 0x80, 0x08, 0x00, 0x00, 0x10},
@@ -967,7 +1036,7 @@ static const u8 ov7648_sensor_param1[][8] = {
static const u8 ov7660_sensor_init[][8] = {
{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset SCCB */
- {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+ {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
{0xa1, 0x21, 0x12, 0x05, 0x00, 0x00, 0x00, 0x10},
/* Outformat = rawRGB */
{0xa1, 0x21, 0x13, 0xb8, 0x00, 0x00, 0x00, 0x10}, /* init COM8 */
@@ -1063,7 +1132,7 @@ static const u8 ov7660_sensor_param1[][8] = {
static const u8 po1030_sensor_init[][8] = {
/* the sensor registers are described in m5602/m5602_po1030.h */
{0xa1, 0x6e, 0x3f, 0x20, 0x00, 0x00, 0x00, 0x10}, /* sensor reset */
- {0xdd, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
+ {DELAY, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 20ms */
{0xa1, 0x6e, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x3e, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x6e, 0x04, 0x02, 0xb1, 0x02, 0x39, 0x10},
@@ -1117,10 +1186,10 @@ static const u8 po1030_sensor_param1[][8] = {
static const u8 po2030n_sensor_init[][8] = {
{0xa1, 0x6e, 0x1e, 0x1a, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x1f, 0x99, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
+ {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
{0xa1, 0x6e, 0x1e, 0x0a, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x1f, 0x19, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
+ {DELAY, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 10ms */
{0xa1, 0x6e, 0x20, 0x44, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x04, 0x03, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x05, 0x70, 0x00, 0x00, 0x00, 0x10},
@@ -1169,7 +1238,7 @@ static const u8 po2030n_sensor_init[][8] = {
};
static const u8 po2030n_sensor_param1[][8] = {
{0xa1, 0x6e, 0x1a, 0x01, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */
+ {DELAY, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 8ms */
{0xa1, 0x6e, 0x1b, 0xf4, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x6e, 0x15, 0x04, 0x00, 0x00, 0x00, 0x10},
{0xd1, 0x6e, 0x16, 0x50, 0x40, 0x49, 0x40, 0x10},
@@ -1183,16 +1252,16 @@ static const u8 po2030n_sensor_param1[][8] = {
{0xc1, 0x6e, 0x16, 0x52, 0x40, 0x48, 0x00, 0x10},
/*after start*/
{0xa1, 0x6e, 0x15, 0x0f, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
+ {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
{0xa1, 0x6e, 0x1a, 0x05, 0x00, 0x00, 0x00, 0x10},
- {0xdd, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
+ {DELAY, 0x05, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 5ms */
{0xa1, 0x6e, 0x1b, 0x53, 0x00, 0x00, 0x00, 0x10},
{}
};
static const u8 soi768_sensor_init[][8] = {
{0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10}, /* reset */
- {0xdd, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 96ms */
+ {DELAY, 0x60, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}, /* delay 96ms */
{0xa1, 0x21, 0x12, 0x00, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x13, 0x80, 0x00, 0x00, 0x00, 0x10},
{0xa1, 0x21, 0x0f, 0x03, 0x00, 0x00, 0x00, 0x10},
@@ -1311,6 +1380,7 @@ static const u8 (*sensor_init[])[8] = {
[SENSOR_GC0307] = gc0307_sensor_init,
[SENSOR_HV7131R] = hv7131r_sensor_init,
[SENSOR_MI0360] = mi0360_sensor_init,
+[SENSOR_MI0360B] = mi0360b_sensor_init,
[SENSOR_MO4000] = mo4000_sensor_init,
[SENSOR_MT9V111] = mt9v111_sensor_init,
[SENSOR_OM6802] = om6802_sensor_init,
@@ -1327,13 +1397,17 @@ static const u8 (*sensor_init[])[8] = {
static void reg_r(struct gspca_dev *gspca_dev,
u16 value, int len)
{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
#ifdef GSPCA_DEBUG
if (len > USB_BUF_SZ) {
err("reg_r: buffer overflow");
return;
}
#endif
- usb_control_msg(gspca_dev->dev,
+ ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
0,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1341,15 +1415,23 @@ static void reg_r(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf, len,
500);
PDEBUG(D_USBI, "reg_r [%02x] -> %02x", value, gspca_dev->usb_buf[0]);
+ if (ret < 0) {
+ err("reg_r err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
}
static void reg_w1(struct gspca_dev *gspca_dev,
u16 value,
u8 data)
{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
PDEBUG(D_USBO, "reg_w1 [%04x] = %02x", value, data);
gspca_dev->usb_buf[0] = data;
- usb_control_msg(gspca_dev->dev,
+ ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1357,12 +1439,20 @@ static void reg_w1(struct gspca_dev *gspca_dev,
0,
gspca_dev->usb_buf, 1,
500);
+ if (ret < 0) {
+ err("reg_w1 err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
}
static void reg_w(struct gspca_dev *gspca_dev,
u16 value,
const u8 *buffer,
int len)
{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
PDEBUG(D_USBO, "reg_w [%04x] = %02x %02x ..",
value, buffer[0], buffer[1]);
#ifdef GSPCA_DEBUG
@@ -1372,20 +1462,27 @@ static void reg_w(struct gspca_dev *gspca_dev,
}
#endif
memcpy(gspca_dev->usb_buf, buffer, len);
- usb_control_msg(gspca_dev->dev,
+ ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
value, 0,
gspca_dev->usb_buf, len,
500);
+ if (ret < 0) {
+ err("reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
}
/* I2C write 1 byte */
static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+ if (gspca_dev->usb_err < 0)
+ return;
PDEBUG(D_USBO, "i2c_w1 [%02x] = %02x", reg, val);
switch (sd->sensor) {
case SENSOR_ADCM1700:
@@ -1404,7 +1501,7 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
gspca_dev->usb_buf[5] = 0;
gspca_dev->usb_buf[6] = 0;
gspca_dev->usb_buf[7] = 0x10;
- usb_control_msg(gspca_dev->dev,
+ ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1412,16 +1509,24 @@ static void i2c_w1(struct gspca_dev *gspca_dev, u8 reg, u8 val)
0,
gspca_dev->usb_buf, 8,
500);
+ if (ret < 0) {
+ err("i2c_w1 err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
}
/* I2C write 8 bytes */
static void i2c_w8(struct gspca_dev *gspca_dev,
const u8 *buffer)
{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
PDEBUG(D_USBO, "i2c_w8 [%02x] = %02x ..",
buffer[2], buffer[3]);
memcpy(gspca_dev->usb_buf, buffer, 8);
- usb_control_msg(gspca_dev->dev,
+ ret = usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0x08,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_INTERFACE,
@@ -1429,6 +1534,10 @@ static void i2c_w8(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf, 8,
500);
msleep(2);
+ if (ret < 0) {
+ err("i2c_w8 err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
}
/* sensor read 'len' (1..5) bytes in gspca_dev->usb_buf */
@@ -1467,7 +1576,7 @@ static void i2c_w_seq(struct gspca_dev *gspca_dev,
const u8 (*data)[8])
{
while ((*data)[0] != 0) {
- if ((*data)[0] != 0xdd)
+ if ((*data)[0] != DELAY)
i2c_w8(gspca_dev, *data);
else
msleep((*data)[1]);
@@ -1475,22 +1584,22 @@ static void i2c_w_seq(struct gspca_dev *gspca_dev,
}
}
+/* check the ID of the hv7131 sensor */
+/* this sequence is needed because it activates the sensor */
static void hv7131r_probe(struct gspca_dev *gspca_dev)
{
- i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */
+ i2c_w1(gspca_dev, 0x02, 0); /* sensor wakeup */
msleep(10);
- reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */
+ reg_w1(gspca_dev, 0x02, 0x66); /* Gpio on */
msleep(10);
- i2c_r(gspca_dev, 0, 5); /* read sensor id */
- if (gspca_dev->usb_buf[0] == 0x02
+ i2c_r(gspca_dev, 0, 5); /* read sensor id */
+ if (gspca_dev->usb_buf[0] == 0x02 /* chip ID (02 is R) */
&& gspca_dev->usb_buf[1] == 0x09
- && gspca_dev->usb_buf[2] == 0x01
- && gspca_dev->usb_buf[3] == 0x00
- && gspca_dev->usb_buf[4] == 0x00) {
- PDEBUG(D_PROBE, "Sensor sn9c102P HV7131R found");
+ && gspca_dev->usb_buf[2] == 0x01) {
+ PDEBUG(D_PROBE, "Sensor HV7131R found");
return;
}
- PDEBUG(D_PROBE, "Sensor 0x%02x 0x%02x 0x%02x - sn9c102P not found",
+ warn("Erroneous HV7131R ID 0x%02x 0x%02x 0x%02x",
gspca_dev->usb_buf[0], gspca_dev->usb_buf[1],
gspca_dev->usb_buf[2]);
}
@@ -1530,7 +1639,13 @@ static void mi0360_probe(struct gspca_dev *gspca_dev)
if (val != 0xffff)
break;
}
+ if (gspca_dev->usb_err < 0)
+ return;
switch (val) {
+ case 0x8221:
+ PDEBUG(D_PROBE, "Sensor mi0360b");
+ sd->sensor = SENSOR_MI0360B;
+ break;
case 0x823a:
PDEBUG(D_PROBE, "Sensor mt9v111");
sd->sensor = SENSOR_MT9V111;
@@ -1557,6 +1672,8 @@ static void ov7630_probe(struct gspca_dev *gspca_dev)
val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
reg_w1(gspca_dev, 0x01, 0x29);
reg_w1(gspca_dev, 0x17, 0x42);
+ if (gspca_dev->usb_err < 0)
+ return;
if (val == 0x7628) { /* soi768 */
sd->sensor = SENSOR_SOI768;
/*fixme: only valid for 0c45:613e?*/
@@ -1594,13 +1711,14 @@ static void ov7648_probe(struct gspca_dev *gspca_dev)
val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
reg_w1(gspca_dev, 0x01, 0x29);
reg_w1(gspca_dev, 0x17, 0x42);
+ if (gspca_dev->usb_err < 0)
+ return;
if (val == 0x1030) { /* po1030 */
PDEBUG(D_PROBE, "Sensor po1030");
sd->sensor = SENSOR_PO1030;
return;
}
-
- PDEBUG(D_PROBE, "Unknown sensor %04x", val);
+ err("Unknown sensor %04x", val);
}
/* 0c45:6142 sensor may be po2030n, gc0305 or gc0307 */
@@ -1632,137 +1750,13 @@ static void po2030n_probe(struct gspca_dev *gspca_dev)
val = (gspca_dev->usb_buf[3] << 8) | gspca_dev->usb_buf[4];
reg_w1(gspca_dev, 0x01, 0x29);
reg_w1(gspca_dev, 0x17, 0x42);
+ if (gspca_dev->usb_err < 0)
+ return;
if (val == 0x2030) {
PDEBUG(D_PROBE, "Sensor po2030n");
/* sd->sensor = SENSOR_PO2030N; */
} else {
- PDEBUG(D_PROBE, "Unknown sensor ID %04x", val);
- }
-}
-
-static void bridge_init(struct gspca_dev *gspca_dev,
- const u8 *sn9c1xx)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- const u8 *reg9a;
- static const u8 reg9a_def[] =
- {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
- static const u8 reg9a_spec[] =
- {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
- static const u8 regd4[] = {0x60, 0x00, 0x00};
-
- /* sensor clock already enabled in sd_init */
- /* reg_w1(gspca_dev, 0xf1, 0x00); */
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
-
- /* configure gpio */
- reg_w(gspca_dev, 0x01, &sn9c1xx[1], 2);
- reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
- reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
- switch (sd->sensor) {
- case SENSOR_GC0307:
- case SENSOR_OV7660:
- case SENSOR_PO1030:
- case SENSOR_PO2030N:
- case SENSOR_SOI768:
- case SENSOR_SP80708:
- reg9a = reg9a_spec;
- break;
- default:
- reg9a = reg9a_def;
- break;
- }
- reg_w(gspca_dev, 0x9a, reg9a, 6);
-
- reg_w(gspca_dev, 0xd4, regd4, sizeof regd4);
-
- reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
-
- switch (sd->sensor) {
- case SENSOR_ADCM1700:
- reg_w1(gspca_dev, 0x01, 0x43);
- reg_w1(gspca_dev, 0x17, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_GC0307:
- msleep(50);
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x22);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- msleep(50);
- break;
- case SENSOR_MT9V111:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x61);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_OM6802:
- msleep(10);
- reg_w1(gspca_dev, 0x02, 0x73);
- reg_w1(gspca_dev, 0x17, 0x60);
- reg_w1(gspca_dev, 0x01, 0x22);
- msleep(100);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x17, 0x64);
- reg_w1(gspca_dev, 0x17, 0x64);
- reg_w1(gspca_dev, 0x01, 0x42);
- msleep(10);
- reg_w1(gspca_dev, 0x01, 0x42);
- i2c_w8(gspca_dev, om6802_init0[0]);
- i2c_w8(gspca_dev, om6802_init0[1]);
- msleep(15);
- reg_w1(gspca_dev, 0x02, 0x71);
- msleep(150);
- break;
- case SENSOR_OV7630:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0xe2);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_OV7648:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_PO1030:
- case SENSOR_SOI768:
- reg_w1(gspca_dev, 0x01, 0x61);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x60);
- reg_w1(gspca_dev, 0x01, 0x40);
- break;
- case SENSOR_PO2030N:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- break;
- case SENSOR_OV7660:
- /* fall thru */
- case SENSOR_SP80708:
- reg_w1(gspca_dev, 0x01, 0x63);
- reg_w1(gspca_dev, 0x17, 0x20);
- reg_w1(gspca_dev, 0x01, 0x62);
- reg_w1(gspca_dev, 0x01, 0x42);
- msleep(100);
- reg_w1(gspca_dev, 0x02, 0x62);
- break;
- default:
-/* case SENSOR_HV7131R: */
-/* case SENSOR_MI0360: */
-/* case SENSOR_MO4000: */
- reg_w1(gspca_dev, 0x01, 0x43);
- reg_w1(gspca_dev, 0x17, 0x61);
- reg_w1(gspca_dev, 0x01, 0x42);
- if (sd->sensor == SENSOR_HV7131R
- && sd->bridge == BRIDGE_SN9C102P)
- hv7131r_probe(gspca_dev);
- break;
+ err("Unknown sensor ID %04x", val);
}
}
@@ -1774,7 +1768,8 @@ static int sd_config(struct gspca_dev *gspca_dev,
struct cam *cam;
sd->bridge = id->driver_info >> 16;
- sd->sensor = id->driver_info;
+ sd->sensor = id->driver_info >> 8;
+ sd->flags = id->driver_info;
cam = &gspca_dev->cam;
if (sd->sensor == SENSOR_ADCM1700) {
@@ -1785,26 +1780,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->nmodes = ARRAY_SIZE(vga_mode);
}
cam->npkt = 24; /* 24 packets per ISOC message */
+ cam->ctrls = sd->ctrls;
- sd->brightness = BRIGHTNESS_DEF;
- sd->contrast = CONTRAST_DEF;
- sd->colors = COLOR_DEF;
- sd->blue = BLUE_BALANCE_DEF;
- sd->red = RED_BALANCE_DEF;
- sd->gamma = GAMMA_DEF;
- sd->autogain = AUTOGAIN_DEF;
sd->ag_cnt = -1;
- sd->vflip = VFLIP_DEF;
- switch (sd->sensor) {
- case SENSOR_OM6802:
- sd->sharpness = 0x10;
- break;
- default:
- sd->sharpness = SHARPNESS_DEF;
- break;
- }
- sd->infrared = INFRARED_DEF;
- sd->freq = FREQ_DEF;
sd->quality = QUALITY_DEF;
sd->jpegqual = 80;
@@ -1816,58 +1794,65 @@ static int sd_init(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
const u8 *sn9c1xx;
- u8 regGpio[] = { 0x29, 0x74 };
+ u8 regGpio[] = { 0x29, 0x74 }; /* with audio */
u8 regF1;
/* setup a selector by bridge */
reg_w1(gspca_dev, 0xf1, 0x01);
reg_r(gspca_dev, 0x00, 1);
- reg_w1(gspca_dev, 0xf1, gspca_dev->usb_buf[0]);
+ reg_w1(gspca_dev, 0xf1, 0x00);
reg_r(gspca_dev, 0x00, 1); /* get sonix chip id */
regF1 = gspca_dev->usb_buf[0];
+ if (gspca_dev->usb_err < 0)
+ return gspca_dev->usb_err;
PDEBUG(D_PROBE, "Sonix chip id: %02x", regF1);
switch (sd->bridge) {
case BRIDGE_SN9C102P:
- if (regF1 != 0x11)
- return -ENODEV;
- reg_w1(gspca_dev, 0x02, regGpio[1]);
- break;
case BRIDGE_SN9C105:
if (regF1 != 0x11)
return -ENODEV;
- if (sd->sensor == SENSOR_MI0360)
- mi0360_probe(gspca_dev);
- reg_w(gspca_dev, 0x01, regGpio, 2);
- break;
- case BRIDGE_SN9C120:
- if (regF1 != 0x12)
- return -ENODEV;
- switch (sd->sensor) {
- case SENSOR_MI0360:
- mi0360_probe(gspca_dev);
- break;
- case SENSOR_OV7630:
- ov7630_probe(gspca_dev);
- break;
- case SENSOR_OV7648:
- ov7648_probe(gspca_dev);
- break;
- case SENSOR_PO2030N:
- po2030n_probe(gspca_dev);
- break;
- }
- regGpio[1] = 0x70;
- reg_w(gspca_dev, 0x01, regGpio, 2);
break;
default:
/* case BRIDGE_SN9C110: */
-/* case BRIDGE_SN9C325: */
+/* case BRIDGE_SN9C120: */
if (regF1 != 0x12)
return -ENODEV;
+ }
+
+ switch (sd->sensor) {
+ case SENSOR_MI0360:
+ mi0360_probe(gspca_dev);
+ break;
+ case SENSOR_OV7630:
+ ov7630_probe(gspca_dev);
+ break;
+ case SENSOR_OV7648:
+ ov7648_probe(gspca_dev);
+ break;
+ case SENSOR_PO2030N:
+ po2030n_probe(gspca_dev);
+ break;
+ }
+
+ switch (sd->bridge) {
+ case BRIDGE_SN9C102P:
+ reg_w1(gspca_dev, 0x02, regGpio[1]);
+ break;
+ case BRIDGE_SN9C105:
+ reg_w(gspca_dev, 0x01, regGpio, 2);
+ break;
+ case BRIDGE_SN9C110:
reg_w1(gspca_dev, 0x02, 0x62);
break;
+ case BRIDGE_SN9C120:
+ regGpio[1] = 0x70; /* no audio */
+ reg_w(gspca_dev, 0x01, regGpio, 2);
+ break;
}
+ if (sd->sensor == SENSOR_OM6802)
+ sd->ctrls[SHARPNESS].def = 0x10;
+
/* Note we do not disable the sensor clock here (power saving mode),
as that also disables the button on the cam. */
reg_w1(gspca_dev, 0xf1, 0x00);
@@ -1877,8 +1862,10 @@ static int sd_init(struct gspca_dev *gspca_dev)
sd->i2c_addr = sn9c1xx[9];
gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
+ if (!(sd->flags & F_ILLUM))
+ gspca_dev->ctrl_dis |= (1 << ILLUM);
- return 0;
+ return gspca_dev->usb_err;
}
static u32 setexposure(struct gspca_dev *gspca_dev,
@@ -1909,7 +1896,8 @@ static u32 setexposure(struct gspca_dev *gspca_dev,
i2c_w8(gspca_dev, Expodoit);
break;
}
- case SENSOR_MI0360: {
+ case SENSOR_MI0360:
+ case SENSOR_MI0360B: {
u8 expoMi[] = /* exposure 0x0635 -> 4 fp/s 0x10 */
{ 0xb1, 0x5d, 0x09, 0x00, 0x00, 0x00, 0x00, 0x16 };
static const u8 doit[] = /* update sensor */
@@ -1988,16 +1976,18 @@ static void setbrightness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
unsigned int expo;
+ int brightness;
u8 k2;
- k2 = ((int) sd->brightness - 0x8000) >> 10;
+ brightness = sd->ctrls[BRIGHTNESS].val;
+ k2 = (brightness - 0x80) >> 2;
switch (sd->sensor) {
case SENSOR_ADCM1700:
if (k2 > 0x1f)
k2 = 0; /* only positive Y offset */
break;
case SENSOR_HV7131R:
- expo = sd->brightness << 4;
+ expo = brightness << 12;
if (expo > 0x002dc6c0)
expo = 0x002dc6c0;
else if (expo < 0x02a0)
@@ -2006,18 +1996,22 @@ static void setbrightness(struct gspca_dev *gspca_dev)
break;
case SENSOR_MI0360:
case SENSOR_MO4000:
- expo = sd->brightness >> 4;
+ expo = brightness << 4;
+ sd->exposure = setexposure(gspca_dev, expo);
+ break;
+ case SENSOR_MI0360B:
+ expo = brightness << 2;
sd->exposure = setexposure(gspca_dev, expo);
break;
case SENSOR_GC0307:
case SENSOR_MT9V111:
- expo = sd->brightness >> 8;
+ expo = brightness;
sd->exposure = setexposure(gspca_dev, expo);
return; /* don't set the Y offset */
case SENSOR_OM6802:
- expo = sd->brightness >> 6;
+ expo = brightness << 2;
sd->exposure = setexposure(gspca_dev, expo);
- k2 = sd->brightness >> 11;
+ k2 = brightness >> 3;
break;
}
@@ -2030,7 +2024,8 @@ static void setcontrast(struct gspca_dev *gspca_dev)
u8 k2;
u8 contrast[6];
- k2 = sd->contrast * 0x30 / (CONTRAST_MAX + 1) + 0x10; /* 10..40 */
+ k2 = sd->ctrls[CONTRAST].val * 0x30 / (CONTRAST_MAX + 1)
+ + 0x10; /* 10..40 */
contrast[0] = (k2 + 1) / 2; /* red */
contrast[1] = 0;
contrast[2] = k2; /* green */
@@ -2043,15 +2038,25 @@ static void setcontrast(struct gspca_dev *gspca_dev)
static void setcolors(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i, v;
+ int i, v, colors;
+ const s16 *uv;
u8 reg8a[12]; /* U & V gains */
- static const s16 uv[6] = { /* same as reg84 in signed decimal */
+ static const s16 uv_com[6] = { /* same as reg84 in signed decimal */
-24, -38, 64, /* UR UG UB */
62, -51, -9 /* VR VG VB */
};
+ static const s16 uv_mi0360b[6] = {
+ -20, -38, 64, /* UR UG UB */
+ 60, -51, -9 /* VR VG VB */
+ };
+ colors = sd->ctrls[COLORS].val;
+ if (sd->sensor == SENSOR_MI0360B)
+ uv = uv_mi0360b;
+ else
+ uv = uv_com;
for (i = 0; i < 6; i++) {
- v = uv[i] * sd->colors / COLOR_DEF;
+ v = uv[i] * colors / COLORS_DEF;
reg8a[i * 2] = v;
reg8a[i * 2 + 1] = (v >> 8) & 0x0f;
}
@@ -2062,15 +2067,15 @@ 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, 0x05, sd->ctrls[RED].val);
/* reg_w1(gspca_dev, 0x07, 32); */
- reg_w1(gspca_dev, 0x06, sd->blue);
+ reg_w1(gspca_dev, 0x06, sd->ctrls[BLUE].val);
}
static void setgamma(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int i;
+ int i, val;
u8 gamma[17];
const u8 *gamma_base;
static const u8 delta[17] = {
@@ -2083,6 +2088,7 @@ static void setgamma(struct gspca_dev *gspca_dev)
gamma_base = gamma_spec_0;
break;
case SENSOR_HV7131R:
+ case SENSOR_MI0360B:
case SENSOR_MT9V111:
gamma_base = gamma_spec_1;
break;
@@ -2097,9 +2103,10 @@ static void setgamma(struct gspca_dev *gspca_dev)
break;
}
+ val = sd->ctrls[GAMMA].val;
for (i = 0; i < sizeof gamma; i++)
gamma[i] = gamma_base[i]
- + delta[i] * (sd->gamma - GAMMA_DEF) / 32;
+ + delta[i] * (val - GAMMA_DEF) / 32;
reg_w(gspca_dev, 0x20, gamma, sizeof gamma);
}
@@ -2107,7 +2114,7 @@ static void setautogain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+ if (gspca_dev->ctrl_dis & (1 << AUTOGAIN))
return;
switch (sd->sensor) {
case SENSOR_OV7630:
@@ -2118,74 +2125,103 @@ static void setautogain(struct gspca_dev *gspca_dev)
comb = 0xc0;
else
comb = 0xa0;
- if (sd->autogain)
+ if (sd->ctrls[AUTOGAIN].val)
comb |= 0x03;
i2c_w1(&sd->gspca_dev, 0x13, comb);
return;
}
}
- if (sd->autogain)
+ if (sd->ctrls[AUTOGAIN].val)
sd->ag_cnt = AG_CNT_START;
else
sd->ag_cnt = -1;
}
-/* hv7131r/ov7630/ov7648 only */
-static void setvflip(struct sd *sd)
+static void sethvflip(struct gspca_dev *gspca_dev)
{
+ struct sd *sd = (struct sd *) gspca_dev;
u8 comn;
- if (sd->gspca_dev.ctrl_dis & (1 << VFLIP_IDX))
- return;
switch (sd->sensor) {
case SENSOR_HV7131R:
comn = 0x18; /* clkdiv = 1, ablcen = 1 */
- if (sd->vflip)
+ if (sd->ctrls[VFLIP].val)
comn |= 0x01;
- i2c_w1(&sd->gspca_dev, 0x01, comn); /* sctra */
+ i2c_w1(gspca_dev, 0x01, comn); /* sctra */
break;
case SENSOR_OV7630:
comn = 0x02;
- if (!sd->vflip)
+ if (!sd->ctrls[VFLIP].val)
comn |= 0x80;
- i2c_w1(&sd->gspca_dev, 0x75, comn);
+ i2c_w1(gspca_dev, 0x75, comn);
break;
- default:
-/* case SENSOR_OV7648: */
+ case SENSOR_OV7648:
comn = 0x06;
- if (sd->vflip)
+ if (sd->ctrls[VFLIP].val)
comn |= 0x80;
- i2c_w1(&sd->gspca_dev, 0x75, comn);
+ i2c_w1(gspca_dev, 0x75, comn);
+ break;
+ case SENSOR_PO2030N:
+ /* Reg. 0x1E: Timing Generator Control Register 2 (Tgcontrol2)
+ * (reset value: 0x0A)
+ * bit7: HM: Horizontal Mirror: 0: disable, 1: enable
+ * bit6: VM: Vertical Mirror: 0: disable, 1: enable
+ * bit5: ST: Shutter Selection: 0: electrical, 1: mechanical
+ * bit4: FT: Single Frame Transfer: 0: disable, 1: enable
+ * bit3-0: X
+ */
+ comn = 0x0a;
+ if (sd->ctrls[HFLIP].val)
+ comn |= 0x80;
+ if (sd->ctrls[VFLIP].val)
+ comn |= 0x40;
+ i2c_w1(&sd->gspca_dev, 0x1e, comn);
break;
}
}
-static void setsharpness(struct sd *sd)
+static void setsharpness(struct gspca_dev *gspca_dev)
{
- reg_w1(&sd->gspca_dev, 0x99, sd->sharpness);
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_w1(gspca_dev, 0x99, sd->ctrls[SHARPNESS].val);
}
-static void setinfrared(struct sd *sd)
+static void setillum(struct gspca_dev *gspca_dev)
{
- if (sd->gspca_dev.ctrl_dis & (1 << INFRARED_IDX))
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (gspca_dev->ctrl_dis & (1 << ILLUM))
return;
-/*fixme: different sequence for StarCam Clip and StarCam 370i */
-/* Clip */
- i2c_w1(&sd->gspca_dev, 0x02, /* gpio */
- sd->infrared ? 0x66 : 0x64);
+ switch (sd->sensor) {
+ case SENSOR_ADCM1700:
+ reg_w1(gspca_dev, 0x02, /* gpio */
+ sd->ctrls[ILLUM].val ? 0x64 : 0x60);
+ break;
+ case SENSOR_MT9V111:
+ if (starcam)
+ reg_w1(gspca_dev, 0x02,
+ sd->ctrls[ILLUM].val ?
+ 0x55 : 0x54); /* 370i */
+ else
+ reg_w1(gspca_dev, 0x02,
+ sd->ctrls[ILLUM].val ?
+ 0x66 : 0x64); /* Clip */
+ break;
+ }
}
static void setfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- if (gspca_dev->ctrl_dis & (1 << FREQ_IDX))
+ if (gspca_dev->ctrl_dis & (1 << FREQ))
return;
if (sd->sensor == SENSOR_OV7660) {
u8 com8;
com8 = 0xdf; /* auto gain/wb/expo */
- switch (sd->freq) {
+ switch (sd->ctrls[FREQ].val) {
case 0: /* Banding filter disabled */
i2c_w1(gspca_dev, 0x13, com8 | 0x20);
break;
@@ -2213,7 +2249,7 @@ static void setfreq(struct gspca_dev *gspca_dev)
break;
}
- switch (sd->freq) {
+ switch (sd->ctrls[FREQ].val) {
case 0: /* Banding filter disabled */
break;
case 1: /* 50 hz (filter on and framerate adj) */
@@ -2274,10 +2310,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i;
- u8 reg1, reg2, reg17;
+ u8 reg01, reg17;
+ u8 reg0102[2];
const u8 *sn9c1xx;
const u8 (*init)[8];
+ const u8 *reg9a;
int mode;
+ static const u8 reg9a_def[] =
+ {0x00, 0x40, 0x20, 0x00, 0x00, 0x00};
+ static const u8 reg9a_spec[] =
+ {0x00, 0x40, 0x38, 0x30, 0x00, 0x20};
+ static const u8 regd4[] = {0x60, 0x00, 0x00};
static const u8 C0[] = { 0x2d, 0x2d, 0x3a, 0x05, 0x04, 0x3f };
static const u8 CA[] = { 0x28, 0xd8, 0x14, 0xec };
static const u8 CA_adcm1700[] =
@@ -2299,27 +2342,88 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* initialize the bridge */
sn9c1xx = sn_tb[sd->sensor];
- bridge_init(gspca_dev, sn9c1xx);
- /* initialize the sensor */
- i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
+ /* sensor clock already enabled in sd_init */
+ /* reg_w1(gspca_dev, 0xf1, 0x00); */
+ reg01 = sn9c1xx[1];
+ if (sd->flags & F_PDN_INV)
+ reg01 ^= S_PDN_INV; /* power down inverted */
+ reg_w1(gspca_dev, 0x01, reg01);
+ /* configure gpio */
+ reg0102[0] = reg01;
+ reg0102[1] = sn9c1xx[2];
+ if (gspca_dev->audio)
+ reg0102[1] |= 0x04; /* keep the audio connection */
+ reg_w(gspca_dev, 0x01, reg0102, 2);
+ reg_w(gspca_dev, 0x08, &sn9c1xx[8], 2);
+ reg_w(gspca_dev, 0x17, &sn9c1xx[0x17], 5);
switch (sd->sensor) {
- case SENSOR_ADCM1700:
- reg2 = 0x60;
+ case SENSOR_GC0307:
+ case SENSOR_OV7660:
+ case SENSOR_PO1030:
+ case SENSOR_PO2030N:
+ case SENSOR_SOI768:
+ case SENSOR_SP80708:
+ reg9a = reg9a_spec;
+ break;
+ default:
+ reg9a = reg9a_def;
+ break;
+ }
+ reg_w(gspca_dev, 0x9a, reg9a, 6);
+
+ reg_w(gspca_dev, 0xd4, regd4, sizeof regd4);
+
+ reg_w(gspca_dev, 0x03, &sn9c1xx[3], 0x0f);
+
+ reg17 = sn9c1xx[0x17];
+ switch (sd->sensor) {
+ case SENSOR_GC0307:
+ msleep(50); /*fixme: is it useful? */
break;
case SENSOR_OM6802:
- reg2 = 0x71;
+ msleep(10);
+ reg_w1(gspca_dev, 0x02, 0x73);
+ reg17 |= SEN_CLK_EN;
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg_w1(gspca_dev, 0x01, 0x22);
+ msleep(100);
+ reg01 = SCL_SEL_OD | S_PDN_INV;
+ reg17 &= MCK_SIZE_MASK;
+ reg17 |= 0x04; /* clock / 4 */
break;
- case SENSOR_SP80708:
- reg2 = 0x62;
+ }
+ reg01 |= SYS_SEL_48M;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg17 |= SEN_CLK_EN;
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg01 &= ~S_PWR_DN; /* sensor power on */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 &= ~SYS_SEL_48M;
+ reg_w1(gspca_dev, 0x01, reg01);
+
+ switch (sd->sensor) {
+ case SENSOR_HV7131R:
+ hv7131r_probe(gspca_dev); /*fixme: is it useful? */
break;
- default:
- reg2 = 0x40;
+ case SENSOR_OM6802:
+ msleep(10);
+ reg_w1(gspca_dev, 0x01, reg01);
+ i2c_w8(gspca_dev, om6802_init0[0]);
+ i2c_w8(gspca_dev, om6802_init0[1]);
+ msleep(15);
+ reg_w1(gspca_dev, 0x02, 0x71);
+ msleep(150);
+ break;
+ case SENSOR_SP80708:
+ msleep(100);
+ reg_w1(gspca_dev, 0x02, 0x62);
break;
}
- reg_w1(gspca_dev, 0x02, reg2);
- reg_w1(gspca_dev, 0x02, reg2);
+
+ /* initialize the sensor */
+ i2c_w_seq(gspca_dev, sensor_init[sd->sensor]);
reg_w1(gspca_dev, 0x15, sn9c1xx[0x15]);
reg_w1(gspca_dev, 0x16, sn9c1xx[0x16]);
@@ -2344,29 +2448,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
reg_w1(gspca_dev, 0x18, sn9c1xx[0x18]);
switch (sd->sensor) {
- case SENSOR_GC0307:
- reg17 = 0xa2;
- break;
- case SENSOR_MT9V111:
- reg17 = 0xe0;
- break;
- case SENSOR_ADCM1700:
- case SENSOR_OV7630:
- reg17 = 0xe2;
- break;
- case SENSOR_OV7648:
- reg17 = 0x20;
- break;
- case SENSOR_OV7660:
- case SENSOR_SOI768:
- reg17 = 0xa0;
- break;
- case SENSOR_PO1030:
- case SENSOR_PO2030N:
- reg17 = 0xa0;
+ case SENSOR_OM6802:
+/* case SENSOR_OV7648: * fixme: sometimes */
break;
default:
- reg17 = 0x60;
+ reg17 |= DEF_EN;
break;
}
reg_w1(gspca_dev, 0x17, reg17);
@@ -2389,6 +2475,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
case SENSOR_GC0307:
case SENSOR_MT9V111:
+ case SENSOR_MI0360B:
reg_w1(gspca_dev, 0x9a, 0x07);
break;
case SENSOR_OV7630:
@@ -2403,7 +2490,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, 0x9a, 0x08);
break;
}
- setsharpness(sd);
+ setsharpness(gspca_dev);
reg_w(gspca_dev, 0x84, reg84, sizeof reg84);
reg_w1(gspca_dev, 0x05, 0x20); /* red */
@@ -2412,91 +2499,67 @@ static int sd_start(struct gspca_dev *gspca_dev)
init = NULL;
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
- if (mode)
- reg1 = 0x46; /* 320x240: clk 48Mhz, video trf enable */
- else
- reg1 = 0x06; /* 640x480: clk 24Mhz, video trf enable */
- reg17 = 0x61; /* 0x:20: enable sensor clock */
+ reg01 |= SYS_SEL_48M | V_TX_EN;
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x02; /* clock / 2 */
switch (sd->sensor) {
case SENSOR_ADCM1700:
init = adcm1700_sensor_param1;
- reg1 = 0x46;
- reg17 = 0xe2;
break;
case SENSOR_GC0307:
init = gc0307_sensor_param1;
- reg17 = 0xa2;
- reg1 = 0x44;
+ break;
+ case SENSOR_HV7131R:
+ case SENSOR_MI0360:
+ if (mode)
+ reg01 |= SYS_SEL_48M; /* 320x240: clk 48Mhz */
+ else
+ reg01 &= ~SYS_SEL_48M; /* 640x480: clk 24Mhz */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
+ break;
+ case SENSOR_MI0360B:
+ init = mi0360b_sensor_param1;
break;
case SENSOR_MO4000:
- if (mode) {
-/* reg1 = 0x46; * 320 clk 48Mhz 60fp/s */
- reg1 = 0x06; /* clk 24Mz */
- } else {
- reg17 = 0x22; /* 640 MCKSIZE */
-/* reg1 = 0x06; * 640 clk 24Mz (done) */
+ if (mode) { /* if 320x240 */
+ reg01 &= ~SYS_SEL_48M; /* clk 24Mz */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
}
break;
case SENSOR_MT9V111:
init = mt9v111_sensor_param1;
- if (mode) {
- reg1 = 0x04; /* 320 clk 48Mhz */
- } else {
-/* reg1 = 0x06; * 640 clk 24Mz (done) */
- reg17 = 0xc2;
- }
break;
case SENSOR_OM6802:
init = om6802_sensor_param1;
- reg17 = 0x64; /* 640 MCKSIZE */
+ if (!mode) { /* if 640x480 */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x04; /* clock / 4 */
+ }
break;
case SENSOR_OV7630:
init = ov7630_sensor_param1;
- reg17 = 0xe2;
- reg1 = 0x44;
break;
case SENSOR_OV7648:
init = ov7648_sensor_param1;
- reg17 = 0x21;
-/* reg1 = 0x42; * 42 - 46? */
+ reg17 &= ~MCK_SIZE_MASK;
+ reg17 |= 0x01; /* clock / 1 */
break;
case SENSOR_OV7660:
init = ov7660_sensor_param1;
- 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 */
- }
break;
case SENSOR_PO1030:
init = po1030_sensor_param1;
- reg17 = 0xa2;
- reg1 = 0x44;
break;
case SENSOR_PO2030N:
init = po2030n_sensor_param1;
- reg1 = 0x46;
- reg17 = 0xa2;
break;
case SENSOR_SOI768:
init = soi768_sensor_param1;
- reg1 = 0x44;
- reg17 = 0xa2;
break;
- default:
-/* case SENSOR_SP80708: */
+ case SENSOR_SP80708:
init = sp80708_sensor_param1;
- if (mode) {
-/*?? reg1 = 0x04; * 320 clk 48Mhz */
- } else {
- reg1 = 0x46; /* 640 clk 48Mz */
- reg17 = 0xa2;
- }
break;
}
@@ -2540,22 +2603,23 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
}
-
/* here change size mode 0 -> VGA; 1 -> CIF */
sd->reg18 = sn9c1xx[0x18] | (mode << 4) | 0x40;
reg_w1(gspca_dev, 0x18, sd->reg18);
setjpegqual(gspca_dev);
reg_w1(gspca_dev, 0x17, reg17);
- reg_w1(gspca_dev, 0x01, reg1);
+ reg_w1(gspca_dev, 0x01, reg01);
+ sd->reg01 = reg01;
+ sd->reg17 = reg17;
- setvflip(sd);
+ sethvflip(gspca_dev);
setbrightness(gspca_dev);
setcontrast(gspca_dev);
setcolors(gspca_dev);
setautogain(gspca_dev);
setfreq(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
@@ -2569,40 +2633,64 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
{ 0xa1, 0x21, 0x76, 0x20, 0x00, 0x00, 0x00, 0x10 };
static const u8 stopsoi768[] =
{ 0xa1, 0x21, 0x12, 0x80, 0x00, 0x00, 0x00, 0x10 };
- u8 data;
- const u8 *sn9c1xx;
+ u8 reg01;
+ u8 reg17;
- data = 0x0b;
+ reg01 = sd->reg01;
+ reg17 = sd->reg17 & ~SEN_CLK_EN;
switch (sd->sensor) {
+ case SENSOR_ADCM1700:
case SENSOR_GC0307:
- data = 0x29;
+ case SENSOR_PO2030N:
+ case SENSOR_SP80708:
+ reg01 |= LED;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 &= ~(LED | V_TX_EN);
+ reg_w1(gspca_dev, 0x01, reg01);
+/* reg_w1(gspca_dev, 0x02, 0x??); * LED off ? */
break;
case SENSOR_HV7131R:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
i2c_w8(gspca_dev, stophv7131);
- data = 0x2b;
break;
case SENSOR_MI0360:
+ case SENSOR_MI0360B:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+/* reg_w1(gspca_dev, 0x02, 0x40); * LED off ? */
i2c_w8(gspca_dev, stopmi0360);
- data = 0x29;
break;
- case SENSOR_OV7648:
- i2c_w8(gspca_dev, stopov7648);
- /* fall thru */
case SENSOR_MT9V111:
- case SENSOR_OV7630:
+ case SENSOR_OM6802:
case SENSOR_PO1030:
- data = 0x29;
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+ break;
+ case SENSOR_OV7630:
+ case SENSOR_OV7648:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
+ i2c_w8(gspca_dev, stopov7648);
+ break;
+ case SENSOR_OV7660:
+ reg01 &= ~V_TX_EN;
+ reg_w1(gspca_dev, 0x01, reg01);
break;
case SENSOR_SOI768:
i2c_w8(gspca_dev, stopsoi768);
- data = 0x29;
break;
}
- sn9c1xx = sn_tb[sd->sensor];
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
- reg_w1(gspca_dev, 0x17, sn9c1xx[0x17]);
- reg_w1(gspca_dev, 0x01, sn9c1xx[1]);
- reg_w1(gspca_dev, 0x01, data);
+
+ reg01 |= SCL_SEL_OD;
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 |= S_PWR_DN; /* sensor power down */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg_w1(gspca_dev, 0x17, reg17);
+ reg01 &= ~SYS_SEL_48M; /* clock 24MHz */
+ reg_w1(gspca_dev, 0x01, reg01);
+ reg01 |= LED;
+ reg_w1(gspca_dev, 0x01, reg01);
/* Don't disable sensor clock as that disables the button on the cam */
/* reg_w1(gspca_dev, 0xf1, 0x01); */
}
@@ -2655,6 +2743,7 @@ static void do_autogain(struct gspca_dev *gspca_dev)
default:
/* case SENSOR_MO4000: */
/* case SENSOR_MI0360: */
+/* case SENSOR_MI0360B: */
/* case SENSOR_MT9V111: */
expotimes = sd->exposure;
expotimes += (luma_mean - delta) >> 6;
@@ -2677,236 +2766,52 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
struct sd *sd = (struct sd *) gspca_dev;
int sof, avg_lum;
- sof = len - 64;
- if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9) {
+ /* the image ends on a 64 bytes block starting with
+ * ff d9 ff ff 00 c4 c4 96
+ * and followed by various information including luminosity */
+ /* this block may be splitted between two packets */
+ /* a new image always starts in a new packet */
+ switch (gspca_dev->last_packet_type) {
+ case DISCARD_PACKET: /* restart image building */
+ sof = len - 64;
+ if (sof >= 0 && data[sof] == 0xff && data[sof + 1] == 0xd9)
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+ return;
+ case LAST_PACKET: /* put the JPEG 422 header */
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
+ break;
+ }
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
- /* end of frame */
- gspca_frame_add(gspca_dev, LAST_PACKET,
- data, sof + 2);
- if (sd->ag_cnt < 0)
- return;
+ data = gspca_dev->image;
+ if (data == NULL)
+ return;
+ sof = gspca_dev->image_len - 64;
+ if (data[sof] != 0xff
+ || data[sof + 1] != 0xd9)
+ return;
+
+ /* end of image found - remove the trailing data */
+ gspca_dev->image_len = sof + 2;
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+ if (sd->ag_cnt < 0)
+ return;
/* w1 w2 w3 */
/* w4 w5 w6 */
/* w7 w8 */
/* w4 */
- avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
+ avg_lum = ((data[sof + 29] << 8) | data[sof + 30]) >> 6;
/* w6 */
- avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
+ avg_lum += ((data[sof + 33] << 8) | data[sof + 34]) >> 6;
/* w2 */
- avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
+ avg_lum += ((data[sof + 25] << 8) | data[sof + 26]) >> 6;
/* w8 */
- avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
+ avg_lum += ((data[sof + 37] << 8) | data[sof + 38]) >> 6;
/* w5 */
- avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
- avg_lum >>= 4;
- atomic_set(&sd->avg_lum, avg_lum);
- return;
- }
- if (gspca_dev->last_packet_type == LAST_PACKET) {
-
- /* put the JPEG 422 header */
- gspca_frame_add(gspca_dev, FIRST_PACKET,
- sd->jpeg_hdr, JPEG_HDR_SZ);
- }
- gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
-}
-
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightness(gspca_dev);
- return 0;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->brightness;
- return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->colors = val;
- if (gspca_dev->streaming)
- setcolors(gspca_dev);
- return 0;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->colors;
- 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_setgamma(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gamma = val;
- if (gspca_dev->streaming)
- setgamma(gspca_dev);
- return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->gamma;
- return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->autogain = val;
- if (gspca_dev->streaming)
- setautogain(gspca_dev);
- return 0;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autogain;
- return 0;
-}
-
-static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->sharpness = val;
- if (gspca_dev->streaming)
- setsharpness(sd);
- 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_setvflip(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->vflip = val;
- if (gspca_dev->streaming)
- setvflip(sd);
- 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;
-}
-
-static int sd_setinfrared(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->infrared = val;
- if (gspca_dev->streaming)
- setinfrared(sd);
- return 0;
-}
-
-static int sd_getinfrared(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->infrared;
- return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->freq = val;
- if (gspca_dev->streaming)
- setfreq(gspca_dev);
- return 0;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->freq;
- return 0;
+ avg_lum += ((data[sof + 31] << 8) | data[sof + 32]) >> 4;
+ avg_lum >>= 4;
+ atomic_set(&sd->avg_lum, avg_lum);
}
static int sd_set_jcomp(struct gspca_dev *gspca_dev,
@@ -2958,7 +2863,7 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
return -EINVAL;
}
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrupt packet length */
@@ -2981,7 +2886,7 @@ static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
+ .nctrls = NCTRLS,
.config = sd_config,
.init = sd_init,
.start = sd_start,
@@ -2991,7 +2896,7 @@ static const struct sd_desc sd_desc = {
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
.querymenu = sd_querymenu,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
@@ -2999,14 +2904,16 @@ static const struct sd_desc sd_desc = {
/* -- module initialisation -- */
#define BS(bridge, sensor) \
.driver_info = (BRIDGE_ ## bridge << 16) \
- | SENSOR_ ## sensor
-static const __devinitdata struct usb_device_id device_table[] = {
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
+ | (SENSOR_ ## sensor << 8)
+#define BSF(bridge, sensor, flags) \
+ .driver_info = (BRIDGE_ ## bridge << 16) \
+ | (SENSOR_ ## sensor << 8) \
+ | (flags)
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0458, 0x7025), BS(SN9C120, MI0360)},
{USB_DEVICE(0x0458, 0x702e), BS(SN9C120, OV7660)},
-#endif
- {USB_DEVICE(0x045e, 0x00f5), BS(SN9C105, OV7660)},
- {USB_DEVICE(0x045e, 0x00f7), BS(SN9C105, OV7660)},
+ {USB_DEVICE(0x045e, 0x00f5), BSF(SN9C105, OV7660, F_PDN_INV)},
+ {USB_DEVICE(0x045e, 0x00f7), BSF(SN9C105, OV7660, F_PDN_INV)},
{USB_DEVICE(0x0471, 0x0327), BS(SN9C105, MI0360)},
{USB_DEVICE(0x0471, 0x0328), BS(SN9C105, MI0360)},
{USB_DEVICE(0x0471, 0x0330), BS(SN9C105, MI0360)},
@@ -3018,20 +2925,21 @@ static const __devinitdata struct usb_device_id device_table[] = {
/* {USB_DEVICE(0x0c45, 0x607b), BS(SN9C102P, OV7660)}, */
{USB_DEVICE(0x0c45, 0x607c), BS(SN9C102P, HV7131R)},
/* {USB_DEVICE(0x0c45, 0x607e), BS(SN9C102P, OV7630)}, */
- {USB_DEVICE(0x0c45, 0x60c0), BS(SN9C105, MI0360)},
+ {USB_DEVICE(0x0c45, 0x60c0), BSF(SN9C105, MI0360, F_ILLUM)},
+ /* or MT9V111 */
/* {USB_DEVICE(0x0c45, 0x60c2), BS(SN9C105, P1030xC)}, */
/* {USB_DEVICE(0x0c45, 0x60c8), BS(SN9C105, OM6802)}, */
/* {USB_DEVICE(0x0c45, 0x60cc), BS(SN9C105, HV7131GP)}, */
+ {USB_DEVICE(0x0c45, 0x60ce), BS(SN9C105, SP80708)},
{USB_DEVICE(0x0c45, 0x60ec), BS(SN9C105, MO4000)},
/* {USB_DEVICE(0x0c45, 0x60ef), BS(SN9C105, ICM105C)}, */
/* {USB_DEVICE(0x0c45, 0x60fa), BS(SN9C105, OV7648)}, */
+/* {USB_DEVICE(0x0c45, 0x60f2), BS(SN9C105, OV7660)}, */
{USB_DEVICE(0x0c45, 0x60fb), BS(SN9C105, OV7660)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x60fc), BS(SN9C105, HV7131R)},
{USB_DEVICE(0x0c45, 0x60fe), BS(SN9C105, OV7630)},
-#endif
{USB_DEVICE(0x0c45, 0x6100), BS(SN9C120, MI0360)}, /*sn9c128*/
-/* {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, P1030xC)}, */
+ {USB_DEVICE(0x0c45, 0x6102), BS(SN9C120, PO2030N)}, /* /GC0305*/
/* {USB_DEVICE(0x0c45, 0x6108), BS(SN9C120, OM6802)}, */
{USB_DEVICE(0x0c45, 0x610a), BS(SN9C120, OV7648)}, /*sn9c128*/
{USB_DEVICE(0x0c45, 0x610b), BS(SN9C120, OV7660)}, /*sn9c128*/
@@ -3043,24 +2951,24 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x0c45, 0x6128), BS(SN9C120, OM6802)}, /*sn9c325?*/
/*bw600.inf:*/
{USB_DEVICE(0x0c45, 0x612a), BS(SN9C120, OV7648)}, /*sn9c325?*/
+ {USB_DEVICE(0x0c45, 0x612b), BS(SN9C110, ADCM1700)},
{USB_DEVICE(0x0c45, 0x612c), BS(SN9C110, MO4000)},
{USB_DEVICE(0x0c45, 0x612e), BS(SN9C110, OV7630)},
/* {USB_DEVICE(0x0c45, 0x612f), BS(SN9C110, ICM105C)}, */
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x6130), BS(SN9C120, MI0360)},
-#endif
+ /* or MT9V111 / MI0360B */
/* {USB_DEVICE(0x0c45, 0x6132), BS(SN9C120, OV7670)}, */
{USB_DEVICE(0x0c45, 0x6138), BS(SN9C120, MO4000)},
{USB_DEVICE(0x0c45, 0x613a), BS(SN9C120, OV7648)},
-#if !defined CONFIG_USB_SN9C102 && !defined CONFIG_USB_SN9C102_MODULE
{USB_DEVICE(0x0c45, 0x613b), BS(SN9C120, OV7660)},
-#endif
{USB_DEVICE(0x0c45, 0x613c), BS(SN9C120, HV7131R)},
{USB_DEVICE(0x0c45, 0x613e), BS(SN9C120, OV7630)},
{USB_DEVICE(0x0c45, 0x6142), BS(SN9C120, PO2030N)}, /*sn9c120b*/
+ /* or GC0305 / GC0307 */
{USB_DEVICE(0x0c45, 0x6143), BS(SN9C120, SP80708)}, /*sn9c120b*/
{USB_DEVICE(0x0c45, 0x6148), BS(SN9C120, OM6802)}, /*sn9c120b*/
- {USB_DEVICE(0x0c45, 0x614a), BS(SN9C120, ADCM1700)}, /*sn9c120b*/
+ {USB_DEVICE(0x0c45, 0x614a), BSF(SN9C120, ADCM1700, F_ILLUM)},
+/* {USB_DEVICE(0x0c45, 0x614c), BS(SN9C120, GC0306)}, */ /*sn9c120b*/
{}
};
MODULE_DEVICE_TABLE(usb, device_table);
@@ -3087,18 +2995,16 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- info("registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- info("deregistered");
}
module_init(sd_mod_init);
module_exit(sd_mod_exit);
+
+module_param(starcam, int, 0644);
+MODULE_PARM_DESC(starcam,
+ "StarCam model. 0: Clip, 1: 370i");
diff --git a/drivers/media/video/gspca/spca1528.c b/drivers/media/video/gspca/spca1528.c
new file mode 100644
index 000000000000..76c006b2bc83
--- /dev/null
+++ b/drivers/media/video/gspca/spca1528.c
@@ -0,0 +1,598 @@
+/*
+ * spca1528 subdriver
+ *
+ * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * 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
+ */
+
+#define MODULE_NAME "spca1528"
+
+#include "gspca.h"
+#include "jpeg.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
+MODULE_DESCRIPTION("SPCA1528 USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ u8 brightness;
+ u8 contrast;
+ u8 hue;
+ u8 color;
+ u8 sharpness;
+
+ u8 pkt_seq;
+
+ u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcolor(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 const struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define BRIGHTNESS_DEF 128
+ .default_value = BRIGHTNESS_DEF,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 8,
+ .step = 1,
+#define CONTRAST_DEF 1
+ .default_value = CONTRAST_DEF,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+ {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define HUE_DEF 0
+ .default_value = HUE_DEF,
+ },
+ .set = sd_sethue,
+ .get = sd_gethue,
+ },
+ {
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 8,
+ .step = 1,
+#define COLOR_DEF 1
+ .default_value = COLOR_DEF,
+ },
+ .set = sd_setcolor,
+ .get = sd_getcolor,
+ },
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+#define SHARPNESS_DEF 0
+ .default_value = SHARPNESS_DEF,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+};
+
+static const struct v4l2_pix_format vga_mode[] = {
+/* (does not work correctly)
+ {176, 144, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 5 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 3},
+*/
+ {320, 240, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 4 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 2},
+ {640, 480, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 8 + 590,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .priv = 1},
+};
+
+/* read <len> bytes to gspca usb_buf */
+static void reg_r(struct gspca_dev *gspca_dev,
+ u8 req,
+ u16 index,
+ int len)
+{
+#if USB_BUF_SZ < 64
+#error "USB buffer too small"
+#endif
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
+ req,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ 0x0000, /* value */
+ index,
+ gspca_dev->usb_buf, len,
+ 500);
+ PDEBUG(D_USBI, "GET %02x 0000 %04x %02x", req, index,
+ gspca_dev->usb_buf[0]);
+ if (ret < 0) {
+ err("reg_r err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev,
+ u8 req,
+ u16 value,
+ u16 index)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ NULL, 0, 500);
+ if (ret < 0) {
+ err("reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev,
+ u8 req,
+ u16 value,
+ u16 index,
+ u8 byte)
+{
+ struct usb_device *dev = gspca_dev->dev;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "SET %02x %04x %04x %02x", req, value, index, byte);
+ gspca_dev->usb_buf[0] = byte;
+ ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
+ req,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ gspca_dev->usb_buf, 1, 500);
+ if (ret < 0) {
+ err("reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void wait_status_0(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ i = 20;
+ do {
+ reg_r(gspca_dev, 0x21, 0x0000, 1);
+ if (gspca_dev->usb_buf[0] == 0)
+ return;
+ msleep(30);
+ } while (--i > 0);
+ PDEBUG(D_ERR, "wait_status_0 timeout");
+ gspca_dev->usb_err = -ETIME;
+}
+
+static void wait_status_1(struct gspca_dev *gspca_dev)
+{
+ int i;
+
+ i = 10;
+ do {
+ reg_r(gspca_dev, 0x21, 0x0001, 1);
+ msleep(10);
+ if (gspca_dev->usb_buf[0] == 1) {
+ reg_wb(gspca_dev, 0x21, 0x0000, 0x0001, 0x00);
+ reg_r(gspca_dev, 0x21, 0x0001, 1);
+ return;
+ }
+ } while (--i > 0);
+ PDEBUG(D_ERR, "wait_status_1 timeout");
+ gspca_dev->usb_err = -ETIME;
+}
+
+static void setbrightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc0, 0x0000, 0x00c0, sd->brightness);
+}
+
+static void setcontrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc1, 0x0000, 0x00c1, sd->contrast);
+}
+
+static void sethue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc2, 0x0000, 0x0000, sd->hue);
+}
+
+static void setcolor(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc3, 0x0000, 0x00c3, sd->color);
+}
+
+static void setsharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ reg_wb(gspca_dev, 0xc4, 0x0000, 0x00c4, sd->sharpness);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->cam.cam_mode = vga_mode;
+ gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
+ gspca_dev->cam.npkt = 128; /* number of packets per ISOC message */
+ /*fixme: 256 in ms-win traces*/
+
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->hue = HUE_DEF;
+ sd->color = COLOR_DEF;
+ sd->sharpness = SHARPNESS_DEF;
+
+ gspca_dev->nbalt = 4; /* use alternate setting 3 */
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, 0x00, 0x0001, 0x2067);
+ reg_w(gspca_dev, 0x00, 0x00d0, 0x206b);
+ reg_w(gspca_dev, 0x00, 0x0000, 0x206c);
+ reg_w(gspca_dev, 0x00, 0x0001, 0x2069);
+ msleep(8);
+ reg_w(gspca_dev, 0x00, 0x00c0, 0x206b);
+ reg_w(gspca_dev, 0x00, 0x0000, 0x206c);
+ reg_w(gspca_dev, 0x00, 0x0001, 0x2069);
+
+ reg_r(gspca_dev, 0x20, 0x0000, 1);
+ reg_r(gspca_dev, 0x20, 0x0000, 5);
+ reg_r(gspca_dev, 0x23, 0x0000, 64);
+ PDEBUG(D_PROBE, "%s%s", &gspca_dev->usb_buf[0x1c],
+ &gspca_dev->usb_buf[0x30]);
+ reg_r(gspca_dev, 0x23, 0x0001, 64);
+ return gspca_dev->usb_err;
+}
+
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ u8 mode;
+
+ reg_r(gspca_dev, 0x00, 0x2520, 1);
+ wait_status_0(gspca_dev);
+ reg_w(gspca_dev, 0xc5, 0x0003, 0x0000);
+ wait_status_1(gspca_dev);
+
+ wait_status_0(gspca_dev);
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ reg_wb(gspca_dev, 0x25, 0x0000, 0x0004, mode);
+ reg_r(gspca_dev, 0x25, 0x0004, 1);
+ reg_wb(gspca_dev, 0x27, 0x0000, 0x0000, 0x06);
+ reg_r(gspca_dev, 0x27, 0x0000, 1);
+ return gspca_dev->usb_err;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* initialize the JPEG header */
+ jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
+ 0x22); /* JPEG 411 */
+
+ /* the JPEG quality seems to be 82% */
+ jpeg_set_qual(sd->jpeg_hdr, 82);
+
+ /* set the controls */
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ sethue(gspca_dev);
+ setcolor(gspca_dev);
+ setsharpness(gspca_dev);
+
+ msleep(5);
+ reg_r(gspca_dev, 0x00, 0x2520, 1);
+ msleep(8);
+
+ /* start the capture */
+ wait_status_0(gspca_dev);
+ reg_w(gspca_dev, 0x31, 0x0000, 0x0004);
+ wait_status_1(gspca_dev);
+ wait_status_0(gspca_dev);
+ msleep(200);
+
+ sd->pkt_seq = 0;
+ return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ /* stop the capture */
+ wait_status_0(gspca_dev);
+ reg_w(gspca_dev, 0x31, 0x0000, 0x0000);
+ wait_status_1(gspca_dev);
+ wait_status_0(gspca_dev);
+}
+
+/* move a packet adding 0x00 after 0xff */
+static void add_packet(struct gspca_dev *gspca_dev,
+ u8 *data,
+ int len)
+{
+ int i;
+
+ i = 0;
+ do {
+ if (data[i] == 0xff) {
+ gspca_frame_add(gspca_dev, INTER_PACKET,
+ data, i + 1);
+ len -= i;
+ data += i;
+ *data = 0x00;
+ i = 0;
+ }
+ } while (++i < len);
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const u8 ffd9[] = {0xff, 0xd9};
+
+ /* image packets start with:
+ * 02 8n
+ * with <n> bit:
+ * 0x01: even (0) / odd (1) image
+ * 0x02: end of image when set
+ */
+ if (len < 3)
+ return; /* empty packet */
+ if (*data == 0x02) {
+ if (data[1] & 0x02) {
+ sd->pkt_seq = !(data[1] & 1);
+ add_packet(gspca_dev, data + 2, len - 2);
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ ffd9, 2);
+ return;
+ }
+ if ((data[1] & 1) != sd->pkt_seq)
+ goto err;
+ if (gspca_dev->last_packet_type == LAST_PACKET)
+ gspca_frame_add(gspca_dev, FIRST_PACKET,
+ sd->jpeg_hdr, JPEG_HDR_SZ);
+ add_packet(gspca_dev, data + 2, len - 2);
+ return;
+ }
+err:
+ gspca_dev->last_packet_type = DISCARD_PACKET;
+}
+
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->brightness = val;
+ if (gspca_dev->streaming)
+ setbrightness(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming)
+ setcontrast(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+ return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = val;
+ if (gspca_dev->streaming)
+ sethue(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->hue;
+ return 0;
+}
+
+static int sd_setcolor(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->color = val;
+ if (gspca_dev->streaming)
+ setcolor(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getcolor(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->color;
+ return 0;
+}
+
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->sharpness = val;
+ if (gspca_dev->streaming)
+ setsharpness(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->sharpness;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .isoc_init = sd_isoc_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x04fc, 0x1528)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ /* the video interface for isochronous transfer is 1 */
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 1)
+ return -ENODEV;
+
+ return gspca_dev_probe2(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/spca500.c b/drivers/media/video/gspca/spca500.c
index b866c73c97db..45552c3ff8d9 100644
--- a/drivers/media/video/gspca/spca500.c
+++ b/drivers/media/video/gspca/spca500.c
@@ -57,7 +57,7 @@ struct sd {
#define PalmPixDC85 13
#define ToptroIndus 14
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
@@ -396,7 +396,7 @@ static int reg_w(struct gspca_dev *gspca_dev,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0, 500);
if (ret < 0)
- PDEBUG(D_ERR, "reg write: error %d", ret);
+ err("reg write: error %d", ret);
return ret;
}
@@ -418,8 +418,8 @@ static int reg_r_12(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf, length,
500); /* timeout */
if (ret < 0) {
- PDEBUG(D_ERR, "reg_r_12 err %d", ret);
- return -1;
+ err("reg_r_12 err %d", ret);
+ return ret;
}
return (gspca_dev->usb_buf[1] << 8) + gspca_dev->usb_buf[0];
}
@@ -669,9 +669,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
__u8 xmult, ymult;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -891,13 +888,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
gspca_dev->usb_buf[0]);
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- kfree(sd->jpeg_hdr);
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
@@ -1055,14 +1045,13 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x040a, 0x0300), .driver_info = KodakEZ200},
{USB_DEVICE(0x041e, 0x400a), .driver_info = CreativePCCam300},
{USB_DEVICE(0x046d, 0x0890), .driver_info = LogitechTraveler},
@@ -1104,17 +1093,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/spca501.c b/drivers/media/video/gspca/spca501.c
index c99333933e32..f7ef282cc600 100644
--- a/drivers/media/video/gspca/spca501.c
+++ b/drivers/media/video/gspca/spca501.c
@@ -1724,7 +1724,7 @@ static const __u16 spca501c_mysterious_init_data[][3] = {
{0x00, 0x0000, 0x0048},
{0x00, 0x0000, 0x0049},
{0x00, 0x0008, 0x004a},
-/* DSP Registers */
+/* DSP Registers */
{0x01, 0x00a6, 0x0000},
{0x01, 0x0028, 0x0001},
{0x01, 0x0000, 0x0002},
@@ -1788,7 +1788,7 @@ static const __u16 spca501c_mysterious_init_data[][3] = {
{0x05, 0x0022, 0x0004},
{0x05, 0x0025, 0x0001},
{0x05, 0x0000, 0x0000},
-/* Part 4 */
+/* Part 4 */
{0x05, 0x0026, 0x0001},
{0x05, 0x0001, 0x0000},
{0x05, 0x0027, 0x0001},
@@ -1806,7 +1806,7 @@ static const __u16 spca501c_mysterious_init_data[][3] = {
{0x05, 0x0001, 0x0000},
{0x05, 0x0027, 0x0001},
{0x05, 0x004e, 0x0000},
-/* Part 5 */
+/* Part 5 */
{0x01, 0x0003, 0x003f},
{0x01, 0x0001, 0x0056},
{0x01, 0x000f, 0x0008},
@@ -1852,7 +1852,7 @@ static int reg_write(struct usb_device *dev,
PDEBUG(D_USBO, "reg write: 0x%02x 0x%02x 0x%02x",
req, index, value);
if (ret < 0)
- PDEBUG(D_ERR, "reg write: error %d", ret);
+ err("reg write: error %d", ret);
return ret;
}
@@ -2155,7 +2155,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x040a, 0x0002), .driver_info = KodakDVC325},
{USB_DEVICE(0x0497, 0xc001), .driver_info = SmileIntlCamera},
{USB_DEVICE(0x0506, 0x00df), .driver_info = ThreeComHomeConnectLite},
@@ -2189,17 +2189,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/spca505.c b/drivers/media/video/gspca/spca505.c
index c576eed73abe..e5bf865147d7 100644
--- a/drivers/media/video/gspca/spca505.c
+++ b/drivers/media/video/gspca/spca505.c
@@ -368,10 +368,6 @@ static const u8 spca505b_init_data[][3] = {
{0x08, 0x00, 0x00},
{0x08, 0x00, 0x01},
{0x08, 0x00, 0x02},
- {0x00, 0x01, 0x00},
- {0x00, 0x01, 0x01},
- {0x00, 0x01, 0x34},
- {0x00, 0x01, 0x35},
{0x06, 0x18, 0x08},
{0x06, 0xfc, 0x09},
{0x06, 0xfc, 0x0a},
@@ -582,7 +578,7 @@ static int reg_write(struct usb_device *dev,
PDEBUG(D_USBO, "reg write: 0x%02x,0x%02x:0x%02x, %d",
req, index, value, ret);
if (ret < 0)
- PDEBUG(D_ERR, "reg write: error %d", ret);
+ err("reg write: error %d", ret);
return ret;
}
@@ -689,8 +685,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
return ret;
}
if (ret != 0x0101) {
- PDEBUG(D_ERR|D_CONF,
- "After vector read returns 0x%04x should be 0x0101",
+ err("After vector read returns 0x%04x should be 0x0101",
ret);
}
@@ -791,7 +786,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x401d), .driver_info = Nxultra},
{USB_DEVICE(0x0733, 0x0430), .driver_info = IntelPCCameraPro},
/*fixme: may be UsbGrabberPV321 BRIDGE_SPCA506 SENSOR_SAA7113 */
@@ -821,18 +816,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/spca508.c b/drivers/media/video/gspca/spca508.c
index edf0fe157501..348319371523 100644
--- a/drivers/media/video/gspca/spca508.c
+++ b/drivers/media/video/gspca/spca508.c
@@ -92,8 +92,7 @@ static const struct v4l2_pix_format sif_mode[] = {
* Initialization data: this is the first set-up data written to the
* device (before the open data).
*/
-static const u16 spca508_init_data[][2] =
-{
+static const u16 spca508_init_data[][2] = {
{0x0000, 0x870b},
{0x0020, 0x8112}, /* Video drop enable, ISO streaming disable */
@@ -1276,7 +1275,7 @@ static int reg_write(struct usb_device *dev,
PDEBUG(D_USBO, "reg write i:0x%04x = 0x%02x",
index, value);
if (ret < 0)
- PDEBUG(D_ERR|D_USBO, "reg write: error %d", ret);
+ err("reg write: error %d", ret);
return ret;
}
@@ -1298,7 +1297,7 @@ static int reg_read(struct gspca_dev *gspca_dev,
PDEBUG(D_USBI, "reg read i:%04x --> %02x",
index, gspca_dev->usb_buf[0]);
if (ret < 0) {
- PDEBUG(D_ERR|D_USBI, "reg_read err %d", ret);
+ err("reg_read err %d", ret);
return ret;
}
return gspca_dev->usb_buf[0];
@@ -1510,7 +1509,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0130, 0x0130), .driver_info = HamaUSBSightcam},
{USB_DEVICE(0x041e, 0x4018), .driver_info = CreativeVista},
{USB_DEVICE(0x0733, 0x0110), .driver_info = ViewQuestVQ110},
@@ -1543,18 +1542,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/spca561.c b/drivers/media/video/gspca/spca561.c
index 7bb2355005dc..e836e778dfb6 100644
--- a/drivers/media/video/gspca/spca561.c
+++ b/drivers/media/video/gspca/spca561.c
@@ -315,7 +315,7 @@ static void reg_w_val(struct usb_device *dev, __u16 index, __u8 value)
value, index, NULL, 0, 500);
PDEBUG(D_USBO, "reg write: 0x%02x:0x%02x", index, value);
if (ret < 0)
- PDEBUG(D_ERR, "reg write: error %d", ret);
+ err("reg write: error %d", ret);
}
static void write_vector(struct gspca_dev *gspca_dev,
@@ -597,7 +597,7 @@ static void setgain(struct gspca_dev *gspca_dev)
else if (sd->gain < 128)
gspca_dev->usb_buf[0] = (sd->gain / 2) | 0x40;
else
- gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xC0;
+ gspca_dev->usb_buf[0] = (sd->gain / 4) | 0xc0;
gspca_dev->usb_buf[1] = 0;
reg_w_buf(gspca_dev, 0x8335, 2);
@@ -787,7 +787,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
return;
}
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
if (data[0] & 0x20) {
input_report_key(gspca_dev->input_dev, KEY_CAMERA, 1);
input_sync(gspca_dev->input_dev);
@@ -1037,7 +1037,7 @@ static const struct sd_desc sd_desc_12a = {
.start = sd_start_12a,
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.other_input = 1,
#endif
};
@@ -1051,7 +1051,7 @@ static const struct sd_desc sd_desc_72a = {
.stopN = sd_stopN,
.pkt_scan = sd_pkt_scan,
.dq_callback = do_autogain,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.other_input = 1,
#endif
};
@@ -1061,7 +1061,7 @@ static const struct sd_desc *sd_desc[2] = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x401a), .driver_info = Rev072A},
{USB_DEVICE(0x041e, 0x403b), .driver_info = Rev012A},
{USB_DEVICE(0x0458, 0x7004), .driver_info = Rev072A},
@@ -1107,17 +1107,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/sq905.c b/drivers/media/video/gspca/sq905.c
index 09b3f93fa4d6..2e9c06175192 100644
--- a/drivers/media/video/gspca/sq905.c
+++ b/drivers/media/video/gspca/sq905.c
@@ -123,7 +123,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
SQ905_COMMAND, index, gspca_dev->usb_buf, 1,
SQ905_CMD_TIMEOUT);
if (ret < 0) {
- PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+ err("%s: usb_control_msg failed (%d)",
__func__, ret);
return ret;
}
@@ -135,7 +135,7 @@ static int sq905_command(struct gspca_dev *gspca_dev, u16 index)
SQ905_PING, 0, gspca_dev->usb_buf, 1,
SQ905_CMD_TIMEOUT);
if (ret < 0) {
- PDEBUG(D_ERR, "%s: usb_control_msg failed 2 (%d)",
+ err("%s: usb_control_msg failed 2 (%d)",
__func__, ret);
return ret;
}
@@ -158,7 +158,7 @@ static int sq905_ack_frame(struct gspca_dev *gspca_dev)
SQ905_READ_DONE, 0, gspca_dev->usb_buf, 1,
SQ905_CMD_TIMEOUT);
if (ret < 0) {
- PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
+ err("%s: usb_control_msg failed (%d)", __func__, ret);
return ret;
}
@@ -186,7 +186,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock)
if (need_lock)
mutex_unlock(&gspca_dev->usb_lock);
if (ret < 0) {
- PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)", __func__, ret);
+ err("%s: usb_control_msg failed (%d)", __func__, ret);
return ret;
}
ret = usb_bulk_msg(gspca_dev->dev,
@@ -195,7 +195,7 @@ sq905_read_data(struct gspca_dev *gspca_dev, u8 *data, int size, int need_lock)
/* successful, it returns 0, otherwise negative */
if (ret < 0 || act_len != size) {
- PDEBUG(D_ERR, "bulk read fail (%d) len %d/%d",
+ err("bulk read fail (%d) len %d/%d",
ret, act_len, size);
return -EIO;
}
@@ -226,7 +226,7 @@ static void sq905_dostream(struct work_struct *work)
buffer = kmalloc(SQ905_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
if (!buffer) {
- PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+ err("Couldn't allocate USB buffer");
goto quit_stream;
}
@@ -396,7 +396,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x2770, 0x9120)},
{}
};
@@ -436,19 +436,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/sq905c.c b/drivers/media/video/gspca/sq905c.c
index 4c70628ca615..457563b7a71b 100644
--- a/drivers/media/video/gspca/sq905c.c
+++ b/drivers/media/video/gspca/sq905c.c
@@ -95,7 +95,7 @@ static int sq905c_command(struct gspca_dev *gspca_dev, u16 command, u16 index)
command, index, NULL, 0,
SQ905C_CMD_TIMEOUT);
if (ret < 0) {
- PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+ err("%s: usb_control_msg failed (%d)",
__func__, ret);
return ret;
}
@@ -115,7 +115,7 @@ static int sq905c_read(struct gspca_dev *gspca_dev, u16 command, u16 index,
command, index, gspca_dev->usb_buf, size,
SQ905C_CMD_TIMEOUT);
if (ret < 0) {
- PDEBUG(D_ERR, "%s: usb_control_msg failed (%d)",
+ err("%s: usb_control_msg failed (%d)",
__func__, ret);
return ret;
}
@@ -146,7 +146,7 @@ static void sq905c_dostream(struct work_struct *work)
buffer = kmalloc(SQ905C_MAX_TRANSFER, GFP_KERNEL | GFP_DMA);
if (!buffer) {
- PDEBUG(D_ERR, "Couldn't allocate USB buffer");
+ err("Couldn't allocate USB buffer");
goto quit_stream;
}
@@ -298,9 +298,10 @@ static int sd_start(struct gspca_dev *gspca_dev)
}
/* Table of supported USB devices */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x2770, 0x905c)},
{USB_DEVICE(0x2770, 0x9050)},
+ {USB_DEVICE(0x2770, 0x9051)},
{USB_DEVICE(0x2770, 0x9052)},
{USB_DEVICE(0x2770, 0x913d)},
{}
@@ -341,19 +342,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/sq930x.c b/drivers/media/video/gspca/sq930x.c
new file mode 100644
index 000000000000..8215d5dcd456
--- /dev/null
+++ b/drivers/media/video/gspca/sq930x.c
@@ -0,0 +1,1208 @@
+/*
+ * SQ930x subdriver
+ *
+ * Copyright (C) 2010 Jean-François Moine <http://moinejf.free.fr>
+ * Copyright (C) 2006 -2008 Gerard Klaver <gerard at gkall dot hobby dot nl>
+ * Copyright (C) 2007 Sam Revitch <samr7@cs.washington.edu>
+ *
+ * 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
+ * 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
+ */
+
+#define MODULE_NAME "sq930x"
+
+#include "gspca.h"
+
+MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>\n"
+ "Gerard Klaver <gerard at gkall dot hobby dot nl\n"
+ "Sam Revitch <samr7@cs.washington.edu>");
+MODULE_DESCRIPTION("GSPCA/SQ930x USB Camera Driver");
+MODULE_LICENSE("GPL");
+
+/* Structure to hold all of our device specific stuff */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+
+ u16 expo;
+ u8 gain;
+
+ u8 do_ctrl;
+ u8 gpio[2];
+ u8 sensor;
+ u8 type;
+#define Generic 0
+#define Creative_live_motion 1
+};
+enum sensors {
+ SENSOR_ICX098BQ,
+ SENSOR_LZ24BP,
+ SENSOR_MI0360,
+ SENSOR_MT9V111, /* = MI360SOC */
+ SENSOR_OV7660,
+ SENSOR_OV9630,
+};
+
+static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static const struct ctrl sd_ctrls[] = {
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0x0001,
+ .maximum = 0x0fff,
+ .step = 1,
+#define EXPO_DEF 0x0356
+ .default_value = EXPO_DEF,
+ },
+ .set = sd_setexpo,
+ .get = sd_getexpo,
+ },
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0x01,
+ .maximum = 0xff,
+ .step = 1,
+#define GAIN_DEF 0x8d
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+};
+
+static struct v4l2_pix_format vga_mode[] = {
+ {320, 240, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 0},
+ {640, 480, V4L2_PIX_FMT_SRGGB8, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ .priv = 1},
+};
+
+/* sq930x registers */
+#define SQ930_CTRL_UCBUS_IO 0x0001
+#define SQ930_CTRL_I2C_IO 0x0002
+#define SQ930_CTRL_GPIO 0x0005
+#define SQ930_CTRL_CAP_START 0x0010
+#define SQ930_CTRL_CAP_STOP 0x0011
+#define SQ930_CTRL_SET_EXPOSURE 0x001d
+#define SQ930_CTRL_RESET 0x001e
+#define SQ930_CTRL_GET_DEV_INFO 0x001f
+
+/* gpio 1 (8..15) */
+#define SQ930_GPIO_DFL_I2C_SDA 0x0001
+#define SQ930_GPIO_DFL_I2C_SCL 0x0002
+#define SQ930_GPIO_RSTBAR 0x0004
+#define SQ930_GPIO_EXTRA1 0x0040
+#define SQ930_GPIO_EXTRA2 0x0080
+/* gpio 3 (24..31) */
+#define SQ930_GPIO_POWER 0x0200
+#define SQ930_GPIO_DFL_LED 0x1000
+
+struct ucbus_write_cmd {
+ u16 bw_addr;
+ u8 bw_data;
+};
+struct i2c_write_cmd {
+ u8 reg;
+ u16 val;
+};
+
+static const struct ucbus_write_cmd icx098bq_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xce},
+ {0xf802, 0xc1}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x0e},
+ {0xf80a, 0x01}, {0xf80b, 0xee}, {0xf807, 0x60}, {0xf80c, 0x02},
+ {0xf80d, 0xf0}, {0xf80e, 0x03}, {0xf80f, 0x0a}, {0xf81c, 0x02},
+ {0xf81d, 0xf0}, {0xf81e, 0x03}, {0xf81f, 0x0a}, {0xf83a, 0x00},
+ {0xf83b, 0x10}, {0xf83c, 0x00}, {0xf83d, 0x4e}, {0xf810, 0x04},
+ {0xf811, 0x00}, {0xf812, 0x02}, {0xf813, 0x10}, {0xf803, 0x00},
+ {0xf814, 0x01}, {0xf815, 0x18}, {0xf816, 0x00}, {0xf817, 0x48},
+ {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+ {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+ {0xf823, 0x07}, {0xf824, 0xff}, {0xf825, 0x03}, {0xf826, 0xff},
+ {0xf827, 0x06}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+ {0xf82b, 0x0c}, {0xf82c, 0xfd}, {0xf82d, 0x01}, {0xf82e, 0x00},
+ {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+ {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+ {0xf854, 0x00}, {0xf855, 0x18}, {0xf856, 0x00}, {0xf857, 0x3c},
+ {0xf858, 0x00}, {0xf859, 0x0c}, {0xf85a, 0x00}, {0xf85b, 0x30},
+ {0xf85c, 0x00}, {0xf85d, 0x0c}, {0xf85e, 0x00}, {0xf85f, 0x30},
+ {0xf860, 0x00}, {0xf861, 0x48}, {0xf862, 0x01}, {0xf863, 0xdc},
+ {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+ {0xf868, 0xff}, {0xf869, 0x70}, {0xf86c, 0xff}, {0xf86d, 0x00},
+ {0xf86a, 0xff}, {0xf86b, 0x48}, {0xf86e, 0xff}, {0xf86f, 0x00},
+ {0xf870, 0x01}, {0xf871, 0xdb}, {0xf872, 0x01}, {0xf873, 0xfa},
+ {0xf874, 0x01}, {0xf875, 0xdb}, {0xf876, 0x01}, {0xf877, 0xfa},
+ {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+ {0xf800, 0x03}
+};
+static const struct ucbus_write_cmd icx098bq_start_1[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xc0},
+ {0xf5f0, 0x49}, {0xf5f1, 0xcd}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xc0},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd icx098bq_start_2[] = {
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x82}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x40}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xcf}, {0xf806, 0xd0},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf800, 0x02}, {0xf801, 0xbe},
+ {0xf802, 0xc6}, {0xf804, 0x00}, {0xf808, 0x00}, {0xf809, 0x06},
+ {0xf80a, 0x01}, {0xf80b, 0xfe}, {0xf807, 0x84}, {0xf80c, 0x02},
+ {0xf80d, 0xf7}, {0xf80e, 0x03}, {0xf80f, 0x0b}, {0xf81c, 0x00},
+ {0xf81d, 0x49}, {0xf81e, 0x03}, {0xf81f, 0x0b}, {0xf83a, 0x00},
+ {0xf83b, 0x01}, {0xf83c, 0x00}, {0xf83d, 0x6b}, {0xf810, 0x03},
+ {0xf811, 0x10}, {0xf812, 0x02}, {0xf813, 0x6f}, {0xf803, 0x00},
+ {0xf814, 0x00}, {0xf815, 0x44}, {0xf816, 0x00}, {0xf817, 0x48},
+ {0xf818, 0x00}, {0xf819, 0x25}, {0xf81a, 0x00}, {0xf81b, 0x3c},
+ {0xf82f, 0x03}, {0xf820, 0xff}, {0xf821, 0x0d}, {0xf822, 0xff},
+ {0xf823, 0x07}, {0xf824, 0xfd}, {0xf825, 0x07}, {0xf826, 0xf0},
+ {0xf827, 0x0c}, {0xf828, 0xff}, {0xf829, 0x03}, {0xf82a, 0xff},
+ {0xf82b, 0x0c}, {0xf82c, 0xfc}, {0xf82d, 0x01}, {0xf82e, 0x00},
+ {0xf830, 0x00}, {0xf831, 0x47}, {0xf832, 0x00}, {0xf833, 0x00},
+ {0xf850, 0x00}, {0xf851, 0x00}, {0xf852, 0x00}, {0xf853, 0x24},
+ {0xf854, 0x00}, {0xf855, 0x0c}, {0xf856, 0x00}, {0xf857, 0x30},
+ {0xf858, 0x00}, {0xf859, 0x18}, {0xf85a, 0x00}, {0xf85b, 0x3c},
+ {0xf85c, 0x00}, {0xf85d, 0x18}, {0xf85e, 0x00}, {0xf85f, 0x3c},
+ {0xf860, 0xff}, {0xf861, 0x37}, {0xf862, 0xff}, {0xf863, 0x1d},
+ {0xf864, 0xff}, {0xf865, 0x98}, {0xf866, 0xff}, {0xf867, 0xc0},
+ {0xf868, 0x00}, {0xf869, 0x37}, {0xf86c, 0x02}, {0xf86d, 0x1d},
+ {0xf86a, 0x00}, {0xf86b, 0x37}, {0xf86e, 0x02}, {0xf86f, 0x1d},
+ {0xf870, 0x01}, {0xf871, 0xc6}, {0xf872, 0x02}, {0xf873, 0x04},
+ {0xf874, 0x01}, {0xf875, 0xc6}, {0xf876, 0x02}, {0xf877, 0x04},
+ {0xf878, 0x0f}, {0xf879, 0x0f}, {0xf87a, 0xff}, {0xf87b, 0xff},
+ {0xf800, 0x03}
+};
+static const struct ucbus_write_cmd lz24bp_start_1_gen[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xb3},
+ {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xb3},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_1_clm[] = {
+ {0xf5f0, 0x00}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+ {0xf5f4, 0xc0},
+ {0xf5f0, 0x40}, {0xf5f1, 0xff}, {0xf5f2, 0x88}, {0xf5f3, 0x88},
+ {0xf5f4, 0xc0},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+
+static const struct ucbus_write_cmd lz24bp_start_2[] = {
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x80}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x4e}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0xc0}, {0xf806, 0x48},
+ {0xf807, 0x7f}, {0xf800, 0x03},
+ {0xf800, 0x02}, {0xf807, 0xff}, {0xf805, 0x00}, {0xf806, 0x00},
+ {0xf807, 0x7f}, {0xf800, 0x03}
+};
+
+static const struct ucbus_write_cmd mi0360_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0xcc}, {0xf333, 0xcc},
+ {0xf334, 0xcc}, {0xf335, 0xcc}, {0xf33f, 0x00}
+};
+static const struct i2c_write_cmd mi0360_init_23[] = {
+ {0x30, 0x0040}, /* reserved - def 0x0005 */
+ {0x31, 0x0000}, /* reserved - def 0x002a */
+ {0x34, 0x0100}, /* reserved - def 0x0100 */
+ {0x3d, 0x068f}, /* reserved - def 0x068f */
+};
+static const struct i2c_write_cmd mi0360_init_24[] = {
+ {0x03, 0x01e5}, /* window height */
+ {0x04, 0x0285}, /* window width */
+};
+static const struct i2c_write_cmd mi0360_init_25[] = {
+ {0x35, 0x0020}, /* global gain */
+ {0x2b, 0x0020}, /* green1 gain */
+ {0x2c, 0x002a}, /* blue gain */
+ {0x2d, 0x0028}, /* red gain */
+ {0x2e, 0x0020}, /* green2 gain */
+};
+static const struct ucbus_write_cmd mi0360_start_1[] = {
+ {0xf5f0, 0x11}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xa6},
+ {0xf5f0, 0x51}, {0xf5f1, 0x99}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xa6},
+ {0xf5fa, 0x00}, {0xf5f6, 0x00}, {0xf5f7, 0x00}, {0xf5f8, 0x00},
+ {0xf5f9, 0x00}
+};
+static const struct i2c_write_cmd mi0360_start_2[] = {
+ {0x62, 0x041d}, /* reserved - def 0x0418 */
+};
+static const struct i2c_write_cmd mi0360_start_3[] = {
+ {0x05, 0x007b}, /* horiz blanking */
+};
+static const struct i2c_write_cmd mi0360_start_4[] = {
+ {0x05, 0x03f5}, /* horiz blanking */
+};
+
+static const struct i2c_write_cmd mt9v111_init_0[] = {
+ {0x01, 0x0001}, /* select IFP/SOC registers */
+ {0x06, 0x300c}, /* operating mode control */
+ {0x08, 0xcc00}, /* output format control (RGB) */
+ {0x01, 0x0004}, /* select sensor core registers */
+};
+static const struct i2c_write_cmd mt9v111_init_1[] = {
+ {0x03, 0x01e5}, /* window height */
+ {0x04, 0x0285}, /* window width */
+};
+static const struct i2c_write_cmd mt9v111_init_2[] = {
+ {0x30, 0x7800},
+ {0x31, 0x0000},
+ {0x07, 0x3002}, /* output control */
+ {0x35, 0x0020}, /* global gain */
+ {0x2b, 0x0020}, /* green1 gain */
+ {0x2c, 0x0020}, /* blue gain */
+ {0x2d, 0x0020}, /* red gain */
+ {0x2e, 0x0020}, /* green2 gain */
+};
+static const struct ucbus_write_cmd mt9v111_start_1[] = {
+ {0xf5f0, 0x11}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xaa},
+ {0xf5f0, 0x51}, {0xf5f1, 0x96}, {0xf5f2, 0x80}, {0xf5f3, 0x80},
+ {0xf5f4, 0xaa},
+ {0xf5fa, 0x00}, {0xf5f6, 0x0a}, {0xf5f7, 0x0a}, {0xf5f8, 0x0a},
+ {0xf5f9, 0x0a}
+};
+static const struct i2c_write_cmd mt9v111_init_3[] = {
+ {0x62, 0x0405},
+};
+static const struct i2c_write_cmd mt9v111_init_4[] = {
+/* {0x05, 0x00ce}, */
+ {0x05, 0x005d}, /* horizontal blanking */
+};
+
+static const struct ucbus_write_cmd ov7660_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0xc0},
+ {0xf334, 0x39}, {0xf335, 0xe7}, {0xf33f, 0x03}
+};
+
+static const struct ucbus_write_cmd ov9630_start_0[] = {
+ {0x0354, 0x00}, {0x03fa, 0x00}, {0xf332, 0x00}, {0xf333, 0x00},
+ {0xf334, 0x3e}, {0xf335, 0xf8}, {0xf33f, 0x03}
+};
+
+/* start parameters indexed by [sensor][mode] */
+static const struct cap_s {
+ u8 cc_sizeid;
+ u8 cc_bytes[32];
+} capconfig[4][2] = {
+ [SENSOR_ICX098BQ] = {
+ {2, /* Bayer 320x240 */
+ {0x05, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+ 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {4, /* Bayer 640x480 */
+ {0x01, 0x1f, 0x20, 0x0e, 0x00, 0x9f, 0x02, 0xee,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ },
+ [SENSOR_LZ24BP] = {
+ {2, /* Bayer 320x240 */
+ {0x05, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
+ 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {4, /* Bayer 640x480 */
+ {0x01, 0x22, 0x20, 0x0e, 0x00, 0xa2, 0x02, 0xee,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ },
+ [SENSOR_MI0360] = {
+ {2, /* Bayer 320x240 */
+ {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+ 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {4, /* Bayer 640x480 */
+ {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ },
+ [SENSOR_MT9V111] = {
+ {2, /* Bayer 320x240 */
+ {0x05, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+ 0x01, 0x01, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ {4, /* Bayer 640x480 */
+ {0x01, 0x02, 0x20, 0x01, 0x20, 0x82, 0x02, 0xe1,
+ 0x01, 0x02, 0x00, 0x08, 0x18, 0x12, 0x78, 0xc8,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+ },
+};
+
+struct sensor_s {
+ const char *name;
+ u8 i2c_addr;
+ u8 i2c_dum;
+ u8 gpio[5];
+ u8 cmd_len;
+ const struct ucbus_write_cmd *cmd;
+};
+
+static const struct sensor_s sensor_tb[] = {
+ [SENSOR_ICX098BQ] = {
+ "icx098bp",
+ 0x00, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 8, icx098bq_start_0
+ },
+ [SENSOR_LZ24BP] = {
+ "lz24bp",
+ 0x00, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 8, lz24bp_start_0
+ },
+ [SENSOR_MI0360] = {
+ "mi0360",
+ 0x5d, 0x80,
+ {SQ930_GPIO_RSTBAR,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ 0
+ },
+ 7, mi0360_start_0
+ },
+ [SENSOR_MT9V111] = {
+ "mt9v111",
+ 0x5c, 0x7f,
+ {SQ930_GPIO_RSTBAR,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ 0
+ },
+ 7, mi0360_start_0
+ },
+ [SENSOR_OV7660] = {
+ "ov7660",
+ 0x21, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 7, ov7660_start_0
+ },
+ [SENSOR_OV9630] = {
+ "ov9630",
+ 0x30, 0x00,
+ {0,
+ SQ930_GPIO_DFL_I2C_SDA | SQ930_GPIO_DFL_I2C_SCL,
+ SQ930_GPIO_DFL_I2C_SDA,
+ 0,
+ SQ930_GPIO_RSTBAR
+ },
+ 7, ov9630_start_0
+ },
+};
+
+static void reg_r(struct gspca_dev *gspca_dev,
+ u16 value, int len)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_rcvctrlpipe(gspca_dev->dev, 0),
+ 0x0c,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, 0, gspca_dev->usb_buf, len,
+ 500);
+ if (ret < 0) {
+ err("reg_r %04x failed %d", value, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_w(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "reg_w v: %04x i: %04x", value, index);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, NULL, 0,
+ 500);
+ msleep(30);
+ if (ret < 0) {
+ err("reg_w %04x %04x failed %d", value, index, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void reg_wb(struct gspca_dev *gspca_dev, u16 value, u16 index,
+ const u8 *data, int len)
+{
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "reg_wb v: %04x i: %04x %02x...%02x",
+ value, index, *data, data[len - 1]);
+ memcpy(gspca_dev->usb_buf, data, len);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index, gspca_dev->usb_buf, len,
+ 1000);
+ msleep(30);
+ if (ret < 0) {
+ err("reg_wb %04x %04x failed %d", value, index, ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void i2c_write(struct sd *sd,
+ const struct i2c_write_cmd *cmd,
+ int ncmds)
+{
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+ const struct sensor_s *sensor;
+ u16 val, idx;
+ u8 *buf;
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+
+ sensor = &sensor_tb[sd->sensor];
+
+ val = (sensor->i2c_addr << 8) | SQ930_CTRL_I2C_IO;
+ idx = (cmd->val & 0xff00) | cmd->reg;
+
+ buf = gspca_dev->usb_buf;
+ *buf++ = sensor->i2c_dum;
+ *buf++ = cmd->val;
+
+ while (--ncmds > 0) {
+ cmd++;
+ *buf++ = cmd->reg;
+ *buf++ = cmd->val >> 8;
+ *buf++ = sensor->i2c_dum;
+ *buf++ = cmd->val;
+ }
+
+ PDEBUG(D_USBO, "i2c_w v: %04x i: %04x %02x...%02x",
+ val, idx, gspca_dev->usb_buf[0], buf[-1]);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ val, idx,
+ gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+ 500);
+ if (ret < 0) {
+ err("i2c_write failed %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+
+static void ucbus_write(struct gspca_dev *gspca_dev,
+ const struct ucbus_write_cmd *cmd,
+ int ncmds,
+ int batchsize)
+{
+ u8 *buf;
+ u16 val, idx;
+ int len, ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+
+#ifdef GSPCA_DEBUG
+ if ((batchsize - 1) * 3 > USB_BUF_SZ) {
+ err("Bug: usb_buf overflow");
+ gspca_dev->usb_err = -ENOMEM;
+ return;
+ }
+#endif
+
+ for (;;) {
+ len = ncmds;
+ if (len > batchsize)
+ len = batchsize;
+ ncmds -= len;
+
+ val = (cmd->bw_addr << 8) | SQ930_CTRL_UCBUS_IO;
+ idx = (cmd->bw_data << 8) | (cmd->bw_addr >> 8);
+
+ buf = gspca_dev->usb_buf;
+ while (--len > 0) {
+ cmd++;
+ *buf++ = cmd->bw_addr;
+ *buf++ = cmd->bw_addr >> 8;
+ *buf++ = cmd->bw_data;
+ }
+ if (buf != gspca_dev->usb_buf)
+ PDEBUG(D_USBO, "ucbus v: %04x i: %04x %02x...%02x",
+ val, idx,
+ gspca_dev->usb_buf[0], buf[-1]);
+ else
+ PDEBUG(D_USBO, "ucbus v: %04x i: %04x",
+ val, idx);
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
+ 0x0c, /* request */
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ val, idx,
+ gspca_dev->usb_buf, buf - gspca_dev->usb_buf,
+ 500);
+ if (ret < 0) {
+ err("ucbus_write failed %d", ret);
+ gspca_dev->usb_err = ret;
+ return;
+ }
+ msleep(30);
+ if (ncmds <= 0)
+ break;
+ cmd++;
+ }
+}
+
+static void gpio_set(struct sd *sd, u16 val, u16 mask)
+{
+ struct gspca_dev *gspca_dev = &sd->gspca_dev;
+
+ if (mask & 0x00ff) {
+ sd->gpio[0] &= ~mask;
+ sd->gpio[0] |= val;
+ reg_w(gspca_dev, 0x0100 | SQ930_CTRL_GPIO,
+ ~sd->gpio[0] << 8);
+ }
+ mask >>= 8;
+ val >>= 8;
+ if (mask) {
+ sd->gpio[1] &= ~mask;
+ sd->gpio[1] |= val;
+ reg_w(gspca_dev, 0x0300 | SQ930_CTRL_GPIO,
+ ~sd->gpio[1] << 8);
+ }
+}
+
+static void gpio_init(struct sd *sd,
+ const u8 *gpio)
+{
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio++, 0x000f);
+ gpio_set(sd, *gpio, 0x000f);
+}
+
+static void bridge_init(struct sd *sd)
+{
+ static const struct ucbus_write_cmd clkfreq_cmd = {
+ 0xf031, 0 /* SQ930_CLKFREQ_60MHZ */
+ };
+
+ ucbus_write(&sd->gspca_dev, &clkfreq_cmd, 1, 1);
+
+ gpio_set(sd, SQ930_GPIO_POWER, 0xff00);
+}
+
+static void cmos_probe(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+ const struct sensor_s *sensor;
+ static const u8 probe_order[] = {
+/* SENSOR_LZ24BP, (tested as ccd) */
+ SENSOR_OV9630,
+ SENSOR_MI0360,
+ SENSOR_OV7660,
+ SENSOR_MT9V111,
+ };
+
+ for (i = 0; i < ARRAY_SIZE(probe_order); i++) {
+ sensor = &sensor_tb[probe_order[i]];
+ ucbus_write(&sd->gspca_dev, sensor->cmd, sensor->cmd_len, 8);
+ gpio_init(sd, sensor->gpio);
+ msleep(100);
+ reg_r(gspca_dev, (sensor->i2c_addr << 8) | 0x001c, 1);
+ msleep(100);
+ if (gspca_dev->usb_buf[0] != 0)
+ break;
+ }
+ if (i >= ARRAY_SIZE(probe_order)) {
+ err("Unknown sensor");
+ gspca_dev->usb_err = -EINVAL;
+ return;
+ }
+ sd->sensor = probe_order[i];
+ switch (sd->sensor) {
+ case SENSOR_OV7660:
+ case SENSOR_OV9630:
+ err("Sensor %s not yet treated", sensor_tb[sd->sensor].name);
+ gspca_dev->usb_err = -EINVAL;
+ break;
+ }
+}
+
+static void mt9v111_init(struct gspca_dev *gspca_dev)
+{
+ int i, nwait;
+ static const u8 cmd_001b[] = {
+ 0x00, 0x3b, 0xf6, 0x01, 0x03, 0x02, 0x00, 0x00,
+ 0x00, 0x00, 0x00
+ };
+ static const u8 cmd_011b[][7] = {
+ {0x10, 0x01, 0x66, 0x08, 0x00, 0x00, 0x00},
+ {0x01, 0x00, 0x1a, 0x04, 0x00, 0x00, 0x00},
+ {0x20, 0x00, 0x10, 0x04, 0x00, 0x00, 0x00},
+ {0x02, 0x01, 0xae, 0x01, 0x00, 0x00, 0x00},
+ };
+
+ reg_wb(gspca_dev, 0x001b, 0x0000, cmd_001b, sizeof cmd_001b);
+ for (i = 0; i < ARRAY_SIZE(cmd_011b); i++) {
+ reg_wb(gspca_dev, 0x001b, 0x0000, cmd_011b[i],
+ ARRAY_SIZE(cmd_011b[0]));
+ msleep(400);
+ nwait = 20;
+ for (;;) {
+ reg_r(gspca_dev, 0x031b, 1);
+ if (gspca_dev->usb_buf[0] == 0
+ || gspca_dev->usb_err != 0)
+ break;
+ if (--nwait < 0) {
+ PDEBUG(D_PROBE, "mt9v111_init timeout");
+ gspca_dev->usb_err = -ETIME;
+ return;
+ }
+ msleep(50);
+ }
+ }
+}
+
+static void global_init(struct sd *sd, int first_time)
+{
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ:
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ icx098bq_start_0,
+ 8, 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ case SENSOR_LZ24BP:
+ if (sd->type != Creative_live_motion)
+ gpio_set(sd, SQ930_GPIO_EXTRA1, 0x00ff);
+ else
+ gpio_set(sd, 0, 0x00ff);
+ msleep(50);
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ lz24bp_start_0,
+ 8, 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ case SENSOR_MI0360:
+ if (first_time)
+ ucbus_write(&sd->gspca_dev,
+ mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ gpio_set(sd, SQ930_GPIO_EXTRA2, SQ930_GPIO_EXTRA2);
+ break;
+ default:
+/* case SENSOR_MT9V111: */
+ if (first_time)
+ mt9v111_init(&sd->gspca_dev);
+ else
+ gpio_init(sd, sensor_tb[sd->sensor].gpio);
+ break;
+ }
+}
+
+static void lz24bp_ppl(struct sd *sd, u16 ppl)
+{
+ struct ucbus_write_cmd cmds[2] = {
+ {0xf810, ppl >> 8},
+ {0xf811, ppl}
+ };
+
+ ucbus_write(&sd->gspca_dev, cmds, ARRAY_SIZE(cmds), 2);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, integclks, intstartclk, frameclks, min_frclk;
+ const struct sensor_s *sensor;
+ u16 cmd;
+ u8 buf[15];
+
+ integclks = sd->expo;
+ i = 0;
+ cmd = SQ930_CTRL_SET_EXPOSURE;
+
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ: /* ccd */
+ case SENSOR_LZ24BP:
+ min_frclk = sd->sensor == SENSOR_ICX098BQ ? 0x210 : 0x26f;
+ if (integclks >= min_frclk) {
+ intstartclk = 0;
+ frameclks = integclks;
+ } else {
+ intstartclk = min_frclk - integclks;
+ frameclks = min_frclk;
+ }
+ buf[i++] = intstartclk >> 8;
+ buf[i++] = intstartclk;
+ buf[i++] = frameclks >> 8;
+ buf[i++] = frameclks;
+ buf[i++] = sd->gain;
+ break;
+ default: /* cmos */
+/* case SENSOR_MI0360: */
+/* case SENSOR_MT9V111: */
+ cmd |= 0x0100;
+ sensor = &sensor_tb[sd->sensor];
+ buf[i++] = sensor->i2c_addr; /* i2c_slave_addr */
+ buf[i++] = 0x08; /* 2 * ni2c */
+ buf[i++] = 0x09; /* reg = shutter width */
+ buf[i++] = integclks >> 8; /* val H */
+ buf[i++] = sensor->i2c_dum;
+ buf[i++] = integclks; /* val L */
+ buf[i++] = 0x35; /* reg = global gain */
+ buf[i++] = 0x00; /* val H */
+ buf[i++] = sensor->i2c_dum;
+ buf[i++] = 0x80 + sd->gain / 2; /* val L */
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x00;
+ buf[i++] = 0x83;
+ break;
+ }
+ reg_wb(gspca_dev, cmd, 0, buf, i);
+}
+
+/* This function is called at probe time just before sd_init */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam = &gspca_dev->cam;
+
+ sd->sensor = id->driver_info >> 8;
+ sd->type = id->driver_info;
+
+ cam->cam_mode = vga_mode;
+ cam->nmodes = ARRAY_SIZE(vga_mode);
+
+ cam->bulk = 1;
+
+ sd->gain = GAIN_DEF;
+ sd->expo = EXPO_DEF;
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gpio[0] = sd->gpio[1] = 0xff; /* force gpio rewrite */
+
+/*fixme: is this needed for icx098bp and mi0360?
+ if (sd->sensor != SENSOR_LZ24BP)
+ reg_w(gspca_dev, SQ930_CTRL_RESET, 0x0000);
+ */
+
+ reg_r(gspca_dev, SQ930_CTRL_GET_DEV_INFO, 8);
+ if (gspca_dev->usb_err < 0)
+ return gspca_dev->usb_err;
+
+/* it returns:
+ * 03 00 12 93 0b f6 c9 00 live! ultra
+ * 03 00 07 93 0b f6 ca 00 live! ultra for notebook
+ * 03 00 12 93 0b fe c8 00 Trust WB-3500T
+ * 02 00 06 93 0b fe c8 00 Joy-IT 318S
+ * 03 00 12 93 0b f6 cf 00 icam tracer - sensor icx098bq
+ * 02 00 12 93 0b fe cf 00 ProQ Motion Webcam
+ *
+ * byte
+ * 0: 02 = usb 1.0 (12Mbit) / 03 = usb2.0 (480Mbit)
+ * 1: 00
+ * 2: 06 / 07 / 12 = mode webcam? firmware??
+ * 3: 93 chip = 930b (930b or 930c)
+ * 4: 0b
+ * 5: f6 = cdd (icx098bq, lz24bp) / fe or de = cmos (i2c) (other sensors)
+ * 6: c8 / c9 / ca / cf = mode webcam?, sensor? webcam?
+ * 7: 00
+ */
+ PDEBUG(D_PROBE, "info: %02x %02x %02x %02x %02x %02x %02x %02x",
+ gspca_dev->usb_buf[0],
+ gspca_dev->usb_buf[1],
+ gspca_dev->usb_buf[2],
+ gspca_dev->usb_buf[3],
+ gspca_dev->usb_buf[4],
+ gspca_dev->usb_buf[5],
+ gspca_dev->usb_buf[6],
+ gspca_dev->usb_buf[7]);
+
+ bridge_init(sd);
+
+ if (sd->sensor == SENSOR_MI0360) {
+
+ /* no sensor probe for icam tracer */
+ if (gspca_dev->usb_buf[5] == 0xf6) /* if ccd */
+ sd->sensor = SENSOR_ICX098BQ;
+ else
+ cmos_probe(gspca_dev);
+ }
+ if (gspca_dev->usb_err >= 0) {
+ PDEBUG(D_PROBE, "Sensor %s", sensor_tb[sd->sensor].name);
+ global_init(sd, 1);
+ }
+ return gspca_dev->usb_err;
+}
+
+/* send the start/stop commands to the webcam */
+static void send_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ const struct cap_s *cap;
+ int mode;
+
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ cap = &capconfig[sd->sensor][mode];
+ reg_wb(gspca_dev, 0x0900 | SQ930_CTRL_CAP_START,
+ 0x0a00 | cap->cc_sizeid,
+ cap->cc_bytes, 32);
+}
+
+static void send_stop(struct gspca_dev *gspca_dev)
+{
+ reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0);
+}
+
+/* function called at start time before URB creation */
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ gspca_dev->cam.bulk_nurbs = 1; /* there must be one URB only */
+ sd->do_ctrl = 0;
+ gspca_dev->cam.bulk_size = gspca_dev->width * gspca_dev->height + 8;
+ return 0;
+}
+
+/* start the capture */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int mode;
+
+ bridge_init(sd);
+ global_init(sd, 0);
+ msleep(100);
+
+ switch (sd->sensor) {
+ case SENSOR_ICX098BQ:
+ ucbus_write(gspca_dev, icx098bq_start_0,
+ ARRAY_SIZE(icx098bq_start_0),
+ 8);
+ ucbus_write(gspca_dev, icx098bq_start_1,
+ ARRAY_SIZE(icx098bq_start_1),
+ 5);
+ ucbus_write(gspca_dev, icx098bq_start_2,
+ ARRAY_SIZE(icx098bq_start_2),
+ 6);
+ msleep(50);
+
+ /* 1st start */
+ send_start(gspca_dev);
+ gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+ msleep(70);
+ reg_w(gspca_dev, SQ930_CTRL_CAP_STOP, 0x0000);
+ gpio_set(sd, 0x7f, 0x00ff);
+
+ /* 2nd start */
+ send_start(gspca_dev);
+ gpio_set(sd, SQ930_GPIO_EXTRA2 | SQ930_GPIO_RSTBAR, 0x00ff);
+ goto out;
+ case SENSOR_LZ24BP:
+ ucbus_write(gspca_dev, lz24bp_start_0,
+ ARRAY_SIZE(lz24bp_start_0),
+ 8);
+ if (sd->type != Creative_live_motion)
+ ucbus_write(gspca_dev, lz24bp_start_1_gen,
+ ARRAY_SIZE(lz24bp_start_1_gen),
+ 5);
+ else
+ ucbus_write(gspca_dev, lz24bp_start_1_clm,
+ ARRAY_SIZE(lz24bp_start_1_clm),
+ 5);
+ ucbus_write(gspca_dev, lz24bp_start_2,
+ ARRAY_SIZE(lz24bp_start_2),
+ 6);
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
+ lz24bp_ppl(sd, mode == 1 ? 0x0564 : 0x0310);
+ msleep(10);
+ break;
+ case SENSOR_MI0360:
+ ucbus_write(gspca_dev, mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ i2c_write(sd, mi0360_init_23,
+ ARRAY_SIZE(mi0360_init_23));
+ i2c_write(sd, mi0360_init_24,
+ ARRAY_SIZE(mi0360_init_24));
+ i2c_write(sd, mi0360_init_25,
+ ARRAY_SIZE(mi0360_init_25));
+ ucbus_write(gspca_dev, mi0360_start_1,
+ ARRAY_SIZE(mi0360_start_1),
+ 5);
+ i2c_write(sd, mi0360_start_2,
+ ARRAY_SIZE(mi0360_start_2));
+ i2c_write(sd, mi0360_start_3,
+ ARRAY_SIZE(mi0360_start_3));
+
+ /* 1st start */
+ send_start(gspca_dev);
+ msleep(60);
+ send_stop(gspca_dev);
+
+ i2c_write(sd,
+ mi0360_start_4, ARRAY_SIZE(mi0360_start_4));
+ break;
+ default:
+/* case SENSOR_MT9V111: */
+ ucbus_write(gspca_dev, mi0360_start_0,
+ ARRAY_SIZE(mi0360_start_0),
+ 8);
+ i2c_write(sd, mt9v111_init_0,
+ ARRAY_SIZE(mt9v111_init_0));
+ i2c_write(sd, mt9v111_init_1,
+ ARRAY_SIZE(mt9v111_init_1));
+ i2c_write(sd, mt9v111_init_2,
+ ARRAY_SIZE(mt9v111_init_2));
+ ucbus_write(gspca_dev, mt9v111_start_1,
+ ARRAY_SIZE(mt9v111_start_1),
+ 5);
+ i2c_write(sd, mt9v111_init_3,
+ ARRAY_SIZE(mt9v111_init_3));
+ i2c_write(sd, mt9v111_init_4,
+ ARRAY_SIZE(mt9v111_init_4));
+ break;
+ }
+
+ send_start(gspca_dev);
+out:
+ msleep(1000);
+
+ if (sd->sensor == SENSOR_MT9V111)
+ gpio_set(sd, SQ930_GPIO_DFL_LED, SQ930_GPIO_DFL_LED);
+
+ sd->do_ctrl = 1; /* set the exposure */
+
+ return gspca_dev->usb_err;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->sensor == SENSOR_MT9V111)
+ gpio_set(sd, 0, SQ930_GPIO_DFL_LED);
+ send_stop(gspca_dev);
+}
+
+/* function called when the application gets a new frame */
+/* It sets the exposure if required and restart the bulk transfer. */
+static void sd_dq_callback(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int ret;
+
+ if (!sd->do_ctrl || gspca_dev->cam.bulk_nurbs != 0)
+ return;
+ sd->do_ctrl = 0;
+
+ setexposure(gspca_dev);
+
+ gspca_dev->cam.bulk_nurbs = 1;
+ ret = usb_submit_urb(gspca_dev->urb[0], GFP_ATOMIC);
+ if (ret < 0)
+ err("sd_dq_callback() err %d", ret);
+
+ /* wait a little time, otherwise the webcam crashes */
+ msleep(100);
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, /* isoc packet */
+ int len) /* iso packet length */
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (sd->do_ctrl)
+ gspca_dev->cam.bulk_nurbs = 0;
+ gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len - 8);
+ gspca_frame_add(gspca_dev, LAST_PACKET, NULL, 0);
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ sd->do_ctrl = 1;
+ return 0;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+static int sd_setexpo(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->expo = val;
+ if (gspca_dev->streaming)
+ sd->do_ctrl = 1;
+ return 0;
+}
+
+static int sd_getexpo(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->expo;
+ return 0;
+}
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .isoc_init = sd_isoc_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .pkt_scan = sd_pkt_scan,
+ .dq_callback = sd_dq_callback,
+};
+
+/* Table of supported USB devices */
+#define ST(sensor, type) \
+ .driver_info = (SENSOR_ ## sensor << 8) \
+ | (type)
+static const struct usb_device_id device_table[] = {
+ {USB_DEVICE(0x041e, 0x4038), ST(MI0360, 0)},
+ {USB_DEVICE(0x041e, 0x403c), ST(LZ24BP, 0)},
+ {USB_DEVICE(0x041e, 0x403d), ST(LZ24BP, 0)},
+ {USB_DEVICE(0x041e, 0x4041), ST(LZ24BP, Creative_live_motion)},
+ {USB_DEVICE(0x2770, 0x930b), ST(MI0360, 0)},
+ {USB_DEVICE(0x2770, 0x930c), ST(MI0360, 0)},
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ return gspca_dev_probe(intf, id, &sd_desc, sizeof(struct sd),
+ THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/stk014.c b/drivers/media/video/gspca/stk014.c
index 0fb534210a2c..87be52b5e1e3 100644
--- a/drivers/media/video/gspca/stk014.c
+++ b/drivers/media/video/gspca/stk014.c
@@ -27,34 +27,37 @@ MODULE_AUTHOR("Jean-Francois Moine <http://moinejf.free.fr>");
MODULE_DESCRIPTION("Syntek DV4000 (STK014) USB Camera Driver");
MODULE_LICENSE("GPL");
+/* controls */
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ COLORS,
+ LIGHTFREQ,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- unsigned char brightness;
- unsigned char contrast;
- unsigned char colors;
- unsigned char lightfreq;
+ struct gspca_ctrl ctrls[NCTRLS];
+
u8 quality;
-#define QUALITY_MIN 60
+#define QUALITY_MIN 70
#define QUALITY_MAX 95
-#define QUALITY_DEF 80
+#define QUALITY_DEF 88
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val);
-
-static const struct ctrl sd_ctrls[] = {
- {
+static void setbrightness(struct gspca_dev *gspca_dev);
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setcolors(struct gspca_dev *gspca_dev);
+static void setlightfreq(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -62,13 +65,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define BRIGHTNESS_DEF 127
- .default_value = BRIGHTNESS_DEF,
+ .default_value = 127,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set_control = setbrightness
},
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -76,13 +77,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define CONTRAST_DEF 127
- .default_value = CONTRAST_DEF,
+ .default_value = 127,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = setcontrast
},
- {
+[COLORS] = {
{
.id = V4L2_CID_SATURATION,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -90,13 +89,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define COLOR_DEF 127
- .default_value = COLOR_DEF,
+ .default_value = 127,
},
- .set = sd_setcolors,
- .get = sd_getcolors,
+ .set_control = setcolors
},
- {
+[LIGHTFREQ] = {
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
@@ -104,11 +101,9 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 1,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
-#define FREQ_DEF 1
- .default_value = FREQ_DEF,
+ .default_value = 1,
},
- .set = sd_setfreq,
- .get = sd_getfreq,
+ .set_control = setlightfreq
},
};
@@ -142,7 +137,7 @@ static u8 reg_r(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_r err %d", ret);
+ err("reg_r err %d", ret);
gspca_dev->usb_err = ret;
return 0;
}
@@ -167,7 +162,7 @@ static void reg_w(struct gspca_dev *gspca_dev,
0,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w err %d", ret);
+ err("reg_w err %d", ret);
gspca_dev->usb_err = ret;
}
}
@@ -197,7 +192,7 @@ static void rcv_val(struct gspca_dev *gspca_dev,
&alen,
500); /* timeout in milliseconds */
if (ret < 0) {
- PDEBUG(D_ERR, "rcv_val err %d", ret);
+ err("rcv_val err %d", ret);
gspca_dev->usb_err = ret;
}
}
@@ -240,7 +235,7 @@ static void snd_val(struct gspca_dev *gspca_dev,
&alen,
500); /* timeout in milliseconds */
if (ret < 0) {
- PDEBUG(D_ERR, "snd_val err %d", ret);
+ err("snd_val err %d", ret);
gspca_dev->usb_err = ret;
} else {
if (ads == 0x003f08) {
@@ -264,7 +259,7 @@ static void setbrightness(struct gspca_dev *gspca_dev)
int parval;
parval = 0x06000000 /* whiteness */
- + (sd->brightness << 16);
+ + (sd->ctrls[BRIGHTNESS].val << 16);
set_par(gspca_dev, parval);
}
@@ -274,7 +269,7 @@ static void setcontrast(struct gspca_dev *gspca_dev)
int parval;
parval = 0x07000000 /* contrast */
- + (sd->contrast << 16);
+ + (sd->ctrls[CONTRAST].val << 16);
set_par(gspca_dev, parval);
}
@@ -284,15 +279,15 @@ static void setcolors(struct gspca_dev *gspca_dev)
int parval;
parval = 0x08000000 /* saturation */
- + (sd->colors << 16);
+ + (sd->ctrls[COLORS].val << 16);
set_par(gspca_dev, parval);
}
-static void setfreq(struct gspca_dev *gspca_dev)
+static void setlightfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- set_par(gspca_dev, sd->lightfreq == 1
+ set_par(gspca_dev, sd->ctrls[LIGHTFREQ].val == 1
? 0x33640000 /* 50 Hz */
: 0x33780000); /* 60 Hz */
}
@@ -305,10 +300,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
gspca_dev->cam.cam_mode = vga_mode;
gspca_dev->cam.nmodes = ARRAY_SIZE(vga_mode);
- sd->brightness = BRIGHTNESS_DEF;
- sd->contrast = CONTRAST_DEF;
- sd->colors = COLOR_DEF;
- sd->lightfreq = FREQ_DEF;
+ gspca_dev->cam.ctrls = sd->ctrls;
sd->quality = QUALITY_DEF;
return 0;
}
@@ -323,7 +315,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
ret = reg_r(gspca_dev, 0x0740);
if (gspca_dev->usb_err >= 0) {
if (ret != 0xff) {
- PDEBUG(D_ERR|D_STREAM, "init reg: 0x%02x", ret);
+ err("init reg: 0x%02x", ret);
gspca_dev->usb_err = -EIO;
}
}
@@ -337,9 +329,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int ret, value;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -360,7 +349,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
gspca_dev->iface,
gspca_dev->alt);
if (ret < 0) {
- PDEBUG(D_ERR|D_STREAM, "set intf %d %d failed",
+ err("set intf %d %d failed",
gspca_dev->iface, gspca_dev->alt);
gspca_dev->usb_err = ret;
goto out;
@@ -381,7 +370,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
set_par(gspca_dev, 0x0a800000); /* Green ? */
set_par(gspca_dev, 0x0b800000); /* Blue ? */
set_par(gspca_dev, 0x0d030000); /* Gamma ? */
- setfreq(gspca_dev); /* light frequency */
+ setlightfreq(gspca_dev);
/* start the video flow */
set_par(gspca_dev, 0x01000000);
@@ -412,13 +401,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "camera stopped");
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- kfree(sd->jpeg_hdr);
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
@@ -451,78 +433,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->brightness = val;
- if (gspca_dev->streaming)
- setbrightness(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->brightness;
- return 0;
-}
-
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->colors = val;
- if (gspca_dev->streaming)
- setcolors(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->colors;
- return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->lightfreq = val;
- if (gspca_dev->streaming)
- setfreq(gspca_dev);
- return gspca_dev->usb_err;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->lightfreq;
- return 0;
-}
-
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
@@ -573,12 +483,11 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
static const struct sd_desc sd_desc = {
.name = MODULE_NAME,
.ctrls = sd_ctrls,
- .nctrls = ARRAY_SIZE(sd_ctrls),
+ .nctrls = NCTRLS,
.config = sd_config,
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.querymenu = sd_querymenu,
.get_jcomp = sd_get_jcomp,
@@ -586,7 +495,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x05e1, 0x0893)},
{}
};
@@ -614,17 +523,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- info("registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- info("deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/stv0680.c b/drivers/media/video/gspca/stv0680.c
index e50dd7693f74..e2ef41cf72d7 100644
--- a/drivers/media/video/gspca/stv0680.c
+++ b/drivers/media/video/gspca/stv0680.c
@@ -1,7 +1,7 @@
/*
* STV0680 USB Camera Driver
*
- * Copyright (C) 2009 Hans de Goede <hdgoede@redhat.com>
+ * Copyright (C) 2009 Hans de Goede <hdegoede@redhat.com>
*
* This module is adapted from the in kernel v4l1 stv680 driver:
*
@@ -31,7 +31,7 @@
#include "gspca.h"
-MODULE_AUTHOR("Hans de Goede <hdgoede@redhat.com>");
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
MODULE_DESCRIPTION("STV0680 USB Camera Driver");
MODULE_LICENSE("GPL");
@@ -79,8 +79,7 @@ static int stv_sndctrl(struct gspca_dev *gspca_dev, int set, u8 req, u16 val,
val, 0, gspca_dev->usb_buf, size, 500);
if ((ret < 0) && (req != 0x0a))
- PDEBUG(D_ERR,
- "usb_control_msg error %i, request = 0x%x, error = %i",
+ err("usb_control_msg error %i, request = 0x%x, error = %i",
set, req, ret);
return ret;
@@ -237,7 +236,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
if (stv_sndctrl(gspca_dev, 2, 0x06, 0x0100, 0x12) != 0x12 ||
gspca_dev->usb_buf[8] != 0x53 || gspca_dev->usb_buf[9] != 0x05) {
- PDEBUG(D_ERR, "Could not get descriptor 0100.");
+ err("Could not get descriptor 0100.");
return stv0680_handle_error(gspca_dev, -EIO);
}
@@ -328,7 +327,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x0553, 0x0202)},
{USB_DEVICE(0x041e, 0x4007)},
{}
@@ -357,17 +356,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.c b/drivers/media/video/gspca/stv06xx/stv06xx.c
index 14f179a19485..7e0661429293 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -189,7 +189,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH,
STV06XX_URB_MSG_TIMEOUT);
if (err < 0) {
- PDEBUG(D_ERR, "I2C: Read error writing address: %d", err);
+ err("I2C: Read error writing address: %d", err);
return err;
}
@@ -263,7 +263,21 @@ static int stv06xx_init(struct gspca_dev *gspca_dev)
static int stv06xx_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- int err;
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
+ int err, packet_size;
+
+ intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+ alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ if (!alt) {
+ PDEBUG(D_ERR, "Couldn't get altsetting");
+ return -EIO;
+ }
+
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ err = stv06xx_write_bridge(sd, STV_ISO_SIZE_L, packet_size);
+ if (err < 0)
+ return err;
/* Prepare the sensor for start */
err = sd->sensor->start(sd);
@@ -282,6 +296,43 @@ out:
return (err < 0) ? err : 0;
}
+static int stv06xx_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct usb_host_interface *alt;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt->endpoint[0].desc.wMaxPacketSize =
+ cpu_to_le16(sd->sensor->max_packet_size[gspca_dev->curr_mode]);
+
+ return 0;
+}
+
+static int stv06xx_isoc_nego(struct gspca_dev *gspca_dev)
+{
+ int ret, packet_size, min_packet_size;
+ struct usb_host_interface *alt;
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ min_packet_size = sd->sensor->min_packet_size[gspca_dev->curr_mode];
+ if (packet_size <= min_packet_size)
+ return -EIO;
+
+ packet_size -= 100;
+ if (packet_size < min_packet_size)
+ packet_size = min_packet_size;
+ alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size);
+
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+ if (ret < 0)
+ PDEBUG(D_ERR|D_STREAM, "set alt 1 err %d", ret);
+
+ return ret;
+}
+
static void stv06xx_stopN(struct gspca_dev *gspca_dev)
{
int err;
@@ -349,7 +400,7 @@ static void stv06xx_pkt_scan(struct gspca_dev *gspca_dev,
}
/* First byte seem to be 02=data 2nd byte is unknown??? */
- if (sd->bridge == BRIDGE_ST6422 && (id & 0xFF00) == 0x0200)
+ if (sd->bridge == BRIDGE_ST6422 && (id & 0xff00) == 0x0200)
goto frame_data;
switch (id) {
@@ -428,7 +479,7 @@ frame_data:
}
}
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrupt packet length */
@@ -462,7 +513,9 @@ static const struct sd_desc sd_desc = {
.start = stv06xx_start,
.stopN = stv06xx_stopN,
.pkt_scan = stv06xx_pkt_scan,
-#ifdef CONFIG_INPUT
+ .isoc_init = stv06xx_isoc_init,
+ .isoc_nego = stv06xx_isoc_nego,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
@@ -511,7 +564,7 @@ static int stv06xx_config(struct gspca_dev *gspca_dev,
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
/* QuickCam Express */
{USB_DEVICE(0x046d, 0x0840), .driver_info = BRIDGE_STV600 },
/* LEGO cam / QuickCam Web */
@@ -562,17 +615,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx.h b/drivers/media/video/gspca/stv06xx/stv06xx.h
index 992ce530f138..e0f63c51f40d 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx.h
@@ -30,13 +30,14 @@
#ifndef STV06XX_H_
#define STV06XX_H_
+#include <linux/slab.h>
#include "gspca.h"
#define MODULE_NAME "STV06xx"
#define STV_ISOC_ENDPOINT_ADDR 0x81
-#define STV_REG23 0x0423
+#define STV_REG23 0x0423
/* Control registers of the STV0600 ASIC */
#define STV_I2C_PARTNER 0x1420
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
index 706e08dc5254..17531b41a073 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -39,8 +39,8 @@ static const struct ctrl hdcs1x00_ctrl[] = {
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
- .default_value = HDCS_DEFAULT_EXPOSURE,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .default_value = HDCS_DEFAULT_EXPOSURE,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = hdcs_set_exposure,
.get = hdcs_get_exposure
@@ -52,8 +52,8 @@ static const struct ctrl hdcs1x00_ctrl[] = {
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
- .default_value = HDCS_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .default_value = HDCS_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = hdcs_set_gain,
.get = hdcs_get_gain
@@ -83,8 +83,8 @@ static const struct ctrl hdcs1020_ctrl[] = {
.minimum = 0x00,
.maximum = 0xffff,
.step = 0x1,
- .default_value = HDCS_DEFAULT_EXPOSURE,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .default_value = HDCS_DEFAULT_EXPOSURE,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = hdcs_set_exposure,
.get = hdcs_get_exposure
@@ -96,8 +96,8 @@ static const struct ctrl hdcs1020_ctrl[] = {
.minimum = 0x00,
.maximum = 0xff,
.step = 0x1,
- .default_value = HDCS_DEFAULT_GAIN,
- .flags = V4L2_CTRL_FLAG_SLIDER
+ .default_value = HDCS_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
},
.set = hdcs_set_gain,
.get = hdcs_get_gain
@@ -163,7 +163,8 @@ static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
for (i = 0; i < len; i++) {
regs[2 * i] = reg;
regs[2 * i + 1] = vals[i];
- /* All addresses are shifted left one bit as bit 0 toggles r/w */
+ /* All addresses are shifted left one bit
+ * as bit 0 toggles r/w */
reg += 2;
}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
index 37b31c99d956..b538dce96f78 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
@@ -37,7 +37,7 @@
#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_1X00_DEF_HEIGHT 296
#define HDCS_1020_DEF_WIDTH 352
#define HDCS_1020_DEF_HEIGHT 292
@@ -146,6 +146,11 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1x00 = {
.i2c_addr = (0x55 << 1),
.i2c_len = 1,
+ /* FIXME (see if we can lower min_packet_size, needs testing, and also
+ adjusting framerate when the bandwidth gets lower) */
+ .min_packet_size = { 847 },
+ .max_packet_size = { 847 },
+
.init = hdcs_init,
.probe = hdcs_probe_1x00,
.start = hdcs_start,
@@ -160,6 +165,11 @@ const struct stv06xx_sensor stv06xx_sensor_hdcs1020 = {
.i2c_addr = (0x55 << 1),
.i2c_len = 1,
+ /* FIXME (see if we can lower min_packet_size, needs testing, and also
+ adjusting framerate when the bandwidthm gets lower) */
+ .min_packet_size = { 847 },
+ .max_packet_size = { 847 },
+
.init = hdcs_init,
.probe = hdcs_probe_1020,
.start = hdcs_start,
@@ -177,7 +187,6 @@ static const u16 stv_bridge_init[][2] = {
{STV_REG04, 0x07},
{STV_SCAN_RATE, 0x20},
- {STV_ISO_SIZE_L, 847},
{STV_Y_CTRL, 0x01},
{STV_X_CTRL, 0x0a}
};
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
index 285221e6b390..ac47b4c94388 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.c
@@ -208,11 +208,24 @@ static int pb0100_probe(struct sd *sd)
static int pb0100_start(struct sd *sd)
{
- int err;
+ int err, packet_size, max_packet_size;
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
struct cam *cam = &sd->gspca_dev.cam;
s32 *sensor_settings = sd->sensor_priv;
u32 mode = cam->cam_mode[sd->gspca_dev.curr_mode].priv;
+ intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
+ alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+
+ /* If we don't have enough bandwidth use a lower framerate */
+ max_packet_size = sd->sensor->max_packet_size[sd->gspca_dev.curr_mode];
+ if (packet_size < max_packet_size)
+ stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(4)|BIT(3)|BIT(1));
+ else
+ stv06xx_write_sensor(sd, PB_ROWSPEED, BIT(5)|BIT(3)|BIT(1));
+
/* Setup sensor window */
if (mode & PB0100_CROP_TO_VGA) {
stv06xx_write_sensor(sd, PB_RSTART, 30);
@@ -328,9 +341,6 @@ static int pb0100_init(struct sd *sd)
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);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
index 4de4fa5ebc57..757de246dc75 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_pb0100.h
@@ -138,6 +138,9 @@ const struct stv06xx_sensor stv06xx_sensor_pb0100 = {
.i2c_addr = 0xba,
.i2c_len = 2,
+ .min_packet_size = { 635, 847 },
+ .max_packet_size = { 847, 923 },
+
.init = pb0100_init,
.probe = pb0100_probe,
.start = pb0100_start,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
index 934b9cebc1ab..fb229d8ded58 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_sensor.h
@@ -53,6 +53,10 @@ struct stv06xx_sensor {
/* length of an i2c word */
u8 i2c_len;
+ /* Isoc packet size (per mode) */
+ int min_packet_size[4];
+ int max_packet_size[4];
+
/* Probes if the sensor is connected */
int (*probe)(struct sd *sd);
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
index c11f06e4ae76..8a456de4970a 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
@@ -28,6 +28,20 @@
#include "stv06xx_st6422.h"
+/* controls */
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ GAIN,
+ EXPOSURE,
+ NCTRLS /* number of controls */
+};
+
+/* sensor settings */
+struct st6422_settings {
+ struct gspca_ctrl ctrls[NCTRLS];
+};
+
static struct v4l2_pix_format st6422_mode[] = {
/* Note we actually get 124 lines of data, of which we skip the 4st
4 as they are garbage */
@@ -57,9 +71,14 @@ static struct v4l2_pix_format st6422_mode[] = {
},
};
-static const struct ctrl st6422_ctrl[] = {
-#define BRIGHTNESS_IDX 0
- {
+/* V4L2 controls supported by the driver */
+static void st6422_set_brightness(struct gspca_dev *gspca_dev);
+static void st6422_set_contrast(struct gspca_dev *gspca_dev);
+static void st6422_set_gain(struct gspca_dev *gspca_dev);
+static void st6422_set_exposure(struct gspca_dev *gspca_dev);
+
+static const struct ctrl st6422_ctrl[NCTRLS] = {
+[BRIGHTNESS] = {
{
.id = V4L2_CID_BRIGHTNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -69,11 +88,9 @@ static const struct ctrl st6422_ctrl[] = {
.step = 1,
.default_value = 3
},
- .set = st6422_set_brightness,
- .get = st6422_get_brightness
+ .set_control = st6422_set_brightness
},
-#define CONTRAST_IDX 1
- {
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -83,11 +100,9 @@ static const struct ctrl st6422_ctrl[] = {
.step = 1,
.default_value = 11
},
- .set = st6422_set_contrast,
- .get = st6422_get_contrast
+ .set_control = st6422_set_contrast
},
-#define GAIN_IDX 2
- {
+[GAIN] = {
{
.id = V4L2_CID_GAIN,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -97,49 +112,43 @@ static const struct ctrl st6422_ctrl[] = {
.step = 1,
.default_value = 64
},
- .set = st6422_set_gain,
- .get = st6422_get_gain
+ .set_control = st6422_set_gain
},
-#define EXPOSURE_IDX 3
- {
+[EXPOSURE] = {
{
.id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "Exposure",
.minimum = 0,
- .maximum = 1023,
+#define EXPOSURE_MAX 1023
+ .maximum = EXPOSURE_MAX,
.step = 1,
.default_value = 256
},
- .set = st6422_set_exposure,
- .get = st6422_get_exposure
+ .set_control = st6422_set_exposure
},
};
static int st6422_probe(struct sd *sd)
{
- int i;
- s32 *sensor_settings;
+ struct st6422_settings *sensor_settings;
if (sd->bridge != BRIDGE_ST6422)
return -ENODEV;
info("st6422 sensor detected");
- sensor_settings = kmalloc(ARRAY_SIZE(st6422_ctrl) * sizeof(s32),
- GFP_KERNEL);
+ sensor_settings = kmalloc(sizeof *sensor_settings, GFP_KERNEL);
if (!sensor_settings)
return -ENOMEM;
sd->gspca_dev.cam.cam_mode = st6422_mode;
sd->gspca_dev.cam.nmodes = ARRAY_SIZE(st6422_mode);
+ sd->gspca_dev.cam.ctrls = sensor_settings->ctrls;
sd->desc.ctrls = st6422_ctrl;
sd->desc.nctrls = ARRAY_SIZE(st6422_ctrl);
sd->sensor_priv = sensor_settings;
- for (i = 0; i < sd->desc.nctrls; i++)
- sensor_settings[i] = st6422_ctrl[i].qctrl.default_value;
-
return 0;
}
@@ -151,11 +160,11 @@ static int st6422_init(struct sd *sd)
{ STV_ISO_ENABLE, 0x00 }, /* disable capture */
{ 0x1436, 0x00 },
{ 0x1432, 0x03 }, /* 0x00-0x1F brightness */
- { 0x143a, 0xF9 }, /* 0x00-0x0F contrast */
+ { 0x143a, 0xf9 }, /* 0x00-0x0F contrast */
{ 0x0509, 0x38 }, /* R */
{ 0x050a, 0x38 }, /* G */
{ 0x050b, 0x38 }, /* B */
- { 0x050c, 0x2A },
+ { 0x050c, 0x2a },
{ 0x050d, 0x01 },
@@ -213,7 +222,6 @@ static int st6422_init(struct sd *sd)
{ 0x150e, 0x8e },
{ 0x150f, 0x37 },
{ 0x15c0, 0x00 },
- { 0x15c1, 1023 }, /* 160x120, ISOC_PACKET_SIZE */
{ 0x15c3, 0x08 }, /* 0x04/0x14 ... test pictures ??? */
@@ -235,91 +243,92 @@ static void st6422_disconnect(struct sd *sd)
kfree(sd->sensor_priv);
}
-static int st6422_start(struct sd *sd)
+static int setbrightness(struct sd *sd)
{
- int err, packet_size;
- struct cam *cam = &sd->gspca_dev.cam;
- s32 *sensor_settings = sd->sensor_priv;
- struct usb_host_interface *alt;
- struct usb_interface *intf;
-
- intf = usb_ifnum_to_if(sd->gspca_dev.dev, sd->gspca_dev.iface);
- alt = usb_altnum_to_altsetting(intf, sd->gspca_dev.alt);
- if (!alt) {
- PDEBUG(D_ERR, "Couldn't get altsetting");
- return -EIO;
- }
+ struct st6422_settings *sensor_settings = sd->sensor_priv;
- packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
- err = stv06xx_write_bridge(sd, 0x15c1, packet_size);
- if (err < 0)
- return err;
+ /* val goes from 0 -> 31 */
+ return stv06xx_write_bridge(sd, 0x1432,
+ sensor_settings->ctrls[BRIGHTNESS].val);
+}
- if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)
- err = stv06xx_write_bridge(sd, 0x1505, 0x0f);
- else
- err = stv06xx_write_bridge(sd, 0x1505, 0x02);
- if (err < 0)
- return err;
+static int setcontrast(struct sd *sd)
+{
+ struct st6422_settings *sensor_settings = sd->sensor_priv;
+
+ /* Val goes from 0 -> 15 */
+ return stv06xx_write_bridge(sd, 0x143a,
+ sensor_settings->ctrls[CONTRAST].val | 0xf0);
+}
+
+static int setgain(struct sd *sd)
+{
+ struct st6422_settings *sensor_settings = sd->sensor_priv;
+ u8 gain;
+ int err;
+
+ gain = sensor_settings->ctrls[GAIN].val;
- err = st6422_set_brightness(&sd->gspca_dev,
- sensor_settings[BRIGHTNESS_IDX]);
+ /* Set red, green, blue, gain */
+ err = stv06xx_write_bridge(sd, 0x0509, gain);
if (err < 0)
return err;
- err = st6422_set_contrast(&sd->gspca_dev,
- sensor_settings[CONTRAST_IDX]);
+ err = stv06xx_write_bridge(sd, 0x050a, gain);
if (err < 0)
return err;
- err = st6422_set_exposure(&sd->gspca_dev,
- sensor_settings[EXPOSURE_IDX]);
+ err = stv06xx_write_bridge(sd, 0x050b, gain);
if (err < 0)
return err;
- err = st6422_set_gain(&sd->gspca_dev,
- sensor_settings[GAIN_IDX]);
+ /* 2 mystery writes */
+ err = stv06xx_write_bridge(sd, 0x050c, 0x2a);
if (err < 0)
return err;
- PDEBUG(D_STREAM, "Starting stream");
-
- return 0;
+ return stv06xx_write_bridge(sd, 0x050d, 0x01);
}
-static int st6422_stop(struct sd *sd)
+static int setexposure(struct sd *sd)
{
- PDEBUG(D_STREAM, "Halting stream");
-
- return 0;
-}
-
-static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[BRIGHTNESS_IDX];
+ struct st6422_settings *sensor_settings = sd->sensor_priv;
+ u16 expo;
+ int err;
- PDEBUG(D_V4L2, "Read brightness %d", *val);
+ expo = sensor_settings->ctrls[EXPOSURE].val;
+ err = stv06xx_write_bridge(sd, 0x143d, expo & 0xff);
+ if (err < 0)
+ return err;
- return 0;
+ return stv06xx_write_bridge(sd, 0x143e, expo >> 8);
}
-static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
+static int st6422_start(struct sd *sd)
{
int err;
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
+ struct cam *cam = &sd->gspca_dev.cam;
- sensor_settings[BRIGHTNESS_IDX] = val;
+ if (cam->cam_mode[sd->gspca_dev.curr_mode].priv)
+ err = stv06xx_write_bridge(sd, 0x1505, 0x0f);
+ else
+ err = stv06xx_write_bridge(sd, 0x1505, 0x02);
+ if (err < 0)
+ return err;
- if (!gspca_dev->streaming)
- return 0;
+ err = setbrightness(sd);
+ if (err < 0)
+ return err;
- /* val goes from 0 -> 31 */
- PDEBUG(D_V4L2, "Set brightness to %d", val);
- err = stv06xx_write_bridge(sd, 0x1432, val);
+ err = setcontrast(sd);
+ if (err < 0)
+ return err;
+
+ err = setexposure(sd);
+ if (err < 0)
+ return err;
+
+ err = setgain(sd);
if (err < 0)
return err;
@@ -328,125 +337,65 @@ static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val)
return (err < 0) ? err : 0;
}
-static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val)
+static int st6422_stop(struct sd *sd)
{
- struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- *val = sensor_settings[CONTRAST_IDX];
-
- PDEBUG(D_V4L2, "Read contrast %d", *val);
+ PDEBUG(D_STREAM, "Halting stream");
return 0;
}
-static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val)
+static void st6422_set_brightness(struct gspca_dev *gspca_dev)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[CONTRAST_IDX] = val;
- if (!gspca_dev->streaming)
- return 0;
-
- /* Val goes from 0 -> 15 */
- PDEBUG(D_V4L2, "Set contrast to %d\n", val);
- err = stv06xx_write_bridge(sd, 0x143a, 0xf0 | val);
- if (err < 0)
- return err;
+ err = setbrightness(sd);
/* commit settings */
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return (err < 0) ? err : 0;
-}
-
-static int st6422_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];
-
- PDEBUG(D_V4L2, "Read gain %d", *val);
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return 0;
+ gspca_dev->usb_err = err;
}
-static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val)
+static void st6422_set_contrast(struct gspca_dev *gspca_dev)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[GAIN_IDX] = val;
-
- if (!gspca_dev->streaming)
- return 0;
-
- PDEBUG(D_V4L2, "Set gain to %d", val);
- /* Set red, green, blue, gain */
- err = stv06xx_write_bridge(sd, 0x0509, val);
- if (err < 0)
- return err;
-
- err = stv06xx_write_bridge(sd, 0x050a, val);
- if (err < 0)
- return err;
-
- err = stv06xx_write_bridge(sd, 0x050b, val);
- if (err < 0)
- return err;
-
- /* 2 mystery writes */
- err = stv06xx_write_bridge(sd, 0x050c, 0x2a);
- if (err < 0)
- return err;
-
- err = stv06xx_write_bridge(sd, 0x050d, 0x01);
- if (err < 0)
- return err;
+ err = setcontrast(sd);
/* commit settings */
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return (err < 0) ? err : 0;
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+
+ gspca_dev->usb_err = err;
}
-static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
+static void st6422_set_gain(struct gspca_dev *gspca_dev)
{
+ int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
- *val = sensor_settings[EXPOSURE_IDX];
+ err = setgain(sd);
- PDEBUG(D_V4L2, "Read exposure %d", *val);
+ /* commit settings */
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return 0;
+ gspca_dev->usb_err = err;
}
-static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
+static void st6422_set_exposure(struct gspca_dev *gspca_dev)
{
int err;
struct sd *sd = (struct sd *) gspca_dev;
- s32 *sensor_settings = sd->sensor_priv;
-
- sensor_settings[EXPOSURE_IDX] = val;
- if (!gspca_dev->streaming)
- return 0;
-
- PDEBUG(D_V4L2, "Set exposure to %d\n", val);
- err = stv06xx_write_bridge(sd, 0x143d, val & 0xff);
- if (err < 0)
- return err;
-
- err = stv06xx_write_bridge(sd, 0x143e, val >> 8);
- if (err < 0)
- return err;
+ err = setexposure(sd);
/* commit settings */
- err = stv06xx_write_bridge(sd, 0x143f, 0x01);
- return (err < 0) ? err : 0;
+ if (err >= 0)
+ err = stv06xx_write_bridge(sd, 0x143f, 0x01);
+
+ gspca_dev->usb_err = err;
}
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
index b2d45fe50522..d7498e06432b 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_st6422.h
@@ -37,18 +37,11 @@ static int st6422_init(struct sd *sd);
static int st6422_stop(struct sd *sd);
static void st6422_disconnect(struct sd *sd);
-/* V4L2 controls supported by the driver */
-static int st6422_get_brightness(struct gspca_dev *gspca_dev, __s32 *val);
-static int st6422_set_brightness(struct gspca_dev *gspca_dev, __s32 val);
-static int st6422_get_contrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int st6422_set_contrast(struct gspca_dev *gspca_dev, __s32 val);
-static int st6422_get_gain(struct gspca_dev *gspca_dev, __s32 *val);
-static int st6422_set_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int st6422_get_exposure(struct gspca_dev *gspca_dev, __s32 *val);
-static int st6422_set_exposure(struct gspca_dev *gspca_dev, __s32 val);
-
const struct stv06xx_sensor stv06xx_sensor_st6422 = {
.name = "ST6422",
+ /* No known way to lower framerate in case of less bandwidth */
+ .min_packet_size = { 300, 847 },
+ .max_packet_size = { 300, 847 },
.init = st6422_init,
.probe = st6422_probe,
.start = st6422_start,
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
index 11a0c002f5dc..f8398434c328 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.c
@@ -66,7 +66,7 @@ static const struct ctrl vv6410_ctrl[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
- .default_value = 0
+ .default_value = 0
},
.set = vv6410_set_vflip,
.get = vv6410_get_vflip
diff --git a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
index 96c61926d372..7fe3587f5f71 100644
--- a/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
+++ b/drivers/media/video/gspca/stv06xx/stv06xx_vv6410.h
@@ -157,8 +157,8 @@
/* Audio Amplifier Setup Register */
#define VV6410_AT1 0x79
-#define VV6410_HFLIP (1 << 3)
-#define VV6410_VFLIP (1 << 4)
+#define VV6410_HFLIP (1 << 3)
+#define VV6410_VFLIP (1 << 4)
#define VV6410_LOW_POWER_MODE (1 << 0)
#define VV6410_SOFT_RESET (1 << 2)
@@ -197,6 +197,10 @@ const struct stv06xx_sensor stv06xx_sensor_vv6410 = {
.i2c_flush = 5,
.i2c_addr = 0x20,
.i2c_len = 1,
+ /* FIXME (see if we can lower packet_size-s, needs testing, and also
+ adjusting framerate when the bandwidth gets lower) */
+ .min_packet_size = { 1023 },
+ .max_packet_size = { 1023 },
.init = vv6410_init,
.probe = vv6410_probe,
.start = vv6410_start,
@@ -220,10 +224,6 @@ 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},
@@ -232,7 +232,6 @@ static const struct stv_init stv_bridge_init[] = {
{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] = {
diff --git a/drivers/media/video/gspca/sunplus.c b/drivers/media/video/gspca/sunplus.c
index 0c786e00ebcf..543542af2720 100644
--- a/drivers/media/video/gspca/sunplus.c
+++ b/drivers/media/video/gspca/sunplus.c
@@ -54,7 +54,7 @@ struct sd {
#define MegapixV4 4
#define MegaImageVI 5
- u8 *jpeg_hdr;
+ u8 jpeg_hdr[JPEG_HDR_SZ];
};
/* V4L2 controls supported by the driver */
@@ -343,7 +343,7 @@ static void reg_r(struct gspca_dev *gspca_dev,
len ? gspca_dev->usb_buf : NULL, len,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_r err %d", ret);
+ err("reg_r err %d", ret);
gspca_dev->usb_err = ret;
}
}
@@ -368,7 +368,7 @@ static void reg_w_1(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf, 1,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w_1 err %d", ret);
+ err("reg_w_1 err %d", ret);
gspca_dev->usb_err = ret;
}
}
@@ -388,7 +388,7 @@ static void reg_w_riv(struct gspca_dev *gspca_dev,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0, 500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_w_riv err %d", ret);
+ err("reg_w_riv err %d", ret);
gspca_dev->usb_err = ret;
return;
}
@@ -413,7 +413,7 @@ static u8 reg_r_1(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf, 1,
500); /* timeout */
if (ret < 0) {
- PDEBUG(D_ERR, "reg_r_1 err %d", ret);
+ err("reg_r_1 err %d", ret);
gspca_dev->usb_err = ret;
return 0;
}
@@ -440,7 +440,7 @@ static u16 reg_r_12(struct gspca_dev *gspca_dev,
gspca_dev->usb_buf, length,
500);
if (ret < 0) {
- PDEBUG(D_ERR, "reg_r_12 err %d", ret);
+ err("reg_r_12 err %d", ret);
gspca_dev->usb_err = ret;
return 0;
}
@@ -463,7 +463,7 @@ static void setup_qtable(struct gspca_dev *gspca_dev,
/* loop over y components */
for (i = 0; i < 64; i++)
- reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
+ reg_w_riv(gspca_dev, 0x00, 0x2800 + i, qtable[0][i]);
/* loop over c components */
for (i = 0; i < 64; i++)
@@ -712,8 +712,9 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->subtype = id->driver_info;
if (sd->subtype == AiptekMiniPenCam13) {
-/* try to get the firmware as some cam answer 2.0.1.2.2
- * and should be a spca504b then overwrite that setting */
+
+ /* try to get the firmware as some cam answer 2.0.1.2.2
+ * and should be a spca504b then overwrite that setting */
reg_r(gspca_dev, 0x20, 0, 1);
switch (gspca_dev->usb_buf[0]) {
case 1:
@@ -733,7 +734,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
/* case BRIDGE_SPCA504: */
/* case BRIDGE_SPCA536: */
cam->cam_mode = vga_mode;
- cam->nmodes =ARRAY_SIZE(vga_mode);
+ cam->nmodes = ARRAY_SIZE(vga_mode);
break;
case BRIDGE_SPCA533:
cam->cam_mode = custom_mode;
@@ -805,7 +806,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 1);
- /* Twice sequencial need status 0xff->0x9e->0x9d */
+ /* Twice sequential need status 0xff->0x9e->0x9d */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 0);
@@ -842,9 +843,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
int enable;
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x22); /* JPEG 411 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
@@ -880,7 +878,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
/* Set AE AWB Banding Type 3-> 50Hz 2-> 60Hz */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 1);
- /* Twice sequencial need status 0xff->0x9e->0x9d */
+ /* Twice sequential need status 0xff->0x9e->0x9d */
spca504A_acknowledged_command(gspca_dev, 0x24,
8, 3, 0x9e, 0);
spca504A_acknowledged_command(gspca_dev, 0x24,
@@ -954,13 +952,6 @@ static void sd_stopN(struct gspca_dev *gspca_dev)
}
}
-static void sd_stop0(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- kfree(sd->jpeg_hdr);
-}
-
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
@@ -1162,7 +1153,6 @@ static const struct sd_desc sd_desc = {
.init = sd_init,
.start = sd_start,
.stopN = sd_stopN,
- .stop0 = sd_stop0,
.pkt_scan = sd_pkt_scan,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
@@ -1172,7 +1162,7 @@ static const struct sd_desc sd_desc = {
#define BS(bridge, subtype) \
.driver_info = (BRIDGE_ ## bridge << 8) \
| (subtype)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x400b), BS(SPCA504C, 0)},
{USB_DEVICE(0x041e, 0x4012), BS(SPCA504C, 0)},
{USB_DEVICE(0x041e, 0x4013), BS(SPCA504C, 0)},
@@ -1258,17 +1248,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/t613.c b/drivers/media/video/gspca/t613.c
index 63014372adbc..a3eccd815766 100644
--- a/drivers/media/video/gspca/t613.c
+++ b/drivers/media/video/gspca/t613.c
@@ -1,5 +1,7 @@
/*
- * V4L2 by Jean-Francois Moine <http://moinejf.free.fr>
+ * T613 subdriver
+ *
+ * Copyright (C) 2010 Jean-Francois Moine (http://moinejf.free.fr)
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,6 +28,7 @@
#define MODULE_NAME "t613"
+#include <linux/slab.h>
#include "gspca.h"
#define V4L2_CID_EFFECTS (V4L2_CID_PRIVATE_BASE + 0)
@@ -44,18 +47,20 @@ struct sd {
u8 gamma;
u8 sharpness;
u8 freq;
- u8 red_balance; /* split balance */
- u8 blue_balance;
- u8 global_gain; /* aka gain */
- u8 whitebalance; /* set default r/g/b and activate */
+ u8 red_gain;
+ u8 blue_gain;
+ u8 green_gain;
+ u8 awb; /* set default r/g/b and activate */
u8 mirror;
u8 effect;
u8 sensor;
-#define SENSOR_OM6802 0
-#define SENSOR_OTHER 1
-#define SENSOR_TAS5130A 2
-#define SENSOR_LT168G 3 /* must verify if this is the actual model */
+};
+enum sensors {
+ SENSOR_OM6802,
+ SENSOR_OTHER,
+ SENSOR_TAS5130A,
+ SENSOR_LT168G, /* must verify if this is the actual model */
};
/* V4L2 controls supported by the driver */
@@ -74,24 +79,22 @@ static int sd_getsharpness(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_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getwhitebalance(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_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val);
-
-static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+
+static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_seteffect(struct gspca_dev *gspca_dev, __s32 val);
static int sd_geteffect(struct gspca_dev *gspca_dev, __s32 *val);
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu);
-
static const struct ctrl sd_ctrls[] = {
{
{
@@ -177,8 +180,8 @@ static const struct ctrl sd_ctrls[] = {
#define MIRROR_DEF 0
.default_value = MIRROR_DEF,
},
- .set = sd_setflip,
- .get = sd_getflip
+ .set = sd_setmirror,
+ .get = sd_getmirror
},
{
{
@@ -198,15 +201,15 @@ static const struct ctrl sd_ctrls[] = {
{
.id = V4L2_CID_AUTO_WHITE_BALANCE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "White Balance",
+ .name = "Auto White Balance",
.minimum = 0,
.maximum = 1,
.step = 1,
-#define WHITE_BALANCE_DEF 0
- .default_value = WHITE_BALANCE_DEF,
+#define AWB_DEF 0
+ .default_value = AWB_DEF,
},
- .set = sd_setwhitebalance,
- .get = sd_getwhitebalance
+ .set = sd_setawb,
+ .get = sd_getawb
},
{
{
@@ -244,11 +247,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0x10,
.maximum = 0x40,
.step = 1,
-#define BLUE_BALANCE_DEF 0x20
- .default_value = BLUE_BALANCE_DEF,
+#define BLUE_GAIN_DEF 0x20
+ .default_value = BLUE_GAIN_DEF,
},
- .set = sd_setblue_balance,
- .get = sd_getblue_balance,
+ .set = sd_setblue_gain,
+ .get = sd_getblue_gain,
},
{
{
@@ -258,11 +261,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0x10,
.maximum = 0x40,
.step = 1,
-#define RED_BALANCE_DEF 0x20
- .default_value = RED_BALANCE_DEF,
+#define RED_GAIN_DEF 0x20
+ .default_value = RED_GAIN_DEF,
},
- .set = sd_setred_balance,
- .get = sd_getred_balance,
+ .set = sd_setred_gain,
+ .get = sd_getred_gain,
},
{
{
@@ -272,24 +275,14 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0x10,
.maximum = 0x40,
.step = 1,
-#define global_gain_DEF 0x20
- .default_value = global_gain_DEF,
+#define GAIN_DEF 0x20
+ .default_value = GAIN_DEF,
},
- .set = sd_setglobal_gain,
- .get = sd_getglobal_gain,
+ .set = sd_setgain,
+ .get = sd_getgain,
},
};
-static char *effects_control[] = {
- "Normal",
- "Emboss", /* disabled */
- "Monochrome",
- "Sepia",
- "Sketch",
- "Sun Effect", /* disabled */
- "Negative",
-};
-
static const struct v4l2_pix_format vga_mode_t16[] = {
{160, 120, V4L2_PIX_FMT_JPEG, V4L2_FIELD_NONE,
.bytesperline = 160,
@@ -327,7 +320,6 @@ struct additional_sensor_data {
const u8 data1[10];
const u8 data2[9];
const u8 data3[9];
- const u8 data4[4];
const u8 data5[6];
const u8 stream[4];
};
@@ -375,7 +367,7 @@ static const u8 n4_lt168g[] = {
};
static const struct additional_sensor_data sensor_data[] = {
- { /* 0: OM6802 */
+[SENSOR_OM6802] = {
.n3 =
{0x61, 0x68, 0x65, 0x0a, 0x60, 0x04},
.n4 = n4_om6802,
@@ -392,14 +384,12 @@ static const struct additional_sensor_data sensor_data[] = {
.data3 =
{0x80, 0xff, 0xff, 0x80, 0xff, 0xff, 0x80, 0xff,
0xff},
- .data4 = /*Freq (50/60Hz). Splitted for test purpose */
- {0x66, 0xca, 0xa8, 0xf0},
.data5 = /* this could be removed later */
{0x0c, 0x03, 0xab, 0x13, 0x81, 0x23},
.stream =
{0x0b, 0x04, 0x0a, 0x78},
},
- { /* 1: OTHER */
+[SENSOR_OTHER] = {
.n3 =
{0x61, 0xc2, 0x65, 0x88, 0x60, 0x00},
.n4 = n4_other,
@@ -416,14 +406,12 @@ static const struct additional_sensor_data sensor_data[] = {
.data3 =
{0x4e, 0x9c, 0xec, 0x40, 0x80, 0xc0, 0x48, 0x96,
0xd9},
- .data4 =
- {0x66, 0x00, 0xa8, 0xa8},
.data5 =
{0x0c, 0x03, 0xab, 0x29, 0x81, 0x69},
.stream =
{0x0b, 0x04, 0x0a, 0x00},
},
- { /* 2: TAS5130A */
+[SENSOR_TAS5130A] = {
.n3 =
{0x61, 0xc2, 0x65, 0x0d, 0x60, 0x08},
.n4 = n4_tas5130a,
@@ -440,14 +428,12 @@ static const struct additional_sensor_data sensor_data[] = {
.data3 =
{0x60, 0xa8, 0xe0, 0x60, 0xa8, 0xe0, 0x60, 0xa8,
0xe0},
- .data4 = /* Freq (50/60Hz). Splitted for test purpose */
- {0x66, 0x00, 0xa8, 0xe8},
.data5 =
{0x0c, 0x03, 0xab, 0x10, 0x81, 0x20},
.stream =
{0x0b, 0x04, 0x0a, 0x40},
},
- { /* 3: LT168G */
+[SENSOR_LT168G] = {
.n3 = {0x61, 0xc2, 0x65, 0x68, 0x60, 0x00},
.n4 = n4_lt168g,
.n4sz = sizeof n4_lt168g,
@@ -460,7 +446,6 @@ static const struct additional_sensor_data sensor_data[] = {
0xff},
.data3 = {0x40, 0x80, 0xc0, 0x50, 0xa0, 0xf0, 0x53, 0xa6,
0xff},
- .data4 = {0x66, 0x41, 0xa8, 0xf0},
.data5 = {0x0c, 0x03, 0xab, 0x4b, 0x81, 0x2b},
.stream = {0x0b, 0x04, 0x0a, 0x28},
},
@@ -469,6 +454,15 @@ static const struct additional_sensor_data sensor_data[] = {
#define MAX_EFFECTS 7
/* easily done by soft, this table could be removed,
* i keep it here just in case */
+static char *effects_control[MAX_EFFECTS] = {
+ "Normal",
+ "Emboss", /* disabled */
+ "Monochrome",
+ "Sepia",
+ "Sketch",
+ "Sun Effect", /* disabled */
+ "Negative",
+};
static const u8 effects_table[MAX_EFFECTS][6] = {
{0xa8, 0xe8, 0xc6, 0xd2, 0xc0, 0x00}, /* Normal */
{0xa8, 0xc8, 0xc6, 0x52, 0xc0, 0x04}, /* Repujar */
@@ -480,40 +474,41 @@ static const u8 effects_table[MAX_EFFECTS][6] = {
};
static const u8 gamma_table[GAMMA_MAX][17] = {
- {0x00, 0x3e, 0x69, 0x85, 0x95, 0xa1, 0xae, 0xb9, /* 0 */
- 0xc2, 0xcb, 0xd4, 0xdb, 0xe3, 0xea, 0xf1, 0xf8,
+/* gamma table from cam1690.ini */
+ {0x00, 0x00, 0x01, 0x04, 0x08, 0x0e, 0x16, 0x21, /* 0 */
+ 0x2e, 0x3d, 0x50, 0x65, 0x7d, 0x99, 0xb8, 0xdb,
0xff},
- {0x00, 0x33, 0x5a, 0x75, 0x85, 0x93, 0xa1, 0xad, /* 1 */
- 0xb7, 0xc2, 0xcb, 0xd4, 0xde, 0xe7, 0xf0, 0xf7,
+ {0x00, 0x01, 0x03, 0x08, 0x0e, 0x16, 0x21, 0x2d, /* 1 */
+ 0x3c, 0x4d, 0x60, 0x75, 0x8d, 0xa6, 0xc2, 0xe1,
0xff},
- {0x00, 0x2f, 0x51, 0x6b, 0x7c, 0x8a, 0x99, 0xa6, /* 2 */
- 0xb1, 0xbc, 0xc6, 0xd0, 0xdb, 0xe4, 0xed, 0xf6,
+ {0x00, 0x01, 0x05, 0x0b, 0x12, 0x1c, 0x28, 0x35, /* 2 */
+ 0x45, 0x56, 0x69, 0x7e, 0x95, 0xad, 0xc7, 0xe3,
0xff},
- {0x00, 0x29, 0x48, 0x60, 0x72, 0x81, 0x90, 0x9e, /* 3 */
- 0xaa, 0xb5, 0xbf, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
+ {0x00, 0x02, 0x07, 0x0f, 0x18, 0x24, 0x30, 0x3f, /* 3 */
+ 0x4f, 0x61, 0x73, 0x88, 0x9d, 0xb4, 0xcd, 0xe6,
0xff},
- {0x00, 0x23, 0x3f, 0x55, 0x68, 0x77, 0x86, 0x95, /* 4 */
- 0xa2, 0xad, 0xb9, 0xc6, 0xd2, 0xde, 0xe9, 0xf4,
+ {0x00, 0x04, 0x0b, 0x15, 0x20, 0x2d, 0x3b, 0x4a, /* 4 */
+ 0x5b, 0x6c, 0x7f, 0x92, 0xa7, 0xbc, 0xd2, 0xe9,
0xff},
- {0x00, 0x1b, 0x33, 0x48, 0x59, 0x69, 0x79, 0x87, /* 5 */
- 0x96, 0xa3, 0xb1, 0xbe, 0xcc, 0xda, 0xe7, 0xf3,
+ {0x00, 0x07, 0x11, 0x15, 0x20, 0x2d, 0x48, 0x58, /* 5 */
+ 0x68, 0x79, 0x8b, 0x9d, 0xb0, 0xc4, 0xd7, 0xec,
0xff},
- {0x00, 0x02, 0x10, 0x20, 0x32, 0x40, 0x57, 0x67, /* 6 */
+ {0x00, 0x0c, 0x1a, 0x29, 0x38, 0x47, 0x57, 0x67, /* 6 */
0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee,
0xff},
- {0x00, 0x02, 0x14, 0x26, 0x38, 0x4a, 0x60, 0x70, /* 7 */
+ {0x00, 0x10, 0x20, 0x30, 0x40, 0x50, 0x60, 0x70, /* 7 */
0x80, 0x90, 0xa0, 0xb0, 0xc0, 0xd0, 0xe0, 0xf0,
0xff},
- {0x00, 0x10, 0x22, 0x35, 0x47, 0x5a, 0x69, 0x79, /* 8 */
- 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe0, 0xf0,
+ {0x00, 0x15, 0x27, 0x38, 0x49, 0x59, 0x69, 0x79, /* 8 */
+ 0x88, 0x97, 0xa7, 0xb6, 0xc4, 0xd3, 0xe2, 0xf0,
0xff},
- {0x00, 0x10, 0x26, 0x40, 0x54, 0x65, 0x75, 0x84, /* 9 */
- 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd6, 0xe0, 0xf0,
+ {0x00, 0x1c, 0x30, 0x43, 0x54, 0x65, 0x75, 0x84, /* 9 */
+ 0x93, 0xa1, 0xb0, 0xbd, 0xca, 0xd8, 0xe5, 0xf2,
0xff},
- {0x00, 0x18, 0x2b, 0x44, 0x60, 0x70, 0x80, 0x8e, /* 10 */
- 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xd8, 0xe2, 0xf0,
+ {0x00, 0x24, 0x3b, 0x4f, 0x60, 0x70, 0x80, 0x8e, /* 10 */
+ 0x9c, 0xaa, 0xb7, 0xc4, 0xd0, 0xdc, 0xe8, 0xf3,
0xff},
- {0x00, 0x1a, 0x34, 0x52, 0x66, 0x7e, 0x8d, 0x9b, /* 11 */
+ {0x00, 0x2a, 0x3c, 0x5d, 0x6e, 0x7e, 0x8d, 0x9b, /* 11 */
0xa8, 0xb4, 0xc0, 0xcb, 0xd6, 0xe1, 0xeb, 0xf5,
0xff},
{0x00, 0x3f, 0x5a, 0x6e, 0x7f, 0x8e, 0x9c, 0xa8, /* 12 */
@@ -577,12 +572,11 @@ static void reg_w_buf(struct gspca_dev *gspca_dev,
} else {
u8 *tmpbuf;
- tmpbuf = kmalloc(len, GFP_KERNEL);
+ tmpbuf = kmemdup(buffer, len, GFP_KERNEL);
if (!tmpbuf) {
err("Out of memory");
return;
}
- memcpy(tmpbuf, buffer, len);
usb_control_msg(gspca_dev->dev,
usb_sndctrlpipe(gspca_dev->dev, 0),
0,
@@ -625,7 +619,6 @@ static void reg_w_ixbuf(struct gspca_dev *gspca_dev,
kfree(tmpbuf);
}
-/* Reported as OM6802*/
static void om6802_sensor_init(struct gspca_dev *gspca_dev)
{
int i;
@@ -703,12 +696,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->autogain = AUTOGAIN_DEF;
sd->mirror = MIRROR_DEF;
sd->freq = FREQ_DEF;
- sd->whitebalance = WHITE_BALANCE_DEF;
+ sd->awb = AWB_DEF;
sd->sharpness = SHARPNESS_DEF;
sd->effect = EFFECTS_DEF;
- sd->red_balance = RED_BALANCE_DEF;
- sd->blue_balance = BLUE_BALANCE_DEF;
- sd->global_gain = global_gain_DEF;
+ sd->red_gain = RED_GAIN_DEF;
+ sd->blue_gain = BLUE_GAIN_DEF;
+ sd->green_gain = GAIN_DEF * 3 - RED_GAIN_DEF - BLUE_GAIN_DEF;
return 0;
}
@@ -761,40 +754,59 @@ static void setgamma(struct gspca_dev *gspca_dev)
reg_w_ixbuf(gspca_dev, 0x90,
gamma_table[sd->gamma], sizeof gamma_table[0]);
}
-static void setglobalgain(struct gspca_dev *gspca_dev)
-{
+static void setRGB(struct gspca_dev *gspca_dev)
+{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w(gspca_dev, (sd->red_balance << 8) + 0x87);
- reg_w(gspca_dev, (sd->blue_balance << 8) + 0x88);
- reg_w(gspca_dev, (sd->global_gain << 8) + 0x89);
+ u8 all_gain_reg[6] =
+ {0x87, 0x00, 0x88, 0x00, 0x89, 0x00};
+
+ all_gain_reg[1] = sd->red_gain;
+ all_gain_reg[3] = sd->blue_gain;
+ all_gain_reg[5] = sd->green_gain;
+ reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
}
-/* Generic fnc for r/b balance, exposure and whitebalance */
-static void setbalance(struct gspca_dev *gspca_dev)
+/* Generic fnc for r/b balance, exposure and awb */
+static void setawb(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
+ u16 reg80;
- /* on whitebalance leave defaults values */
- if (sd->whitebalance) {
- reg_w(gspca_dev, 0x3c80);
- } else {
- reg_w(gspca_dev, 0x3880);
+ reg80 = (sensor_data[sd->sensor].reg80 << 8) | 0x80;
+
+ /* on awb leave defaults values */
+ if (!sd->awb) {
/* shoud we wait here.. */
- /* update and reset 'global gain' with webcam parameters */
- sd->red_balance = reg_r(gspca_dev, 0x0087);
- sd->blue_balance = reg_r(gspca_dev, 0x0088);
- sd->global_gain = reg_r(gspca_dev, 0x0089);
- setglobalgain(gspca_dev);
+ /* update and reset RGB gains with webcam values */
+ sd->red_gain = reg_r(gspca_dev, 0x0087);
+ sd->blue_gain = reg_r(gspca_dev, 0x0088);
+ sd->green_gain = reg_r(gspca_dev, 0x0089);
+ reg80 &= ~0x0400; /* AWB off */
}
-
+ reg_w(gspca_dev, reg80);
+ reg_w(gspca_dev, reg80);
}
-
-
-static void setwhitebalance(struct gspca_dev *gspca_dev)
+static void init_gains(struct gspca_dev *gspca_dev)
{
- setbalance(gspca_dev);
+ struct sd *sd = (struct sd *) gspca_dev;
+ u16 reg80;
+ u8 all_gain_reg[8] =
+ {0x87, 0x00, 0x88, 0x00, 0x89, 0x00, 0x80, 0x00};
+
+ all_gain_reg[1] = sd->red_gain;
+ all_gain_reg[3] = sd->blue_gain;
+ all_gain_reg[5] = sd->green_gain;
+ reg80 = sensor_data[sd->sensor].reg80;
+ if (!sd->awb)
+ reg80 &= ~0x04;
+ all_gain_reg[7] = reg80;
+ reg_w_buf(gspca_dev, all_gain_reg, sizeof all_gain_reg);
+
+ reg_w(gspca_dev, (sd->red_gain << 8) + 0x87);
+ reg_w(gspca_dev, (sd->blue_gain << 8) + 0x88);
+ reg_w(gspca_dev, (sd->green_gain << 8) + 0x89);
}
static void setsharpness(struct gspca_dev *gspca_dev)
@@ -807,6 +819,38 @@ static void setsharpness(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, reg_to_write);
}
+static void setfreq(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 reg66;
+ u8 freq[4] = { 0x66, 0x00, 0xa8, 0xe8 };
+
+ switch (sd->sensor) {
+ case SENSOR_LT168G:
+ if (sd->freq != 0)
+ freq[3] = 0xa8;
+ reg66 = 0x41;
+ break;
+ case SENSOR_OM6802:
+ reg66 = 0xca;
+ break;
+ default:
+ reg66 = 0x40;
+ break;
+ }
+ switch (sd->freq) {
+ case 0: /* no flicker */
+ freq[3] = 0xf0;
+ break;
+ case 2: /* 60Hz */
+ reg66 &= ~0x40;
+ break;
+ }
+ freq[1] = reg66;
+
+ reg_w_buf(gspca_dev, freq, sizeof freq);
+}
+
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
@@ -848,7 +892,7 @@ static int sd_init(struct gspca_dev *gspca_dev)
sd->sensor = SENSOR_OM6802;
break;
default:
- PDEBUG(D_ERR|D_PROBE, "unknown sensor %04x", sensor_id);
+ err("unknown sensor %04x", sensor_id);
return -EINVAL;
}
@@ -901,13 +945,9 @@ static int sd_init(struct gspca_dev *gspca_dev)
setgamma(gspca_dev);
setcolors(gspca_dev);
setsharpness(gspca_dev);
- setwhitebalance(gspca_dev);
-
- reg_w(gspca_dev, 0x2087); /* tied to white balance? */
- reg_w(gspca_dev, 0x2088);
- reg_w(gspca_dev, 0x2089);
+ init_gains(gspca_dev);
+ setfreq(gspca_dev);
- reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
reg_w_buf(gspca_dev, sensor->data5, sizeof sensor->data5);
reg_w_buf(gspca_dev, sensor->nset8, sizeof sensor->nset8);
reg_w_buf(gspca_dev, sensor->stream, sizeof sensor->stream);
@@ -926,16 +966,16 @@ static int sd_init(struct gspca_dev *gspca_dev)
return 0;
}
-static void setflip(struct gspca_dev *gspca_dev)
+static void setmirror(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- u8 flipcmd[8] =
+ u8 hflipcmd[8] =
{0x62, 0x07, 0x63, 0x03, 0x64, 0x00, 0x60, 0x09};
if (sd->mirror)
- flipcmd[3] = 0x01;
+ hflipcmd[3] = 0x01;
- reg_w_buf(gspca_dev, flipcmd, sizeof flipcmd);
+ reg_w_buf(gspca_dev, hflipcmd, sizeof hflipcmd);
}
static void seteffect(struct gspca_dev *gspca_dev)
@@ -956,17 +996,6 @@ static void seteffect(struct gspca_dev *gspca_dev)
reg_w(gspca_dev, 0xfaa6);
}
-static void setlightfreq(struct gspca_dev *gspca_dev)
-{
- struct sd *sd = (struct sd *) gspca_dev;
- u8 freq[4] = { 0x66, 0x40, 0xa8, 0xe8 };
-
- if (sd->freq == 2) /* 60hz */
- freq[1] = 0x00;
-
- reg_w_buf(gspca_dev, freq, sizeof freq);
-}
-
/* Is this really needed?
* i added some module parameters for test with some users */
static void poll_sensor(struct gspca_dev *gspca_dev)
@@ -979,9 +1008,7 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
static const u8 poll2[] =
{0x67, 0x02, 0x68, 0x71, 0x69, 0x72, 0x72, 0xa9,
0x73, 0x02, 0x73, 0x02, 0x60, 0x14};
- static const u8 poll3[] =
- {0x87, 0x3f, 0x88, 0x20, 0x89, 0x2d};
- static const u8 poll4[] =
+ static const u8 noise03[] = /* (some differences / ms-drv) */
{0xa6, 0x0a, 0xea, 0xcf, 0xbe, 0x26, 0xb1, 0x5f,
0xa1, 0xb1, 0xda, 0x6b, 0xdb, 0x98, 0xdf, 0x0c,
0xc2, 0x80, 0xc3, 0x10};
@@ -989,8 +1016,7 @@ static void poll_sensor(struct gspca_dev *gspca_dev)
PDEBUG(D_STREAM, "[Sensor requires polling]");
reg_w_buf(gspca_dev, poll1, sizeof poll1);
reg_w_buf(gspca_dev, poll2, sizeof poll2);
- reg_w_buf(gspca_dev, poll3, sizeof poll3);
- reg_w_buf(gspca_dev, poll4, sizeof poll4);
+ reg_w_buf(gspca_dev, noise03, sizeof noise03);
}
static int sd_start(struct gspca_dev *gspca_dev)
@@ -1025,12 +1051,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OM6802:
om6802_sensor_init(gspca_dev);
break;
- case SENSOR_LT168G:
- break;
- case SENSOR_OTHER:
- break;
- default:
-/* case SENSOR_TAS5130A: */
+ case SENSOR_TAS5130A:
i = 0;
for (;;) {
reg_w_buf(gspca_dev, tas5130a_sensor_init[i],
@@ -1047,7 +1068,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
break;
}
sensor = &sensor_data[sd->sensor];
- reg_w_buf(gspca_dev, sensor->data4, sizeof sensor->data4);
+ setfreq(gspca_dev);
reg_r(gspca_dev, 0x0012);
reg_w_buf(gspca_dev, t2, sizeof t2);
reg_w_ixbuf(gspca_dev, 0xb3, t3, sizeof t3);
@@ -1080,7 +1101,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* isoc packet */
int len) /* iso packet length */
{
- static u8 ffd9[] = { 0xff, 0xd9 };
+ int pkt_type;
if (data[0] == 0x5a) {
/* Control Packet, after this came the header again,
@@ -1090,84 +1111,88 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
}
data += 2;
len -= 2;
- if (data[0] == 0xff && data[1] == 0xd8) {
- /* extra bytes....., could be processed too but would be
- * a waste of time, right now leave the application and
- * libjpeg do it for ourserlves.. */
- gspca_frame_add(gspca_dev, LAST_PACKET,
- ffd9, 2);
- gspca_frame_add(gspca_dev, FIRST_PACKET, data, len);
- return;
- }
-
- if (data[len - 2] == 0xff && data[len - 1] == 0xd9) {
- /* Just in case, i have seen packets with the marker,
- * other's do not include it... */
- len -= 2;
- }
- gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+ if (data[0] == 0xff && data[1] == 0xd8)
+ pkt_type = FIRST_PACKET;
+ else if (data[len - 2] == 0xff && data[len - 1] == 0xd9)
+ pkt_type = LAST_PACKET;
+ else
+ pkt_type = INTER_PACKET;
+ gspca_frame_add(gspca_dev, pkt_type, data, len);
}
-
-static int sd_setblue_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setblue_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->blue_balance = val;
+ sd->blue_gain = val;
if (gspca_dev->streaming)
reg_w(gspca_dev, (val << 8) + 0x88);
return 0;
}
-static int sd_getblue_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getblue_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->blue_balance;
+ *val = sd->blue_gain;
return 0;
}
-static int sd_setred_balance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setred_gain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->red_balance = val;
+ sd->red_gain = val;
if (gspca_dev->streaming)
reg_w(gspca_dev, (val << 8) + 0x87);
return 0;
}
-static int sd_getred_balance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getred_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->red_balance;
+ *val = sd->red_gain;
return 0;
}
-
-
-static int sd_setglobal_gain(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
+ u16 psg, nsg;
+
+ psg = sd->red_gain + sd->blue_gain + sd->green_gain;
+ nsg = val * 3;
+ sd->red_gain = sd->red_gain * nsg / psg;
+ if (sd->red_gain > 0x40)
+ sd->red_gain = 0x40;
+ else if (sd->red_gain < 0x10)
+ sd->red_gain = 0x10;
+ sd->blue_gain = sd->blue_gain * nsg / psg;
+ if (sd->blue_gain > 0x40)
+ sd->blue_gain = 0x40;
+ else if (sd->blue_gain < 0x10)
+ sd->blue_gain = 0x10;
+ sd->green_gain = sd->green_gain * nsg / psg;
+ if (sd->green_gain > 0x40)
+ sd->green_gain = 0x40;
+ else if (sd->green_gain < 0x10)
+ sd->green_gain = 0x10;
- sd->global_gain = val;
if (gspca_dev->streaming)
- setglobalgain(gspca_dev);
-
+ setRGB(gspca_dev);
return 0;
}
-static int sd_getglobal_gain(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->global_gain;
+ *val = (sd->red_gain + sd->blue_gain + sd->green_gain) / 3;
return 0;
}
-
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1186,35 +1211,35 @@ static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
return *val;
}
-static int sd_setwhitebalance(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setawb(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->whitebalance = val;
+ sd->awb = val;
if (gspca_dev->streaming)
- setwhitebalance(gspca_dev);
+ setawb(gspca_dev);
return 0;
}
-static int sd_getwhitebalance(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getawb(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->whitebalance;
+ *val = sd->awb;
return *val;
}
-static int sd_setflip(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setmirror(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
sd->mirror = val;
if (gspca_dev->streaming)
- setflip(gspca_dev);
+ setmirror(gspca_dev);
return 0;
}
-static int sd_getflip(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getmirror(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
@@ -1300,7 +1325,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
sd->freq = val;
if (gspca_dev->streaming)
- setlightfreq(gspca_dev);
+ setfreq(gspca_dev);
return 0;
}
@@ -1368,7 +1393,8 @@ static int sd_querymenu(struct gspca_dev *gspca_dev,
case V4L2_CID_EFFECTS:
if ((unsigned) menu->index < ARRAY_SIZE(effects_control)) {
strncpy((char *) menu->name,
- effects_control[menu->index], 32);
+ effects_control[menu->index],
+ sizeof menu->name);
return 0;
}
break;
@@ -1390,7 +1416,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x17a1, 0x0128)},
{}
};
@@ -1418,17 +1444,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/tv8532.c b/drivers/media/video/gspca/tv8532.c
index c7b6eb1e04d5..933ef2ca658c 100644
--- a/drivers/media/video/gspca/tv8532.c
+++ b/drivers/media/video/gspca/tv8532.c
@@ -30,29 +30,46 @@ MODULE_LICENSE("GPL");
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- __u16 brightness;
+ __u16 exposure;
+ __u16 gain;
__u8 packet;
};
/* V4L2 controls supported by the driver */
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
static const struct ctrl sd_ctrls[] = {
{
{
- .id = V4L2_CID_BRIGHTNESS,
+ .id = V4L2_CID_EXPOSURE,
.type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
+ .name = "Exposure",
.minimum = 1,
- .maximum = 0x15f, /* = 352 - 1 */
+ .maximum = 0x18f,
.step = 1,
-#define BRIGHTNESS_DEF 0x14c
- .default_value = BRIGHTNESS_DEF,
+#define EXPOSURE_DEF 0x18f
+ .default_value = EXPOSURE_DEF,
},
- .set = sd_setbrightness,
- .get = sd_getbrightness,
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 0x7ff,
+ .step = 1,
+#define GAIN_DEF 0x100
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
},
};
@@ -92,6 +109,14 @@ static const struct v4l2_pix_format sif_mode[] = {
#define R14_AD_ROW_BEGINL 0x14
#define R15_AD_ROWBEGINH 0x15
#define R1C_AD_EXPOSE_TIMEL 0x1c
+#define R20_GAIN_G1L 0x20
+#define R21_GAIN_G1H 0x21
+#define R22_GAIN_RL 0x22
+#define R23_GAIN_RH 0x23
+#define R24_GAIN_BL 0x24
+#define R25_GAIN_BH 0x25
+#define R26_GAIN_G2L 0x26
+#define R27_GAIN_G2H 0x27
#define R28_QUANT 0x28
#define R29_LINE 0x29
#define R2C_POLARITY 0x2c
@@ -107,7 +132,7 @@ static const struct v4l2_pix_format sif_mode[] = {
#define R36_PID 0x36
#define R37_PIDH 0x37
#define R39_Test1 0x39 /* GPIO */
-#define R3B_Test3 0x3B /* GPIO */
+#define R3B_Test3 0x3b /* GPIO */
#define R83_AD_IDH 0x83
#define R91_AD_SLOPEREG 0x91
#define R94_AD_BITCONTROL 0x94
@@ -129,18 +154,6 @@ static const u8 eeprom_data[][3] = {
{0x05, 0x09, 0xf1},
};
-static int reg_r(struct gspca_dev *gspca_dev,
- __u16 index)
-{
- usb_control_msg(gspca_dev->dev,
- usb_rcvctrlpipe(gspca_dev->dev, 0),
- 0x03,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, /* value */
- index, gspca_dev->usb_buf, 1,
- 500);
- return gspca_dev->usb_buf[0];
-}
/* write 1 byte */
static void reg_w1(struct gspca_dev *gspca_dev,
@@ -183,7 +196,6 @@ static void tv_8532WriteEEprom(struct gspca_dev *gspca_dev)
}
reg_w1(gspca_dev, R07_TABLE_LEN, i);
reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
- msleep(10);
}
/* this function is called at probe time */
@@ -197,53 +209,13 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->cam_mode = sif_mode;
cam->nmodes = ARRAY_SIZE(sif_mode);
- sd->brightness = BRIGHTNESS_DEF;
+ sd->exposure = EXPOSURE_DEF;
+ sd->gain = GAIN_DEF;
return 0;
}
-static void tv_8532ReadRegisters(struct gspca_dev *gspca_dev)
-{
- int i;
- static u8 reg_tb[] = {
- R0C_AD_WIDTHL,
- R0D_AD_WIDTHH,
- R28_QUANT,
- R29_LINE,
- R2C_POLARITY,
- R2D_POINT,
- R2E_POINTH,
- R2F_POINTB,
- R30_POINTBH,
- R2A_HIGH_BUDGET,
- R2B_LOW_BUDGET,
- R34_VID,
- R35_VIDH,
- R36_PID,
- R37_PIDH,
- R83_AD_IDH,
- R10_AD_COL_BEGINL,
- R11_AD_COL_BEGINH,
- R14_AD_ROW_BEGINL,
- R15_AD_ROWBEGINH,
- 0
- };
-
- i = 0;
- do {
- reg_r(gspca_dev, reg_tb[i]);
- i++;
- } while (reg_tb[i] != 0);
-}
-
static void tv_8532_setReg(struct gspca_dev *gspca_dev)
{
- reg_w1(gspca_dev, R10_AD_COL_BEGINL, 0x44);
- /* begin active line */
- reg_w1(gspca_dev, R11_AD_COL_BEGINH, 0x00);
- /* mirror and digital gain */
- reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
- /* = 0x84 */
-
reg_w1(gspca_dev, R3B_Test3, 0x0a); /* Test0Sel = 10 */
/******************************************************/
reg_w1(gspca_dev, R0E_AD_HEIGHTL, 0x90);
@@ -255,100 +227,43 @@ static void tv_8532_setReg(struct gspca_dev *gspca_dev)
/* mirror and digital gain */
reg_w1(gspca_dev, R14_AD_ROW_BEGINL, 0x0a);
- reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x02);
-
- reg_w1(gspca_dev, R01_TIMING_CONTROL_LOW, CMD_EEprom_Close);
-
reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x00);
reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
/* = 0x84 */
}
-static void tv_8532_PollReg(struct gspca_dev *gspca_dev)
-{
- int i;
-
- /* strange polling from tgc */
- for (i = 0; i < 10; i++) {
- reg_w1(gspca_dev, R2C_POLARITY, 0x10);
- reg_w1(gspca_dev, R00_PART_CONTROL,
- LATENT_CHANGE | EXPO_CHANGE);
- reg_w1(gspca_dev, R31_UPD, 0x01);
- }
-}
-
/* this function is called at probe and resume time */
static int sd_init(struct gspca_dev *gspca_dev)
{
tv_8532WriteEEprom(gspca_dev);
- reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V,
- * slope rate 2 */
- reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
- tv_8532ReadRegisters(gspca_dev);
- reg_w1(gspca_dev, R3B_Test3, 0x0b);
- reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
- reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, 0x018f);
- reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8);
- reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
-
- /*******************************************************************/
- reg_w1(gspca_dev, R28_QUANT, 0x90);
- /* no compress - fixed Q - quant 0 */
- reg_w1(gspca_dev, R29_LINE, 0x81);
- /* 0x84; // CIF | 4 packet 0x29 */
-
- /************************************************/
- reg_w1(gspca_dev, R2C_POLARITY, 0x10);
- /* 0x48; //0x08; 0x2c */
- reg_w1(gspca_dev, R2D_POINT, 0x14);
- /* 0x38; 0x2d */
- reg_w1(gspca_dev, R2E_POINTH, 0x01);
- /* 0x04; 0x2e */
- reg_w1(gspca_dev, R2F_POINTB, 0x12);
- /* 0x04; 0x2f */
- reg_w1(gspca_dev, R30_POINTBH, 0x01);
- /* 0x04; 0x30 */
- reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
- /* 0x00<-0x84 */
- /*************************************************/
- reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */
- msleep(200);
- reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
- /*************************************************/
- tv_8532_setReg(gspca_dev);
- /*************************************************/
- reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */
- /*************************************************/
- tv_8532_setReg(gspca_dev);
- /*************************************************/
- tv_8532_PollReg(gspca_dev);
return 0;
}
-static void setbrightness(struct gspca_dev *gspca_dev)
+static void setexposure(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->brightness);
+ reg_w2(gspca_dev, R1C_AD_EXPOSE_TIMEL, sd->exposure);
reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
/* 0x84 */
}
-/* -- start the camera -- */
-static int sd_start(struct gspca_dev *gspca_dev)
+static void setgain(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- reg_w1(gspca_dev, R91_AD_SLOPEREG, 0x32); /* slope begin 1,7V,
- * slope rate 2 */
- reg_w1(gspca_dev, R94_AD_BITCONTROL, 0x00);
- tv_8532ReadRegisters(gspca_dev);
- reg_w1(gspca_dev, R3B_Test3, 0x0b);
+ reg_w2(gspca_dev, R20_GAIN_G1L, sd->gain);
+ reg_w2(gspca_dev, R22_GAIN_RL, sd->gain);
+ reg_w2(gspca_dev, R24_GAIN_BL, sd->gain);
+ reg_w2(gspca_dev, R26_GAIN_G2L, sd->gain);
+}
- reg_w2(gspca_dev, R0E_AD_HEIGHTL, 0x0190);
- setbrightness(gspca_dev);
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
reg_w1(gspca_dev, R0C_AD_WIDTHL, 0xe8); /* 0x20; 0x0c */
reg_w1(gspca_dev, R0D_AD_WIDTHH, 0x03);
@@ -371,19 +286,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
reg_w1(gspca_dev, R2E_POINTH, 0x01);
reg_w1(gspca_dev, R2F_POINTB, 0x12);
reg_w1(gspca_dev, R30_POINTBH, 0x01);
- reg_w1(gspca_dev, R00_PART_CONTROL, LATENT_CHANGE | EXPO_CHANGE);
+
+ tv_8532_setReg(gspca_dev);
+
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+
/************************************************/
reg_w1(gspca_dev, R31_UPD, 0x01); /* update registers */
msleep(200);
- reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
- /************************************************/
- tv_8532_setReg(gspca_dev);
- /************************************************/
- reg_w1(gspca_dev, R3B_Test3, 0x0b); /* Test0Sel = 11 = GPIO */
- /************************************************/
- tv_8532_setReg(gspca_dev);
- /************************************************/
- tv_8532_PollReg(gspca_dev);
reg_w1(gspca_dev, R31_UPD, 0x00); /* end update */
gspca_dev->empty_packet = 0; /* check the empty packets */
@@ -428,21 +339,39 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
data + gspca_dev->width + 5, gspca_dev->width);
}
-static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return 0;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
{
struct sd *sd = (struct sd *) gspca_dev;
- sd->brightness = val;
+ sd->gain = val;
if (gspca_dev->streaming)
- setbrightness(gspca_dev);
+ setgain(gspca_dev);
return 0;
}
-static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- *val = sd->brightness;
+ *val = sd->gain;
return 0;
}
@@ -459,7 +388,7 @@ static const struct sd_desc sd_desc = {
};
/* -- module initialisation -- */
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x0920)},
{USB_DEVICE(0x046d, 0x0921)},
{USB_DEVICE(0x0545, 0x808b)},
@@ -492,18 +421,12 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/vc032x.c b/drivers/media/video/gspca/vc032x.c
index 732c3dfe46ff..6caed734a06a 100644
--- a/drivers/media/video/gspca/vc032x.c
+++ b/drivers/media/video/gspca/vc032x.c
@@ -39,28 +39,37 @@ struct sd {
u8 vflip;
u8 lightfreq;
s8 sharpness;
+ u16 exposure;
+ u8 gain;
+ u8 autogain;
+ u8 backlight;
u8 image_offset;
u8 bridge;
-#define BRIDGE_VC0321 0
-#define BRIDGE_VC0323 1
u8 sensor;
-#define SENSOR_HV7131R 0
-#define SENSOR_MI0360 1
-#define SENSOR_MI1310_SOC 2
-#define SENSOR_MI1320 3
-#define SENSOR_MI1320_SOC 4
-#define SENSOR_OV7660 5
-#define SENSOR_OV7670 6
-#define SENSOR_PO1200 7
-#define SENSOR_PO3130NC 8
-#define SENSOR_POxxxx 9
u8 flags;
#define FL_SAMSUNG 0x01 /* SamsungQ1 (2 sensors) */
#define FL_HFLIP 0x02 /* mirrored by default */
#define FL_VFLIP 0x04 /* vertical flipped by default */
};
+enum bridges {
+ BRIDGE_VC0321,
+ BRIDGE_VC0323,
+};
+enum sensors {
+ SENSOR_HV7131R,
+ SENSOR_MI0360,
+ SENSOR_MI1310_SOC,
+ SENSOR_MI1320,
+ SENSOR_MI1320_SOC,
+ SENSOR_OV7660,
+ SENSOR_OV7670,
+ SENSOR_PO1200,
+ SENSOR_PO3130NC,
+ SENSOR_POxxxx,
+ NSENSORS
+};
/* V4L2 controls supported by the driver */
static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
@@ -77,6 +86,14 @@ 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 int sd_setgain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setbacklight(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbacklight(struct gspca_dev *gspca_dev, __s32 *val);
static const struct ctrl sd_ctrls[] = {
#define BRIGHTNESS_IDX 0
@@ -185,41 +202,119 @@ static const struct ctrl sd_ctrls[] = {
.set = sd_setsharpness,
.get = sd_getsharpness,
},
+#define GAIN_IDX 7
+ {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 78,
+ .step = 1,
+#define GAIN_DEF 0
+ .default_value = GAIN_DEF,
+ },
+ .set = sd_setgain,
+ .get = sd_getgain,
+ },
+#define EXPOSURE_IDX 8
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+#define EXPOSURE_DEF 450
+ .minimum = 0,
+ .maximum = 4095,
+ .step = 1,
+ .default_value = EXPOSURE_DEF,
+ },
+ .set = sd_setexposure,
+ .get = sd_getexposure,
+ },
+#define AUTOGAIN_IDX 9
+ {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Gain and Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define AUTOGAIN_DEF 1
+ .default_value = AUTOGAIN_DEF,
+ },
+ .set = sd_setautogain,
+ .get = sd_getautogain,
+ },
+#define BACKLIGHT_IDX 10
+ {
+ {
+ .id = V4L2_CID_BACKLIGHT_COMPENSATION,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Backlight Compensation",
+ .minimum = 0,
+ .maximum = 15,
+ .step = 1,
+#define BACKLIGHT_DEF 15
+ .default_value = BACKLIGHT_DEF,
+ },
+ .set = sd_setbacklight,
+ .get = sd_getbacklight,
+ },
};
/* table of the disabled controls */
-static u32 ctrl_dis[] = {
-/* SENSOR_HV7131R 0 */
+static u32 ctrl_dis[NSENSORS] = {
+ [SENSOR_HV7131R] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
- | (1 << SHARPNESS_IDX),
-/* SENSOR_MI0360 1 */
+ | (1 << SHARPNESS_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_MI0360] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
- | (1 << SHARPNESS_IDX),
-/* SENSOR_MI1310_SOC 2 */
+ | (1 << SHARPNESS_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_MI1310_SOC] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
- | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX),
-/* SENSOR_MI1320 3 */
+ | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_MI1320] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
- | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX),
-/* SENSOR_MI1320_SOC 4 */
+ | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_MI1320_SOC] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
- | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX),
-/* SENSOR_OV7660 5 */
+ | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_OV7660] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
- | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX),
-/* SENSOR_OV7670 6 */
+ | (1 << LIGHTFREQ_IDX) | (1 << SHARPNESS_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_OV7670] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
- | (1 << SHARPNESS_IDX),
-/* SENSOR_PO1200 7 */
+ | (1 << SHARPNESS_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_PO1200] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
- | (1 << LIGHTFREQ_IDX),
-/* SENSOR_PO3130NC 8 */
+ | (1 << LIGHTFREQ_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_PO3130NC] =
(1 << BRIGHTNESS_IDX) | (1 << CONTRAST_IDX) | (1 << COLORS_IDX)
| (1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX)
- | (1 << SHARPNESS_IDX),
-/* SENSOR_POxxxx 9 */
+ | (1 << SHARPNESS_IDX)
+ | (1 << GAIN_IDX) | (1 << EXPOSURE_IDX)
+ | (1 << AUTOGAIN_IDX) | (1 << BACKLIGHT_IDX),
+ [SENSOR_POxxxx] =
(1 << HFLIP_IDX) | (1 << VFLIP_IDX) | (1 << LIGHTFREQ_IDX),
};
@@ -2748,11 +2843,11 @@ static const u8 poxxxx_init_common[][4] = {
{0xb3, 0x04, 0x15, 0xcc},
{0xb3, 0x20, 0x00, 0xcc},
{0xb3, 0x21, 0x00, 0xcc},
- {0xb3, 0x22, 0x04, 0xcc},
+ {0xb3, 0x22, 0x04, 0xcc}, /* sensor height = 1024 */
{0xb3, 0x23, 0x00, 0xcc},
{0xb3, 0x14, 0x00, 0xcc},
{0xb3, 0x15, 0x00, 0xcc},
- {0xb3, 0x16, 0x04, 0xcc},
+ {0xb3, 0x16, 0x04, 0xcc}, /* sensor width = 1280 */
{0xb3, 0x17, 0xff, 0xcc},
{0xb3, 0x2c, 0x03, 0xcc},
{0xb3, 0x2d, 0x56, 0xcc},
@@ -2825,7 +2920,9 @@ static const u8 poxxxx_init_common[][4] = {
{0x00, 0x1e, 0xc6, 0xaa},
{0x00, 0x00, 0x40, 0xdd},
{0x00, 0x1d, 0x05, 0xaa},
-
+ {}
+};
+static const u8 poxxxx_gamma[][4] = {
{0x00, 0xd6, 0x22, 0xaa}, /* gamma 0 */
{0x00, 0x73, 0x00, 0xaa},
{0x00, 0x74, 0x0a, 0xaa},
@@ -2867,19 +2964,9 @@ static const u8 poxxxx_init_common[][4] = {
{0x00, 0x7c, 0xba, 0xaa},
{0x00, 0x7d, 0xd4, 0xaa},
{0x00, 0x7e, 0xea, 0xaa},
-
- {0x00, 0xaa, 0xff, 0xaa}, /* back light comp */
- {0x00, 0xc4, 0x03, 0xaa},
- {0x00, 0xc5, 0x19, 0xaa},
- {0x00, 0xc6, 0x03, 0xaa},
- {0x00, 0xc7, 0x91, 0xaa},
- {0x00, 0xc8, 0x01, 0xaa},
- {0x00, 0xc9, 0xdd, 0xaa},
- {0x00, 0xca, 0x02, 0xaa},
- {0x00, 0xcb, 0x37, 0xaa},
-
-/* read d1 */
- {0x00, 0xd1, 0x3c, 0xaa},
+ {}
+};
+static const u8 poxxxx_init_start_3[][4] = {
{0x00, 0xb8, 0x28, 0xaa},
{0x00, 0xb9, 0x1e, 0xaa},
{0x00, 0xb6, 0x14, 0xaa},
@@ -2919,7 +3006,7 @@ static const u8 poxxxx_initVGA[][4] = {
{0x00, 0x20, 0x11, 0xaa},
{0x00, 0x33, 0x38, 0xaa},
{0x00, 0xbb, 0x0d, 0xaa},
- {0xb3, 0x22, 0x01, 0xcc},
+ {0xb3, 0x22, 0x01, 0xcc}, /* change to 640x480 */
{0xb3, 0x23, 0xe0, 0xcc},
{0xb3, 0x16, 0x02, 0xcc},
{0xb3, 0x17, 0x7f, 0xcc},
@@ -2935,7 +3022,7 @@ static const u8 poxxxx_initQVGA[][4] = {
{0x00, 0x20, 0x33, 0xaa},
{0x00, 0x33, 0x38, 0xaa},
{0x00, 0xbb, 0x0d, 0xaa},
- {0xb3, 0x22, 0x00, 0xcc},
+ {0xb3, 0x22, 0x00, 0xcc}, /* change to 320x240 */
{0xb3, 0x23, 0xf0, 0xcc},
{0xb3, 0x16, 0x01, 0xcc},
{0xb3, 0x17, 0x3f, 0xcc},
@@ -2959,9 +3046,6 @@ static const u8 poxxxx_init_end_1[][4] = {
{0x00, 0xb3, 0x08, 0xaa},
{0x00, 0xb4, 0x0b, 0xaa},
{0x00, 0xb5, 0x0d, 0xaa},
- {0x00, 0x59, 0x7e, 0xaa}, /* sharpness */
- {0x00, 0x16, 0x00, 0xaa}, /* white balance */
- {0x00, 0x18, 0x00, 0xaa},
{}
};
static const u8 poxxxx_init_end_2[][4] = {
@@ -3068,48 +3152,95 @@ static const struct sensor_info vc0323_probe_data[] = {
};
/* read 'len' bytes in gspca_dev->usb_buf */
-static void reg_r(struct gspca_dev *gspca_dev,
+static void reg_r_i(struct gspca_dev *gspca_dev,
u16 req,
u16 index,
u16 len)
{
- usb_control_msg(gspca_dev->dev,
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
req,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
1, /* value */
index, gspca_dev->usb_buf, len,
500);
+ if (ret < 0) {
+ err("reg_r err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+static void reg_r(struct gspca_dev *gspca_dev,
+ u16 req,
+ u16 index,
+ u16 len)
+{
+ reg_r_i(gspca_dev, req, index, len);
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ if (len == 1)
+ PDEBUG(D_USBI, "GET %02x 0001 %04x %02x", req, index,
+ gspca_dev->usb_buf[0]);
+ else
+ PDEBUG(D_USBI, "GET %02x 0001 %04x %02x %02x %02x",
+ req, index,
+ gspca_dev->usb_buf[0],
+ gspca_dev->usb_buf[1],
+ gspca_dev->usb_buf[2]);
+#endif
}
-static void reg_w(struct usb_device *dev,
+static void reg_w_i(struct gspca_dev *gspca_dev,
u16 req,
u16 value,
u16 index)
{
- usb_control_msg(dev,
- usb_sndctrlpipe(dev, 0),
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0,
500);
+ if (ret < 0) {
+ err("reg_w err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
+}
+static void reg_w(struct gspca_dev *gspca_dev,
+ u16 req,
+ u16 value,
+ u16 index)
+{
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ PDEBUG(D_USBO, "SET %02x %04x %04x", req, value, index);
+#endif
+ reg_w_i(gspca_dev, req, value, index);
}
static u16 read_sensor_register(struct gspca_dev *gspca_dev,
u16 address)
{
- struct usb_device *dev = gspca_dev->dev;
u8 ldata, mdata, hdata;
int retry = 50;
reg_r(gspca_dev, 0xa1, 0xb33f, 1);
if (!(gspca_dev->usb_buf[0] & 0x02)) {
- PDEBUG(D_ERR, "I2c Bus Busy Wait %02x",
+ err("I2c Bus Busy Wait %02x",
gspca_dev->usb_buf[0]);
return 0;
}
- reg_w(dev, 0xa0, address, 0xb33a);
- reg_w(dev, 0xa0, 0x02, 0xb339);
+ reg_w(gspca_dev, 0xa0, address, 0xb33a);
+ reg_w(gspca_dev, 0xa0, 0x02, 0xb339);
do {
reg_r(gspca_dev, 0xa1, 0xb33b, 1);
@@ -3136,15 +3267,15 @@ static u16 read_sensor_register(struct gspca_dev *gspca_dev,
static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int i, n;
u16 value;
const struct sensor_info *ptsensor_info;
/*fixme: should also check the other sensor (back mi1320_soc, front mc501cb)*/
if (sd->flags & FL_SAMSUNG) {
- reg_w(dev, 0xa0, 0x01, 0xb301);
- reg_w(dev, 0x89, 0xf0ff, 0xffff); /* select the back sensor */
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+ reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+ /* select the back sensor */
}
reg_r(gspca_dev, 0xa1, 0xbfcf, 1);
@@ -3158,13 +3289,13 @@ static int vc032x_probe_sensor(struct gspca_dev *gspca_dev)
n = ARRAY_SIZE(vc0323_probe_data);
}
for (i = 0; i < n; i++) {
- reg_w(dev, 0xa0, 0x02, 0xb334);
- reg_w(dev, 0xa0, ptsensor_info->m1, 0xb300);
- reg_w(dev, 0xa0, ptsensor_info->m2, 0xb300);
- reg_w(dev, 0xa0, 0x01, 0xb308);
- reg_w(dev, 0xa0, 0x0c, 0xb309);
- reg_w(dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
- reg_w(dev, 0xa0, ptsensor_info->op, 0xb301);
+ reg_w(gspca_dev, 0xa0, 0x02, 0xb334);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->m1, 0xb300);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->m2, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb308);
+ reg_w(gspca_dev, 0xa0, 0x0c, 0xb309);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->I2cAdd, 0xb335);
+ reg_w(gspca_dev, 0xa0, ptsensor_info->op, 0xb301);
value = read_sensor_register(gspca_dev, ptsensor_info->IdAdd);
if (value == 0 && ptsensor_info->IdAdd == 0x82)
value = read_sensor_register(gspca_dev, 0x83);
@@ -3192,26 +3323,33 @@ static void i2c_write(struct gspca_dev *gspca_dev,
u8 reg, const u8 *val,
u8 size) /* 1 or 2 */
{
- struct usb_device *dev = gspca_dev->dev;
int retry;
- reg_r(gspca_dev, 0xa1, 0xb33f, 1);
+#ifdef GSPCA_DEBUG
+ if (gspca_dev->usb_err < 0)
+ return;
+ if (size == 1)
+ PDEBUG(D_USBO, "i2c_w %02x %02x", reg, *val);
+ else
+ PDEBUG(D_USBO, "i2c_w %02x %02x%02x", reg, *val, val[1]);
+#endif
+ reg_r_i(gspca_dev, 0xa1, 0xb33f, 1);
/*fixme:should check if (!(gspca_dev->usb_buf[0] & 0x02)) error*/
- reg_w(dev, 0xa0, size, 0xb334);
- reg_w(dev, 0xa0, reg, 0xb33a);
- reg_w(dev, 0xa0, val[0], 0xb336);
+ reg_w_i(gspca_dev, 0xa0, size, 0xb334);
+ reg_w_i(gspca_dev, 0xa0, reg, 0xb33a);
+ reg_w_i(gspca_dev, 0xa0, val[0], 0xb336);
if (size > 1)
- reg_w(dev, 0xa0, val[1], 0xb337);
- reg_w(dev, 0xa0, 0x01, 0xb339);
+ reg_w_i(gspca_dev, 0xa0, val[1], 0xb337);
+ reg_w_i(gspca_dev, 0xa0, 0x01, 0xb339);
retry = 4;
do {
- reg_r(gspca_dev, 0xa1, 0xb33b, 1);
+ reg_r_i(gspca_dev, 0xa1, 0xb33b, 1);
if (gspca_dev->usb_buf[0] == 0)
break;
msleep(20);
} while (--retry > 0);
if (retry <= 0)
- PDEBUG(D_ERR, "i2c_write failed");
+ err("i2c_write timeout");
}
static void put_tab_to_reg(struct gspca_dev *gspca_dev,
@@ -3221,13 +3359,12 @@ static void put_tab_to_reg(struct gspca_dev *gspca_dev,
u16 ad = addr;
for (j = 0; j < tabsize; j++)
- reg_w(gspca_dev->dev, 0xa0, tab[j], ad++);
+ reg_w(gspca_dev, 0xa0, tab[j], ad++);
}
static void usb_exchange(struct gspca_dev *gspca_dev,
const u8 data[][4])
{
- struct usb_device *dev = gspca_dev->dev;
int i = 0;
for (;;) {
@@ -3235,7 +3372,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
default:
return;
case 0xcc: /* normal write */
- reg_w(dev, 0xa0, data[i][2],
+ reg_w(gspca_dev, 0xa0, data[i][2],
(data[i][0]) << 8 | data[i][1]);
break;
case 0xaa: /* i2c op */
@@ -3259,33 +3396,57 @@ static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
- struct cam *cam;
- int sensor;
- static u8 npkt[] = { /* number of packets per ISOC message */
- 64, /* HV7131R 0 */
- 32, /* MI0360 1 */
- 32, /* MI1310_SOC 2 */
- 64, /* MI1320 3 */
- 128, /* MI1320_SOC 4 */
- 32, /* OV7660 5 */
- 64, /* OV7670 6 */
- 128, /* PO1200 7 */
- 128, /* PO3130NC 8 */
- 128, /* POxxxx 9 */
- };
- cam = &gspca_dev->cam;
sd->bridge = id->driver_info >> 8;
sd->flags = id->driver_info & 0xff;
+
if (id->idVendor == 0x046d &&
(id->idProduct == 0x0892 || id->idProduct == 0x0896))
- sensor = SENSOR_POxxxx;
- else
+ sd->sensor = SENSOR_POxxxx; /* no probe */
+
+ sd->brightness = BRIGHTNESS_DEF;
+ sd->contrast = CONTRAST_DEF;
+ sd->colors = COLOR_DEF;
+ sd->hflip = HFLIP_DEF;
+ sd->vflip = VFLIP_DEF;
+ sd->lightfreq = FREQ_DEF;
+ sd->sharpness = SHARPNESS_DEF;
+ sd->gain = GAIN_DEF;
+ sd->exposure = EXPOSURE_DEF;
+ sd->autogain = AUTOGAIN_DEF;
+ sd->backlight = BACKLIGHT_DEF;
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+ int sensor;
+ /* number of packets per ISOC message */
+ static u8 npkt[NSENSORS] = {
+ [SENSOR_HV7131R] = 64,
+ [SENSOR_MI0360] = 32,
+ [SENSOR_MI1310_SOC] = 32,
+ [SENSOR_MI1320] = 64,
+ [SENSOR_MI1320_SOC] = 128,
+ [SENSOR_OV7660] = 32,
+ [SENSOR_OV7670] = 64,
+ [SENSOR_PO1200] = 128,
+ [SENSOR_PO3130NC] = 128,
+ [SENSOR_POxxxx] = 128,
+ };
+
+ if (sd->sensor != SENSOR_POxxxx)
sensor = vc032x_probe_sensor(gspca_dev);
+ else
+ sensor = sd->sensor;
+
switch (sensor) {
case -1:
- PDEBUG(D_PROBE, "Unknown sensor...");
+ err("Unknown sensor...");
return -EINVAL;
case SENSOR_HV7131R:
PDEBUG(D_PROBE, "Find Sensor HV7131R");
@@ -3321,6 +3482,7 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
sd->sensor = sensor;
+ cam = &gspca_dev->cam;
if (sd->bridge == BRIDGE_VC0321) {
cam->cam_mode = vc0321_mode;
cam->nmodes = ARRAY_SIZE(vc0321_mode);
@@ -3349,15 +3511,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
}
}
cam->npkt = npkt[sd->sensor];
-
- sd->brightness = BRIGHTNESS_DEF;
- sd->contrast = CONTRAST_DEF;
- sd->colors = COLOR_DEF;
- sd->hflip = HFLIP_DEF;
- sd->vflip = VFLIP_DEF;
- sd->lightfreq = FREQ_DEF;
- sd->sharpness = SHARPNESS_DEF;
-
gspca_dev->ctrl_dis = ctrl_dis[sd->sensor];
if (sd->sensor == SENSOR_OV7670)
@@ -3365,28 +3518,19 @@ static int sd_config(struct gspca_dev *gspca_dev,
if (sd->bridge == BRIDGE_VC0321) {
reg_r(gspca_dev, 0x8a, 0, 3);
- reg_w(dev, 0x87, 0x00, 0x0f0f);
-
+ reg_w(gspca_dev, 0x87, 0x00, 0x0f0f);
reg_r(gspca_dev, 0x8b, 0, 3);
- reg_w(dev, 0x88, 0x00, 0x0202);
- }
- 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;
-
- if (sd->sensor == SENSOR_POxxxx) {
- reg_r(gspca_dev, 0xa1, 0xb300, 1);
- if (gspca_dev->usb_buf[0] != 0) {
- reg_w(gspca_dev->dev, 0xa0, 0x26, 0xb300);
- reg_w(gspca_dev->dev, 0xa0, 0x04, 0xb300);
- reg_w(gspca_dev->dev, 0xa0, 0x00, 0xb300);
+ reg_w(gspca_dev, 0x88, 0x00, 0x0202);
+ if (sd->sensor == SENSOR_POxxxx) {
+ reg_r(gspca_dev, 0xa1, 0xb300, 1);
+ if (gspca_dev->usb_buf[0] != 0) {
+ reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+ }
+ reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
}
}
- return 0;
+ return gspca_dev->usb_err;
}
static void setbrightness(struct gspca_dev *gspca_dev)
@@ -3500,6 +3644,82 @@ static void setsharpness(struct gspca_dev *gspca_dev)
break;
}
}
+static void setgain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ if (gspca_dev->ctrl_dis & (1 << GAIN_IDX))
+ return;
+ i2c_write(gspca_dev, 0x15, &sd->gain, 1);
+}
+
+static void setexposure(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 data;
+
+ if (gspca_dev->ctrl_dis & (1 << EXPOSURE_IDX))
+ return;
+ data = sd->exposure >> 8;
+ i2c_write(gspca_dev, 0x1a, &data, 1);
+ data = sd->exposure;
+ i2c_write(gspca_dev, 0x1b, &data, 1);
+}
+
+static void setautogain(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ static const u8 data[2] = {0x28, 0x3c};
+
+ if (gspca_dev->ctrl_dis & (1 << AUTOGAIN_IDX))
+ return;
+ i2c_write(gspca_dev, 0xd1, &data[sd->autogain], 1);
+}
+
+static void setgamma(struct gspca_dev *gspca_dev)
+{
+/*fixme:to do */
+ usb_exchange(gspca_dev, poxxxx_gamma);
+}
+
+static void setbacklight(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u16 v;
+ u8 data;
+
+ data = (sd->backlight << 4) | 0x0f;
+ i2c_write(gspca_dev, 0xaa, &data, 1);
+ v = 613 + 12 * sd->backlight;
+ data = v >> 8;
+ i2c_write(gspca_dev, 0xc4, &data, 1);
+ data = v;
+ i2c_write(gspca_dev, 0xc5, &data, 1);
+ v = 1093 - 12 * sd->backlight;
+ data = v >> 8;
+ i2c_write(gspca_dev, 0xc6, &data, 1);
+ data = v;
+ i2c_write(gspca_dev, 0xc7, &data, 1);
+ v = 342 + 9 * sd->backlight;
+ data = v >> 8;
+ i2c_write(gspca_dev, 0xc8, &data, 1);
+ data = v;
+ i2c_write(gspca_dev, 0xc9, &data, 1);
+ v = 702 - 9 * sd->backlight;
+ data = v >> 8;
+ i2c_write(gspca_dev, 0xca, &data, 1);
+ data = v;
+ i2c_write(gspca_dev, 0xcb, &data, 1);
+}
+
+static void setwb(struct gspca_dev *gspca_dev)
+{
+/*fixme:to do - valid when reg d1 = 0x1c - (reg16 + reg15 = 0xa3)*/
+ static const u8 data[2] = {0x00, 0x00};
+
+ i2c_write(gspca_dev, 0x16, &data[0], 1);
+ i2c_write(gspca_dev, 0x18, &data[1], 1);
+}
static int sd_start(struct gspca_dev *gspca_dev)
{
@@ -3516,17 +3736,17 @@ static int sd_start(struct gspca_dev *gspca_dev)
/*fixme: back sensor only*/
if (sd->flags & FL_SAMSUNG) {
- reg_w(gspca_dev->dev, 0x89, 0xf0ff, 0xffff);
- reg_w(gspca_dev->dev, 0xa9, 0x8348, 0x000e);
- reg_w(gspca_dev->dev, 0xa9, 0x0000, 0x001a);
+ reg_w(gspca_dev, 0x89, 0xf0ff, 0xffff);
+ reg_w(gspca_dev, 0xa9, 0x8348, 0x000e);
+ reg_w(gspca_dev, 0xa9, 0x0000, 0x001a);
}
/* Assume start use the good resolution from gspca_dev->mode */
if (sd->bridge == BRIDGE_VC0321) {
- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfec);
- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfed);
- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfee);
- reg_w(gspca_dev->dev, 0xa0, 0xff, 0xbfef);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfec);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfed);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfee);
+ reg_w(gspca_dev, 0xa0, 0xff, 0xbfef);
sd->image_offset = 46;
} else {
if (gspca_dev->cam.cam_mode[gspca_dev->curr_mode].pixelformat
@@ -3611,13 +3831,23 @@ static int sd_start(struct gspca_dev *gspca_dev)
default:
/* case SENSOR_POxxxx: */
usb_exchange(gspca_dev, poxxxx_init_common);
+ setgamma(gspca_dev);
+ setbacklight(gspca_dev);
+ setbrightness(gspca_dev);
+ setcontrast(gspca_dev);
+ setcolors(gspca_dev);
+ setsharpness(gspca_dev);
+ setautogain(gspca_dev);
+ setexposure(gspca_dev);
+ setgain(gspca_dev);
+ usb_exchange(gspca_dev, poxxxx_init_start_3);
if (mode)
init = poxxxx_initQVGA;
else
init = poxxxx_initVGA;
usb_exchange(gspca_dev, init);
reg_r(gspca_dev, 0x8c, 0x0000, 3);
- reg_w(gspca_dev->dev, 0xa0,
+ reg_w(gspca_dev, 0xa0,
gspca_dev->usb_buf[2] & 1 ? 0 : 1,
0xb35c);
msleep(300);
@@ -3635,75 +3865,68 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_PO1200:
case SENSOR_HV7131R:
- reg_w(gspca_dev->dev, 0x89, 0x0400, 0x1415);
+ reg_w(gspca_dev, 0x89, 0x0400, 0x1415);
break;
case SENSOR_MI1310_SOC:
- reg_w(gspca_dev->dev, 0x89, 0x058c, 0x0000);
+ reg_w(gspca_dev, 0x89, 0x058c, 0x0000);
break;
}
msleep(100);
- setsharpness(gspca_dev);
sethvflip(gspca_dev);
setlightfreq(gspca_dev);
}
switch (sd->sensor) {
case SENSOR_OV7670:
- reg_w(gspca_dev->dev, 0x87, 0xffff, 0xffff);
- reg_w(gspca_dev->dev, 0x88, 0xff00, 0xf0f1);
- reg_w(gspca_dev->dev, 0xa0, 0x0000, 0xbfff);
+ reg_w(gspca_dev, 0x87, 0xffff, 0xffff);
+ reg_w(gspca_dev, 0x88, 0xff00, 0xf0f1);
+ reg_w(gspca_dev, 0xa0, 0x0000, 0xbfff);
break;
case SENSOR_POxxxx:
- setcolors(gspca_dev);
- setbrightness(gspca_dev);
- setcontrast(gspca_dev);
-
- /* led on */
- msleep(80);
- reg_w(gspca_dev->dev, 0x89, 0xffff, 0xfdff);
usb_exchange(gspca_dev, poxxxx_init_end_2);
+ setwb(gspca_dev);
+ msleep(80); /* led on */
+ reg_w(gspca_dev, 0x89, 0xffff, 0xfdff);
break;
}
- return 0;
+ return gspca_dev->usb_err;
}
static void sd_stopN(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
struct sd *sd = (struct sd *) gspca_dev;
switch (sd->sensor) {
case SENSOR_MI1310_SOC:
- reg_w(dev, 0x89, 0x058c, 0x00ff);
+ reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
break;
case SENSOR_POxxxx:
return;
default:
if (!(sd->flags & FL_SAMSUNG))
- reg_w(dev, 0x89, 0xffff, 0xffff);
+ reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
break;
}
- reg_w(dev, 0xa0, 0x01, 0xb301);
- reg_w(dev, 0xa0, 0x09, 0xb003);
+ reg_w(gspca_dev, 0xa0, 0x01, 0xb301);
+ reg_w(gspca_dev, 0xa0, 0x09, 0xb003);
}
/* called on streamoff with alt 0 and on disconnect */
static void sd_stop0(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
struct sd *sd = (struct sd *) gspca_dev;
if (!gspca_dev->present)
return;
/*fixme: is this useful?*/
if (sd->sensor == SENSOR_MI1310_SOC)
- reg_w(dev, 0x89, 0x058c, 0x00ff);
+ reg_w(gspca_dev, 0x89, 0x058c, 0x00ff);
else if (!(sd->flags & FL_SAMSUNG))
- reg_w(dev, 0x89, 0xffff, 0xffff);
+ reg_w(gspca_dev, 0x89, 0xffff, 0xffff);
if (sd->sensor == SENSOR_POxxxx) {
- reg_w(dev, 0xa0, 0x26, 0xb300);
- reg_w(dev, 0xa0, 0x04, 0xb300);
- reg_w(dev, 0xa0, 0x00, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x26, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x04, 0xb300);
+ reg_w(gspca_dev, 0xa0, 0x00, 0xb300);
}
}
@@ -3726,17 +3949,12 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* The vc0321 sends some additional data after sending the complete
* frame, we ignore this. */
if (sd->bridge == BRIDGE_VC0321) {
- struct gspca_frame *frame;
- int l;
+ int size, l;
- frame = gspca_get_i_frame(gspca_dev);
- if (frame == NULL) {
- gspca_dev->last_packet_type = DISCARD_PACKET;
- return;
- }
- l = frame->data_end - frame->data;
- if (len > frame->v4l2_buf.length - l)
- len = frame->v4l2_buf.length - l;
+ l = gspca_dev->image_len;
+ size = gspca_dev->frsz;
+ if (len > size - l)
+ len = size - l;
}
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
@@ -3748,7 +3966,7 @@ static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val)
sd->brightness = val;
if (gspca_dev->streaming)
setbrightness(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3766,7 +3984,7 @@ static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
sd->contrast = val;
if (gspca_dev->streaming)
setcontrast(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3784,7 +4002,7 @@ static int sd_setcolors(struct gspca_dev *gspca_dev, __s32 val)
sd->colors = val;
if (gspca_dev->streaming)
setcolors(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getcolors(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3802,7 +4020,7 @@ static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
sd->hflip = val;
if (gspca_dev->streaming)
sethvflip(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3820,7 +4038,7 @@ static int sd_setvflip(struct gspca_dev *gspca_dev, __s32 val)
sd->vflip = val;
if (gspca_dev->streaming)
sethvflip(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getvflip(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3838,7 +4056,7 @@ static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
sd->lightfreq = val;
if (gspca_dev->streaming)
setlightfreq(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3856,7 +4074,7 @@ static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val)
sd->sharpness = val;
if (gspca_dev->streaming)
setsharpness(gspca_dev);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
@@ -3867,6 +4085,80 @@ static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val)
return 0;
}
+static int sd_setgain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->gain = val;
+ if (gspca_dev->streaming)
+ setgain(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getgain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->gain;
+ return 0;
+}
+
+static int sd_setexposure(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->exposure = val;
+ if (gspca_dev->streaming)
+ setexposure(gspca_dev);
+ return gspca_dev->usb_err;
+}
+
+static int sd_getexposure(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->exposure;
+ return 0;
+}
+
+static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->autogain = val;
+ if (gspca_dev->streaming)
+ setautogain(gspca_dev);
+
+ return gspca_dev->usb_err;
+}
+
+static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->autogain;
+ return 0;
+}
+
+static int sd_setbacklight(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->backlight = val;
+ if (gspca_dev->streaming)
+ setbacklight(gspca_dev);
+
+ return gspca_dev->usb_err;
+}
+
+static int sd_getbacklight(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->backlight;
+ return 0;
+}
+
static int sd_querymenu(struct gspca_dev *gspca_dev,
struct v4l2_querymenu *menu)
{
@@ -3900,7 +4192,7 @@ static const struct sd_desc sd_desc = {
#define BF(bridge, flags) \
.driver_info = (BRIDGE_ ## bridge << 8) \
| (flags)
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x405b), BF(VC0323, FL_VFLIP)},
{USB_DEVICE(0x046d, 0x0892), BF(VC0321, 0)},
{USB_DEVICE(0x046d, 0x0896), BF(VC0321, 0)},
@@ -3940,18 +4232,11 @@ static struct usb_driver sd_driver = {
/* -- module insert / remove -- */
static int __init sd_mod_init(void)
{
- int ret;
-
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/gspca/w996Xcf.c b/drivers/media/video/gspca/w996Xcf.c
index 2fffe203bed8..4a9e622e5e1b 100644
--- a/drivers/media/video/gspca/w996Xcf.c
+++ b/drivers/media/video/gspca/w996Xcf.c
@@ -31,14 +31,10 @@
the sensor drivers to v4l2 sub drivers, and properly split of this
driver from ov519.c */
-/* The CONEX_CAM define for jpeg.h needs renaming, now its used here too */
-#define CONEX_CAM
-#include "jpeg.h"
-
#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */
-#define Y_QUANTABLE (sd->jpeg_hdr + JPEG_QT0_OFFSET)
-#define UV_QUANTABLE (sd->jpeg_hdr + JPEG_QT1_OFFSET)
+#define Y_QUANTABLE (&sd->jpeg_hdr[JPEG_QT0_OFFSET])
+#define UV_QUANTABLE (&sd->jpeg_hdr[JPEG_QT1_OFFSET])
static const struct v4l2_pix_format w9968cf_vga_mode[] = {
{160, 120, V4L2_PIX_FMT_UYVY, V4L2_FIELD_NONE,
@@ -63,18 +59,21 @@ static const struct v4l2_pix_format w9968cf_vga_mode[] = {
.colorspace = V4L2_COLORSPACE_JPEG},
};
-static int reg_w(struct sd *sd, __u16 index, __u16 value);
+static void reg_w(struct sd *sd, u16 index, u16 value);
/*--------------------------------------------------------------------------
Write 64-bit data to the fast serial bus registers.
Return 0 on success, -1 otherwise.
--------------------------------------------------------------------------*/
-static int w9968cf_write_fsb(struct sd *sd, u16* data)
+static void w9968cf_write_fsb(struct sd *sd, u16* data)
{
- struct usb_device* udev = sd->gspca_dev.dev;
+ struct usb_device *udev = sd->gspca_dev.dev;
u16 value;
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
value = *data++;
memcpy(sd->gspca_dev.usb_buf, data, 6);
@@ -82,21 +81,22 @@ static int w9968cf_write_fsb(struct sd *sd, u16* data)
USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
value, 0x06, sd->gspca_dev.usb_buf, 6, 500);
if (ret < 0) {
- PDEBUG(D_ERR, "Write FSB registers failed (%d)", ret);
- return ret;
+ err("Write FSB registers failed (%d)", ret);
+ sd->gspca_dev.usb_err = ret;
}
-
- return 0;
}
/*--------------------------------------------------------------------------
Write data to the serial bus control register.
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
-static int w9968cf_write_sb(struct sd *sd, u16 value)
+static void w9968cf_write_sb(struct sd *sd, u16 value)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return;
+
/* We don't use reg_w here, as that would cause all writes when
bitbanging i2c to be logged, making the logs impossible to read */
ret = usb_control_msg(sd->gspca_dev.dev,
@@ -108,11 +108,9 @@ static int w9968cf_write_sb(struct sd *sd, u16 value)
udelay(W9968CF_I2C_BUS_DELAY);
if (ret < 0) {
- PDEBUG(D_ERR, "Write SB reg [01] %04x failed", value);
- return ret;
+ err("Write SB reg [01] %04x failed", value);
+ sd->gspca_dev.usb_err = ret;
}
-
- return 0;
}
/*--------------------------------------------------------------------------
@@ -123,6 +121,9 @@ static int w9968cf_read_sb(struct sd *sd)
{
int ret;
+ if (sd->gspca_dev.usb_err < 0)
+ return -1;
+
/* We don't use reg_r here, as the w9968cf is special and has 16
bit registers instead of 8 bit */
ret = usb_control_msg(sd->gspca_dev.dev,
@@ -130,11 +131,13 @@ static int w9968cf_read_sb(struct sd *sd)
1,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0, 0x01, sd->gspca_dev.usb_buf, 2, 500);
- if (ret >= 0)
+ if (ret >= 0) {
ret = sd->gspca_dev.usb_buf[0] |
(sd->gspca_dev.usb_buf[1] << 8);
- else
- PDEBUG(D_ERR, "Read SB reg [01] failed");
+ } else {
+ err("Read SB reg [01] failed");
+ sd->gspca_dev.usb_err = ret;
+ }
udelay(W9968CF_I2C_BUS_DELAY);
@@ -146,22 +149,20 @@ static int w9968cf_read_sb(struct sd *sd)
This function is called by w9968cf_start_transfer().
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
-static int w9968cf_upload_quantizationtables(struct sd *sd)
+static void w9968cf_upload_quantizationtables(struct sd *sd)
{
u16 a, b;
- int ret = 0, i, j;
+ int i, j;
- ret += reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */
+ reg_w(sd, 0x39, 0x0010); /* JPEG clock enable */
for (i = 0, j = 0; i < 32; i++, j += 2) {
- a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
- b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
- ret += reg_w(sd, 0x40+i, a);
- ret += reg_w(sd, 0x60+i, b);
+ a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j + 1]) << 8);
+ b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j + 1]) << 8);
+ reg_w(sd, 0x40 + i, a);
+ reg_w(sd, 0x60 + i, b);
}
- ret += reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */
-
- return ret;
+ reg_w(sd, 0x39, 0x0012); /* JPEG encoder enable */
}
/****************************************************************************
@@ -172,50 +173,39 @@ static int w9968cf_upload_quantizationtables(struct sd *sd)
* i2c_adap_read_byte() *
****************************************************************************/
-static int w9968cf_smbus_start(struct sd *sd)
+static void w9968cf_smbus_start(struct sd *sd)
{
- int ret = 0;
-
- ret += w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
- return ret;
+ w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+ w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
}
-static int w9968cf_smbus_stop(struct sd *sd)
+static void w9968cf_smbus_stop(struct sd *sd)
{
- int ret = 0;
-
- ret += w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-
- return ret;
+ w9968cf_write_sb(sd, 0x0010); /* SDE=1, SDA=0, SCL=0 */
+ w9968cf_write_sb(sd, 0x0011); /* SDE=1, SDA=0, SCL=1 */
+ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
}
-static int w9968cf_smbus_write_byte(struct sd *sd, u8 v)
+static void w9968cf_smbus_write_byte(struct sd *sd, u8 v)
{
u8 bit;
- int ret = 0, sda;
+ int sda;
for (bit = 0 ; bit < 8 ; bit++) {
sda = (v & 0x80) ? 2 : 0;
v <<= 1;
/* SDE=1, SDA=sda, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x10 | sda);
+ w9968cf_write_sb(sd, 0x10 | sda);
/* SDE=1, SDA=sda, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x11 | sda);
+ w9968cf_write_sb(sd, 0x11 | sda);
/* SDE=1, SDA=sda, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x10 | sda);
+ w9968cf_write_sb(sd, 0x10 | sda);
}
-
- return ret;
}
-static int w9968cf_smbus_read_byte(struct sd *sd, u8* v)
+static void w9968cf_smbus_read_byte(struct sd *sd, u8 *v)
{
u8 bit;
- int ret = 0;
/* No need to ensure SDA is high as we are always called after
read_ack which ends with SDA high */
@@ -223,51 +213,40 @@ static int w9968cf_smbus_read_byte(struct sd *sd, u8* v)
for (bit = 0 ; bit < 8 ; bit++) {
*v <<= 1;
/* SDE=1, SDA=1, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x0013);
+ w9968cf_write_sb(sd, 0x0013);
*v |= (w9968cf_read_sb(sd) & 0x0008) ? 1 : 0;
/* SDE=1, SDA=1, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x0012);
+ w9968cf_write_sb(sd, 0x0012);
}
-
- return ret;
}
-static int w9968cf_smbus_write_nack(struct sd *sd)
+static void w9968cf_smbus_write_nack(struct sd *sd)
{
- int ret = 0;
-
/* No need to ensure SDA is high as we are always called after
read_byte which ends with SDA high */
- ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
- ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
-
- return ret;
+ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
}
-static int w9968cf_smbus_read_ack(struct sd *sd)
+static void w9968cf_smbus_read_ack(struct sd *sd)
{
- int ret = 0, sda;
+ int sda;
/* Ensure SDA is high before raising clock to avoid a spurious stop */
- ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
- ret += w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
+ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+ w9968cf_write_sb(sd, 0x0013); /* SDE=1, SDA=1, SCL=1 */
sda = w9968cf_read_sb(sd);
- ret += w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
- if (sda < 0)
- ret += sda;
- else if (sda & 0x08) {
+ w9968cf_write_sb(sd, 0x0012); /* SDE=1, SDA=1, SCL=0 */
+ if (sda >= 0 && (sda & 0x08)) {
PDEBUG(D_USBI, "Did not receive i2c ACK");
- ret += -1;
+ sd->gspca_dev.usb_err = -EIO;
}
-
- return ret;
}
/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
-static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
+static void w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
{
u16* data = (u16 *)sd->gspca_dev.usb_buf;
- int ret = 0;
data[0] = 0x082f | ((sd->sensor_addr & 0x80) ? 0x1500 : 0x0);
data[0] |= (sd->sensor_addr & 0x40) ? 0x4000 : 0x0;
@@ -280,7 +259,7 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[3] = 0x1d20 | ((sd->sensor_addr & 0x02) ? 0x0001 : 0x0);
data[3] |= (sd->sensor_addr & 0x01) ? 0x0054 : 0x0;
- ret += w9968cf_write_fsb(sd, data);
+ w9968cf_write_fsb(sd, data);
data[0] = 0x8208 | ((reg & 0x80) ? 0x0015 : 0x0);
data[0] |= (reg & 0x40) ? 0x0540 : 0x0;
@@ -294,7 +273,7 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[2] |= (reg & 0x01) ? 0x5400 : 0x0;
data[3] = 0x001d;
- ret += w9968cf_write_fsb(sd, data);
+ w9968cf_write_fsb(sd, data);
data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
data[0] |= (value & 0x40) ? 0x0540 : 0x0;
@@ -308,14 +287,9 @@ static int w9968cf_i2c_w(struct sd *sd, u8 reg, u8 value)
data[2] |= (value & 0x01) ? 0x5400 : 0x0;
data[3] = 0xfe1d;
- ret += w9968cf_write_fsb(sd, data);
+ w9968cf_write_fsb(sd, data);
- if (!ret)
- PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
- else
- PDEBUG(D_ERR, "i2c 0x%02x -> [0x%02x] failed", value, reg);
-
- return ret;
+ PDEBUG(D_USBO, "i2c 0x%02x -> [0x%02x]", value, reg);
}
/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
@@ -325,28 +299,28 @@ static int w9968cf_i2c_r(struct sd *sd, u8 reg)
u8 value;
/* Fast serial bus data control disable */
- ret += w9968cf_write_sb(sd, 0x0013); /* don't change ! */
-
- ret += w9968cf_smbus_start(sd);
- ret += w9968cf_smbus_write_byte(sd, sd->sensor_addr);
- ret += w9968cf_smbus_read_ack(sd);
- ret += w9968cf_smbus_write_byte(sd, reg);
- ret += w9968cf_smbus_read_ack(sd);
- ret += w9968cf_smbus_stop(sd);
- ret += w9968cf_smbus_start(sd);
- ret += w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1);
- ret += w9968cf_smbus_read_ack(sd);
- ret += w9968cf_smbus_read_byte(sd, &value);
+ w9968cf_write_sb(sd, 0x0013); /* don't change ! */
+
+ w9968cf_smbus_start(sd);
+ w9968cf_smbus_write_byte(sd, sd->sensor_addr);
+ w9968cf_smbus_read_ack(sd);
+ w9968cf_smbus_write_byte(sd, reg);
+ w9968cf_smbus_read_ack(sd);
+ w9968cf_smbus_stop(sd);
+ w9968cf_smbus_start(sd);
+ w9968cf_smbus_write_byte(sd, sd->sensor_addr + 1);
+ w9968cf_smbus_read_ack(sd);
+ w9968cf_smbus_read_byte(sd, &value);
/* signal we don't want to read anymore, the v4l1 driver used to
send an ack here which is very wrong! (and then fixed
the issues this gave by retrying reads) */
- ret += w9968cf_smbus_write_nack(sd);
- ret += w9968cf_smbus_stop(sd);
+ w9968cf_smbus_write_nack(sd);
+ w9968cf_smbus_stop(sd);
/* Fast serial bus data control re-enable */
- ret += w9968cf_write_sb(sd, 0x0030);
+ w9968cf_write_sb(sd, 0x0030);
- if (!ret) {
+ if (sd->gspca_dev.usb_err >= 0) {
ret = value;
PDEBUG(D_USBI, "i2c [0x%02X] -> 0x%02X", reg, value);
} else
@@ -355,79 +329,68 @@ static int w9968cf_i2c_r(struct sd *sd, u8 reg)
return ret;
}
-
/*--------------------------------------------------------------------------
Turn on the LED on some webcams. A beep should be heard too.
Return 0 on success, a negative number otherwise.
--------------------------------------------------------------------------*/
-static int w9968cf_configure(struct sd *sd)
+static void w9968cf_configure(struct sd *sd)
{
- int ret = 0;
-
- ret += reg_w(sd, 0x00, 0xff00); /* power-down */
- ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */
- ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */
- ret += reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */
- ret += reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */
- ret += reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */
- ret += reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */
-
- if (ret)
- PDEBUG(D_ERR, "Couldn't turn on the LED");
+ reg_w(sd, 0x00, 0xff00); /* power-down */
+ reg_w(sd, 0x00, 0xbf17); /* reset everything */
+ reg_w(sd, 0x00, 0xbf10); /* normal operation */
+ reg_w(sd, 0x01, 0x0010); /* serial bus, SDS high */
+ reg_w(sd, 0x01, 0x0000); /* serial bus, SDS low */
+ reg_w(sd, 0x01, 0x0010); /* ..high 'beep-beep' */
+ reg_w(sd, 0x01, 0x0030); /* Set sda scl to FSB mode */
sd->stopped = 1;
-
- return ret;
}
-static int w9968cf_init(struct sd *sd)
+static void w9968cf_init(struct sd *sd)
{
- int ret = 0;
unsigned long hw_bufsize = sd->sif ? (352 * 288 * 2) : (640 * 480 * 2),
y0 = 0x0000,
- u0 = y0 + hw_bufsize/2,
- v0 = u0 + hw_bufsize/4,
- y1 = v0 + hw_bufsize/4,
- u1 = y1 + hw_bufsize/2,
- v1 = u1 + hw_bufsize/4;
-
- ret += reg_w(sd, 0x00, 0xff00); /* power off */
- ret += reg_w(sd, 0x00, 0xbf10); /* power on */
-
- ret += reg_w(sd, 0x03, 0x405d); /* DRAM timings */
- ret += reg_w(sd, 0x04, 0x0030); /* SDRAM timings */
-
- ret += reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */
- ret += reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */
- ret += reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */
- ret += reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */
- ret += reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */
- ret += reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */
-
- ret += reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */
- ret += reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */
- ret += reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */
- ret += reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */
- ret += reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */
- ret += reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */
-
- ret += reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */
- ret += reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */
-
- ret += reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */
- ret += reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */
-
- ret += reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */
- ret += reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/
- ret += reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */
- ret += reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */
-
- return ret;
+ u0 = y0 + hw_bufsize / 2,
+ v0 = u0 + hw_bufsize / 4,
+ y1 = v0 + hw_bufsize / 4,
+ u1 = y1 + hw_bufsize / 2,
+ v1 = u1 + hw_bufsize / 4;
+
+ reg_w(sd, 0x00, 0xff00); /* power off */
+ reg_w(sd, 0x00, 0xbf10); /* power on */
+
+ reg_w(sd, 0x03, 0x405d); /* DRAM timings */
+ reg_w(sd, 0x04, 0x0030); /* SDRAM timings */
+
+ reg_w(sd, 0x20, y0 & 0xffff); /* Y buf.0, low */
+ reg_w(sd, 0x21, y0 >> 16); /* Y buf.0, high */
+ reg_w(sd, 0x24, u0 & 0xffff); /* U buf.0, low */
+ reg_w(sd, 0x25, u0 >> 16); /* U buf.0, high */
+ reg_w(sd, 0x28, v0 & 0xffff); /* V buf.0, low */
+ reg_w(sd, 0x29, v0 >> 16); /* V buf.0, high */
+
+ reg_w(sd, 0x22, y1 & 0xffff); /* Y buf.1, low */
+ reg_w(sd, 0x23, y1 >> 16); /* Y buf.1, high */
+ reg_w(sd, 0x26, u1 & 0xffff); /* U buf.1, low */
+ reg_w(sd, 0x27, u1 >> 16); /* U buf.1, high */
+ reg_w(sd, 0x2a, v1 & 0xffff); /* V buf.1, low */
+ reg_w(sd, 0x2b, v1 >> 16); /* V buf.1, high */
+
+ reg_w(sd, 0x32, y1 & 0xffff); /* JPEG buf 0 low */
+ reg_w(sd, 0x33, y1 >> 16); /* JPEG buf 0 high */
+
+ reg_w(sd, 0x34, y1 & 0xffff); /* JPEG buf 1 low */
+ reg_w(sd, 0x35, y1 >> 16); /* JPEG bug 1 high */
+
+ reg_w(sd, 0x36, 0x0000);/* JPEG restart interval */
+ reg_w(sd, 0x37, 0x0804);/*JPEG VLE FIFO threshold*/
+ reg_w(sd, 0x38, 0x0000);/* disable hw up-scaling */
+ reg_w(sd, 0x3f, 0x0000); /* JPEG/MCTL test data */
}
-static int w9968cf_set_crop_window(struct sd *sd)
+static void w9968cf_set_crop_window(struct sd *sd)
{
- int ret = 0, start_cropx, start_cropy, x, y, fw, fh, cw, ch,
+ int start_cropx, start_cropy, x, y, fw, fh, cw, ch,
max_width, max_height;
if (sd->sif) {
@@ -441,7 +404,7 @@ static int w9968cf_set_crop_window(struct sd *sd)
if (sd->sensor == SEN_OV7620) {
/* Sigh, this is dependend on the clock / framerate changes
made by the frequency control, sick. */
- if (sd->freq == 1) {
+ if (sd->ctrls[FREQ].val == 1) {
start_cropx = 277;
start_cropy = 37;
} else {
@@ -460,8 +423,8 @@ static int w9968cf_set_crop_window(struct sd *sd)
fw = SC(sd->gspca_dev.width) / max_width;
fh = SC(sd->gspca_dev.height) / max_height;
- cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width)/fh;
- ch = (fw >= fh) ? SC(sd->gspca_dev.height)/fw : max_height;
+ cw = (fw >= fh) ? max_width : SC(sd->gspca_dev.width) / fh;
+ ch = (fw >= fh) ? SC(sd->gspca_dev.height) / fw : max_height;
sd->sensor_width = max_width;
sd->sensor_height = max_height;
@@ -469,55 +432,48 @@ static int w9968cf_set_crop_window(struct sd *sd)
x = (max_width - cw) / 2;
y = (max_height - ch) / 2;
- ret += reg_w(sd, 0x10, start_cropx + x);
- ret += reg_w(sd, 0x11, start_cropy + y);
- ret += reg_w(sd, 0x12, start_cropx + x + cw);
- ret += reg_w(sd, 0x13, start_cropy + y + ch);
-
- return ret;
+ reg_w(sd, 0x10, start_cropx + x);
+ reg_w(sd, 0x11, start_cropy + y);
+ reg_w(sd, 0x12, start_cropx + x + cw);
+ reg_w(sd, 0x13, start_cropy + y + ch);
}
-static int w9968cf_mode_init_regs(struct sd *sd)
+static void w9968cf_mode_init_regs(struct sd *sd)
{
- int ret = 0, val, vs_polarity, hs_polarity;
+ int val, vs_polarity, hs_polarity;
- ret += w9968cf_set_crop_window(sd);
+ w9968cf_set_crop_window(sd);
- ret += reg_w(sd, 0x14, sd->gspca_dev.width);
- ret += reg_w(sd, 0x15, sd->gspca_dev.height);
+ reg_w(sd, 0x14, sd->gspca_dev.width);
+ reg_w(sd, 0x15, sd->gspca_dev.height);
/* JPEG width & height */
- ret += reg_w(sd, 0x30, sd->gspca_dev.width);
- ret += reg_w(sd, 0x31, sd->gspca_dev.height);
+ reg_w(sd, 0x30, sd->gspca_dev.width);
+ reg_w(sd, 0x31, sd->gspca_dev.height);
/* Y & UV frame buffer strides (in WORD) */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
- ret += reg_w(sd, 0x2c, sd->gspca_dev.width/2);
- ret += reg_w(sd, 0x2d, sd->gspca_dev.width/4);
+ reg_w(sd, 0x2c, sd->gspca_dev.width / 2);
+ reg_w(sd, 0x2d, sd->gspca_dev.width / 4);
} else
- ret += reg_w(sd, 0x2c, sd->gspca_dev.width);
+ reg_w(sd, 0x2c, sd->gspca_dev.width);
- ret += reg_w(sd, 0x00, 0xbf17); /* reset everything */
- ret += reg_w(sd, 0x00, 0xbf10); /* normal operation */
+ reg_w(sd, 0x00, 0xbf17); /* reset everything */
+ reg_w(sd, 0x00, 0xbf10); /* normal operation */
/* Transfer size in WORDS (for UYVY format only) */
val = sd->gspca_dev.width * sd->gspca_dev.height;
- ret += reg_w(sd, 0x3d, val & 0xffff); /* low bits */
- ret += reg_w(sd, 0x3e, val >> 16); /* high bits */
+ reg_w(sd, 0x3d, val & 0xffff); /* low bits */
+ reg_w(sd, 0x3e, val >> 16); /* high bits */
if (w9968cf_vga_mode[sd->gspca_dev.curr_mode].pixelformat ==
V4L2_PIX_FMT_JPEG) {
/* We may get called multiple times (usb isoc bw negotiat.) */
- if (!sd->jpeg_hdr)
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
-
jpeg_define(sd->jpeg_hdr, sd->gspca_dev.height,
sd->gspca_dev.width, 0x22); /* JPEG 420 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
- ret += w9968cf_upload_quantizationtables(sd);
+ w9968cf_upload_quantizationtables(sd);
}
/* Video Capture Control Register */
@@ -549,22 +505,15 @@ static int w9968cf_mode_init_regs(struct sd *sd)
val |= 0x8000; /* capt. enable */
- ret += reg_w(sd, 0x16, val);
+ reg_w(sd, 0x16, val);
sd->gspca_dev.empty_packet = 0;
-
- return ret;
}
static void w9968cf_stop0(struct sd *sd)
{
- if (sd->gspca_dev.present) {
- reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
- reg_w(sd, 0x16, 0x0000); /* stop video capture */
- }
-
- kfree(sd->jpeg_hdr);
- sd->jpeg_hdr = NULL;
+ reg_w(sd, 0x39, 0x0000); /* disable JPEG encoder */
+ reg_w(sd, 0x16, 0x0000); /* stop video capture */
}
/* The w9968cf docs say that a 0 sized packet means EOF (and also SOF
diff --git a/drivers/media/video/gspca/xirlink_cit.c b/drivers/media/video/gspca/xirlink_cit.c
new file mode 100644
index 000000000000..c089a0f6f1d0
--- /dev/null
+++ b/drivers/media/video/gspca/xirlink_cit.c
@@ -0,0 +1,3337 @@
+/*
+ * USB IBM C-It Video Camera driver
+ *
+ * Supports Xirlink C-It Video Camera, IBM PC Camera,
+ * IBM NetCamera and Veo Stingray.
+ *
+ * Copyright (C) 2010 Hans de Goede <hdegoede@redhat.com>
+ *
+ * This driver is based on earlier work of:
+ *
+ * (C) Copyright 1999 Johannes Erdfelt
+ * (C) Copyright 1999 Randy Dunlap
+ *
+ * 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
+ *
+ */
+
+#define MODULE_NAME "xirlink-cit"
+
+#include <linux/input.h>
+#include "gspca.h"
+
+MODULE_AUTHOR("Hans de Goede <hdegoede@redhat.com>");
+MODULE_DESCRIPTION("Xirlink C-IT");
+MODULE_LICENSE("GPL");
+
+/* FIXME we should autodetect this */
+static int ibm_netcam_pro;
+module_param(ibm_netcam_pro, int, 0);
+MODULE_PARM_DESC(ibm_netcam_pro,
+ "Use IBM Netcamera Pro init sequences for Model 3 cams");
+
+/* FIXME this should be handled through the V4L2 input selection API */
+static int rca_input;
+module_param(rca_input, int, 0644);
+MODULE_PARM_DESC(rca_input,
+ "Use rca input instead of ccd sensor on Model 3 cams");
+
+/* specific webcam descriptor */
+struct sd {
+ struct gspca_dev gspca_dev; /* !! must be the first item */
+ u8 model;
+#define CIT_MODEL0 0 /* bcd version 0.01 cams ie the xvp-500 */
+#define CIT_MODEL1 1 /* The model 1 - 4 nomenclature comes from the old */
+#define CIT_MODEL2 2 /* ibmcam driver */
+#define CIT_MODEL3 3
+#define CIT_MODEL4 4
+#define CIT_IBM_NETCAM_PRO 5
+ u8 input_index;
+ u8 button_state;
+ u8 stop_on_control_change;
+ u8 sof_read;
+ u8 sof_len;
+ u8 contrast;
+ u8 brightness;
+ u8 hue;
+ u8 sharpness;
+ u8 lighting;
+ u8 hflip;
+};
+
+/* V4L2 controls supported by the driver */
+static int sd_setbrightness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setsharpness(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getsharpness(struct gspca_dev *gspca_dev, __s32 *val);
+static int sd_setlighting(struct gspca_dev *gspca_dev, __s32 val);
+static int sd_getlighting(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 void sd_stop0(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[] = {
+#define SD_BRIGHTNESS 0
+ {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 63,
+ .step = 1,
+#define BRIGHTNESS_DEFAULT 32
+ .default_value = BRIGHTNESS_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setbrightness,
+ .get = sd_getbrightness,
+ },
+#define SD_CONTRAST 1
+ {
+ {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "contrast",
+ .minimum = 0,
+ .maximum = 20,
+ .step = 1,
+#define CONTRAST_DEFAULT 10
+ .default_value = CONTRAST_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setcontrast,
+ .get = sd_getcontrast,
+ },
+#define SD_HUE 2
+ {
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+#define HUE_DEFAULT 63
+ .default_value = HUE_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_sethue,
+ .get = sd_gethue,
+ },
+#define SD_SHARPNESS 3
+ {
+ {
+ .id = V4L2_CID_SHARPNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Sharpness",
+ .minimum = 0,
+ .maximum = 6,
+ .step = 1,
+#define SHARPNESS_DEFAULT 3
+ .default_value = SHARPNESS_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setsharpness,
+ .get = sd_getsharpness,
+ },
+#define SD_LIGHTING 4
+ {
+ {
+ .id = V4L2_CID_BACKLIGHT_COMPENSATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Lighting",
+ .minimum = 0,
+ .maximum = 2,
+ .step = 1,
+#define LIGHTING_DEFAULT 1
+ .default_value = LIGHTING_DEFAULT,
+ .flags = 0,
+ },
+ .set = sd_setlighting,
+ .get = sd_getlighting,
+ },
+#define SD_HFLIP 5
+ {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mirror",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+#define HFLIP_DEFAULT 0
+ .default_value = HFLIP_DEFAULT,
+ },
+ .set = sd_sethflip,
+ .get = sd_gethflip,
+ },
+};
+
+static const struct v4l2_pix_format cif_yuv_mode[] = {
+ {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {352, 288, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+static const struct v4l2_pix_format vga_yuv_mode[] = {
+ {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {640, 480, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 640,
+ .sizeimage = 640 * 480 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+static const struct v4l2_pix_format model0_mode[] = {
+ {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {320, 240, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+static const struct v4l2_pix_format model2_mode[] = {
+ {160, 120, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 160,
+ .sizeimage = 160 * 120 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {176, 144, V4L2_PIX_FMT_CIT_YYVYUY, V4L2_FIELD_NONE,
+ .bytesperline = 176,
+ .sizeimage = 176 * 144 * 3 / 2 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {320, 240, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+ .bytesperline = 320,
+ .sizeimage = 320 * 240 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+ {352, 288, V4L2_PIX_FMT_SGRBG8, V4L2_FIELD_NONE,
+ .bytesperline = 352,
+ .sizeimage = 352 * 288 + 4,
+ .colorspace = V4L2_COLORSPACE_SRGB},
+};
+
+/*
+ * 01.01.08 - Added for RCA video in support -LO
+ * This struct is used to init the Model3 cam to use the RCA video in port
+ * instead of the CCD sensor.
+ */
+static const u16 rca_initdata[][3] = {
+ {0, 0x0000, 0x010c},
+ {0, 0x0006, 0x012c},
+ {0, 0x0078, 0x012d},
+ {0, 0x0046, 0x012f},
+ {0, 0xd141, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfea8, 0x0124},
+ {1, 0x0000, 0x0116},
+ {0, 0x0064, 0x0116},
+ {1, 0x0000, 0x0115},
+ {0, 0x0003, 0x0115},
+ {0, 0x0008, 0x0123},
+ {0, 0x0000, 0x0117},
+ {0, 0x0000, 0x0112},
+ {0, 0x0080, 0x0100},
+ {0, 0x0000, 0x0100},
+ {1, 0x0000, 0x0116},
+ {0, 0x0060, 0x0116},
+ {0, 0x0002, 0x0112},
+ {0, 0x0000, 0x0123},
+ {0, 0x0001, 0x0117},
+ {0, 0x0040, 0x0108},
+ {0, 0x0019, 0x012c},
+ {0, 0x0040, 0x0116},
+ {0, 0x000a, 0x0115},
+ {0, 0x000b, 0x0115},
+ {0, 0x0078, 0x012d},
+ {0, 0x0046, 0x012f},
+ {0, 0xd141, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfea8, 0x0124},
+ {0, 0x0064, 0x0116},
+ {0, 0x0000, 0x0115},
+ {0, 0x0001, 0x0115},
+ {0, 0xffff, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x00aa, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xffff, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x00f2, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x000f, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xffff, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x00f8, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x00fc, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xffff, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x00f9, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x003c, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xffff, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0027, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0019, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0021, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0006, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0045, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x002a, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x000e, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x002b, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x00f4, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x002c, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0004, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x002d, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0014, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x002e, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0003, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x002f, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0003, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0014, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0040, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0040, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0053, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0x0000, 0x0101},
+ {0, 0x00a0, 0x0103},
+ {0, 0x0078, 0x0105},
+ {0, 0x0000, 0x010a},
+ {0, 0x0024, 0x010b},
+ {0, 0x0028, 0x0119},
+ {0, 0x0088, 0x011b},
+ {0, 0x0002, 0x011d},
+ {0, 0x0003, 0x011e},
+ {0, 0x0000, 0x0129},
+ {0, 0x00fc, 0x012b},
+ {0, 0x0008, 0x0102},
+ {0, 0x0000, 0x0104},
+ {0, 0x0008, 0x011a},
+ {0, 0x0028, 0x011c},
+ {0, 0x0021, 0x012a},
+ {0, 0x0000, 0x0118},
+ {0, 0x0000, 0x0132},
+ {0, 0x0000, 0x0109},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0031, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0040, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0040, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x00dc, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0032, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0020, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0001, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0040, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0040, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0037, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0030, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0xfff9, 0x0124},
+ {0, 0x0086, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0038, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0008, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0x0000, 0x0127},
+ {0, 0xfff8, 0x0124},
+ {0, 0xfffd, 0x0124},
+ {0, 0xfffa, 0x0124},
+ {0, 0x0003, 0x0111},
+};
+
+/* TESTME the old ibmcam driver repeats certain commands to Model1 cameras, we
+ do the same for now (testing needed to see if this is really necessary) */
+static const int cit_model1_ntries = 5;
+static const int cit_model1_ntries2 = 2;
+
+static int cit_write_reg(struct gspca_dev *gspca_dev, u16 value, u16 index)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ int err;
+
+ err = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x00,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+ value, index, NULL, 0, 1000);
+ if (err < 0)
+ err("Failed to write a register (index 0x%04X,"
+ " value 0x%02X, error %d)", index, value, err);
+
+ return 0;
+}
+
+static int cit_read_reg(struct gspca_dev *gspca_dev, u16 index, int verbose)
+{
+ struct usb_device *udev = gspca_dev->dev;
+ __u8 *buf = gspca_dev->usb_buf;
+ int res;
+
+ res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x01,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
+ 0x00, index, buf, 8, 1000);
+ if (res < 0) {
+ err("Failed to read a register (index 0x%04X, error %d)",
+ index, res);
+ return res;
+ }
+
+ if (verbose)
+ PDEBUG(D_PROBE, "Register %04x value: %02x", index, buf[0]);
+
+ return 0;
+}
+
+/*
+ * cit_send_FF_04_02()
+ *
+ * This procedure sends magic 3-command prefix to the camera.
+ * The purpose of this prefix is not known.
+ *
+ * History:
+ * 1/2/00 Created.
+ */
+static void cit_send_FF_04_02(struct gspca_dev *gspca_dev)
+{
+ cit_write_reg(gspca_dev, 0x00FF, 0x0127);
+ cit_write_reg(gspca_dev, 0x0004, 0x0124);
+ cit_write_reg(gspca_dev, 0x0002, 0x0124);
+}
+
+static void cit_send_00_04_06(struct gspca_dev *gspca_dev)
+{
+ cit_write_reg(gspca_dev, 0x0000, 0x0127);
+ cit_write_reg(gspca_dev, 0x0004, 0x0124);
+ cit_write_reg(gspca_dev, 0x0006, 0x0124);
+}
+
+static void cit_send_x_00(struct gspca_dev *gspca_dev, unsigned short x)
+{
+ cit_write_reg(gspca_dev, x, 0x0127);
+ cit_write_reg(gspca_dev, 0x0000, 0x0124);
+}
+
+static void cit_send_x_00_05(struct gspca_dev *gspca_dev, unsigned short x)
+{
+ cit_send_x_00(gspca_dev, x);
+ cit_write_reg(gspca_dev, 0x0005, 0x0124);
+}
+
+static void cit_send_x_00_05_02(struct gspca_dev *gspca_dev, unsigned short x)
+{
+ cit_write_reg(gspca_dev, x, 0x0127);
+ cit_write_reg(gspca_dev, 0x0000, 0x0124);
+ cit_write_reg(gspca_dev, 0x0005, 0x0124);
+ cit_write_reg(gspca_dev, 0x0002, 0x0124);
+}
+
+static void cit_send_x_01_00_05(struct gspca_dev *gspca_dev, u16 x)
+{
+ cit_write_reg(gspca_dev, x, 0x0127);
+ cit_write_reg(gspca_dev, 0x0001, 0x0124);
+ cit_write_reg(gspca_dev, 0x0000, 0x0124);
+ cit_write_reg(gspca_dev, 0x0005, 0x0124);
+}
+
+static void cit_send_x_00_05_02_01(struct gspca_dev *gspca_dev, u16 x)
+{
+ cit_write_reg(gspca_dev, x, 0x0127);
+ cit_write_reg(gspca_dev, 0x0000, 0x0124);
+ cit_write_reg(gspca_dev, 0x0005, 0x0124);
+ cit_write_reg(gspca_dev, 0x0002, 0x0124);
+ cit_write_reg(gspca_dev, 0x0001, 0x0124);
+}
+
+static void cit_send_x_00_05_02_08_01(struct gspca_dev *gspca_dev, u16 x)
+{
+ cit_write_reg(gspca_dev, x, 0x0127);
+ cit_write_reg(gspca_dev, 0x0000, 0x0124);
+ cit_write_reg(gspca_dev, 0x0005, 0x0124);
+ cit_write_reg(gspca_dev, 0x0002, 0x0124);
+ cit_write_reg(gspca_dev, 0x0008, 0x0124);
+ cit_write_reg(gspca_dev, 0x0001, 0x0124);
+}
+
+static void cit_Packet_Format1(struct gspca_dev *gspca_dev, u16 fkey, u16 val)
+{
+ cit_send_x_01_00_05(gspca_dev, 0x0088);
+ cit_send_x_00_05(gspca_dev, fkey);
+ cit_send_x_00_05_02_08_01(gspca_dev, val);
+ cit_send_x_00_05(gspca_dev, 0x0088);
+ cit_send_x_00_05_02_01(gspca_dev, fkey);
+ cit_send_x_00_05(gspca_dev, 0x0089);
+ cit_send_x_00(gspca_dev, fkey);
+ cit_send_00_04_06(gspca_dev);
+ cit_read_reg(gspca_dev, 0x0126, 0);
+ cit_send_FF_04_02(gspca_dev);
+}
+
+static void cit_PacketFormat2(struct gspca_dev *gspca_dev, u16 fkey, u16 val)
+{
+ cit_send_x_01_00_05(gspca_dev, 0x0088);
+ cit_send_x_00_05(gspca_dev, fkey);
+ cit_send_x_00_05_02(gspca_dev, val);
+}
+
+static void cit_model2_Packet2(struct gspca_dev *gspca_dev)
+{
+ cit_write_reg(gspca_dev, 0x00ff, 0x012d);
+ cit_write_reg(gspca_dev, 0xfea3, 0x0124);
+}
+
+static void cit_model2_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
+{
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x00ff, 0x012e);
+ cit_write_reg(gspca_dev, v1, 0x012f);
+ cit_write_reg(gspca_dev, 0x00ff, 0x0130);
+ cit_write_reg(gspca_dev, 0xc719, 0x0124);
+ cit_write_reg(gspca_dev, v2, 0x0127);
+
+ cit_model2_Packet2(gspca_dev);
+}
+
+/*
+ * cit_model3_Packet1()
+ *
+ * 00_0078_012d
+ * 00_0097_012f
+ * 00_d141_0124
+ * 00_0096_0127
+ * 00_fea8_0124
+*/
+static void cit_model3_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
+{
+ cit_write_reg(gspca_dev, 0x0078, 0x012d);
+ cit_write_reg(gspca_dev, v1, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, v2, 0x0127);
+ cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+}
+
+static void cit_model4_Packet1(struct gspca_dev *gspca_dev, u16 v1, u16 v2)
+{
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, v1, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, v2, 0x0127);
+ cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+}
+
+static void cit_model4_BrightnessPacket(struct gspca_dev *gspca_dev, u16 val)
+{
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0026, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, val, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0038, 0x012d);
+ cit_write_reg(gspca_dev, 0x0004, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+}
+
+/* this function is called at probe time */
+static int sd_config(struct gspca_dev *gspca_dev,
+ const struct usb_device_id *id)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ struct cam *cam;
+
+ sd->model = id->driver_info;
+ if (sd->model == CIT_MODEL3 && ibm_netcam_pro)
+ sd->model = CIT_IBM_NETCAM_PRO;
+
+ cam = &gspca_dev->cam;
+ switch (sd->model) {
+ case CIT_MODEL0:
+ cam->cam_mode = model0_mode;
+ cam->nmodes = ARRAY_SIZE(model0_mode);
+ cam->reverse_alts = 1;
+ gspca_dev->ctrl_dis = ~((1 << SD_CONTRAST) | (1 << SD_HFLIP));
+ sd->sof_len = 4;
+ break;
+ case CIT_MODEL1:
+ cam->cam_mode = cif_yuv_mode;
+ cam->nmodes = ARRAY_SIZE(cif_yuv_mode);
+ cam->reverse_alts = 1;
+ gspca_dev->ctrl_dis = (1 << SD_HUE) | (1 << SD_HFLIP);
+ sd->sof_len = 4;
+ break;
+ case CIT_MODEL2:
+ cam->cam_mode = model2_mode + 1; /* no 160x120 */
+ cam->nmodes = 3;
+ gspca_dev->ctrl_dis = (1 << SD_CONTRAST) |
+ (1 << SD_SHARPNESS) |
+ (1 << SD_HFLIP);
+ break;
+ case CIT_MODEL3:
+ cam->cam_mode = vga_yuv_mode;
+ cam->nmodes = ARRAY_SIZE(vga_yuv_mode);
+ gspca_dev->ctrl_dis = (1 << SD_HUE) |
+ (1 << SD_LIGHTING) |
+ (1 << SD_HFLIP);
+ sd->stop_on_control_change = 1;
+ sd->sof_len = 4;
+ break;
+ case CIT_MODEL4:
+ cam->cam_mode = model2_mode;
+ cam->nmodes = ARRAY_SIZE(model2_mode);
+ gspca_dev->ctrl_dis = (1 << SD_CONTRAST) |
+ (1 << SD_SHARPNESS) |
+ (1 << SD_LIGHTING) |
+ (1 << SD_HFLIP);
+ break;
+ case CIT_IBM_NETCAM_PRO:
+ cam->cam_mode = vga_yuv_mode;
+ cam->nmodes = 2; /* no 640 x 480 */
+ cam->input_flags = V4L2_IN_ST_VFLIP;
+ gspca_dev->ctrl_dis = ~(1 << SD_CONTRAST);
+ sd->stop_on_control_change = 1;
+ sd->sof_len = 4;
+ break;
+ }
+
+ sd->brightness = BRIGHTNESS_DEFAULT;
+ sd->contrast = CONTRAST_DEFAULT;
+ sd->hue = HUE_DEFAULT;
+ sd->sharpness = SHARPNESS_DEFAULT;
+ sd->lighting = LIGHTING_DEFAULT;
+ sd->hflip = HFLIP_DEFAULT;
+
+ return 0;
+}
+
+static int cit_init_model0(struct gspca_dev *gspca_dev)
+{
+ cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */
+ cit_write_reg(gspca_dev, 0x0001, 0x0112); /* turn on autogain ? */
+ cit_write_reg(gspca_dev, 0x0000, 0x0400);
+ cit_write_reg(gspca_dev, 0x0001, 0x0400);
+ cit_write_reg(gspca_dev, 0x0000, 0x0420);
+ cit_write_reg(gspca_dev, 0x0001, 0x0420);
+ cit_write_reg(gspca_dev, 0x000d, 0x0409);
+ cit_write_reg(gspca_dev, 0x0002, 0x040a);
+ cit_write_reg(gspca_dev, 0x0018, 0x0405);
+ cit_write_reg(gspca_dev, 0x0008, 0x0435);
+ cit_write_reg(gspca_dev, 0x0026, 0x040b);
+ cit_write_reg(gspca_dev, 0x0007, 0x0437);
+ cit_write_reg(gspca_dev, 0x0015, 0x042f);
+ cit_write_reg(gspca_dev, 0x002b, 0x0439);
+ cit_write_reg(gspca_dev, 0x0026, 0x043a);
+ cit_write_reg(gspca_dev, 0x0008, 0x0438);
+ cit_write_reg(gspca_dev, 0x001e, 0x042b);
+ cit_write_reg(gspca_dev, 0x0041, 0x042c);
+
+ return 0;
+}
+
+static int cit_init_ibm_netcam_pro(struct gspca_dev *gspca_dev)
+{
+ cit_read_reg(gspca_dev, 0x128, 1);
+ cit_write_reg(gspca_dev, 0x0003, 0x0133);
+ cit_write_reg(gspca_dev, 0x0000, 0x0117);
+ cit_write_reg(gspca_dev, 0x0008, 0x0123);
+ cit_write_reg(gspca_dev, 0x0000, 0x0100);
+ cit_read_reg(gspca_dev, 0x0116, 0);
+ cit_write_reg(gspca_dev, 0x0060, 0x0116);
+ cit_write_reg(gspca_dev, 0x0002, 0x0112);
+ cit_write_reg(gspca_dev, 0x0000, 0x0133);
+ cit_write_reg(gspca_dev, 0x0000, 0x0123);
+ cit_write_reg(gspca_dev, 0x0001, 0x0117);
+ cit_write_reg(gspca_dev, 0x0040, 0x0108);
+ cit_write_reg(gspca_dev, 0x0019, 0x012c);
+ cit_write_reg(gspca_dev, 0x0060, 0x0116);
+ cit_write_reg(gspca_dev, 0x0002, 0x0115);
+ cit_write_reg(gspca_dev, 0x000b, 0x0115);
+
+ cit_write_reg(gspca_dev, 0x0078, 0x012d);
+ cit_write_reg(gspca_dev, 0x0001, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0079, 0x012d);
+ cit_write_reg(gspca_dev, 0x00ff, 0x0130);
+ cit_write_reg(gspca_dev, 0xcd41, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+ cit_read_reg(gspca_dev, 0x0126, 1);
+
+ cit_model3_Packet1(gspca_dev, 0x0000, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0000, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x000b, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x000c, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x000d, 0x003a);
+ cit_model3_Packet1(gspca_dev, 0x000e, 0x0060);
+ cit_model3_Packet1(gspca_dev, 0x000f, 0x0060);
+ cit_model3_Packet1(gspca_dev, 0x0010, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x0011, 0x0004);
+ cit_model3_Packet1(gspca_dev, 0x0012, 0x0028);
+ cit_model3_Packet1(gspca_dev, 0x0013, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x0014, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0015, 0x00fb);
+ cit_model3_Packet1(gspca_dev, 0x0016, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x0017, 0x0037);
+ cit_model3_Packet1(gspca_dev, 0x0018, 0x0036);
+ cit_model3_Packet1(gspca_dev, 0x001e, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x001f, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x0020, 0x00c1);
+ cit_model3_Packet1(gspca_dev, 0x0021, 0x0034);
+ cit_model3_Packet1(gspca_dev, 0x0022, 0x0034);
+ cit_model3_Packet1(gspca_dev, 0x0025, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x0028, 0x0022);
+ cit_model3_Packet1(gspca_dev, 0x0029, 0x000a);
+ cit_model3_Packet1(gspca_dev, 0x002b, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x002c, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x002d, 0x00ff);
+ cit_model3_Packet1(gspca_dev, 0x002e, 0x00ff);
+ cit_model3_Packet1(gspca_dev, 0x002f, 0x00ff);
+ cit_model3_Packet1(gspca_dev, 0x0030, 0x00ff);
+ cit_model3_Packet1(gspca_dev, 0x0031, 0x00ff);
+ cit_model3_Packet1(gspca_dev, 0x0032, 0x0007);
+ cit_model3_Packet1(gspca_dev, 0x0033, 0x0005);
+ cit_model3_Packet1(gspca_dev, 0x0037, 0x0040);
+ cit_model3_Packet1(gspca_dev, 0x0039, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x003a, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x003b, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x003c, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0040, 0x000c);
+ cit_model3_Packet1(gspca_dev, 0x0041, 0x00fb);
+ cit_model3_Packet1(gspca_dev, 0x0042, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x0043, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0045, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0046, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0047, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0048, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0049, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x004a, 0x00ff);
+ cit_model3_Packet1(gspca_dev, 0x004b, 0x00ff);
+ cit_model3_Packet1(gspca_dev, 0x004c, 0x00ff);
+ cit_model3_Packet1(gspca_dev, 0x004f, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0050, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0051, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x0055, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0056, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0057, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0058, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x0059, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x005c, 0x0016);
+ cit_model3_Packet1(gspca_dev, 0x005d, 0x0022);
+ cit_model3_Packet1(gspca_dev, 0x005e, 0x003c);
+ cit_model3_Packet1(gspca_dev, 0x005f, 0x0050);
+ cit_model3_Packet1(gspca_dev, 0x0060, 0x0044);
+ cit_model3_Packet1(gspca_dev, 0x0061, 0x0005);
+ cit_model3_Packet1(gspca_dev, 0x006a, 0x007e);
+ cit_model3_Packet1(gspca_dev, 0x006f, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0072, 0x001b);
+ cit_model3_Packet1(gspca_dev, 0x0073, 0x0005);
+ cit_model3_Packet1(gspca_dev, 0x0074, 0x000a);
+ cit_model3_Packet1(gspca_dev, 0x0075, 0x001b);
+ cit_model3_Packet1(gspca_dev, 0x0076, 0x002a);
+ cit_model3_Packet1(gspca_dev, 0x0077, 0x003c);
+ cit_model3_Packet1(gspca_dev, 0x0078, 0x0050);
+ cit_model3_Packet1(gspca_dev, 0x007b, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x007c, 0x0011);
+ cit_model3_Packet1(gspca_dev, 0x007d, 0x0024);
+ cit_model3_Packet1(gspca_dev, 0x007e, 0x0043);
+ cit_model3_Packet1(gspca_dev, 0x007f, 0x005a);
+ cit_model3_Packet1(gspca_dev, 0x0084, 0x0020);
+ cit_model3_Packet1(gspca_dev, 0x0085, 0x0033);
+ cit_model3_Packet1(gspca_dev, 0x0086, 0x000a);
+ cit_model3_Packet1(gspca_dev, 0x0087, 0x0030);
+ cit_model3_Packet1(gspca_dev, 0x0088, 0x0070);
+ cit_model3_Packet1(gspca_dev, 0x008b, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x008f, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0090, 0x0006);
+ cit_model3_Packet1(gspca_dev, 0x0091, 0x0028);
+ cit_model3_Packet1(gspca_dev, 0x0092, 0x005a);
+ cit_model3_Packet1(gspca_dev, 0x0093, 0x0082);
+ cit_model3_Packet1(gspca_dev, 0x0096, 0x0014);
+ cit_model3_Packet1(gspca_dev, 0x0097, 0x0020);
+ cit_model3_Packet1(gspca_dev, 0x0098, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00b0, 0x0046);
+ cit_model3_Packet1(gspca_dev, 0x00b1, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00b2, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00b3, 0x0004);
+ cit_model3_Packet1(gspca_dev, 0x00b4, 0x0007);
+ cit_model3_Packet1(gspca_dev, 0x00b6, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x00b7, 0x0004);
+ cit_model3_Packet1(gspca_dev, 0x00bb, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00bc, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x00bd, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00bf, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00c0, 0x00c8);
+ cit_model3_Packet1(gspca_dev, 0x00c1, 0x0014);
+ cit_model3_Packet1(gspca_dev, 0x00c2, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x00c3, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00c4, 0x0004);
+ cit_model3_Packet1(gspca_dev, 0x00cb, 0x00bf);
+ cit_model3_Packet1(gspca_dev, 0x00cc, 0x00bf);
+ cit_model3_Packet1(gspca_dev, 0x00cd, 0x00bf);
+ cit_model3_Packet1(gspca_dev, 0x00ce, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00cf, 0x0020);
+ cit_model3_Packet1(gspca_dev, 0x00d0, 0x0040);
+ cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf);
+ cit_model3_Packet1(gspca_dev, 0x00d1, 0x00bf);
+ cit_model3_Packet1(gspca_dev, 0x00d2, 0x00bf);
+ cit_model3_Packet1(gspca_dev, 0x00d3, 0x00bf);
+ cit_model3_Packet1(gspca_dev, 0x00ea, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x00eb, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00ec, 0x00e8);
+ cit_model3_Packet1(gspca_dev, 0x00ed, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x00ef, 0x0022);
+ cit_model3_Packet1(gspca_dev, 0x00f0, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00f2, 0x0028);
+ cit_model3_Packet1(gspca_dev, 0x00f4, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x00f5, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00fa, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00fb, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x00fc, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00fd, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00fe, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00ff, 0x0000);
+
+ cit_model3_Packet1(gspca_dev, 0x00be, 0x0003);
+ cit_model3_Packet1(gspca_dev, 0x00c8, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00c9, 0x0020);
+ cit_model3_Packet1(gspca_dev, 0x00ca, 0x0040);
+ cit_model3_Packet1(gspca_dev, 0x0053, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x0082, 0x000e);
+ cit_model3_Packet1(gspca_dev, 0x0083, 0x0020);
+ cit_model3_Packet1(gspca_dev, 0x0034, 0x003c);
+ cit_model3_Packet1(gspca_dev, 0x006e, 0x0055);
+ cit_model3_Packet1(gspca_dev, 0x0062, 0x0005);
+ cit_model3_Packet1(gspca_dev, 0x0063, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x0066, 0x000a);
+ cit_model3_Packet1(gspca_dev, 0x0067, 0x0006);
+ cit_model3_Packet1(gspca_dev, 0x006b, 0x0010);
+ cit_model3_Packet1(gspca_dev, 0x005a, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x005b, 0x000a);
+ cit_model3_Packet1(gspca_dev, 0x0023, 0x0006);
+ cit_model3_Packet1(gspca_dev, 0x0026, 0x0004);
+ cit_model3_Packet1(gspca_dev, 0x0036, 0x0069);
+ cit_model3_Packet1(gspca_dev, 0x0038, 0x0064);
+ cit_model3_Packet1(gspca_dev, 0x003d, 0x0003);
+ cit_model3_Packet1(gspca_dev, 0x003e, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x00b8, 0x0014);
+ cit_model3_Packet1(gspca_dev, 0x00b9, 0x0014);
+ cit_model3_Packet1(gspca_dev, 0x00e6, 0x0004);
+ cit_model3_Packet1(gspca_dev, 0x00e8, 0x0001);
+
+ 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;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ cit_init_model0(gspca_dev);
+ sd_stop0(gspca_dev);
+ break;
+ case CIT_MODEL1:
+ case CIT_MODEL2:
+ case CIT_MODEL3:
+ case CIT_MODEL4:
+ break; /* All is done in sd_start */
+ case CIT_IBM_NETCAM_PRO:
+ cit_init_ibm_netcam_pro(gspca_dev);
+ sd_stop0(gspca_dev);
+ break;
+ }
+ return 0;
+}
+
+static int cit_set_brightness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ case CIT_IBM_NETCAM_PRO:
+ /* No (known) brightness control for these */
+ break;
+ case CIT_MODEL1:
+ /* Model 1: Brightness range 0 - 63 */
+ cit_Packet_Format1(gspca_dev, 0x0031, sd->brightness);
+ cit_Packet_Format1(gspca_dev, 0x0032, sd->brightness);
+ cit_Packet_Format1(gspca_dev, 0x0033, sd->brightness);
+ break;
+ case CIT_MODEL2:
+ /* Model 2: Brightness range 0x60 - 0xee */
+ /* Scale 0 - 63 to 0x60 - 0xee */
+ i = 0x60 + sd->brightness * 2254 / 1000;
+ cit_model2_Packet1(gspca_dev, 0x001a, i);
+ break;
+ case CIT_MODEL3:
+ /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
+ i = sd->brightness;
+ if (i < 0x0c)
+ i = 0x0c;
+ cit_model3_Packet1(gspca_dev, 0x0036, i);
+ break;
+ case CIT_MODEL4:
+ /* Model 4: Brightness range 'i' in [0x04..0xb4] */
+ /* Scale 0 - 63 to 0x04 - 0xb4 */
+ i = 0x04 + sd->brightness * 2794 / 1000;
+ cit_model4_BrightnessPacket(gspca_dev, i);
+ break;
+ }
+
+ return 0;
+}
+
+static int cit_set_contrast(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->model) {
+ case CIT_MODEL0: {
+ int i;
+ /* gain 0-15, 0-20 -> 0-15 */
+ i = sd->contrast * 1000 / 1333;
+ cit_write_reg(gspca_dev, i, 0x0422);
+ /* gain 0-31, may not be lower then 0x0422, 0-20 -> 0-31 */
+ i = sd->contrast * 2000 / 1333;
+ cit_write_reg(gspca_dev, i, 0x0423);
+ /* gain 0-127, may not be lower then 0x0423, 0-20 -> 0-63 */
+ i = sd->contrast * 4000 / 1333;
+ cit_write_reg(gspca_dev, i, 0x0424);
+ /* gain 0-127, may not be lower then 0x0424, , 0-20 -> 0-127 */
+ i = sd->contrast * 8000 / 1333;
+ cit_write_reg(gspca_dev, i, 0x0425);
+ break;
+ }
+ case CIT_MODEL2:
+ case CIT_MODEL4:
+ /* These models do not have this control. */
+ break;
+ case CIT_MODEL1:
+ {
+ /* Scale 0 - 20 to 15 - 0 */
+ int i, new_contrast = (20 - sd->contrast) * 1000 / 1333;
+ for (i = 0; i < cit_model1_ntries; i++) {
+ cit_Packet_Format1(gspca_dev, 0x0014, new_contrast);
+ cit_send_FF_04_02(gspca_dev);
+ }
+ break;
+ }
+ case CIT_MODEL3:
+ { /* Preset hardware values */
+ static const struct {
+ unsigned short cv1;
+ unsigned short cv2;
+ unsigned short cv3;
+ } cv[7] = {
+ { 0x05, 0x05, 0x0f }, /* Minimum */
+ { 0x04, 0x04, 0x16 },
+ { 0x02, 0x03, 0x16 },
+ { 0x02, 0x08, 0x16 },
+ { 0x01, 0x0c, 0x16 },
+ { 0x01, 0x0e, 0x16 },
+ { 0x01, 0x10, 0x16 } /* Maximum */
+ };
+ int i = sd->contrast / 3;
+ cit_model3_Packet1(gspca_dev, 0x0067, cv[i].cv1);
+ cit_model3_Packet1(gspca_dev, 0x005b, cv[i].cv2);
+ cit_model3_Packet1(gspca_dev, 0x005c, cv[i].cv3);
+ break;
+ }
+ case CIT_IBM_NETCAM_PRO:
+ cit_model3_Packet1(gspca_dev, 0x005b, sd->contrast + 1);
+ break;
+ }
+ return 0;
+}
+
+static int cit_set_hue(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ case CIT_MODEL1:
+ case CIT_IBM_NETCAM_PRO:
+ /* No hue control for these models */
+ break;
+ case CIT_MODEL2:
+ cit_model2_Packet1(gspca_dev, 0x0024, sd->hue);
+ /* cit_model2_Packet1(gspca_dev, 0x0020, sat); */
+ break;
+ case CIT_MODEL3: {
+ /* Model 3: Brightness range 'i' in [0x05..0x37] */
+ /* TESTME according to the ibmcam driver this does not work */
+ if (0) {
+ /* Scale 0 - 127 to 0x05 - 0x37 */
+ int i = 0x05 + sd->hue * 1000 / 2540;
+ cit_model3_Packet1(gspca_dev, 0x007e, i);
+ }
+ break;
+ }
+ case CIT_MODEL4:
+ /* HDG: taken from ibmcam, setting the color gains does not
+ * really belong here.
+ *
+ * I am not sure r/g/b_gain variables exactly control gain
+ * of those channels. Most likely they subtly change some
+ * very internal image processing settings in the camera.
+ * In any case, here is what they do, and feel free to tweak:
+ *
+ * r_gain: seriously affects red gain
+ * g_gain: seriously affects green gain
+ * b_gain: seriously affects blue gain
+ * hue: changes average color from violet (0) to red (0xFF)
+ */
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x001e, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 160, 0x0127); /* Green gain */
+ cit_write_reg(gspca_dev, 160, 0x012e); /* Red gain */
+ cit_write_reg(gspca_dev, 160, 0x0130); /* Blue gain */
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, sd->hue, 0x012d); /* Hue */
+ cit_write_reg(gspca_dev, 0xf545, 0x0124);
+ break;
+ }
+ return 0;
+}
+
+static int cit_set_sharpness(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ case CIT_MODEL2:
+ case CIT_MODEL4:
+ case CIT_IBM_NETCAM_PRO:
+ /* These models do not have this control */
+ break;
+ case CIT_MODEL1: {
+ int i;
+ const unsigned short sa[] = {
+ 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
+
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_PacketFormat2(gspca_dev, 0x0013, sa[sd->sharpness]);
+ break;
+ }
+ case CIT_MODEL3:
+ { /*
+ * "Use a table of magic numbers.
+ * This setting doesn't really change much.
+ * But that's how Windows does it."
+ */
+ static const struct {
+ unsigned short sv1;
+ unsigned short sv2;
+ unsigned short sv3;
+ unsigned short sv4;
+ } sv[7] = {
+ { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */
+ { 0x01, 0x04, 0x05, 0x14 },
+ { 0x02, 0x04, 0x05, 0x14 },
+ { 0x03, 0x04, 0x05, 0x14 },
+ { 0x03, 0x05, 0x05, 0x14 },
+ { 0x03, 0x06, 0x05, 0x14 },
+ { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */
+ };
+ cit_model3_Packet1(gspca_dev, 0x0060, sv[sd->sharpness].sv1);
+ cit_model3_Packet1(gspca_dev, 0x0061, sv[sd->sharpness].sv2);
+ cit_model3_Packet1(gspca_dev, 0x0062, sv[sd->sharpness].sv3);
+ cit_model3_Packet1(gspca_dev, 0x0063, sv[sd->sharpness].sv4);
+ break;
+ }
+ }
+ return 0;
+}
+
+/*
+ * cit_set_lighting()
+ *
+ * Camera model 1:
+ * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
+ *
+ * Camera model 2:
+ * We have 16 levels of lighting, 0 for bright light and up to 15 for
+ * low light. But values above 5 or so are useless because camera is
+ * not really capable to produce anything worth viewing at such light.
+ * This setting may be altered only in certain camera state.
+ *
+ * Low lighting forces slower FPS.
+ *
+ * History:
+ * 1/5/00 Created.
+ * 2/20/00 Added support for Model 2 cameras.
+ */
+static void cit_set_lighting(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ case CIT_MODEL2:
+ case CIT_MODEL3:
+ case CIT_MODEL4:
+ case CIT_IBM_NETCAM_PRO:
+ break;
+ case CIT_MODEL1: {
+ int i;
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting);
+ break;
+ }
+ }
+}
+
+static void cit_set_hflip(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ if (sd->hflip)
+ cit_write_reg(gspca_dev, 0x0020, 0x0115);
+ else
+ cit_write_reg(gspca_dev, 0x0040, 0x0115);
+ break;
+ case CIT_MODEL1:
+ case CIT_MODEL2:
+ case CIT_MODEL3:
+ case CIT_MODEL4:
+ case CIT_IBM_NETCAM_PRO:
+ break;
+ }
+}
+
+static int cit_restart_stream(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ case CIT_MODEL1:
+ cit_write_reg(gspca_dev, 0x0001, 0x0114);
+ /* Fall through */
+ case CIT_MODEL2:
+ case CIT_MODEL4:
+ cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */
+ usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
+ break;
+ case CIT_MODEL3:
+ case CIT_IBM_NETCAM_PRO:
+ cit_write_reg(gspca_dev, 0x0001, 0x0114);
+ cit_write_reg(gspca_dev, 0x00c0, 0x010c); /* Go! */
+ usb_clear_halt(gspca_dev->dev, gspca_dev->urb[0]->pipe);
+ /* Clear button events from while we were not streaming */
+ cit_write_reg(gspca_dev, 0x0001, 0x0113);
+ break;
+ }
+
+ sd->sof_read = 0;
+
+ return 0;
+}
+
+static int cit_get_packet_size(struct gspca_dev *gspca_dev)
+{
+ struct usb_host_interface *alt;
+ struct usb_interface *intf;
+
+ intf = usb_ifnum_to_if(gspca_dev->dev, gspca_dev->iface);
+ alt = usb_altnum_to_altsetting(intf, gspca_dev->alt);
+ if (!alt) {
+ err("Couldn't get altsetting");
+ return -EIO;
+ }
+
+ return le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+}
+
+/* Calculate the clockdiv giving us max fps given the available bandwidth */
+static int cit_get_clock_div(struct gspca_dev *gspca_dev)
+{
+ int clock_div = 7; /* 0=30 1=25 2=20 3=15 4=12 5=7.5 6=6 7=3fps ?? */
+ int fps[8] = { 30, 25, 20, 15, 12, 8, 6, 3 };
+ int packet_size;
+
+ packet_size = cit_get_packet_size(gspca_dev);
+ if (packet_size < 0)
+ return packet_size;
+
+ while (clock_div > 3 &&
+ 1000 * packet_size >
+ gspca_dev->width * gspca_dev->height *
+ fps[clock_div - 1] * 3 / 2)
+ clock_div--;
+
+ PDEBUG(D_PROBE,
+ "PacketSize: %d, res: %dx%d -> using clockdiv: %d (%d fps)",
+ packet_size, gspca_dev->width, gspca_dev->height, clock_div,
+ fps[clock_div]);
+
+ return clock_div;
+}
+
+static int cit_start_model0(struct gspca_dev *gspca_dev)
+{
+ const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+ int clock_div;
+
+ clock_div = cit_get_clock_div(gspca_dev);
+ if (clock_div < 0)
+ return clock_div;
+
+ cit_write_reg(gspca_dev, 0x0000, 0x0100); /* turn on led */
+ cit_write_reg(gspca_dev, 0x0003, 0x0438);
+ cit_write_reg(gspca_dev, 0x001e, 0x042b);
+ cit_write_reg(gspca_dev, 0x0041, 0x042c);
+ cit_write_reg(gspca_dev, 0x0008, 0x0436);
+ cit_write_reg(gspca_dev, 0x0024, 0x0403);
+ cit_write_reg(gspca_dev, 0x002c, 0x0404);
+ cit_write_reg(gspca_dev, 0x0002, 0x0426);
+ cit_write_reg(gspca_dev, 0x0014, 0x0427);
+
+ switch (gspca_dev->width) {
+ case 160: /* 160x120 */
+ cit_write_reg(gspca_dev, 0x0004, 0x010b);
+ cit_write_reg(gspca_dev, 0x0001, 0x010a);
+ cit_write_reg(gspca_dev, 0x0010, 0x0102);
+ cit_write_reg(gspca_dev, 0x00a0, 0x0103);
+ cit_write_reg(gspca_dev, 0x0000, 0x0104);
+ cit_write_reg(gspca_dev, 0x0078, 0x0105);
+ break;
+
+ case 176: /* 176x144 */
+ cit_write_reg(gspca_dev, 0x0006, 0x010b);
+ cit_write_reg(gspca_dev, 0x0000, 0x010a);
+ cit_write_reg(gspca_dev, 0x0005, 0x0102);
+ cit_write_reg(gspca_dev, 0x00b0, 0x0103);
+ cit_write_reg(gspca_dev, 0x0000, 0x0104);
+ cit_write_reg(gspca_dev, 0x0090, 0x0105);
+ break;
+
+ case 320: /* 320x240 */
+ cit_write_reg(gspca_dev, 0x0008, 0x010b);
+ cit_write_reg(gspca_dev, 0x0004, 0x010a);
+ cit_write_reg(gspca_dev, 0x0005, 0x0102);
+ cit_write_reg(gspca_dev, 0x00a0, 0x0103);
+ cit_write_reg(gspca_dev, 0x0010, 0x0104);
+ cit_write_reg(gspca_dev, 0x0078, 0x0105);
+ break;
+ }
+
+ cit_write_reg(gspca_dev, compression, 0x0109);
+ cit_write_reg(gspca_dev, clock_div, 0x0111);
+
+ return 0;
+}
+
+static int cit_start_model1(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int i, clock_div;
+
+ clock_div = cit_get_clock_div(gspca_dev);
+ if (clock_div < 0)
+ return clock_div;
+
+ cit_read_reg(gspca_dev, 0x0128, 1);
+ cit_read_reg(gspca_dev, 0x0100, 0);
+ cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */
+ cit_read_reg(gspca_dev, 0x0100, 0);
+ cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */
+ cit_read_reg(gspca_dev, 0x0100, 0);
+ cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */
+ cit_write_reg(gspca_dev, 0x01, 0x0108);
+
+ cit_write_reg(gspca_dev, 0x03, 0x0112);
+ cit_read_reg(gspca_dev, 0x0115, 0);
+ cit_write_reg(gspca_dev, 0x06, 0x0115);
+ cit_read_reg(gspca_dev, 0x0116, 0);
+ cit_write_reg(gspca_dev, 0x44, 0x0116);
+ cit_read_reg(gspca_dev, 0x0116, 0);
+ cit_write_reg(gspca_dev, 0x40, 0x0116);
+ cit_read_reg(gspca_dev, 0x0115, 0);
+ cit_write_reg(gspca_dev, 0x0e, 0x0115);
+ cit_write_reg(gspca_dev, 0x19, 0x012c);
+
+ cit_Packet_Format1(gspca_dev, 0x00, 0x1e);
+ cit_Packet_Format1(gspca_dev, 0x39, 0x0d);
+ cit_Packet_Format1(gspca_dev, 0x39, 0x09);
+ cit_Packet_Format1(gspca_dev, 0x3b, 0x00);
+ cit_Packet_Format1(gspca_dev, 0x28, 0x22);
+ cit_Packet_Format1(gspca_dev, 0x27, 0x00);
+ cit_Packet_Format1(gspca_dev, 0x2b, 0x1f);
+ cit_Packet_Format1(gspca_dev, 0x39, 0x08);
+
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x2c, 0x00);
+
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x30, 0x14);
+
+ cit_PacketFormat2(gspca_dev, 0x39, 0x02);
+ cit_PacketFormat2(gspca_dev, 0x01, 0xe1);
+ cit_PacketFormat2(gspca_dev, 0x02, 0xcd);
+ cit_PacketFormat2(gspca_dev, 0x03, 0xcd);
+ cit_PacketFormat2(gspca_dev, 0x04, 0xfa);
+ cit_PacketFormat2(gspca_dev, 0x3f, 0xff);
+ cit_PacketFormat2(gspca_dev, 0x39, 0x00);
+
+ cit_PacketFormat2(gspca_dev, 0x39, 0x02);
+ cit_PacketFormat2(gspca_dev, 0x0a, 0x37);
+ cit_PacketFormat2(gspca_dev, 0x0b, 0xb8);
+ cit_PacketFormat2(gspca_dev, 0x0c, 0xf3);
+ cit_PacketFormat2(gspca_dev, 0x0d, 0xe3);
+ cit_PacketFormat2(gspca_dev, 0x0e, 0x0d);
+ cit_PacketFormat2(gspca_dev, 0x0f, 0xf2);
+ cit_PacketFormat2(gspca_dev, 0x10, 0xd5);
+ cit_PacketFormat2(gspca_dev, 0x11, 0xba);
+ cit_PacketFormat2(gspca_dev, 0x12, 0x53);
+ cit_PacketFormat2(gspca_dev, 0x3f, 0xff);
+ cit_PacketFormat2(gspca_dev, 0x39, 0x00);
+
+ cit_PacketFormat2(gspca_dev, 0x39, 0x02);
+ cit_PacketFormat2(gspca_dev, 0x16, 0x00);
+ cit_PacketFormat2(gspca_dev, 0x17, 0x28);
+ cit_PacketFormat2(gspca_dev, 0x18, 0x7d);
+ cit_PacketFormat2(gspca_dev, 0x19, 0xbe);
+ cit_PacketFormat2(gspca_dev, 0x3f, 0xff);
+ cit_PacketFormat2(gspca_dev, 0x39, 0x00);
+
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x00, 0x18);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x13, 0x18);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x14, 0x06);
+
+ /* TESTME These are handled through controls
+ KEEP until someone can test leaving this out is ok */
+ if (0) {
+ /* This is default brightness */
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x31, 0x37);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x32, 0x46);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x33, 0x55);
+ }
+
+ cit_Packet_Format1(gspca_dev, 0x2e, 0x04);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x2d, 0x04);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x29, 0x80);
+ cit_Packet_Format1(gspca_dev, 0x2c, 0x01);
+ cit_Packet_Format1(gspca_dev, 0x30, 0x17);
+ cit_Packet_Format1(gspca_dev, 0x39, 0x08);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x34, 0x00);
+
+ cit_write_reg(gspca_dev, 0x00, 0x0101);
+ cit_write_reg(gspca_dev, 0x00, 0x010a);
+
+ switch (gspca_dev->width) {
+ case 128: /* 128x96 */
+ cit_write_reg(gspca_dev, 0x80, 0x0103);
+ cit_write_reg(gspca_dev, 0x60, 0x0105);
+ cit_write_reg(gspca_dev, 0x0c, 0x010b);
+ cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x0b, 0x011d);
+ cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x00, 0x0129);
+ break;
+ case 176: /* 176x144 */
+ cit_write_reg(gspca_dev, 0xb0, 0x0103);
+ cit_write_reg(gspca_dev, 0x8f, 0x0105);
+ cit_write_reg(gspca_dev, 0x06, 0x010b);
+ cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x0d, 0x011d);
+ cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x03, 0x0129);
+ break;
+ case 352: /* 352x288 */
+ cit_write_reg(gspca_dev, 0xb0, 0x0103);
+ cit_write_reg(gspca_dev, 0x90, 0x0105);
+ cit_write_reg(gspca_dev, 0x02, 0x010b);
+ cit_write_reg(gspca_dev, 0x04, 0x011b); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x05, 0x011d);
+ cit_write_reg(gspca_dev, 0x00, 0x011e); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x00, 0x0129);
+ break;
+ }
+
+ cit_write_reg(gspca_dev, 0xff, 0x012b);
+
+ /* TESTME These are handled through controls
+ KEEP until someone can test leaving this out is ok */
+ if (0) {
+ /* This is another brightness - don't know why */
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x31, 0xc3);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x32, 0xd2);
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x33, 0xe1);
+
+ /* Default contrast */
+ for (i = 0; i < cit_model1_ntries; i++)
+ cit_Packet_Format1(gspca_dev, 0x14, 0x0a);
+
+ /* Default sharpness */
+ for (i = 0; i < cit_model1_ntries2; i++)
+ cit_PacketFormat2(gspca_dev, 0x13, 0x1a);
+
+ /* Default lighting conditions */
+ cit_Packet_Format1(gspca_dev, 0x0027, sd->lighting);
+ }
+
+ /* Assorted init */
+ switch (gspca_dev->width) {
+ case 128: /* 128x96 */
+ cit_Packet_Format1(gspca_dev, 0x2b, 0x1e);
+ cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x36, 0x0102);
+ cit_write_reg(gspca_dev, 0x1a, 0x0104);
+ cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x2b, 0x011c);
+ cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */
+ break;
+ case 176: /* 176x144 */
+ cit_Packet_Format1(gspca_dev, 0x2b, 0x1e);
+ cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x04, 0x0102);
+ cit_write_reg(gspca_dev, 0x02, 0x0104);
+ cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x2b, 0x011c);
+ cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */
+ break;
+ case 352: /* 352x288 */
+ cit_Packet_Format1(gspca_dev, 0x2b, 0x1f);
+ cit_write_reg(gspca_dev, 0xc9, 0x0119); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x80, 0x0109); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x08, 0x0102);
+ cit_write_reg(gspca_dev, 0x01, 0x0104);
+ cit_write_reg(gspca_dev, 0x04, 0x011a); /* Same everywhere */
+ cit_write_reg(gspca_dev, 0x2f, 0x011c);
+ cit_write_reg(gspca_dev, 0x23, 0x012a); /* Same everywhere */
+ break;
+ }
+
+ cit_write_reg(gspca_dev, 0x01, 0x0100); /* LED On */
+ cit_write_reg(gspca_dev, clock_div, 0x0111);
+
+ return 0;
+}
+
+static int cit_start_model2(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int clock_div = 0;
+
+ cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */
+ cit_read_reg(gspca_dev, 0x0116, 0);
+ cit_write_reg(gspca_dev, 0x0060, 0x0116);
+ cit_write_reg(gspca_dev, 0x0002, 0x0112);
+ cit_write_reg(gspca_dev, 0x00bc, 0x012c);
+ cit_write_reg(gspca_dev, 0x0008, 0x012b);
+ cit_write_reg(gspca_dev, 0x0000, 0x0108);
+ cit_write_reg(gspca_dev, 0x0001, 0x0133);
+ cit_write_reg(gspca_dev, 0x0001, 0x0102);
+ switch (gspca_dev->width) {
+ case 176: /* 176x144 */
+ cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */
+ cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */
+ cit_write_reg(gspca_dev, 0x0024, 0x0105); /* 176x144, 352x288 */
+ cit_write_reg(gspca_dev, 0x00b9, 0x010a); /* Unique to this mode */
+ cit_write_reg(gspca_dev, 0x0038, 0x0119); /* Unique to this mode */
+ /* TESTME HDG: this does not seem right
+ (it is 2 for all other resolutions) */
+ sd->sof_len = 10;
+ break;
+ case 320: /* 320x240 */
+ cit_write_reg(gspca_dev, 0x0028, 0x0103); /* Unique to this mode */
+ cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */
+ cit_write_reg(gspca_dev, 0x001e, 0x0105); /* 320x240, 352x240 */
+ cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */
+ cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */
+ sd->sof_len = 2;
+ break;
+ /* case VIDEOSIZE_352x240: */
+ cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */
+ cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */
+ cit_write_reg(gspca_dev, 0x001e, 0x0105); /* 320x240, 352x240 */
+ cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */
+ cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */
+ sd->sof_len = 2;
+ break;
+ case 352: /* 352x288 */
+ cit_write_reg(gspca_dev, 0x002c, 0x0103); /* All except 320x240 */
+ cit_write_reg(gspca_dev, 0x0000, 0x0104); /* Same */
+ cit_write_reg(gspca_dev, 0x0024, 0x0105); /* 176x144, 352x288 */
+ cit_write_reg(gspca_dev, 0x0039, 0x010a); /* All except 176x144 */
+ cit_write_reg(gspca_dev, 0x0070, 0x0119); /* All except 176x144 */
+ sd->sof_len = 2;
+ break;
+ }
+
+ cit_write_reg(gspca_dev, 0x0000, 0x0100); /* LED on */
+
+ switch (gspca_dev->width) {
+ case 176: /* 176x144 */
+ cit_write_reg(gspca_dev, 0x0050, 0x0111);
+ cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+ break;
+ case 320: /* 320x240 */
+ case 352: /* 352x288 */
+ cit_write_reg(gspca_dev, 0x0040, 0x0111);
+ cit_write_reg(gspca_dev, 0x00c0, 0x0111);
+ break;
+ }
+ cit_write_reg(gspca_dev, 0x009b, 0x010f);
+ cit_write_reg(gspca_dev, 0x00bb, 0x010f);
+
+ /*
+ * Hardware settings, may affect CMOS sensor; not user controls!
+ * -------------------------------------------------------------
+ * 0x0004: no effect
+ * 0x0006: hardware effect
+ * 0x0008: no effect
+ * 0x000a: stops video stream, probably important h/w setting
+ * 0x000c: changes color in hardware manner (not user setting)
+ * 0x0012: changes number of colors (does not affect speed)
+ * 0x002a: no effect
+ * 0x002c: hardware setting (related to scan lines)
+ * 0x002e: stops video stream, probably important h/w setting
+ */
+ cit_model2_Packet1(gspca_dev, 0x000a, 0x005c);
+ cit_model2_Packet1(gspca_dev, 0x0004, 0x0000);
+ cit_model2_Packet1(gspca_dev, 0x0006, 0x00fb);
+ cit_model2_Packet1(gspca_dev, 0x0008, 0x0000);
+ cit_model2_Packet1(gspca_dev, 0x000c, 0x0009);
+ cit_model2_Packet1(gspca_dev, 0x0012, 0x000a);
+ cit_model2_Packet1(gspca_dev, 0x002a, 0x0000);
+ cit_model2_Packet1(gspca_dev, 0x002c, 0x0000);
+ cit_model2_Packet1(gspca_dev, 0x002e, 0x0008);
+
+ /*
+ * Function 0x0030 pops up all over the place. Apparently
+ * it is a hardware control register, with every bit assigned to
+ * do something.
+ */
+ cit_model2_Packet1(gspca_dev, 0x0030, 0x0000);
+
+ /*
+ * Magic control of CMOS sensor. Only lower values like
+ * 0-3 work, and picture shifts left or right. Don't change.
+ */
+ switch (gspca_dev->width) {
+ case 176: /* 176x144 */
+ cit_model2_Packet1(gspca_dev, 0x0014, 0x0002);
+ cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */
+ cit_model2_Packet1(gspca_dev, 0x0018, 0x004a); /* Another hardware setting */
+ clock_div = 6;
+ break;
+ case 320: /* 320x240 */
+ cit_model2_Packet1(gspca_dev, 0x0014, 0x0009);
+ cit_model2_Packet1(gspca_dev, 0x0016, 0x0005); /* Horizontal shift */
+ cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Another hardware setting */
+ clock_div = 8;
+ break;
+ /* case VIDEOSIZE_352x240: */
+ /* This mode doesn't work as Windows programs it; changed to work */
+ cit_model2_Packet1(gspca_dev, 0x0014, 0x0009); /* Windows sets this to 8 */
+ cit_model2_Packet1(gspca_dev, 0x0016, 0x0003); /* Horizontal shift */
+ cit_model2_Packet1(gspca_dev, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
+ clock_div = 10;
+ break;
+ case 352: /* 352x288 */
+ cit_model2_Packet1(gspca_dev, 0x0014, 0x0003);
+ cit_model2_Packet1(gspca_dev, 0x0016, 0x0002); /* Horizontal shift */
+ cit_model2_Packet1(gspca_dev, 0x0018, 0x004a); /* Another hardware setting */
+ clock_div = 16;
+ break;
+ }
+
+ /* TESTME These are handled through controls
+ KEEP until someone can test leaving this out is ok */
+ if (0)
+ cit_model2_Packet1(gspca_dev, 0x001a, 0x005a);
+
+ /*
+ * We have our own frame rate setting varying from 0 (slowest) to 6
+ * (fastest). The camera model 2 allows frame rate in range [0..0x1F]
+ # where 0 is also the slowest setting. However for all practical
+ # reasons high settings make no sense because USB is not fast enough
+ # to support high FPS. Be aware that the picture datastream will be
+ # severely disrupted if you ask for frame rate faster than allowed
+ # for the video size - see below:
+ *
+ * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
+ * -----------------------------------------------------------------
+ * 176x144: [6..31]
+ * 320x240: [8..31]
+ * 352x240: [10..31]
+ * 352x288: [16..31] I have to raise lower threshold for stability...
+ *
+ * As usual, slower FPS provides better sensitivity.
+ */
+ cit_model2_Packet1(gspca_dev, 0x001c, clock_div);
+
+ /*
+ * This setting does not visibly affect pictures; left it here
+ * because it was present in Windows USB data stream. This function
+ * does not allow arbitrary values and apparently is a bit mask, to
+ * be activated only at appropriate time. Don't change it randomly!
+ */
+ switch (gspca_dev->width) {
+ case 176: /* 176x144 */
+ cit_model2_Packet1(gspca_dev, 0x0026, 0x00c2);
+ break;
+ case 320: /* 320x240 */
+ cit_model2_Packet1(gspca_dev, 0x0026, 0x0044);
+ break;
+ /* case VIDEOSIZE_352x240: */
+ cit_model2_Packet1(gspca_dev, 0x0026, 0x0046);
+ break;
+ case 352: /* 352x288 */
+ cit_model2_Packet1(gspca_dev, 0x0026, 0x0048);
+ break;
+ }
+
+ /* FIXME this cannot be changed while streaming, so we
+ should report a grabbed flag for this control. */
+ cit_model2_Packet1(gspca_dev, 0x0028, sd->lighting);
+ /* color balance rg2 */
+ cit_model2_Packet1(gspca_dev, 0x001e, 0x002f);
+ /* saturation */
+ cit_model2_Packet1(gspca_dev, 0x0020, 0x0034);
+ /* color balance yb */
+ cit_model2_Packet1(gspca_dev, 0x0022, 0x00a0);
+
+ /* Hardware control command */
+ cit_model2_Packet1(gspca_dev, 0x0030, 0x0004);
+
+ return 0;
+}
+
+static int cit_start_model3(struct gspca_dev *gspca_dev)
+{
+ const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+ int i, clock_div = 0;
+
+ /* HDG not in ibmcam driver, added to see if it helps with
+ auto-detecting between model3 and ibm netcamera pro */
+ cit_read_reg(gspca_dev, 0x128, 1);
+
+ cit_write_reg(gspca_dev, 0x0000, 0x0100);
+ cit_read_reg(gspca_dev, 0x0116, 0);
+ cit_write_reg(gspca_dev, 0x0060, 0x0116);
+ cit_write_reg(gspca_dev, 0x0002, 0x0112);
+ cit_write_reg(gspca_dev, 0x0000, 0x0123);
+ cit_write_reg(gspca_dev, 0x0001, 0x0117);
+ cit_write_reg(gspca_dev, 0x0040, 0x0108);
+ cit_write_reg(gspca_dev, 0x0019, 0x012c);
+ cit_write_reg(gspca_dev, 0x0060, 0x0116);
+ cit_write_reg(gspca_dev, 0x0002, 0x0115);
+ cit_write_reg(gspca_dev, 0x0003, 0x0115);
+ cit_read_reg(gspca_dev, 0x0115, 0);
+ cit_write_reg(gspca_dev, 0x000b, 0x0115);
+
+ /* TESTME HDG not in ibmcam driver, added to see if it helps with
+ auto-detecting between model3 and ibm netcamera pro */
+ if (0) {
+ cit_write_reg(gspca_dev, 0x0078, 0x012d);
+ cit_write_reg(gspca_dev, 0x0001, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0079, 0x012d);
+ cit_write_reg(gspca_dev, 0x00ff, 0x0130);
+ cit_write_reg(gspca_dev, 0xcd41, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+ cit_read_reg(gspca_dev, 0x0126, 1);
+ }
+
+ cit_model3_Packet1(gspca_dev, 0x000a, 0x0040);
+ cit_model3_Packet1(gspca_dev, 0x000b, 0x00f6);
+ cit_model3_Packet1(gspca_dev, 0x000c, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x000d, 0x0020);
+ cit_model3_Packet1(gspca_dev, 0x000e, 0x0033);
+ cit_model3_Packet1(gspca_dev, 0x000f, 0x0007);
+ cit_model3_Packet1(gspca_dev, 0x0010, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0011, 0x0070);
+ cit_model3_Packet1(gspca_dev, 0x0012, 0x0030);
+ cit_model3_Packet1(gspca_dev, 0x0013, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0014, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x0015, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x0016, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x0017, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x0018, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x001e, 0x00c3);
+ cit_model3_Packet1(gspca_dev, 0x0020, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0028, 0x0010);
+ cit_model3_Packet1(gspca_dev, 0x0029, 0x0054);
+ cit_model3_Packet1(gspca_dev, 0x002a, 0x0013);
+ cit_model3_Packet1(gspca_dev, 0x002b, 0x0007);
+ cit_model3_Packet1(gspca_dev, 0x002d, 0x0028);
+ cit_model3_Packet1(gspca_dev, 0x002e, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0031, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0032, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0033, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0034, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0035, 0x0038);
+ cit_model3_Packet1(gspca_dev, 0x003a, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x003c, 0x001e);
+ cit_model3_Packet1(gspca_dev, 0x003f, 0x000a);
+ cit_model3_Packet1(gspca_dev, 0x0041, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0046, 0x003f);
+ cit_model3_Packet1(gspca_dev, 0x0047, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0050, 0x0005);
+ cit_model3_Packet1(gspca_dev, 0x0052, 0x001a);
+ cit_model3_Packet1(gspca_dev, 0x0053, 0x0003);
+ cit_model3_Packet1(gspca_dev, 0x005a, 0x006b);
+ cit_model3_Packet1(gspca_dev, 0x005d, 0x001e);
+ cit_model3_Packet1(gspca_dev, 0x005e, 0x0030);
+ cit_model3_Packet1(gspca_dev, 0x005f, 0x0041);
+ cit_model3_Packet1(gspca_dev, 0x0064, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x0065, 0x0015);
+ cit_model3_Packet1(gspca_dev, 0x0068, 0x000f);
+ cit_model3_Packet1(gspca_dev, 0x0079, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x007a, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x007c, 0x003f);
+ cit_model3_Packet1(gspca_dev, 0x0082, 0x000f);
+ cit_model3_Packet1(gspca_dev, 0x0085, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0099, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x009b, 0x0023);
+ cit_model3_Packet1(gspca_dev, 0x009c, 0x0022);
+ cit_model3_Packet1(gspca_dev, 0x009d, 0x0096);
+ cit_model3_Packet1(gspca_dev, 0x009e, 0x0096);
+ cit_model3_Packet1(gspca_dev, 0x009f, 0x000a);
+
+ switch (gspca_dev->width) {
+ case 160:
+ cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+ cit_write_reg(gspca_dev, 0x0024, 0x010b); /* Differs everywhere */
+ cit_write_reg(gspca_dev, 0x00a9, 0x0119);
+ cit_write_reg(gspca_dev, 0x0016, 0x011b);
+ cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */
+ cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+ cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+ cit_write_reg(gspca_dev, 0x0018, 0x0102);
+ cit_write_reg(gspca_dev, 0x0004, 0x0104);
+ cit_write_reg(gspca_dev, 0x0004, 0x011a);
+ cit_write_reg(gspca_dev, 0x0028, 0x011c);
+ cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+ cit_write_reg(gspca_dev, 0x0000, 0x0118);
+ cit_write_reg(gspca_dev, 0x0000, 0x0132);
+ cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+ cit_write_reg(gspca_dev, compression, 0x0109);
+ clock_div = 3;
+ break;
+ case 320:
+ cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+ cit_write_reg(gspca_dev, 0x0028, 0x010b); /* Differs everywhere */
+ cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same */
+ cit_write_reg(gspca_dev, 0x0000, 0x011e);
+ cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+ cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+ /* 4 commands from 160x120 skipped */
+ cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+ cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+ cit_write_reg(gspca_dev, compression, 0x0109);
+ cit_write_reg(gspca_dev, 0x00d9, 0x0119);
+ cit_write_reg(gspca_dev, 0x0006, 0x011b);
+ cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+ cit_write_reg(gspca_dev, 0x0010, 0x0104);
+ cit_write_reg(gspca_dev, 0x0004, 0x011a);
+ cit_write_reg(gspca_dev, 0x003f, 0x011c);
+ cit_write_reg(gspca_dev, 0x001c, 0x0118);
+ cit_write_reg(gspca_dev, 0x0000, 0x0132);
+ clock_div = 5;
+ break;
+ case 640:
+ cit_write_reg(gspca_dev, 0x00f0, 0x0105);
+ cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+ cit_write_reg(gspca_dev, 0x0038, 0x010b); /* Differs everywhere */
+ cit_write_reg(gspca_dev, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
+ cit_write_reg(gspca_dev, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
+ cit_write_reg(gspca_dev, 0x0004, 0x011d); /* NC */
+ cit_write_reg(gspca_dev, 0x0003, 0x011e); /* Same on 160x120, 640x480 */
+ cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+ cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+ cit_write_reg(gspca_dev, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
+ cit_write_reg(gspca_dev, 0x0016, 0x0104); /* NC */
+ cit_write_reg(gspca_dev, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
+ cit_write_reg(gspca_dev, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
+ cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+ cit_write_reg(gspca_dev, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
+ cit_model3_Packet1(gspca_dev, 0x0021, 0x0001); /* Same */
+ cit_write_reg(gspca_dev, compression, 0x0109);
+ cit_write_reg(gspca_dev, 0x0040, 0x0101);
+ cit_write_reg(gspca_dev, 0x0040, 0x0103);
+ cit_write_reg(gspca_dev, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
+ clock_div = 7;
+ break;
+ }
+
+ cit_model3_Packet1(gspca_dev, 0x007e, 0x000e); /* Hue */
+ cit_model3_Packet1(gspca_dev, 0x0036, 0x0011); /* Brightness */
+ cit_model3_Packet1(gspca_dev, 0x0060, 0x0002); /* Sharpness */
+ cit_model3_Packet1(gspca_dev, 0x0061, 0x0004); /* Sharpness */
+ cit_model3_Packet1(gspca_dev, 0x0062, 0x0005); /* Sharpness */
+ cit_model3_Packet1(gspca_dev, 0x0063, 0x0014); /* Sharpness */
+ cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0); /* Red sharpness */
+ cit_model3_Packet1(gspca_dev, 0x0097, 0x0096); /* Blue sharpness */
+ cit_model3_Packet1(gspca_dev, 0x0067, 0x0001); /* Contrast */
+ cit_model3_Packet1(gspca_dev, 0x005b, 0x000c); /* Contrast */
+ cit_model3_Packet1(gspca_dev, 0x005c, 0x0016); /* Contrast */
+ cit_model3_Packet1(gspca_dev, 0x0098, 0x000b);
+ cit_model3_Packet1(gspca_dev, 0x002c, 0x0003); /* Was 1, broke 640x480 */
+ cit_model3_Packet1(gspca_dev, 0x002f, 0x002a);
+ cit_model3_Packet1(gspca_dev, 0x0030, 0x0029);
+ cit_model3_Packet1(gspca_dev, 0x0037, 0x0002);
+ cit_model3_Packet1(gspca_dev, 0x0038, 0x0059);
+ cit_model3_Packet1(gspca_dev, 0x003d, 0x002e);
+ cit_model3_Packet1(gspca_dev, 0x003e, 0x0028);
+ cit_model3_Packet1(gspca_dev, 0x0078, 0x0005);
+ cit_model3_Packet1(gspca_dev, 0x007b, 0x0011);
+ cit_model3_Packet1(gspca_dev, 0x007d, 0x004b);
+ cit_model3_Packet1(gspca_dev, 0x007f, 0x0022);
+ cit_model3_Packet1(gspca_dev, 0x0080, 0x000c);
+ cit_model3_Packet1(gspca_dev, 0x0081, 0x000b);
+ cit_model3_Packet1(gspca_dev, 0x0083, 0x00fd);
+ cit_model3_Packet1(gspca_dev, 0x0086, 0x000b);
+ cit_model3_Packet1(gspca_dev, 0x0087, 0x000b);
+ cit_model3_Packet1(gspca_dev, 0x007e, 0x000e);
+ cit_model3_Packet1(gspca_dev, 0x0096, 0x00a0); /* Red sharpness */
+ cit_model3_Packet1(gspca_dev, 0x0097, 0x0096); /* Blue sharpness */
+ cit_model3_Packet1(gspca_dev, 0x0098, 0x000b);
+
+ /* FIXME we should probably use cit_get_clock_div() here (in
+ combination with isoc negotiation using the programmable isoc size)
+ like with the IBM netcam pro). */
+ cit_write_reg(gspca_dev, clock_div, 0x0111); /* Clock Divider */
+
+ switch (gspca_dev->width) {
+ case 160:
+ cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */
+ cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */
+ cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */
+ cit_model3_Packet1(gspca_dev, 0x0040, 0x000a);
+ cit_model3_Packet1(gspca_dev, 0x0051, 0x000a);
+ break;
+ case 320:
+ cit_model3_Packet1(gspca_dev, 0x001f, 0x0000); /* Same */
+ cit_model3_Packet1(gspca_dev, 0x0039, 0x001f); /* Same */
+ cit_model3_Packet1(gspca_dev, 0x003b, 0x003c); /* Same */
+ cit_model3_Packet1(gspca_dev, 0x0040, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x0051, 0x000b);
+ break;
+ case 640:
+ cit_model3_Packet1(gspca_dev, 0x001f, 0x0002); /* !Same */
+ cit_model3_Packet1(gspca_dev, 0x0039, 0x003e); /* !Same */
+ cit_model3_Packet1(gspca_dev, 0x0040, 0x0008);
+ cit_model3_Packet1(gspca_dev, 0x0051, 0x000a);
+ break;
+ }
+
+/* if (sd->input_index) { */
+ if (rca_input) {
+ for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) {
+ if (rca_initdata[i][0])
+ cit_read_reg(gspca_dev, rca_initdata[i][2], 0);
+ else
+ cit_write_reg(gspca_dev, rca_initdata[i][1],
+ rca_initdata[i][2]);
+ }
+ }
+
+ return 0;
+}
+
+static int cit_start_model4(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ cit_write_reg(gspca_dev, 0x0000, 0x0100);
+ cit_write_reg(gspca_dev, 0x00c0, 0x0111);
+ cit_write_reg(gspca_dev, 0x00bc, 0x012c);
+ cit_write_reg(gspca_dev, 0x0080, 0x012b);
+ cit_write_reg(gspca_dev, 0x0000, 0x0108);
+ cit_write_reg(gspca_dev, 0x0001, 0x0133);
+ cit_write_reg(gspca_dev, 0x009b, 0x010f);
+ cit_write_reg(gspca_dev, 0x00bb, 0x010f);
+ cit_model4_Packet1(gspca_dev, 0x0038, 0x0000);
+ cit_model4_Packet1(gspca_dev, 0x000a, 0x005c);
+
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0004, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0000, 0x0127);
+ cit_write_reg(gspca_dev, 0x00fb, 0x012e);
+ cit_write_reg(gspca_dev, 0x0000, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+ cit_write_reg(gspca_dev, 0xd055, 0x0124);
+ cit_write_reg(gspca_dev, 0x000c, 0x0127);
+ cit_write_reg(gspca_dev, 0x0009, 0x012e);
+ cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0012, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0008, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x002a, 0x012d);
+ cit_write_reg(gspca_dev, 0x0000, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+ cit_model4_Packet1(gspca_dev, 0x0034, 0x0000);
+
+ switch (gspca_dev->width) {
+ case 128: /* 128x96 */
+ cit_write_reg(gspca_dev, 0x0070, 0x0119);
+ cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+ cit_write_reg(gspca_dev, 0x0039, 0x010a);
+ cit_write_reg(gspca_dev, 0x0001, 0x0102);
+ cit_write_reg(gspca_dev, 0x0028, 0x0103);
+ cit_write_reg(gspca_dev, 0x0000, 0x0104);
+ cit_write_reg(gspca_dev, 0x001e, 0x0105);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0016, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x000a, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0014, 0x012d);
+ cit_write_reg(gspca_dev, 0x0008, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+ cit_write_reg(gspca_dev, 0x001a, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+ cit_write_reg(gspca_dev, 0x005a, 0x012d);
+ cit_write_reg(gspca_dev, 0x9545, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+ cit_write_reg(gspca_dev, 0x0018, 0x012e);
+ cit_write_reg(gspca_dev, 0x0043, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+ cit_write_reg(gspca_dev, 0xd055, 0x0124);
+ cit_write_reg(gspca_dev, 0x001c, 0x0127);
+ cit_write_reg(gspca_dev, 0x00eb, 0x012e);
+ cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0032, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0000, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0036, 0x012d);
+ cit_write_reg(gspca_dev, 0x0008, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x001e, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0017, 0x0127);
+ cit_write_reg(gspca_dev, 0x0013, 0x012e);
+ cit_write_reg(gspca_dev, 0x0031, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x0017, 0x012d);
+ cit_write_reg(gspca_dev, 0x0078, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x0000, 0x0127);
+ cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+ sd->sof_len = 2;
+ break;
+ case 160: /* 160x120 */
+ cit_write_reg(gspca_dev, 0x0038, 0x0119);
+ cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+ cit_write_reg(gspca_dev, 0x00b9, 0x010a);
+ cit_write_reg(gspca_dev, 0x0001, 0x0102);
+ cit_write_reg(gspca_dev, 0x0028, 0x0103);
+ cit_write_reg(gspca_dev, 0x0000, 0x0104);
+ cit_write_reg(gspca_dev, 0x001e, 0x0105);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0016, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x000b, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0014, 0x012d);
+ cit_write_reg(gspca_dev, 0x0008, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+ cit_write_reg(gspca_dev, 0x001a, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+ cit_write_reg(gspca_dev, 0x005a, 0x012d);
+ cit_write_reg(gspca_dev, 0x9545, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+ cit_write_reg(gspca_dev, 0x0018, 0x012e);
+ cit_write_reg(gspca_dev, 0x0043, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+ cit_write_reg(gspca_dev, 0xd055, 0x0124);
+ cit_write_reg(gspca_dev, 0x001c, 0x0127);
+ cit_write_reg(gspca_dev, 0x00c7, 0x012e);
+ cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0032, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0025, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0036, 0x012d);
+ cit_write_reg(gspca_dev, 0x0008, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x001e, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0048, 0x0127);
+ cit_write_reg(gspca_dev, 0x0035, 0x012e);
+ cit_write_reg(gspca_dev, 0x00d0, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x0048, 0x012d);
+ cit_write_reg(gspca_dev, 0x0090, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x0001, 0x0127);
+ cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+ sd->sof_len = 2;
+ break;
+ case 176: /* 176x144 */
+ cit_write_reg(gspca_dev, 0x0038, 0x0119);
+ cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+ cit_write_reg(gspca_dev, 0x00b9, 0x010a);
+ cit_write_reg(gspca_dev, 0x0001, 0x0102);
+ cit_write_reg(gspca_dev, 0x002c, 0x0103);
+ cit_write_reg(gspca_dev, 0x0000, 0x0104);
+ cit_write_reg(gspca_dev, 0x0024, 0x0105);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0016, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0007, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0014, 0x012d);
+ cit_write_reg(gspca_dev, 0x0001, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+ cit_write_reg(gspca_dev, 0x001a, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+ cit_write_reg(gspca_dev, 0x005e, 0x012d);
+ cit_write_reg(gspca_dev, 0x9545, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+ cit_write_reg(gspca_dev, 0x0018, 0x012e);
+ cit_write_reg(gspca_dev, 0x0049, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+ cit_write_reg(gspca_dev, 0xd055, 0x0124);
+ cit_write_reg(gspca_dev, 0x001c, 0x0127);
+ cit_write_reg(gspca_dev, 0x00c7, 0x012e);
+ cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0032, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0028, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0036, 0x012d);
+ cit_write_reg(gspca_dev, 0x0008, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x001e, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0010, 0x0127);
+ cit_write_reg(gspca_dev, 0x0013, 0x012e);
+ cit_write_reg(gspca_dev, 0x002a, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x0010, 0x012d);
+ cit_write_reg(gspca_dev, 0x006d, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x0001, 0x0127);
+ cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+ /* TESTME HDG: this does not seem right
+ (it is 2 for all other resolutions) */
+ sd->sof_len = 10;
+ break;
+ case 320: /* 320x240 */
+ cit_write_reg(gspca_dev, 0x0070, 0x0119);
+ cit_write_reg(gspca_dev, 0x00d0, 0x0111);
+ cit_write_reg(gspca_dev, 0x0039, 0x010a);
+ cit_write_reg(gspca_dev, 0x0001, 0x0102);
+ cit_write_reg(gspca_dev, 0x0028, 0x0103);
+ cit_write_reg(gspca_dev, 0x0000, 0x0104);
+ cit_write_reg(gspca_dev, 0x001e, 0x0105);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0016, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x000a, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0014, 0x012d);
+ cit_write_reg(gspca_dev, 0x0008, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+ cit_write_reg(gspca_dev, 0x001a, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+ cit_write_reg(gspca_dev, 0x005a, 0x012d);
+ cit_write_reg(gspca_dev, 0x9545, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+ cit_write_reg(gspca_dev, 0x0018, 0x012e);
+ cit_write_reg(gspca_dev, 0x0043, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+ cit_write_reg(gspca_dev, 0xd055, 0x0124);
+ cit_write_reg(gspca_dev, 0x001c, 0x0127);
+ cit_write_reg(gspca_dev, 0x00eb, 0x012e);
+ cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0032, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0000, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0036, 0x012d);
+ cit_write_reg(gspca_dev, 0x0008, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x001e, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0017, 0x0127);
+ cit_write_reg(gspca_dev, 0x0013, 0x012e);
+ cit_write_reg(gspca_dev, 0x0031, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x0017, 0x012d);
+ cit_write_reg(gspca_dev, 0x0078, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x0000, 0x0127);
+ cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+ sd->sof_len = 2;
+ break;
+ case 352: /* 352x288 */
+ cit_write_reg(gspca_dev, 0x0070, 0x0119);
+ cit_write_reg(gspca_dev, 0x00c0, 0x0111);
+ cit_write_reg(gspca_dev, 0x0039, 0x010a);
+ cit_write_reg(gspca_dev, 0x0001, 0x0102);
+ cit_write_reg(gspca_dev, 0x002c, 0x0103);
+ cit_write_reg(gspca_dev, 0x0000, 0x0104);
+ cit_write_reg(gspca_dev, 0x0024, 0x0105);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0016, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0006, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0014, 0x012d);
+ cit_write_reg(gspca_dev, 0x0002, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012e);
+ cit_write_reg(gspca_dev, 0x001a, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a0a, 0x0124);
+ cit_write_reg(gspca_dev, 0x005e, 0x012d);
+ cit_write_reg(gspca_dev, 0x9545, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0127);
+ cit_write_reg(gspca_dev, 0x0018, 0x012e);
+ cit_write_reg(gspca_dev, 0x0049, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012f);
+ cit_write_reg(gspca_dev, 0xd055, 0x0124);
+ cit_write_reg(gspca_dev, 0x001c, 0x0127);
+ cit_write_reg(gspca_dev, 0x00cf, 0x012e);
+ cit_write_reg(gspca_dev, 0xaa28, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x0032, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0000, 0x0127);
+ cit_write_reg(gspca_dev, 0x00aa, 0x0130);
+ cit_write_reg(gspca_dev, 0x82a8, 0x0124);
+ cit_write_reg(gspca_dev, 0x0036, 0x012d);
+ cit_write_reg(gspca_dev, 0x0008, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0xfffa, 0x0124);
+ cit_write_reg(gspca_dev, 0x00aa, 0x012d);
+ cit_write_reg(gspca_dev, 0x001e, 0x012f);
+ cit_write_reg(gspca_dev, 0xd141, 0x0124);
+ cit_write_reg(gspca_dev, 0x0010, 0x0127);
+ cit_write_reg(gspca_dev, 0x0013, 0x012e);
+ cit_write_reg(gspca_dev, 0x0025, 0x0130);
+ cit_write_reg(gspca_dev, 0x8a28, 0x0124);
+ cit_write_reg(gspca_dev, 0x0010, 0x012d);
+ cit_write_reg(gspca_dev, 0x0048, 0x012f);
+ cit_write_reg(gspca_dev, 0xd145, 0x0124);
+ cit_write_reg(gspca_dev, 0x0000, 0x0127);
+ cit_write_reg(gspca_dev, 0xfea8, 0x0124);
+ sd->sof_len = 2;
+ break;
+ }
+
+ cit_model4_Packet1(gspca_dev, 0x0038, 0x0004);
+
+ return 0;
+}
+
+static int cit_start_ibm_netcam_pro(struct gspca_dev *gspca_dev)
+{
+ const unsigned short compression = 0; /* 0=none, 7=best frame rate */
+ int i, clock_div;
+
+ clock_div = cit_get_clock_div(gspca_dev);
+ if (clock_div < 0)
+ return clock_div;
+
+ cit_write_reg(gspca_dev, 0x0003, 0x0133);
+ cit_write_reg(gspca_dev, 0x0000, 0x0117);
+ cit_write_reg(gspca_dev, 0x0008, 0x0123);
+ cit_write_reg(gspca_dev, 0x0000, 0x0100);
+ cit_write_reg(gspca_dev, 0x0060, 0x0116);
+ /* cit_write_reg(gspca_dev, 0x0002, 0x0112); see sd_stop0 */
+ cit_write_reg(gspca_dev, 0x0000, 0x0133);
+ cit_write_reg(gspca_dev, 0x0000, 0x0123);
+ cit_write_reg(gspca_dev, 0x0001, 0x0117);
+ cit_write_reg(gspca_dev, 0x0040, 0x0108);
+ cit_write_reg(gspca_dev, 0x0019, 0x012c);
+ cit_write_reg(gspca_dev, 0x0060, 0x0116);
+ /* cit_write_reg(gspca_dev, 0x000b, 0x0115); see sd_stop0 */
+
+ cit_model3_Packet1(gspca_dev, 0x0049, 0x0000);
+
+ cit_write_reg(gspca_dev, 0x0000, 0x0101); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x003a, 0x0102); /* Hstart */
+ cit_write_reg(gspca_dev, 0x00a0, 0x0103); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x0078, 0x0105); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x0000, 0x010a); /* Same */
+ cit_write_reg(gspca_dev, 0x0002, 0x011d); /* Same on 160x120, 320x240 */
+ cit_write_reg(gspca_dev, 0x0000, 0x0129); /* Same */
+ cit_write_reg(gspca_dev, 0x00fc, 0x012b); /* Same */
+ cit_write_reg(gspca_dev, 0x0022, 0x012a); /* Same */
+
+ switch (gspca_dev->width) {
+ case 160: /* 160x120 */
+ cit_write_reg(gspca_dev, 0x0024, 0x010b);
+ cit_write_reg(gspca_dev, 0x0089, 0x0119);
+ cit_write_reg(gspca_dev, 0x000a, 0x011b);
+ cit_write_reg(gspca_dev, 0x0003, 0x011e);
+ cit_write_reg(gspca_dev, 0x0007, 0x0104);
+ cit_write_reg(gspca_dev, 0x0009, 0x011a);
+ cit_write_reg(gspca_dev, 0x008b, 0x011c);
+ cit_write_reg(gspca_dev, 0x0008, 0x0118);
+ cit_write_reg(gspca_dev, 0x0000, 0x0132);
+ break;
+ case 320: /* 320x240 */
+ cit_write_reg(gspca_dev, 0x0028, 0x010b);
+ cit_write_reg(gspca_dev, 0x00d9, 0x0119);
+ cit_write_reg(gspca_dev, 0x0006, 0x011b);
+ cit_write_reg(gspca_dev, 0x0000, 0x011e);
+ cit_write_reg(gspca_dev, 0x000e, 0x0104);
+ cit_write_reg(gspca_dev, 0x0004, 0x011a);
+ cit_write_reg(gspca_dev, 0x003f, 0x011c);
+ cit_write_reg(gspca_dev, 0x000c, 0x0118);
+ cit_write_reg(gspca_dev, 0x0000, 0x0132);
+ break;
+ }
+
+ cit_model3_Packet1(gspca_dev, 0x0019, 0x0031);
+ cit_model3_Packet1(gspca_dev, 0x001a, 0x0003);
+ cit_model3_Packet1(gspca_dev, 0x001b, 0x0038);
+ cit_model3_Packet1(gspca_dev, 0x001c, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0024, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x0027, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x002a, 0x0004);
+ cit_model3_Packet1(gspca_dev, 0x0035, 0x000b);
+ cit_model3_Packet1(gspca_dev, 0x003f, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x0044, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x0054, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00c4, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00e7, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x00e9, 0x0001);
+ cit_model3_Packet1(gspca_dev, 0x00ee, 0x0000);
+ cit_model3_Packet1(gspca_dev, 0x00f3, 0x00c0);
+
+ cit_write_reg(gspca_dev, compression, 0x0109);
+ cit_write_reg(gspca_dev, clock_div, 0x0111);
+
+/* if (sd->input_index) { */
+ if (rca_input) {
+ for (i = 0; i < ARRAY_SIZE(rca_initdata); i++) {
+ if (rca_initdata[i][0])
+ cit_read_reg(gspca_dev, rca_initdata[i][2], 0);
+ else
+ cit_write_reg(gspca_dev, rca_initdata[i][1],
+ rca_initdata[i][2]);
+ }
+ }
+
+ return 0;
+}
+
+/* -- start the camera -- */
+static int sd_start(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ int packet_size;
+
+ packet_size = cit_get_packet_size(gspca_dev);
+ if (packet_size < 0)
+ return packet_size;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ cit_start_model0(gspca_dev);
+ break;
+ case CIT_MODEL1:
+ cit_start_model1(gspca_dev);
+ break;
+ case CIT_MODEL2:
+ cit_start_model2(gspca_dev);
+ break;
+ case CIT_MODEL3:
+ cit_start_model3(gspca_dev);
+ break;
+ case CIT_MODEL4:
+ cit_start_model4(gspca_dev);
+ break;
+ case CIT_IBM_NETCAM_PRO:
+ cit_start_ibm_netcam_pro(gspca_dev);
+ break;
+ }
+
+ cit_set_brightness(gspca_dev);
+ cit_set_contrast(gspca_dev);
+ cit_set_hue(gspca_dev);
+ cit_set_sharpness(gspca_dev);
+ cit_set_lighting(gspca_dev);
+ cit_set_hflip(gspca_dev);
+
+ /* Program max isoc packet size */
+ cit_write_reg(gspca_dev, packet_size >> 8, 0x0106);
+ cit_write_reg(gspca_dev, packet_size & 0xff, 0x0107);
+
+ cit_restart_stream(gspca_dev);
+
+ return 0;
+}
+
+static int sd_isoc_init(struct gspca_dev *gspca_dev)
+{
+ struct usb_host_interface *alt;
+ int max_packet_size;
+
+ switch (gspca_dev->width) {
+ case 160:
+ max_packet_size = 450;
+ break;
+ case 176:
+ max_packet_size = 600;
+ break;
+ default:
+ max_packet_size = 1022;
+ break;
+ }
+
+ /* Start isoc bandwidth "negotiation" at max isoc bandwidth */
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(max_packet_size);
+
+ return 0;
+}
+
+static int sd_isoc_nego(struct gspca_dev *gspca_dev)
+{
+ int ret, packet_size, min_packet_size;
+ struct usb_host_interface *alt;
+
+ switch (gspca_dev->width) {
+ case 160:
+ min_packet_size = 200;
+ break;
+ case 176:
+ min_packet_size = 266;
+ break;
+ default:
+ min_packet_size = 400;
+ break;
+ }
+
+ alt = &gspca_dev->dev->config->intf_cache[0]->altsetting[1];
+ packet_size = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
+ if (packet_size <= min_packet_size)
+ return -EIO;
+
+ packet_size -= 100;
+ if (packet_size < min_packet_size)
+ packet_size = min_packet_size;
+ alt->endpoint[0].desc.wMaxPacketSize = cpu_to_le16(packet_size);
+
+ ret = usb_set_interface(gspca_dev->dev, gspca_dev->iface, 1);
+ if (ret < 0)
+ err("set alt 1 err %d", ret);
+
+ return ret;
+}
+
+static void sd_stopN(struct gspca_dev *gspca_dev)
+{
+ cit_write_reg(gspca_dev, 0x0000, 0x010c);
+}
+
+static void sd_stop0(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ /* We cannot use gspca_dev->present here as that is not set when
+ sd_init gets called and we get called from sd_init */
+ if (!gspca_dev->dev)
+ return;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ /* HDG windows does this, but it causes the cams autogain to
+ restart from a gain of 0, which does not look good when
+ changing resolutions. */
+ /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */
+ cit_write_reg(gspca_dev, 0x00c0, 0x0100); /* LED Off */
+ break;
+ case CIT_MODEL1:
+ cit_send_FF_04_02(gspca_dev);
+ cit_read_reg(gspca_dev, 0x0100, 0);
+ cit_write_reg(gspca_dev, 0x81, 0x0100); /* LED Off */
+ break;
+ case CIT_MODEL2:
+ case CIT_MODEL4:
+ cit_model2_Packet1(gspca_dev, 0x0030, 0x0004);
+
+ cit_write_reg(gspca_dev, 0x0080, 0x0100); /* LED Off */
+ cit_write_reg(gspca_dev, 0x0020, 0x0111);
+ cit_write_reg(gspca_dev, 0x00a0, 0x0111);
+
+ cit_model2_Packet1(gspca_dev, 0x0030, 0x0002);
+
+ cit_write_reg(gspca_dev, 0x0020, 0x0111);
+ cit_write_reg(gspca_dev, 0x0000, 0x0112);
+ break;
+ case CIT_MODEL3:
+ cit_write_reg(gspca_dev, 0x0006, 0x012c);
+ cit_model3_Packet1(gspca_dev, 0x0046, 0x0000);
+ cit_read_reg(gspca_dev, 0x0116, 0);
+ cit_write_reg(gspca_dev, 0x0064, 0x0116);
+ cit_read_reg(gspca_dev, 0x0115, 0);
+ cit_write_reg(gspca_dev, 0x0003, 0x0115);
+ cit_write_reg(gspca_dev, 0x0008, 0x0123);
+ cit_write_reg(gspca_dev, 0x0000, 0x0117);
+ cit_write_reg(gspca_dev, 0x0000, 0x0112);
+ cit_write_reg(gspca_dev, 0x0080, 0x0100);
+ break;
+ case CIT_IBM_NETCAM_PRO:
+ cit_model3_Packet1(gspca_dev, 0x0049, 0x00ff);
+ cit_write_reg(gspca_dev, 0x0006, 0x012c);
+ cit_write_reg(gspca_dev, 0x0000, 0x0116);
+ /* HDG windows does this, but I cannot get the camera
+ to restart with this without redoing the entire init
+ sequence which makes switching modes really slow */
+ /* cit_write_reg(gspca_dev, 0x0006, 0x0115); */
+ cit_write_reg(gspca_dev, 0x0008, 0x0123);
+ cit_write_reg(gspca_dev, 0x0000, 0x0117);
+ cit_write_reg(gspca_dev, 0x0003, 0x0133);
+ cit_write_reg(gspca_dev, 0x0000, 0x0111);
+ /* HDG windows does this, but I get a green picture when
+ restarting the stream after this */
+ /* cit_write_reg(gspca_dev, 0x0000, 0x0112); */
+ cit_write_reg(gspca_dev, 0x00c0, 0x0100);
+ break;
+ }
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ /* If the last button state is pressed, release it now! */
+ if (sd->button_state) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA, 0);
+ input_sync(gspca_dev->input_dev);
+ sd->button_state = 0;
+ }
+#endif
+}
+
+static u8 *cit_find_sof(struct gspca_dev *gspca_dev, u8 *data, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ u8 byte3 = 0, byte4 = 0;
+ int i;
+
+ switch (sd->model) {
+ case CIT_MODEL0:
+ case CIT_MODEL1:
+ case CIT_MODEL3:
+ case CIT_IBM_NETCAM_PRO:
+ switch (gspca_dev->width) {
+ case 160: /* 160x120 */
+ byte3 = 0x02;
+ byte4 = 0x0a;
+ break;
+ case 176: /* 176x144 */
+ byte3 = 0x02;
+ byte4 = 0x0e;
+ break;
+ case 320: /* 320x240 */
+ byte3 = 0x02;
+ byte4 = 0x08;
+ break;
+ case 352: /* 352x288 */
+ byte3 = 0x02;
+ byte4 = 0x00;
+ break;
+ case 640:
+ byte3 = 0x03;
+ byte4 = 0x08;
+ break;
+ }
+
+ /* These have a different byte3 */
+ if (sd->model <= CIT_MODEL1)
+ byte3 = 0x00;
+
+ for (i = 0; i < len; i++) {
+ /* For this model the SOF always starts at offset 0
+ so no need to search the entire frame */
+ if (sd->model == CIT_MODEL0 && sd->sof_read != i)
+ break;
+
+ switch (sd->sof_read) {
+ case 0:
+ if (data[i] == 0x00)
+ sd->sof_read++;
+ break;
+ case 1:
+ if (data[i] == 0xff)
+ sd->sof_read++;
+ else if (data[i] == 0x00)
+ sd->sof_read = 1;
+ else
+ sd->sof_read = 0;
+ break;
+ case 2:
+ if (data[i] == byte3)
+ sd->sof_read++;
+ else if (data[i] == 0x00)
+ sd->sof_read = 1;
+ else
+ sd->sof_read = 0;
+ break;
+ case 3:
+ if (data[i] == byte4) {
+ sd->sof_read = 0;
+ return data + i + (sd->sof_len - 3);
+ }
+ if (byte3 == 0x00 && data[i] == 0xff)
+ sd->sof_read = 2;
+ else if (data[i] == 0x00)
+ sd->sof_read = 1;
+ else
+ sd->sof_read = 0;
+ break;
+ }
+ }
+ break;
+ case CIT_MODEL2:
+ case CIT_MODEL4:
+ /* TESTME we need to find a longer sof signature to avoid
+ false positives */
+ for (i = 0; i < len; i++) {
+ switch (sd->sof_read) {
+ case 0:
+ if (data[i] == 0x00)
+ sd->sof_read++;
+ break;
+ case 1:
+ sd->sof_read = 0;
+ if (data[i] == 0xff) {
+ if (i >= 4)
+ PDEBUG(D_FRAM,
+ "header found at offset: %d: %02x %02x 00 %02x %02x %02x\n",
+ i - 1,
+ data[i - 4],
+ data[i - 3],
+ data[i],
+ data[i + 1],
+ data[i + 2]);
+ else
+ PDEBUG(D_FRAM,
+ "header found at offset: %d: 00 %02x %02x %02x\n",
+ i - 1,
+ data[i],
+ data[i + 1],
+ data[i + 2]);
+ return data + i + (sd->sof_len - 1);
+ }
+ break;
+ }
+ }
+ break;
+ }
+ return NULL;
+}
+
+static void sd_pkt_scan(struct gspca_dev *gspca_dev,
+ u8 *data, int len)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+ unsigned char *sof;
+
+ sof = cit_find_sof(gspca_dev, data, len);
+ if (sof) {
+ int n;
+
+ /* finish decoding current frame */
+ n = sof - data;
+ if (n > sd->sof_len)
+ n -= sd->sof_len;
+ else
+ n = 0;
+ gspca_frame_add(gspca_dev, LAST_PACKET,
+ data, n);
+ gspca_frame_add(gspca_dev, FIRST_PACKET, NULL, 0);
+ len -= sof - data;
+ data = sof;
+ }
+
+ gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
+}
+
+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) {
+ if (sd->stop_on_control_change)
+ sd_stopN(gspca_dev);
+ cit_set_brightness(gspca_dev);
+ if (sd->stop_on_control_change)
+ cit_restart_stream(gspca_dev);
+ }
+
+ return 0;
+}
+
+static int sd_getbrightness(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->brightness;
+
+ return 0;
+}
+
+static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->contrast = val;
+ if (gspca_dev->streaming) {
+ if (sd->stop_on_control_change)
+ sd_stopN(gspca_dev);
+ cit_set_contrast(gspca_dev);
+ if (sd->stop_on_control_change)
+ cit_restart_stream(gspca_dev);
+ }
+
+ return 0;
+}
+
+static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->contrast;
+
+ return 0;
+}
+
+static int sd_sethue(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hue = val;
+ if (gspca_dev->streaming) {
+ if (sd->stop_on_control_change)
+ sd_stopN(gspca_dev);
+ cit_set_hue(gspca_dev);
+ if (sd->stop_on_control_change)
+ cit_restart_stream(gspca_dev);
+ }
+ return 0;
+}
+
+static int sd_gethue(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->hue;
+
+ 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) {
+ if (sd->stop_on_control_change)
+ sd_stopN(gspca_dev);
+ cit_set_sharpness(gspca_dev);
+ if (sd->stop_on_control_change)
+ cit_restart_stream(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_setlighting(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->lighting = val;
+ if (gspca_dev->streaming) {
+ if (sd->stop_on_control_change)
+ sd_stopN(gspca_dev);
+ cit_set_lighting(gspca_dev);
+ if (sd->stop_on_control_change)
+ cit_restart_stream(gspca_dev);
+ }
+ return 0;
+}
+
+static int sd_getlighting(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->lighting;
+
+ return 0;
+}
+
+static int sd_sethflip(struct gspca_dev *gspca_dev, __s32 val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ sd->hflip = val;
+ if (gspca_dev->streaming) {
+ if (sd->stop_on_control_change)
+ sd_stopN(gspca_dev);
+ cit_set_hflip(gspca_dev);
+ if (sd->stop_on_control_change)
+ cit_restart_stream(gspca_dev);
+ }
+ return 0;
+}
+
+static int sd_gethflip(struct gspca_dev *gspca_dev, __s32 *val)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
+
+ *val = sd->hflip;
+
+ return 0;
+}
+
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+static void cit_check_button(struct gspca_dev *gspca_dev)
+{
+ int new_button_state;
+ struct sd *sd = (struct sd *)gspca_dev;
+
+ switch (sd->model) {
+ case CIT_MODEL3:
+ case CIT_IBM_NETCAM_PRO:
+ break;
+ default: /* TEST ME unknown if this works on other models too */
+ return;
+ }
+
+ /* Read the button state */
+ cit_read_reg(gspca_dev, 0x0113, 0);
+ new_button_state = !gspca_dev->usb_buf[0];
+
+ /* Tell the cam we've seen the button press, notice that this
+ is a nop (iow the cam keeps reporting pressed) until the
+ button is actually released. */
+ if (new_button_state)
+ cit_write_reg(gspca_dev, 0x01, 0x0113);
+
+ if (sd->button_state != new_button_state) {
+ input_report_key(gspca_dev->input_dev, KEY_CAMERA,
+ new_button_state);
+ input_sync(gspca_dev->input_dev);
+ sd->button_state = new_button_state;
+ }
+}
+#endif
+
+/* sub-driver description */
+static const struct sd_desc sd_desc = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ .dq_callback = cit_check_button,
+ .other_input = 1,
+#endif
+};
+
+static const struct sd_desc sd_desc_isoc_nego = {
+ .name = MODULE_NAME,
+ .ctrls = sd_ctrls,
+ .nctrls = ARRAY_SIZE(sd_ctrls),
+ .config = sd_config,
+ .init = sd_init,
+ .start = sd_start,
+ .isoc_init = sd_isoc_init,
+ .isoc_nego = sd_isoc_nego,
+ .stopN = sd_stopN,
+ .stop0 = sd_stop0,
+ .pkt_scan = sd_pkt_scan,
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
+ .dq_callback = cit_check_button,
+ .other_input = 1,
+#endif
+};
+
+/* -- module initialisation -- */
+static const struct usb_device_id device_table[] = {
+ { USB_DEVICE_VER(0x0545, 0x8080, 0x0001, 0x0001), .driver_info = CIT_MODEL0 },
+ { USB_DEVICE_VER(0x0545, 0x8080, 0x0002, 0x0002), .driver_info = CIT_MODEL1 },
+ { USB_DEVICE_VER(0x0545, 0x8080, 0x030a, 0x030a), .driver_info = CIT_MODEL2 },
+ { USB_DEVICE_VER(0x0545, 0x8080, 0x0301, 0x0301), .driver_info = CIT_MODEL3 },
+ { USB_DEVICE_VER(0x0545, 0x8002, 0x030a, 0x030a), .driver_info = CIT_MODEL4 },
+ { USB_DEVICE_VER(0x0545, 0x800c, 0x030a, 0x030a), .driver_info = CIT_MODEL2 },
+ { USB_DEVICE_VER(0x0545, 0x800d, 0x030a, 0x030a), .driver_info = CIT_MODEL4 },
+ {}
+};
+MODULE_DEVICE_TABLE(usb, device_table);
+
+/* -- device connect -- */
+static int sd_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ const struct sd_desc *desc = &sd_desc;
+
+ switch (id->driver_info) {
+ case CIT_MODEL0:
+ case CIT_MODEL1:
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 2)
+ return -ENODEV;
+ break;
+ case CIT_MODEL2:
+ case CIT_MODEL4:
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
+ break;
+ case CIT_MODEL3:
+ if (intf->cur_altsetting->desc.bInterfaceNumber != 0)
+ return -ENODEV;
+ /* FIXME this likely applies to all model3 cams and probably
+ to other models too. */
+ if (ibm_netcam_pro)
+ desc = &sd_desc_isoc_nego;
+ break;
+ }
+
+ return gspca_dev_probe2(intf, id, desc, sizeof(struct sd), THIS_MODULE);
+}
+
+static struct usb_driver sd_driver = {
+ .name = MODULE_NAME,
+ .id_table = device_table,
+ .probe = sd_probe,
+ .disconnect = gspca_disconnect,
+#ifdef CONFIG_PM
+ .suspend = gspca_suspend,
+ .resume = gspca_resume,
+#endif
+};
+
+/* -- module insert / remove -- */
+static int __init sd_mod_init(void)
+{
+ return usb_register(&sd_driver);
+}
+static void __exit sd_mod_exit(void)
+{
+ usb_deregister(&sd_driver);
+}
+
+module_init(sd_mod_init);
+module_exit(sd_mod_exit);
diff --git a/drivers/media/video/gspca/zc3xx.c b/drivers/media/video/gspca/zc3xx.c
index d02aa5c8472a..865216e9362c 100644
--- a/drivers/media/video/gspca/zc3xx.c
+++ b/drivers/media/video/gspca/zc3xx.c
@@ -22,7 +22,6 @@
#define MODULE_NAME "zc3xx"
#include <linux/input.h>
-#include <linux/slab.h>
#include "gspca.h"
#include "jpeg.h"
@@ -36,62 +35,81 @@ static int force_sensor = -1;
#define QUANT_VAL 1 /* quantization table */
#include "zc3xx-reg.h"
+/* controls */
+enum e_ctrl {
+ BRIGHTNESS,
+ CONTRAST,
+ GAMMA,
+ AUTOGAIN,
+ LIGHTFREQ,
+ SHARPNESS,
+ NCTRLS /* number of controls */
+};
+
/* specific webcam descriptor */
struct sd {
struct gspca_dev gspca_dev; /* !! must be the first item */
- u8 contrast;
- u8 gamma;
- u8 autogain;
- u8 lightfreq;
- u8 sharpness;
+ struct gspca_ctrl ctrls[NCTRLS];
+
u8 quality; /* image quality */
-#define QUALITY_MIN 40
-#define QUALITY_MAX 60
-#define QUALITY_DEF 50
+#define QUALITY_MIN 50
+#define QUALITY_MAX 80
+#define QUALITY_DEF 70
+ u8 bridge;
u8 sensor; /* Type of image sensor chip */
-/* !! values used in different tables */
-#define SENSOR_ADCM2700 0
-#define SENSOR_CS2102 1
-#define SENSOR_CS2102K 2
-#define SENSOR_GC0305 3
-#define SENSOR_HDCS2020b 4
-#define SENSOR_HV7131B 5
-#define SENSOR_HV7131C 6
-#define SENSOR_ICM105A 7
-#define SENSOR_MC501CB 8
-#define SENSOR_MI0360SOC 9
-#define SENSOR_OV7620 10
-/*#define SENSOR_OV7648 10 - same values */
-#define SENSOR_OV7630C 11
-#define SENSOR_PAS106 12
-#define SENSOR_PAS202B 13
-#define SENSOR_PB0330 14 /* (MI0360) */
-#define SENSOR_PO2030 15
-#define SENSOR_TAS5130CK 16
-#define SENSOR_TAS5130CXX 17
-#define SENSOR_TAS5130C_VF0250 18
-#define SENSOR_MAX 19
- unsigned short chip_revision;
-
- u8 *jpeg_hdr;
+ u16 chip_revision;
+
+ u8 jpeg_hdr[JPEG_HDR_SZ];
+};
+enum bridges {
+ BRIDGE_ZC301,
+ BRIDGE_ZC303,
+};
+enum sensors {
+ SENSOR_ADCM2700,
+ SENSOR_CS2102,
+ SENSOR_CS2102K,
+ SENSOR_GC0303,
+ SENSOR_GC0305,
+ SENSOR_HDCS2020b,
+ SENSOR_HV7131B,
+ SENSOR_HV7131R,
+ SENSOR_ICM105A,
+ SENSOR_MC501CB,
+ SENSOR_MT9V111_1, /* (mi360soc) zc301 */
+ SENSOR_MT9V111_3, /* (mi360soc) zc303 */
+ SENSOR_OV7620, /* OV7648 - same values */
+ SENSOR_OV7630C,
+ SENSOR_PAS106,
+ SENSOR_PAS202B,
+ SENSOR_PB0330,
+ SENSOR_PO2030,
+ SENSOR_TAS5130C,
+ SENSOR_MAX
};
/* V4L2 controls supported by the driver */
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val);
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val);
-static int sd_getgamma(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 const struct ctrl sd_ctrls[] = {
- {
+static void setcontrast(struct gspca_dev *gspca_dev);
+static void setautogain(struct gspca_dev *gspca_dev);
+static void setlightfreq(struct gspca_dev *gspca_dev);
+static void setsharpness(struct gspca_dev *gspca_dev);
+
+static const struct ctrl sd_ctrls[NCTRLS] = {
+[BRIGHTNESS] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128,
+ },
+ .set_control = setcontrast
+ },
+[CONTRAST] = {
{
.id = V4L2_CID_CONTRAST,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -99,13 +117,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 255,
.step = 1,
-#define CONTRAST_DEF 128
- .default_value = CONTRAST_DEF,
+ .default_value = 128,
},
- .set = sd_setcontrast,
- .get = sd_getcontrast,
+ .set_control = setcontrast
},
- {
+[GAMMA] = {
{
.id = V4L2_CID_GAMMA,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -115,10 +131,9 @@ static const struct ctrl sd_ctrls[] = {
.step = 1,
.default_value = 4,
},
- .set = sd_setgamma,
- .get = sd_getgamma,
+ .set_control = setcontrast
},
- {
+[AUTOGAIN] = {
{
.id = V4L2_CID_AUTOGAIN,
.type = V4L2_CTRL_TYPE_BOOLEAN,
@@ -126,14 +141,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 1,
.step = 1,
-#define AUTOGAIN_DEF 1
- .default_value = AUTOGAIN_DEF,
+ .default_value = 1,
},
- .set = sd_setautogain,
- .get = sd_getautogain,
+ .set_control = setautogain
},
-#define LIGHTFREQ_IDX 3
- {
+[LIGHTFREQ] = {
{
.id = V4L2_CID_POWER_LINE_FREQUENCY,
.type = V4L2_CTRL_TYPE_MENU,
@@ -141,13 +153,11 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 2, /* 0: 0, 1: 50Hz, 2:60Hz */
.step = 1,
-#define FREQ_DEF 0
- .default_value = FREQ_DEF,
+ .default_value = 0,
},
- .set = sd_setfreq,
- .get = sd_getfreq,
+ .set_control = setlightfreq
},
- {
+[SHARPNESS] = {
{
.id = V4L2_CID_SHARPNESS,
.type = V4L2_CTRL_TYPE_INTEGER,
@@ -155,11 +165,9 @@ static const struct ctrl sd_ctrls[] = {
.minimum = 0,
.maximum = 3,
.step = 1,
-#define SHARPNESS_DEF 2
- .default_value = SHARPNESS_DEF,
+ .default_value = 2,
},
- .set = sd_setsharpness,
- .get = sd_getsharpness,
+ .set_control = setsharpness
},
};
@@ -2058,6 +2066,7 @@ static const struct usb_action hv7131b_NoFlikerScale[] = { /* 320x240 */
{}
};
+/* from lPEPI264v.inf (hv7131b!) */
static const struct usb_action hv7131r_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
@@ -2065,8 +2074,8 @@ static const struct usb_action hv7131r_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
- {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
@@ -2079,6 +2088,8 @@ static const struct usb_action hv7131r_InitialScale[] = {
{0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xdd, 0x00, 0x0200},
{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xaa, 0x01, 0x000c},
{0xaa, 0x11, 0x0000},
@@ -2087,10 +2098,10 @@ static const struct usb_action hv7131r_InitialScale[] = {
{0xaa, 0x15, 0x00e8},
{0xaa, 0x16, 0x0002},
{0xaa, 0x17, 0x0088},
-
+ {0xaa, 0x30, 0x000b},
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
- {0xa0, 0x89, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET},
{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},
{0xa0, 0x00, 0x01ad},
{0xa0, 0xc0, 0x019b},
@@ -2100,96 +2111,44 @@ static const struct usb_action hv7131r_InitialScale[] = {
{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
- {0xa1, 0x01, 0x0002},
- {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
- {0xa1, 0x01, 0x0091},
- {0xa1, 0x01, 0x0095},
- {0xa1, 0x01, 0x0096},
-
- {0xa1, 0x01, 0x0008},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
- {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
- {0xa1, 0x01, 0x01c8},
- {0xa1, 0x01, 0x01c9},
- {0xa1, 0x01, 0x01ca},
- {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
-
- {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */
- {0xa0, 0xf0, ZC3XX_R10B_RGB01},
- {0xa0, 0xf0, ZC3XX_R10C_RGB02},
- {0xa0, 0xf0, ZC3XX_R10D_RGB10},
- {0xa0, 0x60, ZC3XX_R10E_RGB11},
- {0xa0, 0xf0, ZC3XX_R10F_RGB12},
- {0xa0, 0xf0, ZC3XX_R110_RGB20},
- {0xa0, 0xf0, ZC3XX_R111_RGB21},
- {0xa0, 0x60, ZC3XX_R112_RGB22},
- {0xa1, 0x01, 0x0180},
- {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
- {0xaa, 0x25, 0x0007},
- {0xaa, 0x26, 0x0053},
- {0xaa, 0x27, 0x0000},
-
- {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */
- {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 9b */
- {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 80 */
- {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
- {0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID},
- {0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW},
- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
- {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
- {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
- {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
- {0xa0, 0x13, ZC3XX_R1AA_DIGITALGAINSTEP},
- {0xa1, 0x01, 0x001d},
- {0xa1, 0x01, 0x001e},
- {0xa1, 0x01, 0x001f},
- {0xa1, 0x01, 0x0020},
- {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa1, 0x01, 0x0180},
- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
{}
};
-
static const struct usb_action hv7131r_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
-
- {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT}, /* diff */
+ {0xa0, 0x00, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT},
{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
{0xa0, 0x77, ZC3XX_R101_SENSORCORRECTION},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
-
- {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
-
+ {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
{0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
{0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
- {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW}, /* 1e0 */
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
{0xa0, 0x01, ZC3XX_R09B_WINHEIGHTHIGH},
- {0xa0, 0xe8, ZC3XX_R09C_WINHEIGHTLOW},
+ {0xa0, 0xe6, ZC3XX_R09C_WINHEIGHTLOW},
{0xa0, 0x02, ZC3XX_R09D_WINWIDTHHIGH},
- {0xa0, 0x88, ZC3XX_R09E_WINWIDTHLOW},
+ {0xa0, 0x86, ZC3XX_R09E_WINWIDTHLOW},
{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xdd, 0x00, 0x0200},
{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xaa, 0x01, 0x000c},
{0xaa, 0x11, 0x0000},
{0xaa, 0x13, 0x0000},
{0xaa, 0x14, 0x0001},
- {0xaa, 0x15, 0x00e8},
+ {0xaa, 0x15, 0x00e6},
{0xaa, 0x16, 0x0002},
- {0xaa, 0x17, 0x0088},
-
- {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00 */
-
+ {0xaa, 0x17, 0x0086},
+ {0xaa, 0x30, 0x000b},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
- {0xa0, 0x89, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x78, ZC3XX_R18D_YTARGET},
{0xa0, 0x50, ZC3XX_R1A8_DIGITALGAIN},
{0xa0, 0x00, 0x01ad},
{0xa0, 0xc0, 0x019b},
@@ -2199,58 +2158,114 @@ static const struct usb_action hv7131r_Initial[] = {
{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
- {0xa1, 0x01, 0x0002},
- {0xa0, 0x00, ZC3XX_R092_I2CADDRESSSELECT},
- /* read the i2c chips ident */
- {0xa0, 0x02, ZC3XX_R090_I2CCOMMAND},
- {0xa1, 0x01, 0x0091},
- {0xa1, 0x01, 0x0095},
- {0xa1, 0x01, 0x0096},
-
- {0xa1, 0x01, 0x0008},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
- {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
- {0xa1, 0x01, 0x01c8},
- {0xa1, 0x01, 0x01c9},
- {0xa1, 0x01, 0x01ca},
- {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
-
- {0xa0, 0x60, ZC3XX_R10A_RGB00}, /* matrix */
- {0xa0, 0xf0, ZC3XX_R10B_RGB01},
- {0xa0, 0xf0, ZC3XX_R10C_RGB02},
- {0xa0, 0xf0, ZC3XX_R10D_RGB10},
- {0xa0, 0x60, ZC3XX_R10E_RGB11},
- {0xa0, 0xf0, ZC3XX_R10F_RGB12},
- {0xa0, 0xf0, ZC3XX_R110_RGB20},
- {0xa0, 0xf0, ZC3XX_R111_RGB21},
- {0xa0, 0x60, ZC3XX_R112_RGB22},
- {0xa1, 0x01, 0x0180},
- {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action hv7131r_50HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
- {0xaa, 0x25, 0x0007},
- {0xaa, 0x26, 0x0053},
- {0xaa, 0x27, 0x0000},
-
- {0xa0, 0x10, ZC3XX_R190_EXPOSURELIMITHIGH}, /* 2f */
- {0xa0, 0x04, ZC3XX_R191_EXPOSURELIMITMID}, /* 9b */
- {0xa0, 0x60, ZC3XX_R192_EXPOSURELIMITLOW}, /* 80 */
-
+ {0xa0, 0x06, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x68, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xa0, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0xea, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x60, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x18, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x00, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x08, ZC3XX_R020_HSYNC_3},
+ {}
+};
+static const struct usb_action hv7131r_50HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x0c, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0xd1, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x40, ZC3XX_R192_EXPOSURELIMITLOW},
{0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
{0xa0, 0xd4, ZC3XX_R196_ANTIFLICKERMID},
{0xa0, 0xc0, ZC3XX_R197_ANTIFLICKERLOW},
-
- {0xa0, 0x10, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x18, ZC3XX_R18C_AEFREEZE},
{0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
- {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
{0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
- {0xa0, 0x13, ZC3XX_R1AA_DIGITALGAINSTEP},
- {0xa1, 0x01, 0x001d},
- {0xa1, 0x01, 0x001e},
- {0xa1, 0x01, 0x001f},
- {0xa1, 0x01, 0x0020},
- {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa1, 0x01, 0x0180},
- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x00, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x08, ZC3XX_R020_HSYNC_3},
+ {}
+};
+static const struct usb_action hv7131r_60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x06, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x1a, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x80, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0xc3, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x50, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x18, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x00, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x08, ZC3XX_R020_HSYNC_3},
+ {}
+};
+static const struct usb_action hv7131r_60HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x0c, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x35, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x01, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x86, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0xa0, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x18, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x20, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x10, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x00, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x08, ZC3XX_R020_HSYNC_3},
+ {}
+};
+static const struct usb_action hv7131r_NoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x02, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x58, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x00, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x08, ZC3XX_R020_HSYNC_3},
+ {}
+};
+static const struct usb_action hv7131r_NoFlikerScale[] = {
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xa0, 0x2f, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0xf8, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x00, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x04, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0xb0, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0c, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x18, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x00, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xd0, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x00, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0x08, ZC3XX_R020_HSYNC_3},
{}
};
@@ -2923,7 +2938,7 @@ static const struct usb_action mc501cb_Initial[] = {
{}
};
-static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */
+static const struct usb_action mc501cb_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc */
{0xa0, 0x10, ZC3XX_R002_CLOCKSELECT}, /* 00,02,10,cc */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc */
@@ -3334,7 +3349,7 @@ static const struct usb_action ov7620_NoFliker[] = {
{0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID}, /* 01,96,00,cc */
{0xa0, 0x01, ZC3XX_R197_ANTIFLICKERLOW}, /* 01,97,01,cc */
/* {0xa0, 0x44, ZC3XX_R002_CLOCKSELECT}, * 00,02,44,cc
- - if mode1 (320x240) */
+ * if mode1 (320x240) */
/* ?? was
{0xa0, 0x00, 0x0039}, * 00,00,00,dd *
{0xa1, 0x01, 0x0037}, */
@@ -3423,7 +3438,6 @@ static const struct usb_action ov7630c_InitialScale[] = {
{0xa0, 0xf8, ZC3XX_R110_RGB20},
{0xa0, 0xf8, ZC3XX_R111_RGB21},
{0xa0, 0x50, ZC3XX_R112_RGB22},
-/* 0x03, */
{0xa1, 0x01, 0x0008},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING}, /* clock ? */
{0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
@@ -3702,8 +3716,7 @@ static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */
{0xaa, 0x0d, 0x0000},
{0xaa, 0x0e, 0x0002},
{0xaa, 0x14, 0x0081},
-
-/* Other registors */
+/* Other registers */
{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
/* Frame retreiving */
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
@@ -3714,7 +3727,7 @@ static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */
/* Sharpness */
{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
-/* Other registors */
+/* Other registers */
{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
/* Auto exposure and white balance */
{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
@@ -3756,7 +3769,6 @@ static const struct usb_action pas106b_InitialScale[] = { /* 176x144 */
{0xa0, 0x05, ZC3XX_R185_WINYWIDTH},
{0xa0, 0x14, ZC3XX_R186_WINYCENTER},
{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
-
/* Auto exposure and white balance */
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
{0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},
@@ -3820,8 +3832,7 @@ static const struct usb_action pas106b_Initial[] = { /* 352x288 */
{0xaa, 0x0d, 0x0000},
{0xaa, 0x0e, 0x0002},
{0xaa, 0x14, 0x0081},
-
-/* Other registors */
+/* Other registers */
{0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
/* Frame retreiving */
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
@@ -3832,7 +3843,7 @@ static const struct usb_action pas106b_Initial[] = { /* 352x288 */
/* Sharpness */
{0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
{0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
-/* Other registors */
+/* Other registers */
{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
/* Auto exposure and white balance */
{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
@@ -4225,8 +4236,8 @@ static const struct usb_action pas202b_NoFlikerScale[] = {
{}
};
-/* mi0360soc and pb0330 from vm30x.inf for 0ac8:301b and 0ac8:303b 07/02/13 */
-static const struct usb_action mi0360soc_Initial[] = { /* 640x480 */
+/* mt9v111 (mi0360soc) and pb0330 from vm30x.inf 0ac8:301b 07/02/13 */
+static const struct usb_action mt9v111_1_Initial[] = { /* 640x480 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
@@ -4237,14 +4248,14 @@ static const struct usb_action mi0360soc_Initial[] = { /* 640x480 */
{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
- {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, /*jfm: was 03*/
-/* {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, */
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
{0xdd, 0x00, 0x0200},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xaa, 0x01, 0x0001},
{0xaa, 0x06, 0x0000},
{0xaa, 0x08, 0x0483},
@@ -4254,18 +4265,18 @@ static const struct usb_action mi0360soc_Initial[] = { /* 640x480 */
{0xaa, 0x03, 0x01e5}, /*jfm: was 01e7*/
{0xaa, 0x04, 0x0285}, /*jfm: was 0287*/
{0xaa, 0x07, 0x3002},
- {0xaa, 0x20, 0x5100}, /*jfm: was 1100*/
- {0xaa, 0x35, 0x507f}, /*jfm: was 0050*/
+ {0xaa, 0x20, 0x5100},
+ {0xaa, 0x35, 0x507f},
{0xaa, 0x30, 0x0005},
{0xaa, 0x31, 0x0000},
{0xaa, 0x58, 0x0078},
{0xaa, 0x62, 0x0411},
- {0xaa, 0x2b, 0x0028},
+ {0xaa, 0x2b, 0x007f},
{0xaa, 0x2c, 0x007f}, /*jfm: was 0030*/
{0xaa, 0x2d, 0x007f}, /*jfm: was 0030*/
{0xaa, 0x2e, 0x007f}, /*jfm: was 0030*/
{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
- {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /*jfm: was 37*/
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
@@ -4275,12 +4286,12 @@ static const struct usb_action mi0360soc_Initial[] = { /* 640x480 */
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
- {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, /* jfm: was 78 */
+ {0xa0, 0x6c, ZC3XX_R18D_YTARGET},
{0xa0, 0x61, ZC3XX_R116_RGAIN},
{0xa0, 0x65, ZC3XX_R118_BGAIN},
{}
};
-static const struct usb_action mi0360soc_InitialScale[] = { /* 320x240 */
+static const struct usb_action mt9v111_1_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
{0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
@@ -4291,14 +4302,14 @@ static const struct usb_action mi0360soc_InitialScale[] = { /* 320x240 */
{0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
{0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
- {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC}, /*jfm: was 03*/
-/* {0xa0, 0x01, ZC3XX_R012_VIDEOCONTROLFUNC}, */
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
{0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
{0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
{0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
{0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
{0xdd, 0x00, 0x0200},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xaa, 0x01, 0x0001},
{0xaa, 0x06, 0x0000},
{0xaa, 0x08, 0x0483},
@@ -4308,7 +4319,7 @@ static const struct usb_action mi0360soc_InitialScale[] = { /* 320x240 */
{0xaa, 0x03, 0x01e7},
{0xaa, 0x04, 0x0287},
{0xaa, 0x07, 0x3002},
- {0xaa, 0x20, 0x5100}, /*jfm: was 1100*/
+ {0xaa, 0x20, 0x5100},
{0xaa, 0x35, 0x007f}, /*jfm: was 0050*/
{0xaa, 0x30, 0x0005},
{0xaa, 0x31, 0x0000},
@@ -4319,7 +4330,7 @@ static const struct usb_action mi0360soc_InitialScale[] = { /* 320x240 */
{0xaa, 0x2d, 0x007f}, /*jfm: was 30*/
{0xaa, 0x2e, 0x007f}, /*jfm: was 28*/
{0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
- {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION}, /*jfm: was 37*/
+ {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
{0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
{0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
{0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
@@ -4329,12 +4340,12 @@ static const struct usb_action mi0360soc_InitialScale[] = { /* 320x240 */
{0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
{0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
{0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
- {0xa0, 0x6c, ZC3XX_R18D_YTARGET}, /*jfm: was 78*/
+ {0xa0, 0x6c, ZC3XX_R18D_YTARGET},
{0xa0, 0x61, ZC3XX_R116_RGAIN},
{0xa0, 0x65, ZC3XX_R118_BGAIN},
{}
};
-static const struct usb_action mi360soc_AE50HZ[] = {
+static const struct usb_action mt9v111_1_AE50HZ[] = {
{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xbb, 0x00, 0x0562},
@@ -4357,7 +4368,7 @@ static const struct usb_action mi360soc_AE50HZ[] = {
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
{}
};
-static const struct usb_action mi360soc_AE50HZScale[] = {
+static const struct usb_action mt9v111_1_AE50HZScale[] = {
{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xbb, 0x00, 0x0509},
@@ -4379,11 +4390,11 @@ static const struct usb_action mi360soc_AE50HZScale[] = {
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
{}
};
-static const struct usb_action mi360soc_AE60HZ[] = {
+static const struct usb_action mt9v111_1_AE60HZ[] = {
{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
- {0xbb, 0x00, 0x053d},
- {0xbb, 0x01, 0x096e},
+ {0xaa, 0x05, 0x003d},
+ {0xaa, 0x09, 0x016e},
{0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
{0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
{0xa0, 0xdd, ZC3XX_R192_EXPOSURELIMITLOW},
@@ -4402,7 +4413,7 @@ static const struct usb_action mi360soc_AE60HZ[] = {
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
{}
};
-static const struct usb_action mi360soc_AE60HZScale[] = {
+static const struct usb_action mt9v111_1_AE60HZScale[] = {
{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xbb, 0x00, 0x0509},
@@ -4424,7 +4435,7 @@ static const struct usb_action mi360soc_AE60HZScale[] = {
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
{}
};
-static const struct usb_action mi360soc_AENoFliker[] = {
+static const struct usb_action mt9v111_1_AENoFliker[] = {
{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xbb, 0x00, 0x0509},
@@ -4447,7 +4458,7 @@ static const struct usb_action mi360soc_AENoFliker[] = {
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
{}
};
-static const struct usb_action mi360soc_AENoFlikerScale[] = {
+static const struct usb_action mt9v111_1_AENoFlikerScale[] = {
{0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
{0xbb, 0x00, 0x0534},
@@ -4470,6 +4481,251 @@ static const struct usb_action mi360soc_AENoFlikerScale[] = {
{0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
{}
};
+/* from usbvm303.inf 0ac8:303b 07/03/25 (3 - tas5130c) */
+static const struct usb_action mt9v111_3_Initial[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0a, 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, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xdd, 0x00, 0x0200},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xaa, 0x01, 0x0001}, /* select IFP/SOC registers */
+ {0xaa, 0x06, 0x0000}, /* operating mode control */
+ {0xaa, 0x08, 0x0483}, /* output format control */
+ /* H red first, V red or blue first,
+ * raw Bayer, auto flicker */
+ {0xaa, 0x01, 0x0004}, /* select sensor core registers */
+ {0xaa, 0x08, 0x0006}, /* row start */
+ {0xaa, 0x02, 0x0011}, /* column start */
+ {0xaa, 0x03, 0x01e5}, /* window height - 1 */
+ {0xaa, 0x04, 0x0285}, /* window width - 1 */
+ {0xaa, 0x07, 0x3002}, /* output control */
+ {0xaa, 0x20, 0x1100}, /* read mode: bits 8 & 12 (?) */
+ {0xaa, 0x35, 0x007f}, /* global gain */
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xaa, 0x2b, 0x007f}, /* green1 gain */
+ {0xaa, 0x2c, 0x007f}, /* blue gain */
+ {0xaa, 0x2d, 0x007f}, /* red gain */
+ {0xaa, 0x2e, 0x007f}, /* green2 gain */
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {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, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x61, ZC3XX_R116_RGAIN},
+ {0xa0, 0x65, ZC3XX_R118_BGAIN},
+ {}
+};
+static const struct usb_action mt9v111_3_InitialScale[] = {
+ {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
+ {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
+ {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
+ {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
+ {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
+ {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
+ {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
+ {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
+ {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
+ {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
+ {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
+ {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
+ {0xdd, 0x00, 0x0200},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {0xaa, 0x01, 0x0001},
+ {0xaa, 0x06, 0x0000},
+ {0xaa, 0x08, 0x0483},
+ {0xaa, 0x01, 0x0004},
+ {0xaa, 0x08, 0x0006},
+ {0xaa, 0x02, 0x0011},
+ {0xaa, 0x03, 0x01e7},
+ {0xaa, 0x04, 0x0287},
+ {0xaa, 0x07, 0x3002},
+ {0xaa, 0x20, 0x1100},
+ {0xaa, 0x35, 0x007f},
+ {0xaa, 0x30, 0x0005},
+ {0xaa, 0x31, 0x0000},
+ {0xaa, 0x58, 0x0078},
+ {0xaa, 0x62, 0x0411},
+ {0xaa, 0x2b, 0x007f},
+ {0xaa, 0x2c, 0x007f},
+ {0xaa, 0x2d, 0x007f},
+ {0xaa, 0x2e, 0x007f},
+ {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
+ {0xa0, 0x37, ZC3XX_R101_SENSORCORRECTION},
+ {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
+ {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, 0x60, ZC3XX_R1A8_DIGITALGAIN},
+ {0xa0, 0x80, ZC3XX_R18D_YTARGET},
+ {0xa0, 0x61, ZC3XX_R116_RGAIN},
+ {0xa0, 0x65, ZC3XX_R118_BGAIN},
+ {}
+};
+static const struct usb_action mt9v111_3_AE50HZ[] = {
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0009}, /* horizontal blanking */
+ {0xaa, 0x09, 0x01ce}, /* shutter width */
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action mt9v111_3_AE50HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0009},
+ {0xaa, 0x09, 0x01ce},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action mt9v111_3_AE60HZ[] = {
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0009},
+ {0xaa, 0x09, 0x0083},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action mt9v111_3_AE60HZScale[] = {
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0009},
+ {0xaa, 0x09, 0x0083},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0x8f, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x81, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x24, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action mt9v111_3_AENoFliker[] = {
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0034},
+ {0xaa, 0x09, 0x0260},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x34, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x60, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x90, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xe0, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
+static const struct usb_action mt9v111_3_AENoFlikerScale[] = {
+ {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
+ {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
+ {0xaa, 0x05, 0x0034},
+ {0xaa, 0x09, 0x0260},
+ {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
+ {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
+ {0xa0, 0xf0, ZC3XX_R192_EXPOSURELIMITLOW},
+ {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
+ {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
+ {0xa0, 0x04, ZC3XX_R197_ANTIFLICKERLOW},
+ {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
+ {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
+ {0xa0, 0x00, ZC3XX_R1A9_DIGITALLIMITDIFF},
+ {0xa0, 0x00, ZC3XX_R1AA_DIGITALGAINSTEP},
+ {0xa0, 0x34, ZC3XX_R01D_HSYNC_0},
+ {0xa0, 0x60, ZC3XX_R01E_HSYNC_1},
+ {0xa0, 0x90, ZC3XX_R01F_HSYNC_2},
+ {0xa0, 0xe0, ZC3XX_R020_HSYNC_3},
+ {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
+ {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
+ {}
+};
static const struct usb_action pb0330_Initial[] = { /* 640x480 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
@@ -4912,419 +5168,7 @@ static const struct usb_action po2030_NoFliker[] = {
{}
};
-/* TEST */
-static const struct usb_action tas5130cK_InitialScale[] = {
- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
- {0xa0, 0x01, 0x003b},
- {0xa0, 0x0e, 0x003a},
- {0xa0, 0x01, 0x0038},
- {0xa0, 0x0b, 0x0039},
- {0xa0, 0x00, 0x0038},
- {0xa0, 0x0b, 0x0039},
- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
- {0xa0, 0x0a, ZC3XX_R010_CMOSSENSORSELECT},
- {0xa0, 0x10, ZC3XX_R002_CLOCKSELECT},
- {0xa0, 0x02, ZC3XX_R003_FRAMEWIDTHHIGH},
- {0xa0, 0x80, ZC3XX_R004_FRAMEWIDTHLOW},
- {0xa0, 0x01, ZC3XX_R005_FRAMEHEIGHTHIGH},
- {0xa0, 0xe0, ZC3XX_R006_FRAMEHEIGHTLOW},
- {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
- {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
- {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
- {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
- {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
- {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
- {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
- {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x83, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x06, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x02, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0xE7, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x87, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x02, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x07, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x30, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x51, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x35, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x30, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x05, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x31, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x58, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x78, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x62, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x2B, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x2c, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x2D, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x2e, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
- {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
- {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
- {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
- {0xa0, 0x09, 0x01ad},
- {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
- {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
- {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
- {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
- {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
- {0xa0, 0x6c, ZC3XX_R18D_YTARGET},
- {0xa0, 0x61, ZC3XX_R116_RGAIN},
- {0xa0, 0x65, ZC3XX_R118_BGAIN},
- {0xa0, 0x09, 0x01ad},
- {0xa0, 0x15, 0x01ae},
- {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
- {0xa0, 0xf1, ZC3XX_R10B_RGB01},
- {0xa0, 0x03, ZC3XX_R10C_RGB02},
- {0xa0, 0xfe, ZC3XX_R10D_RGB10},
- {0xa0, 0x51, ZC3XX_R10E_RGB11},
- {0xa0, 0xf1, ZC3XX_R10F_RGB12},
- {0xa0, 0xec, ZC3XX_R110_RGB20},
- {0xa0, 0x03, ZC3XX_R111_RGB21},
- {0xa0, 0x51, ZC3XX_R112_RGB22},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
- {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
- {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
- {0xa0, 0x38, ZC3XX_R120_GAMMA00}, /* gamma > 5 */
- {0xa0, 0x51, ZC3XX_R121_GAMMA01},
- {0xa0, 0x6e, ZC3XX_R122_GAMMA02},
- {0xa0, 0x8c, ZC3XX_R123_GAMMA03},
- {0xa0, 0xa2, ZC3XX_R124_GAMMA04},
- {0xa0, 0xb6, ZC3XX_R125_GAMMA05},
- {0xa0, 0xc8, ZC3XX_R126_GAMMA06},
- {0xa0, 0xd6, ZC3XX_R127_GAMMA07},
- {0xa0, 0xe2, ZC3XX_R128_GAMMA08},
- {0xa0, 0xed, ZC3XX_R129_GAMMA09},
- {0xa0, 0xf5, ZC3XX_R12A_GAMMA0A},
- {0xa0, 0xfc, ZC3XX_R12B_GAMMA0B},
- {0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
- {0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
- {0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
- {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
- {0xa0, 0x12, ZC3XX_R130_GAMMA10},
- {0xa0, 0x1b, ZC3XX_R131_GAMMA11},
- {0xa0, 0x1d, ZC3XX_R132_GAMMA12},
- {0xa0, 0x1a, ZC3XX_R133_GAMMA13},
- {0xa0, 0x15, ZC3XX_R134_GAMMA14},
- {0xa0, 0x12, ZC3XX_R135_GAMMA15},
- {0xa0, 0x0f, ZC3XX_R136_GAMMA16},
- {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
- {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
- {0xa0, 0x09, ZC3XX_R139_GAMMA19},
- {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
- {0xa0, 0x05, ZC3XX_R13B_GAMMA1B},
- {0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
- {0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
- {0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
- {0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
- {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
- {0xa0, 0xf1, ZC3XX_R10B_RGB01},
- {0xa0, 0x03, ZC3XX_R10C_RGB02},
- {0xa0, 0xfe, ZC3XX_R10D_RGB10},
- {0xa0, 0x51, ZC3XX_R10E_RGB11},
- {0xa0, 0xf1, ZC3XX_R10F_RGB12},
- {0xa0, 0xec, ZC3XX_R110_RGB20},
- {0xa0, 0x03, ZC3XX_R111_RGB21},
- {0xa0, 0x51, ZC3XX_R112_RGB22},
- {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
- {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x09, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x34, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
- {0xa0, 0x07, ZC3XX_R191_EXPOSURELIMITMID},
- {0xa0, 0xd2, ZC3XX_R192_EXPOSURELIMITLOW},
- {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
- {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
- {0xa0, 0x9a, ZC3XX_R197_ANTIFLICKERLOW},
- {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
- {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
- {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
- {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
- {0xa0, 0xd7, ZC3XX_R01D_HSYNC_0},
- {0xa0, 0xf4, ZC3XX_R01E_HSYNC_1},
- {0xa0, 0xf9, ZC3XX_R01F_HSYNC_2},
- {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x09, 0x01ad},
- {0xa0, 0x15, 0x01ae},
- {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
- {}
-};
-
-static const struct usb_action tas5130cK_Initial[] = {
- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
- {0xa0, 0x01, 0x003b},
- {0xa0, 0x0e, 0x003a},
- {0xa0, 0x01, 0x0038},
- {0xa0, 0x0b, 0x0039},
- {0xa0, 0x00, 0x0038},
- {0xa0, 0x0b, 0x0039},
- {0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
- {0xa0, 0x0a, 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, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
- {0xa0, 0x01, ZC3XX_R001_SYSTEMOPERATING},
- {0xa0, 0x07, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x00, ZC3XX_R098_WINYSTARTLOW},
- {0xa0, 0x00, ZC3XX_R09A_WINXSTARTLOW},
- {0xa0, 0x00, ZC3XX_R11A_FIRSTYLOW},
- {0xa0, 0x00, ZC3XX_R11C_FIRSTXLOW},
- {0xa0, 0xdc, ZC3XX_R08B_I2CDEVICEADDR},
- {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x01, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x06, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x83, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x01, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x04, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x08, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x06, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x02, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x03, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0xe5, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x04, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x85, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x02, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x07, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x02, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x30, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x20, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x51, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x35, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x50, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x30, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x05, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x31, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x00, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x58, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x78, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x62, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x11, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x04, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x2B, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x2C, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7F, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x2D, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x2e, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x7f, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x10, ZC3XX_R087_EXPTIMEMID},
- {0xa0, 0xb7, ZC3XX_R101_SENSORCORRECTION},
- {0xa0, 0x05, ZC3XX_R012_VIDEOCONTROLFUNC},
- {0xa0, 0x0d, ZC3XX_R100_OPERATIONMODE},
- {0xa0, 0x06, ZC3XX_R189_AWBSTATUS},
- {0xa0, 0x09, 0x01ad},
- {0xa0, 0x03, ZC3XX_R1C5_SHARPNESSMODE},
- {0xa0, 0x13, ZC3XX_R1CB_SHARPNESS05},
- {0xa0, 0x08, ZC3XX_R250_DEADPIXELSMODE},
- {0xa0, 0x08, ZC3XX_R301_EEPROMACCESS},
- {0xa0, 0x60, ZC3XX_R1A8_DIGITALGAIN},
- {0xa0, 0x6c, ZC3XX_R18D_YTARGET},
- {0xa0, 0x61, ZC3XX_R116_RGAIN},
- {0xa0, 0x65, ZC3XX_R118_BGAIN},
- {0xa0, 0x09, 0x01ad},
- {0xa0, 0x15, 0x01ae},
- {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
- {0xa0, 0xf1, ZC3XX_R10B_RGB01},
- {0xa0, 0x03, ZC3XX_R10C_RGB02},
- {0xa0, 0xfe, ZC3XX_R10D_RGB10},
- {0xa0, 0x51, ZC3XX_R10E_RGB11},
- {0xa0, 0xf1, ZC3XX_R10F_RGB12},
- {0xa0, 0xec, ZC3XX_R110_RGB20},
- {0xa0, 0x03, ZC3XX_R111_RGB21},
- {0xa0, 0x51, ZC3XX_R112_RGB22},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
- {0xa0, 0x08, ZC3XX_R1C6_SHARPNESS00}, /* sharpness+ */
- {0xa0, 0x0f, ZC3XX_R1CB_SHARPNESS05}, /* sharpness- */
- {0xa0, 0x38, ZC3XX_R120_GAMMA00}, /* gamma > 5 */
- {0xa0, 0x51, ZC3XX_R121_GAMMA01},
- {0xa0, 0x6e, ZC3XX_R122_GAMMA02},
- {0xa0, 0x8c, ZC3XX_R123_GAMMA03},
- {0xa0, 0xa2, ZC3XX_R124_GAMMA04},
- {0xa0, 0xb6, ZC3XX_R125_GAMMA05},
- {0xa0, 0xc8, ZC3XX_R126_GAMMA06},
- {0xa0, 0xd6, ZC3XX_R127_GAMMA07},
- {0xa0, 0xe2, ZC3XX_R128_GAMMA08},
- {0xa0, 0xed, ZC3XX_R129_GAMMA09},
- {0xa0, 0xf5, ZC3XX_R12A_GAMMA0A},
- {0xa0, 0xfc, ZC3XX_R12B_GAMMA0B},
- {0xa0, 0xff, ZC3XX_R12C_GAMMA0C},
- {0xa0, 0xff, ZC3XX_R12D_GAMMA0D},
- {0xa0, 0xff, ZC3XX_R12E_GAMMA0E},
- {0xa0, 0xff, ZC3XX_R12F_GAMMA0F},
- {0xa0, 0x12, ZC3XX_R130_GAMMA10},
- {0xa0, 0x1b, ZC3XX_R131_GAMMA11},
- {0xa0, 0x1d, ZC3XX_R132_GAMMA12},
- {0xa0, 0x1a, ZC3XX_R133_GAMMA13},
- {0xa0, 0x15, ZC3XX_R134_GAMMA14},
- {0xa0, 0x12, ZC3XX_R135_GAMMA15},
- {0xa0, 0x0f, ZC3XX_R136_GAMMA16},
- {0xa0, 0x0d, ZC3XX_R137_GAMMA17},
- {0xa0, 0x0b, ZC3XX_R138_GAMMA18},
- {0xa0, 0x09, ZC3XX_R139_GAMMA19},
- {0xa0, 0x07, ZC3XX_R13A_GAMMA1A},
- {0xa0, 0x05, ZC3XX_R13B_GAMMA1B},
- {0xa0, 0x00, ZC3XX_R13C_GAMMA1C},
- {0xa0, 0x00, ZC3XX_R13D_GAMMA1D},
- {0xa0, 0x00, ZC3XX_R13E_GAMMA1E},
- {0xa0, 0x01, ZC3XX_R13F_GAMMA1F},
- {0xa0, 0x4c, ZC3XX_R10A_RGB00}, /* matrix */
- {0xa0, 0xf1, ZC3XX_R10B_RGB01},
- {0xa0, 0x03, ZC3XX_R10C_RGB02},
- {0xa0, 0xfe, ZC3XX_R10D_RGB10},
- {0xa0, 0x51, ZC3XX_R10E_RGB11},
- {0xa0, 0xf1, ZC3XX_R10F_RGB12},
- {0xa0, 0xec, ZC3XX_R110_RGB20},
- {0xa0, 0x03, ZC3XX_R111_RGB21},
- {0xa0, 0x51, ZC3XX_R112_RGB22},
- {0xa0, 0x10, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x00, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS},
- {0xa0, 0x05, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0x62, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x00, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x09, ZC3XX_R092_I2CADDRESSSELECT},
- {0xa0, 0xaa, ZC3XX_R093_I2CSETVALUE},
- {0xa0, 0x01, ZC3XX_R094_I2CWRITEACK},
- {0xa0, 0x01, ZC3XX_R090_I2CCOMMAND},
- {0xa0, 0x00, ZC3XX_R190_EXPOSURELIMITHIGH},
- {0xa0, 0x03, ZC3XX_R191_EXPOSURELIMITMID},
- {0xa0, 0x9b, ZC3XX_R192_EXPOSURELIMITLOW},
- {0xa0, 0x00, ZC3XX_R195_ANTIFLICKERHIGH},
- {0xa0, 0x00, ZC3XX_R196_ANTIFLICKERMID},
- {0xa0, 0x47, ZC3XX_R197_ANTIFLICKERLOW},
- {0xa0, 0x0e, ZC3XX_R18C_AEFREEZE},
- {0xa0, 0x1c, ZC3XX_R18F_AEUNFREEZE},
- {0xa0, 0x14, ZC3XX_R1A9_DIGITALLIMITDIFF},
- {0xa0, 0x66, ZC3XX_R1AA_DIGITALGAINSTEP},
- {0xa0, 0x62, ZC3XX_R01D_HSYNC_0},
- {0xa0, 0x90, ZC3XX_R01E_HSYNC_1},
- {0xa0, 0xc8, ZC3XX_R01F_HSYNC_2},
- {0xa0, 0xff, ZC3XX_R020_HSYNC_3},
- {0xa0, 0x60, ZC3XX_R11D_GLOBALGAIN},
- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x09, 0x01ad},
- {0xa0, 0x15, 0x01ae},
- {0xa0, 0x40, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x42, ZC3XX_R180_AUTOCORRECTENABLE},
- {0xa0, 0x30, 0x0007},
- {0xa0, 0x02, ZC3XX_R008_CLOCKSETTING},
- {0xa0, 0x00, 0x0007},
- {0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
- {}
-};
-
-static const struct usb_action tas5130cxx_InitialScale[] = { /* 320x240 */
+static const struct usb_action tas5130c_InitialScale[] = { /* 320x240 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x50, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x03, ZC3XX_R008_CLOCKSETTING},
@@ -5361,7 +5205,7 @@ static const struct usb_action tas5130cxx_InitialScale[] = { /* 320x240 */
{0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL},
{}
};
-static const struct usb_action tas5130cxx_Initial[] = { /* 640x480 */
+static const struct usb_action tas5130c_Initial[] = { /* 640x480 */
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL},
{0xa0, 0x40, ZC3XX_R002_CLOCKSELECT},
{0xa0, 0x00, ZC3XX_R008_CLOCKSETTING},
@@ -5397,7 +5241,7 @@ static const struct usb_action tas5130cxx_Initial[] = { /* 640x480 */
{0xa0, 0x02, ZC3XX_R0A6_EXPOSUREBLACKLVL},
{}
};
-static const struct usb_action tas5130cxx_50HZ[] = {
+static const struct usb_action tas5130c_50HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
{0xaa, 0xa4, 0x0063}, /* 00,a4,63,aa */
@@ -5422,7 +5266,7 @@ static const struct usb_action tas5130cxx_50HZ[] = {
{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
{}
};
-static const struct usb_action tas5130cxx_50HZScale[] = {
+static const struct usb_action tas5130c_50HZScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
{0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */
@@ -5447,7 +5291,7 @@ static const struct usb_action tas5130cxx_50HZScale[] = {
{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
{}
};
-static const struct usb_action tas5130cxx_60HZ[] = {
+static const struct usb_action tas5130c_60HZ[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
{0xaa, 0xa4, 0x0036}, /* 00,a4,36,aa */
@@ -5472,7 +5316,7 @@ static const struct usb_action tas5130cxx_60HZ[] = {
{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
{}
};
-static const struct usb_action tas5130cxx_60HZScale[] = {
+static const struct usb_action tas5130c_60HZScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
{0xaa, 0xa4, 0x0077}, /* 00,a4,77,aa */
@@ -5497,7 +5341,7 @@ static const struct usb_action tas5130cxx_60HZScale[] = {
{0xa0, 0x50, ZC3XX_R11D_GLOBALGAIN},
{}
};
-static const struct usb_action tas5130cxx_NoFliker[] = {
+static const struct usb_action tas5130c_NoFliker[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
{0xaa, 0xa4, 0x0040}, /* 00,a4,40,aa */
@@ -5523,7 +5367,7 @@ static const struct usb_action tas5130cxx_NoFliker[] = {
{}
};
-static const struct usb_action tas5130cxx_NoFlikerScale[] = {
+static const struct usb_action tas5130c_NoFlikerScale[] = {
{0xa0, 0x00, ZC3XX_R019_AUTOADJUSTFPS}, /* 00,19,00,cc */
{0xaa, 0xa3, 0x0001}, /* 00,a3,01,aa */
{0xaa, 0xa4, 0x0090}, /* 00,a4,90,aa */
@@ -5549,7 +5393,7 @@ static const struct usb_action tas5130cxx_NoFlikerScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_InitialScale[] = {
+static const struct usb_action gc0303_InitialScale[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
@@ -5616,7 +5460,7 @@ static const struct usb_action tas5130c_vf0250_InitialScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_Initial[] = {
+static const struct usb_action gc0303_Initial[] = {
{0xa0, 0x01, ZC3XX_R000_SYSTEMCONTROL}, /* 00,00,01,cc, */
{0xa0, 0x02, ZC3XX_R008_CLOCKSETTING}, /* 00,08,02,cc, */
{0xa0, 0x01, ZC3XX_R010_CMOSSENSORSELECT}, /* 00,10,01,cc, */
@@ -5681,7 +5525,7 @@ static const struct usb_action tas5130c_vf0250_Initial[] = {
{0xa0, 0x65, ZC3XX_R118_BGAIN}, /* 01,18,65,cc */
{}
};
-static const struct usb_action tas5130c_vf0250_50HZScale[] = {
+static const struct usb_action gc0303_50HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
{0xaa, 0x84, 0x00aa}, /* 00,84,aa,aa */
@@ -5705,7 +5549,7 @@ static const struct usb_action tas5130c_vf0250_50HZScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_50HZ[] = {
+static const struct usb_action gc0303_50HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0003}, /* 00,83,03,aa */
{0xaa, 0x84, 0x0054}, /* 00,84,54,aa */
@@ -5729,7 +5573,7 @@ static const struct usb_action tas5130c_vf0250_50HZ[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_60HZScale[] = {
+static const struct usb_action gc0303_60HZScale[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0001}, /* 00,83,01,aa */
{0xaa, 0x84, 0x0062}, /* 00,84,62,aa */
@@ -5753,7 +5597,7 @@ static const struct usb_action tas5130c_vf0250_60HZScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_60HZ[] = {
+static const struct usb_action gc0303_60HZ[] = {
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0002}, /* 00,83,02,aa */
{0xaa, 0x84, 0x00c4}, /* 00,84,c4,aa */
@@ -5777,7 +5621,7 @@ static const struct usb_action tas5130c_vf0250_60HZ[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
+static const struct usb_action gc0303_NoFlikerScale[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
@@ -5799,7 +5643,7 @@ static const struct usb_action tas5130c_vf0250_NoFlikerScale[] = {
{}
};
-static const struct usb_action tas5130c_vf0250_NoFliker[] = {
+static const struct usb_action gc0303_NoFliker[] = {
{0xa0, 0x0c, ZC3XX_R100_OPERATIONMODE}, /* 01,00,0c,cc, */
{0xaa, 0x82, 0x0000}, /* 00,82,00,aa */
{0xaa, 0x83, 0x0000}, /* 00,83,00,aa */
@@ -5824,13 +5668,22 @@ static const struct usb_action tas5130c_vf0250_NoFliker[] = {
static u8 reg_r_i(struct gspca_dev *gspca_dev,
u16 index)
{
- usb_control_msg(gspca_dev->dev,
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return 0;
+ ret = usb_control_msg(gspca_dev->dev,
usb_rcvctrlpipe(gspca_dev->dev, 0),
0xa1,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x01, /* value */
index, gspca_dev->usb_buf, 1,
500);
+ if (ret < 0) {
+ err("reg_r_i err %d", ret);
+ gspca_dev->usb_err = ret;
+ return 0;
+ }
return gspca_dev->usb_buf[0];
}
@@ -5844,24 +5697,32 @@ static u8 reg_r(struct gspca_dev *gspca_dev,
return ret;
}
-static void reg_w_i(struct usb_device *dev,
+static void reg_w_i(struct gspca_dev *gspca_dev,
u8 value,
u16 index)
{
- usb_control_msg(dev,
- usb_sndctrlpipe(dev, 0),
+ int ret;
+
+ if (gspca_dev->usb_err < 0)
+ return;
+ ret = usb_control_msg(gspca_dev->dev,
+ usb_sndctrlpipe(gspca_dev->dev, 0),
0xa0,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
value, index, NULL, 0,
500);
+ if (ret < 0) {
+ err("reg_w_i err %d", ret);
+ gspca_dev->usb_err = ret;
+ }
}
-static void reg_w(struct usb_device *dev,
+static void reg_w(struct gspca_dev *gspca_dev,
u8 value,
u16 index)
{
PDEBUG(D_USBO, "reg w [%04x] = %02x", index, value);
- reg_w_i(dev, value, index);
+ reg_w_i(gspca_dev, value, index);
}
static u16 i2c_read(struct gspca_dev *gspca_dev,
@@ -5870,8 +5731,10 @@ static u16 i2c_read(struct gspca_dev *gspca_dev,
u8 retbyte;
u16 retval;
- reg_w_i(gspca_dev->dev, reg, 0x0092);
- reg_w_i(gspca_dev->dev, 0x02, 0x0090); /* <- read command */
+ if (gspca_dev->usb_err < 0)
+ return 0;
+ reg_w_i(gspca_dev, reg, 0x0092);
+ reg_w_i(gspca_dev, 0x02, 0x0090); /* <- read command */
msleep(20);
retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
if (retbyte != 0x00)
@@ -5890,10 +5753,12 @@ static u8 i2c_write(struct gspca_dev *gspca_dev,
{
u8 retbyte;
- reg_w_i(gspca_dev->dev, reg, 0x92);
- 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 */
+ if (gspca_dev->usb_err < 0)
+ return 0;
+ reg_w_i(gspca_dev, reg, 0x92);
+ reg_w_i(gspca_dev, valL, 0x93);
+ reg_w_i(gspca_dev, valH, 0x94);
+ reg_w_i(gspca_dev, 0x01, 0x90); /* <- write command */
msleep(1);
retbyte = reg_r_i(gspca_dev, 0x0091); /* read status */
if (retbyte != 0x00)
@@ -5909,7 +5774,7 @@ static void usb_exchange(struct gspca_dev *gspca_dev,
while (action->req) {
switch (action->req) {
case 0xa0: /* write register */
- reg_w(gspca_dev->dev, action->val, action->idx);
+ reg_w(gspca_dev, action->val, action->idx);
break;
case 0xa1: /* read status */
reg_r(gspca_dev, action->idx);
@@ -5955,41 +5820,40 @@ static void setmatrix(struct gspca_dev *gspca_dev)
{0x60, 0xf0, 0xf0, 0xf0, 0x60, 0xf0, 0xf0, 0xf0, 0x60};
static const u8 tas5130c_matrix[9] =
{0x68, 0xec, 0xec, 0xec, 0x68, 0xec, 0xec, 0xec, 0x68};
- static const u8 vf0250_matrix[9] =
+ static const u8 gc0303_matrix[9] =
{0x7b, 0xea, 0xea, 0xea, 0x7b, 0xea, 0xea, 0xea, 0x7b};
static const u8 *matrix_tb[SENSOR_MAX] = {
- adcm2700_matrix, /* SENSOR_ADCM2700 0 */
- ov7620_matrix, /* SENSOR_CS2102 1 */
- NULL, /* SENSOR_CS2102K 2 */
- gc0305_matrix, /* SENSOR_GC0305 3 */
- NULL, /* SENSOR_HDCS2020b 4 */
- NULL, /* SENSOR_HV7131B 5 */
- NULL, /* SENSOR_HV7131C 6 */
- NULL, /* SENSOR_ICM105A 7 */
- NULL, /* SENSOR_MC501CB 8 */
- gc0305_matrix, /* SENSOR_MI0360SOC 9 */
- ov7620_matrix, /* SENSOR_OV7620 10 */
- NULL, /* SENSOR_OV7630C 11 */
- NULL, /* SENSOR_PAS106 12 */
- pas202b_matrix, /* SENSOR_PAS202B 13 */
- gc0305_matrix, /* SENSOR_PB0330 14 */
- po2030_matrix, /* SENSOR_PO2030 15 */
- NULL, /* SENSOR_TAS5130CK 16 */
- tas5130c_matrix, /* SENSOR_TAS5130CXX 17 */
- vf0250_matrix, /* SENSOR_TAS5130C_VF0250 18 */
+ [SENSOR_ADCM2700] = adcm2700_matrix,
+ [SENSOR_CS2102] = ov7620_matrix,
+ [SENSOR_CS2102K] = NULL,
+ [SENSOR_GC0303] = gc0303_matrix,
+ [SENSOR_GC0305] = gc0305_matrix,
+ [SENSOR_HDCS2020b] = NULL,
+ [SENSOR_HV7131B] = NULL,
+ [SENSOR_HV7131R] = NULL,
+ [SENSOR_ICM105A] = po2030_matrix,
+ [SENSOR_MC501CB] = NULL,
+ [SENSOR_MT9V111_1] = gc0305_matrix,
+ [SENSOR_MT9V111_3] = gc0305_matrix,
+ [SENSOR_OV7620] = ov7620_matrix,
+ [SENSOR_OV7630C] = NULL,
+ [SENSOR_PAS106] = NULL,
+ [SENSOR_PAS202B] = pas202b_matrix,
+ [SENSOR_PB0330] = gc0305_matrix,
+ [SENSOR_PO2030] = po2030_matrix,
+ [SENSOR_TAS5130C] = tas5130c_matrix,
};
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);
+ reg_w(gspca_dev, matrix[i], 0x010a + i);
}
static void setsharpness(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int sharpness;
static const u8 sharpness_tb[][2] = {
{0x02, 0x03},
@@ -5998,22 +5862,24 @@ static void setsharpness(struct gspca_dev *gspca_dev)
{0x10, 0x1e}
};
- sharpness = sd->sharpness;
- reg_w(dev, sharpness_tb[sharpness][0], 0x01c6);
+ sharpness = sd->ctrls[SHARPNESS].val;
+ reg_w(gspca_dev, sharpness_tb[sharpness][0], 0x01c6);
reg_r(gspca_dev, 0x01c8);
reg_r(gspca_dev, 0x01c9);
reg_r(gspca_dev, 0x01ca);
- reg_w(dev, sharpness_tb[sharpness][1], 0x01cb);
+ reg_w(gspca_dev, sharpness_tb[sharpness][1], 0x01cb);
}
static void setcontrast(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
const u8 *Tgamma;
- int g, i, k, adj, gp;
+ int g, i, brightness, contrast, adj, gp1, gp2;
u8 gr[16];
- static const u8 delta_tb[16] = /* delta for contrast */
+ static const u8 delta_b[16] = /* delta for brightness */
+ {0x50, 0x38, 0x2d, 0x28, 0x24, 0x21, 0x1e, 0x1d,
+ 0x1d, 0x1b, 0x1b, 0x1b, 0x19, 0x18, 0x18, 0x18};
+ static const u8 delta_c[16] = /* delta for contrast */
{0x2c, 0x1a, 0x12, 0x0c, 0x0a, 0x06, 0x06, 0x06,
0x04, 0x06, 0x04, 0x04, 0x03, 0x03, 0x02, 0x02};
static const u8 gamma_tb[6][16] = {
@@ -6031,40 +5897,39 @@ static void setcontrast(struct gspca_dev *gspca_dev)
0xe0, 0xeb, 0xf4, 0xff, 0xff, 0xff, 0xff, 0xff},
};
- Tgamma = gamma_tb[sd->gamma - 1];
+ Tgamma = gamma_tb[sd->ctrls[GAMMA].val - 1];
- k = ((int) sd->contrast - 128); /* -128 / 128 */
+ contrast = ((int) sd->ctrls[CONTRAST].val - 128); /* -128 / 127 */
+ brightness = ((int) sd->ctrls[BRIGHTNESS].val - 128); /* -128 / 92 */
adj = 0;
- gp = 0;
+ gp1 = gp2 = 0;
for (i = 0; i < 16; i++) {
- g = Tgamma[i] - delta_tb[i] * k / 256 - adj / 2;
+ g = Tgamma[i] + delta_b[i] * brightness / 256
+ - delta_c[i] * contrast / 256 - adj / 2;
if (g > 0xff)
g = 0xff;
else if (g < 0)
g = 0;
- reg_w(dev, g, 0x0120 + i); /* gamma */
- if (k > 0)
+ reg_w(gspca_dev, g, 0x0120 + i); /* gamma */
+ if (contrast > 0)
adj--;
- else
+ else if (contrast < 0)
adj++;
-
- if (i != 0) {
- if (gp == 0)
- gr[i - 1] = 0;
- else
- gr[i - 1] = g - gp;
- }
- gp = g;
+ if (i > 1)
+ gr[i - 1] = (g - gp2) / 2;
+ else if (i != 0)
+ gr[0] = gp1 == 0 ? 0 : (g - gp1);
+ gp2 = gp1;
+ gp1 = g;
}
- gr[15] = gr[14] / 2;
+ gr[15] = (0xff - gp2) / 2;
for (i = 0; i < 16; i++)
- reg_w(dev, gr[i], 0x0130 + i); /* gradient */
+ reg_w(gspca_dev, gr[i], 0x0130 + i); /* gradient */
}
static void setquality(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
u8 frxt;
switch (sd->sensor) {
@@ -6077,9 +5942,9 @@ static void setquality(struct gspca_dev *gspca_dev)
return;
}
/*fixme: is it really 0008 0007 0018 for all other sensors? */
- reg_w(dev, QUANT_VAL, 0x0008);
+ reg_w(gspca_dev, QUANT_VAL, 0x0008);
frxt = 0x30;
- reg_w(dev, frxt, 0x0007);
+ reg_w(gspca_dev, frxt, 0x0007);
#if QUANT_VAL == 0 || QUANT_VAL == 1 || QUANT_VAL == 2
frxt = 0xff;
#elif QUANT_VAL == 3
@@ -6089,7 +5954,7 @@ static void setquality(struct gspca_dev *gspca_dev)
#else
frxt = 0x20;
#endif
- reg_w(dev, frxt, 0x0018);
+ reg_w(gspca_dev, frxt, 0x0018);
}
/* Matches the sensor's internal frame rate to the lighting frequency.
@@ -6097,120 +5962,118 @@ static void setquality(struct gspca_dev *gspca_dev)
* 50Hz, for European and Asian lighting (default)
* 60Hz, for American lighting
* 0 = No Fliker (for outdoore usage)
- * Returns: 0 for success
*/
-static int setlightfreq(struct gspca_dev *gspca_dev)
+static void setlightfreq(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
int i, mode;
const struct usb_action *zc3_freq;
static const struct usb_action *freq_tb[SENSOR_MAX][6] = {
-/* SENSOR_ADCM2700 0 */
+ [SENSOR_ADCM2700] =
{adcm2700_NoFliker, adcm2700_NoFliker,
adcm2700_50HZ, adcm2700_50HZ,
adcm2700_60HZ, adcm2700_60HZ},
-/* SENSOR_CS2102 1 */
+ [SENSOR_CS2102] =
{cs2102_NoFliker, cs2102_NoFlikerScale,
cs2102_50HZ, cs2102_50HZScale,
cs2102_60HZ, cs2102_60HZScale},
-/* SENSOR_CS2102K 2 */
+ [SENSOR_CS2102K] =
{cs2102_NoFliker, cs2102_NoFlikerScale,
NULL, NULL, /* currently disabled */
NULL, NULL},
-/* SENSOR_GC0305 3 */
+ [SENSOR_GC0303] =
+ {gc0303_NoFliker, gc0303_NoFlikerScale,
+ gc0303_50HZ, gc0303_50HZScale,
+ gc0303_60HZ, gc0303_60HZScale},
+ [SENSOR_GC0305] =
{gc0305_NoFliker, gc0305_NoFliker,
gc0305_50HZ, gc0305_50HZ,
gc0305_60HZ, gc0305_60HZ},
-/* SENSOR_HDCS2020b 4 */
+ [SENSOR_HDCS2020b] =
{hdcs2020b_NoFliker, hdcs2020b_NoFliker,
hdcs2020b_50HZ, hdcs2020b_50HZ,
hdcs2020b_60HZ, hdcs2020b_60HZ},
-/* SENSOR_HV7131B 5 */
+ [SENSOR_HV7131B] =
{hv7131b_NoFliker, hv7131b_NoFlikerScale,
hv7131b_50HZ, hv7131b_50HZScale,
hv7131b_60HZ, hv7131b_60HZScale},
-/* SENSOR_HV7131C 6 */
- {NULL, NULL,
- NULL, NULL,
- NULL, NULL},
-/* SENSOR_ICM105A 7 */
+ [SENSOR_HV7131R] =
+ {hv7131r_NoFliker, hv7131r_NoFlikerScale,
+ hv7131r_50HZ, hv7131r_50HZScale,
+ hv7131r_60HZ, hv7131r_60HZScale},
+ [SENSOR_ICM105A] =
{icm105a_NoFliker, icm105a_NoFlikerScale,
icm105a_50HZ, icm105a_50HZScale,
icm105a_60HZ, icm105a_60HZScale},
-/* SENSOR_MC501CB 8 */
+ [SENSOR_MC501CB] =
{mc501cb_NoFliker, mc501cb_NoFlikerScale,
mc501cb_50HZ, mc501cb_50HZScale,
mc501cb_60HZ, mc501cb_60HZScale},
-/* SENSOR_MI0360SOC 9 */
- {mi360soc_AENoFliker, mi360soc_AENoFlikerScale,
- mi360soc_AE50HZ, mi360soc_AE50HZScale,
- mi360soc_AE60HZ, mi360soc_AE60HZScale},
-/* SENSOR_OV7620 10 */
+ [SENSOR_MT9V111_1] =
+ {mt9v111_1_AENoFliker, mt9v111_1_AENoFlikerScale,
+ mt9v111_1_AE50HZ, mt9v111_1_AE50HZScale,
+ mt9v111_1_AE60HZ, mt9v111_1_AE60HZScale},
+ [SENSOR_MT9V111_3] =
+ {mt9v111_3_AENoFliker, mt9v111_3_AENoFlikerScale,
+ mt9v111_3_AE50HZ, mt9v111_3_AE50HZScale,
+ mt9v111_3_AE60HZ, mt9v111_3_AE60HZScale},
+ [SENSOR_OV7620] =
{ov7620_NoFliker, ov7620_NoFliker,
ov7620_50HZ, ov7620_50HZ,
ov7620_60HZ, ov7620_60HZ},
-/* SENSOR_OV7630C 11 */
+ [SENSOR_OV7630C] =
{NULL, NULL,
NULL, NULL,
NULL, NULL},
-/* SENSOR_PAS106 12 */
+ [SENSOR_PAS106] =
{pas106b_NoFliker, pas106b_NoFliker,
pas106b_50HZ, pas106b_50HZ,
pas106b_60HZ, pas106b_60HZ},
-/* SENSOR_PAS202B 13 */
+ [SENSOR_PAS202B] =
{pas202b_NoFliker, pas202b_NoFlikerScale,
pas202b_50HZ, pas202b_50HZScale,
pas202b_60HZ, pas202b_60HZScale},
-/* SENSOR_PB0330 14 */
+ [SENSOR_PB0330] =
{pb0330_NoFliker, pb0330_NoFlikerScale,
pb0330_50HZ, pb0330_50HZScale,
pb0330_60HZ, pb0330_60HZScale},
-/* SENSOR_PO2030 15 */
+ [SENSOR_PO2030] =
{po2030_NoFliker, po2030_NoFliker,
po2030_50HZ, po2030_50HZ,
po2030_60HZ, po2030_60HZ},
-/* SENSOR_TAS5130CK 16 */
- {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
- tas5130cxx_50HZ, tas5130cxx_50HZScale,
- tas5130cxx_60HZ, tas5130cxx_60HZScale},
-/* SENSOR_TAS5130CXX 17 */
- {tas5130cxx_NoFliker, tas5130cxx_NoFlikerScale,
- tas5130cxx_50HZ, tas5130cxx_50HZScale,
- tas5130cxx_60HZ, tas5130cxx_60HZScale},
-/* SENSOR_TAS5130C_VF0250 18 */
- {tas5130c_vf0250_NoFliker, tas5130c_vf0250_NoFlikerScale,
- tas5130c_vf0250_50HZ, tas5130c_vf0250_50HZScale,
- tas5130c_vf0250_60HZ, tas5130c_vf0250_60HZScale},
+ [SENSOR_TAS5130C] =
+ {tas5130c_NoFliker, tas5130c_NoFlikerScale,
+ tas5130c_50HZ, tas5130c_50HZScale,
+ tas5130c_60HZ, tas5130c_60HZScale},
};
- i = sd->lightfreq * 2;
- mode = gspca_dev->cam.cam_mode[(int) gspca_dev->curr_mode].priv;
+ i = sd->ctrls[LIGHTFREQ].val * 2;
+ mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
if (mode)
i++; /* 320x240 */
zc3_freq = freq_tb[sd->sensor][i];
- if (zc3_freq != NULL) {
- usb_exchange(gspca_dev, zc3_freq);
- switch (sd->sensor) {
- case SENSOR_GC0305:
- if (mode /* if 320x240 */
- && sd->lightfreq == 1) /* and 50Hz */
- reg_w(gspca_dev->dev, 0x85, 0x018d);
- /* win: 0x80, 0x018d */
- break;
- case SENSOR_OV7620:
- if (!mode) { /* if 640x480 */
- if (sd->lightfreq != 0) /* and 50 or 60 Hz */
- reg_w(gspca_dev->dev, 0x40, 0x0002);
- else
- reg_w(gspca_dev->dev, 0x44, 0x0002);
- }
- break;
- case SENSOR_PAS202B:
- reg_w(gspca_dev->dev, 0x00, 0x01a7);
- break;
+ if (zc3_freq == NULL)
+ return;
+ usb_exchange(gspca_dev, zc3_freq);
+ switch (sd->sensor) {
+ case SENSOR_GC0305:
+ if (mode /* if 320x240 */
+ && sd->ctrls[LIGHTFREQ].val == 1) /* and 50Hz */
+ reg_w(gspca_dev, 0x85, 0x018d);
+ /* win: 0x80, 0x018d */
+ break;
+ case SENSOR_OV7620:
+ if (!mode) { /* if 640x480 */
+ if (sd->ctrls[LIGHTFREQ].val != 0) /* and filter */
+ reg_w(gspca_dev, 0x40, 0x0002);
+ else
+ reg_w(gspca_dev, 0x44, 0x0002);
}
+ break;
+ case SENSOR_PAS202B:
+ reg_w(gspca_dev, 0x00, 0x01a7);
+ break;
}
- return 0;
}
static void setautogain(struct gspca_dev *gspca_dev)
@@ -6218,49 +6081,50 @@ static void setautogain(struct gspca_dev *gspca_dev)
struct sd *sd = (struct sd *) gspca_dev;
u8 autoval;
- if (sd->autogain)
+ if (sd->ctrls[AUTOGAIN].val)
autoval = 0x42;
else
autoval = 0x02;
- reg_w(gspca_dev->dev, autoval, 0x0180);
+ reg_w(gspca_dev, autoval, 0x0180);
}
-static void send_unknown(struct usb_device *dev, int sensor)
+static void send_unknown(struct gspca_dev *gspca_dev, int sensor)
{
- reg_w(dev, 0x01, 0x0000); /* led off */
+ reg_w(gspca_dev, 0x01, 0x0000); /* led off */
switch (sensor) {
case SENSOR_PAS106:
- reg_w(dev, 0x03, 0x003a);
- reg_w(dev, 0x0c, 0x003b);
- reg_w(dev, 0x08, 0x0038);
+ reg_w(gspca_dev, 0x03, 0x003a);
+ reg_w(gspca_dev, 0x0c, 0x003b);
+ reg_w(gspca_dev, 0x08, 0x0038);
break;
case SENSOR_ADCM2700:
case SENSOR_GC0305:
case SENSOR_OV7620:
- case SENSOR_MI0360SOC:
+ case SENSOR_MT9V111_1:
+ case SENSOR_MT9V111_3:
case SENSOR_PB0330:
case SENSOR_PO2030:
- reg_w(dev, 0x0d, 0x003a);
- reg_w(dev, 0x02, 0x003b);
- reg_w(dev, 0x00, 0x0038);
+ reg_w(gspca_dev, 0x0d, 0x003a);
+ reg_w(gspca_dev, 0x02, 0x003b);
+ reg_w(gspca_dev, 0x00, 0x0038);
break;
case SENSOR_PAS202B:
- reg_w(dev, 0x03, 0x003b);
- reg_w(dev, 0x0c, 0x003a);
- reg_w(dev, 0x0b, 0x0039);
- reg_w(dev, 0x0b, 0x0038);
+ reg_w(gspca_dev, 0x03, 0x003b);
+ reg_w(gspca_dev, 0x0c, 0x003a);
+ reg_w(gspca_dev, 0x0b, 0x0039);
+ reg_w(gspca_dev, 0x0b, 0x0038);
break;
}
}
/* start probe 2 wires */
-static void start_2wr_probe(struct usb_device *dev, int sensor)
+static void start_2wr_probe(struct gspca_dev *gspca_dev, int sensor)
{
- reg_w(dev, 0x01, 0x0000);
- reg_w(dev, sensor, 0x0010);
- reg_w(dev, 0x01, 0x0001);
- reg_w(dev, 0x03, 0x0012);
- reg_w(dev, 0x01, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0000);
+ reg_w(gspca_dev, sensor, 0x0010);
+ reg_w(gspca_dev, 0x01, 0x0001);
+ reg_w(gspca_dev, 0x03, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0012);
/* msleep(2); */
}
@@ -6268,14 +6132,14 @@ static int sif_probe(struct gspca_dev *gspca_dev)
{
u16 checkword;
- start_2wr_probe(gspca_dev->dev, 0x0f); /* PAS106 */
- reg_w(gspca_dev->dev, 0x08, 0x008d);
+ start_2wr_probe(gspca_dev, 0x0f); /* PAS106 */
+ reg_w(gspca_dev, 0x08, 0x008d);
msleep(150);
checkword = ((i2c_read(gspca_dev, 0x00) & 0x0f) << 4)
| ((i2c_read(gspca_dev, 0x01) & 0xf0) >> 4);
PDEBUG(D_PROBE, "probe sif 0x%04x", checkword);
if (checkword == 0x0007) {
- send_unknown(gspca_dev->dev, SENSOR_PAS106);
+ send_unknown(gspca_dev, SENSOR_PAS106);
return 0x0f; /* PAS106 */
}
return -1;
@@ -6283,23 +6147,22 @@ static int sif_probe(struct gspca_dev *gspca_dev)
static int vga_2wr_probe(struct gspca_dev *gspca_dev)
{
- struct usb_device *dev = gspca_dev->dev;
u16 retword;
- start_2wr_probe(dev, 0x00); /* HV7131B */
+ start_2wr_probe(gspca_dev, 0x00); /* HV7131B */
i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
retword = i2c_read(gspca_dev, 0x01);
if (retword != 0)
return 0x00; /* HV7131B */
- start_2wr_probe(dev, 0x04); /* CS2102 */
+ start_2wr_probe(gspca_dev, 0x04); /* CS2102 */
i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
retword = i2c_read(gspca_dev, 0x01);
if (retword != 0)
return 0x04; /* CS2102 */
- start_2wr_probe(dev, 0x06); /* OmniVision */
- reg_w(dev, 0x08, 0x008d);
+ start_2wr_probe(gspca_dev, 0x06); /* OmniVision */
+ reg_w(gspca_dev, 0x08, 0x008d);
i2c_write(gspca_dev, 0x11, 0xaa, 0x00);
retword = i2c_read(gspca_dev, 0x11);
if (retword != 0) {
@@ -6308,14 +6171,14 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev)
goto ov_check;
}
- start_2wr_probe(dev, 0x08); /* HDCS2020 */
+ start_2wr_probe(gspca_dev, 0x08); /* HDCS2020 */
i2c_write(gspca_dev, 0x1c, 0x00, 0x00);
i2c_write(gspca_dev, 0x15, 0xaa, 0x00);
retword = i2c_read(gspca_dev, 0x15);
if (retword != 0)
return 0x08; /* HDCS2020 */
- start_2wr_probe(dev, 0x0a); /* PB0330 */
+ start_2wr_probe(gspca_dev, 0x0a); /* PB0330 */
i2c_write(gspca_dev, 0x07, 0xaa, 0xaa);
retword = i2c_read(gspca_dev, 0x07);
if (retword != 0)
@@ -6327,23 +6190,23 @@ static int vga_2wr_probe(struct gspca_dev *gspca_dev)
if (retword != 0)
return 0x0a; /* PB0330 ?? */
- start_2wr_probe(dev, 0x0c); /* ICM105A */
+ start_2wr_probe(gspca_dev, 0x0c); /* ICM105A */
i2c_write(gspca_dev, 0x01, 0x11, 0x00);
retword = i2c_read(gspca_dev, 0x01);
if (retword != 0)
return 0x0c; /* ICM105A */
- start_2wr_probe(dev, 0x0e); /* PAS202BCB */
- reg_w(dev, 0x08, 0x008d);
+ start_2wr_probe(gspca_dev, 0x0e); /* PAS202BCB */
+ reg_w(gspca_dev, 0x08, 0x008d);
i2c_write(gspca_dev, 0x03, 0xaa, 0x00);
msleep(50);
retword = i2c_read(gspca_dev, 0x03);
if (retword != 0) {
- send_unknown(dev, SENSOR_PAS202B);
+ send_unknown(gspca_dev, SENSOR_PAS202B);
return 0x0e; /* PAS202BCB */
}
- start_2wr_probe(dev, 0x02); /* TAS5130C */
+ start_2wr_probe(gspca_dev, 0x02); /* TAS5130C */
i2c_write(gspca_dev, 0x01, 0xaa, 0x00);
retword = i2c_read(gspca_dev, 0x01);
if (retword != 0)
@@ -6352,20 +6215,20 @@ ov_check:
reg_r(gspca_dev, 0x0010); /* ?? */
reg_r(gspca_dev, 0x0010);
- reg_w(dev, 0x01, 0x0000);
- reg_w(dev, 0x01, 0x0001);
- reg_w(dev, 0x06, 0x0010); /* OmniVision */
- reg_w(dev, 0xa1, 0x008b);
- reg_w(dev, 0x08, 0x008d);
+ reg_w(gspca_dev, 0x01, 0x0000);
+ reg_w(gspca_dev, 0x01, 0x0001);
+ reg_w(gspca_dev, 0x06, 0x0010); /* OmniVision */
+ reg_w(gspca_dev, 0xa1, 0x008b);
+ reg_w(gspca_dev, 0x08, 0x008d);
msleep(500);
- reg_w(dev, 0x01, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0012);
i2c_write(gspca_dev, 0x12, 0x80, 0x00); /* sensor reset */
retword = i2c_read(gspca_dev, 0x0a) << 8;
retword |= i2c_read(gspca_dev, 0x0b);
PDEBUG(D_PROBE, "probe 2wr ov vga 0x%04x", retword);
switch (retword) {
case 0x7631: /* OV7630C */
- reg_w(dev, 0x06, 0x0010);
+ reg_w(gspca_dev, 0x06, 0x0010);
break;
case 0x7620: /* OV7620 */
case 0x7648: /* OV7648 */
@@ -6382,32 +6245,31 @@ struct sensor_by_chipset_revision {
};
static const struct sensor_by_chipset_revision chipset_revision_sensor[] = {
{0xc000, 0x12}, /* TAS5130C */
- {0xc001, 0x13}, /* MI0360SOC */
+ {0xc001, 0x13}, /* MT9V111 */
{0xe001, 0x13},
{0x8001, 0x13},
{0x8000, 0x14}, /* CS2102K */
- {0x8400, 0x15}, /* TAS5130K */
+ {0x8400, 0x15}, /* MT9V111 */
{0xe400, 0x15},
};
static int vga_3wr_probe(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int i;
u8 retbyte;
u16 retword;
/*fixme: lack of 8b=b3 (11,12)-> 10, 8b=e0 (14,15,16)-> 12 found in gspcav1*/
- reg_w(dev, 0x02, 0x0010);
+ reg_w(gspca_dev, 0x02, 0x0010);
reg_r(gspca_dev, 0x0010);
- reg_w(dev, 0x01, 0x0000);
- reg_w(dev, 0x00, 0x0010);
- reg_w(dev, 0x01, 0x0001);
- reg_w(dev, 0x91, 0x008b);
- reg_w(dev, 0x03, 0x0012);
- reg_w(dev, 0x01, 0x0012);
- reg_w(dev, 0x05, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0000);
+ reg_w(gspca_dev, 0x00, 0x0010);
+ reg_w(gspca_dev, 0x01, 0x0001);
+ reg_w(gspca_dev, 0x91, 0x008b);
+ reg_w(gspca_dev, 0x03, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0012);
+ reg_w(gspca_dev, 0x05, 0x0012);
retword = i2c_read(gspca_dev, 0x14);
if (retword != 0)
return 0x11; /* HV7131R */
@@ -6418,93 +6280,89 @@ static int vga_3wr_probe(struct gspca_dev *gspca_dev)
if (retword != 0)
return 0x11; /* HV7131R */
- reg_w(dev, 0x02, 0x0010);
+ reg_w(gspca_dev, 0x02, 0x0010);
retword = reg_r(gspca_dev, 0x000b) << 8;
retword |= reg_r(gspca_dev, 0x000a);
PDEBUG(D_PROBE, "probe 3wr vga 1 0x%04x", retword);
reg_r(gspca_dev, 0x0010);
- /* value 0x4001 is meaningless */
- if (retword != 0x4001) {
- if ((retword & 0xff00) == 0x6400)
- return 0x02; /* TAS5130C */
- for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
- if (chipset_revision_sensor[i].revision == retword) {
- sd->chip_revision = retword;
- send_unknown(dev, SENSOR_PB0330);
- return chipset_revision_sensor[i]
- .internal_sensor_id;
- }
+ if ((retword & 0xff00) == 0x6400)
+ return 0x02; /* TAS5130C */
+ for (i = 0; i < ARRAY_SIZE(chipset_revision_sensor); i++) {
+ if (chipset_revision_sensor[i].revision == retword) {
+ sd->chip_revision = retword;
+ send_unknown(gspca_dev, SENSOR_PB0330);
+ return chipset_revision_sensor[i].internal_sensor_id;
}
}
- reg_w(dev, 0x01, 0x0000); /* check PB0330 */
- reg_w(dev, 0x01, 0x0001);
- reg_w(dev, 0xdd, 0x008b);
- reg_w(dev, 0x0a, 0x0010);
- reg_w(dev, 0x03, 0x0012);
- reg_w(dev, 0x01, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0000); /* check PB0330 */
+ reg_w(gspca_dev, 0x01, 0x0001);
+ reg_w(gspca_dev, 0xdd, 0x008b);
+ reg_w(gspca_dev, 0x0a, 0x0010);
+ reg_w(gspca_dev, 0x03, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0012);
retword = i2c_read(gspca_dev, 0x00);
if (retword != 0) {
- PDEBUG(D_PROBE, "probe 3wr vga type 0a ?");
+ PDEBUG(D_PROBE, "probe 3wr vga type 0a");
return 0x0a; /* PB0330 */
}
- reg_w(dev, 0x01, 0x0000);
- reg_w(dev, 0x01, 0x0001);
- reg_w(dev, 0x98, 0x008b);
- reg_w(dev, 0x01, 0x0010);
- reg_w(dev, 0x03, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0000);
+ reg_w(gspca_dev, 0x01, 0x0001);
+ reg_w(gspca_dev, 0x98, 0x008b);
+ reg_w(gspca_dev, 0x01, 0x0010);
+ reg_w(gspca_dev, 0x03, 0x0012);
msleep(2);
- reg_w(dev, 0x01, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0012);
retword = i2c_read(gspca_dev, 0x00);
if (retword != 0) {
PDEBUG(D_PROBE, "probe 3wr vga type %02x", retword);
- if (retword == 0x0011) /* VF0250 */
- return 0x0250;
+ if (retword == 0x0011) /* gc0303 */
+ return 0x0303;
if (retword == 0x0029) /* gc0305 */
- send_unknown(dev, SENSOR_GC0305);
+ send_unknown(gspca_dev, SENSOR_GC0305);
return retword;
}
- reg_w(dev, 0x01, 0x0000); /* check OmniVision */
- reg_w(dev, 0x01, 0x0001);
- reg_w(dev, 0xa1, 0x008b);
- reg_w(dev, 0x08, 0x008d);
- reg_w(dev, 0x06, 0x0010);
- reg_w(dev, 0x01, 0x0012);
- reg_w(dev, 0x05, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0000); /* check OmniVision */
+ reg_w(gspca_dev, 0x01, 0x0001);
+ reg_w(gspca_dev, 0xa1, 0x008b);
+ reg_w(gspca_dev, 0x08, 0x008d);
+ reg_w(gspca_dev, 0x06, 0x0010);
+ reg_w(gspca_dev, 0x01, 0x0012);
+ reg_w(gspca_dev, 0x05, 0x0012);
if (i2c_read(gspca_dev, 0x1c) == 0x007f /* OV7610 - manufacturer ID */
&& i2c_read(gspca_dev, 0x1d) == 0x00a2) {
- send_unknown(dev, SENSOR_OV7620);
+ send_unknown(gspca_dev, SENSOR_OV7620);
return 0x06; /* OmniVision confirm ? */
}
- reg_w(dev, 0x01, 0x0000);
- reg_w(dev, 0x00, 0x0002);
- reg_w(dev, 0x01, 0x0010);
- reg_w(dev, 0x01, 0x0001);
- reg_w(dev, 0xee, 0x008b);
- reg_w(dev, 0x03, 0x0012);
- reg_w(dev, 0x01, 0x0012);
- reg_w(dev, 0x05, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0000);
+ reg_w(gspca_dev, 0x00, 0x0002);
+ reg_w(gspca_dev, 0x01, 0x0010);
+ reg_w(gspca_dev, 0x01, 0x0001);
+ reg_w(gspca_dev, 0xee, 0x008b);
+ reg_w(gspca_dev, 0x03, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0012);
+ reg_w(gspca_dev, 0x05, 0x0012);
retword = i2c_read(gspca_dev, 0x00) << 8; /* ID 0 */
retword |= i2c_read(gspca_dev, 0x01); /* ID 1 */
PDEBUG(D_PROBE, "probe 3wr vga 2 0x%04x", retword);
if (retword == 0x2030) {
retbyte = i2c_read(gspca_dev, 0x02); /* revision number */
PDEBUG(D_PROBE, "sensor PO2030 rev 0x%02x", retbyte);
- send_unknown(dev, SENSOR_PO2030);
+ send_unknown(gspca_dev, SENSOR_PO2030);
return retword;
}
- reg_w(dev, 0x01, 0x0000);
- reg_w(dev, 0x0a, 0x0010);
- reg_w(dev, 0xd3, 0x008b);
- reg_w(dev, 0x01, 0x0001);
- reg_w(dev, 0x03, 0x0012);
- reg_w(dev, 0x01, 0x0012);
- reg_w(dev, 0x05, 0x0012);
- reg_w(dev, 0xd3, 0x008b);
+ reg_w(gspca_dev, 0x01, 0x0000);
+ reg_w(gspca_dev, 0x0a, 0x0010);
+ reg_w(gspca_dev, 0xd3, 0x008b);
+ reg_w(gspca_dev, 0x01, 0x0001);
+ reg_w(gspca_dev, 0x03, 0x0012);
+ reg_w(gspca_dev, 0x01, 0x0012);
+ reg_w(gspca_dev, 0x05, 0x0012);
+ reg_w(gspca_dev, 0xd3, 0x008b);
retword = i2c_read(gspca_dev, 0x01);
if (retword != 0) {
PDEBUG(D_PROBE, "probe 3wr vga type 0a ? ret: %04x", retword);
@@ -6521,7 +6379,7 @@ static int zcxx_probeSensor(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_MC501CB:
return -1; /* don't probe */
- case SENSOR_TAS5130C_VF0250:
+ case SENSOR_GC0303:
/* may probe but with no write in reg 0x0010 */
return -1; /* don't probe */
case SENSOR_PAS106:
@@ -6541,54 +6399,70 @@ static int sd_config(struct gspca_dev *gspca_dev,
const struct usb_device_id *id)
{
struct sd *sd = (struct sd *) gspca_dev;
+
+ if (id->idProduct == 0x301b)
+ sd->bridge = BRIDGE_ZC301;
+ else
+ sd->bridge = BRIDGE_ZC303;
+
+ /* define some sensors from the vendor/product */
+ sd->sensor = id->driver_info;
+
+ gspca_dev->cam.ctrls = sd->ctrls;
+ sd->quality = QUALITY_DEF;
+
+ return 0;
+}
+
+/* this function is called at probe and resume time */
+static int sd_init(struct gspca_dev *gspca_dev)
+{
+ struct sd *sd = (struct sd *) gspca_dev;
struct cam *cam;
int sensor;
static const u8 gamma[SENSOR_MAX] = {
- 4, /* SENSOR_ADCM2700 0 */
- 4, /* SENSOR_CS2102 1 */
- 5, /* SENSOR_CS2102K 2 */
- 4, /* SENSOR_GC0305 3 */
- 4, /* SENSOR_HDCS2020b 4 */
- 4, /* SENSOR_HV7131B 5 */
- 4, /* SENSOR_HV7131C 6 */
- 4, /* SENSOR_ICM105A 7 */
- 4, /* SENSOR_MC501CB 8 */
- 4, /* SENSOR_MI0360SOC 9 */
- 3, /* SENSOR_OV7620 10 */
- 4, /* SENSOR_OV7630C 11 */
- 4, /* SENSOR_PAS106 12 */
- 4, /* SENSOR_PAS202B 13 */
- 4, /* SENSOR_PB0330 14 */
- 4, /* SENSOR_PO2030 15 */
- 4, /* SENSOR_TAS5130CK 16 */
- 3, /* SENSOR_TAS5130CXX 17 */
- 3, /* SENSOR_TAS5130C_VF0250 18 */
+ [SENSOR_ADCM2700] = 4,
+ [SENSOR_CS2102] = 4,
+ [SENSOR_CS2102K] = 5,
+ [SENSOR_GC0303] = 3,
+ [SENSOR_GC0305] = 4,
+ [SENSOR_HDCS2020b] = 4,
+ [SENSOR_HV7131B] = 4,
+ [SENSOR_HV7131R] = 4,
+ [SENSOR_ICM105A] = 4,
+ [SENSOR_MC501CB] = 4,
+ [SENSOR_MT9V111_1] = 4,
+ [SENSOR_MT9V111_3] = 4,
+ [SENSOR_OV7620] = 3,
+ [SENSOR_OV7630C] = 4,
+ [SENSOR_PAS106] = 4,
+ [SENSOR_PAS202B] = 4,
+ [SENSOR_PB0330] = 4,
+ [SENSOR_PO2030] = 4,
+ [SENSOR_TAS5130C] = 3,
};
static const u8 mode_tb[SENSOR_MAX] = {
- 2, /* SENSOR_ADCM2700 0 */
- 1, /* SENSOR_CS2102 1 */
- 1, /* SENSOR_CS2102K 2 */
- 1, /* SENSOR_GC0305 3 */
- 1, /* SENSOR_HDCS2020b 4 */
- 1, /* SENSOR_HV7131B 5 */
- 1, /* SENSOR_HV7131C 6 */
- 1, /* SENSOR_ICM105A 7 */
- 2, /* SENSOR_MC501CB 8 */
- 1, /* SENSOR_MI0360SOC 9 */
- 2, /* SENSOR_OV7620 10 */
- 1, /* SENSOR_OV7630C 11 */
- 0, /* SENSOR_PAS106 12 */
- 1, /* SENSOR_PAS202B 13 */
- 1, /* SENSOR_PB0330 14 */
- 1, /* SENSOR_PO2030 15 */
- 1, /* SENSOR_TAS5130CK 16 */
- 1, /* SENSOR_TAS5130CXX 17 */
- 1, /* SENSOR_TAS5130C_VF0250 18 */
+ [SENSOR_ADCM2700] = 2,
+ [SENSOR_CS2102] = 1,
+ [SENSOR_CS2102K] = 1,
+ [SENSOR_GC0303] = 1,
+ [SENSOR_GC0305] = 1,
+ [SENSOR_HDCS2020b] = 1,
+ [SENSOR_HV7131B] = 1,
+ [SENSOR_HV7131R] = 1,
+ [SENSOR_ICM105A] = 1,
+ [SENSOR_MC501CB] = 2,
+ [SENSOR_MT9V111_1] = 1,
+ [SENSOR_MT9V111_3] = 1,
+ [SENSOR_OV7620] = 2,
+ [SENSOR_OV7630C] = 1,
+ [SENSOR_PAS106] = 0,
+ [SENSOR_PAS202B] = 1,
+ [SENSOR_PB0330] = 1,
+ [SENSOR_PO2030] = 1,
+ [SENSOR_TAS5130C] = 1,
};
- /* define some sensors from the vendor/product */
- sd->sharpness = SHARPNESS_DEF;
- sd->sensor = id->driver_info;
sensor = zcxx_probeSensor(gspca_dev);
if (sensor >= 0)
PDEBUG(D_PROBE, "probe sensor -> %04x", sensor);
@@ -6602,13 +6476,12 @@ static int sd_config(struct gspca_dev *gspca_dev,
case SENSOR_MC501CB:
PDEBUG(D_PROBE, "Sensor MC501CB");
break;
- case SENSOR_TAS5130C_VF0250:
- PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)");
+ case SENSOR_GC0303:
+ PDEBUG(D_PROBE, "Sensor GC0303");
break;
default:
- PDEBUG(D_PROBE,
- "Sensor UNKNOWN_0 force Tas5130");
- sd->sensor = SENSOR_TAS5130CXX;
+ warn("Unknown sensor - set to TAS5130C");
+ sd->sensor = SENSOR_TAS5130C;
}
break;
case 0:
@@ -6623,14 +6496,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
break;
default:
/* case 2: * hv7131r */
- PDEBUG(D_PROBE, "Find Sensor HV7131R(c)");
- sd->sensor = SENSOR_HV7131C;
+ PDEBUG(D_PROBE, "Find Sensor HV7131R");
+ sd->sensor = SENSOR_HV7131R;
break;
}
break;
case 0x02:
PDEBUG(D_PROBE, "Sensor TAS5130C");
- sd->sensor = SENSOR_TAS5130CXX;
+ sd->sensor = SENSOR_TAS5130C;
break;
case 0x04:
PDEBUG(D_PROBE, "Find Sensor CS2102");
@@ -6662,17 +6535,20 @@ static int sd_config(struct gspca_dev *gspca_dev,
case 0x10:
case 0x12:
PDEBUG(D_PROBE, "Find Sensor TAS5130C");
- sd->sensor = SENSOR_TAS5130CXX;
+ sd->sensor = SENSOR_TAS5130C;
break;
case 0x11:
- PDEBUG(D_PROBE, "Find Sensor HV7131R(c)");
- sd->sensor = SENSOR_HV7131C;
+ PDEBUG(D_PROBE, "Find Sensor HV7131R");
+ sd->sensor = SENSOR_HV7131R;
break;
case 0x13:
+ case 0x15:
PDEBUG(D_PROBE,
- "Find Sensor MI0360SOC. Chip revision %x",
+ "Sensor MT9V111. Chip revision %04x",
sd->chip_revision);
- sd->sensor = SENSOR_MI0360SOC;
+ sd->sensor = sd->bridge == BRIDGE_ZC301
+ ? SENSOR_MT9V111_1
+ : SENSOR_MT9V111_3;
break;
case 0x14:
PDEBUG(D_PROBE,
@@ -6680,12 +6556,6 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->chip_revision);
sd->sensor = SENSOR_CS2102K;
break;
- case 0x15:
- PDEBUG(D_PROBE,
- "Find Sensor TAS5130CK?. Chip revision %x",
- sd->chip_revision);
- sd->sensor = SENSOR_TAS5130CK;
- break;
case 0x16:
PDEBUG(D_PROBE, "Find Sensor ADCM2700");
sd->sensor = SENSOR_ADCM2700;
@@ -6694,14 +6564,14 @@ static int sd_config(struct gspca_dev *gspca_dev,
PDEBUG(D_PROBE, "Find Sensor GC0305");
sd->sensor = SENSOR_GC0305;
break;
- case 0x0250:
- PDEBUG(D_PROBE, "Sensor Tas5130 (VF0250)");
- sd->sensor = SENSOR_TAS5130C_VF0250;
+ case 0x0303:
+ PDEBUG(D_PROBE, "Sensor GC0303");
+ sd->sensor = SENSOR_GC0303;
break;
case 0x2030:
PDEBUG(D_PROBE, "Find Sensor PO2030");
sd->sensor = SENSOR_PO2030;
- sd->sharpness = 0; /* from win traces */
+ sd->ctrls[SHARPNESS].def = 0; /* from win traces */
break;
case 0x7620:
PDEBUG(D_PROBE, "Find Sensor OV7620");
@@ -6716,19 +6586,17 @@ static int sd_config(struct gspca_dev *gspca_dev,
sd->sensor = SENSOR_OV7620; /* same sensor (?) */
break;
default:
- PDEBUG(D_ERR|D_PROBE, "Unknown sensor %04x", sensor);
+ err("Unknown sensor %04x", sensor);
return -EINVAL;
}
}
if (sensor < 0x20) {
if (sensor == -1 || sensor == 0x10 || sensor == 0x12)
- reg_w(gspca_dev->dev, 0x02, 0x0010);
+ reg_w(gspca_dev, 0x02, 0x0010);
reg_r(gspca_dev, 0x0010);
}
cam = &gspca_dev->cam;
-/*fixme:test*/
- gspca_dev->nbalt--;
switch (mode_tb[sd->sensor]) {
case 0:
cam->cam_mode = sif_mode;
@@ -6744,70 +6612,73 @@ static int sd_config(struct gspca_dev *gspca_dev,
cam->nmodes = ARRAY_SIZE(broken_vga_mode);
break;
}
- sd->contrast = CONTRAST_DEF;
- sd->gamma = gamma[sd->sensor];
- sd->autogain = AUTOGAIN_DEF;
- sd->lightfreq = FREQ_DEF;
- sd->quality = QUALITY_DEF;
+
+ sd->ctrls[GAMMA].def = gamma[sd->sensor];
switch (sd->sensor) {
- case SENSOR_HV7131B:
- case SENSOR_HV7131C:
case SENSOR_OV7630C:
- gspca_dev->ctrl_dis = (1 << LIGHTFREQ_IDX);
+ gspca_dev->ctrl_dis = (1 << LIGHTFREQ);
break;
}
- return 0;
-}
-
-/* this function is called at probe and resume time */
-static int sd_init(struct gspca_dev *gspca_dev)
-{
/* switch off the led */
- reg_w(gspca_dev->dev, 0x01, 0x0000);
- return 0;
+ reg_w(gspca_dev, 0x01, 0x0000);
+ return gspca_dev->usb_err;
}
static int sd_start(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- struct usb_device *dev = gspca_dev->dev;
int mode;
static const struct usb_action *init_tb[SENSOR_MAX][2] = {
- {adcm2700_Initial, adcm2700_InitialScale}, /* 0 */
- {cs2102_Initial, cs2102_InitialScale}, /* 1 */
- {cs2102K_Initial, cs2102K_InitialScale}, /* 2 */
- {gc0305_Initial, gc0305_InitialScale}, /* 3 */
- {hdcs2020b_Initial, hdcs2020b_InitialScale}, /* 4 */
- {hv7131b_Initial, hv7131b_InitialScale}, /* 5 */
- {hv7131r_Initial, hv7131r_InitialScale}, /* 6 */
- {icm105a_Initial, icm105a_InitialScale}, /* 7 */
- {mc501cb_Initial, mc501cb_InitialScale}, /* 8 */
- {mi0360soc_Initial, mi0360soc_InitialScale}, /* 9 */
- {ov7620_Initial, ov7620_InitialScale}, /* 10 */
- {ov7630c_Initial, ov7630c_InitialScale}, /* 11 */
- {pas106b_Initial, pas106b_InitialScale}, /* 12 */
- {pas202b_Initial, pas202b_InitialScale}, /* 13 */
- {pb0330_Initial, pb0330_InitialScale}, /* 14 */
- {po2030_Initial, po2030_InitialScale}, /* 15 */
- {tas5130cK_Initial, tas5130cK_InitialScale}, /* 16 */
- {tas5130cxx_Initial, tas5130cxx_InitialScale}, /* 17 */
- {tas5130c_vf0250_Initial, tas5130c_vf0250_InitialScale},
- /* 18 */
+ [SENSOR_ADCM2700] =
+ {adcm2700_Initial, adcm2700_InitialScale},
+ [SENSOR_CS2102] =
+ {cs2102_Initial, cs2102_InitialScale},
+ [SENSOR_CS2102K] =
+ {cs2102K_Initial, cs2102K_InitialScale},
+ [SENSOR_GC0303] =
+ {gc0303_Initial, gc0303_InitialScale},
+ [SENSOR_GC0305] =
+ {gc0305_Initial, gc0305_InitialScale},
+ [SENSOR_HDCS2020b] =
+ {hdcs2020b_Initial, hdcs2020b_InitialScale},
+ [SENSOR_HV7131B] =
+ {hv7131b_Initial, hv7131b_InitialScale},
+ [SENSOR_HV7131R] =
+ {hv7131r_Initial, hv7131r_InitialScale},
+ [SENSOR_ICM105A] =
+ {icm105a_Initial, icm105a_InitialScale},
+ [SENSOR_MC501CB] =
+ {mc501cb_Initial, mc501cb_InitialScale},
+ [SENSOR_MT9V111_1] =
+ {mt9v111_1_Initial, mt9v111_1_InitialScale},
+ [SENSOR_MT9V111_3] =
+ {mt9v111_3_Initial, mt9v111_3_InitialScale},
+ [SENSOR_OV7620] =
+ {ov7620_Initial, ov7620_InitialScale},
+ [SENSOR_OV7630C] =
+ {ov7630c_Initial, ov7630c_InitialScale},
+ [SENSOR_PAS106] =
+ {pas106b_Initial, pas106b_InitialScale},
+ [SENSOR_PAS202B] =
+ {pas202b_Initial, pas202b_InitialScale},
+ [SENSOR_PB0330] =
+ {pb0330_Initial, pb0330_InitialScale},
+ [SENSOR_PO2030] =
+ {po2030_Initial, po2030_InitialScale},
+ [SENSOR_TAS5130C] =
+ {tas5130c_Initial, tas5130c_InitialScale},
};
/* create the JPEG header */
- sd->jpeg_hdr = kmalloc(JPEG_HDR_SZ, GFP_KERNEL);
- if (!sd->jpeg_hdr)
- return -ENOMEM;
jpeg_define(sd->jpeg_hdr, gspca_dev->height, gspca_dev->width,
0x21); /* JPEG 422 */
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
mode = gspca_dev->cam.cam_mode[gspca_dev->curr_mode].priv;
switch (sd->sensor) {
- case SENSOR_HV7131C:
+ case SENSOR_HV7131R:
zcxx_probeSensor(gspca_dev);
break;
case SENSOR_PAS106:
@@ -6821,22 +6692,22 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_GC0305:
case SENSOR_OV7620:
case SENSOR_PO2030:
- case SENSOR_TAS5130CXX:
- case SENSOR_TAS5130C_VF0250:
+ case SENSOR_TAS5130C:
+ case SENSOR_GC0303:
/* msleep(100); * ?? */
reg_r(gspca_dev, 0x0002); /* --> 0x40 */
- reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
- reg_w(dev, 0x15, 0x01ae);
- if (sd->sensor == SENSOR_TAS5130CXX)
+ reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(gspca_dev, 0x15, 0x01ae);
+ if (sd->sensor == SENSOR_TAS5130C)
break;
- reg_w(dev, 0x0d, 0x003a);
- reg_w(dev, 0x02, 0x003b);
- reg_w(dev, 0x00, 0x0038);
+ reg_w(gspca_dev, 0x0d, 0x003a);
+ reg_w(gspca_dev, 0x02, 0x003b);
+ reg_w(gspca_dev, 0x00, 0x0038);
break;
case SENSOR_PAS202B:
- reg_w(dev, 0x03, 0x003b);
- reg_w(dev, 0x0c, 0x003a);
- reg_w(dev, 0x0b, 0x0039);
+ reg_w(gspca_dev, 0x03, 0x003b);
+ reg_w(gspca_dev, 0x0c, 0x003a);
+ reg_w(gspca_dev, 0x0b, 0x0039);
break;
}
@@ -6845,15 +6716,15 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_ADCM2700:
case SENSOR_OV7620:
reg_r(gspca_dev, 0x0008);
- reg_w(dev, 0x00, 0x0008);
+ reg_w(gspca_dev, 0x00, 0x0008);
break;
case SENSOR_PAS202B:
case SENSOR_GC0305:
- case SENSOR_TAS5130CXX:
+ case SENSOR_TAS5130C:
reg_r(gspca_dev, 0x0008);
/* fall thru */
case SENSOR_PO2030:
- reg_w(dev, 0x03, 0x0008);
+ reg_w(gspca_dev, 0x03, 0x0008);
break;
}
setsharpness(gspca_dev);
@@ -6863,7 +6734,6 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_CS2102K: /* gamma set in xxx_Initial */
case SENSOR_HDCS2020b:
case SENSOR_OV7630C:
- case SENSOR_TAS5130CK:
break;
default:
setcontrast(gspca_dev);
@@ -6874,7 +6744,7 @@ static int sd_start(struct gspca_dev *gspca_dev)
case SENSOR_OV7620:
case SENSOR_PAS202B:
reg_r(gspca_dev, 0x0180); /* from win */
- reg_w(dev, 0x00, 0x0180);
+ reg_w(gspca_dev, 0x00, 0x0180);
break;
default:
setquality(gspca_dev);
@@ -6884,29 +6754,29 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_ADCM2700:
- reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
- reg_w(dev, 0x15, 0x01ae);
- reg_w(dev, 0x02, 0x0180);
+ reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(gspca_dev, 0x15, 0x01ae);
+ reg_w(gspca_dev, 0x02, 0x0180);
/* ms-win + */
- reg_w(dev, 0x40, 0x0117);
+ reg_w(gspca_dev, 0x40, 0x0117);
break;
case SENSOR_GC0305:
- case SENSOR_TAS5130CXX:
- reg_w(dev, 0x09, 0x01ad); /* (from win traces) */
- reg_w(dev, 0x15, 0x01ae);
+ case SENSOR_TAS5130C:
+ reg_w(gspca_dev, 0x09, 0x01ad); /* (from win traces) */
+ reg_w(gspca_dev, 0x15, 0x01ae);
/* fall thru */
case SENSOR_PAS202B:
case SENSOR_PO2030:
-/* reg_w(dev, 0x40, ZC3XX_R117_GGAIN); * (from win traces) */
+/* reg_w(gspca_dev, 0x40, ZC3XX_R117_GGAIN); in win traces */
reg_r(gspca_dev, 0x0180);
break;
case SENSOR_OV7620:
- reg_w(dev, 0x09, 0x01ad);
- reg_w(dev, 0x15, 0x01ae);
+ reg_w(gspca_dev, 0x09, 0x01ad);
+ reg_w(gspca_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);
+ /*fixme: returned value to send? */
+ reg_w(gspca_dev, 0x40, 0x0117);
reg_r(gspca_dev, 0x0180);
break;
}
@@ -6915,15 +6785,11 @@ static int sd_start(struct gspca_dev *gspca_dev)
switch (sd->sensor) {
case SENSOR_PO2030:
msleep(50);
- reg_w(dev, 0x00, 0x0007); /* (from win traces) */
- reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
- break;
- case SENSOR_PAS202B:
- reg_w(dev, 0x32, 0x0007); /* (from win traces) */
- reg_w(dev, 0x02, ZC3XX_R008_CLOCKSETTING);
+ reg_w(gspca_dev, 0x00, 0x0007); /* (from win traces) */
+ reg_w(gspca_dev, 0x02, ZC3XX_R008_CLOCKSETTING);
break;
}
- return 0;
+ return gspca_dev->usb_err;
}
/* called on streamoff with alt 0 and on disconnect */
@@ -6931,10 +6797,9 @@ static void sd_stop0(struct gspca_dev *gspca_dev)
{
struct sd *sd = (struct sd *) gspca_dev;
- kfree(sd->jpeg_hdr);
if (!gspca_dev->present)
return;
- send_unknown(gspca_dev->dev, sd->sensor);
+ send_unknown(gspca_dev, sd->sensor);
}
static void sd_pkt_scan(struct gspca_dev *gspca_dev,
@@ -6953,7 +6818,7 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
/* remove the webcam's header:
* ff d8 ff fe 00 0e 00 00 ss ss 00 01 ww ww hh hh pp pp
* - 'ss ss' is the frame sequence number (BE)
- * - 'ww ww' and 'hh hh' are the window dimensions (BE)
+ * - 'ww ww' and 'hh hh' are the window dimensions (BE)
* - 'pp pp' is the packet sequence number (BE)
*/
data += 18;
@@ -6962,96 +6827,6 @@ static void sd_pkt_scan(struct gspca_dev *gspca_dev,
gspca_frame_add(gspca_dev, INTER_PACKET, data, len);
}
-static int sd_setcontrast(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->contrast = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return 0;
-}
-
-static int sd_getcontrast(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->contrast;
- return 0;
-}
-
-static int sd_setautogain(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->autogain = val;
- if (gspca_dev->streaming)
- setautogain(gspca_dev);
- return 0;
-}
-
-static int sd_getautogain(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->autogain;
- return 0;
-}
-
-static int sd_setgamma(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->gamma = val;
- if (gspca_dev->streaming)
- setcontrast(gspca_dev);
- return 0;
-}
-
-static int sd_getgamma(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->gamma;
- return 0;
-}
-
-static int sd_setfreq(struct gspca_dev *gspca_dev, __s32 val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- sd->lightfreq = val;
- if (gspca_dev->streaming)
- setlightfreq(gspca_dev);
- return 0;
-}
-
-static int sd_getfreq(struct gspca_dev *gspca_dev, __s32 *val)
-{
- struct sd *sd = (struct sd *) gspca_dev;
-
- *val = sd->lightfreq;
- 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)
{
@@ -7086,7 +6861,7 @@ static int sd_set_jcomp(struct gspca_dev *gspca_dev,
sd->quality = jcomp->quality;
if (gspca_dev->streaming)
jpeg_set_qual(sd->jpeg_hdr, sd->quality);
- return 0;
+ return gspca_dev->usb_err;
}
static int sd_get_jcomp(struct gspca_dev *gspca_dev,
@@ -7101,7 +6876,7 @@ static int sd_get_jcomp(struct gspca_dev *gspca_dev,
return 0;
}
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
static int sd_int_pkt_scan(struct gspca_dev *gspca_dev,
u8 *data, /* interrupt packet data */
int len) /* interrput packet length */
@@ -7129,12 +6904,12 @@ static const struct sd_desc sd_desc = {
.querymenu = sd_querymenu,
.get_jcomp = sd_get_jcomp,
.set_jcomp = sd_set_jcomp,
-#ifdef CONFIG_INPUT
+#if defined(CONFIG_INPUT) || defined(CONFIG_INPUT_MODULE)
.int_pkt_scan = sd_int_pkt_scan,
#endif
};
-static const __devinitdata struct usb_device_id device_table[] = {
+static const struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x041e)},
{USB_DEVICE(0x041e, 0x4017)},
{USB_DEVICE(0x041e, 0x401c), .driver_info = SENSOR_PAS106},
@@ -7146,8 +6921,8 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x041e, 0x4035), .driver_info = SENSOR_PAS106},
{USB_DEVICE(0x041e, 0x4036)},
{USB_DEVICE(0x041e, 0x403a)},
- {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_TAS5130C_VF0250},
- {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_TAS5130C_VF0250},
+ {USB_DEVICE(0x041e, 0x4051), .driver_info = SENSOR_GC0303},
+ {USB_DEVICE(0x041e, 0x4053), .driver_info = SENSOR_GC0303},
{USB_DEVICE(0x0458, 0x7007)},
{USB_DEVICE(0x0458, 0x700c)},
{USB_DEVICE(0x0458, 0x700f)},
@@ -7163,14 +6938,12 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x046d, 0x08aa)},
{USB_DEVICE(0x046d, 0x08ac)},
{USB_DEVICE(0x046d, 0x08ad)},
-#if !defined CONFIG_USB_ZC0301 && !defined CONFIG_USB_ZC0301_MODULE
{USB_DEVICE(0x046d, 0x08ae)},
-#endif
{USB_DEVICE(0x046d, 0x08af)},
{USB_DEVICE(0x046d, 0x08b9)},
{USB_DEVICE(0x046d, 0x08d7)},
- {USB_DEVICE(0x046d, 0x08d9)},
{USB_DEVICE(0x046d, 0x08d8)},
+ {USB_DEVICE(0x046d, 0x08d9)},
{USB_DEVICE(0x046d, 0x08da)},
{USB_DEVICE(0x046d, 0x08dd), .driver_info = SENSOR_MC501CB},
{USB_DEVICE(0x0471, 0x0325), .driver_info = SENSOR_PAS106},
@@ -7192,7 +6965,6 @@ static const __devinitdata struct usb_device_id device_table[] = {
{USB_DEVICE(0x10fd, 0x8050)},
{} /* end of entry */
};
-#undef DVNAME
MODULE_DEVICE_TABLE(usb, device_table);
/* -- device connect -- */
@@ -7217,18 +6989,12 @@ static struct usb_driver sd_driver = {
static int __init sd_mod_init(void)
{
- int ret;
- ret = usb_register(&sd_driver);
- if (ret < 0)
- return ret;
- PDEBUG(D_PROBE, "registered");
- return 0;
+ return usb_register(&sd_driver);
}
static void __exit sd_mod_exit(void)
{
usb_deregister(&sd_driver);
- PDEBUG(D_PROBE, "deregistered");
}
module_init(sd_mod_init);
diff --git a/drivers/media/video/hdpvr/Makefile b/drivers/media/video/hdpvr/Makefile
index e0230fcb2e36..3baa9f613ca3 100644
--- a/drivers/media/video/hdpvr/Makefile
+++ b/drivers/media/video/hdpvr/Makefile
@@ -1,6 +1,4 @@
-hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o
-
-hdpvr-$(CONFIG_I2C) += hdpvr-i2c.o
+hdpvr-objs := hdpvr-control.o hdpvr-core.o hdpvr-video.o hdpvr-i2c.o
obj-$(CONFIG_VIDEO_HDPVR) += hdpvr.o
diff --git a/drivers/media/video/hdpvr/hdpvr-control.c b/drivers/media/video/hdpvr/hdpvr-control.c
index 5a6b78b8d25d..068df4ba3f51 100644
--- a/drivers/media/video/hdpvr/hdpvr-control.c
+++ b/drivers/media/video/hdpvr/hdpvr-control.c
@@ -29,8 +29,6 @@ int hdpvr_config_call(struct hdpvr_device *dev, uint value, u8 valbuf)
int ret;
char request_type = 0x38, snd_request = 0x01;
- msleep(10);
-
mutex_lock(&dev->usbc_mutex);
dev->usbc_buf[0] = valbuf;
ret = usb_control_msg(dev->udev,
@@ -170,8 +168,7 @@ int hdpvr_set_audio(struct hdpvr_device *dev, u8 input,
if (ret == 2)
ret = 0;
} else
- ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE,
- dev->options.audio_input+1);
+ ret = hdpvr_config_call(dev, CTRL_AUDIO_INPUT_VALUE, input);
error:
return ret;
}
diff --git a/drivers/media/video/hdpvr/hdpvr-core.c b/drivers/media/video/hdpvr/hdpvr-core.c
index 830d47b05e1d..a6572e5ae369 100644
--- a/drivers/media/video/hdpvr/hdpvr-core.c
+++ b/drivers/media/video/hdpvr/hdpvr-core.c
@@ -60,6 +60,7 @@ static struct usb_device_id hdpvr_table[] = {
{ USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID1) },
{ USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID2) },
{ USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID3) },
+ { USB_DEVICE(HD_PVR_VENDOR_ID, HD_PVR_PRODUCT_ID4) },
{ } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, hdpvr_table);
@@ -152,19 +153,26 @@ static int device_authorization(struct hdpvr_device *dev)
ret, print_buf);
}
#endif
- if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION) {
+
+ v4l2_info(&dev->v4l2_dev, "firmware version 0x%x dated %s\n",
+ dev->usbc_buf[1], &dev->usbc_buf[2]);
+
+ switch (dev->usbc_buf[1]) {
+ case HDPVR_FIRMWARE_VERSION:
dev->flags &= ~HDPVR_FLAG_AC3_CAP;
- } else if (dev->usbc_buf[1] == HDPVR_FIRMWARE_VERSION_AC3) {
+ break;
+ case HDPVR_FIRMWARE_VERSION_AC3:
+ case HDPVR_FIRMWARE_VERSION_0X12:
+ case HDPVR_FIRMWARE_VERSION_0X15:
dev->flags |= HDPVR_FLAG_AC3_CAP;
- } else if (dev->usbc_buf[1] > HDPVR_FIRMWARE_VERSION_AC3) {
- v4l2_info(&dev->v4l2_dev, "untested firmware version 0x%x, "
- "the driver might not work\n", dev->usbc_buf[1]);
- dev->flags |= HDPVR_FLAG_AC3_CAP;
- } else {
- v4l2_err(&dev->v4l2_dev, "unknown firmware version 0x%x\n",
- dev->usbc_buf[1]);
- ret = -EINVAL;
- goto unlock;
+ break;
+ default:
+ v4l2_info(&dev->v4l2_dev, "untested firmware, the driver might"
+ " not work.\n");
+ if (dev->usbc_buf[1] >= HDPVR_FIRMWARE_VERSION_AC3)
+ dev->flags |= HDPVR_FLAG_AC3_CAP;
+ else
+ dev->flags &= ~HDPVR_FLAG_AC3_CAP;
}
response = dev->usbc_buf+38;
@@ -286,6 +294,8 @@ static int hdpvr_probe(struct usb_interface *interface,
goto error;
}
+ dev->workqueue = 0;
+
/* register v4l2_device early so it can be used for printks */
if (v4l2_device_register(&interface->dev, &dev->v4l2_dev)) {
err("v4l2_device_register failed");
@@ -317,8 +327,12 @@ static int hdpvr_probe(struct usb_interface *interface,
if (default_video_input < HDPVR_VIDEO_INPUTS)
dev->options.video_input = default_video_input;
- if (default_audio_input < HDPVR_AUDIO_INPUTS)
+ if (default_audio_input < HDPVR_AUDIO_INPUTS) {
dev->options.audio_input = default_audio_input;
+ if (default_audio_input == HDPVR_SPDIF)
+ dev->options.audio_codec =
+ V4L2_MPEG_AUDIO_ENCODING_AC3;
+ }
dev->udev = usb_get_dev(interface_to_usbdev(interface));
@@ -364,14 +378,17 @@ static int hdpvr_probe(struct usb_interface *interface,
goto error;
}
-#ifdef CONFIG_I2C
- /* until i2c is working properly */
- retval = 0; /* hdpvr_register_i2c_adapter(dev); */
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+ retval = hdpvr_register_i2c_adapter(dev);
if (retval < 0) {
v4l2_err(&dev->v4l2_dev, "registering i2c adapter failed\n");
goto error;
}
-#endif /* CONFIG_I2C */
+
+ retval = hdpvr_register_i2c_ir(dev);
+ if (retval < 0)
+ v4l2_err(&dev->v4l2_dev, "registering i2c IR devices failed\n");
+#endif
/* let the user know what node this device is now attached to */
v4l2_info(&dev->v4l2_dev, "device now attached to %s\n",
@@ -380,6 +397,9 @@ static int hdpvr_probe(struct usb_interface *interface,
error:
if (dev) {
+ /* Destroy single thread */
+ if (dev->workqueue)
+ destroy_workqueue(dev->workqueue);
/* this frees allocated memory */
hdpvr_delete(dev);
}
diff --git a/drivers/media/video/hdpvr/hdpvr-i2c.c b/drivers/media/video/hdpvr/hdpvr-i2c.c
index 463b81bef6e2..89b71faeaac2 100644
--- a/drivers/media/video/hdpvr/hdpvr-i2c.c
+++ b/drivers/media/video/hdpvr/hdpvr-i2c.c
@@ -4,12 +4,17 @@
*
* Copyright (C) 2008 Janne Grunau (j@jannau.net)
*
+ * IR device registration code is
+ * Copyright (C) 2010 Andy Walls <awalls@md.metrocast.net>
+ *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation, version 2.
*
*/
+#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+
#include <linux/i2c.h>
#include <linux/slab.h>
@@ -22,59 +27,81 @@
#define REQTYPE_I2C_WRITE 0xb0
#define REQTYPE_I2C_WRITE_STATT 0xd0
-static int hdpvr_i2c_read(struct hdpvr_device *dev, unsigned char addr,
- char *data, int len)
+#define Z8F0811_IR_TX_I2C_ADDR 0x70
+#define Z8F0811_IR_RX_I2C_ADDR 0x71
+
+
+static struct i2c_board_info hdpvr_i2c_board_info = {
+ I2C_BOARD_INFO("ir_tx_z8f0811_hdpvr", Z8F0811_IR_TX_I2C_ADDR),
+ I2C_BOARD_INFO("ir_rx_z8f0811_hdpvr", Z8F0811_IR_RX_I2C_ADDR),
+};
+
+int hdpvr_register_i2c_ir(struct hdpvr_device *dev)
+{
+ struct i2c_client *c;
+ struct IR_i2c_init_data *init_data = &dev->ir_i2c_init_data;
+
+ /* Our default information for ir-kbd-i2c.c to use */
+ init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = "HD PVR";
+ hdpvr_i2c_board_info.platform_data = init_data;
+
+ c = i2c_new_device(&dev->i2c_adapter, &hdpvr_i2c_board_info);
+
+ return (c == NULL) ? -ENODEV : 0;
+}
+
+static int hdpvr_i2c_read(struct hdpvr_device *dev, int bus,
+ unsigned char addr, char *data, int len)
{
int ret;
- char *buf = kmalloc(len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
+
+ if (len > sizeof(dev->i2c_buf))
+ return -EINVAL;
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
REQTYPE_I2C_READ, CTRL_READ_REQUEST,
- 0x100|addr, 0, buf, len, 1000);
+ (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
if (ret == len) {
- memcpy(data, buf, len);
+ memcpy(data, &dev->i2c_buf, len);
ret = 0;
} else if (ret >= 0)
ret = -EIO;
- kfree(buf);
-
return ret;
}
-static int hdpvr_i2c_write(struct hdpvr_device *dev, unsigned char addr,
- char *data, int len)
+static int hdpvr_i2c_write(struct hdpvr_device *dev, int bus,
+ unsigned char addr, char *data, int len)
{
int ret;
- char *buf = kmalloc(len, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
- memcpy(buf, data, len);
+ if (len > sizeof(dev->i2c_buf))
+ return -EINVAL;
+
+ memcpy(&dev->i2c_buf, data, len);
ret = usb_control_msg(dev->udev,
usb_sndctrlpipe(dev->udev, 0),
REQTYPE_I2C_WRITE, CTRL_WRITE_REQUEST,
- 0x100|addr, 0, buf, len, 1000);
+ (bus << 8) | addr, 0, &dev->i2c_buf, len, 1000);
if (ret < 0)
- goto error;
+ return ret;
ret = usb_control_msg(dev->udev,
usb_rcvctrlpipe(dev->udev, 0),
REQTYPE_I2C_WRITE_STATT, CTRL_READ_REQUEST,
- 0, 0, buf, 2, 1000);
+ 0, 0, &dev->i2c_buf, 2, 1000);
- if (ret == 2)
+ if ((ret == 2) && (dev->i2c_buf[1] == (len - 1)))
ret = 0;
else if (ret >= 0)
ret = -EIO;
-error:
- kfree(buf);
return ret;
}
@@ -93,10 +120,10 @@ static int hdpvr_transfer(struct i2c_adapter *i2c_adapter, struct i2c_msg *msgs,
addr = msgs[i].addr << 1;
if (msgs[i].flags & I2C_M_RD)
- retval = hdpvr_i2c_read(dev, addr, msgs[i].buf,
+ retval = hdpvr_i2c_read(dev, 1, addr, msgs[i].buf,
msgs[i].len);
else
- retval = hdpvr_i2c_write(dev, addr, msgs[i].buf,
+ retval = hdpvr_i2c_write(dev, 1, addr, msgs[i].buf,
msgs[i].len);
}
@@ -115,31 +142,47 @@ static struct i2c_algorithm hdpvr_algo = {
.functionality = hdpvr_functionality,
};
+static struct i2c_adapter hdpvr_i2c_adapter_template = {
+ .name = "Hauppage HD PVR I2C",
+ .owner = THIS_MODULE,
+ .algo = &hdpvr_algo,
+};
+
+static int hdpvr_activate_ir(struct hdpvr_device *dev)
+{
+ char buffer[8];
+
+ mutex_lock(&dev->i2c_mutex);
+
+ hdpvr_i2c_read(dev, 0, 0x54, buffer, 1);
+
+ buffer[0] = 0;
+ buffer[1] = 0x8;
+ hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
+
+ buffer[1] = 0x18;
+ hdpvr_i2c_write(dev, 1, 0x54, buffer, 2);
+
+ mutex_unlock(&dev->i2c_mutex);
+
+ return 0;
+}
+
int hdpvr_register_i2c_adapter(struct hdpvr_device *dev)
{
- struct i2c_adapter *i2c_adap;
int retval = -ENOMEM;
- i2c_adap = kzalloc(sizeof(struct i2c_adapter), GFP_KERNEL);
- if (i2c_adap == NULL)
- goto error;
-
- strlcpy(i2c_adap->name, "Hauppauge HD PVR I2C",
- sizeof(i2c_adap->name));
- i2c_adap->algo = &hdpvr_algo;
- i2c_adap->class = I2C_CLASS_TV_ANALOG;
- i2c_adap->owner = THIS_MODULE;
- i2c_adap->dev.parent = &dev->udev->dev;
+ hdpvr_activate_ir(dev);
- i2c_set_adapdata(i2c_adap, dev);
+ memcpy(&dev->i2c_adapter, &hdpvr_i2c_adapter_template,
+ sizeof(struct i2c_adapter));
+ dev->i2c_adapter.dev.parent = &dev->udev->dev;
- retval = i2c_add_adapter(i2c_adap);
+ i2c_set_adapdata(&dev->i2c_adapter, dev);
- if (!retval)
- dev->i2c_adapter = i2c_adap;
- else
- kfree(i2c_adap);
+ retval = i2c_add_adapter(&dev->i2c_adapter);
-error:
return retval;
}
+
+#endif
diff --git a/drivers/media/video/hdpvr/hdpvr-video.c b/drivers/media/video/hdpvr/hdpvr-video.c
index 7cfccfd1b870..514aea76eaa5 100644
--- a/drivers/media/video/hdpvr/hdpvr-video.c
+++ b/drivers/media/video/hdpvr/hdpvr-video.c
@@ -26,7 +26,7 @@
#include <media/v4l2-ioctl.h>
#include "hdpvr.h"
-#define BULK_URB_TIMEOUT 1250 /* 1.25 seconds */
+#define BULK_URB_TIMEOUT 90 /* 0.09 seconds */
#define print_buffer_status() { \
v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev, \
@@ -157,6 +157,7 @@ int hdpvr_alloc_buffers(struct hdpvr_device *dev, uint count)
mem, dev->bulk_in_size,
hdpvr_read_bulk_callback, buf);
+ buf->urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
buf->status = BUFSTAT_AVAILABLE;
list_add_tail(&buf->buff_list, &dev->free_buff_list);
}
@@ -337,8 +338,6 @@ static int hdpvr_stop_streaming(struct hdpvr_device *dev)
dev->bulk_in_endpointAddr),
buf, dev->bulk_in_size, &actual_length,
BULK_URB_TIMEOUT)) {
- /* wait */
- msleep(5);
v4l2_dbg(MSG_BUFFER, hdpvr_debug, &dev->v4l2_dev,
"%2d: got %d bytes\n", c, actual_length);
}
@@ -366,7 +365,7 @@ static int hdpvr_open(struct file *file)
dev = (struct hdpvr_device *)video_get_drvdata(video_devdata(file));
if (!dev) {
- v4l2_err(&dev->v4l2_dev, "open failing with with ENODEV\n");
+ pr_err("open failing with with ENODEV\n");
retval = -ENODEV;
goto err;
}
@@ -394,7 +393,7 @@ err:
static int hdpvr_release(struct file *file)
{
- struct hdpvr_fh *fh = (struct hdpvr_fh *)file->private_data;
+ struct hdpvr_fh *fh = file->private_data;
struct hdpvr_device *dev = fh->dev;
if (!dev)
@@ -518,7 +517,7 @@ err:
static unsigned int hdpvr_poll(struct file *filp, poll_table *wait)
{
struct hdpvr_buffer *buf = NULL;
- struct hdpvr_fh *fh = (struct hdpvr_fh *)filp->private_data;
+ struct hdpvr_fh *fh = filp->private_data;
struct hdpvr_device *dev = fh->dev;
unsigned int mask = 0;
@@ -1221,12 +1220,9 @@ static void hdpvr_device_release(struct video_device *vdev)
v4l2_device_unregister(&dev->v4l2_dev);
/* deregister I2C adapter */
-#ifdef CONFIG_I2C
+#if defined(CONFIG_I2C) || (CONFIG_I2C_MODULE)
mutex_lock(&dev->i2c_mutex);
- if (dev->i2c_adapter)
- i2c_del_adapter(dev->i2c_adapter);
- kfree(dev->i2c_adapter);
- dev->i2c_adapter = NULL;
+ i2c_del_adapter(&dev->i2c_adapter);
mutex_unlock(&dev->i2c_mutex);
#endif /* CONFIG_I2C */
diff --git a/drivers/media/video/hdpvr/hdpvr.h b/drivers/media/video/hdpvr/hdpvr.h
index b0f046df3cd8..ee74e3be9a6a 100644
--- a/drivers/media/video/hdpvr/hdpvr.h
+++ b/drivers/media/video/hdpvr/hdpvr.h
@@ -16,6 +16,7 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/ir-kbd-i2c.h>
#define HDPVR_MAJOR_VERSION 0
#define HDPVR_MINOR_VERSION 2
@@ -24,20 +25,24 @@
KERNEL_VERSION(HDPVR_MAJOR_VERSION, HDPVR_MINOR_VERSION, HDPVR_RELEASE)
#define HDPVR_MAX 8
+#define HDPVR_I2C_MAX_SIZE 128
/* Define these values to match your devices */
#define HD_PVR_VENDOR_ID 0x2040
#define HD_PVR_PRODUCT_ID 0x4900
#define HD_PVR_PRODUCT_ID1 0x4901
#define HD_PVR_PRODUCT_ID2 0x4902
+#define HD_PVR_PRODUCT_ID4 0x4903
#define HD_PVR_PRODUCT_ID3 0x4982
#define UNSET (-1U)
#define NUM_BUFFERS 64
-#define HDPVR_FIRMWARE_VERSION 0x8
-#define HDPVR_FIRMWARE_VERSION_AC3 0xd
+#define HDPVR_FIRMWARE_VERSION 0x08
+#define HDPVR_FIRMWARE_VERSION_AC3 0x0d
+#define HDPVR_FIRMWARE_VERSION_0X12 0x12
+#define HDPVR_FIRMWARE_VERSION_0X15 0x15
/* #define HDPVR_DEBUG */
@@ -102,9 +107,14 @@ struct hdpvr_device {
struct work_struct worker;
/* I2C adapter */
- struct i2c_adapter *i2c_adapter;
+ struct i2c_adapter i2c_adapter;
/* I2C lock */
struct mutex i2c_mutex;
+ /* I2C message buffer space */
+ char i2c_buf[HDPVR_I2C_MAX_SIZE];
+
+ /* For passing data to ir-kbd-i2c */
+ struct IR_i2c_init_data ir_i2c_init_data;
/* usb control transfer buffer and lock */
struct mutex usbc_mutex;
@@ -303,6 +313,8 @@ int hdpvr_cancel_queue(struct hdpvr_device *dev);
/* i2c adapter registration */
int hdpvr_register_i2c_adapter(struct hdpvr_device *dev);
+int hdpvr_register_i2c_ir(struct hdpvr_device *dev);
+
/*========================================================================*/
/* buffer management */
int hdpvr_free_buffers(struct hdpvr_device *dev);
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index ad2c232baa6d..cdf8b191f710 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -37,15 +37,15 @@ static int hexium_num;
#define HEXIUM_INPUTS 9
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
- { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
};
#define HEXIUM_AUDIOS 0
@@ -367,7 +367,6 @@ static int hexium_attach(struct saa7146_dev *dev, struct saa7146_pci_extension_d
saa7146_write(dev, MC1, (MASK_08 | MASK_24 | MASK_10 | MASK_26));
hexium->i2c_adapter = (struct i2c_adapter) {
- .class = I2C_CLASS_TV_ANALOG,
.name = "hexium gemini",
};
saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index 938a1f8f880a..6ad7e1c8b922 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -38,15 +38,15 @@ static int hexium_num;
#define HEXIUM_INPUTS 9
static struct v4l2_input hexium_inputs[HEXIUM_INPUTS] = {
- { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { 0, "CVBS 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 1, "CVBS 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 2, "CVBS 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 3, "CVBS 4", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 4, "CVBS 5", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 5, "CVBS 6", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 6, "Y/C 1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 7, "Y/C 2", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { 8, "Y/C 3", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
};
#define HEXIUM_AUDIOS 0
@@ -230,7 +230,6 @@ static int hexium_probe(struct saa7146_dev *dev)
saa7146_write(dev, MC2, (MASK_09 | MASK_25 | MASK_10 | MASK_26));
hexium->i2c_adapter = (struct i2c_adapter) {
- .class = I2C_CLASS_TV_ANALOG,
.name = "hexium orion",
};
saa7146_i2c_adapter_prepare(dev, &hexium->i2c_adapter, SAA7146_I2C_BUS_BIT_RATE_480);
diff --git a/drivers/media/video/imx074.c b/drivers/media/video/imx074.c
new file mode 100644
index 000000000000..1a1169115716
--- /dev/null
+++ b/drivers/media/video/imx074.c
@@ -0,0 +1,505 @@
+/*
+ * Driver for IMX074 CMOS Image Sensor from Sony
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
+ *
+ * Partially inspired by the IMX074 driver from the Android / MSM tree
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-chip-ident.h>
+
+/* IMX074 registers */
+
+#define MODE_SELECT 0x0100
+#define IMAGE_ORIENTATION 0x0101
+#define GROUPED_PARAMETER_HOLD 0x0104
+
+/* Integration Time */
+#define COARSE_INTEGRATION_TIME_HI 0x0202
+#define COARSE_INTEGRATION_TIME_LO 0x0203
+/* Gain */
+#define ANALOGUE_GAIN_CODE_GLOBAL_HI 0x0204
+#define ANALOGUE_GAIN_CODE_GLOBAL_LO 0x0205
+
+/* PLL registers */
+#define PRE_PLL_CLK_DIV 0x0305
+#define PLL_MULTIPLIER 0x0307
+#define PLSTATIM 0x302b
+#define VNDMY_ABLMGSHLMT 0x300a
+#define Y_OPBADDR_START_DI 0x3014
+/* mode setting */
+#define FRAME_LENGTH_LINES_HI 0x0340
+#define FRAME_LENGTH_LINES_LO 0x0341
+#define LINE_LENGTH_PCK_HI 0x0342
+#define LINE_LENGTH_PCK_LO 0x0343
+#define YADDR_START 0x0347
+#define YADDR_END 0x034b
+#define X_OUTPUT_SIZE_MSB 0x034c
+#define X_OUTPUT_SIZE_LSB 0x034d
+#define Y_OUTPUT_SIZE_MSB 0x034e
+#define Y_OUTPUT_SIZE_LSB 0x034f
+#define X_EVEN_INC 0x0381
+#define X_ODD_INC 0x0383
+#define Y_EVEN_INC 0x0385
+#define Y_ODD_INC 0x0387
+
+#define HMODEADD 0x3001
+#define VMODEADD 0x3016
+#define VAPPLINE_START 0x3069
+#define VAPPLINE_END 0x306b
+#define SHUTTER 0x3086
+#define HADDAVE 0x30e8
+#define LANESEL 0x3301
+
+/* IMX074 supported geometry */
+#define IMX074_WIDTH 1052
+#define IMX074_HEIGHT 780
+
+/* IMX074 has only one fixed colorspace per pixelcode */
+struct imx074_datafmt {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+struct imx074 {
+ struct v4l2_subdev subdev;
+ const struct imx074_datafmt *fmt;
+};
+
+static const struct imx074_datafmt imx074_colour_fmts[] = {
+ {V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
+};
+
+static struct imx074 *to_imx074(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct imx074, subdev);
+}
+
+/* Find a data format by a pixel code in an array */
+static const struct imx074_datafmt *imx074_find_datafmt(enum v4l2_mbus_pixelcode code)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(imx074_colour_fmts); i++)
+ if (imx074_colour_fmts[i].code == code)
+ return imx074_colour_fmts + i;
+
+ return NULL;
+}
+
+static int reg_write(struct i2c_client *client, const u16 addr, const u8 data)
+{
+ struct i2c_adapter *adap = client->adapter;
+ struct i2c_msg msg;
+ unsigned char tx[3];
+ int ret;
+
+ msg.addr = client->addr;
+ msg.buf = tx;
+ msg.len = 3;
+ msg.flags = 0;
+
+ tx[0] = addr >> 8;
+ tx[1] = addr & 0xff;
+ tx[2] = data;
+
+ ret = i2c_transfer(adap, &msg, 1);
+
+ mdelay(2);
+
+ return ret == 1 ? 0 : -EIO;
+}
+
+static int reg_read(struct i2c_client *client, const u16 addr)
+{
+ u8 buf[2] = {addr >> 8, addr & 0xff};
+ int ret;
+ struct i2c_msg msgs[] = {
+ {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = buf,
+ }, {
+ .addr = client->addr,
+ .flags = I2C_M_RD,
+ .len = 2,
+ .buf = buf,
+ },
+ };
+
+ ret = i2c_transfer(client->adapter, msgs, ARRAY_SIZE(msgs));
+ if (ret < 0) {
+ dev_warn(&client->dev, "Reading register %x from %x failed\n",
+ addr, client->addr);
+ return ret;
+ }
+
+ return buf[0] & 0xff; /* no sign-extension */
+}
+
+static int imx074_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct imx074_datafmt *fmt = imx074_find_datafmt(mf->code);
+
+ dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+ if (!fmt) {
+ mf->code = imx074_colour_fmts[0].code;
+ mf->colorspace = imx074_colour_fmts[0].colorspace;
+ }
+
+ mf->width = IMX074_WIDTH;
+ mf->height = IMX074_HEIGHT;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int imx074_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct imx074 *priv = to_imx074(client);
+
+ dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+
+ /* MIPI CSI could have changed the format, double-check */
+ if (!imx074_find_datafmt(mf->code))
+ return -EINVAL;
+
+ imx074_try_fmt(sd, mf);
+
+ priv->fmt = imx074_find_datafmt(mf->code);
+
+ return 0;
+}
+
+static int imx074_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct imx074 *priv = to_imx074(client);
+
+ const struct imx074_datafmt *fmt = priv->fmt;
+
+ mf->code = fmt->code;
+ mf->colorspace = fmt->colorspace;
+ mf->width = IMX074_WIDTH;
+ mf->height = IMX074_HEIGHT;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int imx074_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct v4l2_rect *rect = &a->c;
+
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ rect->top = 0;
+ rect->left = 0;
+ rect->width = IMX074_WIDTH;
+ rect->height = IMX074_HEIGHT;
+
+ return 0;
+}
+
+static int imx074_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = IMX074_WIDTH;
+ a->bounds.height = IMX074_HEIGHT;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int imx074_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if ((unsigned int)index >= ARRAY_SIZE(imx074_colour_fmts))
+ return -EINVAL;
+
+ *code = imx074_colour_fmts[index].code;
+ return 0;
+}
+
+static int imx074_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ /* MODE_SELECT: stream or standby */
+ return reg_write(client, MODE_SELECT, !!enable);
+}
+
+static int imx074_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match.addr != client->addr)
+ return -ENODEV;
+
+ id->ident = V4L2_IDENT_IMX074;
+ id->revision = 0;
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops imx074_subdev_video_ops = {
+ .s_stream = imx074_s_stream,
+ .s_mbus_fmt = imx074_s_fmt,
+ .g_mbus_fmt = imx074_g_fmt,
+ .try_mbus_fmt = imx074_try_fmt,
+ .enum_mbus_fmt = imx074_enum_fmt,
+ .g_crop = imx074_g_crop,
+ .cropcap = imx074_cropcap,
+};
+
+static struct v4l2_subdev_core_ops imx074_subdev_core_ops = {
+ .g_chip_ident = imx074_g_chip_ident,
+};
+
+static struct v4l2_subdev_ops imx074_subdev_ops = {
+ .core = &imx074_subdev_core_ops,
+ .video = &imx074_subdev_video_ops,
+};
+
+/*
+ * We have to provide soc-camera operations, but we don't have anything to say
+ * there. The MIPI CSI2 driver will provide .query_bus_param and .set_bus_param
+ */
+static unsigned long imx074_query_bus_param(struct soc_camera_device *icd)
+{
+ return 0;
+}
+
+static int imx074_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ return -1;
+}
+
+static struct soc_camera_ops imx074_ops = {
+ .query_bus_param = imx074_query_bus_param,
+ .set_bus_param = imx074_set_bus_param,
+};
+
+static int imx074_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
+{
+ int ret;
+ u16 id;
+
+ /* Read sensor Model ID */
+ ret = reg_read(client, 0);
+ if (ret < 0)
+ return ret;
+
+ id = ret << 8;
+
+ ret = reg_read(client, 1);
+ if (ret < 0)
+ return ret;
+
+ id |= ret;
+
+ dev_info(&client->dev, "Chip ID 0x%04x detected\n", id);
+
+ if (id != 0x74)
+ return -ENODEV;
+
+ /* PLL Setting EXTCLK=24MHz, 22.5times */
+ reg_write(client, PLL_MULTIPLIER, 0x2D);
+ reg_write(client, PRE_PLL_CLK_DIV, 0x02);
+ reg_write(client, PLSTATIM, 0x4B);
+
+ /* 2-lane mode */
+ reg_write(client, 0x3024, 0x00);
+
+ reg_write(client, IMAGE_ORIENTATION, 0x00);
+
+ /* select RAW mode:
+ * 0x08+0x08 = top 8 bits
+ * 0x0a+0x08 = compressed 8-bits
+ * 0x0a+0x0a = 10 bits
+ */
+ reg_write(client, 0x0112, 0x08);
+ reg_write(client, 0x0113, 0x08);
+
+ /* Base setting for High frame mode */
+ reg_write(client, VNDMY_ABLMGSHLMT, 0x80);
+ reg_write(client, Y_OPBADDR_START_DI, 0x08);
+ reg_write(client, 0x3015, 0x37);
+ reg_write(client, 0x301C, 0x01);
+ reg_write(client, 0x302C, 0x05);
+ reg_write(client, 0x3031, 0x26);
+ reg_write(client, 0x3041, 0x60);
+ reg_write(client, 0x3051, 0x24);
+ reg_write(client, 0x3053, 0x34);
+ reg_write(client, 0x3057, 0xC0);
+ reg_write(client, 0x305C, 0x09);
+ reg_write(client, 0x305D, 0x07);
+ reg_write(client, 0x3060, 0x30);
+ reg_write(client, 0x3065, 0x00);
+ reg_write(client, 0x30AA, 0x08);
+ reg_write(client, 0x30AB, 0x1C);
+ reg_write(client, 0x30B0, 0x32);
+ reg_write(client, 0x30B2, 0x83);
+ reg_write(client, 0x30D3, 0x04);
+ reg_write(client, 0x3106, 0x78);
+ reg_write(client, 0x310C, 0x82);
+ reg_write(client, 0x3304, 0x05);
+ reg_write(client, 0x3305, 0x04);
+ reg_write(client, 0x3306, 0x11);
+ reg_write(client, 0x3307, 0x02);
+ reg_write(client, 0x3308, 0x0C);
+ reg_write(client, 0x3309, 0x06);
+ reg_write(client, 0x330A, 0x08);
+ reg_write(client, 0x330B, 0x04);
+ reg_write(client, 0x330C, 0x08);
+ reg_write(client, 0x330D, 0x06);
+ reg_write(client, 0x330E, 0x01);
+ reg_write(client, 0x3381, 0x00);
+
+ /* V : 1/2V-addition (1,3), H : 1/2H-averaging (1,3) -> Full HD */
+ /* 1608 = 1560 + 48 (black lines) */
+ reg_write(client, FRAME_LENGTH_LINES_HI, 0x06);
+ reg_write(client, FRAME_LENGTH_LINES_LO, 0x48);
+ reg_write(client, YADDR_START, 0x00);
+ reg_write(client, YADDR_END, 0x2F);
+ /* 0x838 == 2104 */
+ reg_write(client, X_OUTPUT_SIZE_MSB, 0x08);
+ reg_write(client, X_OUTPUT_SIZE_LSB, 0x38);
+ /* 0x618 == 1560 */
+ reg_write(client, Y_OUTPUT_SIZE_MSB, 0x06);
+ reg_write(client, Y_OUTPUT_SIZE_LSB, 0x18);
+ reg_write(client, X_EVEN_INC, 0x01);
+ reg_write(client, X_ODD_INC, 0x03);
+ reg_write(client, Y_EVEN_INC, 0x01);
+ reg_write(client, Y_ODD_INC, 0x03);
+ reg_write(client, HMODEADD, 0x00);
+ reg_write(client, VMODEADD, 0x16);
+ reg_write(client, VAPPLINE_START, 0x24);
+ reg_write(client, VAPPLINE_END, 0x53);
+ reg_write(client, SHUTTER, 0x00);
+ reg_write(client, HADDAVE, 0x80);
+
+ reg_write(client, LANESEL, 0x00);
+
+ reg_write(client, GROUPED_PARAMETER_HOLD, 0x00); /* off */
+
+ return 0;
+}
+
+static int imx074_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct imx074 *priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl;
+ int ret;
+
+ if (!icd) {
+ dev_err(&client->dev, "IMX074: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
+ if (!icl) {
+ dev_err(&client->dev, "IMX074: missing platform data!\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_BYTE\n");
+ return -EIO;
+ }
+
+ priv = kzalloc(sizeof(struct imx074), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &imx074_subdev_ops);
+
+ icd->ops = &imx074_ops;
+ priv->fmt = &imx074_colour_fmts[0];
+
+ ret = imx074_video_probe(icd, client);
+ if (ret < 0) {
+ icd->ops = NULL;
+ kfree(priv);
+ return ret;
+ }
+
+ return ret;
+}
+
+static int imx074_remove(struct i2c_client *client)
+{
+ struct imx074 *priv = to_imx074(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+ icd->ops = NULL;
+ if (icl->free_bus)
+ icl->free_bus(icl);
+ kfree(priv);
+
+ return 0;
+}
+
+static const struct i2c_device_id imx074_id[] = {
+ { "imx074", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, imx074_id);
+
+static struct i2c_driver imx074_i2c_driver = {
+ .driver = {
+ .name = "imx074",
+ },
+ .probe = imx074_probe,
+ .remove = imx074_remove,
+ .id_table = imx074_id,
+};
+
+static int __init imx074_mod_init(void)
+{
+ return i2c_add_driver(&imx074_i2c_driver);
+}
+
+static void __exit imx074_mod_exit(void)
+{
+ i2c_del_driver(&imx074_i2c_driver);
+}
+
+module_init(imx074_mod_init);
+module_exit(imx074_mod_exit);
+
+MODULE_DESCRIPTION("Sony IMX074 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/indycam.c b/drivers/media/video/indycam.c
index 3d6940163b12..e5ed4db32e7b 100644
--- a/drivers/media/video/indycam.c
+++ b/drivers/media/video/indycam.c
@@ -24,7 +24,6 @@
#include <linux/i2c.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include "indycam.h"
@@ -378,9 +377,25 @@ static const struct i2c_device_id indycam_id[] = {
};
MODULE_DEVICE_TABLE(i2c, indycam_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "indycam",
- .probe = indycam_probe,
- .remove = indycam_remove,
- .id_table = indycam_id,
+static struct i2c_driver indycam_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "indycam",
+ },
+ .probe = indycam_probe,
+ .remove = indycam_remove,
+ .id_table = indycam_id,
};
+
+static __init int init_indycam(void)
+{
+ return i2c_add_driver(&indycam_driver);
+}
+
+static __exit void exit_indycam(void)
+{
+ i2c_del_driver(&indycam_driver);
+}
+
+module_init(init_indycam);
+module_exit(exit_indycam);
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 29d439742653..d2b20ad383a3 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -44,10 +44,9 @@
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/workqueue.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
/* ----------------------------------------------------------------------- */
@@ -146,26 +145,6 @@ static int get_key_pixelview(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
return 1;
}
-static int get_key_pv951(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
-{
- unsigned char b;
-
- /* poll IR chip */
- if (1 != i2c_master_recv(ir->c, &b, 1)) {
- dprintk(1,"read error\n");
- return -EIO;
- }
-
- /* ignore 0xaa */
- if (b==0xaa)
- return 0;
- dprintk(2,"key %02x\n", b);
-
- *ir_key = b;
- *ir_raw = b;
- return 1;
-}
-
static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
{
unsigned char buf[4];
@@ -265,32 +244,25 @@ static void ir_key_poll(struct IR_i2c *ir)
static u32 ir_key, ir_raw;
int rc;
- dprintk(2,"ir_poll_key\n");
+ dprintk(3, "%s\n", __func__);
rc = ir->get_key(ir, &ir_key, &ir_raw);
if (rc < 0) {
dprintk(2,"error\n");
return;
}
- if (0 == rc) {
- ir_input_nokey(ir->input, &ir->ir);
- } else {
- ir_input_keydown(ir->input, &ir->ir, ir_key);
+ if (rc) {
+ dprintk(1, "%s: keycode = 0x%04x\n", __func__, ir_key);
+ rc_keydown(ir->rc, ir_key, 0);
}
}
static void ir_work(struct work_struct *work)
{
struct IR_i2c *ir = container_of(work, struct IR_i2c, work.work);
- int polling_interval = 100;
-
- /* MSI TV@nywhere Plus requires more frequent polling
- otherwise it will miss some keypresses */
- if (ir->c->adapter->id == I2C_HW_SAA7134 && ir->c->addr == 0x30)
- polling_interval = 50;
ir_key_poll(ir);
- schedule_delayed_work(&ir->work, msecs_to_jiffies(polling_interval));
+ schedule_delayed_work(&ir->work, msecs_to_jiffies(ir->polling_interval));
}
/* ----------------------------------------------------------------------- */
@@ -299,43 +271,34 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
char *ir_codes = NULL;
const char *name = NULL;
- u64 ir_type = 0;
+ u64 rc_type = RC_TYPE_UNKNOWN;
struct IR_i2c *ir;
- struct input_dev *input_dev;
+ struct rc_dev *rc = NULL;
struct i2c_adapter *adap = client->adapter;
unsigned short addr = client->addr;
int err;
- ir = kzalloc(sizeof(struct IR_i2c),GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev) {
- err = -ENOMEM;
- goto err_out_free;
- }
+ ir = kzalloc(sizeof(struct IR_i2c), GFP_KERNEL);
+ if (!ir)
+ return -ENOMEM;
ir->c = client;
- ir->input = input_dev;
+ ir->polling_interval = DEFAULT_POLLING_INTERVAL;
i2c_set_clientdata(client, ir);
switch(addr) {
case 0x64:
name = "Pixelview";
ir->get_key = get_key_pixelview;
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
ir_codes = RC_MAP_EMPTY;
break;
- case 0x4b:
- name = "PV951";
- ir->get_key = get_key_pv951;
- ir_type = IR_TYPE_OTHER;
- ir_codes = RC_MAP_PV951;
- break;
case 0x18:
case 0x1f:
case 0x1a:
name = "Hauppauge";
ir->get_key = get_key_haup;
- ir_type = IR_TYPE_RC5;
+ rc_type = RC_TYPE_RC5;
if (hauppauge == 1) {
ir_codes = RC_MAP_HAUPPAUGE_NEW;
} else {
@@ -345,42 +308,27 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case 0x30:
name = "KNC One";
ir->get_key = get_key_knc1;
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
ir_codes = RC_MAP_EMPTY;
break;
case 0x6b:
name = "FusionHDTV";
ir->get_key = get_key_fusionhdtv;
- ir_type = IR_TYPE_RC5;
+ rc_type = RC_TYPE_RC5;
ir_codes = RC_MAP_FUSIONHDTV_MCE;
break;
- case 0x0b:
- case 0x47:
- case 0x71:
- if (adap->id == I2C_HW_B_CX2388x ||
- adap->id == I2C_HW_B_CX2341X) {
- /* Handled by cx88-input */
- name = adap->id == I2C_HW_B_CX2341X ? "CX2341x remote"
- : "CX2388x remote";
- ir_type = IR_TYPE_RC5;
- ir->get_key = get_key_haup_xvr;
- if (hauppauge == 1) {
- ir_codes = RC_MAP_HAUPPAUGE_NEW;
- } else {
- ir_codes = RC_MAP_RC5_TV;
- }
- } else {
- /* Handled by saa7134-input */
- name = "SAA713x remote";
- ir_type = IR_TYPE_OTHER;
- }
- break;
case 0x40:
name = "AVerMedia Cardbus remote";
ir->get_key = get_key_avermedia_cardbus;
- ir_type = IR_TYPE_OTHER;
+ rc_type = RC_TYPE_OTHER;
ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
break;
+ case 0x71:
+ name = "Hauppauge/Zilog Z8";
+ ir->get_key = get_key_haup_xvr;
+ rc_type = RC_TYPE_RC5;
+ ir_codes = hauppauge ? RC_MAP_HAUPPAUGE_NEW : RC_MAP_RC5_TV;
+ break;
}
/* Let the caller override settings */
@@ -389,9 +337,14 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
client->dev.platform_data;
ir_codes = init_data->ir_codes;
+ rc = init_data->rc_dev;
+
name = init_data->name;
if (init_data->type)
- ir_type = init_data->type;
+ rc_type = init_data->type;
+
+ if (init_data->polling_interval)
+ ir->polling_interval = init_data->polling_interval;
switch (init_data->internal_get_key_func) {
case IR_KBD_GET_KEY_CUSTOM:
@@ -401,9 +354,6 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
case IR_KBD_GET_KEY_PIXELVIEW:
ir->get_key = get_key_pixelview;
break;
- case IR_KBD_GET_KEY_PV951:
- ir->get_key = get_key_pv951;
- break;
case IR_KBD_GET_KEY_HAUP:
ir->get_key = get_key_haup;
break;
@@ -422,8 +372,21 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
}
}
+ if (!rc) {
+ /*
+ * If platform_data doesn't specify rc_dev, initilize it
+ * internally
+ */
+ rc = rc_allocate_device();
+ if (!rc) {
+ err = -ENOMEM;
+ goto err_out_free;
+ }
+ }
+ ir->rc = rc;
+
/* Make sure we are all setup before going on */
- if (!name || !ir->get_key || !ir_type || !ir_codes) {
+ if (!name || !ir->get_key || !rc_type || !ir_codes) {
dprintk(1, ": Unsupported device at address 0x%02x\n",
addr);
err = -ENODEV;
@@ -438,21 +401,28 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
dev_name(&adap->dev),
dev_name(&client->dev));
- /* init + register input device */
- err = ir_input_init(input_dev, &ir->ir, ir_type);
- if (err < 0)
- goto err_out_free;
+ /*
+ * Initialize input_dev fields
+ * It doesn't make sense to allow overriding them via platform_data
+ */
+ rc->input_id.bustype = BUS_I2C;
+ rc->input_phys = ir->phys;
+ rc->input_name = ir->name;
- input_dev->id.bustype = BUS_I2C;
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
+ /*
+ * Initialize the other fields of rc_dev
+ */
+ rc->map_name = ir->ir_codes;
+ rc->allowed_protos = rc_type;
+ if (!rc->driver_name)
+ rc->driver_name = MODULE_NAME;
- err = ir_input_register(ir->input, ir->ir_codes, NULL, MODULE_NAME);
+ err = rc_register_device(rc);
if (err)
goto err_out_free;
printk(MODULE_NAME ": %s detected at %s [%s]\n",
- ir->input->name, ir->input->phys, adap->name);
+ ir->name, ir->phys, adap->name);
/* start polling via eventd */
INIT_DELAYED_WORK(&ir->work, ir_work);
@@ -461,6 +431,8 @@ static int ir_probe(struct i2c_client *client, const struct i2c_device_id *id)
return 0;
err_out_free:
+ /* Only frees rc if it were allocated internally */
+ rc_free_device(rc);
kfree(ir);
return err;
}
@@ -473,7 +445,7 @@ static int ir_remove(struct i2c_client *client)
cancel_delayed_work_sync(&ir->work);
/* unregister device */
- ir_input_unregister(ir->input);
+ rc_unregister_device(ir->rc);
/* free memory */
kfree(ir);
@@ -485,6 +457,7 @@ static const struct i2c_device_id ir_kbd_id[] = {
{ "ir_video", 0 },
/* IR device specific entries should be added here */
{ "ir_rx_z8f0811_haup", 0 },
+ { "ir_rx_z8f0811_hdpvr", 0 },
{ }
};
diff --git a/drivers/media/video/ivtv/Kconfig b/drivers/media/video/ivtv/Kconfig
index c46bfb1569e3..89f65914cc8e 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -1,9 +1,8 @@
config VIDEO_IVTV
tristate "Conexant cx23416/cx23415 MPEG encoder/decoder support"
depends on VIDEO_V4L2 && PCI && I2C
- depends on INPUT # due to VIDEO_IR
select I2C_ALGOBIT
- select VIDEO_IR
+ depends on RC_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_CX2341X
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index ca1fd3227a93..145e4749a69d 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -65,7 +65,7 @@ static struct ivtv_card_tuner_i2c ivtv_i2c_tda8290 = {
/********************** card configuration *******************************/
-/* Please add new PCI IDs to: http://pci-ids.ucw.cz/iii
+/* Please add new PCI IDs to: http://pci-ids.ucw.cz/
This keeps the PCI ID database up to date. Note that the entries
must be added under vendor 0x4444 (Conexant) as subsystem IDs.
New vendor IDs should still be added to the vendor ID list. */
@@ -405,7 +405,8 @@ static const struct ivtv_card ivtv_card_avc2410 = {
.hw_audio_ctrl = IVTV_HW_MSP34XX,
.hw_muxer = IVTV_HW_CS53L32A,
.hw_all = IVTV_HW_MSP34XX | IVTV_HW_CS53L32A |
- IVTV_HW_SAA7115 | IVTV_HW_TUNER,
+ IVTV_HW_SAA7115 | IVTV_HW_TUNER |
+ IVTV_HW_I2C_IR_RX_ADAPTEC,
.video_inputs = {
{ IVTV_CARD_INPUT_VID_TUNER, 0, IVTV_SAA71XX_COMPOSITE4 },
{ IVTV_CARD_INPUT_SVIDEO1, 1, IVTV_SAA71XX_SVIDEO0 },
@@ -1313,7 +1314,6 @@ int ivtv_get_input(struct ivtv *itv, u16 index, struct v4l2_input *input)
"Composite 3"
};
- memset(input, 0, sizeof(*input));
if (index >= itv->nof_inputs)
return -EINVAL;
input->index = index;
@@ -1331,7 +1331,6 @@ int ivtv_get_output(struct ivtv *itv, u16 index, struct v4l2_output *output)
{
const struct ivtv_card_output *card_output = itv->card->video_outputs + index;
- memset(output, 0, sizeof(*output));
if (index >= itv->card->nof_outputs)
return -EINVAL;
output->index = index;
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 78eca992e1fd..e6f5c02981f1 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -111,6 +111,7 @@
#define IVTV_HW_I2C_IR_RX_HAUP_INT (1 << 18)
#define IVTV_HW_Z8F0811_IR_TX_HAUP (1 << 19)
#define IVTV_HW_Z8F0811_IR_RX_HAUP (1 << 20)
+#define IVTV_HW_I2C_IR_RX_ADAPTEC (1 << 21)
#define IVTV_HW_Z8F0811_IR_HAUP (IVTV_HW_Z8F0811_IR_RX_HAUP | \
IVTV_HW_Z8F0811_IR_TX_HAUP)
@@ -120,7 +121,8 @@
#define IVTV_HW_IR_RX_ANY (IVTV_HW_I2C_IR_RX_AVER | \
IVTV_HW_I2C_IR_RX_HAUP_EXT | \
IVTV_HW_I2C_IR_RX_HAUP_INT | \
- IVTV_HW_Z8F0811_IR_RX_HAUP)
+ IVTV_HW_Z8F0811_IR_RX_HAUP | \
+ IVTV_HW_I2C_IR_RX_ADAPTEC)
#define IVTV_HW_IR_TX_ANY (IVTV_HW_Z8F0811_IR_TX_HAUP)
diff --git a/drivers/media/video/ivtv/ivtv-controls.c b/drivers/media/video/ivtv/ivtv-controls.c
index b59475bfc243..b31ee1bceef8 100644
--- a/drivers/media/video/ivtv/ivtv-controls.c
+++ b/drivers/media/video/ivtv/ivtv-controls.c
@@ -17,163 +17,14 @@
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/kernel.h>
-#include <linux/slab.h>
#include "ivtv-driver.h"
-#include "ivtv-cards.h"
#include "ivtv-ioctl.h"
-#include "ivtv-routing.h"
-#include "ivtv-i2c.h"
-#include "ivtv-mailbox.h"
#include "ivtv-controls.h"
-/* Must be sorted from low to high control ID! */
-static const u32 user_ctrls[] = {
- V4L2_CID_USER_CLASS,
- V4L2_CID_BRIGHTNESS,
- V4L2_CID_CONTRAST,
- V4L2_CID_SATURATION,
- V4L2_CID_HUE,
- V4L2_CID_AUDIO_VOLUME,
- V4L2_CID_AUDIO_BALANCE,
- V4L2_CID_AUDIO_BASS,
- V4L2_CID_AUDIO_TREBLE,
- V4L2_CID_AUDIO_MUTE,
- V4L2_CID_AUDIO_LOUDNESS,
- 0
-};
-
-static const u32 *ctrl_classes[] = {
- user_ctrls,
- cx2341x_mpeg_ctrls,
- NULL
-};
-
-
-int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *qctrl)
-{
- struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- const char *name;
-
- qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
- if (qctrl->id == 0)
- return -EINVAL;
-
- switch (qctrl->id) {
- /* Standard V4L2 controls */
- case V4L2_CID_USER_CLASS:
- return v4l2_ctrl_query_fill(qctrl, 0, 0, 0, 0);
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_HUE:
- case V4L2_CID_SATURATION:
- case V4L2_CID_CONTRAST:
- if (v4l2_subdev_call(itv->sd_video, core, queryctrl, qctrl))
- qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
- return 0;
-
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_LOUDNESS:
- if (v4l2_subdev_call(itv->sd_audio, core, queryctrl, qctrl))
- qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
- return 0;
-
- default:
- if (cx2341x_ctrl_query(&itv->params, qctrl))
- qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
- return 0;
- }
- strncpy(qctrl->name, name, sizeof(qctrl->name) - 1);
- qctrl->name[sizeof(qctrl->name) - 1] = 0;
- return 0;
-}
-
-int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *qmenu)
-{
- struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- struct v4l2_queryctrl qctrl;
-
- qctrl.id = qmenu->id;
- ivtv_queryctrl(file, fh, &qctrl);
- return v4l2_ctrl_query_menu(qmenu, &qctrl,
- cx2341x_ctrl_get_menu(&itv->params, qmenu->id));
-}
-
-static int ivtv_try_ctrl(struct file *file, void *fh,
- struct v4l2_ext_control *vctrl)
-{
- struct v4l2_queryctrl qctrl;
- const char **menu_items = NULL;
- int err;
-
- qctrl.id = vctrl->id;
- err = ivtv_queryctrl(file, fh, &qctrl);
- if (err)
- return err;
- if (qctrl.type == V4L2_CTRL_TYPE_MENU)
- menu_items = v4l2_ctrl_get_menu(qctrl.id);
- return v4l2_ctrl_check(vctrl, &qctrl, menu_items);
-}
-
-static int ivtv_s_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
-{
- switch (vctrl->id) {
- /* Standard V4L2 controls */
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_HUE:
- case V4L2_CID_SATURATION:
- case V4L2_CID_CONTRAST:
- return v4l2_subdev_call(itv->sd_video, core, s_ctrl, vctrl);
-
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_LOUDNESS:
- return v4l2_subdev_call(itv->sd_audio, core, s_ctrl, vctrl);
-
- default:
- IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
- return -EINVAL;
- }
- return 0;
-}
-
-static int ivtv_g_ctrl(struct ivtv *itv, struct v4l2_control *vctrl)
+static int ivtv_s_stream_vbi_fmt(struct cx2341x_handler *cxhdl, u32 fmt)
{
- switch (vctrl->id) {
- /* Standard V4L2 controls */
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_HUE:
- case V4L2_CID_SATURATION:
- case V4L2_CID_CONTRAST:
- return v4l2_subdev_call(itv->sd_video, core, g_ctrl, vctrl);
-
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_MUTE:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_AUDIO_LOUDNESS:
- return v4l2_subdev_call(itv->sd_audio, core, g_ctrl, vctrl);
- default:
- IVTV_DEBUG_IOCTL("invalid control 0x%x\n", vctrl->id);
- return -EINVAL;
- }
- return 0;
-}
-
-static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fmt)
-{
- if (!(itv->v4l2_cap & V4L2_CAP_SLICED_VBI_CAPTURE))
- return -EINVAL;
- if (atomic_read(&itv->capturing) > 0)
- return -EBUSY;
+ struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
/* First try to allocate sliced VBI buffers if needed. */
if (fmt && itv->vbi.sliced_mpeg_data[0] == NULL) {
@@ -208,106 +59,43 @@ static int ivtv_setup_vbi_fmt(struct ivtv *itv, enum v4l2_mpeg_stream_vbi_fmt fm
return 0;
}
-int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+static int ivtv_s_video_encoding(struct cx2341x_handler *cxhdl, u32 val)
{
- struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- struct v4l2_control ctrl;
-
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- ctrl.id = c->controls[i].id;
- ctrl.value = c->controls[i].value;
- err = ivtv_g_ctrl(itv, &ctrl);
- c->controls[i].value = ctrl.value;
- if (err) {
- c->error_idx = i;
- break;
- }
- }
- return err;
- }
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&itv->params, 0, c, VIDIOC_G_EXT_CTRLS);
- return -EINVAL;
+ struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
+ int is_mpeg1 = val == V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
+ struct v4l2_mbus_framefmt fmt;
+
+ /* fix videodecoder resolution */
+ fmt.width = cxhdl->width / (is_mpeg1 ? 2 : 1);
+ fmt.height = cxhdl->height;
+ fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &fmt);
+ return 0;
}
-int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+static int ivtv_s_audio_sampling_freq(struct cx2341x_handler *cxhdl, u32 idx)
{
- struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
- struct v4l2_control ctrl;
-
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- ctrl.id = c->controls[i].id;
- ctrl.value = c->controls[i].value;
- err = ivtv_s_ctrl(itv, &ctrl);
- c->controls[i].value = ctrl.value;
- if (err) {
- c->error_idx = i;
- break;
- }
- }
- return err;
- }
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
- static u32 freqs[3] = { 44100, 48000, 32000 };
- struct cx2341x_mpeg_params p = itv->params;
- int err = cx2341x_ext_ctrls(&p, atomic_read(&itv->capturing), c, VIDIOC_S_EXT_CTRLS);
- unsigned idx;
-
- if (err)
- return err;
+ static const u32 freqs[3] = { 44100, 48000, 32000 };
+ struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
- if (p.video_encoding != itv->params.video_encoding) {
- int is_mpeg1 = p.video_encoding ==
- V4L2_MPEG_VIDEO_ENCODING_MPEG_1;
- struct v4l2_format fmt;
-
- /* fix videodecoder resolution */
- 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;
- 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)
- err = ivtv_setup_vbi_fmt(itv, p.stream_vbi_fmt);
- itv->params = p;
- itv->dualwatch_stereo_mode = p.audio_properties & 0x0300;
- idx = p.audio_properties & 0x03;
- /* The audio clock of the digitizer must match the codec sample
- rate otherwise you get some very strange effects. */
- if (idx < ARRAY_SIZE(freqs))
- ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
- return err;
- }
- return -EINVAL;
+ /* The audio clock of the digitizer must match the codec sample
+ rate otherwise you get some very strange effects. */
+ if (idx < ARRAY_SIZE(freqs))
+ ivtv_call_all(itv, audio, s_clock_freq, freqs[idx]);
+ return 0;
}
-int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *c)
+static int ivtv_s_audio_mode(struct cx2341x_handler *cxhdl, u32 val)
{
- struct ivtv *itv = ((struct ivtv_open_id *)fh)->itv;
+ struct ivtv *itv = container_of(cxhdl, struct ivtv, cxhdl);
- if (c->ctrl_class == V4L2_CTRL_CLASS_USER) {
- int i;
- int err = 0;
-
- for (i = 0; i < c->count; i++) {
- err = ivtv_try_ctrl(file, fh, &c->controls[i]);
- if (err) {
- c->error_idx = i;
- break;
- }
- }
- return err;
- }
- if (c->ctrl_class == V4L2_CTRL_CLASS_MPEG)
- return cx2341x_ext_ctrls(&itv->params, atomic_read(&itv->capturing), c, VIDIOC_TRY_EXT_CTRLS);
- return -EINVAL;
+ itv->dualwatch_stereo_mode = val;
+ return 0;
}
+
+struct cx2341x_handler_ops ivtv_cxhdl_ops = {
+ .s_audio_mode = ivtv_s_audio_mode,
+ .s_audio_sampling_freq = ivtv_s_audio_sampling_freq,
+ .s_video_encoding = ivtv_s_video_encoding,
+ .s_stream_vbi_fmt = ivtv_s_stream_vbi_fmt,
+};
diff --git a/drivers/media/video/ivtv/ivtv-controls.h b/drivers/media/video/ivtv/ivtv-controls.h
index 1c7721e23c9b..d12893dd0183 100644
--- a/drivers/media/video/ivtv/ivtv-controls.h
+++ b/drivers/media/video/ivtv/ivtv-controls.h
@@ -21,10 +21,6 @@
#ifndef IVTV_CONTROLS_H
#define IVTV_CONTROLS_H
-int ivtv_queryctrl(struct file *file, void *fh, struct v4l2_queryctrl *a);
-int ivtv_g_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
-int ivtv_s_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
-int ivtv_try_ext_ctrls(struct file *file, void *fh, struct v4l2_ext_controls *a);
-int ivtv_querymenu(struct file *file, void *fh, struct v4l2_querymenu *a);
+extern struct cx2341x_handler_ops ivtv_cxhdl_ops;
#endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 1b79475ca134..39946420b301 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -53,6 +53,7 @@
#include "ivtv-cards.h"
#include "ivtv-vbi.h"
#include "ivtv-routing.h"
+#include "ivtv-controls.h"
#include "ivtv-gpio.h"
#include <media/tveeprom.h>
@@ -130,6 +131,9 @@ static int ivtv_yuv_threshold = -1;
static int ivtv_pci_latency = 1;
int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+int ivtv_fw_debug;
+#endif
static int tunertype = -1;
static int newi2c = -1;
@@ -141,6 +145,9 @@ module_param_string(pal, pal, sizeof(pal), 0644);
module_param_string(secam, secam, sizeof(secam), 0644);
module_param_string(ntsc, ntsc, sizeof(ntsc), 0644);
module_param_named(debug,ivtv_debug, int, 0644);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+module_param_named(fw_debug, ivtv_fw_debug, int, 0644);
+#endif
module_param(ivtv_pci_latency, int, 0644);
module_param(ivtv_yuv_mode, int, 0644);
module_param(ivtv_yuv_threshold, int, 0644);
@@ -217,6 +224,10 @@ MODULE_PARM_DESC(debug,
"\t\t\t 256/0x0100: yuv\n"
"\t\t\t 512/0x0200: i2c\n"
"\t\t\t1024/0x0400: high volume\n");
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+MODULE_PARM_DESC(fw_debug,
+ "Enable code for debugging firmware problems. Default: 0\n");
+#endif
MODULE_PARM_DESC(ivtv_pci_latency,
"Change the PCI latency to 64 if lower: 0 = No, 1 = Yes,\n"
"\t\t\tDefault: Yes");
@@ -695,6 +706,8 @@ done:
*/
static int __devinit ivtv_init_struct1(struct ivtv *itv)
{
+ struct sched_param param = { .sched_priority = 99 };
+
itv->base_addr = pci_resource_start(itv->pdev, 0);
itv->enc_mbox.max_mbox = 2; /* the encoder has 3 mailboxes (0-2) */
itv->dec_mbox.max_mbox = 1; /* the decoder has 2 mailboxes (0-1) */
@@ -706,21 +719,24 @@ 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->v4l2_dev.name);
- if (itv->irq_work_queues == NULL) {
- IVTV_ERR("Could not create ivtv workqueue\n");
+ init_kthread_worker(&itv->irq_worker);
+ itv->irq_worker_task = kthread_run(kthread_worker_fn, &itv->irq_worker,
+ itv->v4l2_dev.name);
+ if (IS_ERR(itv->irq_worker_task)) {
+ IVTV_ERR("Could not create ivtv task\n");
return -1;
}
+ /* must use the FIFO scheduler as it is realtime sensitive */
+ sched_setscheduler(itv->irq_worker_task, SCHED_FIFO, &param);
- INIT_WORK(&itv->irq_work_queue, ivtv_irq_work_handler);
+ init_kthread_work(&itv->irq_work, ivtv_irq_work_handler);
/* start counting open_id at 1 */
itv->open_id = 1;
/* Initial settings */
- cx2341x_fill_defaults(&itv->params);
- itv->params.port = CX2341X_PORT_MEMORY;
- itv->params.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
+ itv->cxhdl.port = CX2341X_PORT_MEMORY;
+ itv->cxhdl.capabilities = CX2341X_CAP_HAS_SLICED_VBI;
init_waitqueue_head(&itv->eos_waitq);
init_waitqueue_head(&itv->event_waitq);
init_waitqueue_head(&itv->vsync_waitq);
@@ -990,13 +1006,20 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
retval = -ENOMEM;
goto err;
}
+ retval = cx2341x_handler_init(&itv->cxhdl, 50);
+ if (retval)
+ goto err;
+ itv->v4l2_dev.ctrl_handler = &itv->cxhdl.hdl;
+ itv->cxhdl.ops = &ivtv_cxhdl_ops;
+ itv->cxhdl.priv = itv;
+ itv->cxhdl.func = ivtv_api_func;
IVTV_DEBUG_INFO("base addr: 0x%08x\n", itv->base_addr);
/* PCI Device Setup */
retval = ivtv_setup_pci(itv, pdev, pci_id);
if (retval == -EIO)
- goto free_workqueue;
+ goto free_worker;
if (retval == -ENXIO)
goto free_mem;
@@ -1006,8 +1029,13 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->enc_mem = ioremap_nocache(itv->base_addr + IVTV_ENCODER_OFFSET,
IVTV_ENCODER_SIZE);
if (!itv->enc_mem) {
- IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 "
+ "encoder memory\n");
+ IVTV_ERR("Each capture card with a CX23415/6 needs 8 MB of "
+ "vmalloc address space for this window\n");
+ IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+ IVTV_ERR("Use the vmalloc= kernel command line option to set "
+ "VmallocTotal to a larger value\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1018,8 +1046,14 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->dec_mem = ioremap_nocache(itv->base_addr + IVTV_DECODER_OFFSET,
IVTV_DECODER_SIZE);
if (!itv->dec_mem) {
- IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ IVTV_ERR("ioremap failed. Can't get a window into "
+ "CX23415 decoder memory\n");
+ IVTV_ERR("Each capture card with a CX23415 needs 8 MB "
+ "of vmalloc address space for this window\n");
+ IVTV_ERR("Check the output of 'grep Vmalloc "
+ "/proc/meminfo'\n");
+ IVTV_ERR("Use the vmalloc= kernel command line option "
+ "to set VmallocTotal to a larger value\n");
retval = -ENOMEM;
goto free_mem;
}
@@ -1034,8 +1068,13 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->reg_mem =
ioremap_nocache(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (!itv->reg_mem) {
- IVTV_ERR("ioremap failed, perhaps increasing __VMALLOC_RESERVE in page.h\n");
- IVTV_ERR("or disabling CONFIG_HIGHMEM4G into the kernel would help\n");
+ IVTV_ERR("ioremap failed. Can't get a window into CX23415/6 "
+ "register space\n");
+ IVTV_ERR("Each capture card with a CX23415/6 needs 64 kB of "
+ "vmalloc address space for this window\n");
+ IVTV_ERR("Check the output of 'grep Vmalloc /proc/meminfo'\n");
+ IVTV_ERR("Use the vmalloc= kernel command line option to set "
+ "VmallocTotal to a larger value\n");
retval = -ENOMEM;
goto free_io;
}
@@ -1111,7 +1150,7 @@ static int __devinit ivtv_probe(struct pci_dev *pdev,
itv->yuv_info.v4l2_src_w = itv->yuv_info.osd_full_w;
itv->yuv_info.v4l2_src_h = itv->yuv_info.osd_full_h;
- itv->params.video_gop_size = itv->is_60hz ? 15 : 12;
+ cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz);
itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_MPG] = 0x08000;
itv->stream_buf_size[IVTV_ENC_STREAM_TYPE_PCM] = 0x01200;
@@ -1208,8 +1247,8 @@ free_mem:
release_mem_region(itv->base_addr + IVTV_REG_OFFSET, IVTV_REG_SIZE);
if (itv->has_cx23415)
release_mem_region(itv->base_addr + IVTV_DECODER_OFFSET, IVTV_DECODER_SIZE);
-free_workqueue:
- destroy_workqueue(itv->irq_work_queues);
+free_worker:
+ kthread_stop(itv->irq_worker_task);
err:
if (retval == 0)
retval = -ENODEV;
@@ -1253,15 +1292,8 @@ int ivtv_init_on_first_open(struct ivtv *itv)
IVTV_DEBUG_INFO("Getting firmware version..\n");
ivtv_firmware_versions(itv);
- if (itv->card->hw_all & IVTV_HW_CX25840) {
- struct v4l2_control ctrl;
-
+ if (itv->card->hw_all & IVTV_HW_CX25840)
v4l2_subdev_call(itv->sd_video, core, load_fw);
- /* CX25840_CID_ENABLE_PVR150_WORKAROUND */
- ctrl.id = V4L2_CID_PRIVATE_BASE;
- ctrl.value = itv->pvr150_workaround;
- v4l2_subdev_call(itv->sd_video, core, s_ctrl, &ctrl);
- }
vf.tuner = 0;
vf.type = V4L2_TUNER_ANALOG_TV;
@@ -1313,6 +1345,8 @@ int ivtv_init_on_first_open(struct ivtv *itv)
/* For cards with video out, this call needs interrupts enabled */
ivtv_s_std(NULL, &fh, &itv->tuner_std);
+ /* Setup initial controls */
+ cx2341x_handler_setup(&itv->cxhdl);
return 0;
}
@@ -1353,9 +1387,9 @@ static void ivtv_remove(struct pci_dev *pdev)
ivtv_set_irq_mask(itv, 0xffffffff);
del_timer_sync(&itv->dma_timer);
- /* Stop all Work Queues */
- flush_workqueue(itv->irq_work_queues);
- destroy_workqueue(itv->irq_work_queues);
+ /* Kill irq worker */
+ flush_kthread_worker(&itv->irq_worker);
+ kthread_stop(itv->irq_worker_task);
ivtv_streams_cleanup(itv, 1);
ivtv_udma_free(itv);
@@ -1425,12 +1459,16 @@ EXPORT_SYMBOL(ivtv_vapi);
EXPORT_SYMBOL(ivtv_vapi_result);
EXPORT_SYMBOL(ivtv_clear_irq_mask);
EXPORT_SYMBOL(ivtv_debug);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+EXPORT_SYMBOL(ivtv_fw_debug);
+#endif
EXPORT_SYMBOL(ivtv_reset_ir_gpio);
EXPORT_SYMBOL(ivtv_udma_setup);
EXPORT_SYMBOL(ivtv_udma_unmap);
EXPORT_SYMBOL(ivtv_udma_alloc);
EXPORT_SYMBOL(ivtv_udma_prepare);
EXPORT_SYMBOL(ivtv_init_on_first_open);
+EXPORT_SYMBOL(ivtv_firmware_check);
module_init(module_start);
module_exit(module_cleanup);
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 5b45fd2b2645..04bacdbd10bb 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -51,7 +51,7 @@
#include <linux/unistd.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
-#include <linux/workqueue.h>
+#include <linux/kthread.h>
#include <linux/mutex.h>
#include <linux/slab.h>
#include <asm/uaccess.h>
@@ -62,6 +62,7 @@
#include <linux/dvb/audio.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-device.h>
#include <media/v4l2-fh.h>
#include <media/tuner.h>
@@ -122,6 +123,9 @@
/* debugging */
extern int ivtv_debug;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+extern int ivtv_fw_debug;
+#endif
#define IVTV_DBGFLG_WARN (1 << 0)
#define IVTV_DBGFLG_INFO (1 << 1)
@@ -257,7 +261,6 @@ struct ivtv_mailbox_data {
#define IVTV_F_I_DEC_PAUSED 20 /* the decoder is paused */
#define IVTV_F_I_INITED 21 /* set after first open */
#define IVTV_F_I_FAILED 22 /* set if first open failed */
-#define IVTV_F_I_WORK_INITED 23 /* worker thread was initialized */
/* Event notifications */
#define IVTV_F_I_EV_DEC_STOPPED 28 /* decoder stopped event */
@@ -629,6 +632,8 @@ struct ivtv {
struct ivtv_options options; /* user options */
struct v4l2_device v4l2_dev;
+ struct cx2341x_handler cxhdl;
+ struct v4l2_ctrl_handler hdl_gpio;
struct v4l2_subdev sd_gpio; /* GPIO sub-device */
u16 instance;
@@ -646,7 +651,6 @@ struct ivtv {
v4l2_std_id std_out; /* current TV output standard */
u8 audio_stereo_mode; /* decoder setting how to handle stereo MPEG audio */
u8 audio_bilingual_mode; /* decoder setting how to handle bilingual MPEG audio */
- struct cx2341x_mpeg_params params; /* current encoder parameters */
/* Locking */
@@ -663,8 +667,9 @@ struct ivtv {
/* Interrupts & DMA */
u32 irqmask; /* active interrupts */
u32 irq_rr_idx; /* round-robin stream index */
- struct workqueue_struct *irq_work_queues; /* workqueue for PIO/YUV/VBI actions */
- struct work_struct irq_work_queue; /* work entry */
+ struct kthread_worker irq_worker; /* kthread worker for PIO/YUV/VBI actions */
+ struct task_struct *irq_worker_task; /* task for irq_worker */
+ struct kthread_work irq_work; /* kthread work entry */
spinlock_t dma_reg_lock; /* lock access to DMA engine registers */
int cur_dma_stream; /* index of current stream doing DMA (-1 if none) */
int cur_pio_stream; /* index of current stream doing PIO (-1 if none) */
@@ -734,6 +739,7 @@ struct ivtv {
struct v4l2_rect osd_rect; /* current OSD position and size */
struct v4l2_rect main_rect; /* current Main window position and size */
struct osd_info *osd_info; /* ivtvfb private OSD info */
+ void (*ivtvfb_restore)(struct ivtv *itv); /* Used for a warm start */
};
static inline struct ivtv *to_ivtv(struct v4l2_device *v4l2_dev)
@@ -805,15 +811,23 @@ static inline int ivtv_raw_vbi(const struct ivtv *itv)
/* 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)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+ do { \
+ struct v4l2_subdev *__sd; \
+ __v4l2_device_call_subdevs_p(&(itv)->v4l2_dev, __sd, \
+ !(hw) || (__sd->grp_id & (hw)), o, f , ##args); \
+ } while (0)
#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)->v4l2_dev, !(hw) || (sd->grp_id & (hw)), o, f , ##args)
+#define ivtv_call_hw_err(itv, hw, o, f, args...) \
+({ \
+ struct v4l2_subdev *__sd; \
+ __v4l2_device_call_subdevs_until_err_p(&(itv)->v4l2_dev, __sd, \
+ !(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)
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index abf410943cc9..c57a58523ca8 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -32,6 +32,7 @@
#include "ivtv-yuv.h"
#include "ivtv-ioctl.h"
#include "ivtv-cards.h"
+#include "ivtv-firmware.h"
#include <media/v4l2-event.h>
#include <media/saa7115.h>
@@ -149,12 +150,10 @@ void ivtv_release_stream(struct ivtv_stream *s)
static void ivtv_dualwatch(struct ivtv *itv)
{
struct v4l2_tuner vt;
- u32 new_bitmap;
u32 new_stereo_mode;
- const u32 stereo_mask = 0x0300;
- const u32 dual = 0x0200;
+ const u32 dual = 0x02;
- new_stereo_mode = itv->params.audio_properties & stereo_mask;
+ new_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
memset(&vt, 0, sizeof(vt));
ivtv_call_all(itv, tuner, g_tuner, &vt);
if (vt.audmode == V4L2_TUNER_MODE_LANG1_LANG2 && (vt.rxsubchans & V4L2_TUNER_SUB_LANG2))
@@ -163,16 +162,10 @@ static void ivtv_dualwatch(struct ivtv *itv)
if (new_stereo_mode == itv->dualwatch_stereo_mode)
return;
- new_bitmap = new_stereo_mode | (itv->params.audio_properties & ~stereo_mask);
-
- IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x. new audio_bitmask=0x%ux\n",
- itv->dualwatch_stereo_mode, new_stereo_mode, new_bitmap);
-
- if (ivtv_vapi(itv, CX2341X_ENC_SET_AUDIO_PROPERTIES, 1, new_bitmap) == 0) {
- itv->dualwatch_stereo_mode = new_stereo_mode;
- return;
- }
- IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
+ IVTV_DEBUG_INFO("dualwatch: change stereo flag from 0x%x to 0x%x.\n",
+ itv->dualwatch_stereo_mode, new_stereo_mode);
+ if (v4l2_ctrl_s_ctrl(itv->cxhdl.audio_mode, new_stereo_mode))
+ IVTV_DEBUG_INFO("dualwatch: changing stereo flag failed\n");
}
static void ivtv_update_pgm_info(struct ivtv *itv)
@@ -526,6 +519,7 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
{
struct ivtv *itv = id->itv;
struct ivtv_stream *s = &itv->streams[id->type];
+ int rc;
if (atomic_read(&itv->decoding) == 0) {
if (ivtv_claim_stream(id, s->type)) {
@@ -533,7 +527,13 @@ int ivtv_start_decoding(struct ivtv_open_id *id, int speed)
IVTV_DEBUG_WARN("start decode, stream already claimed\n");
return -EBUSY;
}
- ivtv_start_v4l2_decode_stream(s, 0);
+ rc = ivtv_start_v4l2_decode_stream(s, 0);
+ if (rc < 0) {
+ if (rc == -EAGAIN)
+ rc = ivtv_start_v4l2_decode_stream(s, 0);
+ if (rc < 0)
+ return rc;
+ }
}
if (s->type == IVTV_DEC_STREAM_TYPE_MPG)
return ivtv_set_speed(itv, speed);
@@ -570,8 +570,8 @@ ssize_t ivtv_v4l2_write(struct file *filp, const char __user *user_buf, size_t c
int elems = count / sizeof(struct v4l2_sliced_vbi_data);
set_bit(IVTV_F_S_APPL_IO, &s->s_flags);
- ivtv_write_vbi(itv, (const struct v4l2_sliced_vbi_data *)user_buf, elems);
- return elems * sizeof(struct v4l2_sliced_vbi_data);
+ return ivtv_write_vbi_from_user(itv,
+ (const struct v4l2_sliced_vbi_data __user *)user_buf, elems);
}
mode = s->type == IVTV_DEC_STREAM_TYPE_MPG ? OUT_MPG : OUT_YUV;
@@ -823,6 +823,12 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
IVTV_DEBUG_FILE("close() of %s\n", s->name);
+ if (id->type == IVTV_DEC_STREAM_TYPE_YUV &&
+ test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {
+ /* Restore registers we've changed & clean up any mess */
+ ivtv_yuv_close(itv);
+ }
+
/* Stop decoding */
if (test_bit(IVTV_F_S_STREAMING, &s->s_flags)) {
IVTV_DEBUG_INFO("close stopping decode\n");
@@ -832,10 +838,7 @@ static void ivtv_stop_decoding(struct ivtv_open_id *id, int flags, u64 pts)
}
clear_bit(IVTV_F_S_APPL_IO, &s->s_flags);
clear_bit(IVTV_F_S_STREAMOFF, &s->s_flags);
- if (id->type == IVTV_DEC_STREAM_TYPE_YUV && test_bit(IVTV_F_I_DECODING_YUV, &itv->i_flags)) {
- /* Restore registers we've changed & clean up any mess we've made */
- ivtv_yuv_close(itv);
- }
+
if (itv->output_mode == OUT_UDMA_YUV && id->yuv_frames)
itv->output_mode = OUT_NONE;
@@ -883,7 +886,8 @@ int ivtv_v4l2_close(struct file *filp)
if (atomic_read(&itv->capturing) > 0) {
/* Undo video mute */
ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
- itv->params.video_mute | (itv->params.video_mute_yuv << 8));
+ v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute) |
+ (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
}
/* Done! Unmute and continue. */
ivtv_unmute(itv);
@@ -909,12 +913,32 @@ int ivtv_v4l2_close(struct file *filp)
static int ivtv_serialized_open(struct ivtv_stream *s, struct file *filp)
{
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ struct video_device *vdev = video_devdata(filp);
+#endif
struct ivtv *itv = s->itv;
struct ivtv_open_id *item;
int res = 0;
IVTV_DEBUG_FILE("open %s\n", s->name);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ /* Unless ivtv_fw_debug is set, error out if firmware dead. */
+ if (ivtv_fw_debug) {
+ IVTV_WARN("Opening %s with dead firmware lockout disabled\n",
+ video_device_node_name(vdev));
+ IVTV_WARN("Selected firmware errors will be ignored\n");
+ } else {
+#else
+ if (1) {
+#endif
+ res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+ if (res == -EAGAIN)
+ res = ivtv_firmware_check(itv, "ivtv_serialized_open");
+ if (res < 0)
+ return -EIO;
+ }
+
if (s->type == IVTV_DEC_STREAM_TYPE_MPG &&
test_bit(IVTV_F_S_CLAIMED, &itv->streams[IVTV_DEC_STREAM_TYPE_YUV].s_flags))
return -EBUSY;
diff --git a/drivers/media/video/ivtv/ivtv-firmware.c b/drivers/media/video/ivtv/ivtv-firmware.c
index a71e8ba306b0..4df01947a7df 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.c
+++ b/drivers/media/video/ivtv/ivtv-firmware.c
@@ -23,7 +23,10 @@
#include "ivtv-mailbox.h"
#include "ivtv-firmware.h"
#include "ivtv-yuv.h"
+#include "ivtv-ioctl.h"
+#include "ivtv-cards.h"
#include <linux/firmware.h>
+#include <media/saa7127.h>
#define IVTV_MASK_SPU_ENABLE 0xFFFFFFFE
#define IVTV_MASK_VPU_ENABLE15 0xFFFFFFF6
@@ -245,9 +248,9 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
volatile u8 __iomem *mem_offset;
data[0] = 0;
- data[1] = itv->params.width; /* YUV source width */
- data[2] = itv->params.height;
- data[3] = itv->params.audio_properties; /* Audio settings to use,
+ data[1] = itv->cxhdl.width; /* YUV source width */
+ data[2] = itv->cxhdl.height;
+ data[3] = itv->cxhdl.audio_properties; /* Audio settings to use,
bitmap. see docs. */
if (ivtv_api(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, data)) {
IVTV_ERR("ivtv_init_mpeg_decoder failed to set decoder source\n");
@@ -271,3 +274,122 @@ void ivtv_init_mpeg_decoder(struct ivtv *itv)
}
ivtv_vapi(itv, CX2341X_DEC_STOP_PLAYBACK, 4, 0, 0, 0, 1);
}
+
+/* Try to restart the card & restore previous settings */
+int ivtv_firmware_restart(struct ivtv *itv)
+{
+ int rc = 0;
+ v4l2_std_id std;
+ struct ivtv_open_id fh;
+ fh.itv = itv;
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)
+ /* Display test image during restart */
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+ SAA7127_INPUT_TYPE_TEST_IMAGE,
+ itv->card->video_outputs[itv->active_output].video_output,
+ 0);
+
+ mutex_lock(&itv->udma.lock);
+
+ rc = ivtv_firmware_init(itv);
+ if (rc) {
+ mutex_unlock(&itv->udma.lock);
+ return rc;
+ }
+
+ /* Allow settings to reload */
+ ivtv_mailbox_cache_invalidate(itv);
+
+ /* Restore video standard */
+ std = itv->std;
+ itv->std = 0;
+ ivtv_s_std(NULL, &fh, &std);
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ ivtv_init_mpeg_decoder(itv);
+
+ /* Restore framebuffer if active */
+ if (itv->ivtvfb_restore)
+ itv->ivtvfb_restore(itv);
+
+ /* Restore alpha settings */
+ ivtv_set_osd_alpha(itv);
+
+ /* Restore normal output */
+ ivtv_call_hw(itv, IVTV_HW_SAA7127, video, s_routing,
+ SAA7127_INPUT_TYPE_NORMAL,
+ itv->card->video_outputs[itv->active_output].video_output,
+ 0);
+ }
+
+ mutex_unlock(&itv->udma.lock);
+ return rc;
+}
+
+/* Check firmware running state. The checks fall through
+ allowing multiple failures to be logged. */
+int ivtv_firmware_check(struct ivtv *itv, char *where)
+{
+ int res = 0;
+
+ /* Check encoder is still running */
+ if (ivtv_vapi(itv, CX2341X_ENC_PING_FW, 0) < 0) {
+ IVTV_WARN("Encoder has died : %s\n", where);
+ res = -1;
+ }
+
+ /* Also check audio. Only check if not in use & encoder is okay */
+ if (!res && !atomic_read(&itv->capturing) &&
+ (!atomic_read(&itv->decoding) ||
+ (atomic_read(&itv->decoding) < 2 && test_bit(IVTV_F_I_DEC_YUV,
+ &itv->i_flags)))) {
+
+ if (ivtv_vapi(itv, CX2341X_ENC_MISC, 1, 12) < 0) {
+ IVTV_WARN("Audio has died (Encoder OK) : %s\n", where);
+ res = -2;
+ }
+ }
+
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
+ /* Second audio check. Skip if audio already failed */
+ if (res != -2 && read_dec(0x100) != read_dec(0x104)) {
+ /* Wait & try again to be certain. */
+ ivtv_msleep_timeout(14, 0);
+ if (read_dec(0x100) != read_dec(0x104)) {
+ IVTV_WARN("Audio has died (Decoder) : %s\n",
+ where);
+ res = -1;
+ }
+ }
+
+ /* Check decoder is still running */
+ if (ivtv_vapi(itv, CX2341X_DEC_PING_FW, 0) < 0) {
+ IVTV_WARN("Decoder has died : %s\n", where);
+ res = -1;
+ }
+ }
+
+ /* If something failed & currently idle, try to reload */
+ if (res && !atomic_read(&itv->capturing) &&
+ !atomic_read(&itv->decoding)) {
+ IVTV_INFO("Detected in %s that firmware had failed - "
+ "Reloading\n", where);
+ res = ivtv_firmware_restart(itv);
+ /*
+ * Even if restarted ok, still signal a problem had occured.
+ * The caller can come through this function again to check
+ * if things are really ok after the restart.
+ */
+ if (!res) {
+ IVTV_INFO("Firmware restart okay\n");
+ res = -EAGAIN;
+ } else {
+ IVTV_INFO("Firmware restart failed\n");
+ }
+ } else if (res) {
+ res = -EIO;
+ }
+
+ return res;
+}
diff --git a/drivers/media/video/ivtv/ivtv-firmware.h b/drivers/media/video/ivtv/ivtv-firmware.h
index 041ba94e65bc..52bb4e5598fd 100644
--- a/drivers/media/video/ivtv/ivtv-firmware.h
+++ b/drivers/media/video/ivtv/ivtv-firmware.h
@@ -26,5 +26,6 @@ int ivtv_firmware_init(struct ivtv *itv);
void ivtv_firmware_versions(struct ivtv *itv);
void ivtv_halt_firmware(struct ivtv *itv);
void ivtv_init_mpeg_decoder(struct ivtv *itv);
+int ivtv_firmware_check(struct ivtv *itv, char *where);
#endif
diff --git a/drivers/media/video/ivtv/ivtv-gpio.c b/drivers/media/video/ivtv/ivtv-gpio.c
index aede061cae5d..8f0d07789053 100644
--- a/drivers/media/video/ivtv/ivtv-gpio.c
+++ b/drivers/media/video/ivtv/ivtv-gpio.c
@@ -24,6 +24,7 @@
#include "ivtv-gpio.h"
#include "tuner-xc2028.h"
#include <media/tuner.h>
+#include <media/v4l2-ctrls.h>
/*
* GPIO assignment of Yuan MPG600/MPG160
@@ -149,16 +150,10 @@ static inline struct ivtv *sd_to_ivtv(struct v4l2_subdev *sd)
return container_of(sd, struct ivtv, sd_gpio);
}
-static struct v4l2_queryctrl gpio_ctrl_mute = {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
-};
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct ivtv, hdl_gpio)->sd_gpio;
+}
static int subdev_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
{
@@ -262,40 +257,24 @@ static int subdev_s_audio_routing(struct v4l2_subdev *sd,
return 0;
}
-static int subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int subdev_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
struct ivtv *itv = sd_to_ivtv(sd);
u16 mask, data;
- 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_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct ivtv *itv = sd_to_ivtv(sd);
- u16 mask, data;
-
- 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;
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ mask = itv->card->gpio_audio_mute.mask;
+ data = ctrl->val ? 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;
+ }
+ return -EINVAL;
}
-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)
{
@@ -304,6 +283,7 @@ static int subdev_log_status(struct v4l2_subdev *sd)
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));
+ v4l2_ctrl_handler_log_status(&itv->hdl_gpio, sd->name);
return 0;
}
@@ -327,11 +307,19 @@ static int subdev_s_video_routing(struct v4l2_subdev *sd,
return 0;
}
+static const struct v4l2_ctrl_ops gpio_ctrl_ops = {
+ .s_ctrl = subdev_s_ctrl,
+};
+
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,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
};
static const struct v4l2_subdev_tuner_ops subdev_tuner_ops = {
@@ -375,5 +363,12 @@ int ivtv_gpio_init(struct ivtv *itv)
v4l2_subdev_init(&itv->sd_gpio, &subdev_ops);
snprintf(itv->sd_gpio.name, sizeof(itv->sd_gpio.name), "%s-gpio", itv->v4l2_dev.name);
itv->sd_gpio.grp_id = IVTV_HW_GPIO;
+ v4l2_ctrl_handler_init(&itv->hdl_gpio, 1);
+ v4l2_ctrl_new_std(&itv->hdl_gpio, &gpio_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ if (itv->hdl_gpio.error)
+ return itv->hdl_gpio.error;
+ itv->sd_gpio.ctrl_handler = &itv->hdl_gpio;
+ v4l2_ctrl_handler_setup(&itv->hdl_gpio);
return v4l2_device_register_subdev(&itv->v4l2_dev, &itv->sd_gpio);
}
diff --git a/drivers/media/video/ivtv/ivtv-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index a5b92d109c6c..9fb86a081c0f 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -63,6 +63,7 @@
#include "ivtv-cards.h"
#include "ivtv-gpio.h"
#include "ivtv-i2c.h"
+#include <media/cx25840.h>
/* i2c implementation for cx23415/6 chip, ivtv project.
* Author: Kevin Thayer (nufan_wfk at yahoo.com)
@@ -93,6 +94,7 @@
#define IVTV_HAUP_INT_IR_RX_I2C_ADDR 0x18
#define IVTV_Z8F0811_IR_TX_I2C_ADDR 0x70
#define IVTV_Z8F0811_IR_RX_I2C_ADDR 0x71
+#define IVTV_ADAPTEC_IR_ADDR 0x6b
/* This array should match the IVTV_HW_ defines */
static const u8 hw_addrs[] = {
@@ -117,31 +119,7 @@ static const u8 hw_addrs[] = {
IVTV_HAUP_INT_IR_RX_I2C_ADDR, /* IVTV_HW_I2C_IR_RX_HAUP_INT */
IVTV_Z8F0811_IR_TX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_TX_HAUP */
IVTV_Z8F0811_IR_RX_I2C_ADDR, /* IVTV_HW_Z8F0811_IR_RX_HAUP */
-};
-
-/* 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,
- NULL, /* IVTV_HW_I2C_IR_RX_AVER */
- NULL, /* IVTV_HW_I2C_IR_RX_HAUP_EXT */
- NULL, /* IVTV_HW_I2C_IR_RX_HAUP_INT */
- NULL, /* IVTV_HW_Z8F0811_IR_TX_HAUP */
- NULL, /* IVTV_HW_Z8F0811_IR_RX_HAUP */
+ IVTV_ADAPTEC_IR_ADDR, /* IVTV_HW_I2C_IR_RX_ADAPTEC */
};
/* This array should match the IVTV_HW_ defines */
@@ -167,8 +145,34 @@ static const char * const hw_devicenames[] = {
"ir_video", /* IVTV_HW_I2C_IR_RX_HAUP_INT */
"ir_tx_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_TX_HAUP */
"ir_rx_z8f0811_haup", /* IVTV_HW_Z8F0811_IR_RX_HAUP */
+ "ir_video", /* IVTV_HW_I2C_IR_RX_ADAPTEC */
};
+static int get_key_adaptec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
+{
+ unsigned char keybuf[4];
+
+ keybuf[0] = 0x00;
+ i2c_master_send(ir->c, keybuf, 1);
+ /* poll IR chip */
+ if (i2c_master_recv(ir->c, keybuf, sizeof(keybuf)) != sizeof(keybuf)) {
+ return 0;
+ }
+
+ /* key pressed ? */
+ if (keybuf[2] == 0xff)
+ return 0;
+
+ /* remove repeat bit */
+ keybuf[2] &= 0x7f;
+ keybuf[3] |= 0x80;
+
+ *ir_key = keybuf[3] | keybuf[2] << 8 | keybuf[1] << 16 |keybuf[0] << 24;
+ *ir_raw = *ir_key;
+
+ return 1;
+}
+
static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
{
struct i2c_board_info info;
@@ -182,8 +186,8 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
return -1;
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, type, I2C_NAME_SIZE);
- return i2c_new_probed_device(adap, &info, addr_list) == NULL
- ? -1 : 0;
+ return i2c_new_probed_device(adap, &info, addr_list, NULL)
+ == NULL ? -1 : 0;
}
/* Only allow one IR receiver to be registered per board */
@@ -196,7 +200,7 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
init_data->ir_codes = RC_MAP_AVERMEDIA_CARDBUS;
init_data->internal_get_key_func =
IR_KBD_GET_KEY_AVERMEDIA_CARDBUS;
- init_data->type = IR_TYPE_OTHER;
+ init_data->type = RC_TYPE_OTHER;
init_data->name = "AVerMedia AVerTV card";
break;
case IVTV_HW_I2C_IR_RX_HAUP_EXT:
@@ -204,15 +208,22 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
/* Default to old black remote */
init_data->ir_codes = RC_MAP_RC5_TV;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
- init_data->type = IR_TYPE_RC5;
+ init_data->type = RC_TYPE_RC5;
init_data->name = itv->card_name;
break;
case IVTV_HW_Z8F0811_IR_RX_HAUP:
/* Default to grey remote */
init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
- init_data->type = IR_TYPE_RC5;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = itv->card_name;
+ break;
+ case IVTV_HW_I2C_IR_RX_ADAPTEC:
+ init_data->get_key = get_key_adaptec;
init_data->name = itv->card_name;
+ /* FIXME: The protocol and RC_MAP needs to be corrected */
+ init_data->ir_codes = RC_MAP_EMPTY;
+ init_data->type = RC_TYPE_UNKNOWN;
break;
}
@@ -220,7 +231,8 @@ static int ivtv_i2c_new_ir(struct ivtv *itv, u32 hw, const char *type, u8 addr)
info.platform_data = init_data;
strlcpy(info.type, type, I2C_NAME_SIZE);
- return i2c_new_probed_device(adap, &info, addr_list) == NULL ? -1 : 0;
+ return i2c_new_probed_device(adap, &info, addr_list, NULL) == NULL ?
+ -1 : 0;
}
/* Instantiate the IR receiver device using probing -- undesirable */
@@ -241,21 +253,18 @@ struct i2c_client *ivtv_i2c_new_ir_legacy(struct ivtv *itv)
const unsigned short addr_list[] = {
0x1a, /* Hauppauge IR external - collides with WM8739 */
0x18, /* Hauppauge IR internal */
- 0x71, /* Hauppauge IR (PVR150) */
- 0x6b, /* Adaptec IR */
I2C_CLIENT_END
};
memset(&info, 0, sizeof(struct i2c_board_info));
strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list);
+ return i2c_new_probed_device(&itv->i2c_adap, &info, addr_list, NULL);
}
int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
{
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;
@@ -263,19 +272,16 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
return -1;
if (hw == IVTV_HW_TUNER) {
/* special tuner handling */
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type,
- 0, itv->card_i2c->radio);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->radio);
if (sd)
sd->grp_id = 1 << idx;
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type,
- 0, itv->card_i2c->demod);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->demod);
if (sd)
sd->grp_id = 1 << idx;
- sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type,
- 0, itv->card_i2c->tv);
+ sd = v4l2_i2c_new_subdev(&itv->v4l2_dev, adap, type, 0,
+ itv->card_i2c->tv);
if (sd)
sd->grp_id = 1 << idx;
return sd ? 0 : -1;
@@ -291,10 +297,21 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
/* It's an I2C device other than an analog tuner or IR chip */
if (hw == IVTV_HW_UPD64031A || hw == IVTV_HW_UPD6408X) {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type, 0, I2C_ADDRS(hw_addrs[idx]));
+ adap, type, 0, I2C_ADDRS(hw_addrs[idx]));
+ } else if (hw == IVTV_HW_CX25840) {
+ struct cx25840_platform_data pdata;
+ struct i2c_board_info cx25840_info = {
+ .type = "cx25840",
+ .addr = hw_addrs[idx],
+ .platform_data = &pdata,
+ };
+
+ pdata.pvr150_workaround = itv->pvr150_workaround;
+ sd = v4l2_i2c_new_subdev_board(&itv->v4l2_dev, adap,
+ &cx25840_info, NULL);
} else {
sd = v4l2_i2c_new_subdev(&itv->v4l2_dev,
- adap, mod, type, hw_addrs[idx], NULL);
+ adap, type, hw_addrs[idx], NULL);
}
if (sd)
sd->grp_id = 1 << idx;
@@ -698,8 +715,7 @@ int init_ivtv_i2c(struct ivtv *itv)
/* Sanity checks for the I2C hardware arrays. They must be the
* same size.
*/
- if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs) ||
- ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_modules)) {
+ if (ARRAY_SIZE(hw_devicenames) != ARRAY_SIZE(hw_addrs)) {
IVTV_ERR("Mismatched I2C hardware arrays\n");
return -ENODEV;
}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index fa9f0d958f96..b686da5e4326 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -37,7 +37,6 @@
#include <media/v4l2-chip-ident.h>
#include <media/v4l2-event.h>
#include <linux/dvb/audio.h>
-#include <linux/i2c-id.h>
u16 ivtv_service2vbi(int type)
{
@@ -162,7 +161,7 @@ int ivtv_set_speed(struct ivtv *itv, int speed)
data[0] |= (speed > 1000 || speed < -1500) ? 0x40000000 : 0;
data[1] = (speed < 0);
data[2] = speed < 0 ? 3 : 7;
- data[3] = itv->params.video_b_frames;
+ data[3] = v4l2_ctrl_g_ctrl(itv->cxhdl.video_b_frames);
data[4] = (speed == 1500 || speed == 500) ? itv->speed_mute_audio : 0;
data[5] = 0;
data[6] = 0;
@@ -339,8 +338,8 @@ static int ivtv_g_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
struct ivtv *itv = id->itv;
struct v4l2_pix_format *pixfmt = &fmt->fmt.pix;
- pixfmt->width = itv->params.width;
- pixfmt->height = itv->params.height;
+ pixfmt->width = itv->cxhdl.width;
+ pixfmt->height = itv->cxhdl.height;
pixfmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
pixfmt->field = V4L2_FIELD_INTERLACED;
pixfmt->priv = 0;
@@ -568,7 +567,7 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
{
struct ivtv_open_id *id = fh;
struct ivtv *itv = id->itv;
- struct cx2341x_mpeg_params *p = &itv->params;
+ struct v4l2_mbus_framefmt mbus_fmt;
int ret = ivtv_try_fmt_vid_cap(file, fh, fmt);
int w = fmt->fmt.pix.width;
int h = fmt->fmt.pix.height;
@@ -576,17 +575,20 @@ static int ivtv_s_fmt_vid_cap(struct file *file, void *fh, struct v4l2_format *f
if (ret)
return ret;
- if (p->width == w && p->height == h)
+ if (itv->cxhdl.width == w && itv->cxhdl.height == h)
return 0;
if (atomic_read(&itv->capturing) > 0)
return -EBUSY;
- p->width = w;
- p->height = h;
- if (p->video_encoding == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
+ itv->cxhdl.width = w;
+ itv->cxhdl.height = h;
+ if (v4l2_ctrl_g_ctrl(itv->cxhdl.video_encoding) == V4L2_MPEG_VIDEO_ENCODING_MPEG_1)
fmt->fmt.pix.width /= 2;
- v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
+ mbus_fmt.width = fmt->fmt.pix.width;
+ mbus_fmt.height = h;
+ mbus_fmt.code = V4L2_MBUS_FMT_FIXED;
+ v4l2_subdev_call(itv->sd_video, video, s_mbus_fmt, &mbus_fmt);
return ivtv_g_fmt_vid_cap(file, fh, fmt);
}
@@ -1110,9 +1112,10 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
itv->std = *std;
itv->is_60hz = (*std & V4L2_STD_525_60) ? 1 : 0;
- itv->params.is_50hz = itv->is_50hz = !itv->is_60hz;
- itv->params.width = 720;
- itv->params.height = itv->is_50hz ? 576 : 480;
+ itv->is_50hz = !itv->is_60hz;
+ cx2341x_handler_set_50hz(&itv->cxhdl, itv->is_50hz);
+ itv->cxhdl.width = 720;
+ itv->cxhdl.height = itv->is_50hz ? 576 : 480;
itv->vbi.count = itv->is_50hz ? 18 : 12;
itv->vbi.start[0] = itv->is_50hz ? 6 : 10;
itv->vbi.start[1] = itv->is_50hz ? 318 : 273;
@@ -1153,7 +1156,7 @@ int ivtv_s_std(struct file *file, void *fh, v4l2_std_id *std)
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;
- itv->main_rect.height = itv->params.height;
+ itv->main_rect.height = itv->cxhdl.height;
ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
720, itv->main_rect.height, 0, 0);
yi->main_rect = itv->main_rect;
@@ -1550,7 +1553,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->v4l2_dev.name);
+ v4l2_ctrl_handler_log_status(&itv->cxhdl.hdl, itv->v4l2_dev.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];
@@ -1938,11 +1941,6 @@ static const struct v4l2_ioctl_ops ivtv_ioctl_ops = {
.vidioc_s_register = ivtv_s_register,
#endif
.vidioc_default = ivtv_default,
- .vidioc_queryctrl = ivtv_queryctrl,
- .vidioc_querymenu = ivtv_querymenu,
- .vidioc_g_ext_ctrls = ivtv_g_ext_ctrls,
- .vidioc_s_ext_ctrls = ivtv_s_ext_ctrls,
- .vidioc_try_ext_ctrls = ivtv_try_ext_ctrls,
.vidioc_subscribe_event = ivtv_subscribe_event,
.vidioc_unsubscribe_event = v4l2_event_unsubscribe,
};
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index fea1ec33b0df..9b4faf009196 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -71,19 +71,10 @@ static void ivtv_pio_work_handler(struct ivtv *itv)
write_reg(IVTV_IRQ_ENC_PIO_COMPLETE, 0x44);
}
-void ivtv_irq_work_handler(struct work_struct *work)
+void ivtv_irq_work_handler(struct kthread_work *work)
{
- struct ivtv *itv = container_of(work, struct ivtv, irq_work_queue);
+ struct ivtv *itv = container_of(work, struct ivtv, irq_work);
- DEFINE_WAIT(wait);
-
- if (test_and_clear_bit(IVTV_F_I_WORK_INITED, &itv->i_flags)) {
- struct sched_param param = { .sched_priority = 99 };
-
- /* This thread must use the FIFO scheduler as it
- is realtime sensitive. */
- sched_setscheduler(current, SCHED_FIFO, &param);
- }
if (test_and_clear_bit(IVTV_F_I_WORK_HANDLER_PIO, &itv->i_flags))
ivtv_pio_work_handler(itv);
@@ -975,7 +966,7 @@ irqreturn_t ivtv_irq_handler(int irq, void *dev_id)
}
if (test_and_clear_bit(IVTV_F_I_HAVE_WORK, &itv->i_flags)) {
- queue_work(itv->irq_work_queues, &itv->irq_work_queue);
+ queue_kthread_work(&itv->irq_worker, &itv->irq_work);
}
spin_unlock(&itv->dma_reg_lock);
diff --git a/drivers/media/video/ivtv/ivtv-irq.h b/drivers/media/video/ivtv/ivtv-irq.h
index f879a5822e71..1e84433737cc 100644
--- a/drivers/media/video/ivtv/ivtv-irq.h
+++ b/drivers/media/video/ivtv/ivtv-irq.h
@@ -46,7 +46,7 @@
irqreturn_t ivtv_irq_handler(int irq, void *dev_id);
-void ivtv_irq_work_handler(struct work_struct *work);
+void ivtv_irq_work_handler(struct kthread_work *work);
void ivtv_dma_stream_dec_prepare(struct ivtv_stream *s, u32 offset, int lock);
void ivtv_unfinished_dma(unsigned long arg);
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 84577f6f41a2..e3ce96763785 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -377,3 +377,11 @@ void ivtv_api_get_data(struct ivtv_mailbox_data *mbdata, int mb,
for (i = 0; i < argc; i++, p++)
data[i] = readl(p);
}
+
+/* Wipe api cache */
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv)
+{
+ int i;
+ for (i = 0; i < 256; i++)
+ itv->api_cache[i].last_jiffies = 0;
+}
diff --git a/drivers/media/video/ivtv/ivtv-mailbox.h b/drivers/media/video/ivtv/ivtv-mailbox.h
index 8247662c928e..2c834d2cb56f 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.h
+++ b/drivers/media/video/ivtv/ivtv-mailbox.h
@@ -30,5 +30,6 @@ int ivtv_api(struct ivtv *itv, int cmd, int args, u32 data[]);
int ivtv_vapi_result(struct ivtv *itv, u32 data[CX2341X_MBOX_MAX_DATA], int cmd, int args, ...);
int ivtv_vapi(struct ivtv *itv, int cmd, int args, ...);
int ivtv_api_func(void *priv, u32 cmd, int in, int out, u32 data[CX2341X_MBOX_MAX_DATA]);
+void ivtv_mailbox_cache_invalidate(struct ivtv *itv);
#endif
diff --git a/drivers/media/video/ivtv/ivtv-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index de4288cc1889..512607e0cda3 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -42,6 +42,7 @@
#include "ivtv-yuv.h"
#include "ivtv-cards.h"
#include "ivtv-streams.h"
+#include "ivtv-firmware.h"
#include <media/v4l2-event.h>
static const struct v4l2_file_operations ivtv_v4l2_enc_fops = {
@@ -209,6 +210,7 @@ static int ivtv_prep_dev(struct ivtv *itv, int type)
s->vdev->num = num;
s->vdev->v4l2_dev = &itv->v4l2_dev;
+ s->vdev->ctrl_handler = itv->v4l2_dev.ctrl_handler;
s->vdev->fops = ivtv_stream_info[type].fops;
s->vdev->release = video_device_release;
s->vdev->tvnorms = V4L2_STD_ALL;
@@ -450,7 +452,6 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
{
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv *itv = s->itv;
- struct cx2341x_mpeg_params *p = &itv->params;
int captype = 0, subtype = 0;
int enable_passthrough = 0;
@@ -471,7 +472,7 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
}
itv->mpg_data_received = itv->vbi_data_inserted = 0;
itv->dualwatch_jiffies = jiffies;
- itv->dualwatch_stereo_mode = p->audio_properties & 0x0300;
+ itv->dualwatch_stereo_mode = v4l2_ctrl_g_ctrl(itv->cxhdl.audio_mode);
itv->search_pack_header = 0;
break;
@@ -559,12 +560,12 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
itv->pgm_info_offset, itv->pgm_info_num);
/* Setup API for Stream */
- cx2341x_update(itv, ivtv_api_func, NULL, p);
+ cx2341x_handler_setup(&itv->cxhdl);
/* mute if capturing radio */
if (test_bit(IVTV_F_I_RADIO_USER, &itv->i_flags))
ivtv_vapi(itv, CX2341X_ENC_MUTE_VIDEO, 1,
- 1 | (p->video_mute_yuv << 8));
+ 1 | (v4l2_ctrl_g_ctrl(itv->cxhdl.video_mute_yuv) << 8));
}
/* Vsync Setup */
@@ -580,6 +581,8 @@ int ivtv_start_v4l2_encode_stream(struct ivtv_stream *s)
clear_bit(IVTV_F_I_EOS, &itv->i_flags);
+ cx2341x_handler_set_busy(&itv->cxhdl, 1);
+
/* Initialize Digitizer for Capture */
/* Avoid tinny audio problem - ensure audio clocks are going */
v4l2_subdev_call(itv->sd_audio, audio, s_stream, 1);
@@ -616,14 +619,18 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
{
u32 data[CX2341X_MBOX_MAX_DATA];
struct ivtv *itv = s->itv;
- struct cx2341x_mpeg_params *p = &itv->params;
int datatype;
+ u16 width;
+ u16 height;
if (s->vdev == NULL)
return -EINVAL;
IVTV_DEBUG_INFO("Setting some initial decoder settings\n");
+ width = itv->cxhdl.width;
+ height = itv->cxhdl.height;
+
/* set audio mode to left/stereo for dual/stereo mode. */
ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
@@ -646,7 +653,14 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
2 = yuv_from_host */
switch (s->type) {
case IVTV_DEC_STREAM_TYPE_YUV:
- datatype = itv->output_mode == OUT_PASSTHROUGH ? 1 : 2;
+ if (itv->output_mode == OUT_PASSTHROUGH) {
+ datatype = 1;
+ } else {
+ /* Fake size to avoid switching video standard */
+ datatype = 2;
+ width = 720;
+ height = itv->is_out_50hz ? 576 : 480;
+ }
IVTV_DEBUG_INFO("Setup DEC YUV Stream data[0] = %d\n", datatype);
break;
case IVTV_DEC_STREAM_TYPE_MPG:
@@ -655,15 +669,21 @@ static int ivtv_setup_v4l2_decode_stream(struct ivtv_stream *s)
break;
}
if (ivtv_vapi(itv, CX2341X_DEC_SET_DECODER_SOURCE, 4, datatype,
- p->width, p->height, p->audio_properties)) {
+ width, height, itv->cxhdl.audio_properties)) {
IVTV_DEBUG_WARN("Couldn't initialize decoder source\n");
}
- return 0;
+
+ /* Decoder sometimes dies here, so wait a moment */
+ ivtv_msleep_timeout(10, 0);
+
+ /* Known failure point for firmware, so check */
+ return ivtv_firmware_check(itv, "ivtv_setup_v4l2_decode_stream");
}
int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
{
struct ivtv *itv = s->itv;
+ int rc;
if (s->vdev == NULL)
return -EINVAL;
@@ -673,7 +693,11 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
IVTV_DEBUG_INFO("Starting decode stream %s (gop_offset %d)\n", s->name, gop_offset);
- ivtv_setup_v4l2_decode_stream(s);
+ rc = ivtv_setup_v4l2_decode_stream(s);
+ if (rc < 0) {
+ clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
+ return rc;
+ }
/* set dma size to 65536 bytes */
ivtv_vapi(itv, CX2341X_DEC_SET_DMA_BLOCK_SIZE, 1, 65536);
@@ -697,6 +721,9 @@ int ivtv_start_v4l2_decode_stream(struct ivtv_stream *s, int gop_offset)
/* start playback */
ivtv_vapi(itv, CX2341X_DEC_START_PLAYBACK, 2, gop_offset, 0);
+ /* Let things settle before we actually start */
+ ivtv_msleep_timeout(10, 0);
+
/* Clear the following Interrupt mask bits for decoding */
ivtv_clear_irq_mask(itv, IVTV_IRQ_MASK_DECODE);
IVTV_DEBUG_IRQ("IRQ Mask is now: 0x%08x\n", itv->irqmask);
@@ -821,6 +848,8 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
return 0;
}
+ cx2341x_handler_set_busy(&itv->cxhdl, 0);
+
/* Set the following Interrupt mask bits for capture */
ivtv_set_irq_mask(itv, IVTV_IRQ_MASK_CAPTURE);
del_timer(&itv->dma_timer);
@@ -893,6 +922,9 @@ int ivtv_stop_v4l2_decode_stream(struct ivtv_stream *s, int flags, u64 pts)
clear_bit(IVTV_F_S_STREAMING, &s->s_flags);
ivtv_flush_queues(s);
+ /* decoder needs time to settle */
+ ivtv_msleep_timeout(40, 0);
+
/* decrement decoding */
atomic_dec(&itv->decoding);
@@ -938,7 +970,8 @@ int ivtv_passthrough_mode(struct ivtv *itv, int enable)
/* Setup capture if not already done */
if (atomic_read(&itv->capturing) == 0) {
- cx2341x_update(itv, ivtv_api_func, NULL, &itv->params);
+ cx2341x_handler_setup(&itv->cxhdl);
+ cx2341x_handler_set_busy(&itv->cxhdl, 1);
}
/* Start Passthrough Mode */
@@ -959,6 +992,8 @@ int ivtv_passthrough_mode(struct ivtv *itv, int enable)
clear_bit(IVTV_F_S_PASSTHROUGH, &dec_stream->s_flags);
clear_bit(IVTV_F_S_STREAMING, &dec_stream->s_flags);
itv->output_mode = OUT_NONE;
+ if (atomic_read(&itv->capturing) == 0)
+ cx2341x_handler_set_busy(&itv->cxhdl, 0);
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-vbi.c b/drivers/media/video/ivtv/ivtv-vbi.c
index e1c347e5ebd8..2dfa957b0fd5 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.c
+++ b/drivers/media/video/ivtv/ivtv-vbi.c
@@ -92,54 +92,97 @@ static int odd_parity(u8 c)
return c & 1;
}
-void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t cnt)
+static void ivtv_write_vbi_line(struct ivtv *itv,
+ const struct v4l2_sliced_vbi_data *d,
+ struct vbi_cc *cc, int *found_cc)
{
struct vbi_info *vi = &itv->vbi;
- struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
- int found_cc = 0;
- size_t i;
-
- for (i = 0; i < cnt; i++) {
- const struct v4l2_sliced_vbi_data *d = sliced + i;
- if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
- if (d->field) {
- cc.even[0] = d->data[0];
- cc.even[1] = d->data[1];
- } else {
- cc.odd[0] = d->data[0];
- cc.odd[1] = d->data[1];
- }
- found_cc = 1;
+ if (d->id == V4L2_SLICED_CAPTION_525 && d->line == 21) {
+ if (d->field) {
+ cc->even[0] = d->data[0];
+ cc->even[1] = d->data[1];
+ } else {
+ cc->odd[0] = d->data[0];
+ cc->odd[1] = d->data[1];
}
- else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
- struct vbi_vps vps;
-
- vps.data[0] = d->data[2];
- vps.data[1] = d->data[8];
- vps.data[2] = d->data[9];
- vps.data[3] = d->data[10];
- vps.data[4] = d->data[11];
- if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
- vi->vps_payload = vps;
- set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
- }
+ *found_cc = 1;
+ } else if (d->id == V4L2_SLICED_VPS && d->line == 16 && d->field == 0) {
+ struct vbi_vps vps;
+
+ vps.data[0] = d->data[2];
+ vps.data[1] = d->data[8];
+ vps.data[2] = d->data[9];
+ vps.data[3] = d->data[10];
+ vps.data[4] = d->data[11];
+ if (memcmp(&vps, &vi->vps_payload, sizeof(vps))) {
+ vi->vps_payload = vps;
+ set_bit(IVTV_F_I_UPDATE_VPS, &itv->i_flags);
}
- else if (d->id == V4L2_SLICED_WSS_625 && d->line == 23 && d->field == 0) {
- int wss = d->data[0] | d->data[1] << 8;
+ } else if (d->id == V4L2_SLICED_WSS_625 &&
+ d->line == 23 && d->field == 0) {
+ int wss = d->data[0] | d->data[1] << 8;
- if (vi->wss_payload != wss) {
- vi->wss_payload = wss;
- set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
- }
+ if (vi->wss_payload != wss) {
+ vi->wss_payload = wss;
+ set_bit(IVTV_F_I_UPDATE_WSS, &itv->i_flags);
}
}
- if (found_cc && vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
- vi->cc_payload[vi->cc_payload_idx++] = cc;
+}
+
+static void ivtv_write_vbi_cc_lines(struct ivtv *itv, const struct vbi_cc *cc)
+{
+ struct vbi_info *vi = &itv->vbi;
+
+ if (vi->cc_payload_idx < ARRAY_SIZE(vi->cc_payload)) {
+ memcpy(&vi->cc_payload[vi->cc_payload_idx], cc,
+ sizeof(struct vbi_cc));
+ vi->cc_payload_idx++;
set_bit(IVTV_F_I_UPDATE_CC, &itv->i_flags);
}
}
+static void ivtv_write_vbi(struct ivtv *itv,
+ const struct v4l2_sliced_vbi_data *sliced,
+ size_t cnt)
+{
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+ int found_cc = 0;
+ size_t i;
+
+ for (i = 0; i < cnt; i++)
+ ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
+
+ if (found_cc)
+ ivtv_write_vbi_cc_lines(itv, &cc);
+}
+
+ssize_t
+ivtv_write_vbi_from_user(struct ivtv *itv,
+ const struct v4l2_sliced_vbi_data __user *sliced,
+ size_t cnt)
+{
+ struct vbi_cc cc = { .odd = { 0x80, 0x80 }, .even = { 0x80, 0x80 } };
+ int found_cc = 0;
+ size_t i;
+ struct v4l2_sliced_vbi_data d;
+ ssize_t ret = cnt * sizeof(struct v4l2_sliced_vbi_data);
+
+ for (i = 0; i < cnt; i++) {
+ if (copy_from_user(&d, sliced + i,
+ sizeof(struct v4l2_sliced_vbi_data))) {
+ ret = -EFAULT;
+ break;
+ }
+ ivtv_write_vbi_line(itv, sliced + i, &cc, &found_cc);
+ }
+
+ if (found_cc)
+ ivtv_write_vbi_cc_lines(itv, &cc);
+
+ return ret;
+}
+
static void copy_vbi_data(struct ivtv *itv, int lines, u32 pts_stamp)
{
int line = 0;
diff --git a/drivers/media/video/ivtv/ivtv-vbi.h b/drivers/media/video/ivtv/ivtv-vbi.h
index 970567b9194d..166dd0b75d0f 100644
--- a/drivers/media/video/ivtv/ivtv-vbi.h
+++ b/drivers/media/video/ivtv/ivtv-vbi.h
@@ -20,7 +20,10 @@
#ifndef IVTV_VBI_H
#define IVTV_VBI_H
-void ivtv_write_vbi(struct ivtv *itv, const struct v4l2_sliced_vbi_data *sliced, size_t count);
+ssize_t
+ivtv_write_vbi_from_user(struct ivtv *itv,
+ const struct v4l2_sliced_vbi_data __user *sliced,
+ size_t count);
void ivtv_process_vbi_data(struct ivtv *itv, struct ivtv_buffer *buf,
u64 pts_stamp, int streamtype);
int ivtv_used_line(struct ivtv *itv, int line, int field);
diff --git a/drivers/media/video/ivtv/ivtv-version.h b/drivers/media/video/ivtv/ivtv-version.h
index b530dec399d3..b67a4048f5aa 100644
--- a/drivers/media/video/ivtv/ivtv-version.h
+++ b/drivers/media/video/ivtv/ivtv-version.h
@@ -23,7 +23,7 @@
#define IVTV_DRIVER_NAME "ivtv"
#define IVTV_DRIVER_VERSION_MAJOR 1
#define IVTV_DRIVER_VERSION_MINOR 4
-#define IVTV_DRIVER_VERSION_PATCHLEVEL 1
+#define IVTV_DRIVER_VERSION_PATCHLEVEL 2
#define IVTV_VERSION __stringify(IVTV_DRIVER_VERSION_MAJOR) "." __stringify(IVTV_DRIVER_VERSION_MINOR) "." __stringify(IVTV_DRIVER_VERSION_PATCHLEVEL)
#define IVTV_DRIVER_VERSION KERNEL_VERSION(IVTV_DRIVER_VERSION_MAJOR,IVTV_DRIVER_VERSION_MINOR,IVTV_DRIVER_VERSION_PATCHLEVEL)
diff --git a/drivers/media/video/ivtv/ivtvfb.c b/drivers/media/video/ivtv/ivtvfb.c
index 49e1a283ed36..f0316d02f09f 100644
--- a/drivers/media/video/ivtv/ivtvfb.c
+++ b/drivers/media/video/ivtv/ivtvfb.c
@@ -53,6 +53,7 @@
#include "ivtv-i2c.h"
#include "ivtv-udma.h"
#include "ivtv-mailbox.h"
+#include "ivtv-firmware.h"
/* card parameters */
static int ivtvfb_card_id = -1;
@@ -178,6 +179,12 @@ struct osd_info {
struct fb_info ivtvfb_info;
struct fb_var_screeninfo ivtvfb_defined;
struct fb_fix_screeninfo ivtvfb_fix;
+
+ /* Used for a warm start */
+ struct fb_var_screeninfo fbvar_cur;
+ int blank_cur;
+ u32 palette_cur[256];
+ u32 pan_cur;
};
struct ivtv_osd_coords {
@@ -199,6 +206,7 @@ static int ivtvfb_get_framebuffer(struct ivtv *itv, u32 *fbbase,
u32 data[CX2341X_MBOX_MAX_DATA];
int rc;
+ ivtv_firmware_check(itv, "ivtvfb_get_framebuffer");
rc = ivtv_vapi_result(itv, data, CX2341X_OSD_GET_FRAMEBUFFER, 0);
*fbbase = data[0];
*fblength = data[1];
@@ -458,6 +466,8 @@ static int ivtvfb_ioctl(struct fb_info *info, unsigned int cmd, unsigned long ar
struct fb_vblank vblank;
u32 trace;
+ memset(&vblank, 0, sizeof(struct fb_vblank));
+
vblank.flags = FB_VBLANK_HAVE_COUNT |FB_VBLANK_HAVE_VCOUNT |
FB_VBLANK_HAVE_VSYNC;
trace = read_reg(IVTV_REG_DEC_LINE_FIELD) >> 16;
@@ -581,8 +591,10 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
ivtv_window.height = var->yres;
/* Minimum margin cannot be 0, as X won't allow such a mode */
- if (!var->upper_margin) var->upper_margin++;
- if (!var->left_margin) var->left_margin++;
+ if (!var->upper_margin)
+ var->upper_margin++;
+ if (!var->left_margin)
+ var->left_margin++;
ivtv_window.top = var->upper_margin - 1;
ivtv_window.left = var->left_margin - 1;
@@ -595,6 +607,9 @@ static int ivtvfb_set_var(struct ivtv *itv, struct fb_var_screeninfo *var)
/* Force update of yuv registers */
itv->yuv_info.yuv_forced_update = 1;
+ /* Keep a copy of these settings */
+ memcpy(&oi->fbvar_cur, var, sizeof(oi->fbvar_cur));
+
IVTVFB_DEBUG_INFO("Display size: %dx%d (virtual %dx%d) @ %dbpp\n",
var->xres, var->yres,
var->xres_virtual, var->yres_virtual,
@@ -829,6 +844,8 @@ static int ivtvfb_pan_display(struct fb_var_screeninfo *var, struct fb_info *inf
itv->yuv_info.osd_y_pan = var->yoffset;
/* Force update of yuv registers */
itv->yuv_info.yuv_forced_update = 1;
+ /* Remember this value */
+ itv->osd_info->pan_cur = osd_pan_index;
return 0;
}
@@ -842,6 +859,7 @@ static int ivtvfb_set_par(struct fb_info *info)
rc = ivtvfb_set_var(itv, &info->var);
ivtvfb_pan_display(&info->var, info);
ivtvfb_get_fix(itv, &info->fix);
+ ivtv_firmware_check(itv, "ivtvfb_set_par");
return rc;
}
@@ -859,6 +877,7 @@ static int ivtvfb_setcolreg(unsigned regno, unsigned red, unsigned green,
if (info->var.bits_per_pixel <= 8) {
write_reg(regno, 0x02a30);
write_reg(color, 0x02a34);
+ itv->osd_info->palette_cur[regno] = color;
return 0;
}
if (regno >= 16)
@@ -911,6 +930,7 @@ static int ivtvfb_blank(int blank_mode, struct fb_info *info)
ivtv_vapi(itv, CX2341X_OSD_SET_STATE, 1, 0);
break;
}
+ itv->osd_info->blank_cur = blank_mode;
return 0;
}
@@ -929,6 +949,21 @@ static struct fb_ops ivtvfb_ops = {
.fb_blank = ivtvfb_blank,
};
+/* Restore hardware after firmware restart */
+static void ivtvfb_restore(struct ivtv *itv)
+{
+ struct osd_info *oi = itv->osd_info;
+ int i;
+
+ ivtvfb_set_var(itv, &oi->fbvar_cur);
+ ivtvfb_blank(oi->blank_cur, &oi->ivtvfb_info);
+ for (i = 0; i < 256; i++) {
+ write_reg(i, 0x02a30);
+ write_reg(oi->palette_cur[i], 0x02a34);
+ }
+ write_reg(oi->pan_cur, 0x02a0c);
+}
+
/* Initialization */
@@ -1066,7 +1101,11 @@ static int ivtvfb_init_io(struct ivtv *itv)
}
mutex_unlock(&itv->serialize_lock);
- ivtvfb_get_framebuffer(itv, &oi->video_rbase, &oi->video_buffer_size);
+ if (ivtvfb_get_framebuffer(itv, &oi->video_rbase,
+ &oi->video_buffer_size) < 0) {
+ IVTVFB_ERR("Firmware failed to respond\n");
+ return -EIO;
+ }
/* The osd buffer size depends on the number of video buffers allocated
on the PVR350 itself. For now we'll hardcode the smallest osd buffer
@@ -1158,8 +1197,11 @@ static int ivtvfb_init_card(struct ivtv *itv)
}
/* Find & setup the OSD buffer */
- if ((rc = ivtvfb_init_io(itv)))
+ rc = ivtvfb_init_io(itv);
+ if (rc) {
+ ivtvfb_release_buffers(itv);
return rc;
+ }
/* Set the startup video mode information */
if ((rc = ivtvfb_init_vidmode(itv))) {
@@ -1185,6 +1227,9 @@ static int ivtvfb_init_card(struct ivtv *itv)
/* Enable the osd */
ivtvfb_blank(FB_BLANK_UNBLANK, &itv->osd_info->ivtvfb_info);
+ /* Enable restart */
+ itv->ivtvfb_restore = ivtvfb_restore;
+
/* Allocate DMA */
ivtv_udma_alloc(itv);
return 0;
@@ -1196,7 +1241,7 @@ 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, v4l2_dev);
- if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT) {
if (ivtvfb_init_card(itv) == 0) {
IVTVFB_INFO("Framebuffer registered on %s\n",
itv->v4l2_dev.name);
@@ -1210,15 +1255,17 @@ 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, v4l2_dev);
+ struct osd_info *oi = itv->osd_info;
- if (itv && (itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
+ if (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);
+ itv->ivtvfb_restore = NULL;
+ ivtvfb_blank(FB_BLANK_VSYNC_SUSPEND, &oi->ivtvfb_info);
ivtvfb_release_buffers(itv);
itv->osd_video_pbase = 0;
}
diff --git a/drivers/media/video/ks0127.c b/drivers/media/video/ks0127.c
index 94734828053b..afa91182b448 100644
--- a/drivers/media/video/ks0127.c
+++ b/drivers/media/video/ks0127.c
@@ -43,7 +43,6 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include "ks0127.h"
MODULE_DESCRIPTION("KS0127 video decoder driver");
@@ -712,9 +711,25 @@ static const struct i2c_device_id ks0127_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ks0127_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "ks0127",
- .probe = ks0127_probe,
- .remove = ks0127_remove,
- .id_table = ks0127_id,
+static struct i2c_driver ks0127_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ks0127",
+ },
+ .probe = ks0127_probe,
+ .remove = ks0127_remove,
+ .id_table = ks0127_id,
};
+
+static __init int init_ks0127(void)
+{
+ return i2c_add_driver(&ks0127_driver);
+}
+
+static __exit void exit_ks0127(void)
+{
+ i2c_del_driver(&ks0127_driver);
+}
+
+module_init(init_ks0127);
+module_exit(exit_ks0127);
diff --git a/drivers/media/video/m52790.c b/drivers/media/video/m52790.c
index 4491d018eba6..5e1c9a81984c 100644
--- a/drivers/media/video/m52790.c
+++ b/drivers/media/video/m52790.c
@@ -26,12 +26,10 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/m52790.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("i2c device driver for m52790 A/V switch");
MODULE_AUTHOR("Hans Verkuil");
@@ -205,9 +203,25 @@ static const struct i2c_device_id m52790_id[] = {
};
MODULE_DEVICE_TABLE(i2c, m52790_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "m52790",
- .probe = m52790_probe,
- .remove = m52790_remove,
- .id_table = m52790_id,
+static struct i2c_driver m52790_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "m52790",
+ },
+ .probe = m52790_probe,
+ .remove = m52790_remove,
+ .id_table = m52790_id,
};
+
+static __init int init_m52790(void)
+{
+ return i2c_add_driver(&m52790_driver);
+}
+
+static __exit void exit_m52790(void)
+{
+ i2c_del_driver(&m52790_driver);
+}
+
+module_init(init_m52790);
+module_exit(exit_m52790);
diff --git a/drivers/media/video/mem2mem_testdev.c b/drivers/media/video/mem2mem_testdev.c
index 554eaf140128..c179041d91f8 100644
--- a/drivers/media/video/mem2mem_testdev.c
+++ b/drivers/media/video/mem2mem_testdev.c
@@ -239,7 +239,7 @@ static int device_process(struct m2mtest_ctx *ctx,
return -EFAULT;
}
- if (in_buf->vb.size < out_buf->vb.size) {
+ if (in_buf->vb.size > out_buf->vb.size) {
v4l2_err(&dev->v4l2_dev, "Output buffer is too small\n");
return -EINVAL;
}
@@ -524,7 +524,6 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
{
struct m2mtest_q_data *q_data;
struct videobuf_queue *vq;
- int ret = 0;
vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
if (!vq)
@@ -534,12 +533,9 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
if (!q_data)
return -EINVAL;
- mutex_lock(&vq->vb_lock);
-
if (videobuf_queue_is_busy(vq)) {
v4l2_err(&ctx->dev->v4l2_dev, "%s queue busy\n", __func__);
- ret = -EBUSY;
- goto out;
+ return -EBUSY;
}
q_data->fmt = find_format(f);
@@ -553,9 +549,7 @@ static int vidioc_s_fmt(struct m2mtest_ctx *ctx, struct v4l2_format *f)
"Setting format for type %d, wxh: %dx%d, fmt: %d\n",
f->type, q_data->width, q_data->height, q_data->fmt->fourcc);
-out:
- mutex_unlock(&vq->vb_lock);
- return ret;
+ return 0;
}
static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
@@ -845,10 +839,12 @@ static void queue_init(void *priv, struct videobuf_queue *vq,
enum v4l2_buf_type type)
{
struct m2mtest_ctx *ctx = priv;
+ struct m2mtest_dev *dev = ctx->dev;
- videobuf_queue_vmalloc_init(vq, &m2mtest_qops, ctx->dev->v4l2_dev.dev,
- &ctx->dev->irqlock, type, V4L2_FIELD_NONE,
- sizeof(struct m2mtest_buffer), priv);
+ videobuf_queue_vmalloc_init(vq, &m2mtest_qops, dev->v4l2_dev.dev,
+ &dev->irqlock, type, V4L2_FIELD_NONE,
+ sizeof(struct m2mtest_buffer), priv,
+ &dev->dev_mutex);
}
@@ -903,14 +899,14 @@ static int m2mtest_release(struct file *file)
static unsigned int m2mtest_poll(struct file *file,
struct poll_table_struct *wait)
{
- struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+ struct m2mtest_ctx *ctx = file->private_data;
return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
}
static int m2mtest_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct m2mtest_ctx *ctx = (struct m2mtest_ctx *)file->private_data;
+ struct m2mtest_ctx *ctx = file->private_data;
return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
}
@@ -920,7 +916,7 @@ static const struct v4l2_file_operations m2mtest_fops = {
.open = m2mtest_open,
.release = m2mtest_release,
.poll = m2mtest_poll,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = m2mtest_mmap,
};
@@ -965,6 +961,7 @@ static int m2mtest_probe(struct platform_device *pdev)
}
*vfd = m2mtest_videodev;
+ vfd->lock = &dev->dev_mutex;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, 0);
if (ret) {
@@ -988,6 +985,9 @@ static int m2mtest_probe(struct platform_device *pdev)
goto err_m2m;
}
+ q_data[V4L2_M2M_SRC].fmt = &formats[0];
+ q_data[V4L2_M2M_DST].fmt = &formats[0];
+
return 0;
err_m2m:
@@ -1011,6 +1011,7 @@ static int m2mtest_remove(struct platform_device *pdev)
v4l2_m2m_release(dev->m2m_dev);
del_timer_sync(&dev->timer);
video_unregister_device(dev->vfd);
+ video_device_release(dev->vfd);
v4l2_device_unregister(&dev->v4l2_dev);
kfree(dev);
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 2be23bccd3c8..48d2c2419c13 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -1659,7 +1659,7 @@ static const struct v4l2_file_operations meye_fops = {
.open = meye_open,
.release = meye_release,
.mmap = meye_mmap,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.poll = meye_poll,
};
@@ -1831,12 +1831,6 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
msleep(1);
mchip_set(MCHIP_MM_INTA, MCHIP_MM_INTA_HIC_1_MASK);
- if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
- video_nr) < 0) {
- v4l2_err(v4l2_dev, "video_register_device failed\n");
- goto outvideoreg;
- }
-
mutex_init(&meye.lock);
init_waitqueue_head(&meye.proc_list);
meye.brightness = 32 << 10;
@@ -1858,6 +1852,12 @@ static int __devinit meye_probe(struct pci_dev *pcidev,
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE, 0);
sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC, 48);
+ if (video_register_device(meye.vdev, VFL_TYPE_GRABBER,
+ video_nr) < 0) {
+ v4l2_err(v4l2_dev, "video_register_device failed\n");
+ goto outvideoreg;
+ }
+
v4l2_info(v4l2_dev, "Motion Eye Camera Driver v%s.\n",
MEYE_DRIVER_VERSION);
v4l2_info(v4l2_dev, "mchip KL5A72002 rev. %d, base %lx, irq %d\n",
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index e9df3cb02cc1..b1763ac93ab3 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -56,7 +56,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/msp3400.h>
#include <media/tvaudio.h>
#include "msp3400-driver.h"
@@ -283,51 +282,6 @@ void msp_set_scart(struct i2c_client *client, int in, int out)
msp_write_dem(client, 0x40, state->i2s_mode);
}
-void msp_set_audio(struct i2c_client *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;
-
- if (!reallymuted)
- val = (state->volume * 0x7f / 65535) << 8;
-
- v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n",
- state->muted ? "on" : "off",
- state->scan_in_progress ? "yes" : "no",
- state->volume);
-
- msp_write_dsp(client, 0x0000, val);
- msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1));
- if (state->has_scart2_out_volume)
- msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1));
- if (state->has_headphones)
- msp_write_dsp(client, 0x0006, val);
- if (!state->has_sound_processing)
- return;
-
- if (val)
- bal = (u8)((state->balance / 256) - 128);
- bass = ((state->bass - 32768) * 0x60 / 65535) << 8;
- treble = ((state->treble - 32768) * 0x60 / 65535) << 8;
- loudness = state->loudness ? ((5 * 4) << 8) : 0;
-
- v4l_dbg(1, msp_debug, client, "balance=%d bass=%d treble=%d loudness=%d\n",
- state->balance, state->bass, state->treble, state->loudness);
-
- msp_write_dsp(client, 0x0001, bal << 8);
- msp_write_dsp(client, 0x0002, bass);
- msp_write_dsp(client, 0x0003, treble);
- msp_write_dsp(client, 0x0004, loudness);
- if (!state->has_headphones)
- return;
- msp_write_dsp(client, 0x0030, bal << 8);
- msp_write_dsp(client, 0x0031, bass);
- msp_write_dsp(client, 0x0032, treble);
- msp_write_dsp(client, 0x0033, loudness);
-}
-
/* ------------------------------------------------------------------------ */
static void msp_wake_thread(struct i2c_client *client)
@@ -363,98 +317,78 @@ int msp_sleep(struct msp_state *state, int timeout)
/* ------------------------------------------------------------------------ */
-static int msp_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int msp_s_ctrl(struct v4l2_ctrl *ctrl)
{
- struct msp_state *state = to_state(sd);
+ struct msp_state *state = ctrl_to_state(ctrl);
+ struct i2c_client *client = v4l2_get_subdevdata(&state->sd);
+ int val = ctrl->val;
switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = state->volume;
- break;
-
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = state->muted;
- break;
-
- case V4L2_CID_AUDIO_BALANCE:
- if (!state->has_sound_processing)
- return -EINVAL;
- ctrl->value = state->balance;
+ case V4L2_CID_AUDIO_VOLUME: {
+ /* audio volume cluster */
+ int reallymuted = state->muted->val | state->scan_in_progress;
+
+ if (!reallymuted)
+ val = (val * 0x7f / 65535) << 8;
+
+ v4l_dbg(1, msp_debug, client, "mute=%s scanning=%s volume=%d\n",
+ state->muted->val ? "on" : "off",
+ state->scan_in_progress ? "yes" : "no",
+ state->volume->val);
+
+ msp_write_dsp(client, 0x0000, val);
+ msp_write_dsp(client, 0x0007, reallymuted ? 0x1 : (val | 0x1));
+ if (state->has_scart2_out_volume)
+ msp_write_dsp(client, 0x0040, reallymuted ? 0x1 : (val | 0x1));
+ if (state->has_headphones)
+ msp_write_dsp(client, 0x0006, val);
break;
-
- case V4L2_CID_AUDIO_BASS:
- if (!state->has_sound_processing)
- return -EINVAL;
- ctrl->value = state->bass;
- break;
-
- case V4L2_CID_AUDIO_TREBLE:
- if (!state->has_sound_processing)
- return -EINVAL;
- ctrl->value = state->treble;
- break;
-
- case V4L2_CID_AUDIO_LOUDNESS:
- if (!state->has_sound_processing)
- return -EINVAL;
- ctrl->value = state->loudness;
- break;
-
- default:
- return -EINVAL;
}
- return 0;
-}
-
-static int msp_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct msp_state *state = to_state(sd);
- struct i2c_client *client = v4l2_get_subdevdata(sd);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- state->volume = ctrl->value;
- if (state->volume == 0)
- state->balance = 32768;
- break;
-
- case V4L2_CID_AUDIO_MUTE:
- if (ctrl->value < 0 || ctrl->value >= 2)
- return -ERANGE;
- state->muted = ctrl->value;
- break;
case V4L2_CID_AUDIO_BASS:
- if (!state->has_sound_processing)
- return -EINVAL;
- state->bass = ctrl->value;
+ val = ((val - 32768) * 0x60 / 65535) << 8;
+ msp_write_dsp(client, 0x0002, val);
+ if (state->has_headphones)
+ msp_write_dsp(client, 0x0031, val);
break;
case V4L2_CID_AUDIO_TREBLE:
- if (!state->has_sound_processing)
- return -EINVAL;
- state->treble = ctrl->value;
+ val = ((val - 32768) * 0x60 / 65535) << 8;
+ msp_write_dsp(client, 0x0003, val);
+ if (state->has_headphones)
+ msp_write_dsp(client, 0x0032, val);
break;
case V4L2_CID_AUDIO_LOUDNESS:
- if (!state->has_sound_processing)
- return -EINVAL;
- state->loudness = ctrl->value;
+ val = val ? ((5 * 4) << 8) : 0;
+ msp_write_dsp(client, 0x0004, val);
+ if (state->has_headphones)
+ msp_write_dsp(client, 0x0033, val);
break;
case V4L2_CID_AUDIO_BALANCE:
- if (!state->has_sound_processing)
- return -EINVAL;
- state->balance = ctrl->value;
+ val = (u8)((val / 256) - 128);
+ msp_write_dsp(client, 0x0001, val << 8);
+ if (state->has_headphones)
+ msp_write_dsp(client, 0x0030, val << 8);
break;
default:
return -EINVAL;
}
- msp_set_audio(client);
return 0;
}
+void msp_update_volume(struct msp_state *state)
+{
+ /* Force an update of the volume/mute cluster */
+ v4l2_ctrl_lock(state->volume);
+ state->volume->val = state->volume->cur.val;
+ state->muted->val = state->muted->cur.val;
+ msp_s_ctrl(state->volume);
+ v4l2_ctrl_unlock(state->volume);
+}
+
/* --- v4l2 ioctls --- */
static int msp_s_radio(struct v4l2_subdev *sd)
{
@@ -472,7 +406,7 @@ static int msp_s_radio(struct v4l2_subdev *sd)
msp3400c_set_mode(client, MSP_MODE_FM_RADIO);
msp3400c_set_carrier(client, MSP_CARRIER(10.7),
MSP_CARRIER(10.7));
- msp_set_audio(client);
+ msp_update_volume(state);
break;
case OPMODE_AUTODETECT:
case OPMODE_AUTOSELECT:
@@ -592,33 +526,6 @@ static int msp_s_i2s_clock_freq(struct v4l2_subdev *sd, u32 freq)
return 0;
}
-static int msp_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- struct msp_state *state = to_state(sd);
-
- switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
- case V4L2_CID_AUDIO_MUTE:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
- default:
- break;
- }
- if (!state->has_sound_processing)
- return -EINVAL;
- switch (qc->id) {
- case V4L2_CID_AUDIO_LOUDNESS:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 0);
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
- default:
- return -EINVAL;
- }
- return 0;
-}
-
static int msp_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
struct msp_state *state = to_state(sd);
@@ -633,19 +540,14 @@ 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;
+ char prefix[V4L2_SUBDEV_NAME_SIZE + 20];
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");
- }
+ snprintf(prefix, sizeof(prefix), "%s: Audio: ", sd->name);
+ v4l2_ctrl_handler_log_status(&state->hdl, prefix);
switch (state->mode) {
case MSP_MODE_AM_DETECT: p = "AM (for carrier detect)"; break;
case MSP_MODE_FM_RADIO: p = "FM Radio"; break;
@@ -695,12 +597,20 @@ static int msp_resume(struct i2c_client *client)
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops msp_ctrl_ops = {
+ .s_ctrl = msp_s_ctrl,
+};
+
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,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
.s_std = msp_s_std,
};
@@ -728,6 +638,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
{
struct msp_state *state;
struct v4l2_subdev *sd;
+ struct v4l2_ctrl_handler *hdl;
int (*thread_func)(void *data) = NULL;
int msp_hard;
int msp_family;
@@ -752,13 +663,7 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
state->v4l2_std = V4L2_STD_NTSC;
state->audmode = V4L2_TUNER_MODE_STEREO;
- state->volume = 58880; /* 0db gain */
- state->balance = 32768; /* 0db gain */
- state->bass = 32768;
- state->treble = 32768;
- state->loudness = 0;
state->input = -1;
- state->muted = 0;
state->i2s_mode = 0;
init_waitqueue_head(&state->wq);
/* These are the reset input/output positions */
@@ -777,8 +682,6 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
return -ENODEV;
}
- msp_set_audio(client);
-
msp_family = ((state->rev1 >> 4) & 0x0f) + 3;
msp_product = (state->rev2 >> 8) & 0xff;
msp_prod_hi = msp_product / 10;
@@ -849,6 +752,34 @@ static int msp_probe(struct i2c_client *client, const struct i2c_device_id *id)
state->opmode = OPMODE_MANUAL;
}
+ hdl = &state->hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
+ if (state->has_sound_processing) {
+ v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+ V4L2_CID_AUDIO_BASS, 0, 65535, 65535 / 100, 32768);
+ v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+ V4L2_CID_AUDIO_TREBLE, 0, 65535, 65535 / 100, 32768);
+ v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+ V4L2_CID_AUDIO_LOUDNESS, 0, 1, 1, 0);
+ }
+ state->volume = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 58880);
+ v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+ V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
+ state->muted = v4l2_ctrl_new_std(hdl, &msp_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(state);
+ return err;
+ }
+
+ v4l2_ctrl_cluster(2, &state->volume);
+ v4l2_ctrl_handler_setup(hdl);
+
/* hello world :-) */
v4l_info(client, "MSP%d4%02d%c-%c%d found @ 0x%x (%s)\n",
msp_family, msp_product,
@@ -903,6 +834,7 @@ static int msp_remove(struct i2c_client *client)
}
msp_reset(client);
+ v4l2_ctrl_handler_free(&state->hdl);
kfree(state);
return 0;
}
@@ -915,15 +847,31 @@ static const struct i2c_device_id msp_id[] = {
};
MODULE_DEVICE_TABLE(i2c, msp_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "msp3400",
- .probe = msp_probe,
- .remove = msp_remove,
- .suspend = msp_suspend,
- .resume = msp_resume,
- .id_table = msp_id,
+static struct i2c_driver msp_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "msp3400",
+ },
+ .probe = msp_probe,
+ .remove = msp_remove,
+ .suspend = msp_suspend,
+ .resume = msp_resume,
+ .id_table = msp_id,
};
+static __init int init_msp(void)
+{
+ return i2c_add_driver(&msp_driver);
+}
+
+static __exit void exit_msp(void)
+{
+ i2c_del_driver(&msp_driver);
+}
+
+module_init(init_msp);
+module_exit(exit_msp);
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/msp3400-driver.h b/drivers/media/video/msp3400-driver.h
index d6b3e6d0eef7..32a478e532f3 100644
--- a/drivers/media/video/msp3400-driver.h
+++ b/drivers/media/video/msp3400-driver.h
@@ -6,6 +6,7 @@
#include <media/msp3400.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
/* ---------------------------------------------------------------------- */
@@ -51,6 +52,7 @@ extern int msp_stereo_thresh;
struct msp_state {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
int rev1, rev2;
int ident;
u8 has_nicam;
@@ -87,9 +89,12 @@ struct msp_state {
int audmode;
int rxsubchans;
- int volume, muted;
- int balance, loudness;
- int bass, treble;
+ struct {
+ /* volume cluster */
+ struct v4l2_ctrl *volume;
+ struct v4l2_ctrl *muted;
+ };
+
int scan_in_progress;
/* thread */
@@ -104,6 +109,11 @@ static inline struct msp_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct msp_state, sd);
}
+static inline struct msp_state *ctrl_to_state(struct v4l2_ctrl *ctrl)
+{
+ return container_of(ctrl->handler, struct msp_state, hdl);
+}
+
/* 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);
@@ -111,7 +121,7 @@ int msp_read_dem(struct i2c_client *client, int addr);
int msp_read_dsp(struct i2c_client *client, int addr);
int msp_reset(struct i2c_client *client);
void msp_set_scart(struct i2c_client *client, int in, int out);
-void msp_set_audio(struct i2c_client *client);
+void msp_update_volume(struct msp_state *state);
int msp_sleep(struct msp_state *state, int timeout);
/* msp3400-kthreads.c */
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index d5a69c5ee5e4..b376fcdee652 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -496,13 +496,13 @@ restart:
v4l_dbg(1, msp_debug, client,
"thread: no carrier scan\n");
state->scan_in_progress = 0;
- msp_set_audio(client);
+ msp_update_volume(state);
continue;
}
/* mute audio */
state->scan_in_progress = 1;
- msp_set_audio(client);
+ msp_update_volume(state);
msp3400c_set_mode(client, MSP_MODE_AM_DETECT);
val1 = val2 = 0;
@@ -634,7 +634,7 @@ no_second:
/* unmute */
state->scan_in_progress = 0;
msp3400c_set_audmode(client);
- msp_set_audio(client);
+ msp_update_volume(state);
if (msp_debug)
msp3400c_print_mode(client);
@@ -679,13 +679,13 @@ restart:
v4l_dbg(1, msp_debug, client,
"thread: no carrier scan\n");
state->scan_in_progress = 0;
- msp_set_audio(client);
+ msp_update_volume(state);
continue;
}
/* mute audio */
state->scan_in_progress = 1;
- msp_set_audio(client);
+ msp_update_volume(state);
/* start autodetect. Note: autodetect is not supported for
NTSC-M and radio, hence we force the standard in those
@@ -797,7 +797,7 @@ restart:
/* unmute */
msp3400c_set_audmode(client);
state->scan_in_progress = 0;
- msp_set_audio(client);
+ msp_update_volume(state);
/* monitor tv audio mode, the first time don't wait
so long to get a quick stereo/bilingual result */
@@ -974,7 +974,7 @@ restart:
v4l_dbg(1, msp_debug, client,
"thread: no carrier scan\n");
state->scan_in_progress = 0;
- msp_set_audio(client);
+ msp_update_volume(state);
continue;
}
@@ -1020,7 +1020,7 @@ unmute:
}
/* unmute: dispatch sound to scart output, set scart volume */
- msp_set_audio(client);
+ msp_update_volume(state);
/* restore ACB */
if (msp_write_dsp(client, 0x13, state->acb))
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
index b62c0bd3f8ea..f7fc88d240e6 100644
--- a/drivers/media/video/mt9m001.c
+++ b/drivers/media/video/mt9m001.c
@@ -157,7 +157,7 @@ static int mt9m001_init(struct i2c_client *client)
static int mt9m001_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
/* Switch to master "normal" mode or stop sensor readout */
if (reg_write(client, MT9M001_OUTPUT_CONTROL, enable ? 2 : 0) < 0)
@@ -206,7 +206,7 @@ static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_rect rect = a->c;
struct soc_camera_device *icd = client->dev.platform_data;
@@ -271,7 +271,7 @@ static int mt9m001_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int mt9m001_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
a->c = mt9m001->rect;
@@ -297,7 +297,7 @@ static int mt9m001_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9m001_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
mf->width = mt9m001->rect.width;
@@ -312,7 +312,7 @@ static int mt9m001_g_fmt(struct v4l2_subdev *sd,
static int mt9m001_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct v4l2_crop a = {
.c = {
@@ -340,7 +340,7 @@ static int mt9m001_s_fmt(struct v4l2_subdev *sd,
static int mt9m001_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
const struct mt9m001_datafmt *fmt;
@@ -367,7 +367,7 @@ static int mt9m001_try_fmt(struct v4l2_subdev *sd,
static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -386,7 +386,7 @@ static int mt9m001_g_chip_ident(struct v4l2_subdev *sd,
static int mt9m001_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -406,7 +406,7 @@ static int mt9m001_g_register(struct v4l2_subdev *sd,
static int mt9m001_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -468,7 +468,7 @@ static struct soc_camera_ops mt9m001_ops = {
static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
int data;
@@ -494,7 +494,7 @@ static int mt9m001_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9m001_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
struct soc_camera_device *icd = client->dev.platform_data;
const struct v4l2_queryctrl *qctrl;
@@ -683,7 +683,7 @@ static void mt9m001_video_remove(struct soc_camera_device *icd)
static int mt9m001_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
*lines = mt9m001->y_skip_top;
@@ -701,13 +701,13 @@ static struct v4l2_subdev_core_ops mt9m001_subdev_core_ops = {
#endif
};
-static int mt9m001_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9m001_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m001 *mt9m001 = to_mt9m001(client);
- if ((unsigned int)index >= mt9m001->num_fmts)
+ if (index >= mt9m001->num_fmts)
return -EINVAL;
*code = mt9m001->fmts[index].code;
@@ -785,7 +785,6 @@ static int mt9m001_probe(struct i2c_client *client,
ret = mt9m001_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(mt9m001);
}
@@ -799,8 +798,6 @@ static int mt9m001_remove(struct i2c_client *client)
icd->ops = NULL;
mt9m001_video_remove(icd);
- i2c_set_clientdata(client, NULL);
- client->driver = NULL;
kfree(mt9m001);
return 0;
diff --git a/drivers/media/video/mt9m111.c b/drivers/media/video/mt9m111.c
index d35f536f9fc3..53fa2a7bf156 100644
--- a/drivers/media/video/mt9m111.c
+++ b/drivers/media/video/mt9m111.c
@@ -1,5 +1,5 @@
/*
- * Driver for MT9M111/MT9M112 CMOS Image Sensor from Micron
+ * Driver for MT9M111/MT9M112/MT9M131 CMOS Image Sensor from Micron/Aptina
*
* Copyright (C) 2008, Robert Jarzmik <robert.jarzmik@free.fr>
*
@@ -19,11 +19,14 @@
#include <media/soc_camera.h>
/*
- * mt9m111 and mt9m112 i2c address is 0x5d or 0x48 (depending on SAddr pin)
+ * MT9M111, MT9M112 and MT9M131:
+ * i2c address is 0x48 or 0x5d (depending on SADDR pin)
* The platform has to define i2c_board_info and call i2c_register_board_info()
*/
-/* mt9m111: Sensor register addresses */
+/*
+ * Sensor core register addresses (0x000..0x0ff)
+ */
#define MT9M111_CHIP_VERSION 0x000
#define MT9M111_ROW_START 0x001
#define MT9M111_COLUMN_START 0x002
@@ -72,8 +75,9 @@
#define MT9M111_CTXT_CTRL_LED_FLASH_EN (1 << 2)
#define MT9M111_CTXT_CTRL_VBLANK_SEL_B (1 << 1)
#define MT9M111_CTXT_CTRL_HBLANK_SEL_B (1 << 0)
+
/*
- * mt9m111: Colorpipe register addresses (0x100..0x1ff)
+ * Colorpipe register addresses (0x100..0x1ff)
*/
#define MT9M111_OPER_MODE_CTRL 0x106
#define MT9M111_OUTPUT_FORMAT_CTRL 0x108
@@ -96,21 +100,22 @@
#define MT9M111_OUTFMT_BYPASS_IFP (1 << 10)
#define MT9M111_OUTFMT_INV_PIX_CLOCK (1 << 9)
#define MT9M111_OUTFMT_RGB (1 << 8)
-#define MT9M111_OUTFMT_RGB565 (0x0 << 6)
-#define MT9M111_OUTFMT_RGB555 (0x1 << 6)
-#define MT9M111_OUTFMT_RGB444x (0x2 << 6)
-#define MT9M111_OUTFMT_RGBx444 (0x3 << 6)
-#define MT9M111_OUTFMT_TST_RAMP_OFF (0x0 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_COL (0x1 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_ROW (0x2 << 4)
-#define MT9M111_OUTFMT_TST_RAMP_FRAME (0x3 << 4)
+#define MT9M111_OUTFMT_RGB565 (0 << 6)
+#define MT9M111_OUTFMT_RGB555 (1 << 6)
+#define MT9M111_OUTFMT_RGB444x (2 << 6)
+#define MT9M111_OUTFMT_RGBx444 (3 << 6)
+#define MT9M111_OUTFMT_TST_RAMP_OFF (0 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_COL (1 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_ROW (2 << 4)
+#define MT9M111_OUTFMT_TST_RAMP_FRAME (3 << 4)
#define MT9M111_OUTFMT_SHIFT_3_UP (1 << 3)
#define MT9M111_OUTFMT_AVG_CHROMA (1 << 2)
#define MT9M111_OUTFMT_SWAP_YCbCr_C_Y (1 << 1)
#define MT9M111_OUTFMT_SWAP_RGB_EVEN (1 << 1)
#define MT9M111_OUTFMT_SWAP_YCbCr_Cb_Cr (1 << 0)
+
/*
- * mt9m111: Camera control register addresses (0x200..0x2ff not implemented)
+ * Camera control register addresses (0x200..0x2ff not implemented)
*/
#define reg_read(reg) mt9m111_reg_read(client, MT9M111_##reg)
@@ -119,7 +124,7 @@
#define reg_clear(reg, val) mt9m111_reg_clear(client, MT9M111_##reg, (val))
#define MT9M111_MIN_DARK_ROWS 8
-#define MT9M111_MIN_DARK_COLS 24
+#define MT9M111_MIN_DARK_COLS 26
#define MT9M111_MAX_HEIGHT 1024
#define MT9M111_MAX_WIDTH 1280
@@ -143,10 +148,10 @@ static const struct mt9m111_datafmt *mt9m111_find_datafmt(
}
static const struct mt9m111_datafmt mt9m111_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YUYV8_2X8_BE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_BE, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_UYVY8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_VYUY8_2X8, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR8_1X8, V4L2_COLORSPACE_SRGB},
@@ -160,7 +165,8 @@ enum mt9m111_context {
struct mt9m111 {
struct v4l2_subdev subdev;
- int model; /* V4L2_IDENT_MT9M11x* codes from v4l2-chip-ident.h */
+ int model; /* V4L2_IDENT_MT9M111 or V4L2_IDENT_MT9M112 code
+ * from v4l2-chip-ident.h */
enum mt9m111_context context;
struct v4l2_rect rect;
const struct mt9m111_datafmt *fmt;
@@ -434,13 +440,16 @@ static int mt9m111_make_rect(struct i2c_client *client,
static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct v4l2_rect rect = a->c;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
int ret;
dev_dbg(&client->dev, "%s left=%d, top=%d, width=%d, height=%d\n",
__func__, rect.left, rect.top, rect.width, rect.height);
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
ret = mt9m111_make_rect(client, &rect);
if (!ret)
mt9m111->rect = rect;
@@ -449,7 +458,7 @@ static int mt9m111_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
a->c = mt9m111->rect;
@@ -460,12 +469,14 @@ static int mt9m111_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
{
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
a->bounds.left = MT9M111_MIN_DARK_COLS;
a->bounds.top = MT9M111_MIN_DARK_ROWS;
a->bounds.width = MT9M111_MAX_WIDTH;
a->bounds.height = MT9M111_MAX_HEIGHT;
a->defrect = a->bounds;
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
a->pixelaspect.numerator = 1;
a->pixelaspect.denominator = 1;
@@ -475,12 +486,13 @@ static int mt9m111_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9m111_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
mf->width = mt9m111->rect.width;
mf->height = mt9m111->rect.height;
mf->code = mt9m111->fmt->code;
+ mf->colorspace = mt9m111->fmt->colorspace;
mf->field = V4L2_FIELD_NONE;
return 0;
@@ -505,22 +517,22 @@ static int mt9m111_set_pixfmt(struct i2c_client *client,
case V4L2_MBUS_FMT_RGB565_2X8_LE:
ret = mt9m111_setfmt_rgb565(client);
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 0;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
mt9m111->swap_yuv_y_chromas = 0;
mt9m111->swap_yuv_cb_cr = 1;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 0;
ret = mt9m111_setfmt_yuv(client);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
mt9m111->swap_yuv_y_chromas = 1;
mt9m111->swap_yuv_cb_cr = 1;
ret = mt9m111_setfmt_yuv(client);
@@ -537,7 +549,7 @@ static int mt9m111_set_pixfmt(struct i2c_client *client,
static int mt9m111_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
const struct mt9m111_datafmt *fmt;
struct mt9m111 *mt9m111 = to_mt9m111(client);
struct v4l2_rect rect = {
@@ -572,7 +584,7 @@ static int mt9m111_s_fmt(struct v4l2_subdev *sd,
static int mt9m111_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
const struct mt9m111_datafmt *fmt;
bool bayer = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
@@ -612,7 +624,7 @@ static int mt9m111_try_fmt(struct v4l2_subdev *sd,
static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -631,7 +643,7 @@ static int mt9m111_g_chip_ident(struct v4l2_subdev *sd,
static int mt9m111_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int val;
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
@@ -652,7 +664,7 @@ static int mt9m111_g_register(struct v4l2_subdev *sd,
static int mt9m111_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0x2ff)
return -EINVAL;
@@ -800,7 +812,7 @@ static int mt9m111_set_autowhitebalance(struct i2c_client *client, int on)
static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
int data;
@@ -843,7 +855,7 @@ static int mt9m111_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9m111_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9m111 *mt9m111 = to_mt9m111(client);
const struct v4l2_queryctrl *qctrl;
int ret;
@@ -934,7 +946,7 @@ static int mt9m111_init(struct i2c_client *client)
if (!ret)
ret = mt9m111_set_autoexposure(client, mt9m111->autoexposure);
if (ret)
- dev_err(&client->dev, "mt9m11x init failed: %d\n", ret);
+ dev_err(&client->dev, "mt9m111 init failed: %d\n", ret);
return ret;
}
@@ -963,27 +975,27 @@ static int mt9m111_video_probe(struct soc_camera_device *icd,
mt9m111->swap_rgb_even_odd = 1;
mt9m111->swap_rgb_red_blue = 1;
- ret = mt9m111_init(client);
- if (ret)
- goto ei2c;
-
data = reg_read(CHIP_VERSION);
switch (data) {
- case 0x143a: /* MT9M111 */
+ case 0x143a: /* MT9M111 or MT9M131 */
mt9m111->model = V4L2_IDENT_MT9M111;
+ dev_info(&client->dev,
+ "Detected a MT9M111/MT9M131 chip ID %x\n", data);
break;
case 0x148c: /* MT9M112 */
mt9m111->model = V4L2_IDENT_MT9M112;
+ dev_info(&client->dev, "Detected a MT9M112 chip ID %x\n", data);
break;
default:
ret = -ENODEV;
dev_err(&client->dev,
- "No MT9M11x chip detected, register read %x\n", data);
+ "No MT9M111/MT9M112/MT9M131 chip detected register read %x\n",
+ data);
goto ei2c;
}
- dev_info(&client->dev, "Detected a MT9M11x chip ID %x\n", data);
+ ret = mt9m111_init(client);
ei2c:
return ret;
@@ -999,10 +1011,10 @@ static struct v4l2_subdev_core_ops mt9m111_subdev_core_ops = {
#endif
};
-static int mt9m111_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9m111_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(mt9m111_colour_fmts))
+ if (index >= ARRAY_SIZE(mt9m111_colour_fmts))
return -EINVAL;
*code = mt9m111_colour_fmts[index].code;
@@ -1034,13 +1046,13 @@ static int mt9m111_probe(struct i2c_client *client,
int ret;
if (!icd) {
- dev_err(&client->dev, "MT9M11x: missing soc-camera data!\n");
+ dev_err(&client->dev, "mt9m111: soc-camera data missing!\n");
return -EINVAL;
}
icl = to_soc_camera_link(icd);
if (!icl) {
- dev_err(&client->dev, "MT9M11x driver needs platform data\n");
+ dev_err(&client->dev, "mt9m111: driver needs platform data\n");
return -EINVAL;
}
@@ -1068,7 +1080,6 @@ static int mt9m111_probe(struct i2c_client *client,
ret = mt9m111_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(mt9m111);
}
@@ -1081,8 +1092,6 @@ static int mt9m111_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
- client->driver = NULL;
kfree(mt9m111);
return 0;
@@ -1116,6 +1125,6 @@ static void __exit mt9m111_mod_exit(void)
module_init(mt9m111_mod_init);
module_exit(mt9m111_mod_exit);
-MODULE_DESCRIPTION("Micron MT9M111/MT9M112 Camera driver");
+MODULE_DESCRIPTION("Micron/Aptina MT9M111/MT9M112/MT9M131 Camera driver");
MODULE_AUTHOR("Robert Jarzmik");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mt9t031.c b/drivers/media/video/mt9t031.c
index 78b4e091d2d5..7ce279c3751d 100644
--- a/drivers/media/video/mt9t031.c
+++ b/drivers/media/video/mt9t031.c
@@ -163,7 +163,7 @@ static int mt9t031_disable(struct i2c_client *client)
static int mt9t031_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
if (enable)
@@ -393,7 +393,7 @@ static int mt9t031_set_params(struct i2c_client *client,
static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct v4l2_rect rect = a->c;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
rect.width = ALIGN(rect.width, 2);
@@ -410,7 +410,7 @@ static int mt9t031_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int mt9t031_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
a->c = mt9t031->rect;
@@ -436,7 +436,7 @@ static int mt9t031_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9t031_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
mf->width = mt9t031->rect.width / mt9t031->xskip;
@@ -451,7 +451,7 @@ static int mt9t031_g_fmt(struct v4l2_subdev *sd,
static int mt9t031_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
u16 xskip, yskip;
struct v4l2_rect rect = mt9t031->rect;
@@ -490,7 +490,7 @@ static int mt9t031_try_fmt(struct v4l2_subdev *sd,
static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -509,7 +509,7 @@ static int mt9t031_g_chip_ident(struct v4l2_subdev *sd,
static int mt9t031_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -528,7 +528,7 @@ static int mt9t031_g_register(struct v4l2_subdev *sd,
static int mt9t031_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -545,7 +545,7 @@ static int mt9t031_s_register(struct v4l2_subdev *sd,
static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
int data;
@@ -577,7 +577,7 @@ static int mt9t031_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9t031_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
const struct v4l2_queryctrl *qctrl;
int data;
@@ -703,7 +703,7 @@ static int mt9t031_runtime_resume(struct device *dev)
struct soc_camera_device *icd = container_of(vdev->parent,
struct soc_camera_device, dev);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
int ret;
@@ -780,7 +780,7 @@ static int mt9t031_video_probe(struct i2c_client *client)
static int mt9t031_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t031 *mt9t031 = to_mt9t031(client);
*lines = mt9t031->y_skip_top;
@@ -798,7 +798,7 @@ static struct v4l2_subdev_core_ops mt9t031_subdev_core_ops = {
#endif
};
-static int mt9t031_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9t031_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
@@ -883,7 +883,6 @@ static int mt9t031_probe(struct i2c_client *client,
if (ret) {
if (icd)
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(mt9t031);
}
@@ -897,8 +896,6 @@ static int mt9t031_remove(struct i2c_client *client)
if (icd)
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
- client->driver = NULL;
kfree(mt9t031);
return 0;
diff --git a/drivers/media/video/mt9t112.c b/drivers/media/video/mt9t112.c
index 7438f8d775ba..bffa9ee10968 100644
--- a/drivers/media/video/mt9t112.c
+++ b/drivers/media/video/mt9t112.c
@@ -121,22 +121,22 @@ struct mt9t112_priv {
static const struct mt9t112_format mt9t112_cfmts[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 0,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8_BE,
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 1,
}, {
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 2,
}, {
- .code = V4L2_MBUS_FMT_YVYU8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.fmt = 1,
.order = 3,
@@ -804,7 +804,7 @@ static struct soc_camera_ops mt9t112_ops = {
static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
id->ident = priv->model;
@@ -817,7 +817,7 @@ static int mt9t112_g_chip_ident(struct v4l2_subdev *sd,
static int mt9t112_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
reg->size = 2;
@@ -831,7 +831,7 @@ static int mt9t112_g_register(struct v4l2_subdev *sd,
static int mt9t112_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
mt9t112_reg_write(ret, client, reg->reg, reg->val);
@@ -858,7 +858,7 @@ static struct v4l2_subdev_core_ops mt9t112_subdev_core_ops = {
************************************************************************/
static int mt9t112_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
int ret = 0;
@@ -968,22 +968,22 @@ static int mt9t112_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int mt9t112_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct v4l2_rect *rect = &a->c;
return mt9t112_set_params(client, rect->width, rect->height,
- V4L2_MBUS_FMT_YUYV8_2X8_BE);
+ V4L2_MBUS_FMT_UYVY8_2X8);
}
static int mt9t112_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9t112_priv *priv = to_mt9t112(client);
if (!priv->format) {
int ret = mt9t112_set_params(client, VGA_WIDTH, VGA_HEIGHT,
- V4L2_MBUS_FMT_YUYV8_2X8_BE);
+ V4L2_MBUS_FMT_UYVY8_2X8);
if (ret < 0)
return ret;
}
@@ -1000,7 +1000,7 @@ static int mt9t112_g_fmt(struct v4l2_subdev *sd,
static int mt9t112_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
/* TODO: set colorspace */
return mt9t112_set_params(client, mf->width, mf->height, mf->code);
@@ -1017,10 +1017,10 @@ static int mt9t112_try_fmt(struct v4l2_subdev *sd,
return 0;
}
-static int mt9t112_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9t112_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(mt9t112_cfmts))
+ if (index >= ARRAY_SIZE(mt9t112_cfmts))
return -EINVAL;
*code = mt9t112_cfmts[index].code;
@@ -1119,7 +1119,6 @@ static int mt9t112_probe(struct i2c_client *client,
ret = mt9t112_camera_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -1132,7 +1131,6 @@ static int mt9t112_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/mt9v011.c b/drivers/media/video/mt9v011.c
index 72e55be0b4ab..4904d25f689f 100644
--- a/drivers/media/video/mt9v011.c
+++ b/drivers/media/video/mt9v011.c
@@ -11,19 +11,42 @@
#include <linux/delay.h>
#include <asm/div64.h>
#include <media/v4l2-device.h>
-#include "mt9v011.h"
-#include <media/v4l2-i2c-drv.h>
#include <media/v4l2-chip-ident.h>
+#include <media/mt9v011.h>
MODULE_DESCRIPTION("Micron mt9v011 sensor driver");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@redhat.com>");
MODULE_LICENSE("GPL");
-
static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-2)");
+#define R00_MT9V011_CHIP_VERSION 0x00
+#define R01_MT9V011_ROWSTART 0x01
+#define R02_MT9V011_COLSTART 0x02
+#define R03_MT9V011_HEIGHT 0x03
+#define R04_MT9V011_WIDTH 0x04
+#define R05_MT9V011_HBLANK 0x05
+#define R06_MT9V011_VBLANK 0x06
+#define R07_MT9V011_OUT_CTRL 0x07
+#define R09_MT9V011_SHUTTER_WIDTH 0x09
+#define R0A_MT9V011_CLK_SPEED 0x0a
+#define R0B_MT9V011_RESTART 0x0b
+#define R0C_MT9V011_SHUTTER_DELAY 0x0c
+#define R0D_MT9V011_RESET 0x0d
+#define R1E_MT9V011_DIGITAL_ZOOM 0x1e
+#define R20_MT9V011_READ_MODE 0x20
+#define R2B_MT9V011_GREEN_1_GAIN 0x2b
+#define R2C_MT9V011_BLUE_GAIN 0x2c
+#define R2D_MT9V011_RED_GAIN 0x2d
+#define R2E_MT9V011_GREEN_2_GAIN 0x2e
+#define R35_MT9V011_GLOBAL_GAIN 0x35
+#define RF1_MT9V011_CHIP_ENABLE 0xf1
+
+#define MT9V011_VERSION 0x8232
+#define MT9V011_REV_B_VERSION 0x8243
+
/* supported controls */
static struct v4l2_queryctrl mt9v011_qctrl[] = {
{
@@ -392,27 +415,25 @@ static int mt9v011_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return 0;
}
-static int mt9v011_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
+static int mt9v011_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
{
- if (fmt->index > 0)
+ if (index > 0)
return -EINVAL;
- fmt->flags = 0;
- strcpy(fmt->description, "8 bpp Bayer GRGR..BGBG");
- fmt->pixelformat = V4L2_PIX_FMT_SGRBG8;
-
+ *code = V4L2_MBUS_FMT_SGRBG8_1X8;
return 0;
}
-static int mt9v011_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int mt9v011_try_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
-
- if (pix->pixelformat != V4L2_PIX_FMT_SGRBG8)
+ if (fmt->code != V4L2_MBUS_FMT_SGRBG8_1X8)
return -EINVAL;
- v4l_bound_align_image(&pix->width, 48, 639, 1,
- &pix->height, 32, 480, 1, 0);
+ v4l_bound_align_image(&fmt->width, 48, 639, 1,
+ &fmt->height, 32, 480, 1, 0);
+ fmt->field = V4L2_FIELD_NONE;
+ fmt->colorspace = V4L2_COLORSPACE_SRGB;
return 0;
}
@@ -455,41 +476,23 @@ static int mt9v011_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
return 0;
}
-static int mt9v011_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int mt9v011_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
struct mt9v011 *core = to_mt9v011(sd);
int rc;
- rc = mt9v011_try_fmt(sd, fmt);
+ rc = mt9v011_try_mbus_fmt(sd, fmt);
if (rc < 0)
return -EINVAL;
- core->width = pix->width;
- core->height = pix->height;
+ core->width = fmt->width;
+ core->height = fmt->height;
set_res(sd);
return 0;
}
-static int mt9v011_s_config(struct v4l2_subdev *sd, int dumb, void *data)
-{
- struct mt9v011 *core = to_mt9v011(sd);
- unsigned *xtal = data;
-
- v4l2_dbg(1, debug, sd, "s_config called\n");
-
- if (xtal) {
- core->xtal = *xtal;
- v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
- *xtal / 1000000, (*xtal / 1000) % 1000);
- }
-
- return 0;
-}
-
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int mt9v011_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -540,7 +543,6 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
.g_ctrl = mt9v011_g_ctrl,
.s_ctrl = mt9v011_s_ctrl,
.reset = mt9v011_reset,
- .s_config = mt9v011_s_config,
.g_chip_ident = mt9v011_g_chip_ident,
#ifdef CONFIG_VIDEO_ADV_DEBUG
.g_register = mt9v011_g_register,
@@ -549,9 +551,9 @@ static const struct v4l2_subdev_core_ops mt9v011_core_ops = {
};
static const struct v4l2_subdev_video_ops mt9v011_video_ops = {
- .enum_fmt = mt9v011_enum_fmt,
- .try_fmt = mt9v011_try_fmt,
- .s_fmt = mt9v011_s_fmt,
+ .enum_mbus_fmt = mt9v011_enum_mbus_fmt,
+ .try_mbus_fmt = mt9v011_try_mbus_fmt,
+ .s_mbus_fmt = mt9v011_s_mbus_fmt,
.g_parm = mt9v011_g_parm,
.s_parm = mt9v011_s_parm,
};
@@ -600,6 +602,14 @@ static int mt9v011_probe(struct i2c_client *c,
core->height = 480;
core->xtal = 27000000; /* Hz */
+ if (c->dev.platform_data) {
+ struct mt9v011_platform_data *pdata = c->dev.platform_data;
+
+ core->xtal = pdata->xtal;
+ v4l2_dbg(1, debug, sd, "xtal set to %d.%03d MHz\n",
+ core->xtal / 1000000, (core->xtal / 1000) % 1000);
+ }
+
v4l_info(c, "chip found @ 0x%02x (%s - chip version 0x%04x)\n",
c->addr << 1, c->adapter->name, version);
@@ -627,9 +637,25 @@ static const struct i2c_device_id mt9v011_id[] = {
};
MODULE_DEVICE_TABLE(i2c, mt9v011_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "mt9v011",
- .probe = mt9v011_probe,
- .remove = mt9v011_remove,
- .id_table = mt9v011_id,
+static struct i2c_driver mt9v011_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "mt9v011",
+ },
+ .probe = mt9v011_probe,
+ .remove = mt9v011_remove,
+ .id_table = mt9v011_id,
};
+
+static __init int init_mt9v011(void)
+{
+ return i2c_add_driver(&mt9v011_driver);
+}
+
+static __exit void exit_mt9v011(void)
+{
+ i2c_del_driver(&mt9v011_driver);
+}
+
+module_init(init_mt9v011);
+module_exit(exit_mt9v011);
diff --git a/drivers/media/video/mt9v011.h b/drivers/media/video/mt9v011.h
deleted file mode 100644
index 3350fd6083c3..000000000000
--- a/drivers/media/video/mt9v011.h
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * mt9v011 -Micron 1/4-Inch VGA Digital Image Sensor
- *
- * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
- * This code is placed under the terms of the GNU General Public License v2
- */
-
-#ifndef MT9V011_H_
-#define MT9V011_H_
-
-#define R00_MT9V011_CHIP_VERSION 0x00
-#define R01_MT9V011_ROWSTART 0x01
-#define R02_MT9V011_COLSTART 0x02
-#define R03_MT9V011_HEIGHT 0x03
-#define R04_MT9V011_WIDTH 0x04
-#define R05_MT9V011_HBLANK 0x05
-#define R06_MT9V011_VBLANK 0x06
-#define R07_MT9V011_OUT_CTRL 0x07
-#define R09_MT9V011_SHUTTER_WIDTH 0x09
-#define R0A_MT9V011_CLK_SPEED 0x0a
-#define R0B_MT9V011_RESTART 0x0b
-#define R0C_MT9V011_SHUTTER_DELAY 0x0c
-#define R0D_MT9V011_RESET 0x0d
-#define R1E_MT9V011_DIGITAL_ZOOM 0x1e
-#define R20_MT9V011_READ_MODE 0x20
-#define R2B_MT9V011_GREEN_1_GAIN 0x2b
-#define R2C_MT9V011_BLUE_GAIN 0x2c
-#define R2D_MT9V011_RED_GAIN 0x2d
-#define R2E_MT9V011_GREEN_2_GAIN 0x2e
-#define R35_MT9V011_GLOBAL_GAIN 0x35
-#define RF1_MT9V011_CHIP_ENABLE 0xf1
-
-#define MT9V011_VERSION 0x8232
-#define MT9V011_REV_B_VERSION 0x8243
-
-#endif
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
index e5bae4c9393b..6a784c87e5ff 100644
--- a/drivers/media/video/mt9v022.c
+++ b/drivers/media/video/mt9v022.c
@@ -184,7 +184,7 @@ static int mt9v022_init(struct i2c_client *client)
static int mt9v022_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
if (enable)
@@ -273,7 +273,7 @@ static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_rect rect = a->c;
int ret;
@@ -334,7 +334,7 @@ static int mt9v022_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int mt9v022_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
a->c = mt9v022->rect;
@@ -360,7 +360,7 @@ static int mt9v022_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int mt9v022_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
mf->width = mt9v022->rect.width;
@@ -375,7 +375,7 @@ static int mt9v022_g_fmt(struct v4l2_subdev *sd,
static int mt9v022_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
struct v4l2_crop a = {
.c = {
@@ -402,9 +402,6 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
return -EINVAL;
break;
- case 0:
- /* No format change, only geometry */
- break;
default:
return -EINVAL;
}
@@ -425,7 +422,7 @@ static int mt9v022_s_fmt(struct v4l2_subdev *sd,
static int mt9v022_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
const struct mt9v022_datafmt *fmt;
int align = mf->code == V4L2_MBUS_FMT_SBGGR8_1X8 ||
@@ -451,7 +448,7 @@ static int mt9v022_try_fmt(struct v4l2_subdev *sd,
static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
@@ -470,7 +467,7 @@ static int mt9v022_g_chip_ident(struct v4l2_subdev *sd,
static int mt9v022_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -490,7 +487,7 @@ static int mt9v022_g_register(struct v4l2_subdev *sd,
static int mt9v022_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
return -EINVAL;
@@ -568,7 +565,7 @@ static struct soc_camera_ops mt9v022_ops = {
static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
const struct v4l2_queryctrl *qctrl;
unsigned long range;
int data;
@@ -625,7 +622,7 @@ static int mt9v022_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int mt9v022_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
int data;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
const struct v4l2_queryctrl *qctrl;
qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
@@ -820,7 +817,7 @@ static void mt9v022_video_remove(struct soc_camera_device *icd)
static int mt9v022_g_skip_top_lines(struct v4l2_subdev *sd, u32 *lines)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
*lines = mt9v022->y_skip_top;
@@ -838,13 +835,13 @@ static struct v4l2_subdev_core_ops mt9v022_subdev_core_ops = {
#endif
};
-static int mt9v022_enum_fmt(struct v4l2_subdev *sd, int index,
+static int mt9v022_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct mt9v022 *mt9v022 = to_mt9v022(client);
- if ((unsigned int)index >= mt9v022->num_fmts)
+ if (index >= mt9v022->num_fmts)
return -EINVAL;
*code = mt9v022->fmts[index].code;
@@ -920,7 +917,6 @@ static int mt9v022_probe(struct i2c_client *client,
ret = mt9v022_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(mt9v022);
}
@@ -934,8 +930,6 @@ static int mt9v022_remove(struct i2c_client *client)
icd->ops = NULL;
mt9v022_video_remove(icd);
- i2c_set_clientdata(client, NULL);
- client->driver = NULL;
kfree(mt9v022);
return 0;
diff --git a/drivers/media/video/mx1_camera.c b/drivers/media/video/mx1_camera.c
index 5c17f9ec3d7c..bc0c23a1009c 100644
--- a/drivers/media/video/mx1_camera.c
+++ b/drivers/media/video/mx1_camera.c
@@ -161,7 +161,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx1_buffer *buf)
* This waits until this buffer is out of danger, i.e., until it is no
* longer in STATE_QUEUED or STATE_ACTIVE
*/
- videobuf_waiton(vb, 0, 0);
+ videobuf_waiton(vq, vb, 0, 0);
videobuf_dma_contig_free(vq, vb);
vb->state = VIDEOBUF_NEEDS_INIT;
@@ -382,10 +382,9 @@ static void mx1_camera_init_videobuf(struct videobuf_queue *q,
struct mx1_camera_dev *pcdev = ici->priv;
videobuf_queue_dma_contig_init(q, &mx1_videobuf_ops, icd->dev.parent,
- &pcdev->lock,
- V4L2_BUF_TYPE_VIDEO_CAPTURE,
- V4L2_FIELD_NONE,
- sizeof(struct mx1_buffer), icd);
+ &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE,
+ sizeof(struct mx1_buffer), icd, &icd->video_lock);
}
static int mclk_get_divisor(struct mx1_camera_dev *pcdev)
@@ -638,7 +637,7 @@ static int mx1_camera_try_fmt(struct soc_camera_device *icd,
return 0;
}
-static int mx1_camera_reqbufs(struct soc_camera_file *icf,
+static int mx1_camera_reqbufs(struct soc_camera_device *icd,
struct v4l2_requestbuffers *p)
{
int i;
@@ -650,7 +649,7 @@ static int mx1_camera_reqbufs(struct soc_camera_file *icf,
* it hadn't triggered
*/
for (i = 0; i < p->count; i++) {
- struct mx1_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+ struct mx1_buffer *buf = container_of(icd->vb_vidq.bufs[i],
struct mx1_buffer, vb);
buf->inwork = 0;
INIT_LIST_HEAD(&buf->vb.queue);
@@ -661,10 +660,10 @@ static int mx1_camera_reqbufs(struct soc_camera_file *icf,
static unsigned int mx1_camera_poll(struct file *file, poll_table *pt)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
struct mx1_buffer *buf;
- buf = list_entry(icf->vb_vidq.stream.next, struct mx1_buffer,
+ buf = list_entry(icd->vb_vidq.stream.next, struct mx1_buffer,
vb.stream);
poll_wait(file, &buf->vb.done, pt);
diff --git a/drivers/media/video/mx2_camera.c b/drivers/media/video/mx2_camera.c
new file mode 100644
index 000000000000..4eab1c620318
--- /dev/null
+++ b/drivers/media/video/mx2_camera.c
@@ -0,0 +1,1525 @@
+/*
+ * V4L2 Driver for i.MX27/i.MX25 camera host
+ *
+ * Copyright (C) 2008, Sascha Hauer, Pengutronix
+ * Copyright (C) 2010, Baruch Siach, Orex Computed Radiography
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <linux/dma-mapping.h>
+#include <linux/errno.h>
+#include <linux/fs.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/mm.h>
+#include <linux/moduleparam.h>
+#include <linux/time.h>
+#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>
+#include <media/v4l2-dev.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+
+#include <linux/videodev2.h>
+
+#include <mach/mx2_cam.h>
+#ifdef CONFIG_MACH_MX27
+#include <mach/dma-mx1-mx2.h>
+#endif
+#include <mach/hardware.h>
+
+#include <asm/dma.h>
+
+#define MX2_CAM_DRV_NAME "mx2-camera"
+#define MX2_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define MX2_CAM_DRIVER_DESCRIPTION "i.MX2x_Camera"
+
+/* reset values */
+#define CSICR1_RESET_VAL 0x40000800
+#define CSICR2_RESET_VAL 0x0
+#define CSICR3_RESET_VAL 0x0
+
+/* csi control reg 1 */
+#define CSICR1_SWAP16_EN (1 << 31)
+#define CSICR1_EXT_VSYNC (1 << 30)
+#define CSICR1_EOF_INTEN (1 << 29)
+#define CSICR1_PRP_IF_EN (1 << 28)
+#define CSICR1_CCIR_MODE (1 << 27)
+#define CSICR1_COF_INTEN (1 << 26)
+#define CSICR1_SF_OR_INTEN (1 << 25)
+#define CSICR1_RF_OR_INTEN (1 << 24)
+#define CSICR1_STATFF_LEVEL (3 << 22)
+#define CSICR1_STATFF_INTEN (1 << 21)
+#define CSICR1_RXFF_LEVEL(l) (((l) & 3) << 19) /* MX27 */
+#define CSICR1_FB2_DMA_INTEN (1 << 20) /* MX25 */
+#define CSICR1_FB1_DMA_INTEN (1 << 19) /* MX25 */
+#define CSICR1_RXFF_INTEN (1 << 18)
+#define CSICR1_SOF_POL (1 << 17)
+#define CSICR1_SOF_INTEN (1 << 16)
+#define CSICR1_MCLKDIV(d) (((d) & 0xF) << 12)
+#define CSICR1_HSYNC_POL (1 << 11)
+#define CSICR1_CCIR_EN (1 << 10)
+#define CSICR1_MCLKEN (1 << 9)
+#define CSICR1_FCC (1 << 8)
+#define CSICR1_PACK_DIR (1 << 7)
+#define CSICR1_CLR_STATFIFO (1 << 6)
+#define CSICR1_CLR_RXFIFO (1 << 5)
+#define CSICR1_GCLK_MODE (1 << 4)
+#define CSICR1_INV_DATA (1 << 3)
+#define CSICR1_INV_PCLK (1 << 2)
+#define CSICR1_REDGE (1 << 1)
+
+#define SHIFT_STATFF_LEVEL 22
+#define SHIFT_RXFF_LEVEL 19
+#define SHIFT_MCLKDIV 12
+
+/* control reg 3 */
+#define CSICR3_FRMCNT (0xFFFF << 16)
+#define CSICR3_FRMCNT_RST (1 << 15)
+#define CSICR3_DMA_REFLASH_RFF (1 << 14)
+#define CSICR3_DMA_REFLASH_SFF (1 << 13)
+#define CSICR3_DMA_REQ_EN_RFF (1 << 12)
+#define CSICR3_DMA_REQ_EN_SFF (1 << 11)
+#define CSICR3_RXFF_LEVEL(l) (((l) & 7) << 4) /* MX25 */
+#define CSICR3_CSI_SUP (1 << 3)
+#define CSICR3_ZERO_PACK_EN (1 << 2)
+#define CSICR3_ECC_INT_EN (1 << 1)
+#define CSICR3_ECC_AUTO_EN (1 << 0)
+
+#define SHIFT_FRMCNT 16
+
+/* csi status reg */
+#define CSISR_SFF_OR_INT (1 << 25)
+#define CSISR_RFF_OR_INT (1 << 24)
+#define CSISR_STATFF_INT (1 << 21)
+#define CSISR_DMA_TSF_FB2_INT (1 << 20) /* MX25 */
+#define CSISR_DMA_TSF_FB1_INT (1 << 19) /* MX25 */
+#define CSISR_RXFF_INT (1 << 18)
+#define CSISR_EOF_INT (1 << 17)
+#define CSISR_SOF_INT (1 << 16)
+#define CSISR_F2_INT (1 << 15)
+#define CSISR_F1_INT (1 << 14)
+#define CSISR_COF_INT (1 << 13)
+#define CSISR_ECC_INT (1 << 1)
+#define CSISR_DRDY (1 << 0)
+
+#define CSICR1 0x00
+#define CSICR2 0x04
+#define CSISR (cpu_is_mx27() ? 0x08 : 0x18)
+#define CSISTATFIFO 0x0c
+#define CSIRFIFO 0x10
+#define CSIRXCNT 0x14
+#define CSICR3 (cpu_is_mx27() ? 0x1C : 0x08)
+#define CSIDMASA_STATFIFO 0x20
+#define CSIDMATA_STATFIFO 0x24
+#define CSIDMASA_FB1 0x28
+#define CSIDMASA_FB2 0x2c
+#define CSIFBUF_PARA 0x30
+#define CSIIMAG_PARA 0x34
+
+/* EMMA PrP */
+#define PRP_CNTL 0x00
+#define PRP_INTR_CNTL 0x04
+#define PRP_INTRSTATUS 0x08
+#define PRP_SOURCE_Y_PTR 0x0c
+#define PRP_SOURCE_CB_PTR 0x10
+#define PRP_SOURCE_CR_PTR 0x14
+#define PRP_DEST_RGB1_PTR 0x18
+#define PRP_DEST_RGB2_PTR 0x1c
+#define PRP_DEST_Y_PTR 0x20
+#define PRP_DEST_CB_PTR 0x24
+#define PRP_DEST_CR_PTR 0x28
+#define PRP_SRC_FRAME_SIZE 0x2c
+#define PRP_DEST_CH1_LINE_STRIDE 0x30
+#define PRP_SRC_PIXEL_FORMAT_CNTL 0x34
+#define PRP_CH1_PIXEL_FORMAT_CNTL 0x38
+#define PRP_CH1_OUT_IMAGE_SIZE 0x3c
+#define PRP_CH2_OUT_IMAGE_SIZE 0x40
+#define PRP_SRC_LINE_STRIDE 0x44
+#define PRP_CSC_COEF_012 0x48
+#define PRP_CSC_COEF_345 0x4c
+#define PRP_CSC_COEF_678 0x50
+#define PRP_CH1_RZ_HORI_COEF1 0x54
+#define PRP_CH1_RZ_HORI_COEF2 0x58
+#define PRP_CH1_RZ_HORI_VALID 0x5c
+#define PRP_CH1_RZ_VERT_COEF1 0x60
+#define PRP_CH1_RZ_VERT_COEF2 0x64
+#define PRP_CH1_RZ_VERT_VALID 0x68
+#define PRP_CH2_RZ_HORI_COEF1 0x6c
+#define PRP_CH2_RZ_HORI_COEF2 0x70
+#define PRP_CH2_RZ_HORI_VALID 0x74
+#define PRP_CH2_RZ_VERT_COEF1 0x78
+#define PRP_CH2_RZ_VERT_COEF2 0x7c
+#define PRP_CH2_RZ_VERT_VALID 0x80
+
+#define PRP_CNTL_CH1EN (1 << 0)
+#define PRP_CNTL_CH2EN (1 << 1)
+#define PRP_CNTL_CSIEN (1 << 2)
+#define PRP_CNTL_DATA_IN_YUV420 (0 << 3)
+#define PRP_CNTL_DATA_IN_YUV422 (1 << 3)
+#define PRP_CNTL_DATA_IN_RGB16 (2 << 3)
+#define PRP_CNTL_DATA_IN_RGB32 (3 << 3)
+#define PRP_CNTL_CH1_OUT_RGB8 (0 << 5)
+#define PRP_CNTL_CH1_OUT_RGB16 (1 << 5)
+#define PRP_CNTL_CH1_OUT_RGB32 (2 << 5)
+#define PRP_CNTL_CH1_OUT_YUV422 (3 << 5)
+#define PRP_CNTL_CH2_OUT_YUV420 (0 << 7)
+#define PRP_CNTL_CH2_OUT_YUV422 (1 << 7)
+#define PRP_CNTL_CH2_OUT_YUV444 (2 << 7)
+#define PRP_CNTL_CH1_LEN (1 << 9)
+#define PRP_CNTL_CH2_LEN (1 << 10)
+#define PRP_CNTL_SKIP_FRAME (1 << 11)
+#define PRP_CNTL_SWRST (1 << 12)
+#define PRP_CNTL_CLKEN (1 << 13)
+#define PRP_CNTL_WEN (1 << 14)
+#define PRP_CNTL_CH1BYP (1 << 15)
+#define PRP_CNTL_IN_TSKIP(x) ((x) << 16)
+#define PRP_CNTL_CH1_TSKIP(x) ((x) << 19)
+#define PRP_CNTL_CH2_TSKIP(x) ((x) << 22)
+#define PRP_CNTL_INPUT_FIFO_LEVEL(x) ((x) << 25)
+#define PRP_CNTL_RZ_FIFO_LEVEL(x) ((x) << 27)
+#define PRP_CNTL_CH2B1EN (1 << 29)
+#define PRP_CNTL_CH2B2EN (1 << 30)
+#define PRP_CNTL_CH2FEN (1 << 31)
+
+/* IRQ Enable and status register */
+#define PRP_INTR_RDERR (1 << 0)
+#define PRP_INTR_CH1WERR (1 << 1)
+#define PRP_INTR_CH2WERR (1 << 2)
+#define PRP_INTR_CH1FC (1 << 3)
+#define PRP_INTR_CH2FC (1 << 5)
+#define PRP_INTR_LBOVF (1 << 7)
+#define PRP_INTR_CH2OVF (1 << 8)
+
+#define mx27_camera_emma(pcdev) (cpu_is_mx27() && pcdev->use_emma)
+
+#define MAX_VIDEO_MEM 16
+
+struct mx2_camera_dev {
+ struct device *dev;
+ struct soc_camera_host soc_host;
+ struct soc_camera_device *icd;
+ struct clk *clk_csi, *clk_emma;
+
+ unsigned int irq_csi, irq_emma;
+ void __iomem *base_csi, *base_emma;
+ unsigned long base_dma;
+
+ struct mx2_camera_platform_data *pdata;
+ struct resource *res_csi, *res_emma;
+ unsigned long platform_flags;
+
+ struct list_head capture;
+ struct list_head active_bufs;
+
+ spinlock_t lock;
+
+ int dma;
+ struct mx2_buffer *active;
+ struct mx2_buffer *fb1_active;
+ struct mx2_buffer *fb2_active;
+
+ int use_emma;
+
+ u32 csicr1;
+
+ void *discard_buffer;
+ dma_addr_t discard_buffer_dma;
+ size_t discard_size;
+};
+
+/* buffer for one video frame */
+struct mx2_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ enum v4l2_mbus_pixelcode code;
+
+ int bufnum;
+};
+
+static void mx2_camera_deactivate(struct mx2_camera_dev *pcdev)
+{
+ unsigned long flags;
+
+ clk_disable(pcdev->clk_csi);
+ writel(0, pcdev->base_csi + CSICR1);
+ if (mx27_camera_emma(pcdev)) {
+ writel(0, pcdev->base_emma + PRP_CNTL);
+ } else if (cpu_is_mx25()) {
+ spin_lock_irqsave(&pcdev->lock, flags);
+ pcdev->fb1_active = NULL;
+ pcdev->fb2_active = NULL;
+ writel(0, pcdev->base_csi + CSIDMASA_FB1);
+ writel(0, pcdev->base_csi + CSIDMASA_FB2);
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+ }
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on mx2 camera sensor interface
+ */
+static int mx2_camera_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+ int ret;
+ u32 csicr1;
+
+ if (pcdev->icd)
+ return -EBUSY;
+
+ ret = clk_enable(pcdev->clk_csi);
+ if (ret < 0)
+ return ret;
+
+ csicr1 = CSICR1_MCLKEN;
+
+ if (mx27_camera_emma(pcdev)) {
+ csicr1 |= CSICR1_PRP_IF_EN | CSICR1_FCC |
+ CSICR1_RXFF_LEVEL(0);
+ } else if (cpu_is_mx27())
+ csicr1 |= CSICR1_SOF_INTEN | CSICR1_RXFF_LEVEL(2);
+
+ pcdev->csicr1 = csicr1;
+ writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+ pcdev->icd = icd;
+
+ dev_info(icd->dev.parent, "Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ return 0;
+}
+
+static void mx2_camera_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+
+ BUG_ON(icd != pcdev->icd);
+
+ dev_info(icd->dev.parent, "Camera driver detached from camera %d\n",
+ icd->devnum);
+
+ mx2_camera_deactivate(pcdev);
+
+ if (pcdev->discard_buffer) {
+ dma_free_coherent(ici->v4l2_dev.dev, pcdev->discard_size,
+ pcdev->discard_buffer,
+ pcdev->discard_buffer_dma);
+ pcdev->discard_buffer = NULL;
+ }
+
+ pcdev->icd = NULL;
+}
+
+#ifdef CONFIG_MACH_MX27
+static void mx27_camera_dma_enable(struct mx2_camera_dev *pcdev)
+{
+ u32 tmp;
+
+ imx_dma_enable(pcdev->dma);
+
+ tmp = readl(pcdev->base_csi + CSICR1);
+ tmp |= CSICR1_RF_OR_INTEN;
+ writel(tmp, pcdev->base_csi + CSICR1);
+}
+
+static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
+{
+ struct mx2_camera_dev *pcdev = data;
+ u32 status = readl(pcdev->base_csi + CSISR);
+
+ if (status & CSISR_SOF_INT && pcdev->active) {
+ u32 tmp;
+
+ tmp = readl(pcdev->base_csi + CSICR1);
+ writel(tmp | CSICR1_CLR_RXFIFO, pcdev->base_csi + CSICR1);
+ mx27_camera_dma_enable(pcdev);
+ }
+
+ writel(CSISR_SOF_INT | CSISR_RFF_OR_INT, pcdev->base_csi + CSISR);
+
+ return IRQ_HANDLED;
+}
+#else
+static irqreturn_t mx27_camera_irq(int irq_csi, void *data)
+{
+ return IRQ_NONE;
+}
+#endif /* CONFIG_MACH_MX27 */
+
+static void mx25_camera_frame_done(struct mx2_camera_dev *pcdev, int fb,
+ int state)
+{
+ struct videobuf_buffer *vb;
+ struct mx2_buffer *buf;
+ struct mx2_buffer **fb_active = fb == 1 ? &pcdev->fb1_active :
+ &pcdev->fb2_active;
+ u32 fb_reg = fb == 1 ? CSIDMASA_FB1 : CSIDMASA_FB2;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (*fb_active == NULL)
+ goto out;
+
+ vb = &(*fb_active)->vb;
+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ vb->state = state;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+
+ wake_up(&vb->done);
+
+ if (list_empty(&pcdev->capture)) {
+ buf = NULL;
+ writel(0, pcdev->base_csi + fb_reg);
+ } else {
+ buf = list_entry(pcdev->capture.next, struct mx2_buffer,
+ vb.queue);
+ vb = &buf->vb;
+ list_del(&vb->queue);
+ vb->state = VIDEOBUF_ACTIVE;
+ writel(videobuf_to_dma_contig(vb), pcdev->base_csi + fb_reg);
+ }
+
+ *fb_active = buf;
+
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static irqreturn_t mx25_camera_irq(int irq_csi, void *data)
+{
+ struct mx2_camera_dev *pcdev = data;
+ u32 status = readl(pcdev->base_csi + CSISR);
+
+ if (status & CSISR_DMA_TSF_FB1_INT)
+ mx25_camera_frame_done(pcdev, 1, VIDEOBUF_DONE);
+ else if (status & CSISR_DMA_TSF_FB2_INT)
+ mx25_camera_frame_done(pcdev, 2, VIDEOBUF_DONE);
+
+ /* FIXME: handle CSISR_RFF_OR_INT */
+
+ writel(status, pcdev->base_csi + CSISR);
+
+ return IRQ_HANDLED;
+}
+
+/*
+ * Videobuf operations
+ */
+static int mx2_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+
+ dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+
+ *size = bytes_per_line * icd->user_height;
+
+ if (0 == *count)
+ *count = 32;
+ if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct mx2_buffer *buf)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct videobuf_buffer *vb = &buf->vb;
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ /*
+ * This waits until this buffer is out of danger, i.e., until it is no
+ * longer in state VIDEOBUF_QUEUED or VIDEOBUF_ACTIVE
+ */
+ videobuf_waiton(vq, vb, 0, 0);
+
+ videobuf_dma_contig_free(vq, vb);
+ dev_dbg(&icd->dev, "%s freed\n", __func__);
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int mx2_videobuf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ int ret = 0;
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+
+#ifdef DEBUG
+ /*
+ * This can be useful if you want to see if we actually fill
+ * the buffer with something
+ */
+ memset((void *)vb->baddr, 0xaa, vb->bsize);
+#endif
+
+ if (buf->code != icd->current_fmt->code ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height ||
+ vb->field != field) {
+ buf->code = icd->current_fmt->code;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
+ vb->field = field;
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ }
+
+ vb->size = bytes_per_line * vb->height;
+ if (vb->baddr && vb->bsize < vb->size) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret)
+ goto fail;
+
+ vb->state = VIDEOBUF_PREPARED;
+ }
+
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+out:
+ return ret;
+}
+
+static void mx2_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 mx2_camera_dev *pcdev = ici->priv;
+ struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+ unsigned long flags;
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ vb->state = VIDEOBUF_QUEUED;
+ list_add_tail(&vb->queue, &pcdev->capture);
+
+ if (mx27_camera_emma(pcdev)) {
+ goto out;
+#ifdef CONFIG_MACH_MX27
+ } else if (cpu_is_mx27()) {
+ int ret;
+
+ if (pcdev->active == NULL) {
+ ret = imx_dma_setup_single(pcdev->dma,
+ videobuf_to_dma_contig(vb), vb->size,
+ (u32)pcdev->base_dma + 0x10,
+ DMA_MODE_READ);
+ if (ret) {
+ vb->state = VIDEOBUF_ERROR;
+ wake_up(&vb->done);
+ goto out;
+ }
+
+ vb->state = VIDEOBUF_ACTIVE;
+ pcdev->active = buf;
+ }
+#endif
+ } else { /* cpu_is_mx25() */
+ u32 csicr3, dma_inten = 0;
+
+ if (pcdev->fb1_active == NULL) {
+ writel(videobuf_to_dma_contig(vb),
+ pcdev->base_csi + CSIDMASA_FB1);
+ pcdev->fb1_active = buf;
+ dma_inten = CSICR1_FB1_DMA_INTEN;
+ } else if (pcdev->fb2_active == NULL) {
+ writel(videobuf_to_dma_contig(vb),
+ pcdev->base_csi + CSIDMASA_FB2);
+ pcdev->fb2_active = buf;
+ dma_inten = CSICR1_FB2_DMA_INTEN;
+ }
+
+ if (dma_inten) {
+ list_del(&vb->queue);
+ vb->state = VIDEOBUF_ACTIVE;
+
+ csicr3 = readl(pcdev->base_csi + CSICR3);
+
+ /* Reflash DMA */
+ writel(csicr3 | CSICR3_DMA_REFLASH_RFF,
+ pcdev->base_csi + CSICR3);
+
+ /* clear & enable interrupts */
+ writel(dma_inten, pcdev->base_csi + CSISR);
+ pcdev->csicr1 |= dma_inten;
+ writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+ /* enable DMA */
+ csicr3 |= CSICR3_DMA_REQ_EN_RFF | CSICR3_RXFF_LEVEL(1);
+ writel(csicr3, pcdev->base_csi + CSICR3);
+ }
+ }
+
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void mx2_videobuf_release(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 mx2_camera_dev *pcdev = ici->priv;
+ struct mx2_buffer *buf = container_of(vb, struct mx2_buffer, vb);
+ unsigned long flags;
+
+#ifdef DEBUG
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ switch (vb->state) {
+ case VIDEOBUF_ACTIVE:
+ dev_info(&icd->dev, "%s (active)\n", __func__);
+ break;
+ case VIDEOBUF_QUEUED:
+ dev_info(&icd->dev, "%s (queued)\n", __func__);
+ break;
+ case VIDEOBUF_PREPARED:
+ dev_info(&icd->dev, "%s (prepared)\n", __func__);
+ break;
+ default:
+ dev_info(&icd->dev, "%s (unknown) %d\n", __func__,
+ vb->state);
+ break;
+ }
+#endif
+
+ /*
+ * Terminate only queued but inactive buffers. Active buffers are
+ * released when they become inactive after videobuf_waiton().
+ *
+ * FIXME: implement forced termination of active buffers for mx27 and
+ * mx27 eMMA, so that the user won't get stuck in an uninterruptible
+ * state. This requires a specific handling for each of the these DMA
+ * types.
+ */
+ spin_lock_irqsave(&pcdev->lock, flags);
+ if (vb->state == VIDEOBUF_QUEUED) {
+ list_del(&vb->queue);
+ vb->state = VIDEOBUF_ERROR;
+ } else if (cpu_is_mx25() && vb->state == VIDEOBUF_ACTIVE) {
+ if (pcdev->fb1_active == buf) {
+ pcdev->csicr1 &= ~CSICR1_FB1_DMA_INTEN;
+ writel(0, pcdev->base_csi + CSIDMASA_FB1);
+ pcdev->fb1_active = NULL;
+ } else if (pcdev->fb2_active == buf) {
+ pcdev->csicr1 &= ~CSICR1_FB2_DMA_INTEN;
+ writel(0, pcdev->base_csi + CSIDMASA_FB2);
+ pcdev->fb2_active = NULL;
+ }
+ writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+ vb->state = VIDEOBUF_ERROR;
+ }
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops mx2_videobuf_ops = {
+ .buf_setup = mx2_videobuf_setup,
+ .buf_prepare = mx2_videobuf_prepare,
+ .buf_queue = mx2_videobuf_queue,
+ .buf_release = mx2_videobuf_release,
+};
+
+static void mx2_camera_init_videobuf(struct videobuf_queue *q,
+ struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+
+ videobuf_queue_dma_contig_init(q, &mx2_videobuf_ops, pcdev->dev,
+ &pcdev->lock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_NONE, sizeof(struct mx2_buffer),
+ icd, &icd->video_lock);
+}
+
+#define MX2_BUS_FLAGS (SOCAM_DATAWIDTH_8 | \
+ SOCAM_MASTER | \
+ SOCAM_VSYNC_ACTIVE_HIGH | \
+ SOCAM_VSYNC_ACTIVE_LOW | \
+ SOCAM_HSYNC_ACTIVE_HIGH | \
+ SOCAM_HSYNC_ACTIVE_LOW | \
+ SOCAM_PCLK_SAMPLE_RISING | \
+ SOCAM_PCLK_SAMPLE_FALLING | \
+ SOCAM_DATA_ACTIVE_HIGH | \
+ SOCAM_DATA_ACTIVE_LOW)
+
+static int mx27_camera_emma_prp_reset(struct mx2_camera_dev *pcdev)
+{
+ u32 cntl;
+ int count = 0;
+
+ cntl = readl(pcdev->base_emma + PRP_CNTL);
+ writel(PRP_CNTL_SWRST, pcdev->base_emma + PRP_CNTL);
+ while (count++ < 100) {
+ if (!(readl(pcdev->base_emma + PRP_CNTL) & PRP_CNTL_SWRST))
+ return 0;
+ barrier();
+ udelay(1);
+ }
+
+ return -ETIMEDOUT;
+}
+
+static void mx27_camera_emma_buf_init(struct soc_camera_device *icd,
+ int bytesperline)
+{
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+
+ writel(pcdev->discard_buffer_dma,
+ pcdev->base_emma + PRP_DEST_RGB1_PTR);
+ writel(pcdev->discard_buffer_dma,
+ pcdev->base_emma + PRP_DEST_RGB2_PTR);
+
+ /*
+ * We only use the EMMA engine to get rid of the broken
+ * DMA Engine. No color space consversion at the moment.
+ * We set the incomming and outgoing pixelformat to an
+ * 16 Bit wide format and adjust the bytesperline
+ * accordingly. With this configuration the inputdata
+ * will not be changed by the emma and could be any type
+ * of 16 Bit Pixelformat.
+ */
+ writel(PRP_CNTL_CH1EN |
+ PRP_CNTL_CSIEN |
+ PRP_CNTL_DATA_IN_RGB16 |
+ PRP_CNTL_CH1_OUT_RGB16 |
+ PRP_CNTL_CH1_LEN |
+ PRP_CNTL_CH1BYP |
+ PRP_CNTL_CH1_TSKIP(0) |
+ PRP_CNTL_IN_TSKIP(0),
+ pcdev->base_emma + PRP_CNTL);
+
+ writel(((bytesperline >> 1) << 16) | icd->user_height,
+ pcdev->base_emma + PRP_SRC_FRAME_SIZE);
+ writel(((bytesperline >> 1) << 16) | icd->user_height,
+ pcdev->base_emma + PRP_CH1_OUT_IMAGE_SIZE);
+ writel(bytesperline,
+ pcdev->base_emma + PRP_DEST_CH1_LINE_STRIDE);
+ writel(0x2ca00565, /* RGB565 */
+ pcdev->base_emma + PRP_SRC_PIXEL_FORMAT_CNTL);
+ writel(0x2ca00565, /* RGB565 */
+ pcdev->base_emma + PRP_CH1_PIXEL_FORMAT_CNTL);
+
+ /* Enable interrupts */
+ writel(PRP_INTR_RDERR |
+ PRP_INTR_CH1WERR |
+ PRP_INTR_CH2WERR |
+ PRP_INTR_CH1FC |
+ PRP_INTR_CH2FC |
+ PRP_INTR_LBOVF |
+ PRP_INTR_CH2OVF,
+ pcdev->base_emma + PRP_INTR_CNTL);
+}
+
+static int mx2_camera_set_bus_param(struct soc_camera_device *icd,
+ __u32 pixfmt)
+{
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct mx2_camera_dev *pcdev = ici->priv;
+ unsigned long camera_flags, common_flags;
+ int ret = 0;
+ int bytesperline;
+ u32 csicr1 = pcdev->csicr1;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ common_flags = soc_camera_bus_param_compatible(camera_flags,
+ MX2_BUS_FLAGS);
+ if (!common_flags)
+ return -EINVAL;
+
+ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & MX2_CAMERA_HSYNC_HIGH)
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+ else
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+ }
+
+ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+ if (pcdev->platform_flags & MX2_CAMERA_PCLK_SAMPLE_RISING)
+ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+ else
+ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+ }
+
+ ret = icd->ops->set_bus_param(icd, common_flags);
+ if (ret < 0)
+ return ret;
+
+ if (common_flags & SOCAM_PCLK_SAMPLE_RISING)
+ csicr1 |= CSICR1_REDGE;
+ if (common_flags & SOCAM_VSYNC_ACTIVE_HIGH)
+ csicr1 |= CSICR1_SOF_POL;
+ if (common_flags & SOCAM_HSYNC_ACTIVE_HIGH)
+ csicr1 |= CSICR1_HSYNC_POL;
+ if (pcdev->platform_flags & MX2_CAMERA_SWAP16)
+ csicr1 |= CSICR1_SWAP16_EN;
+ if (pcdev->platform_flags & MX2_CAMERA_EXT_VSYNC)
+ csicr1 |= CSICR1_EXT_VSYNC;
+ if (pcdev->platform_flags & MX2_CAMERA_CCIR)
+ csicr1 |= CSICR1_CCIR_EN;
+ if (pcdev->platform_flags & MX2_CAMERA_CCIR_INTERLACE)
+ csicr1 |= CSICR1_CCIR_MODE;
+ if (pcdev->platform_flags & MX2_CAMERA_GATED_CLOCK)
+ csicr1 |= CSICR1_GCLK_MODE;
+ if (pcdev->platform_flags & MX2_CAMERA_INV_DATA)
+ csicr1 |= CSICR1_INV_DATA;
+ if (pcdev->platform_flags & MX2_CAMERA_PACK_DIR_MSB)
+ csicr1 |= CSICR1_PACK_DIR;
+
+ pcdev->csicr1 = csicr1;
+
+ bytesperline = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ if (bytesperline < 0)
+ return bytesperline;
+
+ if (mx27_camera_emma(pcdev)) {
+ ret = mx27_camera_emma_prp_reset(pcdev);
+ if (ret)
+ return ret;
+
+ if (pcdev->discard_buffer)
+ dma_free_coherent(ici->v4l2_dev.dev,
+ pcdev->discard_size, pcdev->discard_buffer,
+ pcdev->discard_buffer_dma);
+
+ /*
+ * I didn't manage to properly enable/disable the prp
+ * on a per frame basis during running transfers,
+ * thus we allocate a buffer here and use it to
+ * discard frames when no buffer is available.
+ * Feel free to work on this ;)
+ */
+ pcdev->discard_size = icd->user_height * bytesperline;
+ pcdev->discard_buffer = dma_alloc_coherent(ici->v4l2_dev.dev,
+ pcdev->discard_size, &pcdev->discard_buffer_dma,
+ GFP_KERNEL);
+ if (!pcdev->discard_buffer)
+ return -ENOMEM;
+
+ mx27_camera_emma_buf_init(icd, bytesperline);
+ } else if (cpu_is_mx25()) {
+ writel((bytesperline * icd->user_height) >> 2,
+ pcdev->base_csi + CSIRXCNT);
+ writel((bytesperline << 16) | icd->user_height,
+ pcdev->base_csi + CSIIMAG_PARA);
+ }
+
+ writel(pcdev->csicr1, pcdev->base_csi + CSICR1);
+
+ return 0;
+}
+
+static int mx2_camera_set_crop(struct soc_camera_device *icd,
+ struct v4l2_crop *a)
+{
+ struct v4l2_rect *rect = &a->c;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ soc_camera_limit_side(&rect->left, &rect->width, 0, 2, 4096);
+ soc_camera_limit_side(&rect->top, &rect->height, 0, 2, 4096);
+
+ ret = v4l2_subdev_call(sd, video, s_crop, a);
+ if (ret < 0)
+ return ret;
+
+ /* The capture device might have changed its output */
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(icd->dev.parent, "Sensor cropped %dx%d\n",
+ mf.width, mf.height);
+
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
+
+ return ret;
+}
+
+static int mx2_camera_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate) {
+ dev_warn(icd->dev.parent, "Format %x not found\n",
+ pix->pixelformat);
+ return -EINVAL;
+ }
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+ if (ret < 0 && ret != -ENOIOCTLCMD)
+ return ret;
+
+ if (mf.code != xlate->code)
+ return -EINVAL;
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->field = mf.field;
+ pix->colorspace = mf.colorspace;
+ icd->current_fmt = xlate;
+
+ return 0;
+}
+
+static int mx2_camera_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_mbus_framefmt mf;
+ __u32 pixfmt = pix->pixelformat;
+ unsigned int width_limit;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ if (pixfmt && !xlate) {
+ dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
+ return -EINVAL;
+ }
+
+ /* FIXME: implement MX27 limits */
+
+ /* limit to MX25 hardware capabilities */
+ if (cpu_is_mx25()) {
+ if (xlate->host_fmt->bits_per_sample <= 8)
+ width_limit = 0xffff * 4;
+ else
+ width_limit = 0xffff * 2;
+ /* CSIIMAG_PARA limit */
+ if (pix->width > width_limit)
+ pix->width = width_limit;
+ if (pix->height > 0xffff)
+ pix->height = 0xffff;
+
+ pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
+ xlate->host_fmt);
+ if (pix->bytesperline < 0)
+ return pix->bytesperline;
+ pix->sizeimage = pix->height * pix->bytesperline;
+ if (pix->sizeimage > (4 * 0x3ffff)) { /* CSIRXCNT limit */
+ dev_warn(icd->dev.parent,
+ "Image size (%u) above limit\n",
+ pix->sizeimage);
+ return -EINVAL;
+ }
+ }
+
+ /* limit to sensor capabilities */
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ if (mf.field == V4L2_FIELD_ANY)
+ mf.field = V4L2_FIELD_NONE;
+ if (mf.field != V4L2_FIELD_NONE) {
+ dev_err(icd->dev.parent, "Field type %d unsupported.\n",
+ mf.field);
+ return -EINVAL;
+ }
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->field = mf.field;
+ pix->colorspace = mf.colorspace;
+
+ return 0;
+}
+
+static int mx2_camera_querycap(struct soc_camera_host *ici,
+ struct v4l2_capability *cap)
+{
+ /* cap->name is set by the friendly caller:-> */
+ strlcpy(cap->card, MX2_CAM_DRIVER_DESCRIPTION, sizeof(cap->card));
+ cap->version = MX2_CAM_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int mx2_camera_reqbufs(struct soc_camera_device *icd,
+ struct v4l2_requestbuffers *p)
+{
+ int i;
+
+ for (i = 0; i < p->count; i++) {
+ struct mx2_buffer *buf = container_of(icd->vb_vidq.bufs[i],
+ struct mx2_buffer, vb);
+ INIT_LIST_HEAD(&buf->vb.queue);
+ }
+
+ return 0;
+}
+
+#ifdef CONFIG_MACH_MX27
+static void mx27_camera_frame_done(struct mx2_camera_dev *pcdev, int state)
+{
+ struct videobuf_buffer *vb;
+ struct mx2_buffer *buf;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (!pcdev->active) {
+ dev_err(pcdev->dev, "%s called with no active buffer!\n",
+ __func__);
+ goto out;
+ }
+
+ vb = &pcdev->active->vb;
+ buf = container_of(vb, struct mx2_buffer, vb);
+ WARN_ON(list_empty(&vb->queue));
+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
+ list_del_init(&vb->queue);
+ vb->state = state;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+
+ wake_up(&vb->done);
+
+ if (list_empty(&pcdev->capture)) {
+ pcdev->active = NULL;
+ goto out;
+ }
+
+ pcdev->active = list_entry(pcdev->capture.next,
+ struct mx2_buffer, vb.queue);
+
+ vb = &pcdev->active->vb;
+ vb->state = VIDEOBUF_ACTIVE;
+
+ ret = imx_dma_setup_single(pcdev->dma, videobuf_to_dma_contig(vb),
+ vb->size, (u32)pcdev->base_dma + 0x10, DMA_MODE_READ);
+
+ if (ret) {
+ vb->state = VIDEOBUF_ERROR;
+ pcdev->active = NULL;
+ wake_up(&vb->done);
+ }
+
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void mx27_camera_dma_err_callback(int channel, void *data, int err)
+{
+ struct mx2_camera_dev *pcdev = data;
+
+ mx27_camera_frame_done(pcdev, VIDEOBUF_ERROR);
+}
+
+static void mx27_camera_dma_callback(int channel, void *data)
+{
+ struct mx2_camera_dev *pcdev = data;
+
+ mx27_camera_frame_done(pcdev, VIDEOBUF_DONE);
+}
+
+#define DMA_REQ_CSI_RX 31 /* FIXME: Add this to a resource */
+
+static int __devinit mx27_camera_dma_init(struct platform_device *pdev,
+ struct mx2_camera_dev *pcdev)
+{
+ int err;
+
+ pcdev->dma = imx_dma_request_by_prio("CSI RX DMA", DMA_PRIO_HIGH);
+ if (pcdev->dma < 0) {
+ dev_err(&pdev->dev, "%s failed to request DMA channel\n",
+ __func__);
+ return pcdev->dma;
+ }
+
+ err = imx_dma_setup_handlers(pcdev->dma, mx27_camera_dma_callback,
+ mx27_camera_dma_err_callback, pcdev);
+ if (err) {
+ dev_err(&pdev->dev, "%s failed to set DMA callback\n",
+ __func__);
+ goto err_out;
+ }
+
+ err = imx_dma_config_channel(pcdev->dma,
+ IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_FIFO,
+ IMX_DMA_MEMSIZE_32 | IMX_DMA_TYPE_LINEAR,
+ DMA_REQ_CSI_RX, 1);
+ if (err) {
+ dev_err(&pdev->dev, "%s failed to config DMA channel\n",
+ __func__);
+ goto err_out;
+ }
+
+ imx_dma_config_burstlen(pcdev->dma, 64);
+
+ return 0;
+
+err_out:
+ imx_dma_free(pcdev->dma);
+
+ return err;
+}
+#endif /* CONFIG_MACH_MX27 */
+
+static unsigned int mx2_camera_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_device *icd = file->private_data;
+
+ return videobuf_poll_stream(file, &icd->vb_vidq, pt);
+}
+
+static struct soc_camera_host_ops mx2_soc_camera_host_ops = {
+ .owner = THIS_MODULE,
+ .add = mx2_camera_add_device,
+ .remove = mx2_camera_remove_device,
+ .set_fmt = mx2_camera_set_fmt,
+ .set_crop = mx2_camera_set_crop,
+ .try_fmt = mx2_camera_try_fmt,
+ .init_videobuf = mx2_camera_init_videobuf,
+ .reqbufs = mx2_camera_reqbufs,
+ .poll = mx2_camera_poll,
+ .querycap = mx2_camera_querycap,
+ .set_bus_param = mx2_camera_set_bus_param,
+};
+
+static void mx27_camera_frame_done_emma(struct mx2_camera_dev *pcdev,
+ int bufnum, int state)
+{
+ struct mx2_buffer *buf;
+ struct videobuf_buffer *vb;
+ unsigned long phys;
+
+ if (!list_empty(&pcdev->active_bufs)) {
+ buf = list_entry(pcdev->active_bufs.next,
+ struct mx2_buffer, vb.queue);
+
+ BUG_ON(buf->bufnum != bufnum);
+
+ vb = &buf->vb;
+#ifdef DEBUG
+ phys = videobuf_to_dma_contig(vb);
+ if (readl(pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum)
+ != phys) {
+ dev_err(pcdev->dev, "%p != %p\n", phys,
+ readl(pcdev->base_emma +
+ PRP_DEST_RGB1_PTR +
+ 4 * bufnum));
+ }
+#endif
+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__, vb,
+ vb->baddr, vb->bsize);
+
+ list_del(&vb->queue);
+ vb->state = state;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+
+ wake_up(&vb->done);
+ }
+
+ if (list_empty(&pcdev->capture)) {
+ writel(pcdev->discard_buffer_dma, pcdev->base_emma +
+ PRP_DEST_RGB1_PTR + 4 * bufnum);
+ return;
+ }
+
+ buf = list_entry(pcdev->capture.next,
+ struct mx2_buffer, vb.queue);
+
+ buf->bufnum = !bufnum;
+
+ list_move_tail(pcdev->capture.next, &pcdev->active_bufs);
+
+ vb = &buf->vb;
+ vb->state = VIDEOBUF_ACTIVE;
+
+ phys = videobuf_to_dma_contig(vb);
+ writel(phys, pcdev->base_emma + PRP_DEST_RGB1_PTR + 4 * bufnum);
+}
+
+static irqreturn_t mx27_camera_emma_irq(int irq_emma, void *data)
+{
+ struct mx2_camera_dev *pcdev = data;
+ unsigned int status = readl(pcdev->base_emma + PRP_INTRSTATUS);
+ struct mx2_buffer *buf;
+
+ if (status & (1 << 7)) { /* overflow */
+ u32 cntl;
+ /*
+ * We only disable channel 1 here since this is the only
+ * enabled channel
+ *
+ * FIXME: the correct DMA overflow handling should be resetting
+ * the buffer, returning an error frame, and continuing with
+ * the next one.
+ */
+ cntl = readl(pcdev->base_emma + PRP_CNTL);
+ writel(cntl & ~PRP_CNTL_CH1EN, pcdev->base_emma + PRP_CNTL);
+ writel(cntl, pcdev->base_emma + PRP_CNTL);
+ }
+ if ((status & (3 << 5)) == (3 << 5)
+ && !list_empty(&pcdev->active_bufs)) {
+ /*
+ * Both buffers have triggered, process the one we're expecting
+ * to first
+ */
+ buf = list_entry(pcdev->active_bufs.next,
+ struct mx2_buffer, vb.queue);
+ mx27_camera_frame_done_emma(pcdev, buf->bufnum, VIDEOBUF_DONE);
+ status &= ~(1 << (6 - buf->bufnum)); /* mark processed */
+ }
+ if (status & (1 << 6))
+ mx27_camera_frame_done_emma(pcdev, 0, VIDEOBUF_DONE);
+ if (status & (1 << 5))
+ mx27_camera_frame_done_emma(pcdev, 1, VIDEOBUF_DONE);
+
+ writel(status, pcdev->base_emma + PRP_INTRSTATUS);
+
+ return IRQ_HANDLED;
+}
+
+static int __devinit mx27_camera_emma_init(struct mx2_camera_dev *pcdev)
+{
+ struct resource *res_emma = pcdev->res_emma;
+ int err = 0;
+
+ if (!request_mem_region(res_emma->start, resource_size(res_emma),
+ MX2_CAM_DRV_NAME)) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ pcdev->base_emma = ioremap(res_emma->start, resource_size(res_emma));
+ if (!pcdev->base_emma) {
+ err = -ENOMEM;
+ goto exit_release;
+ }
+
+ err = request_irq(pcdev->irq_emma, mx27_camera_emma_irq, 0,
+ MX2_CAM_DRV_NAME, pcdev);
+ if (err) {
+ dev_err(pcdev->dev, "Camera EMMA interrupt register failed \n");
+ goto exit_iounmap;
+ }
+
+ pcdev->clk_emma = clk_get(NULL, "emma");
+ if (IS_ERR(pcdev->clk_emma)) {
+ err = PTR_ERR(pcdev->clk_emma);
+ goto exit_free_irq;
+ }
+
+ clk_enable(pcdev->clk_emma);
+
+ err = mx27_camera_emma_prp_reset(pcdev);
+ if (err)
+ goto exit_clk_emma_put;
+
+ return err;
+
+exit_clk_emma_put:
+ clk_disable(pcdev->clk_emma);
+ clk_put(pcdev->clk_emma);
+exit_free_irq:
+ free_irq(pcdev->irq_emma, pcdev);
+exit_iounmap:
+ iounmap(pcdev->base_emma);
+exit_release:
+ release_mem_region(res_emma->start, resource_size(res_emma));
+out:
+ return err;
+}
+
+static int __devinit mx2_camera_probe(struct platform_device *pdev)
+{
+ struct mx2_camera_dev *pcdev;
+ struct resource *res_csi, *res_emma;
+ void __iomem *base_csi;
+ int irq_csi, irq_emma;
+ irq_handler_t mx2_cam_irq_handler = cpu_is_mx25() ? mx25_camera_irq
+ : mx27_camera_irq;
+ int err = 0;
+
+ dev_dbg(&pdev->dev, "initialising\n");
+
+ res_csi = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq_csi = platform_get_irq(pdev, 0);
+ if (res_csi == NULL || irq_csi < 0) {
+ dev_err(&pdev->dev, "Missing platform resources data\n");
+ err = -ENODEV;
+ goto exit;
+ }
+
+ pcdev = kzalloc(sizeof(*pcdev), GFP_KERNEL);
+ if (!pcdev) {
+ dev_err(&pdev->dev, "Could not allocate pcdev\n");
+ err = -ENOMEM;
+ goto exit;
+ }
+
+ pcdev->clk_csi = clk_get(&pdev->dev, NULL);
+ if (IS_ERR(pcdev->clk_csi)) {
+ err = PTR_ERR(pcdev->clk_csi);
+ goto exit_kfree;
+ }
+
+ dev_dbg(&pdev->dev, "Camera clock frequency: %ld\n",
+ clk_get_rate(pcdev->clk_csi));
+
+ /* Initialize DMA */
+#ifdef CONFIG_MACH_MX27
+ if (cpu_is_mx27()) {
+ err = mx27_camera_dma_init(pdev, pcdev);
+ if (err)
+ goto exit_clk_put;
+ }
+#endif /* CONFIG_MACH_MX27 */
+
+ pcdev->res_csi = res_csi;
+ pcdev->pdata = pdev->dev.platform_data;
+ if (pcdev->pdata) {
+ long rate;
+
+ pcdev->platform_flags = pcdev->pdata->flags;
+
+ rate = clk_round_rate(pcdev->clk_csi, pcdev->pdata->clk * 2);
+ if (rate <= 0) {
+ err = -ENODEV;
+ goto exit_dma_free;
+ }
+ err = clk_set_rate(pcdev->clk_csi, rate);
+ if (err < 0)
+ goto exit_dma_free;
+ }
+
+ INIT_LIST_HEAD(&pcdev->capture);
+ INIT_LIST_HEAD(&pcdev->active_bufs);
+ spin_lock_init(&pcdev->lock);
+
+ /*
+ * Request the regions.
+ */
+ if (!request_mem_region(res_csi->start, resource_size(res_csi),
+ MX2_CAM_DRV_NAME)) {
+ err = -EBUSY;
+ goto exit_dma_free;
+ }
+
+ base_csi = ioremap(res_csi->start, resource_size(res_csi));
+ if (!base_csi) {
+ err = -ENOMEM;
+ goto exit_release;
+ }
+ pcdev->irq_csi = irq_csi;
+ pcdev->base_csi = base_csi;
+ pcdev->base_dma = res_csi->start;
+ pcdev->dev = &pdev->dev;
+
+ err = request_irq(pcdev->irq_csi, mx2_cam_irq_handler, 0,
+ MX2_CAM_DRV_NAME, pcdev);
+ if (err) {
+ dev_err(pcdev->dev, "Camera interrupt register failed \n");
+ goto exit_iounmap;
+ }
+
+ if (cpu_is_mx27()) {
+ /* EMMA support */
+ res_emma = platform_get_resource(pdev, IORESOURCE_MEM, 1);
+ irq_emma = platform_get_irq(pdev, 1);
+
+ if (res_emma && irq_emma >= 0) {
+ dev_info(&pdev->dev, "Using EMMA\n");
+ pcdev->use_emma = 1;
+ pcdev->res_emma = res_emma;
+ pcdev->irq_emma = irq_emma;
+ if (mx27_camera_emma_init(pcdev))
+ goto exit_free_irq;
+ }
+ }
+
+ pcdev->soc_host.drv_name = MX2_CAM_DRV_NAME,
+ pcdev->soc_host.ops = &mx2_soc_camera_host_ops,
+ pcdev->soc_host.priv = pcdev;
+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
+ pcdev->soc_host.nr = pdev->id;
+ err = soc_camera_host_register(&pcdev->soc_host);
+ if (err)
+ goto exit_free_emma;
+
+ dev_info(&pdev->dev, "MX2 Camera (CSI) driver probed, clock frequency: %ld\n",
+ clk_get_rate(pcdev->clk_csi));
+
+ return 0;
+
+exit_free_emma:
+ if (mx27_camera_emma(pcdev)) {
+ free_irq(pcdev->irq_emma, pcdev);
+ clk_disable(pcdev->clk_emma);
+ clk_put(pcdev->clk_emma);
+ iounmap(pcdev->base_emma);
+ release_mem_region(res_emma->start, resource_size(res_emma));
+ }
+exit_free_irq:
+ free_irq(pcdev->irq_csi, pcdev);
+exit_iounmap:
+ iounmap(base_csi);
+exit_release:
+ release_mem_region(res_csi->start, resource_size(res_csi));
+exit_dma_free:
+#ifdef CONFIG_MACH_MX27
+ if (cpu_is_mx27())
+ imx_dma_free(pcdev->dma);
+exit_clk_put:
+ clk_put(pcdev->clk_csi);
+#endif /* CONFIG_MACH_MX27 */
+exit_kfree:
+ kfree(pcdev);
+exit:
+ return err;
+}
+
+static int __devexit mx2_camera_remove(struct platform_device *pdev)
+{
+ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+ struct mx2_camera_dev *pcdev = container_of(soc_host,
+ struct mx2_camera_dev, soc_host);
+ struct resource *res;
+
+ clk_put(pcdev->clk_csi);
+#ifdef CONFIG_MACH_MX27
+ if (cpu_is_mx27())
+ imx_dma_free(pcdev->dma);
+#endif /* CONFIG_MACH_MX27 */
+ free_irq(pcdev->irq_csi, pcdev);
+ if (mx27_camera_emma(pcdev))
+ free_irq(pcdev->irq_emma, pcdev);
+
+ soc_camera_host_unregister(&pcdev->soc_host);
+
+ iounmap(pcdev->base_csi);
+
+ if (mx27_camera_emma(pcdev)) {
+ clk_disable(pcdev->clk_emma);
+ clk_put(pcdev->clk_emma);
+ iounmap(pcdev->base_emma);
+ res = pcdev->res_emma;
+ release_mem_region(res->start, resource_size(res));
+ }
+
+ res = pcdev->res_csi;
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(pcdev);
+
+ dev_info(&pdev->dev, "MX2 Camera driver unloaded\n");
+
+ return 0;
+}
+
+static struct platform_driver mx2_camera_driver = {
+ .driver = {
+ .name = MX2_CAM_DRV_NAME,
+ },
+ .remove = __devexit_p(mx2_camera_remove),
+};
+
+
+static int __init mx2_camera_init(void)
+{
+ return platform_driver_probe(&mx2_camera_driver, &mx2_camera_probe);
+}
+
+static void __exit mx2_camera_exit(void)
+{
+ return platform_driver_unregister(&mx2_camera_driver);
+}
+
+module_init(mx2_camera_init);
+module_exit(mx2_camera_exit);
+
+MODULE_DESCRIPTION("i.MX27/i.MX25 SoC Camera Host driver");
+MODULE_AUTHOR("Sascha Hauer <sha@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mx3_camera.c b/drivers/media/video/mx3_camera.c
index d477e3058002..b9cb4a436959 100644
--- a/drivers/media/video/mx3_camera.c
+++ b/drivers/media/video/mx3_camera.c
@@ -27,6 +27,7 @@
#include <mach/ipu.h>
#include <mach/mx3_camera.h>
+#include <mach/dma.h>
#define MX3_CAM_DRV_NAME "mx3-camera"
@@ -185,7 +186,7 @@ static void free_buffer(struct videobuf_queue *vq, struct mx3_camera_buffer *buf
* This waits until this buffer is out of danger, i.e., until it is no
* longer in STATE_QUEUED or STATE_ACTIVE
*/
- videobuf_waiton(vb, 0, 0);
+ videobuf_waiton(vq, vb, 0, 0);
if (txd) {
ichan = to_idmac_chan(txd->chan);
async_tx_ack(txd);
@@ -441,7 +442,8 @@ static void mx3_camera_init_videobuf(struct videobuf_queue *q,
&mx3_cam->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_NONE,
- sizeof(struct mx3_camera_buffer), icd);
+ sizeof(struct mx3_camera_buffer), icd,
+ &icd->video_lock);
}
/* First part of ipu_csi_init_interface() */
@@ -637,6 +639,9 @@ static bool chan_filter(struct dma_chan *chan, void *arg)
struct dma_chan_request *rq = arg;
struct mx3_camera_pdata *pdata;
+ if (!imx_dma_is_ipu(chan))
+ return false;
+
if (!rq)
return false;
@@ -672,7 +677,7 @@ static bool mx3_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
fmt->packing == SOC_MBUS_PACKING_EXTEND16);
}
-static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
+static int mx3_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
struct soc_camera_format_xlate *xlate)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -689,7 +694,7 @@ static int mx3_camera_get_formats(struct soc_camera_device *icd, int idx,
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
dev_err(icd->dev.parent,
- "Invalid format code #%d: %d\n", idx, code);
+ "Invalid format code #%u: %d\n", idx, code);
return 0;
}
@@ -976,7 +981,7 @@ static int mx3_camera_try_fmt(struct soc_camera_device *icd,
return ret;
}
-static int mx3_camera_reqbufs(struct soc_camera_file *icf,
+static int mx3_camera_reqbufs(struct soc_camera_device *icd,
struct v4l2_requestbuffers *p)
{
return 0;
@@ -984,9 +989,9 @@ static int mx3_camera_reqbufs(struct soc_camera_file *icf,
static unsigned int mx3_camera_poll(struct file *file, poll_table *pt)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
- return videobuf_poll_stream(file, &icf->vb_vidq, pt);
+ return videobuf_poll_stream(file, &icd->vb_vidq, pt);
}
static int mx3_camera_querycap(struct soc_camera_host *ici,
@@ -1181,13 +1186,12 @@ static int __devinit mx3_camera_probe(struct platform_device *pdev)
goto egetres;
}
- mx3_cam = vmalloc(sizeof(*mx3_cam));
+ mx3_cam = vzalloc(sizeof(*mx3_cam));
if (!mx3_cam) {
dev_err(&pdev->dev, "Could not allocate mx3 camera object\n");
err = -ENOMEM;
goto ealloc;
}
- memset(mx3_cam, 0, sizeof(*mx3_cam));
mx3_cam->clk = clk_get(&pdev->dev, NULL);
if (IS_ERR(mx3_cam->clk)) {
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index ef0c8178f255..e8846a09b026 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -3,7 +3,7 @@
Copyright (C) 1998-2006 Michael Hunold <michael@mihu.de>
- Visit http://www.mihu.de/linux/saa7146/mxb/
+ Visit http://www.themm.net/~mihu/linux/saa7146/mxb.html
for further details about this card.
This program is free software; you can redistribute it and/or modify
@@ -32,7 +32,6 @@
#include "tea6415c.h"
#include "tea6420.h"
-#define I2C_SAA5246A 0x11
#define I2C_SAA7111A 0x24
#define I2C_TDA9840 0x42
#define I2C_TEA6415C 0x43
@@ -60,10 +59,10 @@ MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
enum { TUNER, AUX1, AUX3, AUX3_YC };
static struct v4l2_input mxb_inputs[MXB_INPUTS] = {
- { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
- { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0 },
+ { TUNER, "Tuner", V4L2_INPUT_TYPE_TUNER, 1, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { AUX1, "AUX1", V4L2_INPUT_TYPE_CAMERA, 2, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { AUX3, "AUX3 Composite", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
+ { AUX3_YC, "AUX3 S-Video", V4L2_INPUT_TYPE_CAMERA, 4, 0, V4L2_STD_PAL_BG|V4L2_STD_NTSC_M, 0, V4L2_IN_CAP_STD },
};
/* this array holds the information, which port of the saa7146 each
@@ -186,21 +185,17 @@ static int mxb_probe(struct saa7146_dev *dev)
}
mxb->saa7111a = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "saa7115", "saa7111", I2C_SAA7111A, NULL);
+ "saa7111", I2C_SAA7111A, NULL);
mxb->tea6420_1 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6420", "tea6420", I2C_TEA6420_1, NULL);
+ "tea6420", I2C_TEA6420_1, NULL);
mxb->tea6420_2 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6420", "tea6420", I2C_TEA6420_2, NULL);
+ "tea6420", I2C_TEA6420_2, NULL);
mxb->tea6415c = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tea6415c", "tea6415c", I2C_TEA6415C, NULL);
+ "tea6415c", I2C_TEA6415C, NULL);
mxb->tda9840 = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tda9840", "tda9840", I2C_TDA9840, NULL);
+ "tda9840", I2C_TDA9840, NULL);
mxb->tuner = v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "tuner", "tuner", I2C_TUNER, NULL);
- if (v4l2_i2c_new_subdev(&dev->v4l2_dev, &mxb->i2c_adapter,
- "saa5246a", "saa5246a", I2C_SAA5246A, NULL)) {
- printk(KERN_INFO "mxb: found teletext decoder\n");
- }
+ "tuner", I2C_TUNER, NULL);
/* check if all devices are present */
if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
diff --git a/drivers/media/video/omap/Kconfig b/drivers/media/video/omap/Kconfig
index 97c53949ca89..e63233fd2aaa 100644
--- a/drivers/media/video/omap/Kconfig
+++ b/drivers/media/video/omap/Kconfig
@@ -1,8 +1,8 @@
config VIDEO_OMAP2_VOUT
tristate "OMAP2/OMAP3 V4L2-Display driver"
- depends on ARCH_OMAP24XX || ARCH_OMAP34XX
+ depends on ARCH_OMAP2 || ARCH_OMAP3
select VIDEOBUF_GEN
- select VIDEOBUF_DMA_SG
+ select VIDEOBUF_DMA_CONTIG
select OMAP2_DSS
select OMAP2_VRAM
select OMAP2_VRFB
diff --git a/drivers/media/video/omap/Makefile b/drivers/media/video/omap/Makefile
index b8bab00ad010..b28788070ae1 100644
--- a/drivers/media/video/omap/Makefile
+++ b/drivers/media/video/omap/Makefile
@@ -3,5 +3,5 @@
#
# OMAP2/3 Display driver
-omap-vout-mod-objs := omap_vout.o omap_voutlib.o
-obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout-mod.o
+omap-vout-y := omap_vout.o omap_voutlib.o
+obj-$(CONFIG_VIDEO_OMAP2_VOUT) += omap-vout.o
diff --git a/drivers/media/video/omap/omap_vout.c b/drivers/media/video/omap/omap_vout.c
index 4c0ab499228b..029a4babfd61 100644
--- a/drivers/media/video/omap/omap_vout.c
+++ b/drivers/media/video/omap/omap_vout.c
@@ -38,8 +38,9 @@
#include <linux/dma-mapping.h>
#include <linux/irq.h>
#include <linux/videodev2.h>
+#include <linux/slab.h>
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-dma-contig.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
@@ -1053,9 +1054,9 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q,
struct videobuf_buffer *vb,
enum v4l2_field field)
{
+ dma_addr_t dmabuf;
struct vid_vrfb_dma *tx;
enum dss_rotation rotation;
- struct videobuf_dmabuf *dmabuf = NULL;
struct omap_vout_device *vout = q->priv_data;
u32 dest_frame_index = 0, src_element_index = 0;
u32 dest_element_index = 0, src_frame_index = 0;
@@ -1074,24 +1075,17 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q,
if (V4L2_MEMORY_USERPTR == vb->memory) {
if (0 == vb->baddr)
return -EINVAL;
- /* Virtual address */
- /* priv points to struct videobuf_pci_sg_memory. But we went
- * pointer to videobuf_dmabuf, which is member of
- * videobuf_pci_sg_memory */
- dmabuf = videobuf_to_dma(q->bufs[vb->i]);
- dmabuf->vmalloc = (void *) vb->baddr;
-
/* Physical address */
- dmabuf->bus_addr =
- (dma_addr_t) omap_vout_uservirt_to_phys(vb->baddr);
+ vout->queued_buf_addr[vb->i] = (u8 *)
+ omap_vout_uservirt_to_phys(vb->baddr);
+ } else {
+ vout->queued_buf_addr[vb->i] = (u8 *)vout->buf_phy_addr[vb->i];
}
- if (!rotation_enabled(vout)) {
- dmabuf = videobuf_to_dma(q->bufs[vb->i]);
- vout->queued_buf_addr[vb->i] = (u8 *) dmabuf->bus_addr;
+ if (!rotation_enabled(vout))
return 0;
- }
- dmabuf = videobuf_to_dma(q->bufs[vb->i]);
+
+ dmabuf = vout->buf_phy_addr[vb->i];
/* If rotation is enabled, copy input buffer into VRFB
* memory space using DMA. We are copying input buffer
* into VRFB memory space of desired angle and DSS will
@@ -1120,7 +1114,7 @@ static int omap_vout_buffer_prepare(struct videobuf_queue *q,
tx->dev_id, 0x0);
/* src_port required only for OMAP1 */
omap_set_dma_src_params(tx->dma_ch, 0, OMAP_DMA_AMODE_POST_INC,
- dmabuf->bus_addr, src_element_index, src_frame_index);
+ dmabuf, src_element_index, src_frame_index);
/*set dma source burst mode for VRFB */
omap_set_dma_src_burst_mode(tx->dma_ch, OMAP_DMA_DATA_BURST_16);
rotation = calc_rotation(vout);
@@ -1211,7 +1205,6 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
void *pos;
unsigned long start = vma->vm_start;
unsigned long size = (vma->vm_end - vma->vm_start);
- struct videobuf_dmabuf *dmabuf = NULL;
struct omap_vout_device *vout = file->private_data;
struct videobuf_queue *q = &vout->vbq;
@@ -1241,8 +1234,7 @@ static int omap_vout_mmap(struct file *file, struct vm_area_struct *vma)
vma->vm_page_prot = pgprot_writecombine(vma->vm_page_prot);
vma->vm_ops = &omap_vout_vm_ops;
vma->vm_private_data = (void *) vout;
- dmabuf = videobuf_to_dma(q->bufs[i]);
- pos = dmabuf->vmalloc;
+ pos = (void *)vout->buf_virt_addr[i];
vma->vm_pgoff = virt_to_phys((void *)pos) >> PAGE_SHIFT;
while (size > 0) {
unsigned long pfn;
@@ -1294,7 +1286,7 @@ static int omap_vout_release(struct file *file)
videobuf_mmap_free(q);
/* Even if apply changes fails we should continue
- freeing allocated memeory */
+ freeing allocated memory */
if (vout->streaming) {
u32 mask = 0;
@@ -1347,9 +1339,9 @@ static int omap_vout_open(struct file *file)
video_vbq_ops.buf_queue = omap_vout_buffer_queue;
spin_lock_init(&vout->vbq_lock);
- videobuf_queue_sg_init(q, &video_vbq_ops, NULL, &vout->vbq_lock,
- vout->type, V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), vout);
+ videobuf_queue_dma_contig_init(q, &video_vbq_ops, q->dev,
+ &vout->vbq_lock, vout->type, V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), vout, NULL);
v4l2_dbg(1, debug, &vout->vid_dev->v4l2_dev, "Exiting %s\n", __func__);
return 0;
@@ -1799,7 +1791,6 @@ static int vidioc_reqbufs(struct file *file, void *fh,
unsigned int i, num_buffers = 0;
struct omap_vout_device *vout = fh;
struct videobuf_queue *q = &vout->vbq;
- struct videobuf_dmabuf *dmabuf = NULL;
if ((req->type != V4L2_BUF_TYPE_VIDEO_OUTPUT) || (req->count < 0))
return -EINVAL;
@@ -1825,8 +1816,7 @@ static int vidioc_reqbufs(struct file *file, void *fh,
num_buffers = (vout->vid == OMAP_VIDEO1) ?
video1_numbuffers : video2_numbuffers;
for (i = num_buffers; i < vout->buffer_allocated; i++) {
- dmabuf = videobuf_to_dma(q->bufs[i]);
- omap_vout_free_buffer((u32)dmabuf->vmalloc,
+ omap_vout_free_buffer(vout->buf_virt_addr[i],
vout->buffer_size);
vout->buf_virt_addr[i] = 0;
vout->buf_phy_addr[i] = 0;
@@ -1855,12 +1845,7 @@ static int vidioc_reqbufs(struct file *file, void *fh,
goto reqbuf_err;
vout->buffer_allocated = req->count;
- for (i = 0; i < req->count; i++) {
- dmabuf = videobuf_to_dma(q->bufs[i]);
- dmabuf->vmalloc = (void *) vout->buf_virt_addr[i];
- dmabuf->bus_addr = (dma_addr_t) vout->buf_phy_addr[i];
- dmabuf->sglen = 1;
- }
+
reqbuf_err:
mutex_unlock(&vout->lock);
return ret;
@@ -2245,7 +2230,6 @@ static int __init omap_vout_setup_video_data(struct omap_vout_device *vout)
strlcpy(vfd->name, VOUT_NAME, sizeof(vfd->name));
- /* need to register for a VID_HARDWARE_* ID in videodev.h */
vfd->fops = &omap_vout_fops;
vfd->v4l2_dev = &vout->vid_dev->v4l2_dev;
mutex_init(&vout->lock);
@@ -2371,12 +2355,11 @@ static int __init omap_vout_create_video_devices(struct platform_device *pdev)
for (k = 0; k < pdev->num_resources; k++) {
- vout = kmalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
+ vout = kzalloc(sizeof(struct omap_vout_device), GFP_KERNEL);
if (!vout) {
dev_err(&pdev->dev, ": could not allocate memory\n");
return -ENOMEM;
}
- memset(vout, 0, sizeof(struct omap_vout_device));
vout->vid = k;
vid_dev->vouts[k] = vout;
@@ -2489,7 +2472,7 @@ static int omap_vout_remove(struct platform_device *pdev)
for (k = 0; k < vid_dev->num_displays; k++) {
if (vid_dev->displays[k]->state != OMAP_DSS_DISPLAY_DISABLED)
- vid_dev->displays[k]->disable(vid_dev->displays[k]);
+ vid_dev->displays[k]->driver->disable(vid_dev->displays[k]);
omap_dss_put_device(vid_dev->displays[k]);
}
@@ -2546,7 +2529,9 @@ static int __init omap_vout_probe(struct platform_device *pdev)
def_display = NULL;
}
if (def_display) {
- ret = def_display->enable(def_display);
+ struct omap_dss_driver *dssdrv = def_display->driver;
+
+ ret = dssdrv->enable(def_display);
if (ret) {
/* Here we are not considering a error
* as display may be enabled by frame
@@ -2559,22 +2544,14 @@ static int __init omap_vout_probe(struct platform_device *pdev)
/* set the update mode */
if (def_display->caps &
OMAP_DSS_DISPLAY_CAP_MANUAL_UPDATE) {
-#ifdef CONFIG_FB_OMAP2_FORCE_AUTO_UPDATE
- if (def_display->enable_te)
- def_display->enable_te(def_display, 1);
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
- OMAP_DSS_UPDATE_AUTO);
-#else /* MANUAL_UPDATE */
- if (def_display->enable_te)
- def_display->enable_te(def_display, 0);
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
+ if (dssdrv->enable_te)
+ dssdrv->enable_te(def_display, 0);
+ if (dssdrv->set_update_mode)
+ dssdrv->set_update_mode(def_display,
OMAP_DSS_UPDATE_MANUAL);
-#endif
} else {
- if (def_display->set_update_mode)
- def_display->set_update_mode(def_display,
+ if (dssdrv->set_update_mode)
+ dssdrv->set_update_mode(def_display,
OMAP_DSS_UPDATE_AUTO);
}
}
@@ -2593,8 +2570,8 @@ static int __init omap_vout_probe(struct platform_device *pdev)
for (i = 0; i < vid_dev->num_displays; i++) {
struct omap_dss_device *display = vid_dev->displays[i];
- if (display->update)
- display->update(display, 0, 0,
+ if (display->driver->update)
+ display->driver->update(display, 0, 0,
display->panel.timings.x_res,
display->panel.timings.y_res);
}
@@ -2609,8 +2586,8 @@ probe_err1:
if (ovl->manager && ovl->manager->device)
def_display = ovl->manager->device;
- if (def_display)
- def_display->disable(def_display);
+ if (def_display && def_display->driver)
+ def_display->driver->disable(def_display);
}
probe_err0:
kfree(vid_dev);
diff --git a/drivers/media/video/omap1_camera.c b/drivers/media/video/omap1_camera.c
new file mode 100644
index 000000000000..0a2fb2bfdbfb
--- /dev/null
+++ b/drivers/media/video/omap1_camera.c
@@ -0,0 +1,1702 @@
+/*
+ * V4L2 SoC Camera driver for OMAP1 Camera Interface
+ *
+ * Copyright (C) 2010, Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Based on V4L2 Driver for i.MXL/i.MXL camera (CSI) host
+ * Copyright (C) 2008, Paulius Zaleckas <paulius.zaleckas@teltonika.lt>
+ * Copyright (C) 2009, Darius Augulis <augulis.darius@gmail.com>
+ *
+ * Based on PXA SoC camera driver
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * Hardware specific bits initialy based on former work by Matt Callow
+ * drivers/media/video/omap/omap1510cam.c
+ * Copyright (C) 2006 Matt Callow
+ *
+ * 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/clk.h>
+#include <linux/dma-mapping.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/version.h>
+
+#include <media/omap1_camera.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/videobuf-dma-sg.h>
+
+#include <plat/dma.h>
+
+
+#define DRIVER_NAME "omap1-camera"
+#define VERSION_CODE KERNEL_VERSION(0, 0, 1)
+
+
+/*
+ * ---------------------------------------------------------------------------
+ * OMAP1 Camera Interface registers
+ * ---------------------------------------------------------------------------
+ */
+
+#define REG_CTRLCLOCK 0x00
+#define REG_IT_STATUS 0x04
+#define REG_MODE 0x08
+#define REG_STATUS 0x0C
+#define REG_CAMDATA 0x10
+#define REG_GPIO 0x14
+#define REG_PEAK_COUNTER 0x18
+
+/* CTRLCLOCK bit shifts */
+#define LCLK_EN BIT(7)
+#define DPLL_EN BIT(6)
+#define MCLK_EN BIT(5)
+#define CAMEXCLK_EN BIT(4)
+#define POLCLK BIT(3)
+#define FOSCMOD_SHIFT 0
+#define FOSCMOD_MASK (0x7 << FOSCMOD_SHIFT)
+#define FOSCMOD_12MHz 0x0
+#define FOSCMOD_6MHz 0x2
+#define FOSCMOD_9_6MHz 0x4
+#define FOSCMOD_24MHz 0x5
+#define FOSCMOD_8MHz 0x6
+
+/* IT_STATUS bit shifts */
+#define DATA_TRANSFER BIT(5)
+#define FIFO_FULL BIT(4)
+#define H_DOWN BIT(3)
+#define H_UP BIT(2)
+#define V_DOWN BIT(1)
+#define V_UP BIT(0)
+
+/* MODE bit shifts */
+#define RAZ_FIFO BIT(18)
+#define EN_FIFO_FULL BIT(17)
+#define EN_NIRQ BIT(16)
+#define THRESHOLD_SHIFT 9
+#define THRESHOLD_MASK (0x7f << THRESHOLD_SHIFT)
+#define DMA BIT(8)
+#define EN_H_DOWN BIT(7)
+#define EN_H_UP BIT(6)
+#define EN_V_DOWN BIT(5)
+#define EN_V_UP BIT(4)
+#define ORDERCAMD BIT(3)
+
+#define IRQ_MASK (EN_V_UP | EN_V_DOWN | EN_H_UP | EN_H_DOWN | \
+ EN_NIRQ | EN_FIFO_FULL)
+
+/* STATUS bit shifts */
+#define HSTATUS BIT(1)
+#define VSTATUS BIT(0)
+
+/* GPIO bit shifts */
+#define CAM_RST BIT(0)
+
+/* end of OMAP1 Camera Interface registers */
+
+
+#define SOCAM_BUS_FLAGS (SOCAM_MASTER | \
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH | \
+ SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING | \
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8)
+
+
+#define FIFO_SIZE ((THRESHOLD_MASK >> THRESHOLD_SHIFT) + 1)
+#define FIFO_SHIFT __fls(FIFO_SIZE)
+
+#define DMA_BURST_SHIFT (1 + OMAP_DMA_DATA_BURST_4)
+#define DMA_BURST_SIZE (1 << DMA_BURST_SHIFT)
+
+#define DMA_ELEMENT_SHIFT OMAP_DMA_DATA_TYPE_S32
+#define DMA_ELEMENT_SIZE (1 << DMA_ELEMENT_SHIFT)
+
+#define DMA_FRAME_SHIFT_CONTIG (FIFO_SHIFT - 1)
+#define DMA_FRAME_SHIFT_SG DMA_BURST_SHIFT
+
+#define DMA_FRAME_SHIFT(x) ((x) == OMAP1_CAM_DMA_CONTIG ? \
+ DMA_FRAME_SHIFT_CONTIG : \
+ DMA_FRAME_SHIFT_SG)
+#define DMA_FRAME_SIZE(x) (1 << DMA_FRAME_SHIFT(x))
+#define DMA_SYNC OMAP_DMA_SYNC_FRAME
+#define THRESHOLD_LEVEL DMA_FRAME_SIZE
+
+
+#define MAX_VIDEO_MEM 4 /* arbitrary video memory limit in MB */
+
+
+/*
+ * Structures
+ */
+
+/* buffer for one video frame */
+struct omap1_cam_buf {
+ struct videobuf_buffer vb;
+ enum v4l2_mbus_pixelcode code;
+ int inwork;
+ struct scatterlist *sgbuf;
+ int sgcount;
+ int bytes_left;
+ enum videobuf_state result;
+};
+
+struct omap1_cam_dev {
+ struct soc_camera_host soc_host;
+ struct soc_camera_device *icd;
+ struct clk *clk;
+
+ unsigned int irq;
+ void __iomem *base;
+
+ int dma_ch;
+
+ struct omap1_cam_platform_data *pdata;
+ struct resource *res;
+ unsigned long pflags;
+ unsigned long camexclk;
+
+ struct list_head capture;
+
+ /* lock used to protect videobuf */
+ spinlock_t lock;
+
+ /* Pointers to DMA buffers */
+ struct omap1_cam_buf *active;
+ struct omap1_cam_buf *ready;
+
+ enum omap1_cam_vb_mode vb_mode;
+ int (*mmap_mapper)(struct videobuf_queue *q,
+ struct videobuf_buffer *buf,
+ struct vm_area_struct *vma);
+
+ u32 reg_cache[0];
+};
+
+
+static void cam_write(struct omap1_cam_dev *pcdev, u16 reg, u32 val)
+{
+ pcdev->reg_cache[reg / sizeof(u32)] = val;
+ __raw_writel(val, pcdev->base + reg);
+}
+
+static u32 cam_read(struct omap1_cam_dev *pcdev, u16 reg, bool from_cache)
+{
+ return !from_cache ? __raw_readl(pcdev->base + reg) :
+ pcdev->reg_cache[reg / sizeof(u32)];
+}
+
+#define CAM_READ(pcdev, reg) \
+ cam_read(pcdev, REG_##reg, false)
+#define CAM_WRITE(pcdev, reg, val) \
+ cam_write(pcdev, REG_##reg, val)
+#define CAM_READ_CACHE(pcdev, reg) \
+ cam_read(pcdev, REG_##reg, true)
+
+/*
+ * Videobuf operations
+ */
+static int omap1_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+
+ *size = bytes_per_line * icd->user_height;
+
+ if (!*count || *count < OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode))
+ *count = OMAP1_CAMERA_MIN_BUF_COUNT(pcdev->vb_mode);
+
+ if (*size * *count > MAX_VIDEO_MEM * 1024 * 1024)
+ *count = (MAX_VIDEO_MEM * 1024 * 1024) / *size;
+
+ dev_dbg(icd->dev.parent,
+ "%s: count=%d, size=%d\n", __func__, *count, *size);
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct omap1_cam_buf *buf,
+ enum omap1_cam_vb_mode vb_mode)
+{
+ struct videobuf_buffer *vb = &buf->vb;
+
+ BUG_ON(in_interrupt());
+
+ videobuf_waiton(vq, vb, 0, 0);
+
+ if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ videobuf_dma_contig_free(vq, vb);
+ } else {
+ struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->dev.parent;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ videobuf_dma_unmap(dev, dma);
+ videobuf_dma_free(dma);
+ }
+
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int omap1_videobuf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct omap1_cam_buf *buf = container_of(vb, struct omap1_cam_buf, vb);
+ int bytes_per_line = soc_mbus_bytes_per_line(icd->user_width,
+ icd->current_fmt->host_fmt);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ int ret;
+
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+
+ WARN_ON(!list_empty(&vb->queue));
+
+ BUG_ON(NULL == icd->current_fmt);
+
+ buf->inwork = 1;
+
+ if (buf->code != icd->current_fmt->code || vb->field != field ||
+ vb->width != icd->user_width ||
+ vb->height != icd->user_height) {
+ buf->code = icd->current_fmt->code;
+ vb->width = icd->user_width;
+ vb->height = icd->user_height;
+ vb->field = field;
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ }
+
+ vb->size = bytes_per_line * vb->height;
+
+ if (vb->baddr && vb->bsize < vb->size) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret)
+ goto fail;
+
+ vb->state = VIDEOBUF_PREPARED;
+ }
+ buf->inwork = 0;
+
+ return 0;
+fail:
+ free_buffer(vq, buf, pcdev->vb_mode);
+out:
+ buf->inwork = 0;
+ return ret;
+}
+
+static void set_dma_dest_params(int dma_ch, struct omap1_cam_buf *buf,
+ enum omap1_cam_vb_mode vb_mode)
+{
+ dma_addr_t dma_addr;
+ unsigned int block_size;
+
+ if (vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ dma_addr = videobuf_to_dma_contig(&buf->vb);
+ block_size = buf->vb.size;
+ } else {
+ if (WARN_ON(!buf->sgbuf)) {
+ buf->result = VIDEOBUF_ERROR;
+ return;
+ }
+ dma_addr = sg_dma_address(buf->sgbuf);
+ if (WARN_ON(!dma_addr)) {
+ buf->sgbuf = NULL;
+ buf->result = VIDEOBUF_ERROR;
+ return;
+ }
+ block_size = sg_dma_len(buf->sgbuf);
+ if (WARN_ON(!block_size)) {
+ buf->sgbuf = NULL;
+ buf->result = VIDEOBUF_ERROR;
+ return;
+ }
+ if (unlikely(buf->bytes_left < block_size))
+ block_size = buf->bytes_left;
+ if (WARN_ON(dma_addr & (DMA_FRAME_SIZE(vb_mode) *
+ DMA_ELEMENT_SIZE - 1))) {
+ dma_addr = ALIGN(dma_addr, DMA_FRAME_SIZE(vb_mode) *
+ DMA_ELEMENT_SIZE);
+ block_size &= ~(DMA_FRAME_SIZE(vb_mode) *
+ DMA_ELEMENT_SIZE - 1);
+ }
+ buf->bytes_left -= block_size;
+ buf->sgcount++;
+ }
+
+ omap_set_dma_dest_params(dma_ch,
+ OMAP_DMA_PORT_EMIFF, OMAP_DMA_AMODE_POST_INC, dma_addr, 0, 0);
+ omap_set_dma_transfer_params(dma_ch,
+ OMAP_DMA_DATA_TYPE_S32, DMA_FRAME_SIZE(vb_mode),
+ block_size >> (DMA_FRAME_SHIFT(vb_mode) + DMA_ELEMENT_SHIFT),
+ DMA_SYNC, 0, 0);
+}
+
+static struct omap1_cam_buf *prepare_next_vb(struct omap1_cam_dev *pcdev)
+{
+ struct omap1_cam_buf *buf;
+
+ /*
+ * If there is already a buffer pointed out by the pcdev->ready,
+ * (re)use it, otherwise try to fetch and configure a new one.
+ */
+ buf = pcdev->ready;
+ if (!buf) {
+ if (list_empty(&pcdev->capture))
+ return buf;
+ buf = list_entry(pcdev->capture.next,
+ struct omap1_cam_buf, vb.queue);
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ pcdev->ready = buf;
+ list_del_init(&buf->vb.queue);
+ }
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, we can safely enter next buffer parameters
+ * into the DMA programming register set after the DMA
+ * has already been activated on the previous buffer
+ */
+ set_dma_dest_params(pcdev->dma_ch, buf, pcdev->vb_mode);
+ } else {
+ /*
+ * In SG mode, the above is not safe since there are probably
+ * a bunch of sgbufs from previous sglist still pending.
+ * Instead, mark the sglist fresh for the upcoming
+ * try_next_sgbuf().
+ */
+ buf->sgbuf = NULL;
+ }
+
+ return buf;
+}
+
+static struct scatterlist *try_next_sgbuf(int dma_ch, struct omap1_cam_buf *buf)
+{
+ struct scatterlist *sgbuf;
+
+ if (likely(buf->sgbuf)) {
+ /* current sglist is active */
+ if (unlikely(!buf->bytes_left)) {
+ /* indicate sglist complete */
+ sgbuf = NULL;
+ } else {
+ /* process next sgbuf */
+ sgbuf = sg_next(buf->sgbuf);
+ if (WARN_ON(!sgbuf)) {
+ buf->result = VIDEOBUF_ERROR;
+ } else if (WARN_ON(!sg_dma_len(sgbuf))) {
+ sgbuf = NULL;
+ buf->result = VIDEOBUF_ERROR;
+ }
+ }
+ buf->sgbuf = sgbuf;
+ } else {
+ /* sglist is fresh, initialize it before using */
+ struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+ sgbuf = dma->sglist;
+ if (!(WARN_ON(!sgbuf))) {
+ buf->sgbuf = sgbuf;
+ buf->sgcount = 0;
+ buf->bytes_left = buf->vb.size;
+ buf->result = VIDEOBUF_DONE;
+ }
+ }
+ if (sgbuf)
+ /*
+ * Put our next sgbuf parameters (address, size)
+ * into the DMA programming register set.
+ */
+ set_dma_dest_params(dma_ch, buf, OMAP1_CAM_DMA_SG);
+
+ return sgbuf;
+}
+
+static void start_capture(struct omap1_cam_dev *pcdev)
+{
+ struct omap1_cam_buf *buf = pcdev->active;
+ u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+ u32 mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN;
+
+ if (WARN_ON(!buf))
+ return;
+
+ /*
+ * Enable start of frame interrupt, which we will use for activating
+ * our end of frame watchdog when capture actually starts.
+ */
+ mode |= EN_V_UP;
+
+ if (unlikely(ctrlclock & LCLK_EN))
+ /* stop pixel clock before FIFO reset */
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+ /* reset FIFO */
+ CAM_WRITE(pcdev, MODE, mode | RAZ_FIFO);
+
+ omap_start_dma(pcdev->dma_ch);
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+ /*
+ * In SG mode, it's a good moment for fetching next sgbuf
+ * from the current sglist and, if available, already putting
+ * its parameters into the DMA programming register set.
+ */
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ }
+
+ /* (re)enable pixel clock */
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | LCLK_EN);
+ /* release FIFO reset */
+ CAM_WRITE(pcdev, MODE, mode);
+}
+
+static void suspend_capture(struct omap1_cam_dev *pcdev)
+{
+ u32 ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+ omap_stop_dma(pcdev->dma_ch);
+}
+
+static void disable_capture(struct omap1_cam_dev *pcdev)
+{
+ u32 mode = CAM_READ_CACHE(pcdev, MODE);
+
+ CAM_WRITE(pcdev, MODE, mode & ~(IRQ_MASK | DMA));
+}
+
+static void omap1_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 omap1_cam_dev *pcdev = ici->priv;
+ struct omap1_cam_buf *buf;
+ u32 mode;
+
+ list_add_tail(&vb->queue, &pcdev->capture);
+ vb->state = VIDEOBUF_QUEUED;
+
+ if (pcdev->active) {
+ /*
+ * Capture in progress, so don't touch pcdev->ready even if
+ * empty. Since the transfer of the DMA programming register set
+ * content to the DMA working register set is done automatically
+ * by the DMA hardware, this can pretty well happen while we
+ * are keeping the lock here. Leave fetching it from the queue
+ * to be done when a next DMA interrupt occures instead.
+ */
+ return;
+ }
+
+ WARN_ON(pcdev->ready);
+
+ buf = prepare_next_vb(pcdev);
+ if (WARN_ON(!buf))
+ return;
+
+ pcdev->active = buf;
+ pcdev->ready = NULL;
+
+ dev_dbg(icd->dev.parent,
+ "%s: capture not active, setup FIFO, start DMA\n", __func__);
+ mode = CAM_READ_CACHE(pcdev, MODE) & ~THRESHOLD_MASK;
+ mode |= THRESHOLD_LEVEL(pcdev->vb_mode) << THRESHOLD_SHIFT;
+ CAM_WRITE(pcdev, MODE, mode | EN_FIFO_FULL | DMA);
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+ /*
+ * In SG mode, the above prepare_next_vb() didn't actually
+ * put anything into the DMA programming register set,
+ * so we have to do it now, before activating DMA.
+ */
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ }
+
+ start_capture(pcdev);
+}
+
+static void omap1_videobuf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct omap1_cam_buf *buf =
+ container_of(vb, struct omap1_cam_buf, vb);
+ struct soc_camera_device *icd = vq->priv_data;
+ struct device *dev = icd->dev.parent;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+
+ switch (vb->state) {
+ case VIDEOBUF_DONE:
+ dev_dbg(dev, "%s (done)\n", __func__);
+ break;
+ case VIDEOBUF_ACTIVE:
+ dev_dbg(dev, "%s (active)\n", __func__);
+ break;
+ case VIDEOBUF_QUEUED:
+ dev_dbg(dev, "%s (queued)\n", __func__);
+ break;
+ case VIDEOBUF_PREPARED:
+ dev_dbg(dev, "%s (prepared)\n", __func__);
+ break;
+ default:
+ dev_dbg(dev, "%s (unknown %d)\n", __func__, vb->state);
+ break;
+ }
+
+ free_buffer(vq, buf, pcdev->vb_mode);
+}
+
+static void videobuf_done(struct omap1_cam_dev *pcdev,
+ enum videobuf_state result)
+{
+ struct omap1_cam_buf *buf = pcdev->active;
+ struct videobuf_buffer *vb;
+ struct device *dev = pcdev->icd->dev.parent;
+
+ if (WARN_ON(!buf)) {
+ suspend_capture(pcdev);
+ disable_capture(pcdev);
+ return;
+ }
+
+ if (result == VIDEOBUF_ERROR)
+ suspend_capture(pcdev);
+
+ vb = &buf->vb;
+ if (waitqueue_active(&vb->done)) {
+ if (!pcdev->ready && result != VIDEOBUF_ERROR) {
+ /*
+ * No next buffer has been entered into the DMA
+ * programming register set on time (could be done only
+ * while the previous DMA interurpt was processed, not
+ * later), so the last DMA block, be it a whole buffer
+ * if in CONTIG or its last sgbuf if in SG mode, is
+ * about to be reused by the just autoreinitialized DMA
+ * engine, and overwritten with next frame data. Best we
+ * can do is stopping the capture as soon as possible,
+ * hopefully before the next frame start.
+ */
+ suspend_capture(pcdev);
+ }
+ vb->state = result;
+ do_gettimeofday(&vb->ts);
+ if (result != VIDEOBUF_ERROR)
+ vb->field_count++;
+ wake_up(&vb->done);
+
+ /* shift in next buffer */
+ buf = pcdev->ready;
+ pcdev->active = buf;
+ pcdev->ready = NULL;
+
+ if (!buf) {
+ /*
+ * No next buffer was ready on time (see above), so
+ * indicate error condition to force capture restart or
+ * stop, depending on next buffer already queued or not.
+ */
+ result = VIDEOBUF_ERROR;
+ prepare_next_vb(pcdev);
+
+ buf = pcdev->ready;
+ pcdev->active = buf;
+ pcdev->ready = NULL;
+ }
+ } else if (pcdev->ready) {
+ /*
+ * In both CONTIG and SG mode, the DMA engine has possibly
+ * been already autoreinitialized with the preprogrammed
+ * pcdev->ready buffer. We can either accept this fact
+ * and just swap the buffers, or provoke an error condition
+ * and restart capture. The former seems less intrusive.
+ */
+ dev_dbg(dev, "%s: nobody waiting on videobuf, swap with next\n",
+ __func__);
+ pcdev->active = pcdev->ready;
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_SG) {
+ /*
+ * In SG mode, we have to make sure that the buffer we
+ * are putting back into the pcdev->ready is marked
+ * fresh.
+ */
+ buf->sgbuf = NULL;
+ }
+ pcdev->ready = buf;
+
+ buf = pcdev->active;
+ } else {
+ /*
+ * No next buffer has been entered into
+ * the DMA programming register set on time.
+ */
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, the DMA engine has already been
+ * reinitialized with the current buffer. Best we can do
+ * is not touching it.
+ */
+ dev_dbg(dev,
+ "%s: nobody waiting on videobuf, reuse it\n",
+ __func__);
+ } else {
+ /*
+ * In SG mode, the DMA engine has just been
+ * autoreinitialized with the last sgbuf from the
+ * current list. Restart capture in order to transfer
+ * next frame start into the first sgbuf, not the last
+ * one.
+ */
+ if (result != VIDEOBUF_ERROR) {
+ suspend_capture(pcdev);
+ result = VIDEOBUF_ERROR;
+ }
+ }
+ }
+
+ if (!buf) {
+ dev_dbg(dev, "%s: no more videobufs, stop capture\n", __func__);
+ disable_capture(pcdev);
+ return;
+ }
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, the current buffer parameters had already
+ * been entered into the DMA programming register set while the
+ * buffer was fetched with prepare_next_vb(), they may have also
+ * been transfered into the runtime set and already active if
+ * the DMA still running.
+ */
+ } else {
+ /* In SG mode, extra steps are required */
+ if (result == VIDEOBUF_ERROR)
+ /* make sure we (re)use sglist from start on error */
+ buf->sgbuf = NULL;
+
+ /*
+ * In any case, enter the next sgbuf parameters into the DMA
+ * programming register set. They will be used either during
+ * nearest DMA autoreinitialization or, in case of an error,
+ * on DMA startup below.
+ */
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ }
+
+ if (result == VIDEOBUF_ERROR) {
+ dev_dbg(dev, "%s: videobuf error; reset FIFO, restart DMA\n",
+ __func__);
+ start_capture(pcdev);
+ /*
+ * In SG mode, the above also resulted in the next sgbuf
+ * parameters being entered into the DMA programming register
+ * set, making them ready for next DMA autoreinitialization.
+ */
+ }
+
+ /*
+ * Finally, try fetching next buffer.
+ * In CONTIG mode, it will also enter it into the DMA programming
+ * register set, making it ready for next DMA autoreinitialization.
+ */
+ prepare_next_vb(pcdev);
+}
+
+static void dma_isr(int channel, unsigned short status, void *data)
+{
+ struct omap1_cam_dev *pcdev = data;
+ struct omap1_cam_buf *buf = pcdev->active;
+ unsigned long flags;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (WARN_ON(!buf)) {
+ suspend_capture(pcdev);
+ disable_capture(pcdev);
+ goto out;
+ }
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, assume we have just managed to collect the
+ * whole frame, hopefully before our end of frame watchdog is
+ * triggered. Then, all we have to do is disabling the watchdog
+ * for this frame, and calling videobuf_done() with success
+ * indicated.
+ */
+ CAM_WRITE(pcdev, MODE,
+ CAM_READ_CACHE(pcdev, MODE) & ~EN_V_DOWN);
+ videobuf_done(pcdev, VIDEOBUF_DONE);
+ } else {
+ /*
+ * In SG mode, we have to process every sgbuf from the current
+ * sglist, one after another.
+ */
+ if (buf->sgbuf) {
+ /*
+ * Current sglist not completed yet, try fetching next
+ * sgbuf, hopefully putting it into the DMA programming
+ * register set, making it ready for next DMA
+ * autoreinitialization.
+ */
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ if (buf->sgbuf)
+ goto out;
+
+ /*
+ * No more sgbufs left in the current sglist. This
+ * doesn't mean that the whole videobuffer is already
+ * complete, but only that the last sgbuf from the
+ * current sglist is about to be filled. It will be
+ * ready on next DMA interrupt, signalled with the
+ * buf->sgbuf set back to NULL.
+ */
+ if (buf->result != VIDEOBUF_ERROR) {
+ /*
+ * Video frame collected without errors so far,
+ * we can prepare for collecting a next one
+ * as soon as DMA gets autoreinitialized
+ * after the current (last) sgbuf is completed.
+ */
+ buf = prepare_next_vb(pcdev);
+ if (!buf)
+ goto out;
+
+ try_next_sgbuf(pcdev->dma_ch, buf);
+ goto out;
+ }
+ }
+ /* end of videobuf */
+ videobuf_done(pcdev, buf->result);
+ }
+
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static irqreturn_t cam_isr(int irq, void *data)
+{
+ struct omap1_cam_dev *pcdev = data;
+ struct device *dev = pcdev->icd->dev.parent;
+ struct omap1_cam_buf *buf = pcdev->active;
+ u32 it_status;
+ unsigned long flags;
+
+ it_status = CAM_READ(pcdev, IT_STATUS);
+ if (!it_status)
+ return IRQ_NONE;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ if (WARN_ON(!buf)) {
+ dev_warn(dev, "%s: unhandled camera interrupt, status == "
+ "%#x\n", __func__, it_status);
+ suspend_capture(pcdev);
+ disable_capture(pcdev);
+ goto out;
+ }
+
+ if (unlikely(it_status & FIFO_FULL)) {
+ dev_warn(dev, "%s: FIFO overflow\n", __func__);
+
+ } else if (it_status & V_DOWN) {
+ /* end of video frame watchdog */
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, the watchdog is disabled with
+ * successful DMA end of block interrupt, and reenabled
+ * on next frame start. If we get here, there is nothing
+ * to check, we must be out of sync.
+ */
+ } else {
+ if (buf->sgcount == 2) {
+ /*
+ * If exactly 2 sgbufs from the next sglist have
+ * been programmed into the DMA engine (the
+ * frist one already transfered into the DMA
+ * runtime register set, the second one still
+ * in the programming set), then we are in sync.
+ */
+ goto out;
+ }
+ }
+ dev_notice(dev, "%s: unexpected end of video frame\n",
+ __func__);
+
+ } else if (it_status & V_UP) {
+ u32 mode;
+
+ if (pcdev->vb_mode == OMAP1_CAM_DMA_CONTIG) {
+ /*
+ * In CONTIG mode, we need this interrupt every frame
+ * in oredr to reenable our end of frame watchdog.
+ */
+ mode = CAM_READ_CACHE(pcdev, MODE);
+ } else {
+ /*
+ * In SG mode, the below enabled end of frame watchdog
+ * is kept on permanently, so we can turn this one shot
+ * setup off.
+ */
+ mode = CAM_READ_CACHE(pcdev, MODE) & ~EN_V_UP;
+ }
+
+ if (!(mode & EN_V_DOWN)) {
+ /* (re)enable end of frame watchdog interrupt */
+ mode |= EN_V_DOWN;
+ }
+ CAM_WRITE(pcdev, MODE, mode);
+ goto out;
+
+ } else {
+ dev_warn(dev, "%s: unhandled camera interrupt, status == %#x\n",
+ __func__, it_status);
+ goto out;
+ }
+
+ videobuf_done(pcdev, VIDEOBUF_ERROR);
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+ return IRQ_HANDLED;
+}
+
+static struct videobuf_queue_ops omap1_videobuf_ops = {
+ .buf_setup = omap1_videobuf_setup,
+ .buf_prepare = omap1_videobuf_prepare,
+ .buf_queue = omap1_videobuf_queue,
+ .buf_release = omap1_videobuf_release,
+};
+
+
+/*
+ * SOC Camera host operations
+ */
+
+static void sensor_reset(struct omap1_cam_dev *pcdev, bool reset)
+{
+ /* apply/release camera sensor reset if requested by platform data */
+ if (pcdev->pflags & OMAP1_CAMERA_RST_HIGH)
+ CAM_WRITE(pcdev, GPIO, reset);
+ else if (pcdev->pflags & OMAP1_CAMERA_RST_LOW)
+ CAM_WRITE(pcdev, GPIO, !reset);
+}
+
+/*
+ * The following two functions absolutely depend on the fact, that
+ * there can be only one camera on OMAP1 camera sensor interface
+ */
+static int omap1_cam_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ u32 ctrlclock;
+
+ if (pcdev->icd)
+ return -EBUSY;
+
+ clk_enable(pcdev->clk);
+
+ /* setup sensor clock */
+ ctrlclock = CAM_READ(pcdev, CTRLCLOCK);
+ ctrlclock &= ~(CAMEXCLK_EN | MCLK_EN | DPLL_EN);
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+ ctrlclock &= ~FOSCMOD_MASK;
+ switch (pcdev->camexclk) {
+ case 6000000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_6MHz;
+ break;
+ case 8000000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_8MHz | DPLL_EN;
+ break;
+ case 9600000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_9_6MHz | DPLL_EN;
+ break;
+ case 12000000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_12MHz;
+ break;
+ case 24000000:
+ ctrlclock |= CAMEXCLK_EN | FOSCMOD_24MHz | DPLL_EN;
+ default:
+ break;
+ }
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~DPLL_EN);
+
+ /* enable internal clock */
+ ctrlclock |= MCLK_EN;
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+ sensor_reset(pcdev, false);
+
+ pcdev->icd = icd;
+
+ dev_dbg(icd->dev.parent, "OMAP1 Camera driver attached to camera %d\n",
+ icd->devnum);
+ return 0;
+}
+
+static void omap1_cam_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ u32 ctrlclock;
+
+ BUG_ON(icd != pcdev->icd);
+
+ suspend_capture(pcdev);
+ disable_capture(pcdev);
+
+ sensor_reset(pcdev, true);
+
+ /* disable and release system clocks */
+ ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+ ctrlclock &= ~(MCLK_EN | DPLL_EN | CAMEXCLK_EN);
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+ ctrlclock = (ctrlclock & ~FOSCMOD_MASK) | FOSCMOD_12MHz;
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock | MCLK_EN);
+
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~MCLK_EN);
+
+ clk_disable(pcdev->clk);
+
+ pcdev->icd = NULL;
+
+ dev_dbg(icd->dev.parent,
+ "OMAP1 Camera driver detached from camera %d\n", icd->devnum);
+}
+
+/* Duplicate standard formats based on host capability of byte swapping */
+static const struct soc_mbus_pixelfmt omap1_cam_formats[] = {
+ [V4L2_MBUS_FMT_UYVY8_2X8] = {
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .name = "YUYV",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+ [V4L2_MBUS_FMT_VYUY8_2X8] = {
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .name = "YVYU",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+ [V4L2_MBUS_FMT_YUYV8_2X8] = {
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .name = "UYVY",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+ [V4L2_MBUS_FMT_YVYU8_2X8] = {
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .name = "VYUY",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+ [V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE] = {
+ .fourcc = V4L2_PIX_FMT_RGB555,
+ .name = "RGB555",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+ [V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE] = {
+ .fourcc = V4L2_PIX_FMT_RGB555X,
+ .name = "RGB555X",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+ [V4L2_MBUS_FMT_RGB565_2X8_BE] = {
+ .fourcc = V4L2_PIX_FMT_RGB565,
+ .name = "RGB565",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+ [V4L2_MBUS_FMT_RGB565_2X8_LE] = {
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .name = "RGB565X",
+ .bits_per_sample = 8,
+ .packing = SOC_MBUS_PACKING_2X8_PADHI,
+ .order = SOC_MBUS_ORDER_BE,
+ },
+};
+
+static int omap1_cam_get_formats(struct soc_camera_device *icd,
+ unsigned int idx, struct soc_camera_format_xlate *xlate)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct device *dev = icd->dev.parent;
+ int formats = 0, ret;
+ enum v4l2_mbus_pixelcode code;
+ const struct soc_mbus_pixelfmt *fmt;
+
+ ret = v4l2_subdev_call(sd, video, enum_mbus_fmt, idx, &code);
+ if (ret < 0)
+ /* No more formats */
+ return 0;
+
+ fmt = soc_mbus_get_fmtdesc(code);
+ if (!fmt) {
+ dev_err(dev, "%s: invalid format code #%d: %d\n", __func__,
+ idx, code);
+ return 0;
+ }
+
+ /* Check support for the requested bits-per-sample */
+ if (fmt->bits_per_sample != 8)
+ return 0;
+
+ switch (code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = &omap1_cam_formats[code];
+ xlate->code = code;
+ xlate++;
+ dev_dbg(dev, "%s: providing format %s "
+ "as byte swapped code #%d\n", __func__,
+ omap1_cam_formats[code].name, code);
+ }
+ default:
+ if (xlate)
+ dev_dbg(dev, "%s: providing format %s "
+ "in pass-through mode\n", __func__,
+ fmt->name);
+ }
+ formats++;
+ if (xlate) {
+ xlate->host_fmt = fmt;
+ xlate->code = code;
+ xlate++;
+ }
+
+ return formats;
+}
+
+static bool is_dma_aligned(s32 bytes_per_line, unsigned int height,
+ enum omap1_cam_vb_mode vb_mode)
+{
+ int size = bytes_per_line * height;
+
+ return IS_ALIGNED(bytes_per_line, DMA_ELEMENT_SIZE) &&
+ IS_ALIGNED(size, DMA_FRAME_SIZE(vb_mode) * DMA_ELEMENT_SIZE);
+}
+
+static int dma_align(int *width, int *height,
+ const struct soc_mbus_pixelfmt *fmt,
+ enum omap1_cam_vb_mode vb_mode, bool enlarge)
+{
+ s32 bytes_per_line = soc_mbus_bytes_per_line(*width, fmt);
+
+ if (bytes_per_line < 0)
+ return bytes_per_line;
+
+ if (!is_dma_aligned(bytes_per_line, *height, vb_mode)) {
+ unsigned int pxalign = __fls(bytes_per_line / *width);
+ unsigned int salign = DMA_FRAME_SHIFT(vb_mode) +
+ DMA_ELEMENT_SHIFT - pxalign;
+ unsigned int incr = enlarge << salign;
+
+ v4l_bound_align_image(width, 1, *width + incr, 0,
+ height, 1, *height + incr, 0, salign);
+ return 0;
+ }
+ return 1;
+}
+
+#define subdev_call_with_sense(pcdev, dev, icd, sd, function, args...) \
+({ \
+ struct soc_camera_sense sense = { \
+ .master_clock = pcdev->camexclk, \
+ .pixel_clock_max = 0, \
+ }; \
+ int __ret; \
+ \
+ if (pcdev->pdata) \
+ sense.pixel_clock_max = pcdev->pdata->lclk_khz_max * 1000; \
+ icd->sense = &sense; \
+ __ret = v4l2_subdev_call(sd, video, function, ##args); \
+ icd->sense = NULL; \
+ \
+ if (sense.flags & SOCAM_SENSE_PCLK_CHANGED) { \
+ if (sense.pixel_clock > sense.pixel_clock_max) { \
+ dev_err(dev, "%s: pixel clock %lu " \
+ "set by the camera too high!\n", \
+ __func__, sense.pixel_clock); \
+ __ret = -EINVAL; \
+ } \
+ } \
+ __ret; \
+})
+
+static int set_mbus_format(struct omap1_cam_dev *pcdev, struct device *dev,
+ struct soc_camera_device *icd, struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf,
+ const struct soc_camera_format_xlate *xlate)
+{
+ s32 bytes_per_line;
+ int ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_mbus_fmt, mf);
+
+ if (ret < 0) {
+ dev_err(dev, "%s: s_mbus_fmt failed\n", __func__);
+ return ret;
+ }
+
+ if (mf->code != xlate->code) {
+ dev_err(dev, "%s: unexpected pixel code change\n", __func__);
+ return -EINVAL;
+ }
+
+ bytes_per_line = soc_mbus_bytes_per_line(mf->width, xlate->host_fmt);
+ if (bytes_per_line < 0) {
+ dev_err(dev, "%s: soc_mbus_bytes_per_line() failed\n",
+ __func__);
+ return bytes_per_line;
+ }
+
+ if (!is_dma_aligned(bytes_per_line, mf->height, pcdev->vb_mode)) {
+ dev_err(dev, "%s: resulting geometry %ux%u not DMA aligned\n",
+ __func__, mf->width, mf->height);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int omap1_cam_set_crop(struct soc_camera_device *icd,
+ struct v4l2_crop *crop)
+{
+ struct v4l2_rect *rect = &crop->c;
+ const struct soc_camera_format_xlate *xlate = icd->current_fmt;
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ struct device *dev = icd->dev.parent;
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ ret = subdev_call_with_sense(pcdev, dev, icd, sd, s_crop, crop);
+ if (ret < 0) {
+ dev_warn(dev, "%s: failed to crop to %ux%u@%u:%u\n", __func__,
+ rect->width, rect->height, rect->left, rect->top);
+ return ret;
+ }
+
+ ret = v4l2_subdev_call(sd, video, g_mbus_fmt, &mf);
+ if (ret < 0) {
+ dev_warn(dev, "%s: failed to fetch current format\n", __func__);
+ return ret;
+ }
+
+ ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
+ false);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
+ __func__, mf.width, mf.height,
+ xlate->host_fmt->name);
+ return ret;
+ }
+
+ if (!ret) {
+ /* sensor returned geometry not DMA aligned, trying to fix */
+ ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to set format\n", __func__);
+ return ret;
+ }
+ }
+
+ icd->user_width = mf.width;
+ icd->user_height = mf.height;
+
+ return 0;
+}
+
+static int omap1_cam_set_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_camera_format_xlate *xlate;
+ struct device *dev = icd->dev.parent;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate) {
+ dev_warn(dev, "%s: format %#x not found\n", __func__,
+ pix->pixelformat);
+ return -EINVAL;
+ }
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ ret = dma_align(&mf.width, &mf.height, xlate->host_fmt, pcdev->vb_mode,
+ true);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to align %ux%u %s with DMA\n",
+ __func__, pix->width, pix->height,
+ xlate->host_fmt->name);
+ return ret;
+ }
+
+ ret = set_mbus_format(pcdev, dev, icd, sd, &mf, xlate);
+ if (ret < 0) {
+ dev_err(dev, "%s: failed to set format\n", __func__);
+ return ret;
+ }
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->field = mf.field;
+ pix->colorspace = mf.colorspace;
+ icd->current_fmt = xlate;
+
+ return 0;
+}
+
+static int omap1_cam_try_fmt(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ const struct soc_camera_format_xlate *xlate;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct v4l2_mbus_framefmt mf;
+ int ret;
+ /* TODO: limit to mx1 hardware capabilities */
+
+ xlate = soc_camera_xlate_by_fourcc(icd, pix->pixelformat);
+ if (!xlate) {
+ dev_warn(icd->dev.parent, "Format %#x not found\n",
+ pix->pixelformat);
+ return -EINVAL;
+ }
+
+ mf.width = pix->width;
+ mf.height = pix->height;
+ mf.field = pix->field;
+ mf.colorspace = pix->colorspace;
+ mf.code = xlate->code;
+
+ /* limit to sensor capabilities */
+ ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ if (ret < 0)
+ return ret;
+
+ pix->width = mf.width;
+ pix->height = mf.height;
+ pix->field = mf.field;
+ pix->colorspace = mf.colorspace;
+
+ return 0;
+}
+
+static bool sg_mode;
+
+/*
+ * Local mmap_mapper wrapper,
+ * used for detecting videobuf-dma-contig buffer allocation failures
+ * and switching to videobuf-dma-sg automatically for future attempts.
+ */
+static int omap1_cam_mmap_mapper(struct videobuf_queue *q,
+ struct videobuf_buffer *buf,
+ struct vm_area_struct *vma)
+{
+ struct soc_camera_device *icd = q->priv_data;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ int ret;
+
+ ret = pcdev->mmap_mapper(q, buf, vma);
+
+ if (ret == -ENOMEM)
+ sg_mode = true;
+
+ return ret;
+}
+
+static void omap1_cam_init_videobuf(struct videobuf_queue *q,
+ struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+
+ if (!sg_mode)
+ videobuf_queue_dma_contig_init(q, &omap1_videobuf_ops,
+ icd->dev.parent, &pcdev->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
+ else
+ videobuf_queue_sg_init(q, &omap1_videobuf_ops,
+ icd->dev.parent, &pcdev->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct omap1_cam_buf), icd, &icd->video_lock);
+
+ /* use videobuf mode (auto)selected with the module parameter */
+ pcdev->vb_mode = sg_mode ? OMAP1_CAM_DMA_SG : OMAP1_CAM_DMA_CONTIG;
+
+ /*
+ * Ensure we substitute the videobuf-dma-contig version of the
+ * mmap_mapper() callback with our own wrapper, used for switching
+ * automatically to videobuf-dma-sg on buffer allocation failure.
+ */
+ if (!sg_mode && q->int_ops->mmap_mapper != omap1_cam_mmap_mapper) {
+ pcdev->mmap_mapper = q->int_ops->mmap_mapper;
+ q->int_ops->mmap_mapper = omap1_cam_mmap_mapper;
+ }
+}
+
+static int omap1_cam_reqbufs(struct soc_camera_device *icd,
+ struct v4l2_requestbuffers *p)
+{
+ int i;
+
+ /*
+ * This is for locking debugging only. I removed spinlocks and now I
+ * check whether .prepare is ever called on a linked buffer, or whether
+ * a dma IRQ can occur for an in-work or unlinked buffer. Until now
+ * it hadn't triggered
+ */
+ for (i = 0; i < p->count; i++) {
+ struct omap1_cam_buf *buf = container_of(icd->vb_vidq.bufs[i],
+ struct omap1_cam_buf, vb);
+ buf->inwork = 0;
+ INIT_LIST_HEAD(&buf->vb.queue);
+ }
+
+ return 0;
+}
+
+static int omap1_cam_querycap(struct soc_camera_host *ici,
+ struct v4l2_capability *cap)
+{
+ /* cap->name is set by the friendly caller:-> */
+ strlcpy(cap->card, "OMAP1 Camera", sizeof(cap->card));
+ cap->version = VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int omap1_cam_set_bus_param(struct soc_camera_device *icd,
+ __u32 pixfmt)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct omap1_cam_dev *pcdev = ici->priv;
+ struct device *dev = icd->dev.parent;
+ const struct soc_camera_format_xlate *xlate;
+ const struct soc_mbus_pixelfmt *fmt;
+ unsigned long camera_flags, common_flags;
+ u32 ctrlclock, mode;
+ int ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ common_flags = soc_camera_bus_param_compatible(camera_flags,
+ SOCAM_BUS_FLAGS);
+ if (!common_flags)
+ return -EINVAL;
+
+ /* Make choices, possibly based on platform configuration */
+ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+ if (!pcdev->pdata ||
+ pcdev->pdata->flags & OMAP1_CAMERA_LCLK_RISING)
+ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+ else
+ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+ }
+
+ ret = icd->ops->set_bus_param(icd, common_flags);
+ if (ret < 0)
+ return ret;
+
+ ctrlclock = CAM_READ_CACHE(pcdev, CTRLCLOCK);
+ if (ctrlclock & LCLK_EN)
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+
+ if (common_flags & SOCAM_PCLK_SAMPLE_RISING) {
+ dev_dbg(dev, "CTRLCLOCK_REG |= POLCLK\n");
+ ctrlclock |= POLCLK;
+ } else {
+ dev_dbg(dev, "CTRLCLOCK_REG &= ~POLCLK\n");
+ ctrlclock &= ~POLCLK;
+ }
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock & ~LCLK_EN);
+
+ if (ctrlclock & LCLK_EN)
+ CAM_WRITE(pcdev, CTRLCLOCK, ctrlclock);
+
+ /* select bus endianess */
+ xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+ fmt = xlate->host_fmt;
+
+ mode = CAM_READ(pcdev, MODE) & ~(RAZ_FIFO | IRQ_MASK | DMA);
+ if (fmt->order == SOC_MBUS_ORDER_LE) {
+ dev_dbg(dev, "MODE_REG &= ~ORDERCAMD\n");
+ CAM_WRITE(pcdev, MODE, mode & ~ORDERCAMD);
+ } else {
+ dev_dbg(dev, "MODE_REG |= ORDERCAMD\n");
+ CAM_WRITE(pcdev, MODE, mode | ORDERCAMD);
+ }
+
+ return 0;
+}
+
+static unsigned int omap1_cam_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_device *icd = file->private_data;
+ struct omap1_cam_buf *buf;
+
+ buf = list_entry(icd->vb_vidq.stream.next, struct omap1_cam_buf,
+ vb.stream);
+
+ poll_wait(file, &buf->vb.done, pt);
+
+ if (buf->vb.state == VIDEOBUF_DONE ||
+ buf->vb.state == VIDEOBUF_ERROR)
+ return POLLIN | POLLRDNORM;
+
+ return 0;
+}
+
+static struct soc_camera_host_ops omap1_host_ops = {
+ .owner = THIS_MODULE,
+ .add = omap1_cam_add_device,
+ .remove = omap1_cam_remove_device,
+ .get_formats = omap1_cam_get_formats,
+ .set_crop = omap1_cam_set_crop,
+ .set_fmt = omap1_cam_set_fmt,
+ .try_fmt = omap1_cam_try_fmt,
+ .init_videobuf = omap1_cam_init_videobuf,
+ .reqbufs = omap1_cam_reqbufs,
+ .querycap = omap1_cam_querycap,
+ .set_bus_param = omap1_cam_set_bus_param,
+ .poll = omap1_cam_poll,
+};
+
+static int __init omap1_cam_probe(struct platform_device *pdev)
+{
+ struct omap1_cam_dev *pcdev;
+ struct resource *res;
+ struct clk *clk;
+ void __iomem *base;
+ unsigned int irq;
+ int err = 0;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ irq = platform_get_irq(pdev, 0);
+ if (!res || (int)irq <= 0) {
+ err = -ENODEV;
+ goto exit;
+ }
+
+ clk = clk_get(&pdev->dev, "armper_ck");
+ if (IS_ERR(clk)) {
+ err = PTR_ERR(clk);
+ goto exit;
+ }
+
+ pcdev = kzalloc(sizeof(*pcdev) + resource_size(res), GFP_KERNEL);
+ if (!pcdev) {
+ dev_err(&pdev->dev, "Could not allocate pcdev\n");
+ err = -ENOMEM;
+ goto exit_put_clk;
+ }
+
+ pcdev->res = res;
+ pcdev->clk = clk;
+
+ pcdev->pdata = pdev->dev.platform_data;
+ pcdev->pflags = pcdev->pdata->flags;
+
+ if (pcdev->pdata)
+ pcdev->camexclk = pcdev->pdata->camexclk_khz * 1000;
+
+ switch (pcdev->camexclk) {
+ case 6000000:
+ case 8000000:
+ case 9600000:
+ case 12000000:
+ case 24000000:
+ break;
+ default:
+ dev_warn(&pdev->dev,
+ "Incorrect sensor clock frequency %ld kHz, "
+ "should be one of 0, 6, 8, 9.6, 12 or 24 MHz, "
+ "please correct your platform data\n",
+ pcdev->pdata->camexclk_khz);
+ pcdev->camexclk = 0;
+ case 0:
+ dev_info(&pdev->dev,
+ "Not providing sensor clock\n");
+ }
+
+ INIT_LIST_HEAD(&pcdev->capture);
+ spin_lock_init(&pcdev->lock);
+
+ /*
+ * Request the region.
+ */
+ if (!request_mem_region(res->start, resource_size(res), DRIVER_NAME)) {
+ err = -EBUSY;
+ goto exit_kfree;
+ }
+
+ base = ioremap(res->start, resource_size(res));
+ if (!base) {
+ err = -ENOMEM;
+ goto exit_release;
+ }
+ pcdev->irq = irq;
+ pcdev->base = base;
+
+ sensor_reset(pcdev, true);
+
+ err = omap_request_dma(OMAP_DMA_CAMERA_IF_RX, DRIVER_NAME,
+ dma_isr, (void *)pcdev, &pcdev->dma_ch);
+ if (err < 0) {
+ dev_err(&pdev->dev, "Can't request DMA for OMAP1 Camera\n");
+ err = -EBUSY;
+ goto exit_iounmap;
+ }
+ dev_dbg(&pdev->dev, "got DMA channel %d\n", pcdev->dma_ch);
+
+ /* preconfigure DMA */
+ omap_set_dma_src_params(pcdev->dma_ch, OMAP_DMA_PORT_TIPB,
+ OMAP_DMA_AMODE_CONSTANT, res->start + REG_CAMDATA,
+ 0, 0);
+ omap_set_dma_dest_burst_mode(pcdev->dma_ch, OMAP_DMA_DATA_BURST_4);
+ /* setup DMA autoinitialization */
+ omap_dma_link_lch(pcdev->dma_ch, pcdev->dma_ch);
+
+ err = request_irq(pcdev->irq, cam_isr, 0, DRIVER_NAME, pcdev);
+ if (err) {
+ dev_err(&pdev->dev, "Camera interrupt register failed\n");
+ goto exit_free_dma;
+ }
+
+ pcdev->soc_host.drv_name = DRIVER_NAME;
+ pcdev->soc_host.ops = &omap1_host_ops;
+ pcdev->soc_host.priv = pcdev;
+ pcdev->soc_host.v4l2_dev.dev = &pdev->dev;
+ pcdev->soc_host.nr = pdev->id;
+
+ err = soc_camera_host_register(&pcdev->soc_host);
+ if (err)
+ goto exit_free_irq;
+
+ dev_info(&pdev->dev, "OMAP1 Camera Interface driver loaded\n");
+
+ return 0;
+
+exit_free_irq:
+ free_irq(pcdev->irq, pcdev);
+exit_free_dma:
+ omap_free_dma(pcdev->dma_ch);
+exit_iounmap:
+ iounmap(base);
+exit_release:
+ release_mem_region(res->start, resource_size(res));
+exit_kfree:
+ kfree(pcdev);
+exit_put_clk:
+ clk_put(clk);
+exit:
+ return err;
+}
+
+static int __exit omap1_cam_remove(struct platform_device *pdev)
+{
+ struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
+ struct omap1_cam_dev *pcdev = container_of(soc_host,
+ struct omap1_cam_dev, soc_host);
+ struct resource *res;
+
+ free_irq(pcdev->irq, pcdev);
+
+ omap_free_dma(pcdev->dma_ch);
+
+ soc_camera_host_unregister(soc_host);
+
+ iounmap(pcdev->base);
+
+ res = pcdev->res;
+ release_mem_region(res->start, resource_size(res));
+
+ kfree(pcdev);
+
+ clk_put(pcdev->clk);
+
+ dev_info(&pdev->dev, "OMAP1 Camera Interface driver unloaded\n");
+
+ return 0;
+}
+
+static struct platform_driver omap1_cam_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ },
+ .probe = omap1_cam_probe,
+ .remove = __exit_p(omap1_cam_remove),
+};
+
+static int __init omap1_cam_init(void)
+{
+ return platform_driver_register(&omap1_cam_driver);
+}
+module_init(omap1_cam_init);
+
+static void __exit omap1_cam_exit(void)
+{
+ platform_driver_unregister(&omap1_cam_driver);
+}
+module_exit(omap1_cam_exit);
+
+module_param(sg_mode, bool, 0644);
+MODULE_PARM_DESC(sg_mode, "videobuf mode, 0: dma-contig (default), 1: dma-sg");
+
+MODULE_DESCRIPTION("OMAP1 Camera Interface driver");
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:" DRIVER_NAME);
diff --git a/drivers/media/video/omap24xxcam.c b/drivers/media/video/omap24xxcam.c
index f85b2ed8a2d8..017552762902 100644
--- a/drivers/media/video/omap24xxcam.c
+++ b/drivers/media/video/omap24xxcam.c
@@ -420,13 +420,13 @@ static void omap24xxcam_vbq_release(struct videobuf_queue *vbq,
struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
/* wait for buffer, especially to get out of the sgdma queue */
- videobuf_waiton(vb, 0, 0);
+ videobuf_waiton(vbq, 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_unmap(vbq->dev, videobuf_to_dma(vb));
videobuf_dma_free(videobuf_to_dma(vb));
}
@@ -1198,7 +1198,7 @@ static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
atomic_inc(&cam->reset_disable);
- flush_scheduled_work();
+ flush_work_sync(&cam->sensor_reset_work);
rval = videobuf_streamoff(q);
if (!rval) {
@@ -1491,7 +1491,7 @@ static int omap24xxcam_open(struct file *file)
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);
+ sizeof(struct videobuf_buffer), fh, NULL);
return 0;
@@ -1512,7 +1512,7 @@ static int omap24xxcam_release(struct file *file)
atomic_inc(&cam->reset_disable);
- flush_scheduled_work();
+ flush_work_sync(&cam->sensor_reset_work);
/* stop streaming capture */
videobuf_streamoff(&fh->vbq);
@@ -1536,7 +1536,7 @@ static int omap24xxcam_release(struct file *file)
* not be scheduled anymore since streaming is already
* disabled.)
*/
- flush_scheduled_work();
+ flush_work_sync(&cam->sensor_reset_work);
mutex_lock(&cam->mutex);
if (atomic_dec_return(&cam->users) == 0) {
diff --git a/drivers/media/video/ov2640.c b/drivers/media/video/ov2640.c
new file mode 100644
index 000000000000..0cea0cf36679
--- /dev/null
+++ b/drivers/media/video/ov2640.c
@@ -0,0 +1,1205 @@
+/*
+ * ov2640 Camera Driver
+ *
+ * Copyright (C) 2010 Alberto Panizzo <maramaopercheseimorto@gmail.com>
+ *
+ * Based on ov772x, ov9640 drivers and previous non merged implementations.
+ *
+ * Copyright 2005-2009 Freescale Semiconductor, Inc. All Rights Reserved.
+ * Copyright (C) 2006, OmniVision
+ *
+ * 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/delay.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/v4l2-subdev.h>
+#include <media/soc_camera.h>
+#include <media/soc_mediabus.h>
+
+#define VAL_SET(x, mask, rshift, lshift) \
+ ((((x) >> rshift) & mask) << lshift)
+/*
+ * DSP registers
+ * register offset for BANK_SEL == BANK_SEL_DSP
+ */
+#define R_BYPASS 0x05 /* Bypass DSP */
+#define R_BYPASS_DSP_BYPAS 0x01 /* Bypass DSP, sensor out directly */
+#define R_BYPASS_USE_DSP 0x00 /* Use the internal DSP */
+#define QS 0x44 /* Quantization Scale Factor */
+#define CTRLI 0x50
+#define CTRLI_LP_DP 0x80
+#define CTRLI_ROUND 0x40
+#define CTRLI_V_DIV_SET(x) VAL_SET(x, 0x3, 0, 3)
+#define CTRLI_H_DIV_SET(x) VAL_SET(x, 0x3, 0, 0)
+#define HSIZE 0x51 /* H_SIZE[7:0] (real/4) */
+#define HSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define VSIZE 0x52 /* V_SIZE[7:0] (real/4) */
+#define VSIZE_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define XOFFL 0x53 /* OFFSET_X[7:0] */
+#define XOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)
+#define YOFFL 0x54 /* OFFSET_Y[7:0] */
+#define YOFFL_SET(x) VAL_SET(x, 0xFF, 0, 0)
+#define VHYX 0x55 /* Offset and size completion */
+#define VHYX_VSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 7)
+#define VHYX_HSIZE_SET(x) VAL_SET(x, 0x1, (8+2), 3)
+#define VHYX_YOFF_SET(x) VAL_SET(x, 0x3, 8, 4)
+#define VHYX_XOFF_SET(x) VAL_SET(x, 0x3, 8, 0)
+#define DPRP 0x56
+#define TEST 0x57 /* Horizontal size completion */
+#define TEST_HSIZE_SET(x) VAL_SET(x, 0x1, (9+2), 7)
+#define ZMOW 0x5A /* Zoom: Out Width OUTW[7:0] (real/4) */
+#define ZMOW_OUTW_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define ZMOH 0x5B /* Zoom: Out Height OUTH[7:0] (real/4) */
+#define ZMOH_OUTH_SET(x) VAL_SET(x, 0xFF, 2, 0)
+#define ZMHH 0x5C /* Zoom: Speed and H&W completion */
+#define ZMHH_ZSPEED_SET(x) VAL_SET(x, 0x0F, 0, 4)
+#define ZMHH_OUTH_SET(x) VAL_SET(x, 0x1, (8+2), 2)
+#define ZMHH_OUTW_SET(x) VAL_SET(x, 0x3, (8+2), 0)
+#define BPADDR 0x7C /* SDE Indirect Register Access: Address */
+#define BPDATA 0x7D /* SDE Indirect Register Access: Data */
+#define CTRL2 0x86 /* DSP Module enable 2 */
+#define CTRL2_DCW_EN 0x20
+#define CTRL2_SDE_EN 0x10
+#define CTRL2_UV_ADJ_EN 0x08
+#define CTRL2_UV_AVG_EN 0x04
+#define CTRL2_CMX_EN 0x01
+#define CTRL3 0x87 /* DSP Module enable 3 */
+#define CTRL3_BPC_EN 0x80
+#define CTRL3_WPC_EN 0x40
+#define SIZEL 0x8C /* Image Size Completion */
+#define SIZEL_HSIZE8_11_SET(x) VAL_SET(x, 0x1, 11, 6)
+#define SIZEL_HSIZE8_SET(x) VAL_SET(x, 0x7, 0, 3)
+#define SIZEL_VSIZE8_SET(x) VAL_SET(x, 0x7, 0, 0)
+#define HSIZE8 0xC0 /* Image Horizontal Size HSIZE[10:3] */
+#define HSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)
+#define VSIZE8 0xC1 /* Image Vertical Size VSIZE[10:3] */
+#define VSIZE8_SET(x) VAL_SET(x, 0xFF, 3, 0)
+#define CTRL0 0xC2 /* DSP Module enable 0 */
+#define CTRL0_AEC_EN 0x80
+#define CTRL0_AEC_SEL 0x40
+#define CTRL0_STAT_SEL 0x20
+#define CTRL0_VFIRST 0x10
+#define CTRL0_YUV422 0x08
+#define CTRL0_YUV_EN 0x04
+#define CTRL0_RGB_EN 0x02
+#define CTRL0_RAW_EN 0x01
+#define CTRL1 0xC3 /* DSP Module enable 1 */
+#define CTRL1_CIP 0x80
+#define CTRL1_DMY 0x40
+#define CTRL1_RAW_GMA 0x20
+#define CTRL1_DG 0x10
+#define CTRL1_AWB 0x08
+#define CTRL1_AWB_GAIN 0x04
+#define CTRL1_LENC 0x02
+#define CTRL1_PRE 0x01
+#define R_DVP_SP 0xD3 /* DVP output speed control */
+#define R_DVP_SP_AUTO_MODE 0x80
+#define R_DVP_SP_DVP_MASK 0x3F /* DVP PCLK = sysclk (48)/[6:0] (YUV0);
+ * = sysclk (48)/(2*[6:0]) (RAW);*/
+#define IMAGE_MODE 0xDA /* Image Output Format Select */
+#define IMAGE_MODE_Y8_DVP_EN 0x40
+#define IMAGE_MODE_JPEG_EN 0x10
+#define IMAGE_MODE_YUV422 0x00
+#define IMAGE_MODE_RAW10 0x04 /* (DVP) */
+#define IMAGE_MODE_RGB565 0x08
+#define IMAGE_MODE_HREF_VSYNC 0x02 /* HREF timing select in DVP JPEG output
+ * mode (0 for HREF is same as sensor) */
+#define IMAGE_MODE_LBYTE_FIRST 0x01 /* Byte swap enable for DVP
+ * 1: Low byte first UYVY (C2[4] =0)
+ * VYUY (C2[4] =1)
+ * 0: High byte first YUYV (C2[4]=0)
+ * YVYU (C2[4] = 1) */
+#define RESET 0xE0 /* Reset */
+#define RESET_MICROC 0x40
+#define RESET_SCCB 0x20
+#define RESET_JPEG 0x10
+#define RESET_DVP 0x04
+#define RESET_IPU 0x02
+#define RESET_CIF 0x01
+#define REGED 0xED /* Register ED */
+#define REGED_CLK_OUT_DIS 0x10
+#define MS_SP 0xF0 /* SCCB Master Speed */
+#define SS_ID 0xF7 /* SCCB Slave ID */
+#define SS_CTRL 0xF8 /* SCCB Slave Control */
+#define SS_CTRL_ADD_AUTO_INC 0x20
+#define SS_CTRL_EN 0x08
+#define SS_CTRL_DELAY_CLK 0x04
+#define SS_CTRL_ACC_EN 0x02
+#define SS_CTRL_SEN_PASS_THR 0x01
+#define MC_BIST 0xF9 /* Microcontroller misc register */
+#define MC_BIST_RESET 0x80 /* Microcontroller Reset */
+#define MC_BIST_BOOT_ROM_SEL 0x40
+#define MC_BIST_12KB_SEL 0x20
+#define MC_BIST_12KB_MASK 0x30
+#define MC_BIST_512KB_SEL 0x08
+#define MC_BIST_512KB_MASK 0x0C
+#define MC_BIST_BUSY_BIT_R 0x02
+#define MC_BIST_MC_RES_ONE_SH_W 0x02
+#define MC_BIST_LAUNCH 0x01
+#define BANK_SEL 0xFF /* Register Bank Select */
+#define BANK_SEL_DSP 0x00
+#define BANK_SEL_SENS 0x01
+
+/*
+ * Sensor registers
+ * register offset for BANK_SEL == BANK_SEL_SENS
+ */
+#define GAIN 0x00 /* AGC - Gain control gain setting */
+#define COM1 0x03 /* Common control 1 */
+#define COM1_1_DUMMY_FR 0x40
+#define COM1_3_DUMMY_FR 0x80
+#define COM1_7_DUMMY_FR 0xC0
+#define COM1_VWIN_LSB_UXGA 0x0F
+#define COM1_VWIN_LSB_SVGA 0x0A
+#define COM1_VWIN_LSB_CIF 0x06
+#define REG04 0x04 /* Register 04 */
+#define REG04_DEF 0x20 /* Always set */
+#define REG04_HFLIP_IMG 0x80 /* Horizontal mirror image ON/OFF */
+#define REG04_VFLIP_IMG 0x40 /* Vertical flip image ON/OFF */
+#define REG04_VREF_EN 0x10
+#define REG04_HREF_EN 0x08
+#define REG04_AEC_SET(x) VAL_SET(x, 0x3, 0, 0)
+#define REG08 0x08 /* Frame Exposure One-pin Control Pre-charge Row Num */
+#define COM2 0x09 /* Common control 2 */
+#define COM2_SOFT_SLEEP_MODE 0x10 /* Soft sleep mode */
+ /* Output drive capability */
+#define COM2_OCAP_Nx_SET(N) (((N) - 1) & 0x03) /* N = [1x .. 4x] */
+#define PID 0x0A /* Product ID Number MSB */
+#define VER 0x0B /* Product ID Number LSB */
+#define COM3 0x0C /* Common control 3 */
+#define COM3_BAND_50H 0x04 /* 0 For Banding at 60H */
+#define COM3_BAND_AUTO 0x02 /* Auto Banding */
+#define COM3_SING_FR_SNAPSH 0x01 /* 0 For enable live video output after the
+ * snapshot sequence*/
+#define AEC 0x10 /* AEC[9:2] Exposure Value */
+#define CLKRC 0x11 /* Internal clock */
+#define CLKRC_EN 0x80
+#define CLKRC_DIV_SET(x) (((x) - 1) & 0x1F) /* CLK = XVCLK/(x) */
+#define COM7 0x12 /* Common control 7 */
+#define COM7_SRST 0x80 /* Initiates system reset. All registers are
+ * set to factory default values after which
+ * the chip resumes normal operation */
+#define COM7_RES_UXGA 0x00 /* Resolution selectors for UXGA */
+#define COM7_RES_SVGA 0x40 /* SVGA */
+#define COM7_RES_CIF 0x20 /* CIF */
+#define COM7_ZOOM_EN 0x04 /* Enable Zoom mode */
+#define COM7_COLOR_BAR_TEST 0x02 /* Enable Color Bar Test Pattern */
+#define COM8 0x13 /* Common control 8 */
+#define COM8_DEF 0xC0 /* Banding filter ON/OFF */
+#define COM8_BNDF_EN 0x20 /* Banding filter ON/OFF */
+#define COM8_AGC_EN 0x04 /* AGC Auto/Manual control selection */
+#define COM8_AEC_EN 0x01 /* Auto/Manual Exposure control */
+#define COM9 0x14 /* Common control 9
+ * Automatic gain ceiling - maximum AGC value [7:5]*/
+#define COM9_AGC_GAIN_2x 0x00 /* 000 : 2x */
+#define COM9_AGC_GAIN_4x 0x20 /* 001 : 4x */
+#define COM9_AGC_GAIN_8x 0x40 /* 010 : 8x */
+#define COM9_AGC_GAIN_16x 0x60 /* 011 : 16x */
+#define COM9_AGC_GAIN_32x 0x80 /* 100 : 32x */
+#define COM9_AGC_GAIN_64x 0xA0 /* 101 : 64x */
+#define COM9_AGC_GAIN_128x 0xC0 /* 110 : 128x */
+#define COM10 0x15 /* Common control 10 */
+#define COM10_PCLK_HREF 0x20 /* PCLK output qualified by HREF */
+#define COM10_PCLK_RISE 0x10 /* Data is updated at the rising edge of
+ * PCLK (user can latch data at the next
+ * falling edge of PCLK).
+ * 0 otherwise. */
+#define COM10_HREF_INV 0x08 /* Invert HREF polarity:
+ * HREF negative for valid data*/
+#define COM10_VSINC_INV 0x02 /* Invert VSYNC polarity */
+#define HSTART 0x17 /* Horizontal Window start MSB 8 bit */
+#define HEND 0x18 /* Horizontal Window end MSB 8 bit */
+#define VSTART 0x19 /* Vertical Window start MSB 8 bit */
+#define VEND 0x1A /* Vertical Window end MSB 8 bit */
+#define MIDH 0x1C /* Manufacturer ID byte - high */
+#define MIDL 0x1D /* Manufacturer ID byte - low */
+#define AEW 0x24 /* AGC/AEC - Stable operating region (upper limit) */
+#define AEB 0x25 /* AGC/AEC - Stable operating region (lower limit) */
+#define VV 0x26 /* AGC/AEC Fast mode operating region */
+#define VV_HIGH_TH_SET(x) VAL_SET(x, 0xF, 0, 4)
+#define VV_LOW_TH_SET(x) VAL_SET(x, 0xF, 0, 0)
+#define REG2A 0x2A /* Dummy pixel insert MSB */
+#define FRARL 0x2B /* Dummy pixel insert LSB */
+#define ADDVFL 0x2D /* LSB of insert dummy lines in Vertical direction */
+#define ADDVFH 0x2E /* MSB of insert dummy lines in Vertical direction */
+#define YAVG 0x2F /* Y/G Channel Average value */
+#define REG32 0x32 /* Common Control 32 */
+#define REG32_PCLK_DIV_2 0x80 /* PCLK freq divided by 2 */
+#define REG32_PCLK_DIV_4 0xC0 /* PCLK freq divided by 4 */
+#define ARCOM2 0x34 /* Zoom: Horizontal start point */
+#define REG45 0x45 /* Register 45 */
+#define FLL 0x46 /* Frame Length Adjustment LSBs */
+#define FLH 0x47 /* Frame Length Adjustment MSBs */
+#define COM19 0x48 /* Zoom: Vertical start point */
+#define ZOOMS 0x49 /* Zoom: Vertical start point */
+#define COM22 0x4B /* Flash light control */
+#define COM25 0x4E /* For Banding operations */
+#define BD50 0x4F /* 50Hz Banding AEC 8 LSBs */
+#define BD60 0x50 /* 60Hz Banding AEC 8 LSBs */
+#define REG5D 0x5D /* AVGsel[7:0], 16-zone average weight option */
+#define REG5E 0x5E /* AVGsel[15:8], 16-zone average weight option */
+#define REG5F 0x5F /* AVGsel[23:16], 16-zone average weight option */
+#define REG60 0x60 /* AVGsel[31:24], 16-zone average weight option */
+#define HISTO_LOW 0x61 /* Histogram Algorithm Low Level */
+#define HISTO_HIGH 0x62 /* Histogram Algorithm High Level */
+
+/*
+ * ID
+ */
+#define MANUFACTURER_ID 0x7FA2
+#define PID_OV2640 0x2642
+#define VERSION(pid, ver) ((pid << 8) | (ver & 0xFF))
+
+/*
+ * Struct
+ */
+struct regval_list {
+ u8 reg_num;
+ u8 value;
+};
+
+/* Supported resolutions */
+enum ov2640_width {
+ W_QCIF = 176,
+ W_QVGA = 320,
+ W_CIF = 352,
+ W_VGA = 640,
+ W_SVGA = 800,
+ W_XGA = 1024,
+ W_SXGA = 1280,
+ W_UXGA = 1600,
+};
+
+enum ov2640_height {
+ H_QCIF = 144,
+ H_QVGA = 240,
+ H_CIF = 288,
+ H_VGA = 480,
+ H_SVGA = 600,
+ H_XGA = 768,
+ H_SXGA = 1024,
+ H_UXGA = 1200,
+};
+
+struct ov2640_win_size {
+ char *name;
+ enum ov2640_width width;
+ enum ov2640_height height;
+ const struct regval_list *regs;
+};
+
+
+struct ov2640_priv {
+ struct v4l2_subdev subdev;
+ struct ov2640_camera_info *info;
+ enum v4l2_mbus_pixelcode cfmt_code;
+ const struct ov2640_win_size *win;
+ int model;
+ u16 flag_vflip:1;
+ u16 flag_hflip:1;
+};
+
+/*
+ * Registers settings
+ */
+
+#define ENDMARKER { 0xff, 0xff }
+
+static const struct regval_list ov2640_init_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { 0x2c, 0xff },
+ { 0x2e, 0xdf },
+ { BANK_SEL, BANK_SEL_SENS },
+ { 0x3c, 0x32 },
+ { CLKRC, CLKRC_DIV_SET(1) },
+ { COM2, COM2_OCAP_Nx_SET(3) },
+ { REG04, REG04_DEF | REG04_HREF_EN },
+ { COM8, COM8_DEF | COM8_BNDF_EN | COM8_AGC_EN | COM8_AEC_EN },
+ { COM9, COM9_AGC_GAIN_8x | 0x08},
+ { 0x2c, 0x0c },
+ { 0x33, 0x78 },
+ { 0x3a, 0x33 },
+ { 0x3b, 0xfb },
+ { 0x3e, 0x00 },
+ { 0x43, 0x11 },
+ { 0x16, 0x10 },
+ { 0x39, 0x02 },
+ { 0x35, 0x88 },
+ { 0x22, 0x0a },
+ { 0x37, 0x40 },
+ { 0x23, 0x00 },
+ { ARCOM2, 0xa0 },
+ { 0x06, 0x02 },
+ { 0x06, 0x88 },
+ { 0x07, 0xc0 },
+ { 0x0d, 0xb7 },
+ { 0x0e, 0x01 },
+ { 0x4c, 0x00 },
+ { 0x4a, 0x81 },
+ { 0x21, 0x99 },
+ { AEW, 0x40 },
+ { AEB, 0x38 },
+ { VV, VV_HIGH_TH_SET(0x08) | VV_LOW_TH_SET(0x02) },
+ { 0x5c, 0x00 },
+ { 0x63, 0x00 },
+ { FLL, 0x22 },
+ { COM3, 0x38 | COM3_BAND_AUTO },
+ { REG5D, 0x55 },
+ { REG5E, 0x7d },
+ { REG5F, 0x7d },
+ { REG60, 0x55 },
+ { HISTO_LOW, 0x70 },
+ { HISTO_HIGH, 0x80 },
+ { 0x7c, 0x05 },
+ { 0x20, 0x80 },
+ { 0x28, 0x30 },
+ { 0x6c, 0x00 },
+ { 0x6d, 0x80 },
+ { 0x6e, 0x00 },
+ { 0x70, 0x02 },
+ { 0x71, 0x94 },
+ { 0x73, 0xc1 },
+ { 0x3d, 0x34 },
+ { COM7, COM7_RES_UXGA | COM7_ZOOM_EN },
+ { 0x5a, 0x57 },
+ { BD50, 0xbb },
+ { BD60, 0x9c },
+ { BANK_SEL, BANK_SEL_DSP },
+ { 0xe5, 0x7f },
+ { MC_BIST, MC_BIST_RESET | MC_BIST_BOOT_ROM_SEL },
+ { 0x41, 0x24 },
+ { RESET, RESET_JPEG | RESET_DVP },
+ { 0x76, 0xff },
+ { 0x33, 0xa0 },
+ { 0x42, 0x20 },
+ { 0x43, 0x18 },
+ { 0x4c, 0x00 },
+ { CTRL3, CTRL3_BPC_EN | CTRL3_WPC_EN | 0x10 },
+ { 0x88, 0x3f },
+ { 0xd7, 0x03 },
+ { 0xd9, 0x10 },
+ { R_DVP_SP , R_DVP_SP_AUTO_MODE | 0x2 },
+ { 0xc8, 0x08 },
+ { 0xc9, 0x80 },
+ { BPADDR, 0x00 },
+ { BPDATA, 0x00 },
+ { BPADDR, 0x03 },
+ { BPDATA, 0x48 },
+ { BPDATA, 0x48 },
+ { BPADDR, 0x08 },
+ { BPDATA, 0x20 },
+ { BPDATA, 0x10 },
+ { BPDATA, 0x0e },
+ { 0x90, 0x00 },
+ { 0x91, 0x0e },
+ { 0x91, 0x1a },
+ { 0x91, 0x31 },
+ { 0x91, 0x5a },
+ { 0x91, 0x69 },
+ { 0x91, 0x75 },
+ { 0x91, 0x7e },
+ { 0x91, 0x88 },
+ { 0x91, 0x8f },
+ { 0x91, 0x96 },
+ { 0x91, 0xa3 },
+ { 0x91, 0xaf },
+ { 0x91, 0xc4 },
+ { 0x91, 0xd7 },
+ { 0x91, 0xe8 },
+ { 0x91, 0x20 },
+ { 0x92, 0x00 },
+ { 0x93, 0x06 },
+ { 0x93, 0xe3 },
+ { 0x93, 0x03 },
+ { 0x93, 0x03 },
+ { 0x93, 0x00 },
+ { 0x93, 0x02 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x93, 0x00 },
+ { 0x96, 0x00 },
+ { 0x97, 0x08 },
+ { 0x97, 0x19 },
+ { 0x97, 0x02 },
+ { 0x97, 0x0c },
+ { 0x97, 0x24 },
+ { 0x97, 0x30 },
+ { 0x97, 0x28 },
+ { 0x97, 0x26 },
+ { 0x97, 0x02 },
+ { 0x97, 0x98 },
+ { 0x97, 0x80 },
+ { 0x97, 0x00 },
+ { 0x97, 0x00 },
+ { 0xa4, 0x00 },
+ { 0xa8, 0x00 },
+ { 0xc5, 0x11 },
+ { 0xc6, 0x51 },
+ { 0xbf, 0x80 },
+ { 0xc7, 0x10 },
+ { 0xb6, 0x66 },
+ { 0xb8, 0xA5 },
+ { 0xb7, 0x64 },
+ { 0xb9, 0x7C },
+ { 0xb3, 0xaf },
+ { 0xb4, 0x97 },
+ { 0xb5, 0xFF },
+ { 0xb0, 0xC5 },
+ { 0xb1, 0x94 },
+ { 0xb2, 0x0f },
+ { 0xc4, 0x5c },
+ { 0xa6, 0x00 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x1b },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x19 },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0xa7, 0x20 },
+ { 0xa7, 0xd8 },
+ { 0xa7, 0x19 },
+ { 0xa7, 0x31 },
+ { 0xa7, 0x00 },
+ { 0xa7, 0x18 },
+ { 0x7f, 0x00 },
+ { 0xe5, 0x1f },
+ { 0xe1, 0x77 },
+ { 0xdd, 0x7f },
+ { CTRL0, CTRL0_YUV422 | CTRL0_YUV_EN | CTRL0_RGB_EN },
+ ENDMARKER,
+};
+
+/*
+ * Register settings for window size
+ * The preamble, setup the internal DSP to input an UXGA (1600x1200) image.
+ * Then the different zooming configurations will setup the output image size.
+ */
+static const struct regval_list ov2640_size_change_preamble_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { RESET, RESET_DVP },
+ { HSIZE8, HSIZE8_SET(W_UXGA) },
+ { VSIZE8, VSIZE8_SET(H_UXGA) },
+ { CTRL2, CTRL2_DCW_EN | CTRL2_SDE_EN |
+ CTRL2_UV_AVG_EN | CTRL2_CMX_EN | CTRL2_UV_ADJ_EN },
+ { HSIZE, HSIZE_SET(W_UXGA) },
+ { VSIZE, VSIZE_SET(H_UXGA) },
+ { XOFFL, XOFFL_SET(0) },
+ { YOFFL, YOFFL_SET(0) },
+ { VHYX, VHYX_HSIZE_SET(W_UXGA) | VHYX_VSIZE_SET(H_UXGA) |
+ VHYX_XOFF_SET(0) | VHYX_YOFF_SET(0)},
+ { TEST, TEST_HSIZE_SET(W_UXGA) },
+ ENDMARKER,
+};
+
+#define PER_SIZE_REG_SEQ(x, y, v_div, h_div, pclk_div) \
+ { CTRLI, CTRLI_LP_DP | CTRLI_V_DIV_SET(v_div) | \
+ CTRLI_H_DIV_SET(h_div)}, \
+ { ZMOW, ZMOW_OUTW_SET(x) }, \
+ { ZMOH, ZMOH_OUTH_SET(y) }, \
+ { ZMHH, ZMHH_OUTW_SET(x) | ZMHH_OUTH_SET(y) }, \
+ { R_DVP_SP, pclk_div }, \
+ { RESET, 0x00}
+
+static const struct regval_list ov2640_qcif_regs[] = {
+ PER_SIZE_REG_SEQ(W_QCIF, H_QCIF, 3, 3, 4),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_qvga_regs[] = {
+ PER_SIZE_REG_SEQ(W_QVGA, H_QVGA, 2, 2, 4),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_cif_regs[] = {
+ PER_SIZE_REG_SEQ(W_CIF, H_CIF, 2, 2, 8),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_vga_regs[] = {
+ PER_SIZE_REG_SEQ(W_VGA, H_VGA, 0, 0, 2),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_svga_regs[] = {
+ PER_SIZE_REG_SEQ(W_SVGA, H_SVGA, 1, 1, 2),
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_xga_regs[] = {
+ PER_SIZE_REG_SEQ(W_XGA, H_XGA, 0, 0, 2),
+ { CTRLI, 0x00},
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_sxga_regs[] = {
+ PER_SIZE_REG_SEQ(W_SXGA, H_SXGA, 0, 0, 2),
+ { CTRLI, 0x00},
+ { R_DVP_SP, 2 | R_DVP_SP_AUTO_MODE },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_uxga_regs[] = {
+ PER_SIZE_REG_SEQ(W_UXGA, H_UXGA, 0, 0, 0),
+ { CTRLI, 0x00},
+ { R_DVP_SP, 0 | R_DVP_SP_AUTO_MODE },
+ ENDMARKER,
+};
+
+#define OV2640_SIZE(n, w, h, r) \
+ {.name = n, .width = w , .height = h, .regs = r }
+
+static const struct ov2640_win_size ov2640_supported_win_sizes[] = {
+ OV2640_SIZE("QCIF", W_QCIF, H_QCIF, ov2640_qcif_regs),
+ OV2640_SIZE("QVGA", W_QVGA, H_QVGA, ov2640_qvga_regs),
+ OV2640_SIZE("CIF", W_CIF, H_CIF, ov2640_cif_regs),
+ OV2640_SIZE("VGA", W_VGA, H_VGA, ov2640_vga_regs),
+ OV2640_SIZE("SVGA", W_SVGA, H_SVGA, ov2640_svga_regs),
+ OV2640_SIZE("XGA", W_XGA, H_XGA, ov2640_xga_regs),
+ OV2640_SIZE("SXGA", W_SXGA, H_SXGA, ov2640_sxga_regs),
+ OV2640_SIZE("UXGA", W_UXGA, H_UXGA, ov2640_uxga_regs),
+};
+
+/*
+ * Register settings for pixel formats
+ */
+static const struct regval_list ov2640_format_change_preamble_regs[] = {
+ { BANK_SEL, BANK_SEL_DSP },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_yuv422_regs[] = {
+ { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_YUV422 },
+ { 0xD7, 0x01 },
+ { 0x33, 0xa0 },
+ { 0xe1, 0x67 },
+ { RESET, 0x00 },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static const struct regval_list ov2640_rgb565_regs[] = {
+ { IMAGE_MODE, IMAGE_MODE_LBYTE_FIRST | IMAGE_MODE_RGB565 },
+ { 0xd7, 0x03 },
+ { RESET, 0x00 },
+ { R_BYPASS, R_BYPASS_USE_DSP },
+ ENDMARKER,
+};
+
+static enum v4l2_mbus_pixelcode ov2640_codes[] = {
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_RGB565_2X8_LE,
+};
+
+/*
+ * Supported controls
+ */
+static const struct v4l2_queryctrl ov2640_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_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Horizontally",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+/*
+ * General functions
+ */
+static struct ov2640_priv *to_ov2640(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov2640_priv,
+ subdev);
+}
+
+static int ov2640_write_array(struct i2c_client *client,
+ const struct regval_list *vals)
+{
+ int ret;
+
+ while ((vals->reg_num != 0xff) || (vals->value != 0xff)) {
+ ret = i2c_smbus_write_byte_data(client,
+ vals->reg_num, vals->value);
+ dev_vdbg(&client->dev, "array: 0x%02x, 0x%02x",
+ vals->reg_num, vals->value);
+
+ if (ret < 0)
+ return ret;
+ vals++;
+ }
+ return 0;
+}
+
+static int ov2640_mask_set(struct i2c_client *client,
+ u8 reg, u8 mask, u8 set)
+{
+ s32 val = i2c_smbus_read_byte_data(client, reg);
+ if (val < 0)
+ return val;
+
+ val &= ~mask;
+ val |= set & mask;
+
+ dev_vdbg(&client->dev, "masks: 0x%02x, 0x%02x", reg, val);
+
+ return i2c_smbus_write_byte_data(client, reg, val);
+}
+
+static int ov2640_reset(struct i2c_client *client)
+{
+ int ret;
+ const struct regval_list reset_seq[] = {
+ {BANK_SEL, BANK_SEL_SENS},
+ {COM7, COM7_SRST},
+ ENDMARKER,
+ };
+
+ ret = ov2640_write_array(client, reset_seq);
+ if (ret)
+ goto err;
+
+ msleep(5);
+err:
+ dev_dbg(&client->dev, "%s: (ret %d)", __func__, ret);
+ return ret;
+}
+
+/*
+ * soc_camera_ops functions
+ */
+static int ov2640_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ return 0;
+}
+
+static int ov2640_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ unsigned long width_flag = flags & SOCAM_DATAWIDTH_MASK;
+
+ /* Only one width bit may be set */
+ if (!is_power_of_2(width_flag))
+ return -EINVAL;
+
+ if (icl->set_bus_param)
+ return icl->set_bus_param(icl, width_flag);
+
+ /*
+ * Without board specific bus width settings we support only the
+ * sensors native bus width witch are tested working
+ */
+ if (width_flag & (SOCAM_DATAWIDTH_10 | SOCAM_DATAWIDTH_8))
+ return 0;
+
+ return 0;
+}
+
+static unsigned long ov2640_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ unsigned long flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_MASTER |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_DATA_ACTIVE_HIGH;
+
+ if (icl->query_bus_param)
+ flags |= icl->query_bus_param(icl) & SOCAM_DATAWIDTH_MASK;
+ else
+ flags |= SOCAM_DATAWIDTH_10;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int ov2640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ ctrl->value = priv->flag_vflip;
+ break;
+ case V4L2_CID_HFLIP:
+ ctrl->value = priv->flag_hflip;
+ break;
+ }
+ return 0;
+}
+
+static int ov2640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+ int ret = 0;
+ u8 val;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ val = ctrl->value ? REG04_VFLIP_IMG : 0x00;
+ priv->flag_vflip = ctrl->value ? 1 : 0;
+ ret = ov2640_mask_set(client, REG04, REG04_VFLIP_IMG, val);
+ break;
+ case V4L2_CID_HFLIP:
+ val = ctrl->value ? REG04_HFLIP_IMG : 0x00;
+ priv->flag_hflip = ctrl->value ? 1 : 0;
+ ret = ov2640_mask_set(client, REG04, REG04_HFLIP_IMG, val);
+ break;
+ }
+
+ return ret;
+}
+
+static int ov2640_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ id->ident = priv->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov2640_g_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+ reg->size = 1;
+ if (reg->reg > 0xff)
+ return -EINVAL;
+
+ ret = i2c_smbus_read_byte_data(client, reg->reg);
+ if (ret < 0)
+ return ret;
+
+ reg->val = ret;
+
+ return 0;
+}
+
+static int ov2640_s_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg > 0xff ||
+ reg->val > 0xff)
+ return -EINVAL;
+
+ return i2c_smbus_write_byte_data(client, reg->reg, reg->val);
+}
+#endif
+
+/* Select the nearest higher resolution for capture */
+static const struct ov2640_win_size *ov2640_select_win(u32 *width, u32 *height)
+{
+ int i, default_size = ARRAY_SIZE(ov2640_supported_win_sizes) - 1;
+
+ for (i = 0; i < ARRAY_SIZE(ov2640_supported_win_sizes); i++) {
+ if (ov2640_supported_win_sizes[i].width >= *width &&
+ ov2640_supported_win_sizes[i].height >= *height) {
+ *width = ov2640_supported_win_sizes[i].width;
+ *height = ov2640_supported_win_sizes[i].height;
+ return &ov2640_supported_win_sizes[i];
+ }
+ }
+
+ *width = ov2640_supported_win_sizes[default_size].width;
+ *height = ov2640_supported_win_sizes[default_size].height;
+ return &ov2640_supported_win_sizes[default_size];
+}
+
+static int ov2640_set_params(struct i2c_client *client, u32 *width, u32 *height,
+ enum v4l2_mbus_pixelcode code)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+ const struct regval_list *selected_cfmt_regs;
+ int ret;
+
+ /* select win */
+ priv->win = ov2640_select_win(width, height);
+
+ /* select format */
+ priv->cfmt_code = 0;
+ switch (code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ dev_dbg(&client->dev, "%s: Selected cfmt RGB565", __func__);
+ selected_cfmt_regs = ov2640_rgb565_regs;
+ break;
+ default:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ dev_dbg(&client->dev, "%s: Selected cfmt YUV422", __func__);
+ selected_cfmt_regs = ov2640_yuv422_regs;
+ }
+
+ /* reset hardware */
+ ov2640_reset(client);
+
+ /* initialize the sensor with default data */
+ dev_dbg(&client->dev, "%s: Init default", __func__);
+ ret = ov2640_write_array(client, ov2640_init_regs);
+ if (ret < 0)
+ goto err;
+
+ /* select preamble */
+ dev_dbg(&client->dev, "%s: Set size to %s", __func__, priv->win->name);
+ ret = ov2640_write_array(client, ov2640_size_change_preamble_regs);
+ if (ret < 0)
+ goto err;
+
+ /* set size win */
+ ret = ov2640_write_array(client, priv->win->regs);
+ if (ret < 0)
+ goto err;
+
+ /* cfmt preamble */
+ dev_dbg(&client->dev, "%s: Set cfmt", __func__);
+ ret = ov2640_write_array(client, ov2640_format_change_preamble_regs);
+ if (ret < 0)
+ goto err;
+
+ /* set cfmt */
+ ret = ov2640_write_array(client, selected_cfmt_regs);
+ if (ret < 0)
+ goto err;
+
+ priv->cfmt_code = code;
+ *width = priv->win->width;
+ *height = priv->win->height;
+
+ return 0;
+
+err:
+ dev_err(&client->dev, "%s: Error %d", __func__, ret);
+ ov2640_reset(client);
+ priv->win = NULL;
+
+ return ret;
+}
+
+static int ov2640_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov2640_priv *priv = to_ov2640(client);
+
+ if (!priv->win) {
+ u32 width = W_SVGA, height = H_SVGA;
+ int ret = ov2640_set_params(client, &width, &height,
+ V4L2_MBUS_FMT_UYVY8_2X8);
+ if (ret < 0)
+ return ret;
+ }
+
+ mf->width = priv->win->width;
+ mf->height = priv->win->height;
+ mf->code = priv->cfmt_code;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static int ov2640_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+
+ ret = ov2640_set_params(client, &mf->width, &mf->height, mf->code);
+
+ return ret;
+}
+
+static int ov2640_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ const struct ov2640_win_size *win;
+
+ /*
+ * select suitable win
+ */
+ win = ov2640_select_win(&mf->width, &mf->height);
+
+ mf->field = V4L2_FIELD_NONE;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_RGB565_2X8_LE:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ }
+
+ return 0;
+}
+
+static int ov2640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov2640_codes))
+ return -EINVAL;
+
+ *code = ov2640_codes[index];
+ return 0;
+}
+
+static int ov2640_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = W_UXGA;
+ a->c.height = H_UXGA;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int ov2640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = W_UXGA;
+ a->bounds.height = H_UXGA;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov2640_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+ u8 pid, ver, midh, midl;
+ const char *devname;
+ 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) {
+ dev_err(&client->dev, "Parent missing or invalid!\n");
+ ret = -ENODEV;
+ goto err;
+ }
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+ i2c_smbus_write_byte_data(client, BANK_SEL, BANK_SEL_SENS);
+ pid = i2c_smbus_read_byte_data(client, PID);
+ ver = i2c_smbus_read_byte_data(client, VER);
+ midh = i2c_smbus_read_byte_data(client, MIDH);
+ midl = i2c_smbus_read_byte_data(client, MIDL);
+
+ switch (VERSION(pid, ver)) {
+ case PID_OV2640:
+ devname = "ov2640";
+ priv->model = V4L2_IDENT_OV2640;
+ break;
+ default:
+ dev_err(&client->dev,
+ "Product ID error %x:%x\n", pid, ver);
+ ret = -ENODEV;
+ goto err;
+ }
+
+ dev_info(&client->dev,
+ "%s Product ID %0x:%0x Manufacturer ID %x:%x\n",
+ devname, pid, ver, midh, midl);
+
+ return 0;
+
+err:
+ return ret;
+}
+
+static struct soc_camera_ops ov2640_ops = {
+ .set_bus_param = ov2640_set_bus_param,
+ .query_bus_param = ov2640_query_bus_param,
+ .controls = ov2640_controls,
+ .num_controls = ARRAY_SIZE(ov2640_controls),
+};
+
+static struct v4l2_subdev_core_ops ov2640_subdev_core_ops = {
+ .g_ctrl = ov2640_g_ctrl,
+ .s_ctrl = ov2640_s_ctrl,
+ .g_chip_ident = ov2640_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov2640_g_register,
+ .s_register = ov2640_s_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops ov2640_subdev_video_ops = {
+ .s_stream = ov2640_s_stream,
+ .g_mbus_fmt = ov2640_g_fmt,
+ .s_mbus_fmt = ov2640_s_fmt,
+ .try_mbus_fmt = ov2640_try_fmt,
+ .cropcap = ov2640_cropcap,
+ .g_crop = ov2640_g_crop,
+ .enum_mbus_fmt = ov2640_enum_fmt,
+};
+
+static struct v4l2_subdev_ops ov2640_subdev_ops = {
+ .core = &ov2640_subdev_core_ops,
+ .video = &ov2640_subdev_video_ops,
+};
+
+/*
+ * i2c_driver functions
+ */
+static int ov2640_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov2640_priv *priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl;
+ int ret;
+
+ if (!icd) {
+ dev_err(&adapter->dev, "OV2640: missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
+ if (!icl) {
+ dev_err(&adapter->dev,
+ "OV2640: Missing platform_data for driver\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_BYTE_DATA)) {
+ dev_err(&adapter->dev,
+ "OV2640: I2C-Adapter doesn't support SMBUS\n");
+ return -EIO;
+ }
+
+ priv = kzalloc(sizeof(struct ov2640_priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&adapter->dev,
+ "Failed to allocate memory for private data!\n");
+ return -ENOMEM;
+ }
+
+ priv->info = icl->priv;
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov2640_subdev_ops);
+
+ icd->ops = &ov2640_ops;
+
+ ret = ov2640_video_probe(icd, client);
+ if (ret) {
+ icd->ops = NULL;
+ kfree(priv);
+ } else {
+ dev_info(&adapter->dev, "OV2640 Probed\n");
+ }
+
+ return ret;
+}
+
+static int ov2640_remove(struct i2c_client *client)
+{
+ struct ov2640_priv *priv = to_ov2640(client);
+ struct soc_camera_device *icd = client->dev.platform_data;
+
+ icd->ops = NULL;
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id ov2640_id[] = {
+ { "ov2640", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov2640_id);
+
+static struct i2c_driver ov2640_i2c_driver = {
+ .driver = {
+ .name = "ov2640",
+ },
+ .probe = ov2640_probe,
+ .remove = ov2640_remove,
+ .id_table = ov2640_id,
+};
+
+/*
+ * Module functions
+ */
+static int __init ov2640_module_init(void)
+{
+ return i2c_add_driver(&ov2640_i2c_driver);
+}
+
+static void __exit ov2640_module_exit(void)
+{
+ i2c_del_driver(&ov2640_i2c_driver);
+}
+
+module_init(ov2640_module_init);
+module_exit(ov2640_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for Omni Vision 2640 sensor");
+MODULE_AUTHOR("Alberto Panizzo");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
deleted file mode 100644
index a10912097b7a..000000000000
--- a/drivers/media/video/ov511.c
+++ /dev/null
@@ -1,5995 +0,0 @@
-/*
- * OmniVision OV511 Camera-to-USB Bridge Driver
- *
- * Copyright (c) 1999-2003 Mark W. McClelland
- * Original decompression code Copyright 1998-2000 OmniVision Technologies
- * Many improvements by Bret Wallach <bwallac1@san.rr.com>
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- * Snapshot code by Kevin Moore
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- * Changes by Claudio Matsuoka <claudio@conectiva.com>
- * Original SAA7111A code by Dave Perks <dperks@ibm.net>
- * URB error messages from pwc driver by Nemosoft
- * generic_ioctl() code from videodev.c by Gerd Knorr and Alan Cox
- * Memory management (rvmalloc) code from bttv driver, by Gerd Knorr and others
- *
- * Based on the Linux CPiA driver written by Peter Pregler,
- * Scott J. Bertin and Johannes Erdfelt.
- *
- * Please see the file: Documentation/usb/ov511.txt
- * and the website at: http://alpha.dyndns.org/ov511
- * for more info.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/ctype.h>
-#include <linux/pagemap.h>
-#include <asm/processor.h>
-#include <linux/mm.h>
-#include <linux/device.h>
-
-#if defined (__i386__)
- #include <asm/cpufeature.h>
-#endif
-
-#include "ov511.h"
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v1.64 for Linux 2.5"
-#define EMAIL "mark@alpha.dyndns.org"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org> & Bret Wallach \
-& Orion Sky Lawlor <olawlor@acm.org> & Kevin Moore & Charl P. Botha \
-<cpbotha@ieee.org> & Claudio Matsuoka <claudio@conectiva.com>"
-#define DRIVER_DESC "ov511 USB Camera Driver"
-
-#define OV511_I2C_RETRIES 3
-#define ENABLE_Y_QUANTABLE 1
-#define ENABLE_UV_QUANTABLE 1
-
-#define OV511_MAX_UNIT_VIDEO 16
-
-/* Pixel count * bytes per YUV420 pixel (1.5) */
-#define MAX_FRAME_SIZE(w, h) ((w) * (h) * 3 / 2)
-
-#define MAX_DATA_SIZE(w, h) (MAX_FRAME_SIZE(w, h) + sizeof(struct timeval))
-
-/* Max size * bytes per YUV420 pixel (1.5) + one extra isoc frame for safety */
-#define MAX_RAW_DATA_SIZE(w, h) ((w) * (h) * 3 / 2 + 1024)
-
-#define FATAL_ERROR(rc) ((rc) < 0 && (rc) != -EPERM)
-
-/**********************************************************************
- * Module Parameters
- * (See ov511.txt for detailed descriptions of these)
- **********************************************************************/
-
-/* These variables (and all static globals) default to zero */
-static int autobright = 1;
-static int autogain = 1;
-static int autoexp = 1;
-static int debug;
-static int snapshot;
-static int cams = 1;
-static int compress;
-static int testpat;
-static int dumppix;
-static int led = 1;
-static int dump_bridge;
-static int dump_sensor;
-static int printph;
-static int phy = 0x1f;
-static int phuv = 0x05;
-static int pvy = 0x06;
-static int pvuv = 0x06;
-static int qhy = 0x14;
-static int qhuv = 0x03;
-static int qvy = 0x04;
-static int qvuv = 0x04;
-static int lightfreq;
-static int bandingfilter;
-static int clockdiv = -1;
-static int packetsize = -1;
-static int framedrop = -1;
-static int fastset;
-static int force_palette;
-static int backlight;
-/* Bitmask marking allocated devices from 0 to OV511_MAX_UNIT_VIDEO */
-static unsigned long ov511_devused;
-static int unit_video[OV511_MAX_UNIT_VIDEO];
-static int remove_zeros;
-static int mirror;
-static int ov518_color;
-
-module_param(autobright, int, 0);
-MODULE_PARM_DESC(autobright, "Sensor automatically changes brightness");
-module_param(autogain, int, 0);
-MODULE_PARM_DESC(autogain, "Sensor automatically changes gain");
-module_param(autoexp, int, 0);
-MODULE_PARM_DESC(autoexp, "Sensor automatically changes exposure");
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
- "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=max");
-module_param(snapshot, int, 0);
-MODULE_PARM_DESC(snapshot, "Enable snapshot mode");
-module_param(cams, int, 0);
-MODULE_PARM_DESC(cams, "Number of simultaneous cameras");
-module_param(compress, int, 0);
-MODULE_PARM_DESC(compress, "Turn on compression");
-module_param(testpat, int, 0);
-MODULE_PARM_DESC(testpat,
- "Replace image with vertical bar testpattern (only partially working)");
-module_param(dumppix, int, 0);
-MODULE_PARM_DESC(dumppix, "Dump raw pixel data");
-module_param(led, int, 0);
-MODULE_PARM_DESC(led,
- "LED policy (OV511+ or later). 0=off, 1=on (default), 2=auto (on when open)");
-module_param(dump_bridge, int, 0);
-MODULE_PARM_DESC(dump_bridge, "Dump the bridge registers");
-module_param(dump_sensor, int, 0);
-MODULE_PARM_DESC(dump_sensor, "Dump the sensor registers");
-module_param(printph, int, 0);
-MODULE_PARM_DESC(printph, "Print frame start/end headers");
-module_param(phy, int, 0);
-MODULE_PARM_DESC(phy, "Prediction range (horiz. Y)");
-module_param(phuv, int, 0);
-MODULE_PARM_DESC(phuv, "Prediction range (horiz. UV)");
-module_param(pvy, int, 0);
-MODULE_PARM_DESC(pvy, "Prediction range (vert. Y)");
-module_param(pvuv, int, 0);
-MODULE_PARM_DESC(pvuv, "Prediction range (vert. UV)");
-module_param(qhy, int, 0);
-MODULE_PARM_DESC(qhy, "Quantization threshold (horiz. Y)");
-module_param(qhuv, int, 0);
-MODULE_PARM_DESC(qhuv, "Quantization threshold (horiz. UV)");
-module_param(qvy, int, 0);
-MODULE_PARM_DESC(qvy, "Quantization threshold (vert. Y)");
-module_param(qvuv, int, 0);
-MODULE_PARM_DESC(qvuv, "Quantization threshold (vert. UV)");
-module_param(lightfreq, int, 0);
-MODULE_PARM_DESC(lightfreq,
- "Light frequency. Set to 50 or 60 Hz, or zero for default settings");
-module_param(bandingfilter, int, 0);
-MODULE_PARM_DESC(bandingfilter,
- "Enable banding filter (to reduce effects of fluorescent lighting)");
-module_param(clockdiv, int, 0);
-MODULE_PARM_DESC(clockdiv, "Force pixel clock divisor to a specific value");
-module_param(packetsize, int, 0);
-MODULE_PARM_DESC(packetsize, "Force a specific isoc packet size");
-module_param(framedrop, int, 0);
-MODULE_PARM_DESC(framedrop, "Force a specific frame drop register setting");
-module_param(fastset, int, 0);
-MODULE_PARM_DESC(fastset, "Allows picture settings to take effect immediately");
-module_param(force_palette, int, 0);
-MODULE_PARM_DESC(force_palette, "Force the palette to a specific value");
-module_param(backlight, int, 0);
-MODULE_PARM_DESC(backlight, "For objects that are lit from behind");
-static unsigned int num_uv;
-module_param_array(unit_video, int, &num_uv, 0);
-MODULE_PARM_DESC(unit_video,
- "Force use of specific minor number(s). 0 is not allowed.");
-module_param(remove_zeros, int, 0);
-MODULE_PARM_DESC(remove_zeros,
- "Remove zero-padding from uncompressed incoming data");
-module_param(mirror, int, 0);
-MODULE_PARM_DESC(mirror, "Reverse image horizontally");
-module_param(ov518_color, int, 0);
-MODULE_PARM_DESC(ov518_color, "Enable OV518 color (experimental)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-/**********************************************************************
- * Miscellaneous Globals
- **********************************************************************/
-
-static struct usb_driver ov511_driver;
-
-/* Number of times to retry a failed I2C transaction. Increase this if you
- * are getting "Failed to read sensor ID..." */
-static const int i2c_detect_tries = 5;
-
-static struct usb_device_id device_table [] = {
- { USB_DEVICE(VEND_OMNIVISION, PROD_OV511) },
- { USB_DEVICE(VEND_OMNIVISION, PROD_OV511PLUS) },
- { USB_DEVICE(VEND_MATTEL, PROD_ME2CAM) },
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, device_table);
-
-static unsigned char yQuanTable511[] = OV511_YQUANTABLE;
-static unsigned char uvQuanTable511[] = OV511_UVQUANTABLE;
-static unsigned char yQuanTable518[] = OV518_YQUANTABLE;
-static unsigned char uvQuanTable518[] = OV518_UVQUANTABLE;
-
-/**********************************************************************
- * Symbolic Names
- **********************************************************************/
-
-/* Known OV511-based cameras */
-static struct symbolic_list camlist[] = {
- { 0, "Generic Camera (no ID)" },
- { 1, "Mustek WCam 3X" },
- { 3, "D-Link DSB-C300" },
- { 4, "Generic OV511/OV7610" },
- { 5, "Puretek PT-6007" },
- { 6, "Lifeview USB Life TV (NTSC)" },
- { 21, "Creative Labs WebCam 3" },
- { 22, "Lifeview USB Life TV (PAL D/K+B/G)" },
- { 36, "Koala-Cam" },
- { 38, "Lifeview USB Life TV (PAL)" },
- { 41, "Samsung Anycam MPC-M10" },
- { 43, "Mtekvision Zeca MV402" },
- { 46, "Suma eON" },
- { 70, "Lifeview USB Life TV (PAL/SECAM)" },
- { 100, "Lifeview RoboCam" },
- { 102, "AverMedia InterCam Elite" },
- { 112, "MediaForte MV300" }, /* or OV7110 evaluation kit */
- { 134, "Ezonics EZCam II" },
- { 192, "Webeye 2000B" },
- { 253, "Alpha Vision Tech. AlphaCam SE" },
- { -1, NULL }
-};
-
-/* Video4Linux1 Palettes */
-static struct symbolic_list v4l1_plist[] = {
- { VIDEO_PALETTE_GREY, "GREY" },
- { VIDEO_PALETTE_HI240, "HI240" },
- { VIDEO_PALETTE_RGB565, "RGB565" },
- { VIDEO_PALETTE_RGB24, "RGB24" },
- { VIDEO_PALETTE_RGB32, "RGB32" },
- { VIDEO_PALETTE_RGB555, "RGB555" },
- { VIDEO_PALETTE_YUV422, "YUV422" },
- { VIDEO_PALETTE_YUYV, "YUYV" },
- { VIDEO_PALETTE_UYVY, "UYVY" },
- { VIDEO_PALETTE_YUV420, "YUV420" },
- { VIDEO_PALETTE_YUV411, "YUV411" },
- { VIDEO_PALETTE_RAW, "RAW" },
- { VIDEO_PALETTE_YUV422P,"YUV422P" },
- { VIDEO_PALETTE_YUV411P,"YUV411P" },
- { VIDEO_PALETTE_YUV420P,"YUV420P" },
- { VIDEO_PALETTE_YUV410P,"YUV410P" },
- { -1, NULL }
-};
-
-static struct symbolic_list brglist[] = {
- { BRG_OV511, "OV511" },
- { BRG_OV511PLUS, "OV511+" },
- { BRG_OV518, "OV518" },
- { BRG_OV518PLUS, "OV518+" },
- { -1, NULL }
-};
-
-static struct symbolic_list senlist[] = {
- { SEN_OV76BE, "OV76BE" },
- { SEN_OV7610, "OV7610" },
- { SEN_OV7620, "OV7620" },
- { SEN_OV7620AE, "OV7620AE" },
- { SEN_OV6620, "OV6620" },
- { SEN_OV6630, "OV6630" },
- { SEN_OV6630AE, "OV6630AE" },
- { SEN_OV6630AF, "OV6630AF" },
- { SEN_OV8600, "OV8600" },
- { SEN_KS0127, "KS0127" },
- { SEN_KS0127B, "KS0127B" },
- { SEN_SAA7111A, "SAA7111A" },
- { -1, NULL }
-};
-
-/* URB error codes: */
-static struct symbolic_list urb_errlist[] = {
- { -ENOSR, "Buffer error (overrun)" },
- { -EPIPE, "Stalled (device not responding)" },
- { -EOVERFLOW, "Babble (device sends too much data)" },
- { -EPROTO, "Bit-stuff error (bad cable?)" },
- { -EILSEQ, "CRC/Timeout (bad cable?)" },
- { -ETIME, "Device does not respond to token" },
- { -ETIMEDOUT, "Device does not respond to command" },
- { -1, NULL }
-};
-
-/**********************************************************************
- * Memory management
- **********************************************************************/
-static void *
-rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-static void
-rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-/**********************************************************************
- *
- * Register I/O
- *
- **********************************************************************/
-
-/* Write an OV51x register */
-static int
-reg_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
- int rc;
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- mutex_lock(&ov->cbuf_lock);
- ov->cbuf[0] = value;
- rc = usb_control_msg(ov->dev,
- usb_sndctrlpipe(ov->dev, 0),
- (ov->bclass == BCL_OV518)?1:2 /* REG_IO */,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, &ov->cbuf[0], 1, 1000);
- mutex_unlock(&ov->cbuf_lock);
-
- if (rc < 0)
- err("reg write: error %d: %s", rc, symbolic(urb_errlist, rc));
-
- return rc;
-}
-
-/* Read from an OV51x register */
-/* returns: negative is error, pos or zero is data */
-static int
-reg_r(struct usb_ov511 *ov, unsigned char reg)
-{
- int rc;
-
- mutex_lock(&ov->cbuf_lock);
- rc = usb_control_msg(ov->dev,
- usb_rcvctrlpipe(ov->dev, 0),
- (ov->bclass == BCL_OV518)?1:3 /* REG_IO */,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, &ov->cbuf[0], 1, 1000);
-
- if (rc < 0) {
- err("reg read: error %d: %s", rc, symbolic(urb_errlist, rc));
- } else {
- rc = ov->cbuf[0];
- PDEBUG(5, "0x%02X:0x%02X", reg, ov->cbuf[0]);
- }
-
- mutex_unlock(&ov->cbuf_lock);
-
- return rc;
-}
-
-/*
- * Writes bits at positions specified by mask to an OV51x reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-reg_w_mask(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int ret;
- unsigned char oldval, newval;
-
- ret = reg_r(ov, reg);
- if (ret < 0)
- return ret;
-
- oldval = (unsigned char) ret;
- oldval &= (~mask); /* Clear the masked bits */
- value &= mask; /* Enforce mask on value */
- newval = oldval | value; /* Set the desired bits */
-
- return (reg_w(ov, reg, newval));
-}
-
-/*
- * Writes multiple (n) byte value to a single register. Only valid with certain
- * registers (0x30 and 0xc4 - 0xce).
- */
-static int
-ov518_reg_w32(struct usb_ov511 *ov, unsigned char reg, u32 val, int n)
-{
- int rc;
-
- PDEBUG(5, "0x%02X:%7d, n=%d", reg, val, n);
-
- mutex_lock(&ov->cbuf_lock);
-
- *((__le32 *)ov->cbuf) = __cpu_to_le32(val);
-
- rc = usb_control_msg(ov->dev,
- usb_sndctrlpipe(ov->dev, 0),
- 1 /* REG_IO */,
- USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, (__u16)reg, ov->cbuf, n, 1000);
- mutex_unlock(&ov->cbuf_lock);
-
- if (rc < 0)
- err("reg write multiple: error %d: %s", rc,
- symbolic(urb_errlist, rc));
-
- return rc;
-}
-
-static int
-ov511_upload_quan_tables(struct usb_ov511 *ov)
-{
- unsigned char *pYTable = yQuanTable511;
- unsigned char *pUVTable = uvQuanTable511;
- unsigned char val0, val1;
- int i, rc, reg = R511_COMP_LUT_BEGIN;
-
- PDEBUG(4, "Uploading quantization tables");
-
- for (i = 0; i < OV511_QUANTABLESIZE / 2; i++) {
- if (ENABLE_Y_QUANTABLE) {
- val0 = *pYTable++;
- val1 = *pYTable++;
- val0 &= 0x0f;
- val1 &= 0x0f;
- val0 |= val1 << 4;
- rc = reg_w(ov, reg, val0);
- if (rc < 0)
- return rc;
- }
-
- if (ENABLE_UV_QUANTABLE) {
- val0 = *pUVTable++;
- val1 = *pUVTable++;
- val0 &= 0x0f;
- val1 &= 0x0f;
- val0 |= val1 << 4;
- rc = reg_w(ov, reg + OV511_QUANTABLESIZE/2, val0);
- if (rc < 0)
- return rc;
- }
-
- reg++;
- }
-
- return 0;
-}
-
-/* OV518 quantization tables are 8x4 (instead of 8x8) */
-static int
-ov518_upload_quan_tables(struct usb_ov511 *ov)
-{
- unsigned char *pYTable = yQuanTable518;
- unsigned char *pUVTable = uvQuanTable518;
- unsigned char val0, val1;
- int i, rc, reg = R511_COMP_LUT_BEGIN;
-
- PDEBUG(4, "Uploading quantization tables");
-
- for (i = 0; i < OV518_QUANTABLESIZE / 2; i++) {
- if (ENABLE_Y_QUANTABLE) {
- val0 = *pYTable++;
- val1 = *pYTable++;
- val0 &= 0x0f;
- val1 &= 0x0f;
- val0 |= val1 << 4;
- rc = reg_w(ov, reg, val0);
- if (rc < 0)
- return rc;
- }
-
- if (ENABLE_UV_QUANTABLE) {
- val0 = *pUVTable++;
- val1 = *pUVTable++;
- val0 &= 0x0f;
- val1 &= 0x0f;
- val0 |= val1 << 4;
- rc = reg_w(ov, reg + OV518_QUANTABLESIZE/2, val0);
- if (rc < 0)
- return rc;
- }
-
- reg++;
- }
-
- return 0;
-}
-
-static int
-ov51x_reset(struct usb_ov511 *ov, unsigned char reset_type)
-{
- int rc;
-
- /* Setting bit 0 not allowed on 518/518Plus */
- if (ov->bclass == BCL_OV518)
- reset_type &= 0xfe;
-
- PDEBUG(4, "Reset: type=0x%02X", reset_type);
-
- rc = reg_w(ov, R51x_SYS_RESET, reset_type);
- rc = reg_w(ov, R51x_SYS_RESET, 0);
-
- if (rc < 0)
- err("reset: command failed");
-
- return rc;
-}
-
-/**********************************************************************
- *
- * Low-level I2C I/O functions
- *
- **********************************************************************/
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_w(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_write_internal(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value)
-{
- int rc;
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- /* Select camera register */
- rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
- if (rc < 0)
- return rc;
-
- /* Write "value" to I2C data port of OV511 */
- rc = reg_w(ov, R51x_I2C_DATA, value);
- if (rc < 0)
- return rc;
-
- /* Initiate 3-byte write cycle */
- rc = reg_w(ov, R518_I2C_CTL, 0x01);
- if (rc < 0)
- return rc;
-
- return 0;
-}
-
-/* NOTE: Do not call this function directly! */
-static int
-ov511_i2c_write_internal(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value)
-{
- int rc, retries;
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- /* Three byte write cycle */
- for (retries = OV511_I2C_RETRIES; ; ) {
- /* Select camera register */
- rc = reg_w(ov, R51x_I2C_SADDR_3, reg);
- if (rc < 0)
- break;
-
- /* Write "value" to I2C data port of OV511 */
- rc = reg_w(ov, R51x_I2C_DATA, value);
- if (rc < 0)
- break;
-
- /* Initiate 3-byte write cycle */
- rc = reg_w(ov, R511_I2C_CTL, 0x01);
- if (rc < 0)
- break;
-
- /* Retry until idle */
- do {
- rc = reg_r(ov, R511_I2C_CTL);
- } while (rc > 0 && ((rc&1) == 0));
- if (rc < 0)
- break;
-
- /* Ack? */
- if ((rc&2) == 0) {
- rc = 0;
- break;
- }
-#if 0
- /* I2C abort */
- reg_w(ov, R511_I2C_CTL, 0x10);
-#endif
- if (--retries < 0) {
- err("i2c write retries exhausted");
- rc = -1;
- break;
- }
- }
-
- return rc;
-}
-
-/* NOTE: Do not call this function directly!
- * The OV518 I2C I/O procedure is different, hence, this function.
- * This is normally only called from i2c_r(). Note that this function
- * always succeeds regardless of whether the sensor is present and working.
- */
-static int
-ov518_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
- int rc, value;
-
- /* Select camera register */
- rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
- if (rc < 0)
- return rc;
-
- /* Initiate 2-byte write cycle */
- rc = reg_w(ov, R518_I2C_CTL, 0x03);
- if (rc < 0)
- return rc;
-
- /* Initiate 2-byte read cycle */
- rc = reg_w(ov, R518_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
-
- value = reg_r(ov, R51x_I2C_DATA);
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- return value;
-}
-
-/* NOTE: Do not call this function directly!
- * returns: negative is error, pos or zero is data */
-static int
-ov511_i2c_read_internal(struct usb_ov511 *ov, unsigned char reg)
-{
- int rc, value, retries;
-
- /* Two byte write cycle */
- for (retries = OV511_I2C_RETRIES; ; ) {
- /* Select camera register */
- rc = reg_w(ov, R51x_I2C_SADDR_2, reg);
- if (rc < 0)
- return rc;
-
- /* Initiate 2-byte write cycle */
- rc = reg_w(ov, R511_I2C_CTL, 0x03);
- if (rc < 0)
- return rc;
-
- /* Retry until idle */
- do {
- rc = reg_r(ov, R511_I2C_CTL);
- } while (rc > 0 && ((rc & 1) == 0));
- if (rc < 0)
- return rc;
-
- if ((rc&2) == 0) /* Ack? */
- break;
-
- /* I2C abort */
- reg_w(ov, R511_I2C_CTL, 0x10);
-
- if (--retries < 0) {
- err("i2c write retries exhausted");
- return -1;
- }
- }
-
- /* Two byte read cycle */
- for (retries = OV511_I2C_RETRIES; ; ) {
- /* Initiate 2-byte read cycle */
- rc = reg_w(ov, R511_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
-
- /* Retry until idle */
- do {
- rc = reg_r(ov, R511_I2C_CTL);
- } while (rc > 0 && ((rc&1) == 0));
- if (rc < 0)
- return rc;
-
- if ((rc&2) == 0) /* Ack? */
- break;
-
- /* I2C abort */
- rc = reg_w(ov, R511_I2C_CTL, 0x10);
- if (rc < 0)
- return rc;
-
- if (--retries < 0) {
- err("i2c read retries exhausted");
- return -1;
- }
- }
-
- value = reg_r(ov, R51x_I2C_DATA);
-
- PDEBUG(5, "0x%02X:0x%02X", reg, value);
-
- /* This is needed to make i2c_w() work */
- rc = reg_w(ov, R511_I2C_CTL, 0x05);
- if (rc < 0)
- return rc;
-
- return value;
-}
-
-/* returns: negative is error, pos or zero is data */
-static int
-i2c_r(struct usb_ov511 *ov, unsigned char reg)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
-
- if (ov->bclass == BCL_OV518)
- rc = ov518_i2c_read_internal(ov, reg);
- else
- rc = ov511_i2c_read_internal(ov, reg);
-
- mutex_unlock(&ov->i2c_lock);
-
- return rc;
-}
-
-static int
-i2c_w(struct usb_ov511 *ov, unsigned char reg, unsigned char value)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
-
- if (ov->bclass == BCL_OV518)
- rc = ov518_i2c_write_internal(ov, reg, value);
- else
- rc = ov511_i2c_write_internal(ov, reg, value);
-
- mutex_unlock(&ov->i2c_lock);
-
- return rc;
-}
-
-/* Do not call this function directly! */
-static int
-ov51x_i2c_write_mask_internal(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int rc;
- unsigned char oldval, newval;
-
- if (mask == 0xff) {
- newval = value;
- } else {
- if (ov->bclass == BCL_OV518)
- rc = ov518_i2c_read_internal(ov, reg);
- else
- rc = ov511_i2c_read_internal(ov, reg);
- if (rc < 0)
- return rc;
-
- oldval = (unsigned char) rc;
- oldval &= (~mask); /* Clear the masked bits */
- value &= mask; /* Enforce mask on value */
- newval = oldval | value; /* Set the desired bits */
- }
-
- if (ov->bclass == BCL_OV518)
- return (ov518_i2c_write_internal(ov, reg, newval));
- else
- return (ov511_i2c_write_internal(ov, reg, newval));
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-static int
-i2c_w_mask(struct usb_ov511 *ov,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
- rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
- mutex_unlock(&ov->i2c_lock);
-
- return rc;
-}
-
-/* Set the read and write slave IDs. The "slave" argument is the write slave,
- * and the read slave will be set to (slave + 1). ov->i2c_lock should be held
- * when calling this. This should not be called from outside the i2c I/O
- * functions.
- */
-static int
-i2c_set_slave_internal(struct usb_ov511 *ov, unsigned char slave)
-{
- int rc;
-
- rc = reg_w(ov, R51x_I2C_W_SID, slave);
- if (rc < 0)
- return rc;
-
- rc = reg_w(ov, R51x_I2C_R_SID, slave + 1);
- if (rc < 0)
- return rc;
-
- return 0;
-}
-
-/* Write to a specific I2C slave ID and register, using the specified mask */
-static int
-i2c_w_slave(struct usb_ov511 *ov,
- unsigned char slave,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int rc = 0;
-
- mutex_lock(&ov->i2c_lock);
-
- /* Set new slave IDs */
- rc = i2c_set_slave_internal(ov, slave);
- if (rc < 0)
- goto out;
-
- rc = ov51x_i2c_write_mask_internal(ov, reg, value, mask);
-
-out:
- /* Restore primary IDs */
- if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
- err("Couldn't restore primary I2C slave");
-
- mutex_unlock(&ov->i2c_lock);
- return rc;
-}
-
-/* Read from a specific I2C slave ID and register */
-static int
-i2c_r_slave(struct usb_ov511 *ov,
- unsigned char slave,
- unsigned char reg)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
-
- /* Set new slave IDs */
- rc = i2c_set_slave_internal(ov, slave);
- if (rc < 0)
- goto out;
-
- if (ov->bclass == BCL_OV518)
- rc = ov518_i2c_read_internal(ov, reg);
- else
- rc = ov511_i2c_read_internal(ov, reg);
-
-out:
- /* Restore primary IDs */
- if (i2c_set_slave_internal(ov, ov->primary_i2c_slave) < 0)
- err("Couldn't restore primary I2C slave");
-
- mutex_unlock(&ov->i2c_lock);
- return rc;
-}
-
-/* Sets I2C read and write slave IDs. Returns <0 for error */
-static int
-ov51x_set_slave_ids(struct usb_ov511 *ov, unsigned char sid)
-{
- int rc;
-
- mutex_lock(&ov->i2c_lock);
-
- rc = i2c_set_slave_internal(ov, sid);
- if (rc < 0)
- goto out;
-
- // FIXME: Is this actually necessary?
- rc = ov51x_reset(ov, OV511_RESET_NOREGS);
-out:
- mutex_unlock(&ov->i2c_lock);
- return rc;
-}
-
-static int
-write_regvals(struct usb_ov511 *ov, struct ov511_regvals * pRegvals)
-{
- int rc;
-
- while (pRegvals->bus != OV511_DONE_BUS) {
- if (pRegvals->bus == OV511_REG_BUS) {
- if ((rc = reg_w(ov, pRegvals->reg, pRegvals->val)) < 0)
- return rc;
- } else if (pRegvals->bus == OV511_I2C_BUS) {
- if ((rc = i2c_w(ov, pRegvals->reg, pRegvals->val)) < 0)
- return rc;
- } else {
- err("Bad regval array");
- return -1;
- }
- pRegvals++;
- }
- return 0;
-}
-
-#ifdef OV511_DEBUG
-static void
-dump_i2c_range(struct usb_ov511 *ov, int reg1, int regn)
-{
- int i, rc;
-
- for (i = reg1; i <= regn; i++) {
- rc = i2c_r(ov, i);
- dev_info(&ov->dev->dev, "Sensor[0x%02X] = 0x%02X\n", i, rc);
- }
-}
-
-static void
-dump_i2c_regs(struct usb_ov511 *ov)
-{
- dev_info(&ov->dev->dev, "I2C REGS\n");
- dump_i2c_range(ov, 0x00, 0x7C);
-}
-
-static void
-dump_reg_range(struct usb_ov511 *ov, int reg1, int regn)
-{
- int i, rc;
-
- for (i = reg1; i <= regn; i++) {
- rc = reg_r(ov, i);
- dev_info(&ov->dev->dev, "OV511[0x%02X] = 0x%02X\n", i, rc);
- }
-}
-
-static void
-ov511_dump_regs(struct usb_ov511 *ov)
-{
- dev_info(&ov->dev->dev, "CAMERA INTERFACE REGS\n");
- dump_reg_range(ov, 0x10, 0x1f);
- dev_info(&ov->dev->dev, "DRAM INTERFACE REGS\n");
- dump_reg_range(ov, 0x20, 0x23);
- dev_info(&ov->dev->dev, "ISO FIFO REGS\n");
- dump_reg_range(ov, 0x30, 0x31);
- dev_info(&ov->dev->dev, "PIO REGS\n");
- dump_reg_range(ov, 0x38, 0x39);
- dump_reg_range(ov, 0x3e, 0x3e);
- dev_info(&ov->dev->dev, "I2C REGS\n");
- dump_reg_range(ov, 0x40, 0x49);
- dev_info(&ov->dev->dev, "SYSTEM CONTROL REGS\n");
- dump_reg_range(ov, 0x50, 0x55);
- dump_reg_range(ov, 0x5e, 0x5f);
- dev_info(&ov->dev->dev, "OmniCE REGS\n");
- dump_reg_range(ov, 0x70, 0x79);
- /* NOTE: Quantization tables are not readable. You will get the value
- * in reg. 0x79 for every table register */
- dump_reg_range(ov, 0x80, 0x9f);
- dump_reg_range(ov, 0xa0, 0xbf);
-
-}
-
-static void
-ov518_dump_regs(struct usb_ov511 *ov)
-{
- dev_info(&ov->dev->dev, "VIDEO MODE REGS\n");
- dump_reg_range(ov, 0x20, 0x2f);
- dev_info(&ov->dev->dev, "DATA PUMP AND SNAPSHOT REGS\n");
- dump_reg_range(ov, 0x30, 0x3f);
- dev_info(&ov->dev->dev, "I2C REGS\n");
- dump_reg_range(ov, 0x40, 0x4f);
- dev_info(&ov->dev->dev, "SYSTEM CONTROL AND VENDOR REGS\n");
- dump_reg_range(ov, 0x50, 0x5f);
- dev_info(&ov->dev->dev, "60 - 6F\n");
- dump_reg_range(ov, 0x60, 0x6f);
- dev_info(&ov->dev->dev, "70 - 7F\n");
- dump_reg_range(ov, 0x70, 0x7f);
- dev_info(&ov->dev->dev, "Y QUANTIZATION TABLE\n");
- dump_reg_range(ov, 0x80, 0x8f);
- dev_info(&ov->dev->dev, "UV QUANTIZATION TABLE\n");
- dump_reg_range(ov, 0x90, 0x9f);
- dev_info(&ov->dev->dev, "A0 - BF\n");
- dump_reg_range(ov, 0xa0, 0xbf);
- dev_info(&ov->dev->dev, "CBR\n");
- dump_reg_range(ov, 0xc0, 0xcf);
-}
-#endif
-
-/*****************************************************************************/
-
-/* Temporarily stops OV511 from functioning. Must do this before changing
- * registers while the camera is streaming */
-static inline int
-ov51x_stop(struct usb_ov511 *ov)
-{
- PDEBUG(4, "stopping");
- ov->stopped = 1;
- if (ov->bclass == BCL_OV518)
- return (reg_w_mask(ov, R51x_SYS_RESET, 0x3a, 0x3a));
- else
- return (reg_w(ov, R51x_SYS_RESET, 0x3d));
-}
-
-/* Restarts OV511 after ov511_stop() is called. Has no effect if it is not
- * actually stopped (for performance). */
-static inline int
-ov51x_restart(struct usb_ov511 *ov)
-{
- if (ov->stopped) {
- PDEBUG(4, "restarting");
- ov->stopped = 0;
-
- /* Reinitialize the stream */
- if (ov->bclass == BCL_OV518)
- reg_w(ov, 0x2f, 0x80);
-
- return (reg_w(ov, R51x_SYS_RESET, 0x00));
- }
-
- return 0;
-}
-
-/* Sleeps until no frames are active. Returns !0 if got signal */
-static int
-ov51x_wait_frames_inactive(struct usb_ov511 *ov)
-{
- return wait_event_interruptible(ov->wq, ov->curframe < 0);
-}
-
-/* Resets the hardware snapshot button */
-static void
-ov51x_clear_snapshot(struct usb_ov511 *ov)
-{
- if (ov->bclass == BCL_OV511) {
- reg_w(ov, R51x_SYS_SNAP, 0x00);
- reg_w(ov, R51x_SYS_SNAP, 0x02);
- reg_w(ov, R51x_SYS_SNAP, 0x00);
- } else if (ov->bclass == BCL_OV518) {
- dev_warn(&ov->dev->dev,
- "snapshot reset not supported yet on OV518(+)\n");
- } else {
- dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
- }
-}
-
-#if 0
-/* Checks the status of the snapshot button. Returns 1 if it was pressed since
- * it was last cleared, and zero in all other cases (including errors) */
-static int
-ov51x_check_snapshot(struct usb_ov511 *ov)
-{
- int ret, status = 0;
-
- if (ov->bclass == BCL_OV511) {
- ret = reg_r(ov, R51x_SYS_SNAP);
- if (ret < 0) {
- dev_err(&ov->dev->dev,
- "Error checking snspshot status (%d)\n", ret);
- } else if (ret & 0x08) {
- status = 1;
- }
- } else if (ov->bclass == BCL_OV518) {
- dev_warn(&ov->dev->dev,
- "snapshot check not supported yet on OV518(+)\n");
- } else {
- dev_err(&ov->dev->dev, "clear snap: invalid bridge type\n");
- }
-
- return status;
-}
-#endif
-
-/* This does an initial reset of an OmniVision sensor and ensures that I2C
- * is synchronized. Returns <0 for failure.
- */
-static int
-init_ov_sensor(struct usb_ov511 *ov)
-{
- int i, success;
-
- /* Reset the sensor */
- if (i2c_w(ov, 0x12, 0x80) < 0)
- return -EIO;
-
- /* Wait for it to initialize */
- msleep(150);
-
- for (i = 0, success = 0; i < i2c_detect_tries && !success; i++) {
- if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
- (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
- success = 1;
- continue;
- }
-
- /* Reset the sensor */
- if (i2c_w(ov, 0x12, 0x80) < 0)
- return -EIO;
- /* Wait for it to initialize */
- msleep(150);
- /* Dummy read to sync I2C */
- if (i2c_r(ov, 0x00) < 0)
- return -EIO;
- }
-
- if (!success)
- return -EIO;
-
- PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
- return 0;
-}
-
-static int
-ov511_set_packet_size(struct usb_ov511 *ov, int size)
-{
- int alt, mult;
-
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- mult = size >> 5;
-
- if (ov->bridge == BRG_OV511) {
- if (size == 0)
- alt = OV511_ALT_SIZE_0;
- else if (size == 257)
- alt = OV511_ALT_SIZE_257;
- else if (size == 513)
- alt = OV511_ALT_SIZE_513;
- else if (size == 769)
- alt = OV511_ALT_SIZE_769;
- else if (size == 993)
- alt = OV511_ALT_SIZE_993;
- else {
- err("Set packet size: invalid size (%d)", size);
- return -EINVAL;
- }
- } else if (ov->bridge == BRG_OV511PLUS) {
- if (size == 0)
- alt = OV511PLUS_ALT_SIZE_0;
- else if (size == 33)
- alt = OV511PLUS_ALT_SIZE_33;
- else if (size == 129)
- alt = OV511PLUS_ALT_SIZE_129;
- else if (size == 257)
- alt = OV511PLUS_ALT_SIZE_257;
- else if (size == 385)
- alt = OV511PLUS_ALT_SIZE_385;
- else if (size == 513)
- alt = OV511PLUS_ALT_SIZE_513;
- else if (size == 769)
- alt = OV511PLUS_ALT_SIZE_769;
- else if (size == 961)
- alt = OV511PLUS_ALT_SIZE_961;
- else {
- err("Set packet size: invalid size (%d)", size);
- return -EINVAL;
- }
- } else {
- err("Set packet size: Invalid bridge type");
- return -EINVAL;
- }
-
- PDEBUG(3, "%d, mult=%d, alt=%d", size, mult, alt);
-
- if (reg_w(ov, R51x_FIFO_PSIZE, mult) < 0)
- return -EIO;
-
- if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
- err("Set packet size: set interface error");
- return -EBUSY;
- }
-
- if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
- return -EIO;
-
- ov->packet_size = size;
-
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return 0;
-}
-
-/* Note: Unlike the OV511/OV511+, the size argument does NOT include the
- * optional packet number byte. The actual size *is* stored in ov->packet_size,
- * though. */
-static int
-ov518_set_packet_size(struct usb_ov511 *ov, int size)
-{
- int alt;
-
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- if (ov->bclass == BCL_OV518) {
- if (size == 0)
- alt = OV518_ALT_SIZE_0;
- else if (size == 128)
- alt = OV518_ALT_SIZE_128;
- else if (size == 256)
- alt = OV518_ALT_SIZE_256;
- else if (size == 384)
- alt = OV518_ALT_SIZE_384;
- else if (size == 512)
- alt = OV518_ALT_SIZE_512;
- else if (size == 640)
- alt = OV518_ALT_SIZE_640;
- else if (size == 768)
- alt = OV518_ALT_SIZE_768;
- else if (size == 896)
- alt = OV518_ALT_SIZE_896;
- else {
- err("Set packet size: invalid size (%d)", size);
- return -EINVAL;
- }
- } else {
- err("Set packet size: Invalid bridge type");
- return -EINVAL;
- }
-
- PDEBUG(3, "%d, alt=%d", size, alt);
-
- ov->packet_size = size;
- if (size > 0) {
- /* Program ISO FIFO size reg (packet number isn't included) */
- ov518_reg_w32(ov, 0x30, size, 2);
-
- if (ov->packet_numbering)
- ++ov->packet_size;
- }
-
- if (usb_set_interface(ov->dev, ov->iface, alt) < 0) {
- err("Set packet size: set interface error");
- return -EBUSY;
- }
-
- /* Initialize the stream */
- if (reg_w(ov, 0x2f, 0x80) < 0)
- return -EIO;
-
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
- return -EIO;
-
- return 0;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov511_init_compression(struct usb_ov511 *ov)
-{
- int rc = 0;
-
- if (!ov->compress_inited) {
- reg_w(ov, 0x70, phy);
- reg_w(ov, 0x71, phuv);
- reg_w(ov, 0x72, pvy);
- reg_w(ov, 0x73, pvuv);
- reg_w(ov, 0x74, qhy);
- reg_w(ov, 0x75, qhuv);
- reg_w(ov, 0x76, qvy);
- reg_w(ov, 0x77, qvuv);
-
- if (ov511_upload_quan_tables(ov) < 0) {
- err("Error uploading quantization tables");
- rc = -EIO;
- goto out;
- }
- }
-
- ov->compress_inited = 1;
-out:
- return rc;
-}
-
-/* Upload compression params and quantization tables. Returns 0 for success. */
-static int
-ov518_init_compression(struct usb_ov511 *ov)
-{
- int rc = 0;
-
- if (!ov->compress_inited) {
- if (ov518_upload_quan_tables(ov) < 0) {
- err("Error uploading quantization tables");
- rc = -EIO;
- goto out;
- }
- }
-
- ov->compress_inited = 1;
-out:
- return rc;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's contrast setting to "val" */
-static int
-sensor_set_contrast(struct usb_ov511 *ov, unsigned short val)
-{
- int rc;
-
- PDEBUG(3, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- {
- rc = i2c_w(ov, OV7610_REG_CNT, val >> 8);
- if (rc < 0)
- goto out;
- break;
- }
- case SEN_OV6630:
- {
- rc = i2c_w_mask(ov, OV7610_REG_CNT, val >> 12, 0x0f);
- if (rc < 0)
- goto out;
- break;
- }
- case SEN_OV7620:
- {
- unsigned char ctab[] = {
- 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
- 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
- };
-
- /* Use Y gamma control instead. Bit 0 enables it. */
- rc = i2c_w(ov, 0x64, ctab[val>>12]);
- if (rc < 0)
- goto out;
- break;
- }
- case SEN_SAA7111A:
- {
- rc = i2c_w(ov, 0x0b, val >> 9);
- if (rc < 0)
- goto out;
- break;
- }
- default:
- {
- PDEBUG(3, "Unsupported with this sensor");
- rc = -EPERM;
- goto out;
- }
- }
-
- rc = 0; /* Success */
- ov->contrast = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-
-/* Gets sensor's contrast setting */
-static int
-sensor_get_contrast(struct usb_ov511 *ov, unsigned short *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- rc = i2c_r(ov, OV7610_REG_CNT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_OV6630:
- rc = i2c_r(ov, OV7610_REG_CNT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 12;
- break;
- case SEN_OV7620:
- /* Use Y gamma reg instead. Bit 0 is the enable bit. */
- rc = i2c_r(ov, 0x64);
- if (rc < 0)
- return rc;
- else
- *val = (rc & 0xfe) << 8;
- break;
- case SEN_SAA7111A:
- *val = ov->contrast;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- }
-
- PDEBUG(3, "%d", *val);
- ov->contrast = *val;
-
- return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's brightness setting to "val" */
-static int
-sensor_set_brightness(struct usb_ov511 *ov, unsigned short val)
-{
- int rc;
-
- PDEBUG(4, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
- if (rc < 0)
- goto out;
- break;
- case SEN_OV7620:
- /* 7620 doesn't like manual changes when in auto mode */
- if (!ov->auto_brt) {
- rc = i2c_w(ov, OV7610_REG_BRT, val >> 8);
- if (rc < 0)
- goto out;
- }
- break;
- case SEN_SAA7111A:
- rc = i2c_w(ov, 0x0a, val >> 8);
- if (rc < 0)
- goto out;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- rc = -EPERM;
- goto out;
- }
-
- rc = 0; /* Success */
- ov->brightness = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-
-/* Gets sensor's brightness setting */
-static int
-sensor_get_brightness(struct usb_ov511 *ov, unsigned short *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_OV7620:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_r(ov, OV7610_REG_BRT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_SAA7111A:
- *val = ov->brightness;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- }
-
- PDEBUG(3, "%d", *val);
- ov->brightness = *val;
-
- return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's saturation (color intensity) setting to "val" */
-static int
-sensor_set_saturation(struct usb_ov511 *ov, unsigned short val)
-{
- int rc;
-
- PDEBUG(3, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
- if (rc < 0)
- goto out;
- break;
- case SEN_OV7620:
-// /* Use UV gamma control instead. Bits 0 & 7 are reserved. */
-// rc = ov_i2c_write(ov->dev, 0x62, (val >> 9) & 0x7e);
-// if (rc < 0)
-// goto out;
- rc = i2c_w(ov, OV7610_REG_SAT, val >> 8);
- if (rc < 0)
- goto out;
- break;
- case SEN_SAA7111A:
- rc = i2c_w(ov, 0x0c, val >> 9);
- if (rc < 0)
- goto out;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- rc = -EPERM;
- goto out;
- }
-
- rc = 0; /* Success */
- ov->colour = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-
-/* Gets sensor's saturation (color intensity) setting */
-static int
-sensor_get_saturation(struct usb_ov511 *ov, unsigned short *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_r(ov, OV7610_REG_SAT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_OV7620:
-// /* Use UV gamma reg instead. Bits 0 & 7 are reserved. */
-// rc = i2c_r(ov, 0x62);
-// if (rc < 0)
-// return rc;
-// else
-// *val = (rc & 0x7e) << 9;
- rc = i2c_r(ov, OV7610_REG_SAT);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_SAA7111A:
- *val = ov->colour;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- }
-
- PDEBUG(3, "%d", *val);
- ov->colour = *val;
-
- return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-/* Sets sensor's hue (red/blue balance) setting to "val" */
-static int
-sensor_set_hue(struct usb_ov511 *ov, unsigned short val)
-{
- int rc;
-
- PDEBUG(3, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_w(ov, OV7610_REG_RED, 0xFF - (val >> 8));
- if (rc < 0)
- goto out;
-
- rc = i2c_w(ov, OV7610_REG_BLUE, val >> 8);
- if (rc < 0)
- goto out;
- break;
- case SEN_OV7620:
-// Hue control is causing problems. I will enable it once it's fixed.
-#if 0
- rc = i2c_w(ov, 0x7a, (unsigned char)(val >> 8) + 0xb);
- if (rc < 0)
- goto out;
-
- rc = i2c_w(ov, 0x79, (unsigned char)(val >> 8) + 0xb);
- if (rc < 0)
- goto out;
-#endif
- break;
- case SEN_SAA7111A:
- rc = i2c_w(ov, 0x0d, (val + 32768) >> 8);
- if (rc < 0)
- goto out;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- rc = -EPERM;
- goto out;
- }
-
- rc = 0; /* Success */
- ov->hue = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-
-/* Gets sensor's hue (red/blue balance) setting */
-static int
-sensor_get_hue(struct usb_ov511 *ov, unsigned short *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = i2c_r(ov, OV7610_REG_BLUE);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_OV7620:
- rc = i2c_r(ov, 0x7a);
- if (rc < 0)
- return rc;
- else
- *val = rc << 8;
- break;
- case SEN_SAA7111A:
- *val = ov->hue;
- break;
- default:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- }
-
- PDEBUG(3, "%d", *val);
- ov->hue = *val;
-
- return 0;
-}
-
-/* -------------------------------------------------------------------------- */
-
-static int
-sensor_set_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
- int rc;
-
- PDEBUG(4, "sensor_set_picture");
-
- ov->whiteness = p->whiteness;
-
- /* Don't return error if a setting is unsupported, or rest of settings
- * will not be performed */
-
- rc = sensor_set_contrast(ov, p->contrast);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_brightness(ov, p->brightness);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_saturation(ov, p->colour);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_hue(ov, p->hue);
- if (FATAL_ERROR(rc))
- return rc;
-
- return 0;
-}
-
-static int
-sensor_get_picture(struct usb_ov511 *ov, struct video_picture *p)
-{
- int rc;
-
- PDEBUG(4, "sensor_get_picture");
-
- /* Don't return error if a setting is unsupported, or rest of settings
- * will not be performed */
-
- rc = sensor_get_contrast(ov, &(p->contrast));
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_get_brightness(ov, &(p->brightness));
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_get_saturation(ov, &(p->colour));
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_get_hue(ov, &(p->hue));
- if (FATAL_ERROR(rc))
- return rc;
-
- p->whiteness = 105 << 8;
-
- return 0;
-}
-
-#if 0
-// FIXME: Exposure range is only 0x00-0x7f in interlace mode
-/* Sets current exposure for sensor. This only has an effect if auto-exposure
- * is off */
-static inline int
-sensor_set_exposure(struct usb_ov511 *ov, unsigned char val)
-{
- int rc;
-
- PDEBUG(3, "%d", val);
-
- if (ov->stop_during_set)
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- switch (ov->sensor) {
- case SEN_OV6620:
- case SEN_OV6630:
- case SEN_OV7610:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- rc = i2c_w(ov, 0x10, val);
- if (rc < 0)
- goto out;
-
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_exposure");
- return -EINVAL;
- }
-
- rc = 0; /* Success */
- ov->exposure = val;
-out:
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return rc;
-}
-#endif
-
-/* Gets current exposure level from sensor, regardless of whether it is under
- * manual control. */
-static int
-sensor_get_exposure(struct usb_ov511 *ov, unsigned char *val)
-{
- int rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV6620:
- case SEN_OV6630:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- rc = i2c_r(ov, 0x10);
- if (rc < 0)
- return rc;
- else
- *val = rc;
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- val = NULL;
- PDEBUG(3, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for get_exposure");
- return -EINVAL;
- }
-
- PDEBUG(3, "%d", *val);
- ov->exposure = *val;
-
- return 0;
-}
-
-/* Turns on or off the LED. Only has an effect with OV511+/OV518(+) */
-static void
-ov51x_led_control(struct usb_ov511 *ov, int enable)
-{
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- if (ov->bridge == BRG_OV511PLUS)
- reg_w(ov, R511_SYS_LED_CTL, enable ? 1 : 0);
- else if (ov->bclass == BCL_OV518)
- reg_w_mask(ov, R518_GPIO_OUT, enable ? 0x02 : 0x00, 0x02);
-
- return;
-}
-
-/* Matches the sensor's internal frame rate to the lighting frequency.
- * Valid frequencies are:
- * 50 - 50Hz, for European and Asian lighting
- * 60 - 60Hz, for American lighting
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_light_freq(struct usb_ov511 *ov, int freq)
-{
- int sixty;
-
- PDEBUG(4, "%d Hz", freq);
-
- if (freq == 60)
- sixty = 1;
- else if (freq == 50)
- sixty = 0;
- else {
- err("Invalid light freq (%d Hz)", freq);
- return -EINVAL;
- }
-
- switch (ov->sensor) {
- case SEN_OV7610:
- i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
- i2c_w(ov, 0x2b, sixty?0x00:0xac);
- i2c_w_mask(ov, 0x13, 0x10, 0x10);
- i2c_w_mask(ov, 0x13, 0x00, 0x10);
- break;
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- i2c_w_mask(ov, 0x2a, sixty?0x00:0x80, 0x80);
- i2c_w(ov, 0x2b, sixty?0x00:0xac);
- i2c_w_mask(ov, 0x76, 0x01, 0x01);
- break;
- case SEN_OV6620:
- case SEN_OV6630:
- i2c_w(ov, 0x2b, sixty?0xa8:0x28);
- i2c_w(ov, 0x2a, sixty?0x84:0xa4);
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_light_freq");
- return -EINVAL;
- }
-
- ov->lightfreq = freq;
-
- return 0;
-}
-
-/* If enable is true, turn on the sensor's banding filter, otherwise turn it
- * off. This filter tries to reduce the pattern of horizontal light/dark bands
- * caused by some (usually fluorescent) lighting. The light frequency must be
- * set either before or after enabling it with ov51x_set_light_freq().
- *
- * Tested with: OV7610, OV7620, OV76BE, OV6620.
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_banding_filter(struct usb_ov511 *ov, int enable)
-{
- int rc;
-
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
- || ov->sensor == SEN_SAA7111A) {
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- }
-
- rc = i2c_w_mask(ov, 0x2d, enable?0x04:0x00, 0x04);
- if (rc < 0)
- return rc;
-
- ov->bandfilt = enable;
-
- return 0;
-}
-
-/* If enable is true, turn on the sensor's auto brightness control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_brightness(struct usb_ov511 *ov, int enable)
-{
- int rc;
-
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- if (ov->sensor == SEN_KS0127 || ov->sensor == SEN_KS0127B
- || ov->sensor == SEN_SAA7111A) {
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- }
-
- rc = i2c_w_mask(ov, 0x2d, enable?0x10:0x00, 0x10);
- if (rc < 0)
- return rc;
-
- ov->auto_brt = enable;
-
- return 0;
-}
-
-/* If enable is true, turn on the sensor's auto exposure control, otherwise
- * turn it off.
- *
- * Unsupported: KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_auto_exposure(struct usb_ov511 *ov, int enable)
-{
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- switch (ov->sensor) {
- case SEN_OV7610:
- i2c_w_mask(ov, 0x29, enable?0x00:0x80, 0x80);
- break;
- case SEN_OV6620:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- i2c_w_mask(ov, 0x13, enable?0x01:0x00, 0x01);
- break;
- case SEN_OV6630:
- i2c_w_mask(ov, 0x28, enable?0x00:0x10, 0x10);
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_auto_exposure");
- return -EINVAL;
- }
-
- ov->auto_exp = enable;
-
- return 0;
-}
-
-/* Modifies the sensor's exposure algorithm to allow proper exposure of objects
- * that are illuminated from behind.
- *
- * Tested with: OV6620, OV7620
- * Unsupported: OV7610, OV76BE, KS0127, KS0127B, SAA7111A
- * Returns: 0 for success
- */
-static int
-sensor_set_backlight(struct usb_ov511 *ov, int enable)
-{
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- switch (ov->sensor) {
- case SEN_OV7620:
- case SEN_OV8600:
- i2c_w_mask(ov, 0x68, enable?0xe0:0xc0, 0xe0);
- i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
- i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
- break;
- case SEN_OV6620:
- i2c_w_mask(ov, 0x4e, enable?0xe0:0xc0, 0xe0);
- i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
- i2c_w_mask(ov, 0x0e, enable?0x80:0x00, 0x80);
- break;
- case SEN_OV6630:
- i2c_w_mask(ov, 0x4e, enable?0x80:0x60, 0xe0);
- i2c_w_mask(ov, 0x29, enable?0x08:0x00, 0x08);
- i2c_w_mask(ov, 0x28, enable?0x02:0x00, 0x02);
- break;
- case SEN_OV7610:
- case SEN_OV76BE:
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_backlight");
- return -EINVAL;
- }
-
- ov->backlight = enable;
-
- return 0;
-}
-
-static int
-sensor_set_mirror(struct usb_ov511 *ov, int enable)
-{
- PDEBUG(4, " (%s)", enable ? "turn on" : "turn off");
-
- switch (ov->sensor) {
- case SEN_OV6620:
- case SEN_OV6630:
- case SEN_OV7610:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- i2c_w_mask(ov, 0x12, enable?0x40:0x00, 0x40);
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- case SEN_SAA7111A:
- PDEBUG(5, "Unsupported with this sensor");
- return -EPERM;
- default:
- err("Sensor not supported for set_mirror");
- return -EINVAL;
- }
-
- ov->mirror = enable;
-
- return 0;
-}
-
-/* Returns number of bits per pixel (regardless of where they are located;
- * planar or not), or zero for unsupported format.
- */
-static inline int
-get_depth(int palette)
-{
- switch (palette) {
- case VIDEO_PALETTE_GREY: return 8;
- case VIDEO_PALETTE_YUV420: return 12;
- case VIDEO_PALETTE_YUV420P: return 12; /* Planar */
- default: return 0; /* Invalid format */
- }
-}
-
-/* Bytes per frame. Used by read(). Return of 0 indicates error */
-static inline long int
-get_frame_length(struct ov511_frame *frame)
-{
- if (!frame)
- return 0;
- else
- return ((frame->width * frame->height
- * get_depth(frame->format)) >> 3);
-}
-
-static int
-mode_init_ov_sensor_regs(struct usb_ov511 *ov, int width, int height,
- int mode, int sub_flag, int qvga)
-{
- int clock;
-
- /******** Mode (VGA/QVGA) and sensor specific regs ********/
-
- switch (ov->sensor) {
- case SEN_OV7610:
- i2c_w(ov, 0x14, qvga?0x24:0x04);
-// FIXME: Does this improve the image quality or frame rate?
-#if 0
- i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
- i2c_w(ov, 0x24, 0x10);
- i2c_w(ov, 0x25, qvga?0x40:0x8a);
- i2c_w(ov, 0x2f, qvga?0x30:0xb0);
- i2c_w(ov, 0x35, qvga?0x1c:0x9c);
-#endif
- break;
- case SEN_OV7620:
-// i2c_w(ov, 0x2b, 0x00);
- i2c_w(ov, 0x14, qvga?0xa4:0x84);
- i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
- i2c_w(ov, 0x24, qvga?0x20:0x3a);
- i2c_w(ov, 0x25, qvga?0x30:0x60);
- i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
- i2c_w_mask(ov, 0x67, qvga?0xf0:0x90, 0xf0);
- i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
- break;
- case SEN_OV76BE:
-// i2c_w(ov, 0x2b, 0x00);
- i2c_w(ov, 0x14, qvga?0xa4:0x84);
-// FIXME: Enable this once 7620AE uses 7620 initial settings
-#if 0
- i2c_w_mask(ov, 0x28, qvga?0x00:0x20, 0x20);
- i2c_w(ov, 0x24, qvga?0x20:0x3a);
- i2c_w(ov, 0x25, qvga?0x30:0x60);
- i2c_w_mask(ov, 0x2d, qvga?0x40:0x00, 0x40);
- i2c_w_mask(ov, 0x67, qvga?0xb0:0x90, 0xf0);
- i2c_w_mask(ov, 0x74, qvga?0x20:0x00, 0x20);
-#endif
- break;
- case SEN_OV6620:
- i2c_w(ov, 0x14, qvga?0x24:0x04);
- break;
- case SEN_OV6630:
- i2c_w(ov, 0x14, qvga?0xa0:0x80);
- break;
- default:
- err("Invalid sensor");
- return -EINVAL;
- }
-
- /******** Palette-specific regs ********/
-
- if (mode == VIDEO_PALETTE_GREY) {
- if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
- /* these aren't valid on the OV6620/OV7620/6630? */
- i2c_w_mask(ov, 0x0e, 0x40, 0x40);
- }
-
- if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
- && ov518_color) {
- i2c_w_mask(ov, 0x12, 0x00, 0x10);
- i2c_w_mask(ov, 0x13, 0x00, 0x20);
- } else {
- i2c_w_mask(ov, 0x13, 0x20, 0x20);
- }
- } else {
- if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
- /* not valid on the OV6620/OV7620/6630? */
- i2c_w_mask(ov, 0x0e, 0x00, 0x40);
- }
-
- /* The OV518 needs special treatment. Although both the OV518
- * and the OV6630 support a 16-bit video bus, only the 8 bit Y
- * bus is actually used. The UV bus is tied to ground.
- * Therefore, the OV6630 needs to be in 8-bit multiplexed
- * output mode */
-
- if (ov->sensor == SEN_OV6630 && ov->bridge == BRG_OV518
- && ov518_color) {
- i2c_w_mask(ov, 0x12, 0x10, 0x10);
- i2c_w_mask(ov, 0x13, 0x20, 0x20);
- } else {
- i2c_w_mask(ov, 0x13, 0x00, 0x20);
- }
- }
-
- /******** Clock programming ********/
-
- /* The OV6620 needs special handling. This prevents the
- * severe banding that normally occurs */
- if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630)
- {
- /* Clock down */
-
- i2c_w(ov, 0x2a, 0x04);
-
- if (ov->compress) {
-// clock = 0; /* This ensures the highest frame rate */
- clock = 3;
- } else if (clockdiv == -1) { /* If user didn't override it */
- clock = 3; /* Gives better exposure time */
- } else {
- clock = clockdiv;
- }
-
- PDEBUG(4, "Setting clock divisor to %d", clock);
-
- i2c_w(ov, 0x11, clock);
-
- i2c_w(ov, 0x2a, 0x84);
- /* This next setting is critical. It seems to improve
- * the gain or the contrast. The "reserved" bits seem
- * to have some effect in this case. */
- i2c_w(ov, 0x2d, 0x85);
- }
- else
- {
- if (ov->compress) {
- clock = 1; /* This ensures the highest frame rate */
- } else if (clockdiv == -1) { /* If user didn't override it */
- /* Calculate and set the clock divisor */
- clock = ((sub_flag ? ov->subw * ov->subh
- : width * height)
- * (mode == VIDEO_PALETTE_GREY ? 2 : 3) / 2)
- / 66000;
- } else {
- clock = clockdiv;
- }
-
- PDEBUG(4, "Setting clock divisor to %d", clock);
-
- i2c_w(ov, 0x11, clock);
- }
-
- /******** Special Features ********/
-
- if (framedrop >= 0)
- i2c_w(ov, 0x16, framedrop);
-
- /* Test Pattern */
- i2c_w_mask(ov, 0x12, (testpat?0x02:0x00), 0x02);
-
- /* Enable auto white balance */
- i2c_w_mask(ov, 0x12, 0x04, 0x04);
-
- // This will go away as soon as ov51x_mode_init_sensor_regs()
- // is fully tested.
- /* 7620/6620/6630? don't have register 0x35, so play it safe */
- if (ov->sensor == SEN_OV7610 || ov->sensor == SEN_OV76BE) {
- if (width == 640 && height == 480)
- i2c_w(ov, 0x35, 0x9e);
- else
- i2c_w(ov, 0x35, 0x1e);
- }
-
- return 0;
-}
-
-static int
-set_ov_sensor_window(struct usb_ov511 *ov, int width, int height, int mode,
- int sub_flag)
-{
- int ret;
- int hwsbase, hwebase, vwsbase, vwebase, hwsize, vwsize;
- int hoffset, voffset, hwscale = 0, vwscale = 0;
-
- /* The different sensor ICs handle setting up of window differently.
- * IF YOU SET IT WRONG, YOU WILL GET ALL ZERO ISOC DATA FROM OV51x!!! */
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV76BE:
- hwsbase = 0x38;
- hwebase = 0x3a;
- vwsbase = vwebase = 0x05;
- break;
- case SEN_OV6620:
- case SEN_OV6630:
- hwsbase = 0x38;
- hwebase = 0x3a;
- vwsbase = 0x05;
- vwebase = 0x06;
- break;
- case SEN_OV7620:
- hwsbase = 0x2f; /* From 7620.SET (spec is wrong) */
- hwebase = 0x2f;
- vwsbase = vwebase = 0x05;
- break;
- default:
- err("Invalid sensor");
- return -EINVAL;
- }
-
- if (ov->sensor == SEN_OV6620 || ov->sensor == SEN_OV6630) {
- /* Note: OV518(+) does downsample on its own) */
- if ((width > 176 && height > 144)
- || ov->bclass == BCL_OV518) { /* CIF */
- ret = mode_init_ov_sensor_regs(ov, width, height,
- mode, sub_flag, 0);
- if (ret < 0)
- return ret;
- hwscale = 1;
- vwscale = 1; /* The datasheet says 0; it's wrong */
- hwsize = 352;
- vwsize = 288;
- } else if (width > 176 || height > 144) {
- err("Illegal dimensions");
- return -EINVAL;
- } else { /* QCIF */
- ret = mode_init_ov_sensor_regs(ov, width, height,
- mode, sub_flag, 1);
- if (ret < 0)
- return ret;
- hwsize = 176;
- vwsize = 144;
- }
- } else {
- if (width > 320 && height > 240) { /* VGA */
- ret = mode_init_ov_sensor_regs(ov, width, height,
- mode, sub_flag, 0);
- if (ret < 0)
- return ret;
- hwscale = 2;
- vwscale = 1;
- hwsize = 640;
- vwsize = 480;
- } else if (width > 320 || height > 240) {
- err("Illegal dimensions");
- return -EINVAL;
- } else { /* QVGA */
- ret = mode_init_ov_sensor_regs(ov, width, height,
- mode, sub_flag, 1);
- if (ret < 0)
- return ret;
- hwscale = 1;
- hwsize = 320;
- vwsize = 240;
- }
- }
-
- /* Center the window */
- hoffset = ((hwsize - width) / 2) >> hwscale;
- voffset = ((vwsize - height) / 2) >> vwscale;
-
- /* FIXME! - This needs to be changed to support 160x120 and 6620!!! */
- if (sub_flag) {
- i2c_w(ov, 0x17, hwsbase+(ov->subx>>hwscale));
- i2c_w(ov, 0x18, hwebase+((ov->subx+ov->subw)>>hwscale));
- i2c_w(ov, 0x19, vwsbase+(ov->suby>>vwscale));
- i2c_w(ov, 0x1a, vwebase+((ov->suby+ov->subh)>>vwscale));
- } else {
- i2c_w(ov, 0x17, hwsbase + hoffset);
- i2c_w(ov, 0x18, hwebase + hoffset + (hwsize>>hwscale));
- i2c_w(ov, 0x19, vwsbase + voffset);
- i2c_w(ov, 0x1a, vwebase + voffset + (vwsize>>vwscale));
- }
-
-#ifdef OV511_DEBUG
- if (dump_sensor)
- dump_i2c_regs(ov);
-#endif
-
- return 0;
-}
-
-/* Set up the OV511/OV511+ with the given image parameters.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov511_mode_init_regs(struct usb_ov511 *ov,
- int width, int height, int mode, int sub_flag)
-{
- int hsegs, vsegs;
-
- if (sub_flag) {
- width = ov->subw;
- height = ov->subh;
- }
-
- PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
- width, height, mode, sub_flag);
-
- // FIXME: This should be moved to a 7111a-specific function once
- // subcapture is dealt with properly
- if (ov->sensor == SEN_SAA7111A) {
- if (width == 320 && height == 240) {
- /* No need to do anything special */
- } else if (width == 640 && height == 480) {
- /* Set the OV511 up as 320x480, but keep the
- * V4L resolution as 640x480 */
- width = 320;
- } else {
- err("SAA7111A only allows 320x240 or 640x480");
- return -EINVAL;
- }
- }
-
- /* Make sure width and height are a multiple of 8 */
- if (width % 8 || height % 8) {
- err("Invalid size (%d, %d) (mode = %d)", width, height, mode);
- return -EINVAL;
- }
-
- if (width < ov->minwidth || height < ov->minheight) {
- err("Requested dimensions are too small");
- return -EINVAL;
- }
-
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- if (mode == VIDEO_PALETTE_GREY) {
- reg_w(ov, R511_CAM_UV_EN, 0x00);
- reg_w(ov, R511_SNAP_UV_EN, 0x00);
- reg_w(ov, R511_SNAP_OPTS, 0x01);
- } else {
- reg_w(ov, R511_CAM_UV_EN, 0x01);
- reg_w(ov, R511_SNAP_UV_EN, 0x01);
- reg_w(ov, R511_SNAP_OPTS, 0x03);
- }
-
- /* Here I'm assuming that snapshot size == image size.
- * I hope that's always true. --claudio
- */
- hsegs = (width >> 3) - 1;
- vsegs = (height >> 3) - 1;
-
- reg_w(ov, R511_CAM_PXCNT, hsegs);
- reg_w(ov, R511_CAM_LNCNT, vsegs);
- reg_w(ov, R511_CAM_PXDIV, 0x00);
- reg_w(ov, R511_CAM_LNDIV, 0x00);
-
- /* YUV420, low pass filter on */
- reg_w(ov, R511_CAM_OPTS, 0x03);
-
- /* Snapshot additions */
- reg_w(ov, R511_SNAP_PXCNT, hsegs);
- reg_w(ov, R511_SNAP_LNCNT, vsegs);
- reg_w(ov, R511_SNAP_PXDIV, 0x00);
- reg_w(ov, R511_SNAP_LNDIV, 0x00);
-
- if (ov->compress) {
- /* Enable Y and UV quantization and compression */
- reg_w(ov, R511_COMP_EN, 0x07);
- reg_w(ov, R511_COMP_LUT_EN, 0x03);
- ov51x_reset(ov, OV511_RESET_OMNICE);
- }
-
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- return 0;
-}
-
-/* Sets up the OV518/OV518+ with the given image parameters
- *
- * OV518 needs a completely different approach, until we can figure out what
- * the individual registers do. Also, only 15 FPS is supported now.
- *
- * Do not put any sensor-specific code in here (including I2C I/O functions)
- */
-static int
-ov518_mode_init_regs(struct usb_ov511 *ov,
- int width, int height, int mode, int sub_flag)
-{
- int hsegs, vsegs, hi_res;
-
- if (sub_flag) {
- width = ov->subw;
- height = ov->subh;
- }
-
- PDEBUG(3, "width:%d, height:%d, mode:%d, sub:%d",
- width, height, mode, sub_flag);
-
- if (width % 16 || height % 8) {
- err("Invalid size (%d, %d)", width, height);
- return -EINVAL;
- }
-
- if (width < ov->minwidth || height < ov->minheight) {
- err("Requested dimensions are too small");
- return -EINVAL;
- }
-
- if (width >= 320 && height >= 240) {
- hi_res = 1;
- } else if (width >= 320 || height >= 240) {
- err("Invalid width/height combination (%d, %d)", width, height);
- return -EINVAL;
- } else {
- hi_res = 0;
- }
-
- if (ov51x_stop(ov) < 0)
- return -EIO;
-
- /******** Set the mode ********/
-
- reg_w(ov, 0x2b, 0);
- reg_w(ov, 0x2c, 0);
- reg_w(ov, 0x2d, 0);
- reg_w(ov, 0x2e, 0);
- reg_w(ov, 0x3b, 0);
- reg_w(ov, 0x3c, 0);
- reg_w(ov, 0x3d, 0);
- reg_w(ov, 0x3e, 0);
-
- if (ov->bridge == BRG_OV518 && ov518_color) {
- /* OV518 needs U and V swapped */
- i2c_w_mask(ov, 0x15, 0x00, 0x01);
-
- if (mode == VIDEO_PALETTE_GREY) {
- /* Set 16-bit input format (UV data are ignored) */
- reg_w_mask(ov, 0x20, 0x00, 0x08);
-
- /* Set 8-bit (4:0:0) output format */
- reg_w_mask(ov, 0x28, 0x00, 0xf0);
- reg_w_mask(ov, 0x38, 0x00, 0xf0);
- } else {
- /* Set 8-bit (YVYU) input format */
- reg_w_mask(ov, 0x20, 0x08, 0x08);
-
- /* Set 12-bit (4:2:0) output format */
- reg_w_mask(ov, 0x28, 0x80, 0xf0);
- reg_w_mask(ov, 0x38, 0x80, 0xf0);
- }
- } else {
- reg_w(ov, 0x28, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
- reg_w(ov, 0x38, (mode == VIDEO_PALETTE_GREY) ? 0x00:0x80);
- }
-
- hsegs = width / 16;
- vsegs = height / 4;
-
- reg_w(ov, 0x29, hsegs);
- reg_w(ov, 0x2a, vsegs);
-
- reg_w(ov, 0x39, hsegs);
- reg_w(ov, 0x3a, vsegs);
-
- /* Windows driver does this here; who knows why */
- reg_w(ov, 0x2f, 0x80);
-
- /******** Set the framerate (to 15 FPS) ********/
-
- /* Mode independent, but framerate dependent, regs */
- reg_w(ov, 0x51, 0x02); /* Clock divider; lower==faster */
- reg_w(ov, 0x22, 0x18);
- reg_w(ov, 0x23, 0xff);
-
- if (ov->bridge == BRG_OV518PLUS)
- reg_w(ov, 0x21, 0x19);
- else
- reg_w(ov, 0x71, 0x19); /* Compression-related? */
-
- // FIXME: Sensor-specific
- /* Bit 5 is what matters here. Of course, it is "reserved" */
- i2c_w(ov, 0x54, 0x23);
-
- reg_w(ov, 0x2f, 0x80);
-
- if (ov->bridge == BRG_OV518PLUS) {
- reg_w(ov, 0x24, 0x94);
- reg_w(ov, 0x25, 0x90);
- ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */
- ov518_reg_w32(ov, 0xc6, 540, 2); /* 21ch */
- ov518_reg_w32(ov, 0xc7, 540, 2); /* 21ch */
- ov518_reg_w32(ov, 0xc8, 108, 2); /* 6ch */
- ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */
- ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */
- ov518_reg_w32(ov, 0xcc, 2400, 2); /* 960h */
- ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */
- ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */
- } else {
- reg_w(ov, 0x24, 0x9f);
- reg_w(ov, 0x25, 0x90);
- ov518_reg_w32(ov, 0xc4, 400, 2); /* 190h */
- ov518_reg_w32(ov, 0xc6, 500, 2); /* 1f4h */
- ov518_reg_w32(ov, 0xc7, 500, 2); /* 1f4h */
- ov518_reg_w32(ov, 0xc8, 142, 2); /* 8eh */
- ov518_reg_w32(ov, 0xca, 131098, 3); /* 2001ah */
- ov518_reg_w32(ov, 0xcb, 532, 2); /* 214h */
- ov518_reg_w32(ov, 0xcc, 2000, 2); /* 7d0h */
- ov518_reg_w32(ov, 0xcd, 32, 2); /* 20h */
- ov518_reg_w32(ov, 0xce, 608, 2); /* 260h */
- }
-
- reg_w(ov, 0x2f, 0x80);
-
- if (ov51x_restart(ov) < 0)
- return -EIO;
-
- /* Reset it just for good measure */
- if (ov51x_reset(ov, OV511_RESET_NOREGS) < 0)
- return -EIO;
-
- return 0;
-}
-
-/* This is a wrapper around the OV511, OV518, and sensor specific functions */
-static int
-mode_init_regs(struct usb_ov511 *ov,
- int width, int height, int mode, int sub_flag)
-{
- int rc = 0;
-
- if (!ov || !ov->dev)
- return -EFAULT;
-
- if (ov->bclass == BCL_OV518) {
- rc = ov518_mode_init_regs(ov, width, height, mode, sub_flag);
- } else {
- rc = ov511_mode_init_regs(ov, width, height, mode, sub_flag);
- }
-
- if (FATAL_ERROR(rc))
- return rc;
-
- switch (ov->sensor) {
- case SEN_OV7610:
- case SEN_OV7620:
- case SEN_OV76BE:
- case SEN_OV8600:
- case SEN_OV6620:
- case SEN_OV6630:
- rc = set_ov_sensor_window(ov, width, height, mode, sub_flag);
- break;
- case SEN_KS0127:
- case SEN_KS0127B:
- err("KS0127-series decoders not supported yet");
- rc = -EINVAL;
- break;
- case SEN_SAA7111A:
-// rc = mode_init_saa_sensor_regs(ov, width, height, mode,
-// sub_flag);
-
- PDEBUG(1, "SAA status = 0x%02X", i2c_r(ov, 0x1f));
- break;
- default:
- err("Unknown sensor");
- rc = -EINVAL;
- }
-
- if (FATAL_ERROR(rc))
- return rc;
-
- /* Sensor-independent settings */
- rc = sensor_set_auto_brightness(ov, ov->auto_brt);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_auto_exposure(ov, ov->auto_exp);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_banding_filter(ov, bandingfilter);
- if (FATAL_ERROR(rc))
- return rc;
-
- if (ov->lightfreq) {
- rc = sensor_set_light_freq(ov, lightfreq);
- if (FATAL_ERROR(rc))
- return rc;
- }
-
- rc = sensor_set_backlight(ov, ov->backlight);
- if (FATAL_ERROR(rc))
- return rc;
-
- rc = sensor_set_mirror(ov, ov->mirror);
- if (FATAL_ERROR(rc))
- return rc;
-
- return 0;
-}
-
-/* This sets the default image parameters. This is useful for apps that use
- * read() and do not set these.
- */
-static int
-ov51x_set_default_params(struct usb_ov511 *ov)
-{
- int i;
-
- /* Set default sizes in case IOCTL (VIDIOCMCAPTURE) is not used
- * (using read() instead). */
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].width = ov->maxwidth;
- ov->frame[i].height = ov->maxheight;
- ov->frame[i].bytes_read = 0;
- if (force_palette)
- ov->frame[i].format = force_palette;
- else
- ov->frame[i].format = VIDEO_PALETTE_YUV420;
-
- ov->frame[i].depth = get_depth(ov->frame[i].format);
- }
-
- PDEBUG(3, "%dx%d, %s", ov->maxwidth, ov->maxheight,
- symbolic(v4l1_plist, ov->frame[0].format));
-
- /* Initialize to max width/height, YUV420 or RGB24 (if supported) */
- if (mode_init_regs(ov, ov->maxwidth, ov->maxheight,
- ov->frame[0].format, 0) < 0)
- return -EINVAL;
-
- return 0;
-}
-
-/**********************************************************************
- *
- * Video decoder stuff
- *
- **********************************************************************/
-
-/* Set analog input port of decoder */
-static int
-decoder_set_input(struct usb_ov511 *ov, int input)
-{
- PDEBUG(4, "port %d", input);
-
- switch (ov->sensor) {
- case SEN_SAA7111A:
- {
- /* Select mode */
- i2c_w_mask(ov, 0x02, input, 0x07);
- /* Bypass chrominance trap for modes 4..7 */
- i2c_w_mask(ov, 0x09, (input > 3) ? 0x80:0x00, 0x80);
- break;
- }
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/* Get ASCII name of video input */
-static int
-decoder_get_input_name(struct usb_ov511 *ov, int input, char *name)
-{
- switch (ov->sensor) {
- case SEN_SAA7111A:
- {
- if (input < 0 || input > 7)
- return -EINVAL;
- else if (input < 4)
- sprintf(name, "CVBS-%d", input);
- else // if (input < 8)
- sprintf(name, "S-Video-%d", input - 4);
- break;
- }
- default:
- sprintf(name, "%s", "Camera");
- }
-
- return 0;
-}
-
-/* Set norm (NTSC, PAL, SECAM, AUTO) */
-static int
-decoder_set_norm(struct usb_ov511 *ov, int norm)
-{
- PDEBUG(4, "%d", norm);
-
- switch (ov->sensor) {
- case SEN_SAA7111A:
- {
- int reg_8, reg_e;
-
- if (norm == VIDEO_MODE_NTSC) {
- reg_8 = 0x40; /* 60 Hz */
- reg_e = 0x00; /* NTSC M / PAL BGHI */
- } else if (norm == VIDEO_MODE_PAL) {
- reg_8 = 0x00; /* 50 Hz */
- reg_e = 0x00; /* NTSC M / PAL BGHI */
- } else if (norm == VIDEO_MODE_AUTO) {
- reg_8 = 0x80; /* Auto field detect */
- reg_e = 0x00; /* NTSC M / PAL BGHI */
- } else if (norm == VIDEO_MODE_SECAM) {
- reg_8 = 0x00; /* 50 Hz */
- reg_e = 0x50; /* SECAM / PAL 4.43 */
- } else {
- return -EINVAL;
- }
-
- i2c_w_mask(ov, 0x08, reg_8, 0xc0);
- i2c_w_mask(ov, 0x0e, reg_e, 0x70);
- break;
- }
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-/**********************************************************************
- *
- * Raw data parsing
- *
- **********************************************************************/
-
-/* Copies a 64-byte segment at pIn to an 8x8 block at pOut. The width of the
- * image at pOut is specified by w.
- */
-static inline void
-make_8x8(unsigned char *pIn, unsigned char *pOut, int w)
-{
- unsigned char *pOut1 = pOut;
- int x, y;
-
- for (y = 0; y < 8; y++) {
- pOut1 = pOut;
- for (x = 0; x < 8; x++) {
- *pOut1++ = *pIn++;
- }
- pOut += w;
- }
-}
-
-/*
- * For RAW BW (YUV 4:0:0) images, data show up in 256 byte segments.
- * The segments represent 4 squares of 8x8 pixels as follows:
- *
- * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
- * 8 9 ... 15 72 73 ... 79 200 201 ... 207
- * ... ... ...
- * 56 57 ... 63 120 121 ... 127 248 249 ... 255
- *
- */
-static void
-yuv400raw_to_yuv400p(struct ov511_frame *frame,
- unsigned char *pIn0, unsigned char *pOut0)
-{
- int x, y;
- unsigned char *pIn, *pOut, *pOutLine;
-
- /* Copy Y */
- pIn = pIn0;
- pOutLine = pOut0;
- for (y = 0; y < frame->rawheight - 1; y += 8) {
- pOut = pOutLine;
- for (x = 0; x < frame->rawwidth - 1; x += 8) {
- make_8x8(pIn, pOut, frame->rawwidth);
- pIn += 64;
- pOut += 8;
- }
- pOutLine += 8 * frame->rawwidth;
- }
-}
-
-/*
- * For YUV 4:2:0 images, the data show up in 384 byte segments.
- * The first 64 bytes of each segment are U, the next 64 are V. The U and
- * V are arranged as follows:
- *
- * 0 1 ... 7
- * 8 9 ... 15
- * ...
- * 56 57 ... 63
- *
- * U and V are shipped at half resolution (1 U,V sample -> one 2x2 block).
- *
- * The next 256 bytes are full resolution Y data and represent 4 squares
- * of 8x8 pixels as follows:
- *
- * 0 1 ... 7 64 65 ... 71 ... 192 193 ... 199
- * 8 9 ... 15 72 73 ... 79 200 201 ... 207
- * ... ... ...
- * 56 57 ... 63 120 121 ... 127 ... 248 249 ... 255
- *
- * Note that the U and V data in one segment represent a 16 x 16 pixel
- * area, but the Y data represent a 32 x 8 pixel area. If the width is not an
- * even multiple of 32, the extra 8x8 blocks within a 32x8 block belong to the
- * next horizontal stripe.
- *
- * If dumppix module param is set, _parse_data just dumps the incoming segments,
- * verbatim, in order, into the frame. When used with vidcat -f ppm -s 640x480
- * this puts the data on the standard output and can be analyzed with the
- * parseppm.c utility I wrote. That's a much faster way for figuring out how
- * these data are scrambled.
- */
-
-/* Converts from raw, uncompressed segments at pIn0 to a YUV420P frame at pOut0.
- *
- * FIXME: Currently only handles width and height that are multiples of 16
- */
-static void
-yuv420raw_to_yuv420p(struct ov511_frame *frame,
- unsigned char *pIn0, unsigned char *pOut0)
-{
- int k, x, y;
- unsigned char *pIn, *pOut, *pOutLine;
- const unsigned int a = frame->rawwidth * frame->rawheight;
- const unsigned int w = frame->rawwidth / 2;
-
- /* Copy U and V */
- pIn = pIn0;
- pOutLine = pOut0 + a;
- for (y = 0; y < frame->rawheight - 1; y += 16) {
- pOut = pOutLine;
- for (x = 0; x < frame->rawwidth - 1; x += 16) {
- make_8x8(pIn, pOut, w);
- make_8x8(pIn + 64, pOut + a/4, w);
- pIn += 384;
- pOut += 8;
- }
- pOutLine += 8 * w;
- }
-
- /* Copy Y */
- pIn = pIn0 + 128;
- pOutLine = pOut0;
- k = 0;
- for (y = 0; y < frame->rawheight - 1; y += 8) {
- pOut = pOutLine;
- for (x = 0; x < frame->rawwidth - 1; x += 8) {
- make_8x8(pIn, pOut, frame->rawwidth);
- pIn += 64;
- pOut += 8;
- if ((++k) > 3) {
- k = 0;
- pIn += 128;
- }
- }
- pOutLine += 8 * frame->rawwidth;
- }
-}
-
-/**********************************************************************
- *
- * Decompression
- *
- **********************************************************************/
-
-static int
-request_decompressor(struct usb_ov511 *ov)
-{
- if (ov->bclass == BCL_OV511 || ov->bclass == BCL_OV518) {
- err("No decompressor available");
- } else {
- err("Unknown bridge");
- }
-
- return -ENOSYS;
-}
-
-static void
-decompress(struct usb_ov511 *ov, struct ov511_frame *frame,
- unsigned char *pIn0, unsigned char *pOut0)
-{
- if (!ov->decomp_ops)
- if (request_decompressor(ov))
- return;
-
-}
-
-/**********************************************************************
- *
- * Format conversion
- *
- **********************************************************************/
-
-/* Fuses even and odd fields together, and doubles width.
- * INPUT: an odd field followed by an even field at pIn0, in YUV planar format
- * OUTPUT: a normal YUV planar image, with correct aspect ratio
- */
-static void
-deinterlace(struct ov511_frame *frame, int rawformat,
- unsigned char *pIn0, unsigned char *pOut0)
-{
- const int fieldheight = frame->rawheight / 2;
- const int fieldpix = fieldheight * frame->rawwidth;
- const int w = frame->width;
- int x, y;
- unsigned char *pInEven, *pInOdd, *pOut;
-
- PDEBUG(5, "fieldheight=%d", fieldheight);
-
- if (frame->rawheight != frame->height) {
- err("invalid height");
- return;
- }
-
- if ((frame->rawwidth * 2) != frame->width) {
- err("invalid width");
- return;
- }
-
- /* Y */
- pInOdd = pIn0;
- pInEven = pInOdd + fieldpix;
- pOut = pOut0;
- for (y = 0; y < fieldheight; y++) {
- for (x = 0; x < frame->rawwidth; x++) {
- *pOut = *pInEven;
- *(pOut+1) = *pInEven++;
- *(pOut+w) = *pInOdd;
- *(pOut+w+1) = *pInOdd++;
- pOut += 2;
- }
- pOut += w;
- }
-
- if (rawformat == RAWFMT_YUV420) {
- /* U */
- pInOdd = pIn0 + fieldpix * 2;
- pInEven = pInOdd + fieldpix / 4;
- for (y = 0; y < fieldheight / 2; y++) {
- for (x = 0; x < frame->rawwidth / 2; x++) {
- *pOut = *pInEven;
- *(pOut+1) = *pInEven++;
- *(pOut+w/2) = *pInOdd;
- *(pOut+w/2+1) = *pInOdd++;
- pOut += 2;
- }
- pOut += w/2;
- }
- /* V */
- pInOdd = pIn0 + fieldpix * 2 + fieldpix / 2;
- pInEven = pInOdd + fieldpix / 4;
- for (y = 0; y < fieldheight / 2; y++) {
- for (x = 0; x < frame->rawwidth / 2; x++) {
- *pOut = *pInEven;
- *(pOut+1) = *pInEven++;
- *(pOut+w/2) = *pInOdd;
- *(pOut+w/2+1) = *pInOdd++;
- pOut += 2;
- }
- pOut += w/2;
- }
- }
-}
-
-static void
-ov51x_postprocess_grey(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
- /* Deinterlace frame, if necessary */
- if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
- if (frame->compressed)
- decompress(ov, frame, frame->rawdata,
- frame->tempdata);
- else
- yuv400raw_to_yuv400p(frame, frame->rawdata,
- frame->tempdata);
-
- deinterlace(frame, RAWFMT_YUV400, frame->tempdata,
- frame->data);
- } else {
- if (frame->compressed)
- decompress(ov, frame, frame->rawdata,
- frame->data);
- else
- yuv400raw_to_yuv400p(frame, frame->rawdata,
- frame->data);
- }
-}
-
-/* Process raw YUV420 data into standard YUV420P */
-static void
-ov51x_postprocess_yuv420(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
- /* Deinterlace frame, if necessary */
- if (ov->sensor == SEN_SAA7111A && frame->rawheight >= 480) {
- if (frame->compressed)
- decompress(ov, frame, frame->rawdata, frame->tempdata);
- else
- yuv420raw_to_yuv420p(frame, frame->rawdata,
- frame->tempdata);
-
- deinterlace(frame, RAWFMT_YUV420, frame->tempdata,
- frame->data);
- } else {
- if (frame->compressed)
- decompress(ov, frame, frame->rawdata, frame->data);
- else
- yuv420raw_to_yuv420p(frame, frame->rawdata,
- frame->data);
- }
-}
-
-/* Post-processes the specified frame. This consists of:
- * 1. Decompress frame, if necessary
- * 2. Deinterlace frame and scale to proper size, if necessary
- * 3. Convert from YUV planar to destination format, if necessary
- * 4. Fix the RGB offset, if necessary
- */
-static void
-ov51x_postprocess(struct usb_ov511 *ov, struct ov511_frame *frame)
-{
- if (dumppix) {
- memset(frame->data, 0,
- MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
- PDEBUG(4, "Dumping %d bytes", frame->bytes_recvd);
- memcpy(frame->data, frame->rawdata, frame->bytes_recvd);
- } else {
- switch (frame->format) {
- case VIDEO_PALETTE_GREY:
- ov51x_postprocess_grey(ov, frame);
- break;
- case VIDEO_PALETTE_YUV420:
- case VIDEO_PALETTE_YUV420P:
- ov51x_postprocess_yuv420(ov, frame);
- break;
- default:
- err("Cannot convert data to %s",
- symbolic(v4l1_plist, frame->format));
- }
- }
-}
-
-/**********************************************************************
- *
- * OV51x data transfer, IRQ handler
- *
- **********************************************************************/
-
-static inline void
-ov511_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
- int num, offset;
- int pnum = in[ov->packet_size - 1]; /* Get packet number */
- int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
- struct ov511_frame *frame = &ov->frame[ov->curframe];
- struct timeval *ts;
-
- /* SOF/EOF packets have 1st to 8th bytes zeroed and the 9th
- * byte non-zero. The EOF packet has image width/height in the
- * 10th and 11th bytes. The 9th byte is given as follows:
- *
- * bit 7: EOF
- * 6: compression enabled
- * 5: 422/420/400 modes
- * 4: 422/420/400 modes
- * 3: 1
- * 2: snapshot button on
- * 1: snapshot frame
- * 0: even/odd field
- */
-
- if (printph) {
- dev_info(&ov->dev->dev,
- "ph(%3d): %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x %2x\n",
- pnum, in[0], in[1], in[2], in[3], in[4], in[5], in[6],
- in[7], in[8], in[9], in[10], in[11]);
- }
-
- /* Check for SOF/EOF packet */
- if ((in[0] | in[1] | in[2] | in[3] | in[4] | in[5] | in[6] | in[7]) ||
- (~in[8] & 0x08))
- goto check_middle;
-
- /* Frame end */
- if (in[8] & 0x80) {
- ts = (struct timeval *)(frame->data
- + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
- do_gettimeofday(ts);
-
- /* Get the actual frame size from the EOF header */
- frame->rawwidth = ((int)(in[9]) + 1) * 8;
- frame->rawheight = ((int)(in[10]) + 1) * 8;
-
- PDEBUG(4, "Frame end, frame=%d, pnum=%d, w=%d, h=%d, recvd=%d",
- ov->curframe, pnum, frame->rawwidth, frame->rawheight,
- frame->bytes_recvd);
-
- /* Validate the header data */
- RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
- RESTRICT_TO_RANGE(frame->rawheight, ov->minheight,
- ov->maxheight);
-
- /* Don't allow byte count to exceed buffer size */
- RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
- if (frame->scanstate == STATE_LINES) {
- int nextf;
-
- frame->grabstate = FRAME_DONE;
- wake_up_interruptible(&frame->wq);
-
- /* If next frame is ready or grabbing,
- * point to it */
- nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
- if (ov->frame[nextf].grabstate == FRAME_READY
- || ov->frame[nextf].grabstate == FRAME_GRABBING) {
- ov->curframe = nextf;
- ov->frame[nextf].scanstate = STATE_SCANNING;
- } else {
- if (frame->grabstate == FRAME_DONE) {
- PDEBUG(4, "** Frame done **");
- } else {
- PDEBUG(4, "Frame not ready? state = %d",
- ov->frame[nextf].grabstate);
- }
-
- ov->curframe = -1;
- }
- } else {
- PDEBUG(5, "Frame done, but not scanning");
- }
- /* Image corruption caused by misplaced frame->segment = 0
- * fixed by carlosf@conectiva.com.br
- */
- } else {
- /* Frame start */
- PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
-
- /* Check to see if it's a snapshot frame */
- /* FIXME?? Should the snapshot reset go here? Performance? */
- if (in[8] & 0x02) {
- frame->snapshot = 1;
- PDEBUG(3, "snapshot detected");
- }
-
- frame->scanstate = STATE_LINES;
- frame->bytes_recvd = 0;
- frame->compressed = in[8] & 0x40;
- }
-
-check_middle:
- /* Are we in a frame? */
- if (frame->scanstate != STATE_LINES) {
- PDEBUG(5, "Not in a frame; packet skipped");
- return;
- }
-
- /* If frame start, skip header */
- if (frame->bytes_recvd == 0)
- offset = 9;
- else
- offset = 0;
-
- num = n - offset - 1;
-
- /* Dump all data exactly as received */
- if (dumppix == 2) {
- frame->bytes_recvd += n - 1;
- if (frame->bytes_recvd <= max_raw)
- memcpy(frame->rawdata + frame->bytes_recvd - (n - 1),
- in, n - 1);
- else
- PDEBUG(3, "Raw data buffer overrun!! (%d)",
- frame->bytes_recvd - max_raw);
- } else if (!frame->compressed && !remove_zeros) {
- frame->bytes_recvd += num;
- if (frame->bytes_recvd <= max_raw)
- memcpy(frame->rawdata + frame->bytes_recvd - num,
- in + offset, num);
- else
- PDEBUG(3, "Raw data buffer overrun!! (%d)",
- frame->bytes_recvd - max_raw);
- } else { /* Remove all-zero FIFO lines (aligned 32-byte blocks) */
- int b, read = 0, allzero, copied = 0;
- if (offset) {
- frame->bytes_recvd += 32 - offset; // Bytes out
- memcpy(frame->rawdata, in + offset, 32 - offset);
- read += 32;
- }
-
- while (read < n - 1) {
- allzero = 1;
- for (b = 0; b < 32; b++) {
- if (in[read + b]) {
- allzero = 0;
- break;
- }
- }
-
- if (allzero) {
- /* Don't copy it */
- } else {
- if (frame->bytes_recvd + copied + 32 <= max_raw)
- {
- memcpy(frame->rawdata
- + frame->bytes_recvd + copied,
- in + read, 32);
- copied += 32;
- } else {
- PDEBUG(3, "Raw data buffer overrun!!");
- }
- }
- read += 32;
- }
-
- frame->bytes_recvd += copied;
- }
-}
-
-static inline void
-ov518_move_data(struct usb_ov511 *ov, unsigned char *in, int n)
-{
- int max_raw = MAX_RAW_DATA_SIZE(ov->maxwidth, ov->maxheight);
- struct ov511_frame *frame = &ov->frame[ov->curframe];
- struct timeval *ts;
-
- /* Don't copy the packet number byte */
- if (ov->packet_numbering)
- --n;
-
- /* A false positive here is likely, until OVT gives me
- * the definitive SOF/EOF format */
- if ((!(in[0] | in[1] | in[2] | in[3] | in[5])) && in[6]) {
- if (printph) {
- dev_info(&ov->dev->dev,
- "ph: %2x %2x %2x %2x %2x %2x %2x %2x\n",
- in[0], in[1], in[2], in[3], in[4], in[5],
- in[6], in[7]);
- }
-
- if (frame->scanstate == STATE_LINES) {
- PDEBUG(4, "Detected frame end/start");
- goto eof;
- } else { //scanstate == STATE_SCANNING
- /* Frame start */
- PDEBUG(4, "Frame start, framenum = %d", ov->curframe);
- goto sof;
- }
- } else {
- goto check_middle;
- }
-
-eof:
- ts = (struct timeval *)(frame->data
- + MAX_FRAME_SIZE(ov->maxwidth, ov->maxheight));
- do_gettimeofday(ts);
-
- PDEBUG(4, "Frame end, curframe = %d, hw=%d, vw=%d, recvd=%d",
- ov->curframe,
- (int)(in[9]), (int)(in[10]), frame->bytes_recvd);
-
- // FIXME: Since we don't know the header formats yet,
- // there is no way to know what the actual image size is
- frame->rawwidth = frame->width;
- frame->rawheight = frame->height;
-
- /* Validate the header data */
- RESTRICT_TO_RANGE(frame->rawwidth, ov->minwidth, ov->maxwidth);
- RESTRICT_TO_RANGE(frame->rawheight, ov->minheight, ov->maxheight);
-
- /* Don't allow byte count to exceed buffer size */
- RESTRICT_TO_RANGE(frame->bytes_recvd, 8, max_raw);
-
- if (frame->scanstate == STATE_LINES) {
- int nextf;
-
- frame->grabstate = FRAME_DONE;
- wake_up_interruptible(&frame->wq);
-
- /* If next frame is ready or grabbing,
- * point to it */
- nextf = (ov->curframe + 1) % OV511_NUMFRAMES;
- if (ov->frame[nextf].grabstate == FRAME_READY
- || ov->frame[nextf].grabstate == FRAME_GRABBING) {
- ov->curframe = nextf;
- ov->frame[nextf].scanstate = STATE_SCANNING;
- frame = &ov->frame[nextf];
- } else {
- if (frame->grabstate == FRAME_DONE) {
- PDEBUG(4, "** Frame done **");
- } else {
- PDEBUG(4, "Frame not ready? state = %d",
- ov->frame[nextf].grabstate);
- }
-
- ov->curframe = -1;
- PDEBUG(4, "SOF dropped (no active frame)");
- return; /* Nowhere to store this frame */
- }
- }
-sof:
- PDEBUG(4, "Starting capture on frame %d", frame->framenum);
-
-// Snapshot not reverse-engineered yet.
-#if 0
- /* Check to see if it's a snapshot frame */
- /* FIXME?? Should the snapshot reset go here? Performance? */
- if (in[8] & 0x02) {
- frame->snapshot = 1;
- PDEBUG(3, "snapshot detected");
- }
-#endif
- frame->scanstate = STATE_LINES;
- frame->bytes_recvd = 0;
- frame->compressed = 1;
-
-check_middle:
- /* Are we in a frame? */
- if (frame->scanstate != STATE_LINES) {
- PDEBUG(4, "scanstate: no SOF yet");
- return;
- }
-
- /* Dump all data exactly as received */
- if (dumppix == 2) {
- frame->bytes_recvd += n;
- if (frame->bytes_recvd <= max_raw)
- memcpy(frame->rawdata + frame->bytes_recvd - n, in, n);
- else
- PDEBUG(3, "Raw data buffer overrun!! (%d)",
- frame->bytes_recvd - max_raw);
- } else {
- /* All incoming data are divided into 8-byte segments. If the
- * segment contains all zero bytes, it must be skipped. These
- * zero-segments allow the OV518 to mainain a constant data rate
- * regardless of the effectiveness of the compression. Segments
- * are aligned relative to the beginning of each isochronous
- * packet. The first segment in each image is a header (the
- * decompressor skips it later).
- */
-
- int b, read = 0, allzero, copied = 0;
-
- while (read < n) {
- allzero = 1;
- for (b = 0; b < 8; b++) {
- if (in[read + b]) {
- allzero = 0;
- break;
- }
- }
-
- if (allzero) {
- /* Don't copy it */
- } else {
- if (frame->bytes_recvd + copied + 8 <= max_raw)
- {
- memcpy(frame->rawdata
- + frame->bytes_recvd + copied,
- in + read, 8);
- copied += 8;
- } else {
- PDEBUG(3, "Raw data buffer overrun!!");
- }
- }
- read += 8;
- }
- frame->bytes_recvd += copied;
- }
-}
-
-static void
-ov51x_isoc_irq(struct urb *urb)
-{
- int i;
- struct usb_ov511 *ov;
- struct ov511_sbuf *sbuf;
-
- if (!urb->context) {
- PDEBUG(4, "no context");
- return;
- }
-
- sbuf = urb->context;
- ov = sbuf->ov;
-
- if (!ov || !ov->dev || !ov->user) {
- PDEBUG(4, "no device, or not open");
- return;
- }
-
- if (!ov->streaming) {
- PDEBUG(4, "hmmm... not streaming, but got interrupt");
- return;
- }
-
- if (urb->status == -ENOENT || urb->status == -ECONNRESET) {
- PDEBUG(4, "URB unlinked");
- return;
- }
-
- if (urb->status != -EINPROGRESS && urb->status != 0) {
- err("ERROR: urb->status=%d: %s", urb->status,
- symbolic(urb_errlist, urb->status));
- }
-
- /* Copy the data received into our frame buffer */
- PDEBUG(5, "sbuf[%d]: Moving %d packets", sbuf->n,
- urb->number_of_packets);
- for (i = 0; i < urb->number_of_packets; i++) {
- /* Warning: Don't call *_move_data() if no frame active! */
- if (ov->curframe >= 0) {
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
- unsigned char *cdata;
-
- urb->iso_frame_desc[i].actual_length = 0;
- urb->iso_frame_desc[i].status = 0;
-
- cdata = urb->transfer_buffer
- + urb->iso_frame_desc[i].offset;
-
- if (!n) {
- PDEBUG(4, "Zero-length packet");
- continue;
- }
-
- if (st)
- PDEBUG(2, "data error: [%d] len=%d, status=%d",
- i, n, st);
-
- if (ov->bclass == BCL_OV511)
- ov511_move_data(ov, cdata, n);
- else if (ov->bclass == BCL_OV518)
- ov518_move_data(ov, cdata, n);
- else
- err("Unknown bridge device (%d)", ov->bridge);
-
- } else if (waitqueue_active(&ov->wq)) {
- wake_up_interruptible(&ov->wq);
- }
- }
-
- /* Resubmit this URB */
- urb->dev = ov->dev;
- if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
- err("usb_submit_urb() ret %d", i);
-
- return;
-}
-
-/****************************************************************************
- *
- * Stream initialization and termination
- *
- ***************************************************************************/
-
-static int
-ov51x_init_isoc(struct usb_ov511 *ov)
-{
- struct urb *urb;
- int fx, err, n, i, size;
-
- PDEBUG(3, "*** Initializing capture ***");
-
- ov->curframe = -1;
-
- if (ov->bridge == BRG_OV511) {
- if (cams == 1)
- size = 993;
- else if (cams == 2)
- size = 513;
- else if (cams == 3 || cams == 4)
- size = 257;
- else {
- err("\"cams\" parameter too high!");
- return -1;
- }
- } else if (ov->bridge == BRG_OV511PLUS) {
- if (cams == 1)
- size = 961;
- else if (cams == 2)
- size = 513;
- else if (cams == 3 || cams == 4)
- size = 257;
- else if (cams >= 5 && cams <= 8)
- size = 129;
- else if (cams >= 9 && cams <= 31)
- size = 33;
- else {
- err("\"cams\" parameter too high!");
- return -1;
- }
- } else if (ov->bclass == BCL_OV518) {
- if (cams == 1)
- size = 896;
- else if (cams == 2)
- size = 512;
- else if (cams == 3 || cams == 4)
- size = 256;
- else if (cams >= 5 && cams <= 8)
- size = 128;
- else {
- err("\"cams\" parameter too high!");
- return -1;
- }
- } else {
- err("invalid bridge type");
- return -1;
- }
-
- // FIXME: OV518 is hardcoded to 15 FPS (alternate 5) for now
- if (ov->bclass == BCL_OV518) {
- if (packetsize == -1) {
- ov518_set_packet_size(ov, 640);
- } else {
- dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
- packetsize);
- ov518_set_packet_size(ov, packetsize);
- }
- } else {
- if (packetsize == -1) {
- ov511_set_packet_size(ov, size);
- } else {
- dev_info(&ov->dev->dev, "Forcing packet size to %d\n",
- packetsize);
- ov511_set_packet_size(ov, packetsize);
- }
- }
-
- for (n = 0; n < OV511_NUMSBUF; n++) {
- urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if (!urb) {
- err("init isoc: usb_alloc_urb ret. NULL");
- for (i = 0; i < n; i++)
- usb_free_urb(ov->sbuf[i].urb);
- return -ENOMEM;
- }
- ov->sbuf[n].urb = urb;
- urb->dev = ov->dev;
- urb->context = &ov->sbuf[n];
- urb->pipe = usb_rcvisocpipe(ov->dev, OV511_ENDPOINT_ADDRESS);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = ov->sbuf[n].data;
- urb->complete = ov51x_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = ov->packet_size * FRAMES_PER_DESC;
- urb->interval = 1;
- for (fx = 0; fx < FRAMES_PER_DESC; fx++) {
- urb->iso_frame_desc[fx].offset = ov->packet_size * fx;
- urb->iso_frame_desc[fx].length = ov->packet_size;
- }
- }
-
- ov->streaming = 1;
-
- for (n = 0; n < OV511_NUMSBUF; n++) {
- ov->sbuf[n].urb->dev = ov->dev;
- err = usb_submit_urb(ov->sbuf[n].urb, GFP_KERNEL);
- if (err) {
- err("init isoc: usb_submit_urb(%d) ret %d", n, err);
- return err;
- }
- }
-
- return 0;
-}
-
-static void
-ov51x_unlink_isoc(struct usb_ov511 *ov)
-{
- int n;
-
- /* Unschedule all of the iso td's */
- for (n = OV511_NUMSBUF - 1; n >= 0; n--) {
- if (ov->sbuf[n].urb) {
- usb_kill_urb(ov->sbuf[n].urb);
- usb_free_urb(ov->sbuf[n].urb);
- ov->sbuf[n].urb = NULL;
- }
- }
-}
-
-static void
-ov51x_stop_isoc(struct usb_ov511 *ov)
-{
- if (!ov->streaming || !ov->dev)
- return;
-
- PDEBUG(3, "*** Stopping capture ***");
-
- if (ov->bclass == BCL_OV518)
- ov518_set_packet_size(ov, 0);
- else
- ov511_set_packet_size(ov, 0);
-
- ov->streaming = 0;
-
- ov51x_unlink_isoc(ov);
-}
-
-static int
-ov51x_new_frame(struct usb_ov511 *ov, int framenum)
-{
- struct ov511_frame *frame;
- int newnum;
-
- PDEBUG(4, "ov->curframe = %d, framenum = %d", ov->curframe, framenum);
-
- if (!ov->dev)
- return -1;
-
- /* If we're not grabbing a frame right now and the other frame is */
- /* ready to be grabbed into, then use it instead */
- if (ov->curframe == -1) {
- newnum = (framenum - 1 + OV511_NUMFRAMES) % OV511_NUMFRAMES;
- if (ov->frame[newnum].grabstate == FRAME_READY)
- framenum = newnum;
- } else
- return 0;
-
- frame = &ov->frame[framenum];
-
- PDEBUG(4, "framenum = %d, width = %d, height = %d", framenum,
- frame->width, frame->height);
-
- frame->grabstate = FRAME_GRABBING;
- frame->scanstate = STATE_SCANNING;
- frame->snapshot = 0;
-
- ov->curframe = framenum;
-
- /* Make sure it's not too big */
- if (frame->width > ov->maxwidth)
- frame->width = ov->maxwidth;
-
- frame->width &= ~7L; /* Multiple of 8 */
-
- if (frame->height > ov->maxheight)
- frame->height = ov->maxheight;
-
- frame->height &= ~3L; /* Multiple of 4 */
-
- return 0;
-}
-
-/****************************************************************************
- *
- * Buffer management
- *
- ***************************************************************************/
-
-/*
- * - You must acquire buf_lock before entering this function.
- * - Because this code will free any non-null pointer, you must be sure to null
- * them if you explicitly free them somewhere else!
- */
-static void
-ov51x_do_dealloc(struct usb_ov511 *ov)
-{
- int i;
- PDEBUG(4, "entered");
-
- if (ov->fbuf) {
- rvfree(ov->fbuf, OV511_NUMFRAMES
- * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight));
- ov->fbuf = NULL;
- }
-
- vfree(ov->rawfbuf);
- ov->rawfbuf = NULL;
-
- vfree(ov->tempfbuf);
- ov->tempfbuf = NULL;
-
- for (i = 0; i < OV511_NUMSBUF; i++) {
- kfree(ov->sbuf[i].data);
- ov->sbuf[i].data = NULL;
- }
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].data = NULL;
- ov->frame[i].rawdata = NULL;
- ov->frame[i].tempdata = NULL;
- if (ov->frame[i].compbuf) {
- free_page((unsigned long) ov->frame[i].compbuf);
- ov->frame[i].compbuf = NULL;
- }
- }
-
- PDEBUG(4, "buffer memory deallocated");
- ov->buf_state = BUF_NOT_ALLOCATED;
- PDEBUG(4, "leaving");
-}
-
-static int
-ov51x_alloc(struct usb_ov511 *ov)
-{
- int i;
- const int w = ov->maxwidth;
- const int h = ov->maxheight;
- const int data_bufsize = OV511_NUMFRAMES * MAX_DATA_SIZE(w, h);
- const int raw_bufsize = OV511_NUMFRAMES * MAX_RAW_DATA_SIZE(w, h);
-
- PDEBUG(4, "entered");
- mutex_lock(&ov->buf_lock);
-
- if (ov->buf_state == BUF_ALLOCATED)
- goto out;
-
- ov->fbuf = rvmalloc(data_bufsize);
- if (!ov->fbuf)
- goto error;
-
- ov->rawfbuf = vmalloc(raw_bufsize);
- if (!ov->rawfbuf)
- goto error;
-
- memset(ov->rawfbuf, 0, raw_bufsize);
-
- ov->tempfbuf = vmalloc(raw_bufsize);
- if (!ov->tempfbuf)
- goto error;
-
- memset(ov->tempfbuf, 0, raw_bufsize);
-
- for (i = 0; i < OV511_NUMSBUF; i++) {
- ov->sbuf[i].data = kmalloc(FRAMES_PER_DESC *
- MAX_FRAME_SIZE_PER_DESC, GFP_KERNEL);
- if (!ov->sbuf[i].data)
- goto error;
-
- PDEBUG(4, "sbuf[%d] @ %p", i, ov->sbuf[i].data);
- }
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].data = ov->fbuf + i * MAX_DATA_SIZE(w, h);
- ov->frame[i].rawdata = ov->rawfbuf
- + i * MAX_RAW_DATA_SIZE(w, h);
- ov->frame[i].tempdata = ov->tempfbuf
- + i * MAX_RAW_DATA_SIZE(w, h);
-
- ov->frame[i].compbuf =
- (unsigned char *) __get_free_page(GFP_KERNEL);
- if (!ov->frame[i].compbuf)
- goto error;
-
- PDEBUG(4, "frame[%d] @ %p", i, ov->frame[i].data);
- }
-
- ov->buf_state = BUF_ALLOCATED;
-out:
- mutex_unlock(&ov->buf_lock);
- PDEBUG(4, "leaving");
- return 0;
-error:
- ov51x_do_dealloc(ov);
- mutex_unlock(&ov->buf_lock);
- PDEBUG(4, "errored");
- return -ENOMEM;
-}
-
-static void
-ov51x_dealloc(struct usb_ov511 *ov)
-{
- PDEBUG(4, "entered");
- mutex_lock(&ov->buf_lock);
- ov51x_do_dealloc(ov);
- mutex_unlock(&ov->buf_lock);
- PDEBUG(4, "leaving");
-}
-
-/****************************************************************************
- *
- * V4L 1 API
- *
- ***************************************************************************/
-
-static int
-ov51x_v4l1_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- int err, i;
-
- PDEBUG(4, "opening");
-
- mutex_lock(&ov->lock);
-
- err = -EBUSY;
- if (ov->user)
- goto out;
-
- ov->sub_flag = 0;
-
- /* In case app doesn't set them... */
- err = ov51x_set_default_params(ov);
- if (err < 0)
- goto out;
-
- /* Make sure frames are reset */
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].grabstate = FRAME_UNUSED;
- ov->frame[i].bytes_read = 0;
- }
-
- /* If compression is on, make sure now that a
- * decompressor can be loaded */
- if (ov->compress && !ov->decomp_ops) {
- err = request_decompressor(ov);
- if (err && !dumppix)
- goto out;
- }
-
- err = ov51x_alloc(ov);
- if (err < 0)
- goto out;
-
- err = ov51x_init_isoc(ov);
- if (err) {
- ov51x_dealloc(ov);
- goto out;
- }
-
- ov->user++;
- file->private_data = vdev;
-
- if (ov->led_policy == LED_AUTO)
- ov51x_led_control(ov, 1);
-
-out:
- mutex_unlock(&ov->lock);
- return err;
-}
-
-static int
-ov51x_v4l1_close(struct file *file)
-{
- struct video_device *vdev = file->private_data;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
-
- PDEBUG(4, "ov511_close");
-
- mutex_lock(&ov->lock);
-
- ov->user--;
- ov51x_stop_isoc(ov);
-
- if (ov->led_policy == LED_AUTO)
- ov51x_led_control(ov, 0);
-
- if (ov->dev)
- ov51x_dealloc(ov);
-
- mutex_unlock(&ov->lock);
-
- /* Device unplugged while open. Only a minimum of unregistration is done
- * here; the disconnect callback already did the rest. */
- if (!ov->dev) {
- mutex_lock(&ov->cbuf_lock);
- kfree(ov->cbuf);
- ov->cbuf = NULL;
- mutex_unlock(&ov->cbuf_lock);
-
- ov51x_dealloc(ov);
- kfree(ov);
- ov = NULL;
- }
-
- file->private_data = NULL;
- return 0;
-}
-
-/* Do not call this function directly! */
-static long
-ov51x_v4l1_ioctl_internal(struct file *file, unsigned int cmd, void *arg)
-{
- struct video_device *vdev = file->private_data;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- PDEBUG(5, "IOCtl: 0x%X", cmd);
-
- if (!ov->dev)
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
-
- PDEBUG(4, "VIDIOCGCAP");
-
- memset(b, 0, sizeof(struct video_capability));
- sprintf(b->name, "%s USB Camera",
- symbolic(brglist, ov->bridge));
- b->type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE;
- b->channels = ov->num_inputs;
- b->audios = 0;
- b->maxwidth = ov->maxwidth;
- b->maxheight = ov->maxheight;
- b->minwidth = ov->minwidth;
- b->minheight = ov->minheight;
-
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- PDEBUG(4, "VIDIOCGCHAN");
-
- if ((unsigned)(v->channel) >= ov->num_inputs) {
- err("Invalid channel (%d)", v->channel);
- return -EINVAL;
- }
-
- v->norm = ov->norm;
- v->type = VIDEO_TYPE_CAMERA;
- v->flags = 0;
-// v->flags |= (ov->has_decoder) ? VIDEO_VC_NORM : 0;
- v->tuners = 0;
- decoder_get_input_name(ov, v->channel, v->name);
-
- return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
- int err;
-
- PDEBUG(4, "VIDIOCSCHAN");
-
- /* Make sure it's not a camera */
- if (!ov->has_decoder) {
- if (v->channel == 0)
- return 0;
- else
- return -EINVAL;
- }
-
- if (v->norm != VIDEO_MODE_PAL &&
- v->norm != VIDEO_MODE_NTSC &&
- v->norm != VIDEO_MODE_SECAM &&
- v->norm != VIDEO_MODE_AUTO) {
- err("Invalid norm (%d)", v->norm);
- return -EINVAL;
- }
-
- if ((unsigned)(v->channel) >= ov->num_inputs) {
- err("Invalid channel (%d)", v->channel);
- return -EINVAL;
- }
-
- err = decoder_set_input(ov, v->channel);
- if (err)
- return err;
-
- err = decoder_set_norm(ov, v->norm);
- if (err)
- return err;
-
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
-
- PDEBUG(4, "VIDIOCGPICT");
-
- memset(p, 0, sizeof(struct video_picture));
- if (sensor_get_picture(ov, p))
- return -EIO;
-
- /* Can we get these from frame[0]? -claudio? */
- p->depth = ov->frame[0].depth;
- p->palette = ov->frame[0].format;
-
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
- int i, rc;
-
- PDEBUG(4, "VIDIOCSPICT");
-
- if (!get_depth(p->palette))
- return -EINVAL;
-
- if (sensor_set_picture(ov, p))
- return -EIO;
-
- if (force_palette && p->palette != force_palette) {
- dev_info(&ov->dev->dev, "Palette rejected (%s)\n",
- symbolic(v4l1_plist, p->palette));
- return -EINVAL;
- }
-
- // FIXME: Format should be independent of frames
- if (p->palette != ov->frame[0].format) {
- PDEBUG(4, "Detected format change");
-
- rc = ov51x_wait_frames_inactive(ov);
- if (rc)
- return rc;
-
- mode_init_regs(ov, ov->frame[0].width,
- ov->frame[0].height, p->palette, ov->sub_flag);
- }
-
- PDEBUG(4, "Setting depth=%d, palette=%s",
- p->depth, symbolic(v4l1_plist, p->palette));
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].depth = p->depth;
- ov->frame[i].format = p->palette;
- }
-
- return 0;
- }
- case VIDIOCGCAPTURE:
- {
- int *vf = arg;
-
- PDEBUG(4, "VIDIOCGCAPTURE");
-
- ov->sub_flag = *vf;
- return 0;
- }
- case VIDIOCSCAPTURE:
- {
- struct video_capture *vc = arg;
-
- PDEBUG(4, "VIDIOCSCAPTURE");
-
- if (vc->flags)
- return -EINVAL;
- if (vc->decimation)
- return -EINVAL;
-
- vc->x &= ~3L;
- vc->y &= ~1L;
- vc->y &= ~31L;
-
- if (vc->width == 0)
- vc->width = 32;
-
- vc->height /= 16;
- vc->height *= 16;
- if (vc->height == 0)
- vc->height = 16;
-
- ov->subx = vc->x;
- ov->suby = vc->y;
- ov->subw = vc->width;
- ov->subh = vc->height;
-
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
- int i, rc;
-
- PDEBUG(4, "VIDIOCSWIN: %dx%d", vw->width, vw->height);
-
-#if 0
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->height != ov->maxheight)
- return -EINVAL;
- if (vw->width != ov->maxwidth)
- return -EINVAL;
-#endif
-
- rc = ov51x_wait_frames_inactive(ov);
- if (rc)
- return rc;
-
- rc = mode_init_regs(ov, vw->width, vw->height,
- ov->frame[0].format, ov->sub_flag);
- if (rc < 0)
- return rc;
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].width = vw->width;
- ov->frame[i].height = vw->height;
- }
-
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
-
- memset(vw, 0, sizeof(struct video_window));
- vw->x = 0; /* FIXME */
- vw->y = 0;
- vw->width = ov->frame[0].width;
- vw->height = ov->frame[0].height;
- vw->flags = 30;
-
- PDEBUG(4, "VIDIOCGWIN: %dx%d", vw->width, vw->height);
-
- return 0;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf *vm = arg;
- int i;
-
- PDEBUG(4, "VIDIOCGMBUF");
-
- memset(vm, 0, sizeof(struct video_mbuf));
- vm->size = OV511_NUMFRAMES
- * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
- vm->frames = OV511_NUMFRAMES;
-
- vm->offsets[0] = 0;
- for (i = 1; i < OV511_NUMFRAMES; i++) {
- vm->offsets[i] = vm->offsets[i-1]
- + MAX_DATA_SIZE(ov->maxwidth, ov->maxheight);
- }
-
- return 0;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap *vm = arg;
- int rc, depth;
- unsigned int f = vm->frame;
-
- PDEBUG(4, "VIDIOCMCAPTURE: frame: %d, %dx%d, %s", f, vm->width,
- vm->height, symbolic(v4l1_plist, vm->format));
-
- depth = get_depth(vm->format);
- if (!depth) {
- PDEBUG(2, "VIDIOCMCAPTURE: invalid format (%s)",
- symbolic(v4l1_plist, vm->format));
- return -EINVAL;
- }
-
- if (f >= OV511_NUMFRAMES) {
- err("VIDIOCMCAPTURE: invalid frame (%d)", f);
- return -EINVAL;
- }
-
- if (vm->width > ov->maxwidth
- || vm->height > ov->maxheight) {
- err("VIDIOCMCAPTURE: requested dimensions too big");
- return -EINVAL;
- }
-
- if (ov->frame[f].grabstate == FRAME_GRABBING) {
- PDEBUG(4, "VIDIOCMCAPTURE: already grabbing");
- return -EBUSY;
- }
-
- if (force_palette && (vm->format != force_palette)) {
- PDEBUG(2, "palette rejected (%s)",
- symbolic(v4l1_plist, vm->format));
- return -EINVAL;
- }
-
- if ((ov->frame[f].width != vm->width) ||
- (ov->frame[f].height != vm->height) ||
- (ov->frame[f].format != vm->format) ||
- (ov->frame[f].sub_flag != ov->sub_flag) ||
- (ov->frame[f].depth != depth)) {
- PDEBUG(4, "VIDIOCMCAPTURE: change in image parameters");
-
- rc = ov51x_wait_frames_inactive(ov);
- if (rc)
- return rc;
-
- rc = mode_init_regs(ov, vm->width, vm->height,
- vm->format, ov->sub_flag);
-#if 0
- if (rc < 0) {
- PDEBUG(1, "Got error while initializing regs ");
- return ret;
- }
-#endif
- ov->frame[f].width = vm->width;
- ov->frame[f].height = vm->height;
- ov->frame[f].format = vm->format;
- ov->frame[f].sub_flag = ov->sub_flag;
- ov->frame[f].depth = depth;
- }
-
- /* Mark it as ready */
- ov->frame[f].grabstate = FRAME_READY;
-
- PDEBUG(4, "VIDIOCMCAPTURE: renewing frame %d", f);
-
- return ov51x_new_frame(ov, f);
- }
- case VIDIOCSYNC:
- {
- unsigned int fnum = *((unsigned int *) arg);
- struct ov511_frame *frame;
- int rc;
-
- if (fnum >= OV511_NUMFRAMES) {
- err("VIDIOCSYNC: invalid frame (%d)", fnum);
- return -EINVAL;
- }
-
- frame = &ov->frame[fnum];
-
- PDEBUG(4, "syncing to frame %d, grabstate = %d", fnum,
- frame->grabstate);
-
- switch (frame->grabstate) {
- case FRAME_UNUSED:
- return -EINVAL;
- case FRAME_READY:
- case FRAME_GRABBING:
- case FRAME_ERROR:
-redo:
- if (!ov->dev)
- return -EIO;
-
- rc = wait_event_interruptible(frame->wq,
- (frame->grabstate == FRAME_DONE)
- || (frame->grabstate == FRAME_ERROR));
-
- if (rc)
- return rc;
-
- if (frame->grabstate == FRAME_ERROR) {
- if ((rc = ov51x_new_frame(ov, fnum)) < 0)
- return rc;
- goto redo;
- }
- /* Fall through */
- case FRAME_DONE:
- if (ov->snap_enabled && !frame->snapshot) {
- if ((rc = ov51x_new_frame(ov, fnum)) < 0)
- return rc;
- goto redo;
- }
-
- frame->grabstate = FRAME_UNUSED;
-
- /* Reset the hardware snapshot button */
- /* FIXME - Is this the best place for this? */
- if ((ov->snap_enabled) && (frame->snapshot)) {
- frame->snapshot = 0;
- ov51x_clear_snapshot(ov);
- }
-
- /* Decompression, format conversion, etc... */
- ov51x_postprocess(ov, frame);
-
- break;
- } /* end switch */
-
- return 0;
- }
- case VIDIOCGFBUF:
- {
- struct video_buffer *vb = arg;
-
- PDEBUG(4, "VIDIOCGFBUF");
-
- memset(vb, 0, sizeof(struct video_buffer));
-
- return 0;
- }
- case VIDIOCGUNIT:
- {
- struct video_unit *vu = arg;
-
- PDEBUG(4, "VIDIOCGUNIT");
-
- memset(vu, 0, sizeof(struct video_unit));
-
- vu->video = ov->vdev->minor;
- vu->vbi = VIDEO_NO_UNIT;
- vu->radio = VIDEO_NO_UNIT;
- vu->audio = VIDEO_NO_UNIT;
- vu->teletext = VIDEO_NO_UNIT;
-
- return 0;
- }
- case OV511IOC_WI2C:
- {
- struct ov511_i2c_struct *w = arg;
-
- return i2c_w_slave(ov, w->slave, w->reg, w->value, w->mask);
- }
- case OV511IOC_RI2C:
- {
- struct ov511_i2c_struct *r = arg;
- int rc;
-
- rc = i2c_r_slave(ov, r->slave, r->reg);
- if (rc < 0)
- return rc;
-
- r->value = rc;
- return 0;
- }
- default:
- PDEBUG(3, "Unsupported IOCtl: 0x%X", cmd);
- return -ENOIOCTLCMD;
- } /* end switch */
-
- return 0;
-}
-
-static long
-ov51x_v4l1_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct video_device *vdev = file->private_data;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- int rc;
-
- if (mutex_lock_interruptible(&ov->lock))
- return -EINTR;
-
- rc = video_usercopy(file, cmd, arg, ov51x_v4l1_ioctl_internal);
-
- mutex_unlock(&ov->lock);
- return rc;
-}
-
-static ssize_t
-ov51x_v4l1_read(struct file *file, char __user *buf, size_t cnt, loff_t *ppos)
-{
- struct video_device *vdev = file->private_data;
- int noblock = file->f_flags&O_NONBLOCK;
- unsigned long count = cnt;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- int i, rc = 0, frmx = -1;
- struct ov511_frame *frame;
-
- if (mutex_lock_interruptible(&ov->lock))
- return -EINTR;
-
- PDEBUG(4, "%ld bytes, noblock=%d", count, noblock);
-
- if (!vdev || !buf) {
- rc = -EFAULT;
- goto error;
- }
-
- if (!ov->dev) {
- rc = -EIO;
- goto error;
- }
-
-// FIXME: Only supports two frames
- /* See if a frame is completed, then use it. */
- if (ov->frame[0].grabstate >= FRAME_DONE) /* _DONE or _ERROR */
- frmx = 0;
- else if (ov->frame[1].grabstate >= FRAME_DONE)/* _DONE or _ERROR */
- frmx = 1;
-
- /* If nonblocking we return immediately */
- if (noblock && (frmx == -1)) {
- rc = -EAGAIN;
- goto error;
- }
-
- /* If no FRAME_DONE, look for a FRAME_GRABBING state. */
- /* See if a frame is in process (grabbing), then use it. */
- if (frmx == -1) {
- if (ov->frame[0].grabstate == FRAME_GRABBING)
- frmx = 0;
- else if (ov->frame[1].grabstate == FRAME_GRABBING)
- frmx = 1;
- }
-
- /* If no frame is active, start one. */
- if (frmx == -1) {
- if ((rc = ov51x_new_frame(ov, frmx = 0))) {
- err("read: ov51x_new_frame error");
- goto error;
- }
- }
-
- frame = &ov->frame[frmx];
-
-restart:
- if (!ov->dev) {
- rc = -EIO;
- goto error;
- }
-
- /* Wait while we're grabbing the image */
- PDEBUG(4, "Waiting image grabbing");
- rc = wait_event_interruptible(frame->wq,
- (frame->grabstate == FRAME_DONE)
- || (frame->grabstate == FRAME_ERROR));
-
- if (rc)
- goto error;
-
- PDEBUG(4, "Got image, frame->grabstate = %d", frame->grabstate);
- PDEBUG(4, "bytes_recvd = %d", frame->bytes_recvd);
-
- if (frame->grabstate == FRAME_ERROR) {
- frame->bytes_read = 0;
- err("** ick! ** Errored frame %d", ov->curframe);
- if (ov51x_new_frame(ov, frmx)) {
- err("read: ov51x_new_frame error");
- goto error;
- }
- goto restart;
- }
-
-
- /* Repeat until we get a snapshot frame */
- if (ov->snap_enabled)
- PDEBUG(4, "Waiting snapshot frame");
- if (ov->snap_enabled && !frame->snapshot) {
- frame->bytes_read = 0;
- if ((rc = ov51x_new_frame(ov, frmx))) {
- err("read: ov51x_new_frame error");
- goto error;
- }
- goto restart;
- }
-
- /* Clear the snapshot */
- if (ov->snap_enabled && frame->snapshot) {
- frame->snapshot = 0;
- ov51x_clear_snapshot(ov);
- }
-
- /* Decompression, format conversion, etc... */
- ov51x_postprocess(ov, frame);
-
- PDEBUG(4, "frmx=%d, bytes_read=%ld, length=%ld", frmx,
- frame->bytes_read,
- get_frame_length(frame));
-
- /* copy bytes to user space; we allow for partials reads */
-// if ((count + frame->bytes_read)
-// > get_frame_length((struct ov511_frame *)frame))
-// count = frame->scanlength - frame->bytes_read;
-
- /* FIXME - count hardwired to be one frame... */
- count = get_frame_length(frame);
-
- PDEBUG(4, "Copy to user space: %ld bytes", count);
- if ((i = copy_to_user(buf, frame->data + frame->bytes_read, count))) {
- PDEBUG(4, "Copy failed! %d bytes not copied", i);
- rc = -EFAULT;
- goto error;
- }
-
- frame->bytes_read += count;
- PDEBUG(4, "{copy} count used=%ld, new bytes_read=%ld",
- count, frame->bytes_read);
-
- /* If all data have been read... */
- if (frame->bytes_read
- >= get_frame_length(frame)) {
- frame->bytes_read = 0;
-
-// FIXME: Only supports two frames
- /* Mark it as available to be used again. */
- ov->frame[frmx].grabstate = FRAME_UNUSED;
- if ((rc = ov51x_new_frame(ov, !frmx))) {
- err("ov51x_new_frame returned error");
- goto error;
- }
- }
-
- PDEBUG(4, "read finished, returning %ld (sweet)", count);
-
- mutex_unlock(&ov->lock);
- return count;
-
-error:
- mutex_unlock(&ov->lock);
- return rc;
-}
-
-static int
-ov51x_v4l1_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *vdev = file->private_data;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end - vma->vm_start;
- struct usb_ov511 *ov = video_get_drvdata(vdev);
- unsigned long page, pos;
-
- if (ov->dev == NULL)
- return -EIO;
-
- PDEBUG(4, "mmap: %ld (%lX) bytes", size, size);
-
- if (size > (((OV511_NUMFRAMES
- * MAX_DATA_SIZE(ov->maxwidth, ov->maxheight)
- + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1))))
- return -EINVAL;
-
- if (mutex_lock_interruptible(&ov->lock))
- return -EINTR;
-
- pos = (unsigned long)ov->fbuf;
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&ov->lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- mutex_unlock(&ov->lock);
- return 0;
-}
-
-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,
-};
-
-static struct video_device vdev_template = {
- .name = "OV511 USB Camera",
- .fops = &ov511_fops,
- .release = video_device_release,
-};
-
-/****************************************************************************
- *
- * OV511 and sensor configuration
- *
- ***************************************************************************/
-
-/* This initializes the OV7610, OV7620, or OV76BE sensor. The OV76BE uses
- * the same register settings as the OV7610, since they are very similar.
- */
-static int
-ov7xx0_configure(struct usb_ov511 *ov)
-{
- int i, success;
- int rc;
-
- /* Lawrence Glaister <lg@jfm.bc.ca> reports:
- *
- * Register 0x0f in the 7610 has the following effects:
- *
- * 0x85 (AEC method 1): Best overall, good contrast range
- * 0x45 (AEC method 2): Very overexposed
- * 0xa5 (spec sheet default): Ok, but the black level is
- * shifted resulting in loss of contrast
- * 0x05 (old driver setting): very overexposed, too much
- * contrast
- */
- static struct ov511_regvals aRegvalsNorm7610[] = {
- { OV511_I2C_BUS, 0x10, 0xff },
- { OV511_I2C_BUS, 0x16, 0x06 },
- { OV511_I2C_BUS, 0x28, 0x24 },
- { OV511_I2C_BUS, 0x2b, 0xac },
- { OV511_I2C_BUS, 0x12, 0x00 },
- { OV511_I2C_BUS, 0x38, 0x81 },
- { OV511_I2C_BUS, 0x28, 0x24 }, /* 0c */
- { OV511_I2C_BUS, 0x0f, 0x85 }, /* lg's setting */
- { OV511_I2C_BUS, 0x15, 0x01 },
- { OV511_I2C_BUS, 0x20, 0x1c },
- { OV511_I2C_BUS, 0x23, 0x2a },
- { OV511_I2C_BUS, 0x24, 0x10 },
- { OV511_I2C_BUS, 0x25, 0x8a },
- { OV511_I2C_BUS, 0x26, 0xa2 },
- { OV511_I2C_BUS, 0x27, 0xc2 },
- { OV511_I2C_BUS, 0x2a, 0x04 },
- { OV511_I2C_BUS, 0x2c, 0xfe },
- { OV511_I2C_BUS, 0x2d, 0x93 },
- { OV511_I2C_BUS, 0x30, 0x71 },
- { OV511_I2C_BUS, 0x31, 0x60 },
- { OV511_I2C_BUS, 0x32, 0x26 },
- { OV511_I2C_BUS, 0x33, 0x20 },
- { OV511_I2C_BUS, 0x34, 0x48 },
- { OV511_I2C_BUS, 0x12, 0x24 },
- { OV511_I2C_BUS, 0x11, 0x01 },
- { OV511_I2C_BUS, 0x0c, 0x24 },
- { OV511_I2C_BUS, 0x0d, 0x24 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- static struct ov511_regvals aRegvalsNorm7620[] = {
- { OV511_I2C_BUS, 0x00, 0x00 },
- { OV511_I2C_BUS, 0x01, 0x80 },
- { OV511_I2C_BUS, 0x02, 0x80 },
- { OV511_I2C_BUS, 0x03, 0xc0 },
- { OV511_I2C_BUS, 0x06, 0x60 },
- { OV511_I2C_BUS, 0x07, 0x00 },
- { OV511_I2C_BUS, 0x0c, 0x24 },
- { OV511_I2C_BUS, 0x0c, 0x24 },
- { OV511_I2C_BUS, 0x0d, 0x24 },
- { OV511_I2C_BUS, 0x11, 0x01 },
- { OV511_I2C_BUS, 0x12, 0x24 },
- { OV511_I2C_BUS, 0x13, 0x01 },
- { OV511_I2C_BUS, 0x14, 0x84 },
- { OV511_I2C_BUS, 0x15, 0x01 },
- { OV511_I2C_BUS, 0x16, 0x03 },
- { OV511_I2C_BUS, 0x17, 0x2f },
- { OV511_I2C_BUS, 0x18, 0xcf },
- { OV511_I2C_BUS, 0x19, 0x06 },
- { OV511_I2C_BUS, 0x1a, 0xf5 },
- { OV511_I2C_BUS, 0x1b, 0x00 },
- { OV511_I2C_BUS, 0x20, 0x18 },
- { OV511_I2C_BUS, 0x21, 0x80 },
- { OV511_I2C_BUS, 0x22, 0x80 },
- { OV511_I2C_BUS, 0x23, 0x00 },
- { OV511_I2C_BUS, 0x26, 0xa2 },
- { OV511_I2C_BUS, 0x27, 0xea },
- { OV511_I2C_BUS, 0x28, 0x20 },
- { OV511_I2C_BUS, 0x29, 0x00 },
- { OV511_I2C_BUS, 0x2a, 0x10 },
- { OV511_I2C_BUS, 0x2b, 0x00 },
- { OV511_I2C_BUS, 0x2c, 0x88 },
- { OV511_I2C_BUS, 0x2d, 0x91 },
- { OV511_I2C_BUS, 0x2e, 0x80 },
- { OV511_I2C_BUS, 0x2f, 0x44 },
- { OV511_I2C_BUS, 0x60, 0x27 },
- { OV511_I2C_BUS, 0x61, 0x02 },
- { OV511_I2C_BUS, 0x62, 0x5f },
- { OV511_I2C_BUS, 0x63, 0xd5 },
- { OV511_I2C_BUS, 0x64, 0x57 },
- { OV511_I2C_BUS, 0x65, 0x83 },
- { OV511_I2C_BUS, 0x66, 0x55 },
- { OV511_I2C_BUS, 0x67, 0x92 },
- { OV511_I2C_BUS, 0x68, 0xcf },
- { OV511_I2C_BUS, 0x69, 0x76 },
- { OV511_I2C_BUS, 0x6a, 0x22 },
- { OV511_I2C_BUS, 0x6b, 0x00 },
- { OV511_I2C_BUS, 0x6c, 0x02 },
- { OV511_I2C_BUS, 0x6d, 0x44 },
- { OV511_I2C_BUS, 0x6e, 0x80 },
- { OV511_I2C_BUS, 0x6f, 0x1d },
- { OV511_I2C_BUS, 0x70, 0x8b },
- { OV511_I2C_BUS, 0x71, 0x00 },
- { OV511_I2C_BUS, 0x72, 0x14 },
- { OV511_I2C_BUS, 0x73, 0x54 },
- { OV511_I2C_BUS, 0x74, 0x00 },
- { OV511_I2C_BUS, 0x75, 0x8e },
- { OV511_I2C_BUS, 0x76, 0x00 },
- { OV511_I2C_BUS, 0x77, 0xff },
- { OV511_I2C_BUS, 0x78, 0x80 },
- { OV511_I2C_BUS, 0x79, 0x80 },
- { OV511_I2C_BUS, 0x7a, 0x80 },
- { OV511_I2C_BUS, 0x7b, 0xe2 },
- { OV511_I2C_BUS, 0x7c, 0x00 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- PDEBUG(4, "starting configuration");
-
- /* This looks redundant, but is necessary for WebCam 3 */
- ov->primary_i2c_slave = OV7xx0_SID;
- if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
- return -1;
-
- if (init_ov_sensor(ov) >= 0) {
- PDEBUG(1, "OV7xx0 sensor initalized (method 1)");
- } else {
- /* Reset the 76xx */
- if (i2c_w(ov, 0x12, 0x80) < 0)
- return -1;
-
- /* Wait for it to initialize */
- msleep(150);
-
- i = 0;
- success = 0;
- while (i <= i2c_detect_tries) {
- if ((i2c_r(ov, OV7610_REG_ID_HIGH) == 0x7F) &&
- (i2c_r(ov, OV7610_REG_ID_LOW) == 0xA2)) {
- success = 1;
- break;
- } else {
- i++;
- }
- }
-
-// Was (i == i2c_detect_tries) previously. This obviously used to always report
-// success. Whether anyone actually depended on that bug is unknown
- if ((i >= i2c_detect_tries) && (success == 0)) {
- err("Failed to read sensor ID. You might not have an");
- err("OV7610/20, or it may be not responding. Report");
- err("this to " EMAIL);
- err("This is only a warning. You can attempt to use");
- err("your camera anyway");
-// Only issue a warning for now
-// return -1;
- } else {
- PDEBUG(1, "OV7xx0 initialized (method 2, %dx)", i+1);
- }
- }
-
- /* Detect sensor (sub)type */
- rc = i2c_r(ov, OV7610_REG_COM_I);
-
- if (rc < 0) {
- err("Error detecting sensor type");
- return -1;
- } else if ((rc & 3) == 3) {
- dev_info(&ov->dev->dev, "Sensor is an OV7610\n");
- ov->sensor = SEN_OV7610;
- } else if ((rc & 3) == 1) {
- /* I don't know what's different about the 76BE yet. */
- if (i2c_r(ov, 0x15) & 1)
- dev_info(&ov->dev->dev, "Sensor is an OV7620AE\n");
- else
- dev_info(&ov->dev->dev, "Sensor is an OV76BE\n");
-
- /* OV511+ will return all zero isoc data unless we
- * configure the sensor as a 7620. Someone needs to
- * find the exact reg. setting that causes this. */
- if (ov->bridge == BRG_OV511PLUS) {
- dev_info(&ov->dev->dev,
- "Enabling 511+/7620AE workaround\n");
- ov->sensor = SEN_OV7620;
- } else {
- ov->sensor = SEN_OV76BE;
- }
- } else if ((rc & 3) == 0) {
- dev_info(&ov->dev->dev, "Sensor is an OV7620\n");
- ov->sensor = SEN_OV7620;
- } else {
- err("Unknown image sensor version: %d", rc & 3);
- return -1;
- }
-
- if (ov->sensor == SEN_OV7620) {
- PDEBUG(4, "Writing 7620 registers");
- if (write_regvals(ov, aRegvalsNorm7620))
- return -1;
- } else {
- PDEBUG(4, "Writing 7610 registers");
- if (write_regvals(ov, aRegvalsNorm7610))
- return -1;
- }
-
- /* Set sensor-specific vars */
- ov->maxwidth = 640;
- ov->maxheight = 480;
- ov->minwidth = 64;
- ov->minheight = 48;
-
- // FIXME: These do not match the actual settings yet
- ov->brightness = 0x80 << 8;
- ov->contrast = 0x80 << 8;
- ov->colour = 0x80 << 8;
- ov->hue = 0x80 << 8;
-
- return 0;
-}
-
-/* This initializes the OV6620, OV6630, OV6630AE, or OV6630AF sensor. */
-static int
-ov6xx0_configure(struct usb_ov511 *ov)
-{
- int rc;
-
- static struct ov511_regvals aRegvalsNorm6x20[] = {
- { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
- { OV511_I2C_BUS, 0x11, 0x01 },
- { OV511_I2C_BUS, 0x03, 0x60 },
- { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
- { OV511_I2C_BUS, 0x07, 0xa8 },
- /* The ratio of 0x0c and 0x0d controls the white point */
- { OV511_I2C_BUS, 0x0c, 0x24 },
- { OV511_I2C_BUS, 0x0d, 0x24 },
- { OV511_I2C_BUS, 0x0f, 0x15 }, /* COMS */
- { OV511_I2C_BUS, 0x10, 0x75 }, /* AEC Exposure time */
- { OV511_I2C_BUS, 0x12, 0x24 }, /* Enable AGC */
- { OV511_I2C_BUS, 0x14, 0x04 },
- /* 0x16: 0x06 helps frame stability with moving objects */
- { OV511_I2C_BUS, 0x16, 0x06 },
-// { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
- { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
- /* 0x28: 0x05 Selects RGB format if RGB on */
- { OV511_I2C_BUS, 0x28, 0x05 },
- { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-// { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
- { OV511_I2C_BUS, 0x2d, 0x99 },
- { OV511_I2C_BUS, 0x33, 0xa0 }, /* Color Processing Parameter */
- { OV511_I2C_BUS, 0x34, 0xd2 }, /* Max A/D range */
- { OV511_I2C_BUS, 0x38, 0x8b },
- { OV511_I2C_BUS, 0x39, 0x40 },
-
- { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
- { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
- { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
-
- { OV511_I2C_BUS, 0x3d, 0x80 },
- /* These next two registers (0x4a, 0x4b) are undocumented. They
- * control the color balance */
- { OV511_I2C_BUS, 0x4a, 0x80 },
- { OV511_I2C_BUS, 0x4b, 0x80 },
- { OV511_I2C_BUS, 0x4d, 0xd2 }, /* This reduces noise a bit */
- { OV511_I2C_BUS, 0x4e, 0xc1 },
- { OV511_I2C_BUS, 0x4f, 0x04 },
-// Do 50-53 have any effect?
-// Toggle 0x12[2] off and on here?
- { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */
- };
-
- static struct ov511_regvals aRegvalsNorm6x30[] = {
- /*OK*/ { OV511_I2C_BUS, 0x12, 0x80 }, /* reset */
- { OV511_I2C_BUS, 0x11, 0x00 },
- /*OK*/ { OV511_I2C_BUS, 0x03, 0x60 },
- /*0A?*/ { OV511_I2C_BUS, 0x05, 0x7f }, /* For when autoadjust is off */
- { OV511_I2C_BUS, 0x07, 0xa8 },
- /* The ratio of 0x0c and 0x0d controls the white point */
- /*OK*/ { OV511_I2C_BUS, 0x0c, 0x24 },
- /*OK*/ { OV511_I2C_BUS, 0x0d, 0x24 },
- /*A*/ { OV511_I2C_BUS, 0x0e, 0x20 },
-// /*04?*/ { OV511_I2C_BUS, 0x14, 0x80 },
- { OV511_I2C_BUS, 0x16, 0x03 },
-// /*OK*/ { OV511_I2C_BUS, 0x20, 0x30 }, /* Aperture correction enable */
- // 21 & 22? The suggested values look wrong. Go with default
- /*A*/ { OV511_I2C_BUS, 0x23, 0xc0 },
- /*A*/ { OV511_I2C_BUS, 0x25, 0x9a }, // Check this against default
-// /*OK*/ { OV511_I2C_BUS, 0x26, 0xb2 }, /* BLC enable */
-
- /* 0x28: 0x05 Selects RGB format if RGB on */
-// /*04?*/ { OV511_I2C_BUS, 0x28, 0x05 },
-// /*04?*/ { OV511_I2C_BUS, 0x28, 0x45 }, // DEBUG: Tristate UV bus
-
- /*OK*/ { OV511_I2C_BUS, 0x2a, 0x04 }, /* Disable framerate adjust */
-// /*OK*/ { OV511_I2C_BUS, 0x2b, 0xac }, /* Framerate; Set 2a[7] first */
- { OV511_I2C_BUS, 0x2d, 0x99 },
-// /*A*/ { OV511_I2C_BUS, 0x33, 0x26 }, // Reserved bits on 6620
-// /*d2?*/ { OV511_I2C_BUS, 0x34, 0x03 }, /* Max A/D range */
-// /*8b?*/ { OV511_I2C_BUS, 0x38, 0x83 },
-// /*40?*/ { OV511_I2C_BUS, 0x39, 0xc0 }, // 6630 adds bit 7
-// { OV511_I2C_BUS, 0x3c, 0x39 }, /* Enable AEC mode changing */
-// { OV511_I2C_BUS, 0x3c, 0x3c }, /* Change AEC mode */
-// { OV511_I2C_BUS, 0x3c, 0x24 }, /* Disable AEC mode changing */
- { OV511_I2C_BUS, 0x3d, 0x80 },
-// /*A*/ { OV511_I2C_BUS, 0x3f, 0x0e },
-
- /* These next two registers (0x4a, 0x4b) are undocumented. They
- * control the color balance */
-// /*OK?*/ { OV511_I2C_BUS, 0x4a, 0x80 }, // Check these
-// /*OK?*/ { OV511_I2C_BUS, 0x4b, 0x80 },
- { OV511_I2C_BUS, 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
- /*c1?*/ { OV511_I2C_BUS, 0x4e, 0x40 },
-
- /* UV average mode, color killer: strongest */
- { OV511_I2C_BUS, 0x4f, 0x07 },
-
- { OV511_I2C_BUS, 0x54, 0x23 }, /* Max AGC gain: 18dB */
- { OV511_I2C_BUS, 0x57, 0x81 }, /* (default) */
- { OV511_I2C_BUS, 0x59, 0x01 }, /* AGC dark current comp: +1 */
- { OV511_I2C_BUS, 0x5a, 0x2c }, /* (undocumented) */
- { OV511_I2C_BUS, 0x5b, 0x0f }, /* AWB chrominance levels */
-// { OV511_I2C_BUS, 0x5c, 0x10 },
- { OV511_DONE_BUS, 0x0, 0x00 }, /* END MARKER */
- };
-
- PDEBUG(4, "starting sensor configuration");
-
- if (init_ov_sensor(ov) < 0) {
- err("Failed to read sensor ID. You might not have an OV6xx0,");
- err("or it may be not responding. Report this to " EMAIL);
- return -1;
- } else {
- PDEBUG(1, "OV6xx0 sensor detected");
- }
-
- /* Detect sensor (sub)type */
- rc = i2c_r(ov, OV7610_REG_COM_I);
-
- if (rc < 0) {
- err("Error detecting sensor type");
- return -1;
- }
-
- if ((rc & 3) == 0) {
- ov->sensor = SEN_OV6630;
- dev_info(&ov->dev->dev, "Sensor is an OV6630\n");
- } else if ((rc & 3) == 1) {
- ov->sensor = SEN_OV6620;
- dev_info(&ov->dev->dev, "Sensor is an OV6620\n");
- } else if ((rc & 3) == 2) {
- ov->sensor = SEN_OV6630;
- dev_info(&ov->dev->dev, "Sensor is an OV6630AE\n");
- } else if ((rc & 3) == 3) {
- ov->sensor = SEN_OV6630;
- dev_info(&ov->dev->dev, "Sensor is an OV6630AF\n");
- }
-
- /* Set sensor-specific vars */
- ov->maxwidth = 352;
- ov->maxheight = 288;
- ov->minwidth = 64;
- ov->minheight = 48;
-
- // FIXME: These do not match the actual settings yet
- ov->brightness = 0x80 << 8;
- ov->contrast = 0x80 << 8;
- ov->colour = 0x80 << 8;
- ov->hue = 0x80 << 8;
-
- if (ov->sensor == SEN_OV6620) {
- PDEBUG(4, "Writing 6x20 registers");
- if (write_regvals(ov, aRegvalsNorm6x20))
- return -1;
- } else {
- PDEBUG(4, "Writing 6x30 registers");
- if (write_regvals(ov, aRegvalsNorm6x30))
- return -1;
- }
-
- return 0;
-}
-
-/* This initializes the KS0127 and KS0127B video decoders. */
-static int
-ks0127_configure(struct usb_ov511 *ov)
-{
- int rc;
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
- if (ov51x_init_ks_sensor(ov) < 0) {
- err("Failed to initialize the KS0127");
- return -1;
- } else {
- PDEBUG(1, "KS012x(B) sensor detected");
- }
-#endif
-
- /* Detect decoder subtype */
- rc = i2c_r(ov, 0x00);
- if (rc < 0) {
- err("Error detecting sensor type");
- return -1;
- } else if (rc & 0x08) {
- rc = i2c_r(ov, 0x3d);
- if (rc < 0) {
- err("Error detecting sensor type");
- return -1;
- } else if ((rc & 0x0f) == 0) {
- dev_info(&ov->dev->dev, "Sensor is a KS0127\n");
- ov->sensor = SEN_KS0127;
- } else if ((rc & 0x0f) == 9) {
- dev_info(&ov->dev->dev, "Sensor is a KS0127B Rev. A\n");
- ov->sensor = SEN_KS0127B;
- }
- } else {
- err("Error: Sensor is an unsupported KS0122");
- return -1;
- }
-
- /* Set sensor-specific vars */
- ov->maxwidth = 640;
- ov->maxheight = 480;
- ov->minwidth = 64;
- ov->minheight = 48;
-
- // FIXME: These do not match the actual settings yet
- ov->brightness = 0x80 << 8;
- ov->contrast = 0x80 << 8;
- ov->colour = 0x80 << 8;
- ov->hue = 0x80 << 8;
-
- /* This device is not supported yet. Bail out now... */
- err("This sensor is not supported yet.");
- return -1;
-
- return 0;
-}
-
-/* This initializes the SAA7111A video decoder. */
-static int
-saa7111a_configure(struct usb_ov511 *ov)
-{
- int rc;
-
- /* Since there is no register reset command, all registers must be
- * written, otherwise gives erratic results */
- static struct ov511_regvals aRegvalsNormSAA7111A[] = {
- { OV511_I2C_BUS, 0x06, 0xce },
- { OV511_I2C_BUS, 0x07, 0x00 },
- { OV511_I2C_BUS, 0x10, 0x44 }, /* YUV422, 240/286 lines */
- { OV511_I2C_BUS, 0x0e, 0x01 }, /* NTSC M or PAL BGHI */
- { OV511_I2C_BUS, 0x00, 0x00 },
- { OV511_I2C_BUS, 0x01, 0x00 },
- { OV511_I2C_BUS, 0x03, 0x23 },
- { OV511_I2C_BUS, 0x04, 0x00 },
- { OV511_I2C_BUS, 0x05, 0x00 },
- { OV511_I2C_BUS, 0x08, 0xc8 }, /* Auto field freq */
- { OV511_I2C_BUS, 0x09, 0x01 }, /* Chrom. trap off, APER=0.25 */
- { OV511_I2C_BUS, 0x0a, 0x80 }, /* BRIG=128 */
- { OV511_I2C_BUS, 0x0b, 0x40 }, /* CONT=1.0 */
- { OV511_I2C_BUS, 0x0c, 0x40 }, /* SATN=1.0 */
- { OV511_I2C_BUS, 0x0d, 0x00 }, /* HUE=0 */
- { OV511_I2C_BUS, 0x0f, 0x00 },
- { OV511_I2C_BUS, 0x11, 0x0c },
- { OV511_I2C_BUS, 0x12, 0x00 },
- { OV511_I2C_BUS, 0x13, 0x00 },
- { OV511_I2C_BUS, 0x14, 0x00 },
- { OV511_I2C_BUS, 0x15, 0x00 },
- { OV511_I2C_BUS, 0x16, 0x00 },
- { OV511_I2C_BUS, 0x17, 0x00 },
- { OV511_I2C_BUS, 0x02, 0xc0 }, /* Composite input 0 */
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
-// FIXME: I don't know how to sync or reset it yet
-#if 0
- if (ov51x_init_saa_sensor(ov) < 0) {
- err("Failed to initialize the SAA7111A");
- return -1;
- } else {
- PDEBUG(1, "SAA7111A sensor detected");
- }
-#endif
-
- /* 640x480 not supported with PAL */
- if (ov->pal) {
- ov->maxwidth = 320;
- ov->maxheight = 240; /* Even field only */
- } else {
- ov->maxwidth = 640;
- ov->maxheight = 480; /* Even/Odd fields */
- }
-
- ov->minwidth = 320;
- ov->minheight = 240; /* Even field only */
-
- ov->has_decoder = 1;
- ov->num_inputs = 8;
- ov->norm = VIDEO_MODE_AUTO;
- ov->stop_during_set = 0; /* Decoder guarantees stable image */
-
- /* Decoder doesn't change these values, so we use these instead of
- * acutally reading the registers (which doesn't work) */
- ov->brightness = 0x80 << 8;
- ov->contrast = 0x40 << 9;
- ov->colour = 0x40 << 9;
- ov->hue = 32768;
-
- PDEBUG(4, "Writing SAA7111A registers");
- if (write_regvals(ov, aRegvalsNormSAA7111A))
- return -1;
-
- /* Detect version of decoder. This must be done after writing the
- * initial regs or the decoder will lock up. */
- rc = i2c_r(ov, 0x00);
-
- if (rc < 0) {
- err("Error detecting sensor version");
- return -1;
- } else {
- dev_info(&ov->dev->dev,
- "Sensor is an SAA7111A (version 0x%x)\n", rc);
- ov->sensor = SEN_SAA7111A;
- }
-
- // FIXME: Fix this for OV518(+)
- /* Latch to negative edge of clock. Otherwise, we get incorrect
- * colors and jitter in the digital signal. */
- if (ov->bclass == BCL_OV511)
- reg_w(ov, 0x11, 0x00);
- else
- dev_warn(&ov->dev->dev,
- "SAA7111A not yet supported with OV518/OV518+\n");
-
- return 0;
-}
-
-/* This initializes the OV511/OV511+ and the sensor */
-static int
-ov511_configure(struct usb_ov511 *ov)
-{
- static struct ov511_regvals aRegvalsInit511[] = {
- { OV511_REG_BUS, R51x_SYS_RESET, 0x7f },
- { OV511_REG_BUS, R51x_SYS_INIT, 0x01 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x7f },
- { OV511_REG_BUS, R51x_SYS_INIT, 0x01 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x3f },
- { OV511_REG_BUS, R51x_SYS_INIT, 0x01 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x3d },
- { OV511_DONE_BUS, 0x0, 0x00},
- };
-
- static struct ov511_regvals aRegvalsNorm511[] = {
- { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0x01 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 },
- { OV511_REG_BUS, R511_FIFO_OPTS, 0x1f },
- { OV511_REG_BUS, R511_COMP_EN, 0x00 },
- { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- static struct ov511_regvals aRegvalsNorm511Plus[] = {
- { OV511_REG_BUS, R511_DRAM_FLOW_CTL, 0xff },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 },
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x00 },
- { OV511_REG_BUS, R511_FIFO_OPTS, 0xff },
- { OV511_REG_BUS, R511_COMP_EN, 0x00 },
- { OV511_REG_BUS, R511_COMP_LUT_EN, 0x03 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- PDEBUG(4, "");
-
- ov->customid = reg_r(ov, R511_SYS_CUST_ID);
- if (ov->customid < 0) {
- err("Unable to read camera bridge registers");
- goto error;
- }
-
- PDEBUG (1, "CustomID = %d", ov->customid);
- ov->desc = symbolic(camlist, ov->customid);
- dev_info(&ov->dev->dev, "model: %s\n", ov->desc);
-
- if (0 == strcmp(ov->desc, NOT_DEFINED_STR)) {
- err("Camera type (%d) not recognized", ov->customid);
- err("Please notify " EMAIL " of the name,");
- err("manufacturer, model, and this number of your camera.");
- err("Also include the output of the detection process.");
- }
-
- if (ov->customid == 70) /* USB Life TV (PAL/SECAM) */
- ov->pal = 1;
-
- if (write_regvals(ov, aRegvalsInit511))
- goto error;
-
- if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
- ov51x_led_control(ov, 0);
-
- /* The OV511+ has undocumented bits in the flow control register.
- * Setting it to 0xff fixes the corruption with moving objects. */
- if (ov->bridge == BRG_OV511) {
- if (write_regvals(ov, aRegvalsNorm511))
- goto error;
- } else if (ov->bridge == BRG_OV511PLUS) {
- if (write_regvals(ov, aRegvalsNorm511Plus))
- goto error;
- } else {
- err("Invalid bridge");
- }
-
- if (ov511_init_compression(ov))
- goto error;
-
- ov->packet_numbering = 1;
- ov511_set_packet_size(ov, 0);
-
- ov->snap_enabled = snapshot;
-
- /* Test for 7xx0 */
- PDEBUG(3, "Testing for 0V7xx0");
- ov->primary_i2c_slave = OV7xx0_SID;
- if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x12, 0x80) < 0) {
- /* Test for 6xx0 */
- PDEBUG(3, "Testing for 0V6xx0");
- ov->primary_i2c_slave = OV6xx0_SID;
- if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x12, 0x80) < 0) {
- /* Test for 8xx0 */
- PDEBUG(3, "Testing for 0V8xx0");
- ov->primary_i2c_slave = OV8xx0_SID;
- if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x12, 0x80) < 0) {
- /* Test for SAA7111A */
- PDEBUG(3, "Testing for SAA7111A");
- ov->primary_i2c_slave = SAA7111A_SID;
- if (ov51x_set_slave_ids(ov, SAA7111A_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x0d, 0x00) < 0) {
- /* Test for KS0127 */
- PDEBUG(3, "Testing for KS0127");
- ov->primary_i2c_slave = KS0127_SID;
- if (ov51x_set_slave_ids(ov, KS0127_SID) < 0)
- goto error;
-
- if (i2c_w(ov, 0x10, 0x00) < 0) {
- err("Can't determine sensor slave IDs");
- goto error;
- } else {
- if (ks0127_configure(ov) < 0) {
- err("Failed to configure KS0127");
- goto error;
- }
- }
- } else {
- if (saa7111a_configure(ov) < 0) {
- err("Failed to configure SAA7111A");
- goto error;
- }
- }
- } else {
- err("Detected unsupported OV8xx0 sensor");
- goto error;
- }
- } else {
- if (ov6xx0_configure(ov) < 0) {
- err("Failed to configure OV6xx0");
- goto error;
- }
- }
- } else {
- if (ov7xx0_configure(ov) < 0) {
- err("Failed to configure OV7xx0");
- goto error;
- }
- }
-
- return 0;
-
-error:
- err("OV511 Config failed");
-
- return -EBUSY;
-}
-
-/* This initializes the OV518/OV518+ and the sensor */
-static int
-ov518_configure(struct usb_ov511 *ov)
-{
- /* For 518 and 518+ */
- static struct ov511_regvals aRegvalsInit518[] = {
- { OV511_REG_BUS, R51x_SYS_RESET, 0x40 },
- { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x3e },
- { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 },
- { OV511_REG_BUS, R51x_SYS_RESET, 0x00 },
- { OV511_REG_BUS, R51x_SYS_INIT, 0xe1 },
- { OV511_REG_BUS, 0x46, 0x00 },
- { OV511_REG_BUS, 0x5d, 0x03 },
- { OV511_DONE_BUS, 0x0, 0x00},
- };
-
- static struct ov511_regvals aRegvalsNorm518[] = {
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */
- { OV511_REG_BUS, 0x31, 0x0f },
- { OV511_REG_BUS, 0x5d, 0x03 },
- { OV511_REG_BUS, 0x24, 0x9f },
- { OV511_REG_BUS, 0x25, 0x90 },
- { OV511_REG_BUS, 0x20, 0x00 },
- { OV511_REG_BUS, 0x51, 0x04 },
- { OV511_REG_BUS, 0x71, 0x19 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- static struct ov511_regvals aRegvalsNorm518Plus[] = {
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x02 }, /* Reset */
- { OV511_REG_BUS, R51x_SYS_SNAP, 0x01 }, /* Enable */
- { OV511_REG_BUS, 0x31, 0x0f },
- { OV511_REG_BUS, 0x5d, 0x03 },
- { OV511_REG_BUS, 0x24, 0x9f },
- { OV511_REG_BUS, 0x25, 0x90 },
- { OV511_REG_BUS, 0x20, 0x60 },
- { OV511_REG_BUS, 0x51, 0x02 },
- { OV511_REG_BUS, 0x71, 0x19 },
- { OV511_REG_BUS, 0x40, 0xff },
- { OV511_REG_BUS, 0x41, 0x42 },
- { OV511_REG_BUS, 0x46, 0x00 },
- { OV511_REG_BUS, 0x33, 0x04 },
- { OV511_REG_BUS, 0x21, 0x19 },
- { OV511_REG_BUS, 0x3f, 0x10 },
- { OV511_DONE_BUS, 0x0, 0x00 },
- };
-
- PDEBUG(4, "");
-
- /* First 5 bits of custom ID reg are a revision ID on OV518 */
- dev_info(&ov->dev->dev, "Device revision %d\n",
- 0x1F & reg_r(ov, R511_SYS_CUST_ID));
-
- /* Give it the default description */
- ov->desc = symbolic(camlist, 0);
-
- if (write_regvals(ov, aRegvalsInit518))
- goto error;
-
- /* Set LED GPIO pin to output mode */
- if (reg_w_mask(ov, 0x57, 0x00, 0x02) < 0)
- goto error;
-
- /* LED is off by default with OV518; have to explicitly turn it on */
- if (ov->led_policy == LED_OFF || ov->led_policy == LED_AUTO)
- ov51x_led_control(ov, 0);
- else
- ov51x_led_control(ov, 1);
-
- /* Don't require compression if dumppix is enabled; otherwise it's
- * required. OV518 has no uncompressed mode, to save RAM. */
- if (!dumppix && !ov->compress) {
- ov->compress = 1;
- dev_warn(&ov->dev->dev,
- "Compression required with OV518...enabling\n");
- }
-
- if (ov->bridge == BRG_OV518) {
- if (write_regvals(ov, aRegvalsNorm518))
- goto error;
- } else if (ov->bridge == BRG_OV518PLUS) {
- if (write_regvals(ov, aRegvalsNorm518Plus))
- goto error;
- } else {
- err("Invalid bridge");
- }
-
- if (reg_w(ov, 0x2f, 0x80) < 0)
- goto error;
-
- if (ov518_init_compression(ov))
- goto error;
-
- if (ov->bridge == BRG_OV518)
- {
- struct usb_interface *ifp;
- struct usb_host_interface *alt;
- __u16 mxps = 0;
-
- ifp = usb_ifnum_to_if(ov->dev, 0);
- if (ifp) {
- alt = usb_altnum_to_altsetting(ifp, 7);
- if (alt)
- mxps = le16_to_cpu(alt->endpoint[0].desc.wMaxPacketSize);
- }
-
- /* Some OV518s have packet numbering by default, some don't */
- if (mxps == 897)
- ov->packet_numbering = 1;
- else
- ov->packet_numbering = 0;
- } else {
- /* OV518+ has packet numbering turned on by default */
- ov->packet_numbering = 1;
- }
-
- ov518_set_packet_size(ov, 0);
-
- ov->snap_enabled = snapshot;
-
- /* Test for 76xx */
- ov->primary_i2c_slave = OV7xx0_SID;
- if (ov51x_set_slave_ids(ov, OV7xx0_SID) < 0)
- goto error;
-
- /* The OV518 must be more aggressive about sensor detection since
- * I2C write will never fail if the sensor is not present. We have
- * to try to initialize the sensor to detect its presence */
-
- if (init_ov_sensor(ov) < 0) {
- /* Test for 6xx0 */
- ov->primary_i2c_slave = OV6xx0_SID;
- if (ov51x_set_slave_ids(ov, OV6xx0_SID) < 0)
- goto error;
-
- if (init_ov_sensor(ov) < 0) {
- /* Test for 8xx0 */
- ov->primary_i2c_slave = OV8xx0_SID;
- if (ov51x_set_slave_ids(ov, OV8xx0_SID) < 0)
- goto error;
-
- if (init_ov_sensor(ov) < 0) {
- err("Can't determine sensor slave IDs");
- goto error;
- } else {
- err("Detected unsupported OV8xx0 sensor");
- goto error;
- }
- } else {
- if (ov6xx0_configure(ov) < 0) {
- err("Failed to configure OV6xx0");
- goto error;
- }
- }
- } else {
- if (ov7xx0_configure(ov) < 0) {
- err("Failed to configure OV7xx0");
- goto error;
- }
- }
-
- ov->maxwidth = 352;
- ov->maxheight = 288;
-
- // The OV518 cannot go as low as the sensor can
- ov->minwidth = 160;
- ov->minheight = 120;
-
- return 0;
-
-error:
- err("OV518 Config failed");
-
- return -EBUSY;
-}
-
-/****************************************************************************
- * sysfs
- ***************************************************************************/
-
-static inline struct usb_ov511 *cd_to_ov(struct device *cd)
-{
- struct video_device *vdev = to_video_device(cd);
- return video_get_drvdata(vdev);
-}
-
-static ssize_t show_custom_id(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- return sprintf(buf, "%d\n", ov->customid);
-}
-static DEVICE_ATTR(custom_id, S_IRUGO, show_custom_id, NULL);
-
-static ssize_t show_model(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- return sprintf(buf, "%s\n", ov->desc);
-}
-static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
-
-static ssize_t show_bridge(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- return sprintf(buf, "%s\n", symbolic(brglist, ov->bridge));
-}
-static DEVICE_ATTR(bridge, S_IRUGO, show_bridge, NULL);
-
-static ssize_t show_sensor(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- return sprintf(buf, "%s\n", symbolic(senlist, ov->sensor));
-}
-static DEVICE_ATTR(sensor, S_IRUGO, show_sensor, NULL);
-
-static ssize_t show_brightness(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned short x;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_brightness(ov, &x);
- return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(brightness, S_IRUGO, show_brightness, NULL);
-
-static ssize_t show_saturation(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned short x;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_saturation(ov, &x);
- return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(saturation, S_IRUGO, show_saturation, NULL);
-
-static ssize_t show_contrast(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned short x;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_contrast(ov, &x);
- return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(contrast, S_IRUGO, show_contrast, NULL);
-
-static ssize_t show_hue(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned short x;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_hue(ov, &x);
- return sprintf(buf, "%d\n", x >> 8);
-}
-static DEVICE_ATTR(hue, S_IRUGO, show_hue, NULL);
-
-static ssize_t show_exposure(struct device *cd,
- struct device_attribute *attr, char *buf)
-{
- struct usb_ov511 *ov = cd_to_ov(cd);
- unsigned char exp = 0;
-
- if (!ov->dev)
- return -ENODEV;
- sensor_get_exposure(ov, &exp);
- return sprintf(buf, "%d\n", exp);
-}
-static DEVICE_ATTR(exposure, S_IRUGO, show_exposure, NULL);
-
-static int ov_create_sysfs(struct video_device *vdev)
-{
- int rc;
-
- rc = device_create_file(&vdev->dev, &dev_attr_custom_id);
- if (rc) goto err;
- rc = device_create_file(&vdev->dev, &dev_attr_model);
- if (rc) goto err_id;
- rc = device_create_file(&vdev->dev, &dev_attr_bridge);
- if (rc) goto err_model;
- rc = device_create_file(&vdev->dev, &dev_attr_sensor);
- if (rc) goto err_bridge;
- rc = device_create_file(&vdev->dev, &dev_attr_brightness);
- if (rc) goto err_sensor;
- rc = device_create_file(&vdev->dev, &dev_attr_saturation);
- if (rc) goto err_bright;
- rc = device_create_file(&vdev->dev, &dev_attr_contrast);
- if (rc) goto err_sat;
- rc = device_create_file(&vdev->dev, &dev_attr_hue);
- if (rc) goto err_contrast;
- rc = device_create_file(&vdev->dev, &dev_attr_exposure);
- if (rc) goto err_hue;
-
- return 0;
-
-err_hue:
- device_remove_file(&vdev->dev, &dev_attr_hue);
-err_contrast:
- device_remove_file(&vdev->dev, &dev_attr_contrast);
-err_sat:
- device_remove_file(&vdev->dev, &dev_attr_saturation);
-err_bright:
- device_remove_file(&vdev->dev, &dev_attr_brightness);
-err_sensor:
- device_remove_file(&vdev->dev, &dev_attr_sensor);
-err_bridge:
- device_remove_file(&vdev->dev, &dev_attr_bridge);
-err_model:
- device_remove_file(&vdev->dev, &dev_attr_model);
-err_id:
- device_remove_file(&vdev->dev, &dev_attr_custom_id);
-err:
- return rc;
-}
-
-/****************************************************************************
- * USB routines
- ***************************************************************************/
-
-static int
-ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_interface_descriptor *idesc;
- struct usb_ov511 *ov;
- int i, rc, nr;
-
- PDEBUG(1, "probing for device...");
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- idesc = &intf->cur_altsetting->desc;
-
- if (idesc->bInterfaceClass != 0xFF)
- return -ENODEV;
- if (idesc->bInterfaceSubClass != 0x00)
- return -ENODEV;
-
- if ((ov = kzalloc(sizeof(*ov), GFP_KERNEL)) == NULL) {
- err("couldn't kmalloc ov struct");
- goto error_out;
- }
-
- ov->dev = dev;
- ov->iface = idesc->bInterfaceNumber;
- ov->led_policy = led;
- ov->compress = compress;
- ov->lightfreq = lightfreq;
- ov->num_inputs = 1; /* Video decoder init functs. change this */
- ov->stop_during_set = !fastset;
- ov->backlight = backlight;
- ov->mirror = mirror;
- ov->auto_brt = autobright;
- ov->auto_gain = autogain;
- ov->auto_exp = autoexp;
-
- switch (le16_to_cpu(dev->descriptor.idProduct)) {
- case PROD_OV511:
- ov->bridge = BRG_OV511;
- ov->bclass = BCL_OV511;
- break;
- case PROD_OV511PLUS:
- ov->bridge = BRG_OV511PLUS;
- ov->bclass = BCL_OV511;
- break;
- case PROD_OV518:
- ov->bridge = BRG_OV518;
- ov->bclass = BCL_OV518;
- break;
- case PROD_OV518PLUS:
- ov->bridge = BRG_OV518PLUS;
- ov->bclass = BCL_OV518;
- break;
- case PROD_ME2CAM:
- if (le16_to_cpu(dev->descriptor.idVendor) != VEND_MATTEL)
- goto error;
- ov->bridge = BRG_OV511PLUS;
- ov->bclass = BCL_OV511;
- break;
- default:
- err("Unknown product ID 0x%04x", le16_to_cpu(dev->descriptor.idProduct));
- goto error;
- }
-
- dev_info(&intf->dev, "USB %s video device found\n",
- symbolic(brglist, ov->bridge));
-
- init_waitqueue_head(&ov->wq);
-
- mutex_init(&ov->lock); /* to 1 == available */
- mutex_init(&ov->buf_lock);
- mutex_init(&ov->i2c_lock);
- mutex_init(&ov->cbuf_lock);
-
- ov->buf_state = BUF_NOT_ALLOCATED;
-
- if (usb_make_path(dev, ov->usb_path, OV511_USB_PATH_LEN) < 0) {
- err("usb_make_path error");
- goto error;
- }
-
- /* Allocate control transfer buffer. */
- /* Must be kmalloc()'ed, for DMA compatibility */
- ov->cbuf = kmalloc(OV511_CBUF_SIZE, GFP_KERNEL);
- if (!ov->cbuf)
- goto error;
-
- if (ov->bclass == BCL_OV518) {
- if (ov518_configure(ov) < 0)
- goto error;
- } else {
- if (ov511_configure(ov) < 0)
- goto error;
- }
-
- for (i = 0; i < OV511_NUMFRAMES; i++) {
- ov->frame[i].framenum = i;
- init_waitqueue_head(&ov->frame[i].wq);
- }
-
- for (i = 0; i < OV511_NUMSBUF; i++) {
- ov->sbuf[i].ov = ov;
- spin_lock_init(&ov->sbuf[i].lock);
- ov->sbuf[i].n = i;
- }
-
- /* Unnecessary? (This is done on open(). Need to make sure variables
- * are properly initialized without this before removing it, though). */
- if (ov51x_set_default_params(ov) < 0)
- goto error;
-
-#ifdef OV511_DEBUG
- if (dump_bridge) {
- if (ov->bclass == BCL_OV511)
- ov511_dump_regs(ov);
- else
- ov518_dump_regs(ov);
- }
-#endif
-
- ov->vdev = video_device_alloc();
- if (!ov->vdev)
- goto error;
-
- memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
- ov->vdev->parent = &intf->dev;
- video_set_drvdata(ov->vdev, ov);
-
- mutex_lock(&ov->lock);
-
- /* Check to see next free device and mark as used */
- nr = find_first_zero_bit(&ov511_devused, OV511_MAX_UNIT_VIDEO);
-
- /* Registers device */
- if (unit_video[nr] != 0)
- rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER,
- unit_video[nr]);
- else
- rc = video_register_device(ov->vdev, VFL_TYPE_GRABBER, -1);
-
- if (rc < 0) {
- err("video_register_device failed");
- mutex_unlock(&ov->lock);
- goto error;
- }
-
- /* Mark device as used */
- ov511_devused |= 1 << nr;
- ov->nr = nr;
-
- dev_info(&intf->dev, "Device at %s registered to %s\n",
- ov->usb_path, video_device_node_name(ov->vdev));
-
- usb_set_intfdata(intf, ov);
- if (ov_create_sysfs(ov->vdev)) {
- err("ov_create_sysfs failed");
- ov511_devused &= ~(1 << nr);
- mutex_unlock(&ov->lock);
- goto error;
- }
-
- mutex_unlock(&ov->lock);
-
- return 0;
-
-error:
- if (ov->vdev) {
- if (!video_is_registered(ov->vdev))
- video_device_release(ov->vdev);
- else
- video_unregister_device(ov->vdev);
- ov->vdev = NULL;
- }
-
- if (ov->cbuf) {
- mutex_lock(&ov->cbuf_lock);
- kfree(ov->cbuf);
- ov->cbuf = NULL;
- mutex_unlock(&ov->cbuf_lock);
- }
-
- kfree(ov);
- ov = NULL;
-
-error_out:
- err("Camera initialization failed");
- return -EIO;
-}
-
-static void
-ov51x_disconnect(struct usb_interface *intf)
-{
- struct usb_ov511 *ov = usb_get_intfdata(intf);
- int n;
-
- PDEBUG(3, "");
-
- mutex_lock(&ov->lock);
- usb_set_intfdata (intf, NULL);
-
- /* Free device number */
- ov511_devused &= ~(1 << ov->nr);
-
- if (ov->vdev)
- video_unregister_device(ov->vdev);
-
- for (n = 0; n < OV511_NUMFRAMES; n++)
- ov->frame[n].grabstate = FRAME_ERROR;
-
- ov->curframe = -1;
-
- /* This will cause the process to request another frame */
- for (n = 0; n < OV511_NUMFRAMES; n++)
- wake_up_interruptible(&ov->frame[n].wq);
-
- wake_up_interruptible(&ov->wq);
-
- ov->streaming = 0;
- ov51x_unlink_isoc(ov);
- mutex_unlock(&ov->lock);
-
- ov->dev = NULL;
-
- /* Free the memory */
- if (!ov->user) {
- mutex_lock(&ov->cbuf_lock);
- kfree(ov->cbuf);
- ov->cbuf = NULL;
- mutex_unlock(&ov->cbuf_lock);
-
- ov51x_dealloc(ov);
- kfree(ov);
- ov = NULL;
- }
-
- PDEBUG(3, "Disconnect complete");
-}
-
-static struct usb_driver ov511_driver = {
- .name = "ov511",
- .id_table = device_table,
- .probe = ov51x_probe,
- .disconnect = ov51x_disconnect
-};
-
-/****************************************************************************
- *
- * Module routines
- *
- ***************************************************************************/
-
-static int __init
-usb_ov511_init(void)
-{
- int retval;
-
- retval = usb_register(&ov511_driver);
- if (retval)
- goto out;
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
-out:
- return retval;
-}
-
-static void __exit
-usb_ov511_exit(void)
-{
- usb_deregister(&ov511_driver);
- printk(KERN_INFO KBUILD_MODNAME ": driver deregistered\n");
-}
-
-module_init(usb_ov511_init);
-module_exit(usb_ov511_exit);
-
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
deleted file mode 100644
index c450c92468da..000000000000
--- a/drivers/media/video/ov511.h
+++ /dev/null
@@ -1,573 +0,0 @@
-#ifndef __LINUX_OV511_H
-#define __LINUX_OV511_H
-
-#include <asm/uaccess.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#define OV511_DEBUG /* Turn on debug messages */
-
-#ifdef OV511_DEBUG
- #define PDEBUG(level, fmt, args...) \
- if (debug >= (level)) \
- printk(KERN_INFO KBUILD_MODNAME "[%s:%d] \n" fmt, \
- __func__, __LINE__ , ## args)
-#else
- #define PDEBUG(level, fmt, args...) do {} while(0)
-#endif
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { \
- if ((v) < (mi)) (v) = (mi); \
- else if ((v) > (ma)) (v) = (ma); \
-}
-
-/* --------------------------------- */
-/* DEFINES FOR OV511 AND OTHER CHIPS */
-/* --------------------------------- */
-
-/* USB IDs */
-#define VEND_OMNIVISION 0x05A9
-#define PROD_OV511 0x0511
-#define PROD_OV511PLUS 0xA511
-#define PROD_OV518 0x0518
-#define PROD_OV518PLUS 0xA518
-
-#define VEND_MATTEL 0x0813
-#define PROD_ME2CAM 0x0002
-
-/* --------------------------------- */
-/* OV51x REGISTER MNEMONICS */
-/* --------------------------------- */
-
-/* Camera interface register numbers */
-#define R511_CAM_DELAY 0x10
-#define R511_CAM_EDGE 0x11
-#define R511_CAM_PXCNT 0x12
-#define R511_CAM_LNCNT 0x13
-#define R511_CAM_PXDIV 0x14
-#define R511_CAM_LNDIV 0x15
-#define R511_CAM_UV_EN 0x16
-#define R511_CAM_LINE_MODE 0x17
-#define R511_CAM_OPTS 0x18
-
-/* Snapshot mode camera interface register numbers */
-#define R511_SNAP_FRAME 0x19
-#define R511_SNAP_PXCNT 0x1A
-#define R511_SNAP_LNCNT 0x1B
-#define R511_SNAP_PXDIV 0x1C
-#define R511_SNAP_LNDIV 0x1D
-#define R511_SNAP_UV_EN 0x1E
-#define R511_SNAP_OPTS 0x1F
-
-/* DRAM register numbers */
-#define R511_DRAM_FLOW_CTL 0x20
-#define R511_DRAM_ARCP 0x21
-#define R511_DRAM_MRC 0x22
-#define R511_DRAM_RFC 0x23
-
-/* ISO FIFO register numbers */
-#define R51x_FIFO_PSIZE 0x30 /* 2 bytes wide w/ OV518(+) */
-#define R511_FIFO_OPTS 0x31
-
-/* Parallel IO register numbers */
-#define R511_PIO_OPTS 0x38
-#define R511_PIO_DATA 0x39
-#define R511_PIO_BIST 0x3E
-#define R518_GPIO_IN 0x55 /* OV518(+) only */
-#define R518_GPIO_OUT 0x56 /* OV518(+) only */
-#define R518_GPIO_CTL 0x57 /* OV518(+) only */
-#define R518_GPIO_PULSE_IN 0x58 /* OV518(+) only */
-#define R518_GPIO_PULSE_CLEAR 0x59 /* OV518(+) only */
-#define R518_GPIO_PULSE_POL 0x5a /* OV518(+) only */
-#define R518_GPIO_PULSE_EN 0x5b /* OV518(+) only */
-#define R518_GPIO_RESET 0x5c /* OV518(+) only */
-
-/* I2C registers */
-#define R511_I2C_CTL 0x40
-#define R518_I2C_CTL 0x47 /* OV518(+) only */
-#define R51x_I2C_W_SID 0x41
-#define R51x_I2C_SADDR_3 0x42
-#define R51x_I2C_SADDR_2 0x43
-#define R51x_I2C_R_SID 0x44
-#define R51x_I2C_DATA 0x45
-#define R51x_I2C_CLOCK 0x46
-#define R51x_I2C_TIMEOUT 0x47
-
-/* I2C snapshot registers */
-#define R511_SI2C_SADDR_3 0x48
-#define R511_SI2C_DATA 0x49
-
-/* System control registers */
-#define R51x_SYS_RESET 0x50
- /* Reset type definitions */
-#define OV511_RESET_UDC 0x01
-#define OV511_RESET_I2C 0x02
-#define OV511_RESET_FIFO 0x04
-#define OV511_RESET_OMNICE 0x08
-#define OV511_RESET_DRAM 0x10
-#define OV511_RESET_CAM_INT 0x20
-#define OV511_RESET_OV511 0x40
-#define OV511_RESET_NOREGS 0x3F /* All but OV511 & regs */
-#define OV511_RESET_ALL 0x7F
-
-#define R511_SYS_CLOCK_DIV 0x51
-#define R51x_SYS_SNAP 0x52
-#define R51x_SYS_INIT 0x53
-#define R511_SYS_PWR_CLK 0x54 /* OV511+/OV518(+) only */
-#define R511_SYS_LED_CTL 0x55 /* OV511+ only */
-#define R511_SYS_USER 0x5E
-#define R511_SYS_CUST_ID 0x5F
-
-/* OmniCE (compression) registers */
-#define R511_COMP_PHY 0x70
-#define R511_COMP_PHUV 0x71
-#define R511_COMP_PVY 0x72
-#define R511_COMP_PVUV 0x73
-#define R511_COMP_QHY 0x74
-#define R511_COMP_QHUV 0x75
-#define R511_COMP_QVY 0x76
-#define R511_COMP_QVUV 0x77
-#define R511_COMP_EN 0x78
-#define R511_COMP_LUT_EN 0x79
-#define R511_COMP_LUT_BEGIN 0x80
-
-/* --------------------------------- */
-/* ALTERNATE NUMBERS */
-/* --------------------------------- */
-
-/* Alternate numbers for various max packet sizes (OV511 only) */
-#define OV511_ALT_SIZE_992 0
-#define OV511_ALT_SIZE_993 1
-#define OV511_ALT_SIZE_768 2
-#define OV511_ALT_SIZE_769 3
-#define OV511_ALT_SIZE_512 4
-#define OV511_ALT_SIZE_513 5
-#define OV511_ALT_SIZE_257 6
-#define OV511_ALT_SIZE_0 7
-
-/* Alternate numbers for various max packet sizes (OV511+ only) */
-#define OV511PLUS_ALT_SIZE_0 0
-#define OV511PLUS_ALT_SIZE_33 1
-#define OV511PLUS_ALT_SIZE_129 2
-#define OV511PLUS_ALT_SIZE_257 3
-#define OV511PLUS_ALT_SIZE_385 4
-#define OV511PLUS_ALT_SIZE_513 5
-#define OV511PLUS_ALT_SIZE_769 6
-#define OV511PLUS_ALT_SIZE_961 7
-
-/* Alternate numbers for various max packet sizes (OV518(+) only) */
-#define OV518_ALT_SIZE_0 0
-#define OV518_ALT_SIZE_128 1
-#define OV518_ALT_SIZE_256 2
-#define OV518_ALT_SIZE_384 3
-#define OV518_ALT_SIZE_512 4
-#define OV518_ALT_SIZE_640 5
-#define OV518_ALT_SIZE_768 6
-#define OV518_ALT_SIZE_896 7
-
-/* --------------------------------- */
-/* OV7610 REGISTER MNEMONICS */
-/* --------------------------------- */
-
-/* OV7610 registers */
-#define OV7610_REG_GAIN 0x00 /* gain setting (5:0) */
-#define OV7610_REG_BLUE 0x01 /* blue channel balance */
-#define OV7610_REG_RED 0x02 /* red channel balance */
-#define OV7610_REG_SAT 0x03 /* saturation */
- /* 04 reserved */
-#define OV7610_REG_CNT 0x05 /* Y contrast */
-#define OV7610_REG_BRT 0x06 /* Y brightness */
- /* 08-0b reserved */
-#define OV7610_REG_BLUE_BIAS 0x0C /* blue channel bias (5:0) */
-#define OV7610_REG_RED_BIAS 0x0D /* read channel bias (5:0) */
-#define OV7610_REG_GAMMA_COEFF 0x0E /* gamma settings */
-#define OV7610_REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
-#define OV7610_REG_EXP 0x10 /* manual exposure setting */
-#define OV7610_REG_CLOCK 0x11 /* polarity/clock prescaler */
-#define OV7610_REG_COM_A 0x12 /* misc common regs */
-#define OV7610_REG_COM_B 0x13 /* misc common regs */
-#define OV7610_REG_COM_C 0x14 /* misc common regs */
-#define OV7610_REG_COM_D 0x15 /* misc common regs */
-#define OV7610_REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
-#define OV7610_REG_HWIN_START 0x17 /* horizontal window start */
-#define OV7610_REG_HWIN_END 0x18 /* horizontal window end */
-#define OV7610_REG_VWIN_START 0x19 /* vertical window start */
-#define OV7610_REG_VWIN_END 0x1A /* vertical window end */
-#define OV7610_REG_PIXEL_SHIFT 0x1B /* pixel shift */
-#define OV7610_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
-#define OV7610_REG_ID_LOW 0x1D /* manufacturer ID LSB */
- /* 0e-0f reserved */
-#define OV7610_REG_COM_E 0x20 /* misc common regs */
-#define OV7610_REG_YOFFSET 0x21 /* Y channel offset */
-#define OV7610_REG_UOFFSET 0x22 /* U channel offset */
- /* 23 reserved */
-#define OV7610_REG_ECW 0x24 /* Exposure white level for AEC */
-#define OV7610_REG_ECB 0x25 /* Exposure black level for AEC */
-#define OV7610_REG_COM_F 0x26 /* misc settings */
-#define OV7610_REG_COM_G 0x27 /* misc settings */
-#define OV7610_REG_COM_H 0x28 /* misc settings */
-#define OV7610_REG_COM_I 0x29 /* misc settings */
-#define OV7610_REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
-#define OV7610_REG_FRAMERATE_L 0x2B /* frame rate LSB */
-#define OV7610_REG_ALC 0x2C /* Auto Level Control settings */
-#define OV7610_REG_COM_J 0x2D /* misc settings */
-#define OV7610_REG_VOFFSET 0x2E /* V channel offset adjustment */
-#define OV7610_REG_ARRAY_BIAS 0x2F /* Array bias -- don't change */
- /* 30-32 reserved */
-#define OV7610_REG_YGAMMA 0x33 /* misc gamma settings (7:6) */
-#define OV7610_REG_BIAS_ADJUST 0x34 /* misc bias settings */
-#define OV7610_REG_COM_L 0x35 /* misc settings */
- /* 36-37 reserved */
-#define OV7610_REG_COM_K 0x38 /* misc registers */
-
-/* --------------------------------- */
-/* I2C ADDRESSES */
-/* --------------------------------- */
-
-#define OV7xx0_SID 0x42
-#define OV6xx0_SID 0xC0
-#define OV8xx0_SID 0xA0
-#define KS0127_SID 0xD8
-#define SAA7111A_SID 0x48
-
-/* --------------------------------- */
-/* MISCELLANEOUS DEFINES */
-/* --------------------------------- */
-
-#define I2C_CLOCK_PRESCALER 0x03
-
-#define FRAMES_PER_DESC 10 /* FIXME - What should this be? */
-#define MAX_FRAME_SIZE_PER_DESC 993 /* For statically allocated stuff */
-#define PIXELS_PER_SEG 256 /* Pixels per segment */
-
-#define OV511_ENDPOINT_ADDRESS 1 /* Isoc endpoint number */
-
-#define OV511_NUMFRAMES 2
-#if OV511_NUMFRAMES > VIDEO_MAX_FRAME
- #error "OV511_NUMFRAMES is too high"
-#endif
-
-#define OV511_NUMSBUF 2
-
-/* Control transfers use up to 4 bytes */
-#define OV511_CBUF_SIZE 4
-
-/* Size of usb_make_path() buffer */
-#define OV511_USB_PATH_LEN 64
-
-/* Bridge types */
-enum {
- BRG_UNKNOWN,
- BRG_OV511,
- BRG_OV511PLUS,
- BRG_OV518,
- BRG_OV518PLUS,
-};
-
-/* Bridge classes */
-enum {
- BCL_UNKNOWN,
- BCL_OV511,
- BCL_OV518,
-};
-
-/* Sensor types */
-enum {
- SEN_UNKNOWN,
- SEN_OV76BE,
- SEN_OV7610,
- SEN_OV7620,
- SEN_OV7620AE,
- SEN_OV6620,
- SEN_OV6630,
- SEN_OV6630AE,
- SEN_OV6630AF,
- SEN_OV8600,
- SEN_KS0127,
- SEN_KS0127B,
- SEN_SAA7111A,
-};
-
-enum {
- STATE_SCANNING, /* Scanning for start */
- STATE_HEADER, /* Parsing header */
- STATE_LINES, /* Parsing lines */
-};
-
-/* Buffer states */
-enum {
- BUF_NOT_ALLOCATED,
- BUF_ALLOCATED,
-};
-
-/* --------- Definition of ioctl interface --------- */
-
-#define OV511_INTERFACE_VER 101
-
-/* LED options */
-enum {
- LED_OFF,
- LED_ON,
- LED_AUTO,
-};
-
-/* Raw frame formats */
-enum {
- RAWFMT_INVALID,
- RAWFMT_YUV400,
- RAWFMT_YUV420,
- RAWFMT_YUV422,
- RAWFMT_GBR422,
-};
-
-struct ov511_i2c_struct {
- unsigned char slave; /* Write slave ID (read ID - 1) */
- unsigned char reg; /* Index of register */
- unsigned char value; /* User sets this w/ write, driver does w/ read */
- unsigned char mask; /* Bits to be changed. Not used with read ops */
-};
-
-/* ioctls */
-#define OV511IOC_WI2C _IOW('v', BASE_VIDIOCPRIVATE + 5, \
- struct ov511_i2c_struct)
-#define OV511IOC_RI2C _IOWR('v', BASE_VIDIOCPRIVATE + 6, \
- struct ov511_i2c_struct)
-/* ------------- End IOCTL interface -------------- */
-
-struct usb_ov511; /* Forward declaration */
-
-struct ov511_sbuf {
- struct usb_ov511 *ov;
- unsigned char *data;
- struct urb *urb;
- spinlock_t lock;
- int n;
-};
-
-enum {
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
- FRAME_READY, /* Ready to start grabbing */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_ERROR, /* Something bad happened while processing */
-};
-
-struct ov511_regvals {
- enum {
- OV511_DONE_BUS,
- OV511_REG_BUS,
- OV511_I2C_BUS,
- } bus;
- unsigned char reg;
- unsigned char val;
-};
-
-struct ov511_frame {
- int framenum; /* Index of this frame */
- unsigned char *data; /* Frame buffer */
- unsigned char *tempdata; /* Temp buffer for multi-stage conversions */
- unsigned char *rawdata; /* Raw camera data buffer */
- unsigned char *compbuf; /* Temp buffer for decompressor */
-
- int depth; /* Bytes per pixel */
- int width; /* Width application is expecting */
- int height; /* Height application is expecting */
-
- int rawwidth; /* Actual width of frame sent from camera */
- int rawheight; /* Actual height of frame sent from camera */
-
- int sub_flag; /* Sub-capture mode for this frame? */
- unsigned int format; /* Format for this frame */
- int compressed; /* Is frame compressed? */
-
- volatile int grabstate; /* State of grabbing */
- int scanstate; /* State of scanning */
-
- int bytes_recvd; /* Number of image bytes received from camera */
-
- long bytes_read; /* Amount that has been read() */
-
- wait_queue_head_t wq; /* Processes waiting */
-
- int snapshot; /* True if frame was a snapshot */
-};
-
-#define DECOMP_INTERFACE_VER 4
-
-/* Compression module operations */
-struct ov51x_decomp_ops {
- int (*decomp_400)(unsigned char *, unsigned char *, unsigned char *,
- int, int, int);
- int (*decomp_420)(unsigned char *, unsigned char *, unsigned char *,
- int, int, int);
- int (*decomp_422)(unsigned char *, unsigned char *, unsigned char *,
- int, int, int);
- struct module *owner;
-};
-
-struct usb_ov511 {
- struct video_device *vdev;
- struct usb_device *dev;
-
- int customid;
- char *desc;
- unsigned char iface;
- char usb_path[OV511_USB_PATH_LEN];
-
- /* Determined by sensor type */
- int maxwidth;
- int maxheight;
- int minwidth;
- int minheight;
-
- int brightness;
- int colour;
- int contrast;
- int hue;
- int whiteness;
- int exposure;
- int auto_brt; /* Auto brightness enabled flag */
- int auto_gain; /* Auto gain control enabled flag */
- int auto_exp; /* Auto exposure enabled flag */
- int backlight; /* Backlight exposure algorithm flag */
- int mirror; /* Image is reversed horizontally */
-
- int led_policy; /* LED: off|on|auto; OV511+ only */
-
- struct mutex lock; /* Serializes user-accessible operations */
- int user; /* user count for exclusive use */
-
- int streaming; /* Are we streaming Isochronous? */
- int grabbing; /* Are we grabbing? */
-
- int compress; /* Should the next frame be compressed? */
- int compress_inited; /* Are compression params uploaded? */
-
- int lightfreq; /* Power (lighting) frequency */
- int bandfilt; /* Banding filter enabled flag */
-
- unsigned char *fbuf; /* Videodev buffer area */
- unsigned char *tempfbuf; /* Temporary (intermediate) buffer area */
- unsigned char *rawfbuf; /* Raw camera data buffer area */
-
- int sub_flag; /* Pix Array subcapture on flag */
- int subx; /* Pix Array subcapture x offset */
- int suby; /* Pix Array subcapture y offset */
- int subw; /* Pix Array subcapture width */
- int subh; /* Pix Array subcapture height */
-
- int curframe; /* Current receiving sbuf */
- struct ov511_frame frame[OV511_NUMFRAMES];
-
- struct ov511_sbuf sbuf[OV511_NUMSBUF];
-
- wait_queue_head_t wq; /* Processes waiting */
-
- int snap_enabled; /* Snapshot mode enabled */
-
- int bridge; /* Type of bridge (BRG_*) */
- int bclass; /* Class of bridge (BCL_*) */
- int sensor; /* Type of image sensor chip (SEN_*) */
-
- int packet_size; /* Frame size per isoc desc */
- int packet_numbering; /* Is ISO frame numbering enabled? */
-
- /* Framebuffer/sbuf management */
- int buf_state;
- struct mutex buf_lock;
-
- struct ov51x_decomp_ops *decomp_ops;
-
- /* Stop streaming while changing picture settings */
- int stop_during_set;
-
- int stopped; /* Streaming is temporarily paused */
-
- /* Video decoder stuff */
- int input; /* Composite, S-VIDEO, etc... */
- int num_inputs; /* Number of inputs */
- int norm; /* NTSC / PAL / SECAM */
- int has_decoder; /* Device has a video decoder */
- int pal; /* Device is designed for PAL resolution */
-
- /* ov511 device number ID */
- int nr; /* Stores a device number */
-
- /* I2C interface */
- struct mutex i2c_lock; /* Protect I2C controller regs */
- unsigned char primary_i2c_slave; /* I2C write id of sensor */
-
- /* Control transaction stuff */
- unsigned char *cbuf; /* Buffer for payload */
- struct mutex cbuf_lock;
-};
-
-/* Used to represent a list of values and their respective symbolic names */
-struct symbolic_list {
- int num;
- char *name;
-};
-
-#define NOT_DEFINED_STR "Unknown"
-
-/* Returns the name of the matching element in the symbolic_list array. The
- * end of the list must be marked with an element that has a NULL name.
- */
-static inline char *
-symbolic(struct symbolic_list list[], int num)
-{
- int i;
-
- for (i = 0; list[i].name != NULL; i++)
- if (list[i].num == num)
- return (list[i].name);
-
- return (NOT_DEFINED_STR);
-}
-
-/* Compression stuff */
-
-#define OV511_QUANTABLESIZE 64
-#define OV518_QUANTABLESIZE 32
-
-#define OV511_YQUANTABLE { \
- 0, 1, 1, 2, 2, 3, 3, 4, \
- 1, 1, 1, 2, 2, 3, 4, 4, \
- 1, 1, 2, 2, 3, 4, 4, 4, \
- 2, 2, 2, 3, 4, 4, 4, 4, \
- 2, 2, 3, 4, 4, 5, 5, 5, \
- 3, 3, 4, 4, 5, 5, 5, 5, \
- 3, 4, 4, 4, 5, 5, 5, 5, \
- 4, 4, 4, 4, 5, 5, 5, 5 \
-}
-
-#define OV511_UVQUANTABLE { \
- 0, 2, 2, 3, 4, 4, 4, 4, \
- 2, 2, 2, 4, 4, 4, 4, 4, \
- 2, 2, 3, 4, 4, 4, 4, 4, \
- 3, 4, 4, 4, 4, 4, 4, 4, \
- 4, 4, 4, 4, 4, 4, 4, 4, \
- 4, 4, 4, 4, 4, 4, 4, 4, \
- 4, 4, 4, 4, 4, 4, 4, 4, \
- 4, 4, 4, 4, 4, 4, 4, 4 \
-}
-
-#define OV518_YQUANTABLE { \
- 5, 4, 5, 6, 6, 7, 7, 7, \
- 5, 5, 5, 5, 6, 7, 7, 7, \
- 6, 6, 6, 6, 7, 7, 7, 8, \
- 7, 7, 6, 7, 7, 7, 8, 8 \
-}
-
-#define OV518_UVQUANTABLE { \
- 6, 6, 6, 7, 7, 7, 7, 7, \
- 6, 6, 6, 7, 7, 7, 7, 7, \
- 6, 6, 6, 7, 7, 7, 7, 8, \
- 7, 7, 7, 7, 7, 7, 8, 8 \
-}
-
-#endif
diff --git a/drivers/media/video/ov6650.c b/drivers/media/video/ov6650.c
new file mode 100644
index 000000000000..cf93de988068
--- /dev/null
+++ b/drivers/media/video/ov6650.c
@@ -0,0 +1,1221 @@
+/*
+ * V4L2 SoC Camera driver for OmniVision OV6650 Camera Sensor
+ *
+ * Copyright (C) 2010 Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>
+ *
+ * Based on OmniVision OV96xx Camera Driver
+ * Copyright (C) 2009 Marek Vasut <marek.vasut@gmail.com>
+ *
+ * Based on ov772x camera driver:
+ * Copyright (C) 2008 Renesas Solutions Corp.
+ * Kuninori Morimoto <morimoto.kuninori@renesas.com>
+ *
+ * Based on ov7670 and soc_camera_platform driver,
+ * Copyright 2006-7 Jonathan Corbet <corbet@lwn.net>
+ * Copyright (C) 2008 Magnus Damm
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * Hardware specific bits initialy based on former work by Matt Callow
+ * drivers/media/video/omap/sensor_ov6650.c
+ * Copyright (C) 2006 Matt Callow
+ *
+ * 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/bitops.h>
+#include <linux/delay.h>
+#include <linux/i2c.h>
+#include <linux/slab.h>
+
+#include <media/soc_camera.h>
+#include <media/v4l2-chip-ident.h>
+
+
+/* Register definitions */
+#define REG_GAIN 0x00 /* range 00 - 3F */
+#define REG_BLUE 0x01
+#define REG_RED 0x02
+#define REG_SAT 0x03 /* [7:4] saturation [0:3] reserved */
+#define REG_HUE 0x04 /* [7:6] rsrvd [5] hue en [4:0] hue */
+
+#define REG_BRT 0x06
+
+#define REG_PIDH 0x0a
+#define REG_PIDL 0x0b
+
+#define REG_AECH 0x10
+#define REG_CLKRC 0x11 /* Data Format and Internal Clock */
+ /* [7:6] Input system clock (MHz)*/
+ /* 00=8, 01=12, 10=16, 11=24 */
+ /* [5:0]: Internal Clock Pre-Scaler */
+#define REG_COMA 0x12 /* [7] Reset */
+#define REG_COMB 0x13
+#define REG_COMC 0x14
+#define REG_COMD 0x15
+#define REG_COML 0x16
+#define REG_HSTRT 0x17
+#define REG_HSTOP 0x18
+#define REG_VSTRT 0x19
+#define REG_VSTOP 0x1a
+#define REG_PSHFT 0x1b
+#define REG_MIDH 0x1c
+#define REG_MIDL 0x1d
+#define REG_HSYNS 0x1e
+#define REG_HSYNE 0x1f
+#define REG_COME 0x20
+#define REG_YOFF 0x21
+#define REG_UOFF 0x22
+#define REG_VOFF 0x23
+#define REG_AEW 0x24
+#define REG_AEB 0x25
+#define REG_COMF 0x26
+#define REG_COMG 0x27
+#define REG_COMH 0x28
+#define REG_COMI 0x29
+
+#define REG_FRARL 0x2b
+#define REG_COMJ 0x2c
+#define REG_COMK 0x2d
+#define REG_AVGY 0x2e
+#define REG_REF0 0x2f
+#define REG_REF1 0x30
+#define REG_REF2 0x31
+#define REG_FRAJH 0x32
+#define REG_FRAJL 0x33
+#define REG_FACT 0x34
+#define REG_L1AEC 0x35
+#define REG_AVGU 0x36
+#define REG_AVGV 0x37
+
+#define REG_SPCB 0x60
+#define REG_SPCC 0x61
+#define REG_GAM1 0x62
+#define REG_GAM2 0x63
+#define REG_GAM3 0x64
+#define REG_SPCD 0x65
+
+#define REG_SPCE 0x68
+#define REG_ADCL 0x69
+
+#define REG_RMCO 0x6c
+#define REG_GMCO 0x6d
+#define REG_BMCO 0x6e
+
+
+/* Register bits, values, etc. */
+#define OV6650_PIDH 0x66 /* high byte of product ID number */
+#define OV6650_PIDL 0x50 /* low byte of product ID number */
+#define OV6650_MIDH 0x7F /* high byte of mfg ID */
+#define OV6650_MIDL 0xA2 /* low byte of mfg ID */
+
+#define DEF_GAIN 0x00
+#define DEF_BLUE 0x80
+#define DEF_RED 0x80
+
+#define SAT_SHIFT 4
+#define SAT_MASK (0xf << SAT_SHIFT)
+#define SET_SAT(x) (((x) << SAT_SHIFT) & SAT_MASK)
+
+#define HUE_EN BIT(5)
+#define HUE_MASK 0x1f
+#define DEF_HUE 0x10
+#define SET_HUE(x) (HUE_EN | ((x) & HUE_MASK))
+
+#define DEF_AECH 0x4D
+
+#define CLKRC_6MHz 0x00
+#define CLKRC_12MHz 0x40
+#define CLKRC_16MHz 0x80
+#define CLKRC_24MHz 0xc0
+#define CLKRC_DIV_MASK 0x3f
+#define GET_CLKRC_DIV(x) (((x) & CLKRC_DIV_MASK) + 1)
+
+#define COMA_RESET BIT(7)
+#define COMA_QCIF BIT(5)
+#define COMA_RAW_RGB BIT(4)
+#define COMA_RGB BIT(3)
+#define COMA_BW BIT(2)
+#define COMA_WORD_SWAP BIT(1)
+#define COMA_BYTE_SWAP BIT(0)
+#define DEF_COMA 0x00
+
+#define COMB_FLIP_V BIT(7)
+#define COMB_FLIP_H BIT(5)
+#define COMB_BAND_FILTER BIT(4)
+#define COMB_AWB BIT(2)
+#define COMB_AGC BIT(1)
+#define COMB_AEC BIT(0)
+#define DEF_COMB 0x5f
+
+#define COML_ONE_CHANNEL BIT(7)
+
+#define DEF_HSTRT 0x24
+#define DEF_HSTOP 0xd4
+#define DEF_VSTRT 0x04
+#define DEF_VSTOP 0x94
+
+#define COMF_HREF_LOW BIT(4)
+
+#define COMJ_PCLK_RISING BIT(4)
+#define COMJ_VSYNC_HIGH BIT(0)
+
+/* supported resolutions */
+#define W_QCIF (DEF_HSTOP - DEF_HSTRT)
+#define W_CIF (W_QCIF << 1)
+#define H_QCIF (DEF_VSTOP - DEF_VSTRT)
+#define H_CIF (H_QCIF << 1)
+
+#define FRAME_RATE_MAX 30
+
+
+struct ov6650_reg {
+ u8 reg;
+ u8 val;
+};
+
+struct ov6650 {
+ struct v4l2_subdev subdev;
+
+ int gain;
+ int blue;
+ int red;
+ int saturation;
+ int hue;
+ int brightness;
+ int exposure;
+ int gamma;
+ int aec;
+ bool vflip;
+ bool hflip;
+ bool awb;
+ bool agc;
+ bool half_scale; /* scale down output by 2 */
+ struct v4l2_rect rect; /* sensor cropping window */
+ unsigned long pclk_limit; /* from host */
+ unsigned long pclk_max; /* from resolution and format */
+ struct v4l2_fract tpf; /* as requested with s_parm */
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+};
+
+
+static enum v4l2_mbus_pixelcode ov6650_codes[] = {
+ V4L2_MBUS_FMT_YUYV8_2X8,
+ V4L2_MBUS_FMT_UYVY8_2X8,
+ V4L2_MBUS_FMT_YVYU8_2X8,
+ V4L2_MBUS_FMT_VYUY8_2X8,
+ V4L2_MBUS_FMT_SBGGR8_1X8,
+ V4L2_MBUS_FMT_GREY8_1X8,
+};
+
+static const struct v4l2_queryctrl ov6650_controls[] = {
+ {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "AGC",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 0x3f,
+ .step = 1,
+ .default_value = DEF_GAIN,
+ },
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "AWB",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = DEF_BLUE,
+ },
+ {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = DEF_RED,
+ },
+ {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 0xf,
+ .step = 1,
+ .default_value = 0x8,
+ },
+ {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = 0,
+ .maximum = HUE_MASK,
+ .step = 1,
+ .default_value = DEF_HUE,
+ },
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x80,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "AEC",
+ .minimum = 0,
+ .maximum = 3,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = DEF_AECH,
+ },
+ {
+ .id = V4L2_CID_GAMMA,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gamma",
+ .minimum = 0,
+ .maximum = 0xff,
+ .step = 1,
+ .default_value = 0x12,
+ },
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Vertically",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Horizontally",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ },
+};
+
+/* read a register */
+static int ov6650_reg_read(struct i2c_client *client, u8 reg, u8 *val)
+{
+ int ret;
+ u8 data = reg;
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 1,
+ .buf = &data,
+ };
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ goto err;
+
+ msg.flags = I2C_M_RD;
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ if (ret < 0)
+ goto err;
+
+ *val = data;
+ return 0;
+
+err:
+ dev_err(&client->dev, "Failed reading register 0x%02x!\n", reg);
+ return ret;
+}
+
+/* write a register */
+static int ov6650_reg_write(struct i2c_client *client, u8 reg, u8 val)
+{
+ int ret;
+ unsigned char data[2] = { reg, val };
+ struct i2c_msg msg = {
+ .addr = client->addr,
+ .flags = 0,
+ .len = 2,
+ .buf = data,
+ };
+
+ ret = i2c_transfer(client->adapter, &msg, 1);
+ udelay(100);
+
+ if (ret < 0) {
+ dev_err(&client->dev, "Failed writing register 0x%02x!\n", reg);
+ return ret;
+ }
+ return 0;
+}
+
+
+/* Read a register, alter its bits, write it back */
+static int ov6650_reg_rmw(struct i2c_client *client, u8 reg, u8 set, u8 mask)
+{
+ u8 val;
+ int ret;
+
+ ret = ov6650_reg_read(client, reg, &val);
+ if (ret) {
+ dev_err(&client->dev,
+ "[Read]-Modify-Write of register 0x%02x failed!\n",
+ reg);
+ return ret;
+ }
+
+ val &= ~mask;
+ val |= set;
+
+ ret = ov6650_reg_write(client, reg, val);
+ if (ret)
+ dev_err(&client->dev,
+ "Read-Modify-[Write] of register 0x%02x failed!\n",
+ reg);
+
+ return ret;
+}
+
+static struct ov6650 *to_ov6650(const struct i2c_client *client)
+{
+ return container_of(i2c_get_clientdata(client), struct ov6650, subdev);
+}
+
+/* Start/Stop streaming from the device */
+static int ov6650_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ return 0;
+}
+
+/* Alter bus settings on camera side */
+static int ov6650_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ struct i2c_client *client = to_i2c_client(to_soc_camera_control(icd));
+ int ret;
+
+ flags = soc_camera_apply_sensor_flags(icl, flags);
+
+ if (flags & SOCAM_PCLK_SAMPLE_RISING)
+ ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_PCLK_RISING, 0);
+ else
+ ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_PCLK_RISING);
+ if (ret)
+ return ret;
+
+ if (flags & SOCAM_HSYNC_ACTIVE_LOW)
+ ret = ov6650_reg_rmw(client, REG_COMF, COMF_HREF_LOW, 0);
+ else
+ ret = ov6650_reg_rmw(client, REG_COMF, 0, COMF_HREF_LOW);
+ if (ret)
+ return ret;
+
+ if (flags & SOCAM_VSYNC_ACTIVE_HIGH)
+ ret = ov6650_reg_rmw(client, REG_COMJ, COMJ_VSYNC_HIGH, 0);
+ else
+ ret = ov6650_reg_rmw(client, REG_COMJ, 0, COMJ_VSYNC_HIGH);
+
+ return ret;
+}
+
+/* Request bus settings on camera side */
+static unsigned long ov6650_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+
+ unsigned long flags = SOCAM_MASTER |
+ SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW |
+ SOCAM_DATA_ACTIVE_HIGH | SOCAM_DATAWIDTH_8;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+/* Get status of additional camera capabilities */
+static int ov6650_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+ uint8_t reg;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ ctrl->value = priv->agc;
+ break;
+ case V4L2_CID_GAIN:
+ if (priv->agc) {
+ ret = ov6650_reg_read(client, REG_GAIN, &reg);
+ ctrl->value = reg;
+ } else {
+ ctrl->value = priv->gain;
+ }
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl->value = priv->awb;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ if (priv->awb) {
+ ret = ov6650_reg_read(client, REG_BLUE, &reg);
+ ctrl->value = reg;
+ } else {
+ ctrl->value = priv->blue;
+ }
+ break;
+ case V4L2_CID_RED_BALANCE:
+ if (priv->awb) {
+ ret = ov6650_reg_read(client, REG_RED, &reg);
+ ctrl->value = reg;
+ } else {
+ ctrl->value = priv->red;
+ }
+ break;
+ case V4L2_CID_SATURATION:
+ ctrl->value = priv->saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctrl->value = priv->hue;
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = priv->brightness;
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl->value = priv->aec;
+ break;
+ case V4L2_CID_EXPOSURE:
+ if (priv->aec) {
+ ret = ov6650_reg_read(client, REG_AECH, &reg);
+ ctrl->value = reg;
+ } else {
+ ctrl->value = priv->exposure;
+ }
+ break;
+ case V4L2_CID_GAMMA:
+ ctrl->value = priv->gamma;
+ break;
+ case V4L2_CID_VFLIP:
+ ctrl->value = priv->vflip;
+ break;
+ case V4L2_CID_HFLIP:
+ ctrl->value = priv->hflip;
+ break;
+ }
+ return ret;
+}
+
+/* Set status of additional camera capabilities */
+static int ov6650_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTOGAIN:
+ ret = ov6650_reg_rmw(client, REG_COMB,
+ ctrl->value ? COMB_AGC : 0, COMB_AGC);
+ if (!ret)
+ priv->agc = ctrl->value;
+ break;
+ case V4L2_CID_GAIN:
+ ret = ov6650_reg_write(client, REG_GAIN, ctrl->value);
+ if (!ret)
+ priv->gain = ctrl->value;
+ break;
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ret = ov6650_reg_rmw(client, REG_COMB,
+ ctrl->value ? COMB_AWB : 0, COMB_AWB);
+ if (!ret)
+ priv->awb = ctrl->value;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = ov6650_reg_write(client, REG_BLUE, ctrl->value);
+ if (!ret)
+ priv->blue = ctrl->value;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ret = ov6650_reg_write(client, REG_RED, ctrl->value);
+ if (!ret)
+ priv->red = ctrl->value;
+ break;
+ case V4L2_CID_SATURATION:
+ ret = ov6650_reg_rmw(client, REG_SAT, SET_SAT(ctrl->value),
+ SAT_MASK);
+ if (!ret)
+ priv->saturation = ctrl->value;
+ break;
+ case V4L2_CID_HUE:
+ ret = ov6650_reg_rmw(client, REG_HUE, SET_HUE(ctrl->value),
+ HUE_MASK);
+ if (!ret)
+ priv->hue = ctrl->value;
+ break;
+ case V4L2_CID_BRIGHTNESS:
+ ret = ov6650_reg_write(client, REG_BRT, ctrl->value);
+ if (!ret)
+ priv->brightness = ctrl->value;
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ switch (ctrl->value) {
+ case V4L2_EXPOSURE_AUTO:
+ ret = ov6650_reg_rmw(client, REG_COMB, COMB_AEC, 0);
+ break;
+ default:
+ ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_AEC);
+ break;
+ }
+ if (!ret)
+ priv->aec = ctrl->value;
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = ov6650_reg_write(client, REG_AECH, ctrl->value);
+ if (!ret)
+ priv->exposure = ctrl->value;
+ break;
+ case V4L2_CID_GAMMA:
+ ret = ov6650_reg_write(client, REG_GAM1, ctrl->value);
+ if (!ret)
+ priv->gamma = ctrl->value;
+ break;
+ case V4L2_CID_VFLIP:
+ ret = ov6650_reg_rmw(client, REG_COMB,
+ ctrl->value ? COMB_FLIP_V : 0, COMB_FLIP_V);
+ if (!ret)
+ priv->vflip = ctrl->value;
+ break;
+ case V4L2_CID_HFLIP:
+ ret = ov6650_reg_rmw(client, REG_COMB,
+ ctrl->value ? COMB_FLIP_H : 0, COMB_FLIP_H);
+ if (!ret)
+ priv->hflip = ctrl->value;
+ break;
+ }
+
+ return ret;
+}
+
+/* Get chip identification */
+static int ov6650_g_chip_ident(struct v4l2_subdev *sd,
+ struct v4l2_dbg_chip_ident *id)
+{
+ id->ident = V4L2_IDENT_OV6650;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int ov6650_get_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ int ret;
+ u8 val;
+
+ if (reg->reg & ~0xff)
+ return -EINVAL;
+
+ reg->size = 1;
+
+ ret = ov6650_reg_read(client, reg->reg, &val);
+ if (!ret)
+ reg->val = (__u64)val;
+
+ return ret;
+}
+
+static int ov6650_set_register(struct v4l2_subdev *sd,
+ struct v4l2_dbg_register *reg)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+
+ if (reg->reg & ~0xff || reg->val & ~0xff)
+ return -EINVAL;
+
+ return ov6650_reg_write(client, reg->reg, reg->val);
+}
+#endif
+
+static int ov6650_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->c = priv->rect;
+
+ return 0;
+}
+
+static int ov6650_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+ struct v4l2_rect *rect = &a->c;
+ int ret;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ rect->left = ALIGN(rect->left, 2);
+ rect->width = ALIGN(rect->width, 2);
+ rect->top = ALIGN(rect->top, 2);
+ rect->height = ALIGN(rect->height, 2);
+ soc_camera_limit_side(&rect->left, &rect->width,
+ DEF_HSTRT << 1, 2, W_CIF);
+ soc_camera_limit_side(&rect->top, &rect->height,
+ DEF_VSTRT << 1, 2, H_CIF);
+
+ ret = ov6650_reg_write(client, REG_HSTRT, rect->left >> 1);
+ if (!ret) {
+ priv->rect.left = rect->left;
+ ret = ov6650_reg_write(client, REG_HSTOP,
+ (rect->left + rect->width) >> 1);
+ }
+ if (!ret) {
+ priv->rect.width = rect->width;
+ ret = ov6650_reg_write(client, REG_VSTRT, rect->top >> 1);
+ }
+ if (!ret) {
+ priv->rect.top = rect->top;
+ ret = ov6650_reg_write(client, REG_VSTOP,
+ (rect->top + rect->height) >> 1);
+ }
+ if (!ret)
+ priv->rect.height = rect->height;
+
+ return ret;
+}
+
+static int ov6650_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
+{
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ a->bounds.left = DEF_HSTRT << 1;
+ a->bounds.top = DEF_VSTRT << 1;
+ a->bounds.width = W_CIF;
+ a->bounds.height = H_CIF;
+ a->defrect = a->bounds;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+static int ov6650_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+
+ mf->width = priv->rect.width >> priv->half_scale;
+ mf->height = priv->rect.height >> priv->half_scale;
+ mf->code = priv->code;
+ mf->colorspace = priv->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+static bool is_unscaled_ok(int width, int height, struct v4l2_rect *rect)
+{
+ return width > rect->width >> 1 || height > rect->height >> 1;
+}
+
+static u8 to_clkrc(struct v4l2_fract *timeperframe,
+ unsigned long pclk_limit, unsigned long pclk_max)
+{
+ unsigned long pclk;
+
+ if (timeperframe->numerator && timeperframe->denominator)
+ pclk = pclk_max * timeperframe->denominator /
+ (FRAME_RATE_MAX * timeperframe->numerator);
+ else
+ pclk = pclk_max;
+
+ if (pclk_limit && pclk_limit < pclk)
+ pclk = pclk_limit;
+
+ return (pclk_max - 1) / pclk;
+}
+
+/* set the format we will capture in */
+static int ov6650_s_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct soc_camera_sense *sense = icd->sense;
+ struct ov6650 *priv = to_ov6650(client);
+ bool half_scale = !is_unscaled_ok(mf->width, mf->height, &priv->rect);
+ struct v4l2_crop a = {
+ .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ .c = {
+ .left = priv->rect.left + (priv->rect.width >> 1) -
+ (mf->width >> (1 - half_scale)),
+ .top = priv->rect.top + (priv->rect.height >> 1) -
+ (mf->height >> (1 - half_scale)),
+ .width = mf->width << half_scale,
+ .height = mf->height << half_scale,
+ },
+ };
+ enum v4l2_mbus_pixelcode code = mf->code;
+ unsigned long mclk, pclk;
+ u8 coma_set = 0, coma_mask = 0, coml_set, coml_mask, clkrc;
+ int ret;
+
+ /* select color matrix configuration for given color encoding */
+ switch (code) {
+ case V4L2_MBUS_FMT_GREY8_1X8:
+ dev_dbg(&client->dev, "pixel format GREY8_1X8\n");
+ coma_mask |= COMA_RGB | COMA_WORD_SWAP | COMA_BYTE_SWAP;
+ coma_set |= COMA_BW;
+ break;
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ dev_dbg(&client->dev, "pixel format YUYV8_2X8_LE\n");
+ coma_mask |= COMA_RGB | COMA_BW | COMA_BYTE_SWAP;
+ coma_set |= COMA_WORD_SWAP;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ dev_dbg(&client->dev, "pixel format YVYU8_2X8_LE (untested)\n");
+ coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP |
+ COMA_BYTE_SWAP;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ dev_dbg(&client->dev, "pixel format YUYV8_2X8_BE\n");
+ if (half_scale) {
+ coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
+ coma_set |= COMA_BYTE_SWAP;
+ } else {
+ coma_mask |= COMA_RGB | COMA_BW;
+ coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
+ }
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ dev_dbg(&client->dev, "pixel format YVYU8_2X8_BE (untested)\n");
+ if (half_scale) {
+ coma_mask |= COMA_RGB | COMA_BW;
+ coma_set |= COMA_BYTE_SWAP | COMA_WORD_SWAP;
+ } else {
+ coma_mask |= COMA_RGB | COMA_BW | COMA_WORD_SWAP;
+ coma_set |= COMA_BYTE_SWAP;
+ }
+ break;
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ dev_dbg(&client->dev, "pixel format SBGGR8_1X8 (untested)\n");
+ coma_mask |= COMA_BW | COMA_BYTE_SWAP | COMA_WORD_SWAP;
+ coma_set |= COMA_RAW_RGB | COMA_RGB;
+ break;
+ default:
+ dev_err(&client->dev, "Pixel format not handled: 0x%x\n", code);
+ return -EINVAL;
+ }
+ priv->code = code;
+
+ if (code == V4L2_MBUS_FMT_GREY8_1X8 ||
+ code == V4L2_MBUS_FMT_SBGGR8_1X8) {
+ coml_mask = COML_ONE_CHANNEL;
+ coml_set = 0;
+ priv->pclk_max = 4000000;
+ } else {
+ coml_mask = 0;
+ coml_set = COML_ONE_CHANNEL;
+ priv->pclk_max = 8000000;
+ }
+
+ if (code == V4L2_MBUS_FMT_SBGGR8_1X8)
+ priv->colorspace = V4L2_COLORSPACE_SRGB;
+ else if (code != 0)
+ priv->colorspace = V4L2_COLORSPACE_JPEG;
+
+ if (half_scale) {
+ dev_dbg(&client->dev, "max resolution: QCIF\n");
+ coma_set |= COMA_QCIF;
+ priv->pclk_max /= 2;
+ } else {
+ dev_dbg(&client->dev, "max resolution: CIF\n");
+ coma_mask |= COMA_QCIF;
+ }
+ priv->half_scale = half_scale;
+
+ if (sense) {
+ if (sense->master_clock == 8000000) {
+ dev_dbg(&client->dev, "8MHz input clock\n");
+ clkrc = CLKRC_6MHz;
+ } else if (sense->master_clock == 12000000) {
+ dev_dbg(&client->dev, "12MHz input clock\n");
+ clkrc = CLKRC_12MHz;
+ } else if (sense->master_clock == 16000000) {
+ dev_dbg(&client->dev, "16MHz input clock\n");
+ clkrc = CLKRC_16MHz;
+ } else if (sense->master_clock == 24000000) {
+ dev_dbg(&client->dev, "24MHz input clock\n");
+ clkrc = CLKRC_24MHz;
+ } else {
+ dev_err(&client->dev,
+ "unspported input clock, check platform data\n");
+ return -EINVAL;
+ }
+ mclk = sense->master_clock;
+ priv->pclk_limit = sense->pixel_clock_max;
+ } else {
+ clkrc = CLKRC_24MHz;
+ mclk = 24000000;
+ priv->pclk_limit = 0;
+ dev_dbg(&client->dev, "using default 24MHz input clock\n");
+ }
+
+ clkrc |= to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+
+ pclk = priv->pclk_max / GET_CLKRC_DIV(clkrc);
+ dev_dbg(&client->dev, "pixel clock divider: %ld.%ld\n",
+ mclk / pclk, 10 * mclk % pclk / pclk);
+
+ ret = ov6650_s_crop(sd, &a);
+ if (!ret)
+ ret = ov6650_reg_rmw(client, REG_COMA, coma_set, coma_mask);
+ if (!ret)
+ ret = ov6650_reg_write(client, REG_CLKRC, clkrc);
+ if (!ret)
+ ret = ov6650_reg_rmw(client, REG_COML, coml_set, coml_mask);
+
+ if (!ret) {
+ mf->colorspace = priv->colorspace;
+ mf->width = priv->rect.width >> half_scale;
+ mf->height = priv->rect.height >> half_scale;
+ }
+
+ return ret;
+}
+
+static int ov6650_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+
+ if (is_unscaled_ok(mf->width, mf->height, &priv->rect))
+ v4l_bound_align_image(&mf->width, 2, W_CIF, 1,
+ &mf->height, 2, H_CIF, 1, 0);
+
+ mf->field = V4L2_FIELD_NONE;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_Y10_1X10:
+ mf->code = V4L2_MBUS_FMT_GREY8_1X8;
+ case V4L2_MBUS_FMT_GREY8_1X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ mf->colorspace = V4L2_COLORSPACE_JPEG;
+ break;
+ default:
+ mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ mf->colorspace = V4L2_COLORSPACE_SRGB;
+ break;
+ }
+
+ return 0;
+}
+
+static int ov6650_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (index >= ARRAY_SIZE(ov6650_codes))
+ return -EINVAL;
+
+ *code = ov6650_codes[index];
+ return 0;
+}
+
+static int ov6650_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(cp, 0, sizeof(*cp));
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = GET_CLKRC_DIV(to_clkrc(&priv->tpf,
+ priv->pclk_limit, priv->pclk_max));
+ cp->timeperframe.denominator = FRAME_RATE_MAX;
+
+ dev_dbg(&client->dev, "Frame interval: %u/%u s\n",
+ cp->timeperframe.numerator, cp->timeperframe.denominator);
+
+ return 0;
+}
+
+static int ov6650_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov6650 *priv = to_ov6650(client);
+ struct v4l2_captureparm *cp = &parms->parm.capture;
+ struct v4l2_fract *tpf = &cp->timeperframe;
+ int div, ret;
+ u8 clkrc;
+
+ if (parms->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (cp->extendedmode != 0)
+ return -EINVAL;
+
+ if (tpf->numerator == 0 || tpf->denominator == 0)
+ div = 1; /* Reset to full rate */
+ else
+ div = (tpf->numerator * FRAME_RATE_MAX) / tpf->denominator;
+
+ if (div == 0)
+ div = 1;
+ else if (div > GET_CLKRC_DIV(CLKRC_DIV_MASK))
+ div = GET_CLKRC_DIV(CLKRC_DIV_MASK);
+
+ /*
+ * Keep result to be used as tpf limit
+ * for subseqent clock divider calculations
+ */
+ priv->tpf.numerator = div;
+ priv->tpf.denominator = FRAME_RATE_MAX;
+
+ clkrc = to_clkrc(&priv->tpf, priv->pclk_limit, priv->pclk_max);
+
+ ret = ov6650_reg_rmw(client, REG_CLKRC, clkrc, CLKRC_DIV_MASK);
+ if (!ret) {
+ tpf->numerator = GET_CLKRC_DIV(clkrc);
+ tpf->denominator = FRAME_RATE_MAX;
+ }
+
+ return ret;
+}
+
+/* Soft reset the camera. This has nothing to do with the RESET pin! */
+static int ov6650_reset(struct i2c_client *client)
+{
+ int ret;
+
+ dev_dbg(&client->dev, "reset\n");
+
+ ret = ov6650_reg_rmw(client, REG_COMA, COMA_RESET, 0);
+ if (ret)
+ dev_err(&client->dev,
+ "An error occured while entering soft reset!\n");
+
+ return ret;
+}
+
+/* program default register values */
+static int ov6650_prog_dflt(struct i2c_client *client)
+{
+ int ret;
+
+ dev_dbg(&client->dev, "initializing\n");
+
+ ret = ov6650_reg_write(client, REG_COMA, 0); /* ~COMA_RESET */
+ if (!ret)
+ ret = ov6650_reg_rmw(client, REG_COMB, 0, COMB_BAND_FILTER);
+
+ return ret;
+}
+
+static int ov6650_video_probe(struct soc_camera_device *icd,
+ struct i2c_client *client)
+{
+ u8 pidh, pidl, midh, midl;
+ int ret = 0;
+
+ /*
+ * check and show product ID and manufacturer ID
+ */
+ ret = ov6650_reg_read(client, REG_PIDH, &pidh);
+ if (!ret)
+ ret = ov6650_reg_read(client, REG_PIDL, &pidl);
+ if (!ret)
+ ret = ov6650_reg_read(client, REG_MIDH, &midh);
+ if (!ret)
+ ret = ov6650_reg_read(client, REG_MIDL, &midl);
+
+ if (ret)
+ return ret;
+
+ if ((pidh != OV6650_PIDH) || (pidl != OV6650_PIDL)) {
+ dev_err(&client->dev, "Product ID error 0x%02x:0x%02x\n",
+ pidh, pidl);
+ return -ENODEV;
+ }
+
+ dev_info(&client->dev,
+ "ov6650 Product ID 0x%02x:0x%02x Manufacturer ID 0x%02x:0x%02x\n",
+ pidh, pidl, midh, midl);
+
+ ret = ov6650_reset(client);
+ if (!ret)
+ ret = ov6650_prog_dflt(client);
+
+ return ret;
+}
+
+static struct soc_camera_ops ov6650_ops = {
+ .set_bus_param = ov6650_set_bus_param,
+ .query_bus_param = ov6650_query_bus_param,
+ .controls = ov6650_controls,
+ .num_controls = ARRAY_SIZE(ov6650_controls),
+};
+
+static struct v4l2_subdev_core_ops ov6650_core_ops = {
+ .g_ctrl = ov6650_g_ctrl,
+ .s_ctrl = ov6650_s_ctrl,
+ .g_chip_ident = ov6650_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .g_register = ov6650_get_register,
+ .s_register = ov6650_set_register,
+#endif
+};
+
+static struct v4l2_subdev_video_ops ov6650_video_ops = {
+ .s_stream = ov6650_s_stream,
+ .g_mbus_fmt = ov6650_g_fmt,
+ .s_mbus_fmt = ov6650_s_fmt,
+ .try_mbus_fmt = ov6650_try_fmt,
+ .enum_mbus_fmt = ov6650_enum_fmt,
+ .cropcap = ov6650_cropcap,
+ .g_crop = ov6650_g_crop,
+ .s_crop = ov6650_s_crop,
+ .g_parm = ov6650_g_parm,
+ .s_parm = ov6650_s_parm,
+};
+
+static struct v4l2_subdev_ops ov6650_subdev_ops = {
+ .core = &ov6650_core_ops,
+ .video = &ov6650_video_ops,
+};
+
+/*
+ * i2c_driver function
+ */
+static int ov6650_probe(struct i2c_client *client,
+ const struct i2c_device_id *did)
+{
+ struct ov6650 *priv;
+ struct soc_camera_device *icd = client->dev.platform_data;
+ struct soc_camera_link *icl;
+ int ret;
+
+ if (!icd) {
+ dev_err(&client->dev, "Missing soc-camera data!\n");
+ return -EINVAL;
+ }
+
+ icl = to_soc_camera_link(icd);
+ if (!icl) {
+ dev_err(&client->dev, "Missing platform_data for driver\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(*priv), GFP_KERNEL);
+ if (!priv) {
+ dev_err(&client->dev,
+ "Failed to allocate memory for private data!\n");
+ return -ENOMEM;
+ }
+
+ v4l2_i2c_subdev_init(&priv->subdev, client, &ov6650_subdev_ops);
+
+ icd->ops = &ov6650_ops;
+
+ priv->rect.left = DEF_HSTRT << 1;
+ priv->rect.top = DEF_VSTRT << 1;
+ priv->rect.width = W_CIF;
+ priv->rect.height = H_CIF;
+ priv->half_scale = false;
+ priv->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ priv->colorspace = V4L2_COLORSPACE_JPEG;
+
+ ret = ov6650_video_probe(icd, client);
+
+ if (ret) {
+ icd->ops = NULL;
+ kfree(priv);
+ }
+
+ return ret;
+}
+
+static int ov6650_remove(struct i2c_client *client)
+{
+ struct ov6650 *priv = to_ov6650(client);
+
+ kfree(priv);
+ return 0;
+}
+
+static const struct i2c_device_id ov6650_id[] = {
+ { "ov6650", 0 },
+ { }
+};
+MODULE_DEVICE_TABLE(i2c, ov6650_id);
+
+static struct i2c_driver ov6650_i2c_driver = {
+ .driver = {
+ .name = "ov6650",
+ },
+ .probe = ov6650_probe,
+ .remove = ov6650_remove,
+ .id_table = ov6650_id,
+};
+
+static int __init ov6650_module_init(void)
+{
+ return i2c_add_driver(&ov6650_i2c_driver);
+}
+
+static void __exit ov6650_module_exit(void)
+{
+ i2c_del_driver(&ov6650_i2c_driver);
+}
+
+module_init(ov6650_module_init);
+module_exit(ov6650_module_exit);
+
+MODULE_DESCRIPTION("SoC Camera driver for OmniVision OV6650");
+MODULE_AUTHOR("Janusz Krzysztofik <jkrzyszt@tis.icnet.pl>");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/video/ov7670.c b/drivers/media/video/ov7670.c
index 91c886ab15c6..d4e7c11553c3 100644
--- a/drivers/media/video/ov7670.c
+++ b/drivers/media/video/ov7670.c
@@ -18,8 +18,9 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-mediabus.h>
+#include "ov7670.h"
MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
MODULE_DESCRIPTION("A low-level driver for OmniVision ov7670 sensors");
@@ -43,11 +44,6 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
#define QCIF_HEIGHT 144
/*
- * Our nominal (default) frame rate.
- */
-#define OV7670_FRAME_RATE 30
-
-/*
* The 7670 sits on i2c with ID 0x42
*/
#define OV7670_I2C_ADDR 0x42
@@ -198,7 +194,11 @@ struct ov7670_info {
struct ov7670_format_struct *fmt; /* Current format */
unsigned char sat; /* Saturation value */
int hue; /* Hue value */
+ int min_width; /* Filter out smaller sizes */
+ int min_height; /* Filter out smaller sizes */
+ int clock_speed; /* External clock speed (MHz) */
u8 clkrc; /* Clock divider value */
+ bool use_smbus; /* Use smbus I/O instead of I2C */
};
static inline struct ov7670_info *to_state(struct v4l2_subdev *sd)
@@ -415,8 +415,7 @@ static struct regval_list ov7670_fmt_raw[] = {
* ov7670 is not really an SMBUS device, though, so the communication
* is not always entirely reliable.
*/
-#ifdef CONFIG_OLPC_XO_1
-static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+static int ov7670_read_smbus(struct v4l2_subdev *sd, unsigned char reg,
unsigned char *value)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -431,7 +430,7 @@ static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
}
-static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+static int ov7670_write_smbus(struct v4l2_subdev *sd, unsigned char reg,
unsigned char value)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -442,11 +441,10 @@ static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
return ret;
}
-#else /* ! CONFIG_OLPC_XO_1 */
/*
* On most platforms, we'd rather do straight i2c I/O.
*/
-static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+static int ov7670_read_i2c(struct v4l2_subdev *sd, unsigned char reg,
unsigned char *value)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -479,7 +477,7 @@ static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
}
-static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+static int ov7670_write_i2c(struct v4l2_subdev *sd, unsigned char reg,
unsigned char value)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -498,8 +496,26 @@ static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
msleep(5); /* Wait for reset to run */
return ret;
}
-#endif /* CONFIG_OLPC_XO_1 */
+static int ov7670_read(struct v4l2_subdev *sd, unsigned char reg,
+ unsigned char *value)
+{
+ struct ov7670_info *info = to_state(sd);
+ if (info->use_smbus)
+ return ov7670_read_smbus(sd, reg, value);
+ else
+ return ov7670_read_i2c(sd, reg, value);
+}
+
+static int ov7670_write(struct v4l2_subdev *sd, unsigned char reg,
+ unsigned char value)
+{
+ struct ov7670_info *info = to_state(sd);
+ if (info->use_smbus)
+ return ov7670_write_smbus(sd, reg, value);
+ else
+ return ov7670_write_i2c(sd, reg, value);
+}
/*
* Write a list of register settings; ff/ff stops the process.
@@ -572,42 +588,37 @@ static int ov7670_detect(struct v4l2_subdev *sd)
/*
* Store information about the video data format. The color matrix
* is deeply tied into the format, so keep the relevant values here.
- * The magic matrix nubmers come from OmniVision.
+ * The magic matrix numbers come from OmniVision.
*/
static struct ov7670_format_struct {
- __u8 *desc;
- __u32 pixelformat;
+ enum v4l2_mbus_pixelcode mbus_code;
+ enum v4l2_colorspace colorspace;
struct regval_list *regs;
int cmatrix[CMATRIX_LEN];
- int bpp; /* Bytes per pixel */
} ov7670_formats[] = {
{
- .desc = "YUYV 4:2:2",
- .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
.regs = ov7670_fmt_yuv422,
.cmatrix = { 128, -128, 0, -34, -94, 128 },
- .bpp = 2,
},
{
- .desc = "RGB 444",
- .pixelformat = V4L2_PIX_FMT_RGB444,
+ .mbus_code = V4L2_MBUS_FMT_RGB444_2X8_PADHI_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.regs = ov7670_fmt_rgb444,
.cmatrix = { 179, -179, 0, -61, -176, 228 },
- .bpp = 2,
},
{
- .desc = "RGB 565",
- .pixelformat = V4L2_PIX_FMT_RGB565,
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.regs = ov7670_fmt_rgb565,
.cmatrix = { 179, -179, 0, -61, -176, 228 },
- .bpp = 2,
},
{
- .desc = "Raw RGB Bayer",
- .pixelformat = V4L2_PIX_FMT_SBGGR8,
+ .mbus_code = V4L2_MBUS_FMT_SBGGR8_1X8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
.regs = ov7670_fmt_raw,
.cmatrix = { 0, 0, 0, 0, 0, 0 },
- .bpp = 1
},
};
#define N_OV7670_FMTS ARRAY_SIZE(ov7670_formats)
@@ -680,10 +691,10 @@ static struct ov7670_win_size {
.width = QVGA_WIDTH,
.height = QVGA_HEIGHT,
.com7_bit = COM7_FMT_QVGA,
- .hstart = 164, /* Empirically determined */
- .hstop = 20,
- .vstart = 14,
- .vstop = 494,
+ .hstart = 168, /* Empirically determined */
+ .hstop = 24,
+ .vstart = 12,
+ .vstop = 492,
.regs = NULL,
},
/* QCIF */
@@ -734,51 +745,45 @@ static int ov7670_set_hw(struct v4l2_subdev *sd, int hstart, int hstop,
}
-static int ov7670_enum_fmt(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
+static int ov7670_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
{
- struct ov7670_format_struct *ofmt;
-
- if (fmt->index >= N_OV7670_FMTS)
+ if (index >= N_OV7670_FMTS)
return -EINVAL;
- ofmt = ov7670_formats + fmt->index;
- fmt->flags = 0;
- strcpy(fmt->description, ofmt->desc);
- fmt->pixelformat = ofmt->pixelformat;
+ *code = ov7670_formats[index].mbus_code;
return 0;
}
-
static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
- struct v4l2_format *fmt,
+ struct v4l2_mbus_framefmt *fmt,
struct ov7670_format_struct **ret_fmt,
struct ov7670_win_size **ret_wsize)
{
int index;
struct ov7670_win_size *wsize;
- struct v4l2_pix_format *pix = &fmt->fmt.pix;
for (index = 0; index < N_OV7670_FMTS; index++)
- if (ov7670_formats[index].pixelformat == pix->pixelformat)
+ if (ov7670_formats[index].mbus_code == fmt->code)
break;
if (index >= N_OV7670_FMTS) {
/* default to first format */
index = 0;
- pix->pixelformat = ov7670_formats[0].pixelformat;
+ fmt->code = ov7670_formats[0].mbus_code;
}
if (ret_fmt != NULL)
*ret_fmt = ov7670_formats + index;
/*
* Fields: the OV devices claim to be progressive.
*/
- pix->field = V4L2_FIELD_NONE;
+ fmt->field = V4L2_FIELD_NONE;
/*
* Round requested image size down to the nearest
* we support, but not below the smallest.
*/
for (wsize = ov7670_win_sizes; wsize < ov7670_win_sizes + N_WIN_SIZES;
wsize++)
- if (pix->width >= wsize->width && pix->height >= wsize->height)
+ if (fmt->width >= wsize->width && fmt->height >= wsize->height)
break;
if (wsize >= ov7670_win_sizes + N_WIN_SIZES)
wsize--; /* Take the smallest one */
@@ -787,14 +792,14 @@ static int ov7670_try_fmt_internal(struct v4l2_subdev *sd,
/*
* Note the size we'll actually handle.
*/
- pix->width = wsize->width;
- pix->height = wsize->height;
- pix->bytesperline = pix->width*ov7670_formats[index].bpp;
- pix->sizeimage = pix->height*pix->bytesperline;
+ fmt->width = wsize->width;
+ fmt->height = wsize->height;
+ fmt->colorspace = ov7670_formats[index].colorspace;
return 0;
}
-static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int ov7670_try_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
{
return ov7670_try_fmt_internal(sd, fmt, NULL, NULL);
}
@@ -802,15 +807,17 @@ static int ov7670_try_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
/*
* Set a format.
*/
-static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int ov7670_s_mbus_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *fmt)
{
- int ret;
struct ov7670_format_struct *ovfmt;
struct ov7670_win_size *wsize;
struct ov7670_info *info = to_state(sd);
unsigned char com7;
+ int ret;
ret = ov7670_try_fmt_internal(sd, fmt, &ovfmt, &wsize);
+
if (ret)
return ret;
/*
@@ -845,7 +852,7 @@ static int ov7670_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
*/
if (ret == 0)
ret = ov7670_write(sd, REG_CLKRC, info->clkrc);
- return ret;
+ return 0;
}
/*
@@ -863,7 +870,7 @@ static int ov7670_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
memset(cp, 0, sizeof(struct v4l2_captureparm));
cp->capability = V4L2_CAP_TIMEPERFRAME;
cp->timeperframe.numerator = 1;
- cp->timeperframe.denominator = OV7670_FRAME_RATE;
+ cp->timeperframe.denominator = info->clock_speed;
if ((info->clkrc & CLK_EXT) == 0 && (info->clkrc & CLK_SCALE) > 1)
cp->timeperframe.denominator /= (info->clkrc & CLK_SCALE);
return 0;
@@ -884,26 +891,72 @@ static int ov7670_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *parms)
if (tpf->numerator == 0 || tpf->denominator == 0)
div = 1; /* Reset to full rate */
else
- div = (tpf->numerator*OV7670_FRAME_RATE)/tpf->denominator;
+ div = (tpf->numerator * info->clock_speed) / tpf->denominator;
if (div == 0)
div = 1;
else if (div > CLK_SCALE)
div = CLK_SCALE;
info->clkrc = (info->clkrc & 0x80) | div;
tpf->numerator = 1;
- tpf->denominator = OV7670_FRAME_RATE/div;
+ tpf->denominator = info->clock_speed / div;
return ov7670_write(sd, REG_CLKRC, info->clkrc);
}
-
/*
- * Code for dealing with controls.
+ * Frame intervals. Since frame rates are controlled with the clock
+ * divider, we can only do 30/n for integer n values. So no continuous
+ * or stepwise options. Here we just pick a handful of logical values.
*/
+static int ov7670_frame_rates[] = { 30, 15, 10, 5, 1 };
+static int ov7670_enum_frameintervals(struct v4l2_subdev *sd,
+ struct v4l2_frmivalenum *interval)
+{
+ if (interval->index >= ARRAY_SIZE(ov7670_frame_rates))
+ return -EINVAL;
+ interval->type = V4L2_FRMIVAL_TYPE_DISCRETE;
+ interval->discrete.numerator = 1;
+ interval->discrete.denominator = ov7670_frame_rates[interval->index];
+ return 0;
+}
+
+/*
+ * Frame size enumeration
+ */
+static int ov7670_enum_framesizes(struct v4l2_subdev *sd,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct ov7670_info *info = to_state(sd);
+ int i;
+ int num_valid = -1;
+ __u32 index = fsize->index;
+
+ /*
+ * If a minimum width/height was requested, filter out the capture
+ * windows that fall outside that.
+ */
+ for (i = 0; i < N_WIN_SIZES; i++) {
+ struct ov7670_win_size *win = &ov7670_win_sizes[index];
+ if (info->min_width && win->width < info->min_width)
+ continue;
+ if (info->min_height && win->height < info->min_height)
+ continue;
+ if (index == ++num_valid) {
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = win->width;
+ fsize->discrete.height = win->height;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+/*
+ * Code for dealing with controls.
+ */
static int ov7670_store_cmatrix(struct v4l2_subdev *sd,
int matrix[CMATRIX_LEN])
@@ -1442,11 +1495,13 @@ static const struct v4l2_subdev_core_ops ov7670_core_ops = {
};
static const struct v4l2_subdev_video_ops ov7670_video_ops = {
- .enum_fmt = ov7670_enum_fmt,
- .try_fmt = ov7670_try_fmt,
- .s_fmt = ov7670_s_fmt,
+ .enum_mbus_fmt = ov7670_enum_mbus_fmt,
+ .try_mbus_fmt = ov7670_try_mbus_fmt,
+ .s_mbus_fmt = ov7670_s_mbus_fmt,
.s_parm = ov7670_s_parm,
.g_parm = ov7670_g_parm,
+ .enum_frameintervals = ov7670_enum_frameintervals,
+ .enum_framesizes = ov7670_enum_framesizes,
};
static const struct v4l2_subdev_ops ov7670_ops = {
@@ -1469,6 +1524,22 @@ static int ov7670_probe(struct i2c_client *client,
sd = &info->sd;
v4l2_i2c_subdev_init(sd, client, &ov7670_ops);
+ info->clock_speed = 30; /* default: a guess */
+ if (client->dev.platform_data) {
+ struct ov7670_config *config = client->dev.platform_data;
+
+ /*
+ * Must apply configuration before initializing device, because it
+ * selects I/O method.
+ */
+ info->min_width = config->min_width;
+ info->min_height = config->min_height;
+ info->use_smbus = config->use_smbus;
+
+ if (config->clock_speed)
+ info->clock_speed = config->clock_speed;
+ }
+
/* Make sure it's an ov7670 */
ret = ov7670_detect(sd);
if (ret) {
@@ -1483,8 +1554,7 @@ static int ov7670_probe(struct i2c_client *client,
info->fmt = &ov7670_formats[0];
info->sat = 128; /* Review this */
- info->clkrc = 1; /* 30fps */
-
+ info->clkrc = info->clock_speed / 30;
return 0;
}
@@ -1504,9 +1574,25 @@ static const struct i2c_device_id ov7670_id[] = {
};
MODULE_DEVICE_TABLE(i2c, ov7670_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "ov7670",
- .probe = ov7670_probe,
- .remove = ov7670_remove,
- .id_table = ov7670_id,
+static struct i2c_driver ov7670_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "ov7670",
+ },
+ .probe = ov7670_probe,
+ .remove = ov7670_remove,
+ .id_table = ov7670_id,
};
+
+static __init int init_ov7670(void)
+{
+ return i2c_add_driver(&ov7670_driver);
+}
+
+static __exit void exit_ov7670(void)
+{
+ i2c_del_driver(&ov7670_driver);
+}
+
+module_init(init_ov7670);
+module_exit(exit_ov7670);
diff --git a/drivers/media/video/ov7670.h b/drivers/media/video/ov7670.h
new file mode 100644
index 000000000000..b133bc123031
--- /dev/null
+++ b/drivers/media/video/ov7670.h
@@ -0,0 +1,20 @@
+/*
+ * A V4L2 driver for OmniVision OV7670 cameras.
+ *
+ * Copyright 2010 One Laptop Per Child
+ *
+ * This file may be distributed under the terms of the GNU General
+ * Public License, version 2.
+ */
+
+#ifndef __OV7670_H
+#define __OV7670_H
+
+struct ov7670_config {
+ int min_width; /* Filter out smaller sizes */
+ int min_height; /* Filter out smaller sizes */
+ int clock_speed; /* External clock speed (MHz) */
+ bool use_smbus; /* Use smbus I/O instead of I2C */
+};
+
+#endif
diff --git a/drivers/media/video/ov772x.c b/drivers/media/video/ov772x.c
index 7f8ece30c77b..48895ef863ff 100644
--- a/drivers/media/video/ov772x.c
+++ b/drivers/media/video/ov772x.c
@@ -440,21 +440,21 @@ static const struct regval_list ov772x_vga_regs[] = {
*/
static const struct ov772x_color_format ov772x_cfmts[] = {
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_YVYU8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = UV_ON,
.com3 = SWAP_YUV,
.com7 = OFMT_YUV,
},
{
- .code = V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
.colorspace = V4L2_COLORSPACE_JPEG,
.dsp3 = 0x0,
.com3 = 0x0,
@@ -599,8 +599,8 @@ static int ov772x_reset(struct i2c_client *client)
static int ov772x_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
- struct ov772x_priv *priv = to_ov772x(client);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
if (!enable) {
ov772x_mask_set(client, COM2, SOFT_SLEEP_MODE, SOFT_SLEEP_MODE);
@@ -645,8 +645,7 @@ static unsigned long ov772x_query_bus_param(struct soc_camera_device *icd)
static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
switch (ctrl->id) {
case V4L2_CID_VFLIP:
@@ -664,8 +663,8 @@ static int ov772x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
- struct ov772x_priv *priv = to_ov772x(client);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
int ret = 0;
u8 val;
@@ -715,8 +714,7 @@ static int ov772x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
id->ident = priv->model;
id->revision = 0;
@@ -728,7 +726,7 @@ static int ov772x_g_chip_ident(struct v4l2_subdev *sd,
static int ov772x_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
reg->size = 1;
@@ -747,7 +745,7 @@ static int ov772x_g_register(struct v4l2_subdev *sd,
static int ov772x_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->reg > 0xff ||
reg->val > 0xff)
@@ -954,13 +952,13 @@ static int ov772x_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int ov772x_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
- struct ov772x_priv *priv = to_ov772x(client);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
if (!priv->win || !priv->cfmt) {
u32 width = VGA_WIDTH, height = VGA_HEIGHT;
int ret = ov772x_set_params(client, &width, &height,
- V4L2_MBUS_FMT_YUYV8_2X8_LE);
+ V4L2_MBUS_FMT_YUYV8_2X8);
if (ret < 0)
return ret;
}
@@ -977,8 +975,8 @@ static int ov772x_g_fmt(struct v4l2_subdev *sd,
static int ov772x_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
- struct ov772x_priv *priv = to_ov772x(client);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
int ret = ov772x_set_params(client, &mf->width, &mf->height,
mf->code);
@@ -991,8 +989,7 @@ static int ov772x_s_fmt(struct v4l2_subdev *sd,
static int ov772x_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
- struct ov772x_priv *priv = to_ov772x(client);
+ struct ov772x_priv *priv = container_of(sd, struct ov772x_priv, subdev);
const struct ov772x_win_size *win;
int i;
@@ -1092,10 +1089,10 @@ static struct v4l2_subdev_core_ops ov772x_subdev_core_ops = {
#endif
};
-static int ov772x_enum_fmt(struct v4l2_subdev *sd, int index,
+static int ov772x_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(ov772x_cfmts))
+ if (index >= ARRAY_SIZE(ov772x_cfmts))
return -EINVAL;
*code = ov772x_cfmts[index].code;
@@ -1159,7 +1156,6 @@ static int ov772x_probe(struct i2c_client *client,
ret = ov772x_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -1172,7 +1168,6 @@ static int ov772x_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/ov9640.c b/drivers/media/video/ov9640.c
index 36599a65f548..53d88a2ab920 100644
--- a/drivers/media/video/ov9640.c
+++ b/drivers/media/video/ov9640.c
@@ -31,6 +31,8 @@
#include "ov9640.h"
+#define to_ov9640_sensor(sd) container_of(sd, struct ov9640_priv, subdev)
+
/* default register setup */
static const struct ov9640_reg ov9640_regs_dflt[] = {
{ OV9640_COM5, OV9640_COM5_SYSCLK | OV9640_COM5_LONGEXP },
@@ -155,7 +157,7 @@ static const struct ov9640_reg ov9640_regs_rgb[] = {
};
static enum v4l2_mbus_pixelcode ov9640_codes[] = {
- V4L2_MBUS_FMT_YUYV8_2X8_BE,
+ V4L2_MBUS_FMT_UYVY8_2X8,
V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE,
V4L2_MBUS_FMT_RGB565_2X8_LE,
};
@@ -308,9 +310,7 @@ static unsigned long ov9640_query_bus_param(struct soc_camera_device *icd)
/* Get status of additional camera capabilities */
static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
- struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
- struct ov9640_priv, subdev);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
switch (ctrl->id) {
case V4L2_CID_VFLIP:
@@ -326,9 +326,8 @@ static int ov9640_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
/* Set status of additional camera capabilities */
static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
- struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
- struct ov9640_priv, subdev);
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
int ret = 0;
@@ -360,9 +359,7 @@ static int ov9640_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
- struct ov9640_priv *priv = container_of(i2c_get_clientdata(client),
- struct ov9640_priv, subdev);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
id->ident = priv->model;
id->revision = priv->revision;
@@ -374,7 +371,7 @@ static int ov9640_g_chip_ident(struct v4l2_subdev *sd,
static int ov9640_get_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
u8 val;
@@ -395,7 +392,7 @@ static int ov9640_get_register(struct v4l2_subdev *sd,
static int ov9640_set_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->reg & ~0xff || reg->val & ~0xff)
return -EINVAL;
@@ -430,7 +427,7 @@ static void ov9640_alter_regs(enum v4l2_mbus_pixelcode code,
{
switch (code) {
default:
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
alt->com12 = OV9640_COM12_YUV_AVG;
alt->com13 = OV9640_COM13_Y_DELAY_EN |
OV9640_COM13_YUV_DLY(0x01);
@@ -493,7 +490,7 @@ static int ov9640_write_regs(struct i2c_client *client, u32 width,
}
/* select color matrix configuration for given color encoding */
- if (code == V4L2_MBUS_FMT_YUYV8_2X8_BE) {
+ if (code == V4L2_MBUS_FMT_UYVY8_2X8) {
matrix_regs = ov9640_regs_yuv;
matrix_regs_len = ARRAY_SIZE(ov9640_regs_yuv);
} else {
@@ -558,7 +555,7 @@ static int ov9640_prog_dflt(struct i2c_client *client)
static int ov9640_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct ov9640_reg_alt alts = {0};
enum v4l2_colorspace cspace;
enum v4l2_mbus_pixelcode code = mf->code;
@@ -579,8 +576,8 @@ static int ov9640_s_fmt(struct v4l2_subdev *sd,
cspace = V4L2_COLORSPACE_SRGB;
break;
default:
- code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
cspace = V4L2_COLORSPACE_JPEG;
}
@@ -606,18 +603,18 @@ static int ov9640_try_fmt(struct v4l2_subdev *sd,
mf->colorspace = V4L2_COLORSPACE_SRGB;
break;
default:
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
mf->colorspace = V4L2_COLORSPACE_JPEG;
}
return 0;
}
-static int ov9640_enum_fmt(struct v4l2_subdev *sd, int index,
+static int ov9640_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(ov9640_codes))
+ if (index >= ARRAY_SIZE(ov9640_codes))
return -EINVAL;
*code = ov9640_codes[index];
@@ -654,7 +651,8 @@ static int ov9640_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int ov9640_video_probe(struct soc_camera_device *icd,
struct i2c_client *client)
{
- struct ov9640_priv *priv = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
u8 pid, ver, midh, midl;
const char *devname;
int ret = 0;
@@ -783,7 +781,6 @@ static int ov9640_probe(struct i2c_client *client,
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -792,9 +789,9 @@ static int ov9640_probe(struct i2c_client *client,
static int ov9640_remove(struct i2c_client *client)
{
- struct ov9640_priv *priv = i2c_get_clientdata(client);
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct ov9640_priv *priv = to_ov9640_sensor(sd);
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/ovcamchip/Makefile b/drivers/media/video/ovcamchip/Makefile
deleted file mode 100644
index cba4cdf20f49..000000000000
--- a/drivers/media/video/ovcamchip/Makefile
+++ /dev/null
@@ -1,4 +0,0 @@
-ovcamchip-objs := ovcamchip_core.o ov6x20.o ov6x30.o ov7x10.o ov7x20.o \
- ov76be.o
-
-obj-$(CONFIG_VIDEO_OVCAMCHIP) += ovcamchip.o
diff --git a/drivers/media/video/ovcamchip/ov6x20.c b/drivers/media/video/ovcamchip/ov6x20.c
deleted file mode 100644
index c04130dab127..000000000000
--- a/drivers/media/video/ovcamchip/ov6x20.c
+++ /dev/null
@@ -1,414 +0,0 @@
-/* OmniVision OV6620/OV6120 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue gain */
-#define REG_RED 0x02 /* red gain */
-#define REG_SAT 0x03 /* saturation */
-#define REG_CNT 0x05 /* Y contrast */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_WB_BLUE 0x0C /* WB blue ratio [5:0] */
-#define REG_WB_RED 0x0D /* WB red ratio [5:0] */
-#define REG_EXP 0x10 /* exposure */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3A
-#define VWSBASE 0x05
-#define VWEBASE 0x06
-
-struct ov6x20 {
- int auto_brt;
- int auto_exp;
- int backlight;
- int bandfilt;
- int mirror;
-};
-
-/* Initial values for use with OV511/OV511+ cameras */
-static struct ovcamchip_regvals regvals_init_6x20_511[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x11, 0x01 },
- { 0x03, 0x60 },
- { 0x05, 0x7f }, /* For when autoadjust is off */
- { 0x07, 0xa8 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0x0f, 0x15 }, /* COMS */
- { 0x10, 0x75 }, /* AEC Exposure time */
- { 0x12, 0x24 }, /* Enable AGC and AWB */
- { 0x14, 0x04 },
- { 0x16, 0x03 },
- { 0x26, 0xb2 }, /* BLC enable */
- /* 0x28: 0x05 Selects RGB format if RGB on */
- { 0x28, 0x05 },
- { 0x2a, 0x04 }, /* Disable framerate adjust */
- { 0x2d, 0x99 },
- { 0x33, 0xa0 }, /* Color Processing Parameter */
- { 0x34, 0xd2 }, /* Max A/D range */
- { 0x38, 0x8b },
- { 0x39, 0x40 },
-
- { 0x3c, 0x39 }, /* Enable AEC mode changing */
- { 0x3c, 0x3c }, /* Change AEC mode */
- { 0x3c, 0x24 }, /* Disable AEC mode changing */
-
- { 0x3d, 0x80 },
- /* These next two registers (0x4a, 0x4b) are undocumented. They
- * control the color balance */
- { 0x4a, 0x80 },
- { 0x4b, 0x80 },
- { 0x4d, 0xd2 }, /* This reduces noise a bit */
- { 0x4e, 0xc1 },
- { 0x4f, 0x04 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Initial values for use with OV518 cameras */
-static struct ovcamchip_regvals regvals_init_6x20_518[] = {
- { 0x12, 0x80 }, /* Do a reset */
- { 0x03, 0xc0 }, /* Saturation */
- { 0x05, 0x8a }, /* Contrast */
- { 0x0c, 0x24 }, /* AWB blue */
- { 0x0d, 0x24 }, /* AWB red */
- { 0x0e, 0x8d }, /* Additional 2x gain */
- { 0x0f, 0x25 }, /* Black expanding level = 1.3V */
- { 0x11, 0x01 }, /* Clock div. */
- { 0x12, 0x24 }, /* Enable AGC and AWB */
- { 0x13, 0x01 }, /* (default) */
- { 0x14, 0x80 }, /* Set reserved bit 7 */
- { 0x15, 0x01 }, /* (default) */
- { 0x16, 0x03 }, /* (default) */
- { 0x17, 0x38 }, /* (default) */
- { 0x18, 0xea }, /* (default) */
- { 0x19, 0x04 },
- { 0x1a, 0x93 },
- { 0x1b, 0x00 }, /* (default) */
- { 0x1e, 0xc4 }, /* (default) */
- { 0x1f, 0x04 }, /* (default) */
- { 0x20, 0x20 }, /* Enable 1st stage aperture correction */
- { 0x21, 0x10 }, /* Y offset */
- { 0x22, 0x88 }, /* U offset */
- { 0x23, 0xc0 }, /* Set XTAL power level */
- { 0x24, 0x53 }, /* AEC bright ratio */
- { 0x25, 0x7a }, /* AEC black ratio */
- { 0x26, 0xb2 }, /* BLC enable */
- { 0x27, 0xa2 }, /* Full output range */
- { 0x28, 0x01 }, /* (default) */
- { 0x29, 0x00 }, /* (default) */
- { 0x2a, 0x84 }, /* (default) */
- { 0x2b, 0xa8 }, /* Set custom frame rate */
- { 0x2c, 0xa0 }, /* (reserved) */
- { 0x2d, 0x95 }, /* Enable banding filter */
- { 0x2e, 0x88 }, /* V offset */
- { 0x33, 0x22 }, /* Luminance gamma on */
- { 0x34, 0xc7 }, /* A/D bias */
- { 0x36, 0x12 }, /* (reserved) */
- { 0x37, 0x63 }, /* (reserved) */
- { 0x38, 0x8b }, /* Quick AEC/AEB */
- { 0x39, 0x00 }, /* (default) */
- { 0x3a, 0x0f }, /* (default) */
- { 0x3b, 0x3c }, /* (default) */
- { 0x3c, 0x5c }, /* AEC controls */
- { 0x3d, 0x80 }, /* Drop 1 (bad) frame when AEC change */
- { 0x3e, 0x80 }, /* (default) */
- { 0x3f, 0x02 }, /* (default) */
- { 0x40, 0x10 }, /* (reserved) */
- { 0x41, 0x10 }, /* (reserved) */
- { 0x42, 0x00 }, /* (reserved) */
- { 0x43, 0x7f }, /* (reserved) */
- { 0x44, 0x80 }, /* (reserved) */
- { 0x45, 0x1c }, /* (reserved) */
- { 0x46, 0x1c }, /* (reserved) */
- { 0x47, 0x80 }, /* (reserved) */
- { 0x48, 0x5f }, /* (reserved) */
- { 0x49, 0x00 }, /* (reserved) */
- { 0x4a, 0x00 }, /* Color balance (undocumented) */
- { 0x4b, 0x80 }, /* Color balance (undocumented) */
- { 0x4c, 0x58 }, /* (reserved) */
- { 0x4d, 0xd2 }, /* U *= .938, V *= .838 */
- { 0x4e, 0xa0 }, /* (default) */
- { 0x4f, 0x04 }, /* UV 3-point average */
- { 0x50, 0xff }, /* (reserved) */
- { 0x51, 0x58 }, /* (reserved) */
- { 0x52, 0xc0 }, /* (reserved) */
- { 0x53, 0x42 }, /* (reserved) */
- { 0x27, 0xa6 }, /* Enable manual offset adj. (reg 21 & 22) */
- { 0x12, 0x20 },
- { 0x12, 0x24 },
-
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV6x20 camera chip and relevant variables. */
-static int ov6x20_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x20 *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- switch (c->adapter->id) {
- case I2C_HW_SMBUS_OV511:
- rc = ov_write_regvals(c, regvals_init_6x20_511);
- break;
- case I2C_HW_SMBUS_OV518:
- rc = ov_write_regvals(c, regvals_init_6x20_518);
- break;
- default:
- dev_err(&c->dev, "ov6x20: Unsupported adapter\n");
- rc = -ENODEV;
- }
-
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = 1;
-
- return rc;
-}
-
-static int ov6x20_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov6x20_set_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x20 *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_write(c, REG_CNT, v >> 8);
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_write(c, REG_BRT, v >> 8);
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, REG_BLUE, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_write(c, REG_EXP, v);
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- {
- rc = ov_write_mask(c, 0x4e, v?0xe0:0xc0, 0xe0);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x0e, v?0x80:0x00, 0x80);
- s->backlight = v;
- break;
- }
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov6x20_get_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x20 *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_read(c, REG_CNT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_read(c, REG_BLUE, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- ctl->value = s->backlight;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov6x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- /******** QCIF-specific regs ********/
-
- ov_write(c, 0x14, win->quarter?0x24:0x04);
-
- /******** Palette-specific regs ********/
-
- /* OV518 needs 8 bit multiplexed in color mode, and 16 bit in B&W */
- if (c->adapter->id == I2C_HW_SMBUS_OV518) {
- if (win->format == VIDEO_PALETTE_GREY)
- ov_write_mask(c, 0x13, 0x00, 0x20);
- else
- ov_write_mask(c, 0x13, 0x20, 0x20);
- } else {
- if (win->format == VIDEO_PALETTE_GREY)
- ov_write_mask(c, 0x13, 0x20, 0x20);
- else
- ov_write_mask(c, 0x13, 0x00, 0x20);
- }
-
- /******** Clock programming ********/
-
- /* The OV6620 needs special handling. This prevents the
- * severe banding that normally occurs */
-
- /* Clock down */
- ov_write(c, 0x2a, 0x04);
-
- ov_write(c, 0x11, win->clockdiv);
-
- ov_write(c, 0x2a, 0x84);
- /* This next setting is critical. It seems to improve
- * the gain or the contrast. The "reserved" bits seem
- * to have some effect in this case. */
- ov_write(c, 0x2d, 0x85); /* FIXME: This messes up banding filter */
-
- return 0;
-}
-
-static int ov6x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov6x20_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 0;
- vwscale = 0;
- } else {
- hwscale = 1;
- vwscale = 1; /* The datasheet says 0; it's wrong */
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov6x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov6x20_set_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov6x20_get_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov6x20_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov6x20_ops = {
- .init = ov6x20_init,
- .free = ov6x20_free,
- .command = ov6x20_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov6x30.c b/drivers/media/video/ovcamchip/ov6x30.c
deleted file mode 100644
index 73b94f51a85a..000000000000
--- a/drivers/media/video/ovcamchip/ov6x30.c
+++ /dev/null
@@ -1,373 +0,0 @@
-/* OmniVision OV6630/OV6130 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue gain */
-#define REG_RED 0x02 /* red gain */
-#define REG_SAT 0x03 /* saturation [7:3] */
-#define REG_CNT 0x05 /* Y contrast [3:0] */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_SHARP 0x07 /* sharpness */
-#define REG_WB_BLUE 0x0C /* WB blue ratio [5:0] */
-#define REG_WB_RED 0x0D /* WB red ratio [5:0] */
-#define REG_EXP 0x10 /* exposure */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3A
-#define VWSBASE 0x05
-#define VWEBASE 0x06
-
-struct ov6x30 {
- int auto_brt;
- int auto_exp;
- int backlight;
- int bandfilt;
- int mirror;
-};
-
-static struct ovcamchip_regvals regvals_init_6x30[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x00, 0x1f }, /* Gain */
- { 0x01, 0x99 }, /* Blue gain */
- { 0x02, 0x7c }, /* Red gain */
- { 0x03, 0xc0 }, /* Saturation */
- { 0x05, 0x0a }, /* Contrast */
- { 0x06, 0x95 }, /* Brightness */
- { 0x07, 0x2d }, /* Sharpness */
- { 0x0c, 0x20 },
- { 0x0d, 0x20 },
- { 0x0e, 0x20 },
- { 0x0f, 0x05 },
- { 0x10, 0x9a }, /* "exposure check" */
- { 0x11, 0x00 }, /* Pixel clock = fastest */
- { 0x12, 0x24 }, /* Enable AGC and AWB */
- { 0x13, 0x21 },
- { 0x14, 0x80 },
- { 0x15, 0x01 },
- { 0x16, 0x03 },
- { 0x17, 0x38 },
- { 0x18, 0xea },
- { 0x19, 0x04 },
- { 0x1a, 0x93 },
- { 0x1b, 0x00 },
- { 0x1e, 0xc4 },
- { 0x1f, 0x04 },
- { 0x20, 0x20 },
- { 0x21, 0x10 },
- { 0x22, 0x88 },
- { 0x23, 0xc0 }, /* Crystal circuit power level */
- { 0x25, 0x9a }, /* Increase AEC black pixel ratio */
- { 0x26, 0xb2 }, /* BLC enable */
- { 0x27, 0xa2 },
- { 0x28, 0x00 },
- { 0x29, 0x00 },
- { 0x2a, 0x84 }, /* (keep) */
- { 0x2b, 0xa8 }, /* (keep) */
- { 0x2c, 0xa0 },
- { 0x2d, 0x95 }, /* Enable auto-brightness */
- { 0x2e, 0x88 },
- { 0x33, 0x26 },
- { 0x34, 0x03 },
- { 0x36, 0x8f },
- { 0x37, 0x80 },
- { 0x38, 0x83 },
- { 0x39, 0x80 },
- { 0x3a, 0x0f },
- { 0x3b, 0x3c },
- { 0x3c, 0x1a },
- { 0x3d, 0x80 },
- { 0x3e, 0x80 },
- { 0x3f, 0x0e },
- { 0x40, 0x00 }, /* White bal */
- { 0x41, 0x00 }, /* White bal */
- { 0x42, 0x80 },
- { 0x43, 0x3f }, /* White bal */
- { 0x44, 0x80 },
- { 0x45, 0x20 },
- { 0x46, 0x20 },
- { 0x47, 0x80 },
- { 0x48, 0x7f },
- { 0x49, 0x00 },
- { 0x4a, 0x00 },
- { 0x4b, 0x80 },
- { 0x4c, 0xd0 },
- { 0x4d, 0x10 }, /* U = 0.563u, V = 0.714v */
- { 0x4e, 0x40 },
- { 0x4f, 0x07 }, /* UV average mode, color killer: strongest */
- { 0x50, 0xff },
- { 0x54, 0x23 }, /* Max AGC gain: 18dB */
- { 0x55, 0xff },
- { 0x56, 0x12 },
- { 0x57, 0x81 }, /* (default) */
- { 0x58, 0x75 },
- { 0x59, 0x01 }, /* AGC dark current compensation: +1 */
- { 0x5a, 0x2c },
- { 0x5b, 0x0f }, /* AWB chrominance levels */
- { 0x5c, 0x10 },
- { 0x3d, 0x80 },
- { 0x27, 0xa6 },
- /* Toggle AWB off and on */
- { 0x12, 0x20 },
- { 0x12, 0x24 },
-
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV6x30 camera chip and relevant variables. */
-static int ov6x30_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x30 *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- rc = ov_write_regvals(c, regvals_init_6x30);
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = 1;
-
- return rc;
-}
-
-static int ov6x30_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov6x30_set_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x30 *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_write_mask(c, REG_CNT, v >> 12, 0x0f);
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_write(c, REG_BRT, v >> 8);
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, REG_BLUE, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_write(c, REG_EXP, v);
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write(c, 0x2b, sixty?0xa8:0x28);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2a, sixty?0x84:0xa4);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x28, v?0x00:0x10, 0x10);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- {
- rc = ov_write_mask(c, 0x4e, v?0x80:0x60, 0xe0);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
- s->backlight = v;
- break;
- }
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov6x30_get_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov6x30 *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_read(c, REG_CNT, &val);
- ctl->value = (val & 0x0f) << 12;
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_read(c, REG_BLUE, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- ctl->value = s->backlight;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov6x30_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- /******** QCIF-specific regs ********/
-
- ov_write_mask(c, 0x14, win->quarter?0x20:0x00, 0x20);
-
- /******** Palette-specific regs ********/
-
- if (win->format == VIDEO_PALETTE_GREY) {
- if (c->adapter->id == I2C_HW_SMBUS_OV518) {
- /* Do nothing - we're already in 8-bit mode */
- } else {
- ov_write_mask(c, 0x13, 0x20, 0x20);
- }
- } else {
- /* The OV518 needs special treatment. Although both the OV518
- * and the OV6630 support a 16-bit video bus, only the 8 bit Y
- * bus is actually used. The UV bus is tied to ground.
- * Therefore, the OV6630 needs to be in 8-bit multiplexed
- * output mode */
-
- if (c->adapter->id == I2C_HW_SMBUS_OV518) {
- /* Do nothing - we want to stay in 8-bit mode */
- /* Warning: Messing with reg 0x13 breaks OV518 color */
- } else {
- ov_write_mask(c, 0x13, 0x00, 0x20);
- }
- }
-
- /******** Clock programming ********/
-
- ov_write(c, 0x11, win->clockdiv);
-
- return 0;
-}
-
-static int ov6x30_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov6x30_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 0;
- vwscale = 0;
- } else {
- hwscale = 1;
- vwscale = 1; /* The datasheet says 0; it's wrong */
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov6x30_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov6x30_set_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov6x30_get_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov6x30_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov6x30_ops = {
- .init = ov6x30_init,
- .free = ov6x30_free,
- .command = ov6x30_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov76be.c b/drivers/media/video/ovcamchip/ov76be.c
deleted file mode 100644
index 11f6be924d8b..000000000000
--- a/drivers/media/video/ovcamchip/ov76be.c
+++ /dev/null
@@ -1,302 +0,0 @@
-/* OmniVision OV76BE Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* OV7610 registers: Since the OV76BE is undocumented, we'll settle for these
- * for now. */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue channel balance */
-#define REG_RED 0x02 /* red channel balance */
-#define REG_SAT 0x03 /* saturation */
-#define REG_CNT 0x05 /* Y contrast */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_BLUE_BIAS 0x0C /* blue channel bias [5:0] */
-#define REG_RED_BIAS 0x0D /* red channel bias [5:0] */
-#define REG_GAMMA_COEFF 0x0E /* gamma settings */
-#define REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
-#define REG_EXP 0x10 /* manual exposure setting */
-#define REG_CLOCK 0x11 /* polarity/clock prescaler */
-#define REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
-#define REG_HWIN_START 0x17 /* horizontal window start */
-#define REG_HWIN_END 0x18 /* horizontal window end */
-#define REG_VWIN_START 0x19 /* vertical window start */
-#define REG_VWIN_END 0x1A /* vertical window end */
-#define REG_PIXEL_SHIFT 0x1B /* pixel shift */
-#define REG_YOFFSET 0x21 /* Y channel offset */
-#define REG_UOFFSET 0x22 /* U channel offset */
-#define REG_ECW 0x24 /* exposure white level for AEC */
-#define REG_ECB 0x25 /* exposure black level for AEC */
-#define REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
-#define REG_FRAMERATE_L 0x2B /* frame rate LSB */
-#define REG_ALC 0x2C /* Auto Level Control settings */
-#define REG_VOFFSET 0x2E /* V channel offset adjustment */
-#define REG_ARRAY_BIAS 0x2F /* array bias -- don't change */
-#define REG_YGAMMA 0x33 /* misc gamma settings [7:6] */
-#define REG_BIAS_ADJUST 0x34 /* misc bias settings */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3a
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov76be {
- int auto_brt;
- int auto_exp;
- int bandfilt;
- int mirror;
-};
-
-/* NOTE: These are the same as the 7x10 settings, but should eventually be
- * optimized for the OV76BE */
-static struct ovcamchip_regvals regvals_init_76be[] = {
- { 0x10, 0xff },
- { 0x16, 0x03 },
- { 0x28, 0x24 },
- { 0x2b, 0xac },
- { 0x12, 0x00 },
- { 0x38, 0x81 },
- { 0x28, 0x24 }, /* 0c */
- { 0x0f, 0x85 }, /* lg's setting */
- { 0x15, 0x01 },
- { 0x20, 0x1c },
- { 0x23, 0x2a },
- { 0x24, 0x10 },
- { 0x25, 0x8a },
- { 0x26, 0xa2 },
- { 0x27, 0xc2 },
- { 0x2a, 0x04 },
- { 0x2c, 0xfe },
- { 0x2d, 0x93 },
- { 0x30, 0x71 },
- { 0x31, 0x60 },
- { 0x32, 0x26 },
- { 0x33, 0x20 },
- { 0x34, 0x48 },
- { 0x12, 0x24 },
- { 0x11, 0x01 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV76be camera chip and relevant variables. */
-static int ov76be_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov76be *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- rc = ov_write_regvals(c, regvals_init_76be);
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = 1;
-
- return rc;
-}
-
-static int ov76be_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov76be_set_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov76be *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_write(c, REG_BRT, v >> 8);
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_write(c, REG_EXP, v);
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2b, sixty?0x00:0xac);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x76, 0x01, 0x01);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov76be_get_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov76be *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov76be_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int qvga = win->quarter;
-
- /******** QVGA-specific regs ********/
-
- ov_write(c, 0x14, qvga?0xa4:0x84);
-
- /******** Palette-specific regs ********/
-
- if (win->format == VIDEO_PALETTE_GREY) {
- ov_write_mask(c, 0x0e, 0x40, 0x40);
- ov_write_mask(c, 0x13, 0x20, 0x20);
- } else {
- ov_write_mask(c, 0x0e, 0x00, 0x40);
- ov_write_mask(c, 0x13, 0x00, 0x20);
- }
-
- /******** Clock programming ********/
-
- ov_write(c, 0x11, win->clockdiv);
-
- /******** Resolution-specific ********/
-
- if (win->width == 640 && win->height == 480)
- ov_write(c, 0x35, 0x9e);
- else
- ov_write(c, 0x35, 0x1e);
-
- return 0;
-}
-
-static int ov76be_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov76be_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 1;
- vwscale = 0;
- } else {
- hwscale = 2;
- vwscale = 1;
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov76be_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov76be_set_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov76be_get_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov76be_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov76be_ops = {
- .init = ov76be_init,
- .free = ov76be_free,
- .command = ov76be_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov7x10.c b/drivers/media/video/ovcamchip/ov7x10.c
deleted file mode 100644
index 5206e7913924..000000000000
--- a/drivers/media/video/ovcamchip/ov7x10.c
+++ /dev/null
@@ -1,334 +0,0 @@
-/* OmniVision OV7610/OV7110 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * Color fixes by by Orion Sky Lawlor <olawlor@acm.org> (2/26/2000)
- *
- * 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue channel balance */
-#define REG_RED 0x02 /* red channel balance */
-#define REG_SAT 0x03 /* saturation */
-#define REG_CNT 0x05 /* Y contrast */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_BLUE_BIAS 0x0C /* blue channel bias [5:0] */
-#define REG_RED_BIAS 0x0D /* red channel bias [5:0] */
-#define REG_GAMMA_COEFF 0x0E /* gamma settings */
-#define REG_WB_RANGE 0x0F /* AEC/ALC/S-AWB settings */
-#define REG_EXP 0x10 /* manual exposure setting */
-#define REG_CLOCK 0x11 /* polarity/clock prescaler */
-#define REG_FIELD_DIVIDE 0x16 /* field interval/mode settings */
-#define REG_HWIN_START 0x17 /* horizontal window start */
-#define REG_HWIN_END 0x18 /* horizontal window end */
-#define REG_VWIN_START 0x19 /* vertical window start */
-#define REG_VWIN_END 0x1A /* vertical window end */
-#define REG_PIXEL_SHIFT 0x1B /* pixel shift */
-#define REG_YOFFSET 0x21 /* Y channel offset */
-#define REG_UOFFSET 0x22 /* U channel offset */
-#define REG_ECW 0x24 /* exposure white level for AEC */
-#define REG_ECB 0x25 /* exposure black level for AEC */
-#define REG_FRAMERATE_H 0x2A /* frame rate MSB + misc */
-#define REG_FRAMERATE_L 0x2B /* frame rate LSB */
-#define REG_ALC 0x2C /* Auto Level Control settings */
-#define REG_VOFFSET 0x2E /* V channel offset adjustment */
-#define REG_ARRAY_BIAS 0x2F /* array bias -- don't change */
-#define REG_YGAMMA 0x33 /* misc gamma settings [7:6] */
-#define REG_BIAS_ADJUST 0x34 /* misc bias settings */
-
-/* Window parameters */
-#define HWSBASE 0x38
-#define HWEBASE 0x3a
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov7x10 {
- int auto_brt;
- int auto_exp;
- int bandfilt;
- int mirror;
-};
-
-/* Lawrence Glaister <lg@jfm.bc.ca> reports:
- *
- * Register 0x0f in the 7610 has the following effects:
- *
- * 0x85 (AEC method 1): Best overall, good contrast range
- * 0x45 (AEC method 2): Very overexposed
- * 0xa5 (spec sheet default): Ok, but the black level is
- * shifted resulting in loss of contrast
- * 0x05 (old driver setting): very overexposed, too much
- * contrast
- */
-static struct ovcamchip_regvals regvals_init_7x10[] = {
- { 0x10, 0xff },
- { 0x16, 0x03 },
- { 0x28, 0x24 },
- { 0x2b, 0xac },
- { 0x12, 0x00 },
- { 0x38, 0x81 },
- { 0x28, 0x24 }, /* 0c */
- { 0x0f, 0x85 }, /* lg's setting */
- { 0x15, 0x01 },
- { 0x20, 0x1c },
- { 0x23, 0x2a },
- { 0x24, 0x10 },
- { 0x25, 0x8a },
- { 0x26, 0xa2 },
- { 0x27, 0xc2 },
- { 0x2a, 0x04 },
- { 0x2c, 0xfe },
- { 0x2d, 0x93 },
- { 0x30, 0x71 },
- { 0x31, 0x60 },
- { 0x32, 0x26 },
- { 0x33, 0x20 },
- { 0x34, 0x48 },
- { 0x12, 0x24 },
- { 0x11, 0x01 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* This initializes the OV7x10 camera chip and relevant variables. */
-static int ov7x10_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x10 *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- rc = ov_write_regvals(c, regvals_init_7x10);
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = 1;
-
- return rc;
-}
-
-static int ov7x10_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov7x10_set_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x10 *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_write(c, REG_CNT, v >> 8);
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_write(c, REG_BRT, v >> 8);
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_write(c, REG_RED, 0xFF - (v >> 8));
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, REG_BLUE, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_write(c, REG_EXP, v);
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2b, sixty?0x00:0xac);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x13, 0x10, 0x10);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x13, 0x00, 0x10);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x29, v?0x00:0x80, 0x80);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov7x10_get_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x10 *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_read(c, REG_CNT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_HUE:
- rc = ov_read(c, REG_BLUE, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov7x10_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int qvga = win->quarter;
-
- /******** QVGA-specific regs ********/
-
- ov_write(c, 0x14, qvga?0x24:0x04);
-
- /******** Palette-specific regs ********/
-
- if (win->format == VIDEO_PALETTE_GREY) {
- ov_write_mask(c, 0x0e, 0x40, 0x40);
- ov_write_mask(c, 0x13, 0x20, 0x20);
- } else {
- ov_write_mask(c, 0x0e, 0x00, 0x40);
- ov_write_mask(c, 0x13, 0x00, 0x20);
- }
-
- /******** Clock programming ********/
-
- ov_write(c, 0x11, win->clockdiv);
-
- /******** Resolution-specific ********/
-
- if (win->width == 640 && win->height == 480)
- ov_write(c, 0x35, 0x9e);
- else
- ov_write(c, 0x35, 0x1e);
-
- return 0;
-}
-
-static int ov7x10_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov7x10_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 1;
- vwscale = 0;
- } else {
- hwscale = 2;
- vwscale = 1;
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov7x10_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov7x10_set_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov7x10_get_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov7x10_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov7x10_ops = {
- .init = ov7x10_init,
- .free = ov7x10_free,
- .command = ov7x10_command,
-};
diff --git a/drivers/media/video/ovcamchip/ov7x20.c b/drivers/media/video/ovcamchip/ov7x20.c
deleted file mode 100644
index 8e26ae338f31..000000000000
--- a/drivers/media/video/ovcamchip/ov7x20.c
+++ /dev/null
@@ -1,454 +0,0 @@
-/* OmniVision OV7620/OV7120 Camera Chip Support Code
- *
- * Copyright (c) 1999-2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * OV7620 fixes by Charl P. Botha <cpbotha@ieee.org>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/slab.h>
-#include "ovcamchip_priv.h"
-
-/* Registers */
-#define REG_GAIN 0x00 /* gain [5:0] */
-#define REG_BLUE 0x01 /* blue gain */
-#define REG_RED 0x02 /* red gain */
-#define REG_SAT 0x03 /* saturation */
-#define REG_BRT 0x06 /* Y brightness */
-#define REG_SHARP 0x07 /* analog sharpness */
-#define REG_BLUE_BIAS 0x0C /* WB blue ratio [5:0] */
-#define REG_RED_BIAS 0x0D /* WB red ratio [5:0] */
-#define REG_EXP 0x10 /* exposure */
-
-/* Default control settings. Values are in terms of V4L2 controls. */
-#define OV7120_DFL_BRIGHT 0x60
-#define OV7620_DFL_BRIGHT 0x60
-#define OV7120_DFL_SAT 0xb0
-#define OV7620_DFL_SAT 0xc0
-#define DFL_AUTO_EXP 1
-#define DFL_AUTO_GAIN 1
-#define OV7120_DFL_GAIN 0x00
-#define OV7620_DFL_GAIN 0x00
-/* NOTE: Since autoexposure is the default, these aren't programmed into the
- * OV7x20 chip. They are just here because V4L2 expects a default */
-#define OV7120_DFL_EXP 0x7f
-#define OV7620_DFL_EXP 0x7f
-
-/* Window parameters */
-#define HWSBASE 0x2F /* From 7620.SET (spec is wrong) */
-#define HWEBASE 0x2F
-#define VWSBASE 0x05
-#define VWEBASE 0x05
-
-struct ov7x20 {
- int auto_brt;
- int auto_exp;
- int auto_gain;
- int backlight;
- int bandfilt;
- int mirror;
-};
-
-/* Contrast look-up table */
-static unsigned char ctab[] = {
- 0x01, 0x05, 0x09, 0x11, 0x15, 0x35, 0x37, 0x57,
- 0x5b, 0xa5, 0xa7, 0xc7, 0xc9, 0xcf, 0xef, 0xff
-};
-
-/* Settings for (Black & White) OV7120 camera chip */
-static struct ovcamchip_regvals regvals_init_7120[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x13, 0x00 }, /* Autoadjust off */
- { 0x12, 0x20 }, /* Disable AWB */
- { 0x13, DFL_AUTO_GAIN?0x01:0x00 }, /* Autoadjust on (if desired) */
- { 0x00, OV7120_DFL_GAIN },
- { 0x01, 0x80 },
- { 0x02, 0x80 },
- { 0x03, OV7120_DFL_SAT },
- { 0x06, OV7120_DFL_BRIGHT },
- { 0x07, 0x00 },
- { 0x0c, 0x20 },
- { 0x0d, 0x20 },
- { 0x11, 0x01 },
- { 0x14, 0x84 },
- { 0x15, 0x01 },
- { 0x16, 0x03 },
- { 0x17, 0x2f },
- { 0x18, 0xcf },
- { 0x19, 0x06 },
- { 0x1a, 0xf5 },
- { 0x1b, 0x00 },
- { 0x20, 0x08 },
- { 0x21, 0x80 },
- { 0x22, 0x80 },
- { 0x23, 0x00 },
- { 0x26, 0xa0 },
- { 0x27, 0xfa },
- { 0x28, 0x20 }, /* DON'T set bit 6. It is for the OV7620 only */
- { 0x29, DFL_AUTO_EXP?0x00:0x80 },
- { 0x2a, 0x10 },
- { 0x2b, 0x00 },
- { 0x2c, 0x88 },
- { 0x2d, 0x95 },
- { 0x2e, 0x80 },
- { 0x2f, 0x44 },
- { 0x60, 0x20 },
- { 0x61, 0x02 },
- { 0x62, 0x5f },
- { 0x63, 0xd5 },
- { 0x64, 0x57 },
- { 0x65, 0x83 }, /* OV says "don't change this value" */
- { 0x66, 0x55 },
- { 0x67, 0x92 },
- { 0x68, 0xcf },
- { 0x69, 0x76 },
- { 0x6a, 0x22 },
- { 0x6b, 0xe2 },
- { 0x6c, 0x40 },
- { 0x6d, 0x48 },
- { 0x6e, 0x80 },
- { 0x6f, 0x0d },
- { 0x70, 0x89 },
- { 0x71, 0x00 },
- { 0x72, 0x14 },
- { 0x73, 0x54 },
- { 0x74, 0xa0 },
- { 0x75, 0x8e },
- { 0x76, 0x00 },
- { 0x77, 0xff },
- { 0x78, 0x80 },
- { 0x79, 0x80 },
- { 0x7a, 0x80 },
- { 0x7b, 0xe6 },
- { 0x7c, 0x00 },
- { 0x24, 0x3a },
- { 0x25, 0x60 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Settings for (color) OV7620 camera chip */
-static struct ovcamchip_regvals regvals_init_7620[] = {
- { 0x12, 0x80 }, /* reset */
- { 0x00, OV7620_DFL_GAIN },
- { 0x01, 0x80 },
- { 0x02, 0x80 },
- { 0x03, OV7620_DFL_SAT },
- { 0x06, OV7620_DFL_BRIGHT },
- { 0x07, 0x00 },
- { 0x0c, 0x24 },
- { 0x0c, 0x24 },
- { 0x0d, 0x24 },
- { 0x11, 0x01 },
- { 0x12, 0x24 },
- { 0x13, DFL_AUTO_GAIN?0x01:0x00 },
- { 0x14, 0x84 },
- { 0x15, 0x01 },
- { 0x16, 0x03 },
- { 0x17, 0x2f },
- { 0x18, 0xcf },
- { 0x19, 0x06 },
- { 0x1a, 0xf5 },
- { 0x1b, 0x00 },
- { 0x20, 0x18 },
- { 0x21, 0x80 },
- { 0x22, 0x80 },
- { 0x23, 0x00 },
- { 0x26, 0xa2 },
- { 0x27, 0xea },
- { 0x28, 0x20 },
- { 0x29, DFL_AUTO_EXP?0x00:0x80 },
- { 0x2a, 0x10 },
- { 0x2b, 0x00 },
- { 0x2c, 0x88 },
- { 0x2d, 0x91 },
- { 0x2e, 0x80 },
- { 0x2f, 0x44 },
- { 0x60, 0x27 },
- { 0x61, 0x02 },
- { 0x62, 0x5f },
- { 0x63, 0xd5 },
- { 0x64, 0x57 },
- { 0x65, 0x83 },
- { 0x66, 0x55 },
- { 0x67, 0x92 },
- { 0x68, 0xcf },
- { 0x69, 0x76 },
- { 0x6a, 0x22 },
- { 0x6b, 0x00 },
- { 0x6c, 0x02 },
- { 0x6d, 0x44 },
- { 0x6e, 0x80 },
- { 0x6f, 0x1d },
- { 0x70, 0x8b },
- { 0x71, 0x00 },
- { 0x72, 0x14 },
- { 0x73, 0x54 },
- { 0x74, 0x00 },
- { 0x75, 0x8e },
- { 0x76, 0x00 },
- { 0x77, 0xff },
- { 0x78, 0x80 },
- { 0x79, 0x80 },
- { 0x7a, 0x80 },
- { 0x7b, 0xe2 },
- { 0x7c, 0x00 },
- { 0xff, 0xff }, /* END MARKER */
-};
-
-/* Returns index into the specified look-up table, with 'n' elements, for which
- * the value is greater than or equal to "val". If a match isn't found, (n-1)
- * is returned. The entries in the table must be in ascending order. */
-static inline int ov7x20_lut_find(unsigned char lut[], int n, unsigned char val)
-{
- int i = 0;
-
- while (lut[i] < val && i < n)
- i++;
-
- return i;
-}
-
-/* This initializes the OV7x20 camera chip and relevant variables. */
-static int ov7x20_init(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x20 *s;
- int rc;
-
- DDEBUG(4, &c->dev, "entered");
-
- if (ov->mono)
- rc = ov_write_regvals(c, regvals_init_7120);
- else
- rc = ov_write_regvals(c, regvals_init_7620);
-
- if (rc < 0)
- return rc;
-
- ov->spriv = s = kzalloc(sizeof *s, GFP_KERNEL);
- if (!s)
- return -ENOMEM;
-
- s->auto_brt = 1;
- s->auto_exp = DFL_AUTO_EXP;
- s->auto_gain = DFL_AUTO_GAIN;
-
- return 0;
-}
-
-static int ov7x20_free(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
-
- kfree(ov->spriv);
- return 0;
-}
-
-static int ov7x20_set_v4l1_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x20 *s = ov->spriv;
- int rc;
- int v = ctl->value;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- {
- /* Use Y gamma control instead. Bit 0 enables it. */
- rc = ov_write(c, 0x64, ctab[v >> 12]);
- break;
- }
- case OVCAMCHIP_CID_BRIGHT:
- /* 7620 doesn't like manual changes when in auto mode */
- if (!s->auto_brt)
- rc = ov_write(c, REG_BRT, v >> 8);
- else
- rc = 0;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_write(c, REG_SAT, v >> 8);
- break;
- case OVCAMCHIP_CID_EXP:
- if (!s->auto_exp)
- rc = ov_write(c, REG_EXP, v);
- else
- rc = -EBUSY;
- break;
- case OVCAMCHIP_CID_FREQ:
- {
- int sixty = (v == 60);
-
- rc = ov_write_mask(c, 0x2a, sixty?0x00:0x80, 0x80);
- if (rc < 0)
- goto out;
-
- rc = ov_write(c, 0x2b, sixty?0x00:0xac);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x76, 0x01, 0x01);
- break;
- }
- case OVCAMCHIP_CID_BANDFILT:
- rc = ov_write_mask(c, 0x2d, v?0x04:0x00, 0x04);
- s->bandfilt = v;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- rc = ov_write_mask(c, 0x2d, v?0x10:0x00, 0x10);
- s->auto_brt = v;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- rc = ov_write_mask(c, 0x13, v?0x01:0x00, 0x01);
- s->auto_exp = v;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- {
- rc = ov_write_mask(c, 0x68, v?0xe0:0xc0, 0xe0);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x29, v?0x08:0x00, 0x08);
- if (rc < 0)
- goto out;
-
- rc = ov_write_mask(c, 0x28, v?0x02:0x00, 0x02);
- s->backlight = v;
- break;
- }
- case OVCAMCHIP_CID_MIRROR:
- rc = ov_write_mask(c, 0x12, v?0x40:0x00, 0x40);
- s->mirror = v;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
-out:
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, v, rc);
- return rc;
-}
-
-static int ov7x20_get_v4l1_control(struct i2c_client *c,
- struct ovcamchip_control *ctl)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- struct ov7x20 *s = ov->spriv;
- int rc = 0;
- unsigned char val = 0;
-
- switch (ctl->id) {
- case OVCAMCHIP_CID_CONT:
- rc = ov_read(c, 0x64, &val);
- ctl->value = ov7x20_lut_find(ctab, 16, val) << 12;
- break;
- case OVCAMCHIP_CID_BRIGHT:
- rc = ov_read(c, REG_BRT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_SAT:
- rc = ov_read(c, REG_SAT, &val);
- ctl->value = val << 8;
- break;
- case OVCAMCHIP_CID_EXP:
- rc = ov_read(c, REG_EXP, &val);
- ctl->value = val;
- break;
- case OVCAMCHIP_CID_BANDFILT:
- ctl->value = s->bandfilt;
- break;
- case OVCAMCHIP_CID_AUTOBRIGHT:
- ctl->value = s->auto_brt;
- break;
- case OVCAMCHIP_CID_AUTOEXP:
- ctl->value = s->auto_exp;
- break;
- case OVCAMCHIP_CID_BACKLIGHT:
- ctl->value = s->backlight;
- break;
- case OVCAMCHIP_CID_MIRROR:
- ctl->value = s->mirror;
- break;
- default:
- DDEBUG(2, &c->dev, "control not supported: %d", ctl->id);
- return -EPERM;
- }
-
- DDEBUG(3, &c->dev, "id=%d, arg=%d, rc=%d", ctl->id, ctl->value, rc);
- return rc;
-}
-
-static int ov7x20_mode_init(struct i2c_client *c, struct ovcamchip_window *win)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int qvga = win->quarter;
-
- /******** QVGA-specific regs ********/
- ov_write_mask(c, 0x14, qvga?0x20:0x00, 0x20);
- ov_write_mask(c, 0x28, qvga?0x00:0x20, 0x20);
- ov_write(c, 0x24, qvga?0x20:0x3a);
- ov_write(c, 0x25, qvga?0x30:0x60);
- ov_write_mask(c, 0x2d, qvga?0x40:0x00, 0x40);
- if (!ov->mono)
- ov_write_mask(c, 0x67, qvga?0xf0:0x90, 0xf0);
- ov_write_mask(c, 0x74, qvga?0x20:0x00, 0x20);
-
- /******** Clock programming ********/
-
- ov_write(c, 0x11, win->clockdiv);
-
- return 0;
-}
-
-static int ov7x20_set_window(struct i2c_client *c, struct ovcamchip_window *win)
-{
- int ret, hwscale, vwscale;
-
- ret = ov7x20_mode_init(c, win);
- if (ret < 0)
- return ret;
-
- if (win->quarter) {
- hwscale = 1;
- vwscale = 0;
- } else {
- hwscale = 2;
- vwscale = 1;
- }
-
- ov_write(c, 0x17, HWSBASE + (win->x >> hwscale));
- ov_write(c, 0x18, HWEBASE + ((win->x + win->width) >> hwscale));
- ov_write(c, 0x19, VWSBASE + (win->y >> vwscale));
- ov_write(c, 0x1a, VWEBASE + ((win->y + win->height) >> vwscale));
-
- return 0;
-}
-
-static int ov7x20_command(struct i2c_client *c, unsigned int cmd, void *arg)
-{
- switch (cmd) {
- case OVCAMCHIP_CMD_S_CTRL:
- return ov7x20_set_v4l1_control(c, arg);
- case OVCAMCHIP_CMD_G_CTRL:
- return ov7x20_get_v4l1_control(c, arg);
- case OVCAMCHIP_CMD_S_MODE:
- return ov7x20_set_window(c, arg);
- default:
- DDEBUG(2, &c->dev, "command not supported: %d", cmd);
- return -ENOIOCTLCMD;
- }
-}
-
-struct ovcamchip_ops ov7x20_ops = {
- .init = ov7x20_init,
- .free = ov7x20_free,
- .command = ov7x20_command,
-};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_core.c b/drivers/media/video/ovcamchip/ovcamchip_core.c
deleted file mode 100644
index d573d8428998..000000000000
--- a/drivers/media/video/ovcamchip/ovcamchip_core.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/* Shared Code for OmniVision Camera Chip Drivers
- *
- * Copyright (c) 2004 Mark McClelland <mark@alpha.dyndns.org>
- * http://alpha.dyndns.org/ov511/
- *
- * 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. NO WARRANTY OF ANY KIND is expressed or implied.
- */
-
-#define DEBUG
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/delay.h>
-#include <linux/i2c.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
-#include "ovcamchip_priv.h"
-
-#define DRIVER_VERSION "v2.27 for Linux 2.6"
-#define DRIVER_AUTHOR "Mark McClelland <mark@alpha.dyndns.org>"
-#define DRIVER_DESC "OV camera chip I2C driver"
-
-#define PINFO(fmt, args...) printk(KERN_INFO "ovcamchip: " fmt "\n" , ## args);
-#define PERROR(fmt, args...) printk(KERN_ERR "ovcamchip: " fmt "\n" , ## args);
-
-#ifdef DEBUG
-int ovcamchip_debug = 0;
-static int debug;
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug,
- "Debug level: 0=none, 1=inits, 2=warning, 3=config, 4=functions, 5=all");
-#endif
-
-/* By default, let bridge driver tell us if chip is monochrome. mono=0
- * will ignore that and always treat chips as color. mono=1 will force
- * monochrome mode for all chips. */
-static int mono = -1;
-module_param(mono, int, 0);
-MODULE_PARM_DESC(mono,
- "1=chips are monochrome (OVx1xx), 0=force color, -1=autodetect (default)");
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-
-
-/* Registers common to all chips, that are needed for detection */
-#define GENERIC_REG_ID_HIGH 0x1C /* manufacturer ID MSB */
-#define GENERIC_REG_ID_LOW 0x1D /* manufacturer ID LSB */
-#define GENERIC_REG_COM_I 0x29 /* misc ID bits */
-
-static char *chip_names[NUM_CC_TYPES] = {
- [CC_UNKNOWN] = "Unknown chip",
- [CC_OV76BE] = "OV76BE",
- [CC_OV7610] = "OV7610",
- [CC_OV7620] = "OV7620",
- [CC_OV7620AE] = "OV7620AE",
- [CC_OV6620] = "OV6620",
- [CC_OV6630] = "OV6630",
- [CC_OV6630AE] = "OV6630AE",
- [CC_OV6630AF] = "OV6630AF",
-};
-
-/* ----------------------------------------------------------------------- */
-
-int ov_write_regvals(struct i2c_client *c, struct ovcamchip_regvals *rvals)
-{
- int rc;
-
- while (rvals->reg != 0xff) {
- rc = ov_write(c, rvals->reg, rvals->val);
- if (rc < 0)
- return rc;
- rvals++;
- }
-
- return 0;
-}
-
-/* Writes bits at positions specified by mask to an I2C reg. Bits that are in
- * the same position as 1's in "mask" are cleared and set to "value". Bits
- * that are in the same position as 0's in "mask" are preserved, regardless
- * of their respective state in "value".
- */
-int ov_write_mask(struct i2c_client *c,
- unsigned char reg,
- unsigned char value,
- unsigned char mask)
-{
- int rc;
- unsigned char oldval, newval;
-
- if (mask == 0xff) {
- newval = value;
- } else {
- rc = ov_read(c, reg, &oldval);
- if (rc < 0)
- return rc;
-
- oldval &= (~mask); /* Clear the masked bits */
- value &= mask; /* Enforce mask on value */
- newval = oldval | value; /* Set the desired bits */
- }
-
- return ov_write(c, reg, newval);
-}
-
-/* ----------------------------------------------------------------------- */
-
-/* Reset the chip and ensure that I2C is synchronized. Returns <0 if failure.
- */
-static int init_camchip(struct i2c_client *c)
-{
- int i, success;
- unsigned char high, low;
-
- /* Reset the chip */
- ov_write(c, 0x12, 0x80);
-
- /* Wait for it to initialize */
- msleep(150);
-
- for (i = 0, success = 0; i < I2C_DETECT_RETRIES && !success; i++) {
- if (ov_read(c, GENERIC_REG_ID_HIGH, &high) >= 0) {
- if (ov_read(c, GENERIC_REG_ID_LOW, &low) >= 0) {
- if (high == 0x7F && low == 0xA2) {
- success = 1;
- continue;
- }
- }
- }
-
- /* Reset the chip */
- ov_write(c, 0x12, 0x80);
-
- /* Wait for it to initialize */
- msleep(150);
-
- /* Dummy read to sync I2C */
- ov_read(c, 0x00, &low);
- }
-
- if (!success)
- return -EIO;
-
- PDEBUG(1, "I2C synced in %d attempt(s)", i);
-
- return 0;
-}
-
-/* This detects the OV7610, OV7620, or OV76BE chip. */
-static int ov7xx0_detect(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int rc;
- unsigned char val;
-
- PDEBUG(4, "");
-
- /* Detect chip (sub)type */
- rc = ov_read(c, GENERIC_REG_COM_I, &val);
- if (rc < 0) {
- PERROR("Error detecting ov7xx0 type");
- return rc;
- }
-
- if ((val & 3) == 3) {
- PINFO("Camera chip is an OV7610");
- ov->subtype = CC_OV7610;
- } else if ((val & 3) == 1) {
- rc = ov_read(c, 0x15, &val);
- if (rc < 0) {
- PERROR("Error detecting ov7xx0 type");
- return rc;
- }
-
- if (val & 1) {
- PINFO("Camera chip is an OV7620AE");
- /* OV7620 is a close enough match for now. There are
- * some definite differences though, so this should be
- * fixed */
- ov->subtype = CC_OV7620;
- } else {
- PINFO("Camera chip is an OV76BE");
- ov->subtype = CC_OV76BE;
- }
- } else if ((val & 3) == 0) {
- PINFO("Camera chip is an OV7620");
- ov->subtype = CC_OV7620;
- } else {
- PERROR("Unknown camera chip version: %d", val & 3);
- return -ENOSYS;
- }
-
- if (ov->subtype == CC_OV76BE)
- ov->sops = &ov76be_ops;
- else if (ov->subtype == CC_OV7620)
- ov->sops = &ov7x20_ops;
- else
- ov->sops = &ov7x10_ops;
-
- return 0;
-}
-
-/* This detects the OV6620, OV6630, OV6630AE, or OV6630AF chip. */
-static int ov6xx0_detect(struct i2c_client *c)
-{
- struct ovcamchip *ov = i2c_get_clientdata(c);
- int rc;
- unsigned char val;
-
- PDEBUG(4, "");
-
- /* Detect chip (sub)type */
- rc = ov_read(c, GENERIC_REG_COM_I, &val);
- if (rc < 0) {
- PERROR("Error detecting ov6xx0 type");
- return -1;
- }
-
- if ((val & 3) == 0) {
- ov->subtype = CC_OV6630;
- PINFO("Camera chip is an OV6630");
- } else if ((val & 3) == 1) {
- ov->subtype = CC_OV6620;
- PINFO("Camera chip is an OV6620");
- } else if ((val & 3) == 2) {
- ov->subtype = CC_OV6630;
- PINFO("Camera chip is an OV6630AE");
- } else if ((val & 3) == 3) {
- ov->subtype = CC_OV6630;
- PINFO("Camera chip is an OV6630AF");
- }
-
- if (ov->subtype == CC_OV6620)
- ov->sops = &ov6x20_ops;
- else
- ov->sops = &ov6x30_ops;
-
- return 0;
-}
-
-static int ovcamchip_detect(struct i2c_client *c)
-{
- /* Ideally we would just try a single register write and see if it NAKs.
- * That isn't possible since the OV518 can't report I2C transaction
- * failures. So, we have to try to initialize the chip (i.e. reset it
- * and check the ID registers) to detect its presence. */
-
- /* Test for 7xx0 */
- PDEBUG(3, "Testing for 0V7xx0");
- if (init_camchip(c) < 0)
- return -ENODEV;
- /* 7-bit addresses with bit 0 set are for the OV7xx0 */
- if (c->addr & 1) {
- if (ov7xx0_detect(c) < 0) {
- PERROR("Failed to init OV7xx0");
- return -EIO;
- }
- return 0;
- }
- /* Test for 6xx0 */
- PDEBUG(3, "Testing for 0V6xx0");
- if (ov6xx0_detect(c) < 0) {
- PERROR("Failed to init OV6xx0");
- return -EIO;
- }
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static long ovcamchip_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
-{
- struct ovcamchip *ov = to_ovcamchip(sd);
- struct i2c_client *c = v4l2_get_subdevdata(sd);
-
- if (!ov->initialized &&
- cmd != OVCAMCHIP_CMD_Q_SUBTYPE &&
- cmd != OVCAMCHIP_CMD_INITIALIZE) {
- v4l2_err(sd, "Camera chip not initialized yet!\n");
- return -EPERM;
- }
-
- switch (cmd) {
- case OVCAMCHIP_CMD_Q_SUBTYPE:
- {
- *(int *)arg = ov->subtype;
- return 0;
- }
- case OVCAMCHIP_CMD_INITIALIZE:
- {
- int rc;
-
- if (mono == -1)
- ov->mono = *(int *)arg;
- else
- ov->mono = mono;
-
- if (ov->mono) {
- if (ov->subtype != CC_OV7620)
- v4l2_warn(sd, "Monochrome not "
- "implemented for this chip\n");
- else
- v4l2_info(sd, "Initializing chip as "
- "monochrome\n");
- }
-
- rc = ov->sops->init(c);
- if (rc < 0)
- return rc;
-
- ov->initialized = 1;
- return 0;
- }
- default:
- return ov->sops->command(c, cmd, arg);
- }
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops ovcamchip_core_ops = {
- .ioctl = ovcamchip_ioctl,
-};
-
-static const struct v4l2_subdev_ops ovcamchip_ops = {
- .core = &ovcamchip_core_ops,
-};
-
-static int ovcamchip_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- struct ovcamchip *ov;
- struct v4l2_subdev *sd;
- int rc = 0;
-
- ov = kzalloc(sizeof *ov, GFP_KERNEL);
- if (!ov) {
- rc = -ENOMEM;
- goto no_ov;
- }
- sd = &ov->sd;
- v4l2_i2c_subdev_init(sd, client, &ovcamchip_ops);
-
- rc = ovcamchip_detect(client);
- if (rc < 0)
- goto error;
-
- v4l_info(client, "%s found @ 0x%02x (%s)\n",
- chip_names[ov->subtype], client->addr << 1, client->adapter->name);
-
- PDEBUG(1, "Camera chip detection complete");
-
- return rc;
-error:
- kfree(ov);
-no_ov:
- PDEBUG(1, "returning %d", rc);
- return rc;
-}
-
-static int ovcamchip_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct ovcamchip *ov = to_ovcamchip(sd);
- int rc;
-
- v4l2_device_unregister_subdev(sd);
- rc = ov->sops->free(client);
- if (rc < 0)
- return rc;
-
- kfree(ov);
- return 0;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct i2c_device_id ovcamchip_id[] = {
- { "ovcamchip", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, ovcamchip_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "ovcamchip",
- .probe = ovcamchip_probe,
- .remove = ovcamchip_remove,
- .id_table = ovcamchip_id,
-};
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
deleted file mode 100644
index 4f07b78c88bc..000000000000
--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ /dev/null
@@ -1,101 +0,0 @@
-/* OmniVision* camera chip driver private definitions for core code and
- * chip-specific code
- *
- * Copyright (c) 1999-2004 Mark McClelland
- *
- * 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. NO WARRANTY OF ANY KIND is expressed or implied.
- *
- * * OmniVision is a trademark of OmniVision Technologies, Inc. This driver
- * is not sponsored or developed by them.
- */
-
-#ifndef __LINUX_OVCAMCHIP_PRIV_H
-#define __LINUX_OVCAMCHIP_PRIV_H
-
-#include <linux/i2c.h>
-#include <media/v4l2-subdev.h>
-#include <media/ovcamchip.h>
-
-#ifdef DEBUG
-extern int ovcamchip_debug;
-#endif
-
-#define PDEBUG(level, fmt, args...) \
- if (ovcamchip_debug >= (level)) pr_debug("[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args)
-
-#define DDEBUG(level, dev, fmt, args...) \
- if (ovcamchip_debug >= (level)) dev_dbg(dev, "[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args)
-
-/* Number of times to retry chip detection. Increase this if you are getting
- * "Failed to init camera chip" */
-#define I2C_DETECT_RETRIES 10
-
-struct ovcamchip_regvals {
- unsigned char reg;
- unsigned char val;
-};
-
-struct ovcamchip_ops {
- int (*init)(struct i2c_client *);
- int (*free)(struct i2c_client *);
- int (*command)(struct i2c_client *, unsigned int, void *);
-};
-
-struct ovcamchip {
- struct v4l2_subdev sd;
- struct ovcamchip_ops *sops;
- void *spriv; /* Private data for OV7x10.c etc... */
- int subtype; /* = SEN_OV7610 etc... */
- int mono; /* Monochrome chip? (invalid until init) */
- int initialized; /* OVCAMCHIP_CMD_INITIALIZE was successful */
-};
-
-static inline struct ovcamchip *to_ovcamchip(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct ovcamchip, sd);
-}
-
-extern struct ovcamchip_ops ov6x20_ops;
-extern struct ovcamchip_ops ov6x30_ops;
-extern struct ovcamchip_ops ov7x10_ops;
-extern struct ovcamchip_ops ov7x20_ops;
-extern struct ovcamchip_ops ov76be_ops;
-
-/* --------------------------------- */
-/* I2C I/O */
-/* --------------------------------- */
-
-static inline int ov_read(struct i2c_client *c, unsigned char reg,
- unsigned char *value)
-{
- int rc;
-
- rc = i2c_smbus_read_byte_data(c, reg);
- *value = (unsigned char) rc;
- return rc;
-}
-
-static inline int ov_write(struct i2c_client *c, unsigned char reg,
- unsigned char value )
-{
- return i2c_smbus_write_byte_data(c, reg, value);
-}
-
-/* --------------------------------- */
-/* FUNCTION PROTOTYPES */
-/* --------------------------------- */
-
-/* Functions in ovcamchip_core.c */
-
-extern int ov_write_regvals(struct i2c_client *c,
- struct ovcamchip_regvals *rvals);
-
-extern int ov_write_mask(struct i2c_client *c, unsigned char reg,
- unsigned char value, unsigned char mask);
-
-#endif
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 7129b50757db..7551907f8c28 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -932,7 +932,7 @@ static ssize_t pms_read(struct file *file, char __user *buf,
static const struct v4l2_file_operations pms_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = pms_read,
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 1b992b847198..7d5a7139a45a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -203,7 +203,7 @@ int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
*blen = 0;
LOCK_TAKE(cptr->hdw->big_lock); do {
if (cptr->info->type == pvr2_ctl_enum) {
- const char **names;
+ const char * const *names;
names = cptr->info->def.type_enum.value_names;
if (pvr2_ctrl_range_check(cptr,val) == 0) {
if (names[val]) {
@@ -367,7 +367,7 @@ static const char *boolNames[] = {
static int parse_token(const char *ptr,unsigned int len,
int *valptr,
- const char **names,unsigned int namecnt)
+ const char * const *names, unsigned int namecnt)
{
char buf[33];
unsigned int slen;
@@ -513,7 +513,7 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
if (ret >= 0) {
ret = pvr2_ctrl_range_check(cptr,*valptr);
}
- if (maskptr) *maskptr = ~0;
+ *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bool) {
ret = parse_token(ptr,len,valptr,boolNames,
ARRAY_SIZE(boolNames));
@@ -522,7 +522,7 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
} else if (ret == 0) {
*valptr = (*valptr & 1) ? !0 : 0;
}
- if (maskptr) *maskptr = 1;
+ *maskptr = 1;
} else if (cptr->info->type == pvr2_ctl_enum) {
ret = parse_token(
ptr,len,valptr,
@@ -531,7 +531,7 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
if (ret >= 0) {
ret = pvr2_ctrl_range_check(cptr,*valptr);
}
- if (maskptr) *maskptr = ~0;
+ *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bitmask) {
ret = parse_tlist(
ptr,len,maskptr,valptr,
@@ -559,7 +559,7 @@ int pvr2_ctrl_value_to_sym_internal(struct pvr2_ctrl *cptr,
*len = scnprintf(buf,maxlen,"%s",val ? "true" : "false");
ret = 0;
} else if (cptr->info->type == pvr2_ctl_enum) {
- const char **names;
+ const char * const *names;
names = cptr->info->def.type_enum.value_names;
if ((val >= 0) &&
(val < cptr->info->def.type_enum.count)) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index e9b11e119f62..4279ebb811a1 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -94,8 +94,6 @@ static int debugifc_parse_unsigned_number(const char *buf,unsigned int count,
u32 *num_ptr)
{
u32 result = 0;
- u32 val;
- int ch;
int radix = 10;
if ((count >= 2) && (buf[0] == '0') &&
((buf[1] == 'x') || (buf[1] == 'X'))) {
@@ -107,17 +105,9 @@ static int debugifc_parse_unsigned_number(const char *buf,unsigned int count,
}
while (count--) {
- ch = *buf++;
- if ((ch >= '0') && (ch <= '9')) {
- val = ch - '0';
- } else if ((ch >= 'a') && (ch <= 'f')) {
- val = ch - 'a' + 10;
- } else if ((ch >= 'A') && (ch <= 'F')) {
- val = ch - 'A' + 10;
- } else {
+ int val = hex_to_bin(*buf++);
+ if (val < 0 || val >= radix)
return -EINVAL;
- }
- if (val >= radix) return -EINVAL;
result *= radix;
result += val;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index 6bc16c13ccef..3092abfd66a2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -117,6 +117,7 @@ static const struct pvr2_device_desc pvr2_device_24xxx = {
static const struct pvr2_device_client_desc pvr2_cli_gotview_2[] = {
{ .module_id = PVR2_CLIENT_ID_CX25840 },
{ .module_id = PVR2_CLIENT_ID_TUNER },
+ { .module_id = PVR2_CLIENT_ID_DEMOD },
};
static const struct pvr2_device_desc pvr2_device_gotview_2 = {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index e5b9594eb5f6..273c8d4b3853 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -177,6 +177,11 @@ struct pvr2_device_desc {
unsigned int flag_has_composite:1; /* Has composite input */
unsigned int flag_has_svideo:1; /* Has s-video input */
unsigned int flag_fx2_16kb:1; /* 16KB FX2 firmware OK here */
+
+ /* If this driver is considered experimental, i.e. not all aspects
+ are working correctly and/or it is untested, mark that fact
+ with this flag. */
+ unsigned int flag_is_experimental:1;
};
extern struct usb_device_id pvr2_device_table[];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index cb4057bb07a0..305e6aaa844a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -40,6 +40,7 @@
#include "pvrusb2-io.h"
#include <media/v4l2-device.h>
#include <media/cx2341x.h>
+#include <media/ir-kbd-i2c.h>
#include "pvrusb2-devattr.h"
/* Legal values for PVR2_CID_HSM */
@@ -115,7 +116,7 @@ struct pvr2_ctl_info {
} type_int;
struct { /* enumerated control */
unsigned int count; /* enum value count */
- const char **value_names; /* symbol names */
+ const char * const *value_names; /* symbol names */
} type_enum;
struct { /* bitmask control */
unsigned int valid_bits; /* bits in use */
@@ -202,6 +203,7 @@ struct pvr2_hdw {
/* IR related */
unsigned int ir_scheme_active; /* IR scheme as seen from the outside */
+ struct IR_i2c_init_data ir_init_data; /* params passed to IR modules */
/* Frequency table */
unsigned int freqTable[FREQTABLE_SIZE];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 301ef197d038..66ad516bdfd9 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2082,29 +2082,20 @@ static int pvr2_hdw_load_subdev(struct pvr2_hdw *hdw,
return -EINVAL;
}
- /* Note how the 2nd and 3rd arguments are the same for
- * v4l2_i2c_new_subdev(). Why?
- * Well the 2nd argument is the module name to load, while the 3rd
- * argument is documented in the framework as being the "chipid" -
- * and every other place where I can find examples of this, the
- * "chipid" appears to just be the module name again. So here we
- * just do the same thing. */
if (i2ccnt == 1) {
pvr2_trace(PVR2_TRACE_INIT,
"Module ID %u:"
" Setting up with specified i2c address 0x%x",
mid, i2caddr[0]);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
- fname, fname,
- i2caddr[0], NULL);
+ fname, i2caddr[0], NULL);
} else {
pvr2_trace(PVR2_TRACE_INIT,
"Module ID %u:"
" Setting up with address probe list",
mid);
sd = v4l2_i2c_new_subdev(&hdw->v4l2_dev, &hdw->i2c_adap,
- fname, fname,
- 0, i2caddr);
+ fname, 0, i2caddr);
}
if (!sd) {
@@ -2459,6 +2450,19 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw,hdw_desc->description);
pvr2_trace(PVR2_TRACE_INFO, "Hardware description: %s",
hdw_desc->description);
+ if (hdw_desc->flag_is_experimental) {
+ pvr2_trace(PVR2_TRACE_INFO, "**********");
+ pvr2_trace(PVR2_TRACE_INFO,
+ "WARNING: Support for this device (%s) is"
+ " experimental.", hdw_desc->description);
+ pvr2_trace(PVR2_TRACE_INFO,
+ "Important functionality might not be"
+ " entirely working.");
+ pvr2_trace(PVR2_TRACE_INFO,
+ "Please consider contacting the driver author to"
+ " help with further stabilization of the driver.");
+ pvr2_trace(PVR2_TRACE_INFO, "**********");
+ }
if (!hdw) goto fail;
init_timer(&hdw->quiescent_timer);
@@ -3056,14 +3060,14 @@ static void pvr2_subdev_update(struct pvr2_hdw *hdw)
}
if (hdw->res_hor_dirty || hdw->res_ver_dirty || hdw->force_dirty) {
- struct v4l2_format fmt;
+ struct v4l2_mbus_framefmt fmt;
memset(&fmt, 0, sizeof(fmt));
- fmt.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt.fmt.pix.width = hdw->res_hor_val;
- fmt.fmt.pix.height = hdw->res_ver_val;
+ fmt.width = hdw->res_hor_val;
+ fmt.height = hdw->res_ver_val;
+ fmt.code = V4L2_MBUS_FMT_FIXED;
pvr2_trace(PVR2_TRACE_CHIPS, "subdev v4l2 set_size(%dx%d)",
- fmt.fmt.pix.width, fmt.fmt.pix.height);
- v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_fmt, &fmt);
+ fmt.width, fmt.height);
+ v4l2_device_call_all(&hdw->v4l2_dev, 0, video, s_mbus_fmt, &fmt);
}
if (hdw->srate_dirty || hdw->force_dirty) {
@@ -4084,12 +4088,20 @@ void pvr2_hdw_device_reset(struct pvr2_hdw *hdw)
void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
{
- char da[1];
+ char *da;
unsigned int pipe;
int ret;
if (!hdw->usb_dev) return;
+ da = kmalloc(16, GFP_KERNEL);
+
+ if (da == NULL) {
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "Unable to allocate memory to control CPU reset");
+ return;
+ }
+
pvr2_trace(PVR2_TRACE_INIT,"cpureset_assert(%d)",val);
da[0] = val ? 0x01 : 0x00;
@@ -4103,6 +4115,8 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
"cpureset_assert(%d) error=%d",val,ret);
pvr2_hdw_render_useless(hdw);
}
+
+ kfree(da);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 7cbe18c4ca95..ccc884948f34 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -19,6 +19,7 @@
*/
#include <linux/i2c.h>
+#include <media/ir-kbd-i2c.h>
#include "pvrusb2-i2c-core.h"
#include "pvrusb2-hdw-internal.h"
#include "pvrusb2-debug.h"
@@ -48,13 +49,6 @@ module_param_named(disable_autoload_ir_video, pvr2_disable_ir_video,
MODULE_PARM_DESC(disable_autoload_ir_video,
"1=do not try to autoload ir_video IR receiver");
-/* Mapping of IR schemes to known I2C addresses - if any */
-static const unsigned char ir_video_addresses[] = {
- [PVR2_IR_SCHEME_ZILOG] = 0x71,
- [PVR2_IR_SCHEME_29XXX] = 0x18,
- [PVR2_IR_SCHEME_24XXX] = 0x18,
-};
-
static int pvr2_i2c_write(struct pvr2_hdw *hdw, /* Context */
u8 i2c_addr, /* I2C address we're talking to */
u8 *data, /* Data to write */
@@ -574,26 +568,56 @@ static void do_i2c_scan(struct pvr2_hdw *hdw)
static void pvr2_i2c_register_ir(struct pvr2_hdw *hdw)
{
struct i2c_board_info info;
- unsigned char addr = 0;
+ struct IR_i2c_init_data *init_data = &hdw->ir_init_data;
if (pvr2_disable_ir_video) {
pvr2_trace(PVR2_TRACE_INFO,
"Automatic binding of ir_video has been disabled.");
return;
}
- if (hdw->ir_scheme_active < ARRAY_SIZE(ir_video_addresses)) {
- addr = ir_video_addresses[hdw->ir_scheme_active];
- }
- if (!addr) {
+ memset(&info, 0, sizeof(struct i2c_board_info));
+ switch (hdw->ir_scheme_active) {
+ case PVR2_IR_SCHEME_24XXX: /* FX2-controlled IR */
+ case PVR2_IR_SCHEME_29XXX: /* Original 29xxx device */
+ init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = hdw->hdw_desc->description;
+ init_data->polling_interval = 100; /* ms From ir-kbd-i2c */
+ /* IR Receiver */
+ info.addr = 0x18;
+ info.platform_data = init_data;
+ strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
+ pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+ info.type, info.addr);
+ i2c_new_device(&hdw->i2c_adap, &info);
+ break;
+ case PVR2_IR_SCHEME_ZILOG: /* HVR-1950 style */
+ case PVR2_IR_SCHEME_24XXX_MCE: /* 24xxx MCE device */
+ init_data->ir_codes = RC_MAP_HAUPPAUGE_NEW;
+ init_data->internal_get_key_func = IR_KBD_GET_KEY_HAUP_XVR;
+ init_data->type = RC_TYPE_RC5;
+ init_data->name = hdw->hdw_desc->description;
+ init_data->polling_interval = 260; /* ms From lirc_zilog */
+ /* IR Receiver */
+ info.addr = 0x71;
+ info.platform_data = init_data;
+ strlcpy(info.type, "ir_rx_z8f0811_haup", I2C_NAME_SIZE);
+ pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+ info.type, info.addr);
+ i2c_new_device(&hdw->i2c_adap, &info);
+ /* IR Trasmitter */
+ info.addr = 0x70;
+ info.platform_data = init_data;
+ strlcpy(info.type, "ir_tx_z8f0811_haup", I2C_NAME_SIZE);
+ pvr2_trace(PVR2_TRACE_INFO, "Binding %s to i2c address 0x%02x.",
+ info.type, info.addr);
+ i2c_new_device(&hdw->i2c_adap, &info);
+ break;
+ default:
/* The device either doesn't support I2C-based IR or we
don't know (yet) how to operate IR on the device. */
- return;
+ break;
}
- pvr2_trace(PVR2_TRACE_INFO,
- "Binding ir_video to i2c address 0x%02x.", addr);
- memset(&info, 0, sizeof(struct i2c_board_info));
- strlcpy(info.type, "ir_video", I2C_NAME_SIZE);
- info.addr = addr;
- i2c_new_device(&hdw->i2c_adap, &info);
}
void pvr2_i2c_core_init(struct pvr2_hdw *hdw)
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index b4824782d858..bba6115c9ae8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -223,7 +223,10 @@ int pvr2_ioread_setup(struct pvr2_ioread *cp,struct pvr2_stream *sp)
" pvr2_ioread_setup (setup) id=%p",cp);
pvr2_stream_kill(sp);
ret = pvr2_stream_set_buffer_count(sp,BUFFER_COUNT);
- if (ret < 0) return ret;
+ if (ret < 0) {
+ mutex_unlock(&cp->mutex);
+ return ret;
+ }
for (idx = 0; idx < BUFFER_COUNT; idx++) {
bp = pvr2_stream_get_buffer(sp,idx);
pvr2_buffer_set_buffer(bp,
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index eeacd0f67855..2254194aad57 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -153,12 +153,12 @@ static void __exit pvr_exit(void)
usb_deregister(&pvr_driver);
+ pvr2_context_global_done();
+
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_class_destroy(class_ptr);
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
- pvr2_context_global_done();
-
pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete");
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 71f50565f637..281806b2df62 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -74,7 +74,7 @@ struct pvr2_sysfs_ctl_item {
int ctl_id;
struct pvr2_sysfs *chptr;
struct pvr2_sysfs_ctl_item *item_next;
- struct attribute *attr_gen[7];
+ struct attribute *attr_gen[8];
struct attribute_group grp;
int created_ok;
char name[80];
@@ -511,6 +511,7 @@ static void pvr2_sysfs_release(struct device *class_dev)
static void class_dev_destroy(struct pvr2_sysfs *sfp)
{
+ struct device *dev;
if (!sfp->class_dev) return;
#ifdef CONFIG_VIDEO_PVRUSB2_DEBUGIFC
pvr2_sysfs_tear_down_debugifc(sfp);
@@ -542,6 +543,9 @@ static void class_dev_destroy(struct pvr2_sysfs *sfp)
}
pvr2_sysfs_trace("Destroying class_dev id=%p",sfp->class_dev);
dev_set_drvdata(sfp->class_dev, NULL);
+ dev = sfp->class_dev->parent;
+ sfp->class_dev->parent = NULL;
+ put_device(dev);
device_unregister(sfp->class_dev);
sfp->class_dev = NULL;
}
@@ -631,10 +635,11 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
pvr2_sysfs_trace("Creating class_dev id=%p",class_dev);
class_dev->class = &class_ptr->class;
+
dev_set_name(class_dev, "%s",
pvr2_hdw_get_device_identifier(sfp->channel.hdw));
- class_dev->parent = &usb_dev->dev;
+ class_dev->parent = get_device(&usb_dev->dev);
sfp->class_dev = class_dev;
dev_set_drvdata(class_dev, sfp);
@@ -642,7 +647,7 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"device_register failed");
- kfree(class_dev);
+ put_device(class_dev);
return;
}
@@ -775,7 +780,8 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
struct pvr2_sysfs_class *clp;
clp = kzalloc(sizeof(*clp),GFP_KERNEL);
if (!clp) return clp;
- pvr2_sysfs_trace("Creating pvr2_sysfs_class id=%p",clp);
+ pvr2_sysfs_trace("Creating and registering pvr2_sysfs_class id=%p",
+ clp);
clp->class.name = "pvrusb2";
clp->class.class_release = pvr2_sysfs_class_release;
clp->class.dev_release = pvr2_sysfs_release;
@@ -791,6 +797,7 @@ struct pvr2_sysfs_class *pvr2_sysfs_class_create(void)
void pvr2_sysfs_class_destroy(struct pvr2_sysfs_class *clp)
{
+ pvr2_sysfs_trace("Unregistering pvr2_sysfs_class id=%p", clp);
class_unregister(&clp->class);
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 5ffa0d2b0b0d..58617fc656c2 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -852,8 +852,8 @@ static long pvr2_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
#endif
default :
- ret = v4l_compat_translate_ioctl(file, cmd,
- arg, pvr2_v4l2_do_ioctl);
+ ret = -EINVAL;
+ break;
}
pvr2_hdw_commit_ctl(hdw);
@@ -883,6 +883,17 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
{
struct pvr2_hdw *hdw = dip->v4lp->channel.mc_head->hdw;
enum pvr2_config cfg = dip->config;
+ char msg[80];
+ unsigned int mcnt;
+
+ /* Construct the unregistration message *before* we actually
+ perform the unregistration step. By doing it this way we don't
+ have to worry about potentially touching deleted resources. */
+ mcnt = scnprintf(msg, sizeof(msg) - 1,
+ "pvrusb2: unregistered device %s [%s]",
+ video_device_node_name(&dip->devbase),
+ pvr2_config_get_name(cfg));
+ msg[mcnt] = 0;
pvr2_hdw_v4l_store_minor_number(hdw,dip->minor_type,-1);
@@ -894,9 +905,7 @@ static void pvr2_v4l2_dev_destroy(struct pvr2_v4l2_dev *dip)
are gone. */
video_unregister_device(&dip->devbase);
- printk(KERN_INFO "pvrusb2: unregistered device %s [%s]\n",
- video_device_node_name(&dip->devbase),
- pvr2_config_get_name(cfg));
+ printk(KERN_INFO "%s\n", msg);
}
diff --git a/drivers/media/video/pwc/Kconfig b/drivers/media/video/pwc/Kconfig
index 11980db22d31..8da42e4f1ba0 100644
--- a/drivers/media/video/pwc/Kconfig
+++ b/drivers/media/video/pwc/Kconfig
@@ -1,6 +1,6 @@
config USB_PWC
tristate "USB Philips Cameras"
- depends on VIDEO_V4L1
+ depends on VIDEO_V4L2
---help---
Say Y or M here if you want to use one of these Philips & OEM
webcams:
diff --git a/drivers/media/video/pwc/pwc-ctrl.c b/drivers/media/video/pwc/pwc-ctrl.c
index f7f7e04cf485..1593f8deb810 100644
--- a/drivers/media/video/pwc/pwc-ctrl.c
+++ b/drivers/media/video/pwc/pwc-ctrl.c
@@ -261,7 +261,7 @@ static int set_video_mode_Nala(struct pwc_device *pdev, int size, int frames)
PWC_DEBUG_MODULE("Failed to send video command... %d\n", ret);
return ret;
}
- if (pEntry->compressed && pdev->vpalette != VIDEO_PALETTE_RAW)
+ if (pEntry->compressed && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
pwc_dec1_init(pdev->type, pdev->release, buf, pdev->decompress_data);
pdev->cmd_len = 3;
@@ -321,7 +321,7 @@ static int set_video_mode_Timon(struct pwc_device *pdev, int size, int frames, i
if (ret < 0)
return ret;
- if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+ if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
pwc_dec23_init(pdev, pdev->type, buf);
pdev->cmd_len = 13;
@@ -356,7 +356,7 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i
fps = (frames / 5) - 1;
/* special case: VGA @ 5 fps and snapshot is raw bayer mode */
- if (size == PSZ_VGA && frames == 5 && snapshot && pdev->vpalette == VIDEO_PALETTE_RAW)
+ if (size == PSZ_VGA && frames == 5 && snapshot && pdev->pixfmt != V4L2_PIX_FMT_YUV420)
{
/* Only available in case the raw palette is selected or
we have the decompressor available. This mode is
@@ -394,7 +394,7 @@ static int set_video_mode_Kiara(struct pwc_device *pdev, int size, int frames, i
if (ret < 0)
return ret;
- if (pChoose->bandlength > 0 && pdev->vpalette != VIDEO_PALETTE_RAW)
+ if (pChoose->bandlength > 0 && pdev->pixfmt == V4L2_PIX_FMT_YUV420)
pwc_dec23_init(pdev, pdev->type, buf);
pdev->cmd_len = 12;
@@ -429,7 +429,7 @@ int pwc_set_video_mode(struct pwc_device *pdev, int width, int height, int frame
{
int ret, size;
- PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, palette %d).\n", width, height, frames, pdev->vpalette);
+ PWC_DEBUG_FLOW("set_video_mode(%dx%d @ %d, pixfmt %08x).\n", width, height, frames, pdev->pixfmt);
size = pwc_decode_size(pdev, width, height);
if (size < 0) {
PWC_DEBUG_MODULE("Could not find suitable size.\n");
@@ -519,13 +519,13 @@ static void pwc_set_image_buffer_size(struct pwc_device *pdev)
{
int i, factor = 0;
- /* for PALETTE_YUV420P */
- switch(pdev->vpalette)
- {
- case VIDEO_PALETTE_YUV420P:
+ /* for V4L2_PIX_FMT_YUV420 */
+ switch (pdev->pixfmt) {
+ case V4L2_PIX_FMT_YUV420:
factor = 6;
break;
- case VIDEO_PALETTE_RAW:
+ case V4L2_PIX_FMT_PWC1:
+ case V4L2_PIX_FMT_PWC2:
factor = 6; /* can be uncompressed YUV420P */
break;
}
@@ -1386,11 +1386,16 @@ long pwc_ioctl(struct pwc_device *pdev, unsigned int cmd, void *arg)
{
ARG_DEF(int, qual)
+ if (pdev->iso_init) {
+ ret = -EBUSY;
+ break;
+ }
+
ARG_IN(qual)
if (ARGR(qual) < 0 || ARGR(qual) > 3)
ret = -EINVAL;
else
- ret = pwc_try_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
+ ret = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, ARGR(qual), pdev->vsnapshot);
if (ret >= 0)
pdev->vcompression = ARGR(qual);
break;
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index aea7e224cef6..bd1519a4ecb4 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -62,7 +62,6 @@
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
#include <linux/usb/input.h>
#endif
@@ -163,7 +162,7 @@ static const struct v4l2_file_operations pwc_fops = {
.read = pwc_video_read,
.poll = pwc_video_poll,
.mmap = pwc_video_mmap,
- .ioctl = pwc_video_ioctl,
+ .unlocked_ioctl = pwc_video_ioctl,
};
static struct video_device pwc_template = {
.name = "Philips Webcam", /* Filled in later */
@@ -288,14 +287,13 @@ static int pwc_allocate_buffers(struct pwc_device *pdev)
/* create frame buffers, and make circular ring */
for (i = 0; i < default_fbufs; i++) {
if (pdev->fbuf[i].data == NULL) {
- kbuf = vmalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
+ kbuf = vzalloc(PWC_FRAME_SIZE); /* need vmalloc since frame buffer > 128K */
if (kbuf == NULL) {
PWC_ERROR("Failed to allocate frame buffer %d.\n", i);
return -ENOMEM;
}
PWC_DEBUG_MEMORY("Allocated frame buffer %d at %p.\n", i, kbuf);
pdev->fbuf[i].data = kbuf;
- memset(kbuf, 0, PWC_FRAME_SIZE);
}
}
@@ -900,10 +898,13 @@ int pwc_isoc_init(struct pwc_device *pdev)
/* link */
for (i = 0; i < MAX_ISO_BUFS; i++) {
ret = usb_submit_urb(pdev->sbuf[i].urb, GFP_KERNEL);
- if (ret)
+ if (ret) {
PWC_ERROR("isoc_init() submit_urb %d failed with error %d\n", i, ret);
- else
- PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
+ pdev->iso_init = 1;
+ pwc_isoc_cleanup(pdev);
+ return ret;
+ }
+ PWC_DEBUG_MEMORY("URB 0x%p submitted.\n", pdev->sbuf[i].urb);
}
/* All is done... */
@@ -959,7 +960,7 @@ void pwc_isoc_cleanup(struct pwc_device *pdev)
/* Stop camera, but only if we are sure the camera is still there (unplug
is signalled by EPIPE)
*/
- if (pdev->error_status && pdev->error_status != EPIPE) {
+ if (pdev->error_status != EPIPE) {
PWC_DEBUG_OPEN("Setting alternate interface 0.\n");
usb_set_interface(pdev->udev, 0, 0);
}
@@ -968,36 +969,6 @@ void pwc_isoc_cleanup(struct pwc_device *pdev)
PWC_DEBUG_OPEN("<< pwc_isoc_cleanup()\n");
}
-int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot)
-{
- int ret, start;
-
- /* Stop isoc stuff */
- pwc_isoc_cleanup(pdev);
- /* Reset parameters */
- pwc_reset_buffers(pdev);
- /* Try to set video mode... */
- start = ret = pwc_set_video_mode(pdev, width, height, new_fps, new_compression, new_snapshot);
- if (ret) {
- PWC_DEBUG_FLOW("pwc_set_video_mode attempt 1 failed.\n");
- /* That failed... restore old mode (we know that worked) */
- start = pwc_set_video_mode(pdev, pdev->view.x, pdev->view.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- if (start) {
- PWC_DEBUG_FLOW("pwc_set_video_mode attempt 2 failed.\n");
- }
- }
- if (start == 0)
- {
- if (pwc_isoc_init(pdev) < 0)
- {
- PWC_WARNING("Failed to restart ISOC transfers in pwc_try_video_mode.\n");
- ret = -EAGAIN; /* let's try again, who knows if it works a second time */
- }
- }
- pdev->drop_frames++; /* try to avoid garbage during switch */
- return ret; /* Return original error code */
-}
-
/*********
* sysfs
*********/
@@ -1177,7 +1148,7 @@ static int pwc_video_open(struct file *file)
/* Set some defaults */
pdev->vsnapshot = 0;
- /* Start iso pipe for video; first try the last used video size
+ /* Set video size, first try the last used video size
(or the default one); if that fails try QCIF/10 or QSIF/10;
it that fails too, give up.
*/
@@ -1204,15 +1175,6 @@ static int pwc_video_open(struct file *file)
return i;
}
- i = pwc_isoc_init(pdev);
- if (i) {
- PWC_DEBUG_OPEN("Failed to init ISOC stuff = %d.\n", i);
- pwc_isoc_cleanup(pdev);
- pwc_free_buffers(pdev);
- mutex_unlock(&pdev->modlock);
- return i;
- }
-
/* Initialize the webcam to sane value */
pwc_set_brightness(pdev, 0x7fff);
pwc_set_agc(pdev, 1, 0);
@@ -1247,8 +1209,8 @@ static int pwc_video_close(struct file *file)
PWC_DEBUG_OPEN(">> video_close called(vdev = 0x%p).\n", vdev);
- lock_kernel();
pdev = video_get_drvdata(vdev);
+ mutex_lock(&pdev->modlock);
if (pdev->vopen == 0)
PWC_DEBUG_MODULE("video_close() called on closed device?\n");
@@ -1286,7 +1248,7 @@ static int pwc_video_close(struct file *file)
if (device_hint[hint].pdev == pdev)
device_hint[hint].pdev = NULL;
}
- unlock_kernel();
+ mutex_unlock(&pdev->modlock);
return 0;
}
@@ -1327,6 +1289,11 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
goto err_out;
}
+ /* Start the stream (if not already started) */
+ rv = pwc_isoc_init(pdev);
+ if (rv)
+ goto err_out;
+
/* In case we're doing partial reads, we don't have to wait for a frame */
if (pdev->image_read_pos == 0) {
/* Do wait queueing according to the (doc)book */
@@ -1365,7 +1332,7 @@ static ssize_t pwc_video_read(struct file *file, char __user *buf,
}
PWC_DEBUG_READ("Copying data to user space.\n");
- if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
bytes_to_read = pdev->frame_size + sizeof(struct pwc_raw_frame);
else
bytes_to_read = pdev->view.size;
@@ -1396,6 +1363,7 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
{
struct video_device *vdev = file->private_data;
struct pwc_device *pdev;
+ int ret;
if (vdev == NULL)
return -EFAULT;
@@ -1403,6 +1371,13 @@ static unsigned int pwc_video_poll(struct file *file, poll_table *wait)
if (pdev == NULL)
return -EFAULT;
+ /* Start the stream (if not already started) */
+ mutex_lock(&pdev->modlock);
+ ret = pwc_isoc_init(pdev);
+ mutex_unlock(&pdev->modlock);
+ if (ret)
+ return ret;
+
poll_wait(file, &pdev->frameq, wait);
if (pdev->error_status)
return POLLERR;
@@ -1800,13 +1775,6 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
}
pdev->vdev->release = video_device_release;
- rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
- if (rc < 0) {
- PWC_ERROR("Failed to register as video device (%d).\n", rc);
- goto err_video_release;
- }
-
- PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev));
/* occupy slot */
if (hint < MAX_DEV_HINTS)
@@ -1814,14 +1782,22 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
PWC_DEBUG_PROBE("probe() function returning struct at 0x%p.\n", pdev);
usb_set_intfdata(intf, pdev);
- rc = pwc_create_sysfs_files(pdev->vdev);
- if (rc)
- goto err_video_unreg;
/* Set the leds off */
pwc_set_leds(pdev, 0, 0);
pwc_camera_power(pdev, 0);
+ rc = video_register_device(pdev->vdev, VFL_TYPE_GRABBER, video_nr);
+ if (rc < 0) {
+ PWC_ERROR("Failed to register as video device (%d).\n", rc);
+ goto err_video_release;
+ }
+ rc = pwc_create_sysfs_files(pdev->vdev);
+ if (rc)
+ goto err_video_unreg;
+
+ PWC_INFO("Registered as %s.\n", video_device_node_name(pdev->vdev));
+
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
/* register webcam snapshot button input device */
pdev->button_dev = input_allocate_device();
@@ -1871,8 +1847,8 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
struct pwc_device *pdev;
int hint;
- lock_kernel();
pdev = usb_get_intfdata (intf);
+ mutex_lock(&pdev->modlock);
usb_set_intfdata (intf, NULL);
if (pdev == NULL) {
PWC_ERROR("pwc_disconnect() Called without private pointer.\n");
@@ -1897,9 +1873,7 @@ static void usb_pwc_disconnect(struct usb_interface *intf)
wake_up_interruptible(&pdev->frameq);
/* Wait until device is closed */
if (pdev->vopen) {
- mutex_lock(&pdev->modlock);
pdev->unplugged = 1;
- mutex_unlock(&pdev->modlock);
pwc_iso_stop(pdev);
} else {
/* Device is closed, so we can safely unregister it */
@@ -1913,7 +1887,7 @@ disconnect_out:
device_hint[hint].pdev = NULL;
}
- unlock_kernel();
+ mutex_unlock(&pdev->modlock);
}
diff --git a/drivers/media/video/pwc/pwc-misc.c b/drivers/media/video/pwc/pwc-misc.c
index 589c687439da..6af5bb538358 100644
--- a/drivers/media/video/pwc/pwc-misc.c
+++ b/drivers/media/video/pwc/pwc-misc.c
@@ -47,7 +47,7 @@ int pwc_decode_size(struct pwc_device *pdev, int width, int height)
you don't have the decompressor loaded or use RAW mode,
the maximum viewable size is smaller.
*/
- if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
{
if (width > pdev->abs_max.x || height > pdev->abs_max.y)
{
@@ -123,7 +123,7 @@ void pwc_construct(struct pwc_device *pdev)
pdev->frame_header_size = 0;
pdev->frame_trailer_size = 0;
}
- pdev->vpalette = VIDEO_PALETTE_YUV420P; /* default */
+ pdev->pixfmt = V4L2_PIX_FMT_YUV420; /* default */
pdev->view_min.size = pdev->view_min.x * pdev->view_min.y;
pdev->view_max.size = pdev->view_max.x * pdev->view_max.y;
/* length of image, in YUV format; always allocate enough memory. */
diff --git a/drivers/media/video/pwc/pwc-uncompress.c b/drivers/media/video/pwc/pwc-uncompress.c
index 5d82028ef942..3b73f295f032 100644
--- a/drivers/media/video/pwc/pwc-uncompress.c
+++ b/drivers/media/video/pwc/pwc-uncompress.c
@@ -54,7 +54,7 @@ int pwc_decompress(struct pwc_device *pdev)
yuv = fbuf->data + pdev->frame_header_size; /* Skip header */
/* Raw format; that's easy... */
- if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
{
struct pwc_raw_frame *raw_frame = image;
raw_frame->type = cpu_to_le16(pdev->type);
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 62d89b3113a4..8ca4d22b4384 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -216,7 +216,7 @@ static void pwc_vidioc_fill_fmt(const struct pwc_device *pdev, struct v4l2_forma
f->fmt.pix.width = pdev->view.x;
f->fmt.pix.height = pdev->view.y;
f->fmt.pix.field = V4L2_FIELD_NONE;
- if (pdev->vpalette == VIDEO_PALETTE_YUV420P) {
+ if (pdev->pixfmt == V4L2_PIX_FMT_YUV420) {
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUV420;
f->fmt.pix.bytesperline = (f->fmt.pix.width * 3)/2;
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
@@ -304,12 +304,15 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
fps = pdev->vframes;
}
- if (pixelformat == V4L2_PIX_FMT_YUV420)
- pdev->vpalette = VIDEO_PALETTE_YUV420P;
- else
- pdev->vpalette = VIDEO_PALETTE_RAW;
+ if (pixelformat != V4L2_PIX_FMT_YUV420 &&
+ pixelformat != V4L2_PIX_FMT_PWC1 &&
+ pixelformat != V4L2_PIX_FMT_PWC2)
+ return -EINVAL;
+
+ if (pdev->iso_init)
+ return -EBUSY;
- PWC_DEBUG_IOCTL("Try to change format to: width=%d height=%d fps=%d "
+ PWC_DEBUG_IOCTL("Trying to set format to: width=%d height=%d fps=%d "
"compression=%d snapshot=%d format=%c%c%c%c\n",
f->fmt.pix.width, f->fmt.pix.height, fps,
compression, snapshot,
@@ -318,18 +321,20 @@ static int pwc_vidioc_set_fmt(struct pwc_device *pdev, struct v4l2_format *f)
(pixelformat>>16)&255,
(pixelformat>>24)&255);
- ret = pwc_try_video_mode(pdev,
+ ret = pwc_set_video_mode(pdev,
f->fmt.pix.width,
f->fmt.pix.height,
fps,
compression,
snapshot);
- PWC_DEBUG_IOCTL("pwc_try_video_mode(), return=%d\n", ret);
+ PWC_DEBUG_IOCTL("pwc_set_video_mode(), return=%d\n", ret);
if (ret)
return ret;
+ pdev->pixfmt = pixelformat;
+
pwc_vidioc_fill_fmt(pdev, f);
return 0;
@@ -357,325 +362,6 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
switch (cmd) {
- /* Query cabapilities */
- case VIDIOCGCAP:
- {
- struct video_capability *caps = arg;
-
- strcpy(caps->name, vdev->name);
- caps->type = VID_TYPE_CAPTURE;
- caps->channels = 1;
- caps->audios = 1;
- caps->minwidth = pdev->view_min.x;
- caps->minheight = pdev->view_min.y;
- caps->maxwidth = pdev->view_max.x;
- caps->maxheight = pdev->view_max.y;
- break;
- }
-
- /* Channel functions (simulate 1 channel) */
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Webcam");
- return 0;
- }
-
- case VIDIOCSCHAN:
- {
- /* The spec says the argument is an integer, but
- the bttv driver uses a video_channel arg, which
- makes sense becasue it also has the norm flag.
- */
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
-
-
- /* Picture functions; contrast etc. */
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
- int val;
-
- val = pwc_get_brightness(pdev);
- if (val >= 0)
- p->brightness = (val<<9);
- else
- p->brightness = 0xffff;
- val = pwc_get_contrast(pdev);
- if (val >= 0)
- p->contrast = (val<<10);
- else
- p->contrast = 0xffff;
- /* Gamma, Whiteness, what's the difference? :) */
- val = pwc_get_gamma(pdev);
- if (val >= 0)
- p->whiteness = (val<<11);
- else
- p->whiteness = 0xffff;
- if (pwc_get_saturation(pdev, &val)<0)
- p->colour = 0xffff;
- else
- p->colour = 32768 + val * 327;
- p->depth = 24;
- p->palette = pdev->vpalette;
- p->hue = 0xFFFF; /* N/A */
- break;
- }
-
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
- /*
- * FIXME: Suppose we are mid read
- ANSWER: No problem: the firmware of the camera
- can handle brightness/contrast/etc
- changes at _any_ time, and the palette
- is used exactly once in the uncompress
- routine.
- */
- pwc_set_brightness(pdev, p->brightness);
- pwc_set_contrast(pdev, p->contrast);
- pwc_set_gamma(pdev, p->whiteness);
- pwc_set_saturation(pdev, (p->colour-32768)/327);
- if (p->palette && p->palette != pdev->vpalette) {
- switch (p->palette) {
- case VIDEO_PALETTE_YUV420P:
- case VIDEO_PALETTE_RAW:
- pdev->vpalette = p->palette;
- return pwc_try_video_mode(pdev, pdev->image.x, pdev->image.y, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- break;
- default:
- return -EINVAL;
- break;
- }
- }
- break;
- }
-
- /* Window/size parameters */
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
-
- vw->x = 0;
- vw->y = 0;
- vw->width = pdev->view.x;
- vw->height = pdev->view.y;
- vw->chromakey = 0;
- vw->flags = (pdev->vframes << PWC_FPS_SHIFT) |
- (pdev->vsnapshot ? PWC_FPS_SNAPSHOT : 0);
- break;
- }
-
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
- int fps, snapshot, ret;
-
- fps = (vw->flags & PWC_FPS_FRMASK) >> PWC_FPS_SHIFT;
- snapshot = vw->flags & PWC_FPS_SNAPSHOT;
- if (fps == 0)
- fps = pdev->vframes;
- if (pdev->view.x == vw->width && pdev->view.y && fps == pdev->vframes && snapshot == pdev->vsnapshot)
- return 0;
- ret = pwc_try_video_mode(pdev, vw->width, vw->height, fps, pdev->vcompression, snapshot);
- if (ret)
- return ret;
- break;
- }
-
- /* We don't have overlay support (yet) */
- case VIDIOCGFBUF:
- {
- struct video_buffer *vb = arg;
-
- memset(vb,0,sizeof(*vb));
- break;
- }
-
- /* mmap() functions */
- case VIDIOCGMBUF:
- {
- /* Tell the user program how much memory is needed for a mmap() */
- struct video_mbuf *vm = arg;
- int i;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = pwc_mbufs * pdev->len_per_image;
- vm->frames = pwc_mbufs; /* double buffering should be enough for most applications */
- for (i = 0; i < pwc_mbufs; i++)
- vm->offsets[i] = i * pdev->len_per_image;
- break;
- }
-
- case VIDIOCMCAPTURE:
- {
- /* Start capture into a given image buffer (called 'frame' in video_mmap structure) */
- struct video_mmap *vm = arg;
-
- PWC_DEBUG_READ("VIDIOCMCAPTURE: %dx%d, frame %d, format %d\n", vm->width, vm->height, vm->frame, vm->format);
- if (vm->frame < 0 || vm->frame >= pwc_mbufs)
- return -EINVAL;
-
- /* xawtv is nasty. It probes the available palettes
- by setting a very small image size and trying
- various palettes... The driver doesn't support
- such small images, so I'm working around it.
- */
- if (vm->format)
- {
- switch (vm->format)
- {
- case VIDEO_PALETTE_YUV420P:
- case VIDEO_PALETTE_RAW:
- break;
- default:
- return -EINVAL;
- break;
- }
- }
-
- if ((vm->width != pdev->view.x || vm->height != pdev->view.y) &&
- (vm->width >= pdev->view_min.x && vm->height >= pdev->view_min.y)) {
- int ret;
-
- PWC_DEBUG_OPEN("VIDIOCMCAPTURE: changing size to please xawtv :-(.\n");
- ret = pwc_try_video_mode(pdev, vm->width, vm->height, pdev->vframes, pdev->vcompression, pdev->vsnapshot);
- if (ret)
- return ret;
- } /* ... size mismatch */
-
- /* FIXME: should we lock here? */
- if (pdev->image_used[vm->frame])
- return -EBUSY; /* buffer wasn't available. Bummer */
- pdev->image_used[vm->frame] = 1;
-
- /* Okay, we're done here. In the SYNC call we wait until a
- frame comes available, then expand image into the given
- buffer.
- In contrast to the CPiA cam the Philips cams deliver a
- constant stream, almost like a grabber card. Also,
- we have separate buffers for the rawdata and the image,
- meaning we can nearly always expand into the requested buffer.
- */
- PWC_DEBUG_READ("VIDIOCMCAPTURE done.\n");
- break;
- }
-
- case VIDIOCSYNC:
- {
- /* The doc says: "Whenever a buffer is used it should
- call VIDIOCSYNC to free this frame up and continue."
-
- The only odd thing about this whole procedure is
- that MCAPTURE flags the buffer as "in use", and
- SYNC immediately unmarks it, while it isn't
- after SYNC that you know that the buffer actually
- got filled! So you better not start a CAPTURE in
- the same frame immediately (use double buffering).
- This is not a problem for this cam, since it has
- extra intermediate buffers, but a hardware
- grabber card will then overwrite the buffer
- you're working on.
- */
- int *mbuf = arg;
- int ret;
-
- PWC_DEBUG_READ("VIDIOCSYNC called (%d).\n", *mbuf);
-
- /* bounds check */
- if (*mbuf < 0 || *mbuf >= pwc_mbufs)
- return -EINVAL;
- /* check if this buffer was requested anyway */
- if (pdev->image_used[*mbuf] == 0)
- return -EINVAL;
-
- /* Add ourselves to the frame wait-queue.
-
- FIXME: needs auditing for safety.
- QUESTION: In what respect? I think that using the
- frameq is safe now.
- */
- add_wait_queue(&pdev->frameq, &wait);
- while (pdev->full_frames == NULL) {
- /* Check for unplugged/etc. here */
- if (pdev->error_status) {
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
- return -pdev->error_status;
- }
-
- if (signal_pending(current)) {
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
- return -ERESTARTSYS;
- }
- schedule();
- set_current_state(TASK_INTERRUPTIBLE);
- }
- remove_wait_queue(&pdev->frameq, &wait);
- set_current_state(TASK_RUNNING);
-
- /* The frame is ready. Expand in the image buffer
- requested by the user. I don't care if you
- mmap() 5 buffers and request data in this order:
- buffer 4 2 3 0 1 2 3 0 4 3 1 . . .
- Grabber hardware may not be so forgiving.
- */
- PWC_DEBUG_READ("VIDIOCSYNC: frame ready.\n");
- pdev->fill_image = *mbuf; /* tell in which buffer we want the image to be expanded */
- /* Decompress, etc */
- ret = pwc_handle_frame(pdev);
- pdev->image_used[*mbuf] = 0;
- if (ret)
- return -EFAULT;
- break;
- }
-
- case VIDIOCGAUDIO:
- {
- struct video_audio *v = arg;
-
- strcpy(v->name, "Microphone");
- v->audio = -1; /* unknown audio minor */
- v->flags = 0;
- v->mode = VIDEO_SOUND_MONO;
- v->volume = 0;
- v->bass = 0;
- v->treble = 0;
- v->balance = 0x8000;
- v->step = 1;
- break;
- }
-
- case VIDIOCSAUDIO:
- {
- /* Dummy: nothing can be set */
- break;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit *vu = arg;
-
- vu->video = pdev->vdev->minor & 0x3F;
- vu->audio = -1; /* not known yet */
- vu->vbi = -1;
- vu->radio = -1;
- vu->teletext = -1;
- break;
- }
-
/* V4L2 Layer */
case VIDIOC_QUERYCAP:
{
@@ -1081,7 +767,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
buf->index = index;
buf->m.offset = index * pdev->len_per_image;
- if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
else
buf->bytesused = pdev->view.size;
@@ -1158,7 +844,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
PWC_DEBUG_IOCTL("VIDIOC_DQBUF: after pwc_handle_frame\n");
buf->index = pdev->fill_image;
- if (pdev->vpalette == VIDEO_PALETTE_RAW)
+ if (pdev->pixfmt != V4L2_PIX_FMT_YUV420)
buf->bytesused = pdev->frame_size + sizeof(struct pwc_raw_frame);
else
buf->bytesused = pdev->view.size;
@@ -1182,9 +868,7 @@ long pwc_video_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_STREAMON:
{
- /* WARNING: pwc_try_video_mode() called pwc_isoc_init */
- pwc_isoc_init(pdev);
- return 0;
+ return pwc_isoc_init(pdev);
}
case VIDIOC_STREAMOFF:
diff --git a/drivers/media/video/pwc/pwc.h b/drivers/media/video/pwc/pwc.h
index f1b206632957..16bbc6df9b07 100644
--- a/drivers/media/video/pwc/pwc.h
+++ b/drivers/media/video/pwc/pwc.h
@@ -34,7 +34,7 @@
#include <linux/mm.h>
#include <linux/slab.h>
#include <asm/errno.h>
-#include <linux/videodev.h>
+#include <linux/videodev2.h>
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
#ifdef CONFIG_USB_PWC_INPUT_EVDEV
@@ -49,7 +49,7 @@
#define PWC_MINOR 0
#define PWC_EXTRAMINOR 12
#define PWC_VERSION_CODE KERNEL_VERSION(PWC_MAJOR,PWC_MINOR,PWC_EXTRAMINOR)
-#define PWC_VERSION "10.0.13"
+#define PWC_VERSION "10.0.14"
#define PWC_NAME "pwc"
#define PFX PWC_NAME ": "
@@ -180,7 +180,7 @@ struct pwc_device
int vcinterface; /* video control interface */
int valternate; /* alternate interface needed */
int vframes, vsize; /* frames-per-second & size (see PSZ_*) */
- int vpalette; /* palette: 420P, RAW or RGBBAYER */
+ int pixfmt; /* pixelformat: V4L2_PIX_FMT_YUV420 or raw: _PWC1, _PWC2 */
int vframe_count; /* received frames */
int vframes_dumped; /* counter for dumped frames */
int vframes_error; /* frames received in error */
@@ -275,7 +275,6 @@ extern int pwc_trace;
extern int pwc_mbufs;
/** functions in pwc-if.c */
-int pwc_try_video_mode(struct pwc_device *pdev, int width, int height, int new_fps, int new_compression, int new_snapshot);
int pwc_handle_frame(struct pwc_device *pdev);
void pwc_next_image(struct pwc_device *pdev);
int pwc_isoc_init(struct pwc_device *pdev);
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
index 7fe70e718656..02686771740d 100644
--- a/drivers/media/video/pxa_camera.c
+++ b/drivers/media/video/pxa_camera.c
@@ -275,8 +275,8 @@ static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
* This waits until this buffer is out of danger, i.e., until it is no
* longer in STATE_QUEUED or STATE_ACTIVE
*/
- videobuf_waiton(&buf->vb, 0, 0);
- videobuf_dma_unmap(vq, dma);
+ videobuf_waiton(vq, &buf->vb, 0, 0);
+ videobuf_dma_unmap(vq->dev, dma);
videobuf_dma_free(dma);
for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
@@ -852,7 +852,7 @@ static void pxa_camera_init_videobuf(struct videobuf_queue *q,
*/
videobuf_queue_sg_init(q, &pxa_videobuf_ops, NULL, &pcdev->lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
- sizeof(struct pxa_buffer), icd);
+ sizeof(struct pxa_buffer), icd, &icd->video_lock);
}
static u32 mclk_get_divisor(struct platform_device *pdev,
@@ -1247,7 +1247,7 @@ static bool pxa_camera_packing_supported(const struct soc_mbus_pixelfmt *fmt)
fmt->packing == SOC_MBUS_PACKING_EXTEND16);
}
-static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
+static int pxa_camera_get_formats(struct soc_camera_device *icd, unsigned int idx,
struct soc_camera_format_xlate *xlate)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
@@ -1264,7 +1264,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(dev, "Invalid format code #%d: %d\n", idx, code);
+ dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
return 0;
}
@@ -1284,7 +1284,7 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
}
switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
formats++;
if (xlate) {
xlate->host_fmt = &pxa_camera_formats[0];
@@ -1293,9 +1293,9 @@ static int pxa_camera_get_formats(struct soc_camera_device *icd, int idx,
dev_dbg(dev, "Providing format %s using code %d\n",
pxa_camera_formats[0].name, code);
}
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
case V4L2_MBUS_FMT_RGB565_2X8_LE:
case V4L2_MBUS_FMT_RGB555_2X8_PADHI_LE:
if (xlate)
@@ -1539,7 +1539,7 @@ static int pxa_camera_try_fmt(struct soc_camera_device *icd,
return ret;
}
-static int pxa_camera_reqbufs(struct soc_camera_file *icf,
+static int pxa_camera_reqbufs(struct soc_camera_device *icd,
struct v4l2_requestbuffers *p)
{
int i;
@@ -1551,7 +1551,7 @@ static int pxa_camera_reqbufs(struct soc_camera_file *icf,
* it hadn't triggered
*/
for (i = 0; i < p->count; i++) {
- struct pxa_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+ struct pxa_buffer *buf = container_of(icd->vb_vidq.bufs[i],
struct pxa_buffer, vb);
buf->inwork = 0;
INIT_LIST_HEAD(&buf->vb.queue);
@@ -1562,10 +1562,10 @@ static int pxa_camera_reqbufs(struct soc_camera_file *icf,
static unsigned int pxa_camera_poll(struct file *file, poll_table *pt)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
struct pxa_buffer *buf;
- buf = list_entry(icf->vb_vidq.stream.next, struct pxa_buffer,
+ buf = list_entry(icd->vb_vidq.stream.next, struct pxa_buffer,
vb.stream);
poll_wait(file, &buf->vb.done, pt);
diff --git a/drivers/media/video/rj54n1cb0c.c b/drivers/media/video/rj54n1cb0c.c
index bbd9c11e2c5a..57e11b6f19fb 100644
--- a/drivers/media/video/rj54n1cb0c.c
+++ b/drivers/media/video/rj54n1cb0c.c
@@ -1,5 +1,5 @@
/*
- * Driver for RJ54N1CB0C CMOS Image Sensor from Micron
+ * Driver for RJ54N1CB0C CMOS Image Sensor from Sharp
*
* Copyright (C) 2009, Guennadi Liakhovetski <g.liakhovetski@gmx.de>
*
@@ -127,8 +127,8 @@ static const struct rj54n1_datafmt *rj54n1_find_datafmt(
}
static const struct rj54n1_datafmt rj54n1_colour_fmts[] = {
- {V4L2_MBUS_FMT_YUYV8_2X8_LE, V4L2_COLORSPACE_JPEG},
- {V4L2_MBUS_FMT_YVYU8_2X8_LE, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YUYV8_2X8, V4L2_COLORSPACE_JPEG},
+ {V4L2_MBUS_FMT_YVYU8_2X8, V4L2_COLORSPACE_JPEG},
{V4L2_MBUS_FMT_RGB565_2X8_LE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_RGB565_2X8_BE, V4L2_COLORSPACE_SRGB},
{V4L2_MBUS_FMT_SBGGR10_2X8_PADHI_LE, V4L2_COLORSPACE_SRGB},
@@ -481,10 +481,10 @@ static int reg_write_multiple(struct i2c_client *client,
return 0;
}
-static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index,
+static int rj54n1_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
- if ((unsigned int)index >= ARRAY_SIZE(rj54n1_colour_fmts))
+ if (index >= ARRAY_SIZE(rj54n1_colour_fmts))
return -EINVAL;
*code = rj54n1_colour_fmts[index].code;
@@ -493,7 +493,7 @@ static int rj54n1_enum_fmt(struct v4l2_subdev *sd, int index,
static int rj54n1_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
/* Switch between preview and still shot modes */
return reg_set(client, RJ54N1_STILL_CONTROL, (!enable) << 7, 0x80);
@@ -503,7 +503,7 @@ static int rj54n1_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
/* Figures 2.5-1 to 2.5-3 - default falling pixclk edge */
if (flags & SOCAM_PCLK_SAMPLE_RISING)
@@ -560,7 +560,7 @@ static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
struct v4l2_rect *rect = &a->c;
int dummy = 0, output_w, output_h,
@@ -595,7 +595,7 @@ static int rj54n1_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
static int rj54n1_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
a->c = rj54n1->rect;
@@ -621,7 +621,7 @@ static int rj54n1_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int rj54n1_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
mf->code = rj54n1->fmt->code;
@@ -641,7 +641,7 @@ static int rj54n1_g_fmt(struct v4l2_subdev *sd,
static int rj54n1_sensor_scale(struct v4l2_subdev *sd, s32 *in_w, s32 *in_h,
s32 *out_w, s32 *out_h)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
unsigned int skip, resize, input_w = *in_w, input_h = *in_h,
output_w = *out_w, output_h = *out_h;
@@ -983,7 +983,7 @@ static int rj54n1_reg_init(struct i2c_client *client)
static int rj54n1_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
const struct rj54n1_datafmt *fmt;
int align = mf->code == V4L2_MBUS_FMT_SBGGR10_1X10 ||
@@ -1014,7 +1014,7 @@ static int rj54n1_try_fmt(struct v4l2_subdev *sd,
static int rj54n1_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
const struct rj54n1_datafmt *fmt;
int output_w, output_h, max_w, max_h,
@@ -1046,12 +1046,12 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
/* RA_SEL_UL is only relevant for raw modes, ignored otherwise. */
switch (mf->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 8, 8);
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
ret = reg_write(client, RJ54N1_OUT_SEL, 0);
if (!ret)
ret = reg_set(client, RJ54N1_BYTE_SWAP, 0, 8);
@@ -1145,7 +1145,7 @@ static int rj54n1_s_fmt(struct v4l2_subdev *sd,
static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (id->match.type != V4L2_CHIP_MATCH_I2C_ADDR)
return -EINVAL;
@@ -1163,7 +1163,7 @@ static int rj54n1_g_chip_ident(struct v4l2_subdev *sd,
static int rj54n1_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
reg->reg < 0x400 || reg->reg > 0x1fff)
@@ -1185,7 +1185,7 @@ static int rj54n1_g_register(struct v4l2_subdev *sd,
static int rj54n1_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->match.type != V4L2_CHIP_MATCH_I2C_ADDR ||
reg->reg < 0x400 || reg->reg > 0x1fff)
@@ -1248,7 +1248,7 @@ static struct soc_camera_ops rj54n1_ops = {
static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
int data;
@@ -1283,7 +1283,7 @@ static int rj54n1_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
static int rj54n1_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
{
int data;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct rj54n1 *rj54n1 = to_rj54n1(client);
const struct v4l2_queryctrl *qctrl;
@@ -1444,7 +1444,6 @@ static int rj54n1_probe(struct i2c_client *client,
ret = rj54n1_video_probe(icd, client, rj54n1_priv);
if (ret < 0) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(rj54n1);
return ret;
}
@@ -1461,8 +1460,6 @@ static int rj54n1_remove(struct i2c_client *client)
icd->ops = NULL;
if (icl->free_bus)
icl->free_bus(icl);
- i2c_set_clientdata(client, NULL);
- client->driver = NULL;
kfree(rj54n1);
return 0;
diff --git a/drivers/media/video/s2255drv.c b/drivers/media/video/s2255drv.c
index 3c7a79f3812a..b63f8cafa671 100644
--- a/drivers/media/video/s2255drv.c
+++ b/drivers/media/video/s2255drv.c
@@ -49,7 +49,6 @@
#include <linux/videodev2.h>
#include <linux/version.h>
#include <linux/mm.h>
-#include <linux/smp_lock.h>
#include <media/videobuf-vmalloc.h>
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
@@ -191,7 +190,6 @@ struct s2255_bufferi {
struct s2255_dmaqueue {
struct list_head active;
struct s2255_dev *dev;
- int channel;
};
/* for firmware loading, fw_state */
@@ -226,51 +224,60 @@ struct s2255_pipeinfo {
};
struct s2255_fmt; /*forward declaration */
+struct s2255_dev;
+
+struct s2255_channel {
+ struct video_device vdev;
+ int resources;
+ struct s2255_dmaqueue vidq;
+ struct s2255_bufferi buffer;
+ struct s2255_mode mode;
+ /* jpeg compression */
+ struct v4l2_jpegcompression jc;
+ /* capture parameters (for high quality mode full size) */
+ struct v4l2_captureparm cap_parm;
+ int cur_frame;
+ int last_frame;
+
+ int b_acquire;
+ /* allocated image size */
+ unsigned long req_image_size;
+ /* received packet size */
+ unsigned long pkt_size;
+ int bad_payload;
+ unsigned long frame_count;
+ /* if JPEG image */
+ int jpg_size;
+ /* if channel configured to default state */
+ int configured;
+ wait_queue_head_t wait_setmode;
+ int setmode_ready;
+ /* video status items */
+ int vidstatus;
+ wait_queue_head_t wait_vidstatus;
+ int vidstatus_ready;
+ unsigned int width;
+ unsigned int height;
+ const struct s2255_fmt *fmt;
+ int idx; /* channel number on device, 0-3 */
+};
+
struct s2255_dev {
- struct video_device vdev[MAX_CHANNELS];
+ struct s2255_channel channel[MAX_CHANNELS];
struct v4l2_device v4l2_dev;
- atomic_t channels; /* number of channels registered */
+ atomic_t num_channels;
int frames;
- struct mutex lock;
+ struct mutex lock; /* channels[].vdev.lock */
struct mutex open_lock;
- int resources[MAX_CHANNELS];
struct usb_device *udev;
struct usb_interface *interface;
u8 read_endpoint;
-
- struct s2255_dmaqueue vidq[MAX_CHANNELS];
struct timer_list timer;
struct s2255_fw *fw_data;
struct s2255_pipeinfo pipe;
- struct s2255_bufferi buffer[MAX_CHANNELS];
- struct s2255_mode mode[MAX_CHANNELS];
- /* jpeg compression */
- struct v4l2_jpegcompression jc[MAX_CHANNELS];
- /* capture parameters (for high quality mode full size) */
- struct v4l2_captureparm cap_parm[MAX_CHANNELS];
- const struct s2255_fmt *cur_fmt[MAX_CHANNELS];
- int cur_frame[MAX_CHANNELS];
- int last_frame[MAX_CHANNELS];
u32 cc; /* current channel */
- int b_acquire[MAX_CHANNELS];
- /* allocated image size */
- unsigned long req_image_size[MAX_CHANNELS];
- /* received packet size */
- unsigned long pkt_size[MAX_CHANNELS];
- int bad_payload[MAX_CHANNELS];
- unsigned long frame_count[MAX_CHANNELS];
int frame_ready;
- /* if JPEG image */
- int jpg_size[MAX_CHANNELS];
- /* if channel configured to default state */
- int chn_configured[MAX_CHANNELS];
- wait_queue_head_t wait_setmode[MAX_CHANNELS];
- int setmode_ready[MAX_CHANNELS];
- /* video status items */
- int vidstatus[MAX_CHANNELS];
- wait_queue_head_t wait_vidstatus[MAX_CHANNELS];
- int vidstatus_ready[MAX_CHANNELS];
int chn_ready;
spinlock_t slock;
/* dsp firmware version (f2255usb.bin) */
@@ -298,16 +305,10 @@ struct s2255_buffer {
struct s2255_fh {
struct s2255_dev *dev;
- const struct s2255_fmt *fmt;
- unsigned int width;
- unsigned int height;
struct videobuf_queue vb_vidq;
enum v4l2_buf_type type;
- int channel;
- /* mode below is the desired mode.
- mode in s2255_dev is the current mode that was last set */
- struct s2255_mode mode;
- int resources[MAX_CHANNELS];
+ struct s2255_channel *channel;
+ int resources;
};
/* current cypress EEPROM firmware version */
@@ -360,12 +361,11 @@ static int *s2255_debug = &debug;
static int s2255_start_readpipe(struct s2255_dev *dev);
static void s2255_stop_readpipe(struct s2255_dev *dev);
-static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn);
-static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn);
-static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
- int chn, int jpgsize);
-static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
- struct s2255_mode *mode);
+static int s2255_start_acquire(struct s2255_channel *channel);
+static int s2255_stop_acquire(struct s2255_channel *channel);
+static void s2255_fillbuff(struct s2255_channel *chn, struct s2255_buffer *buf,
+ int jpgsize);
+static int s2255_set_mode(struct s2255_channel *chan, struct s2255_mode *mode);
static int s2255_board_shutdown(struct s2255_dev *dev);
static void s2255_fwload_start(struct s2255_dev *dev, int reset);
static void s2255_destroy(struct s2255_dev *dev);
@@ -577,10 +577,11 @@ static void s2255_fwchunk_complete(struct urb *urb)
}
-static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
+static int s2255_got_frame(struct s2255_channel *channel, int jpgsize)
{
- struct s2255_dmaqueue *dma_q = &dev->vidq[chn];
+ struct s2255_dmaqueue *dma_q = &channel->vidq;
struct s2255_buffer *buf;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
unsigned long flags = 0;
int rc = 0;
spin_lock_irqsave(&dev->slock, flags);
@@ -593,12 +594,12 @@ static int s2255_got_frame(struct s2255_dev *dev, int chn, int jpgsize)
struct s2255_buffer, vb.queue);
list_del(&buf->vb.queue);
do_gettimeofday(&buf->vb.ts);
- s2255_fillbuff(dev, buf, dma_q->channel, jpgsize);
+ s2255_fillbuff(channel, buf, jpgsize);
wake_up(&buf->vb.done);
dprintk(2, "%s: [buf/i] [%p/%d]\n", __func__, buf, buf->vb.i);
unlock:
spin_unlock_irqrestore(&dev->slock, flags);
- return 0;
+ return rc;
}
static const struct s2255_fmt *format_by_fourcc(int fourcc)
@@ -621,8 +622,8 @@ static const struct s2255_fmt *format_by_fourcc(int fourcc)
* http://v4l.videotechnology.com/
*
*/
-static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
- int chn, int jpgsize)
+static void s2255_fillbuff(struct s2255_channel *channel,
+ struct s2255_buffer *buf, int jpgsize)
{
int pos = 0;
struct timeval ts;
@@ -633,12 +634,11 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
if (!vbuf)
return;
-
- last_frame = dev->last_frame[chn];
+ last_frame = channel->last_frame;
if (last_frame != -1) {
- frm = &dev->buffer[chn].frame[last_frame];
+ frm = &channel->buffer.frame[last_frame];
tmpbuf =
- (const char *)dev->buffer[chn].frame[last_frame].lpvbits;
+ (const char *)channel->buffer.frame[last_frame].lpvbits;
switch (buf->fmt->fourcc) {
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
@@ -661,7 +661,7 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
default:
printk(KERN_DEBUG "s2255: unknown format?\n");
}
- dev->last_frame[chn] = -1;
+ channel->last_frame = -1;
} else {
printk(KERN_ERR "s2255: =======no frame\n");
return;
@@ -671,7 +671,7 @@ static void s2255_fillbuff(struct s2255_dev *dev, struct s2255_buffer *buf,
(unsigned long)vbuf, pos);
/* tell v4l buffer was filled */
- buf->vb.field_count = dev->frame_count[chn] * 2;
+ buf->vb.field_count = channel->frame_count * 2;
do_gettimeofday(&ts);
buf->vb.ts = ts;
buf->vb.state = VIDEOBUF_DONE;
@@ -686,8 +686,8 @@ static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
struct s2255_fh *fh = vq->priv_data;
-
- *size = fh->width * fh->height * (fh->fmt->depth >> 3);
+ struct s2255_channel *channel = fh->channel;
+ *size = channel->width * channel->height * (channel->fmt->depth >> 3);
if (0 == *count)
*count = S2255_DEF_BUFS;
@@ -710,30 +710,31 @@ static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
enum v4l2_field field)
{
struct s2255_fh *fh = vq->priv_data;
+ struct s2255_channel *channel = fh->channel;
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
int rc;
+ int w = channel->width;
+ int h = channel->height;
dprintk(4, "%s, field=%d\n", __func__, field);
- if (fh->fmt == NULL)
+ if (channel->fmt == NULL)
return -EINVAL;
- if ((fh->width < norm_minw(&fh->dev->vdev[fh->channel])) ||
- (fh->width > norm_maxw(&fh->dev->vdev[fh->channel])) ||
- (fh->height < norm_minh(&fh->dev->vdev[fh->channel])) ||
- (fh->height > norm_maxh(&fh->dev->vdev[fh->channel]))) {
+ if ((w < norm_minw(&channel->vdev)) ||
+ (w > norm_maxw(&channel->vdev)) ||
+ (h < norm_minh(&channel->vdev)) ||
+ (h > norm_maxh(&channel->vdev))) {
dprintk(4, "invalid buffer prepare\n");
return -EINVAL;
}
-
- buf->vb.size = fh->width * fh->height * (fh->fmt->depth >> 3);
-
+ buf->vb.size = w * h * (channel->fmt->depth >> 3);
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size) {
dprintk(4, "invalid buffer prepare\n");
return -EINVAL;
}
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
+ buf->fmt = channel->fmt;
+ buf->vb.width = w;
+ buf->vb.height = h;
buf->vb.field = field;
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
@@ -753,8 +754,8 @@ static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
{
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
struct s2255_fh *fh = vq->priv_data;
- struct s2255_dev *dev = fh->dev;
- struct s2255_dmaqueue *vidq = &dev->vidq[fh->channel];
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_dmaqueue *vidq = &channel->vidq;
dprintk(1, "%s\n", __func__);
buf->vb.state = VIDEOBUF_QUEUED;
list_add_tail(&buf->vb.queue, &vidq->active);
@@ -765,7 +766,7 @@ static void buffer_release(struct videobuf_queue *vq,
{
struct s2255_buffer *buf = container_of(vb, struct s2255_buffer, vb);
struct s2255_fh *fh = vq->priv_data;
- dprintk(4, "%s %d\n", __func__, fh->channel);
+ dprintk(4, "%s %d\n", __func__, fh->channel->idx);
free_buffer(vq, buf);
}
@@ -777,40 +778,35 @@ static struct videobuf_queue_ops s2255_video_qops = {
};
-static int res_get(struct s2255_dev *dev, struct s2255_fh *fh)
+static int res_get(struct s2255_fh *fh)
{
+ struct s2255_channel *channel = fh->channel;
/* is it free? */
- mutex_lock(&dev->lock);
- if (dev->resources[fh->channel]) {
- /* no, someone else uses it */
- mutex_unlock(&dev->lock);
- return 0;
- }
+ if (channel->resources)
+ return 0; /* no, someone else uses it */
/* it's free, grab it */
- dev->resources[fh->channel] = 1;
- fh->resources[fh->channel] = 1;
+ channel->resources = 1;
+ fh->resources = 1;
dprintk(1, "s2255: res: get\n");
- mutex_unlock(&dev->lock);
return 1;
}
-static int res_locked(struct s2255_dev *dev, struct s2255_fh *fh)
+static int res_locked(struct s2255_fh *fh)
{
- return dev->resources[fh->channel];
+ return fh->channel->resources;
}
static int res_check(struct s2255_fh *fh)
{
- return fh->resources[fh->channel];
+ return fh->resources;
}
-static void res_free(struct s2255_dev *dev, struct s2255_fh *fh)
+static void res_free(struct s2255_fh *fh)
{
- mutex_lock(&dev->lock);
- dev->resources[fh->channel] = 0;
- fh->resources[fh->channel] = 0;
- mutex_unlock(&dev->lock);
+ struct s2255_channel *channel = fh->channel;
+ channel->resources = 0;
+ fh->resources = 0;
dprintk(1, "res: put\n");
}
@@ -869,12 +865,13 @@ static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
- f->fmt.pix.width = fh->width;
- f->fmt.pix.height = fh->height;
+ f->fmt.pix.width = channel->width;
+ f->fmt.pix.height = channel->height;
f->fmt.pix.field = fh->vb_vidq.field;
- f->fmt.pix.pixelformat = fh->fmt->fourcc;
- f->fmt.pix.bytesperline = f->fmt.pix.width * (fh->fmt->depth >> 3);
+ f->fmt.pix.pixelformat = channel->fmt->fourcc;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * (channel->fmt->depth >> 3);
f->fmt.pix.sizeimage = f->fmt.pix.height * f->fmt.pix.bytesperline;
return 0;
}
@@ -886,11 +883,10 @@ static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
enum v4l2_field field;
int b_any_field = 0;
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
int is_ntsc;
-
is_ntsc =
- (dev->vdev[fh->channel].current_norm & V4L2_STD_NTSC) ? 1 : 0;
+ (channel->vdev.current_norm & V4L2_STD_NTSC) ? 1 : 0;
fmt = format_by_fourcc(f->fmt.pix.pixelformat);
@@ -982,8 +978,10 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
const struct s2255_fmt *fmt;
struct videobuf_queue *q = &fh->vb_vidq;
+ struct s2255_mode mode;
int ret;
int norm;
@@ -1005,54 +1003,61 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
goto out_s_fmt;
}
- if (res_locked(fh->dev, fh)) {
+ if (res_locked(fh)) {
dprintk(1, "%s: channel busy\n", __func__);
ret = -EBUSY;
goto out_s_fmt;
}
-
- fh->fmt = fmt;
- fh->width = f->fmt.pix.width;
- fh->height = f->fmt.pix.height;
+ mode = channel->mode;
+ channel->fmt = fmt;
+ channel->width = f->fmt.pix.width;
+ channel->height = f->fmt.pix.height;
fh->vb_vidq.field = f->fmt.pix.field;
fh->type = f->type;
- norm = norm_minw(&fh->dev->vdev[fh->channel]);
- if (fh->width > norm_minw(&fh->dev->vdev[fh->channel])) {
- if (fh->height > norm_minh(&fh->dev->vdev[fh->channel])) {
- if (fh->dev->cap_parm[fh->channel].capturemode &
+ norm = norm_minw(&channel->vdev);
+ if (channel->width > norm_minw(&channel->vdev)) {
+ if (channel->height > norm_minh(&channel->vdev)) {
+ if (channel->cap_parm.capturemode &
V4L2_MODE_HIGHQUALITY)
- fh->mode.scale = SCALE_4CIFSI;
+ mode.scale = SCALE_4CIFSI;
else
- fh->mode.scale = SCALE_4CIFS;
+ mode.scale = SCALE_4CIFS;
} else
- fh->mode.scale = SCALE_2CIFS;
+ mode.scale = SCALE_2CIFS;
} else {
- fh->mode.scale = SCALE_1CIFS;
+ mode.scale = SCALE_1CIFS;
}
-
/* color mode */
- switch (fh->fmt->fourcc) {
+ switch (channel->fmt->fourcc) {
case V4L2_PIX_FMT_GREY:
- fh->mode.color &= ~MASK_COLOR;
- fh->mode.color |= COLOR_Y8;
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_Y8;
break;
case V4L2_PIX_FMT_JPEG:
- fh->mode.color &= ~MASK_COLOR;
- fh->mode.color |= COLOR_JPG;
- fh->mode.color |= (fh->dev->jc[fh->channel].quality << 8);
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_JPG;
+ mode.color |= (channel->jc.quality << 8);
break;
case V4L2_PIX_FMT_YUV422P:
- fh->mode.color &= ~MASK_COLOR;
- fh->mode.color |= COLOR_YUVPL;
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_YUVPL;
break;
case V4L2_PIX_FMT_YUYV:
case V4L2_PIX_FMT_UYVY:
default:
- fh->mode.color &= ~MASK_COLOR;
- fh->mode.color |= COLOR_YUVPK;
+ mode.color &= ~MASK_COLOR;
+ mode.color |= COLOR_YUVPK;
break;
}
+ if ((mode.color & MASK_COLOR) != (channel->mode.color & MASK_COLOR))
+ mode.restart = 1;
+ else if (mode.scale != channel->mode.scale)
+ mode.restart = 1;
+ else if (mode.format != channel->mode.format)
+ mode.restart = 1;
+ channel->mode = mode;
+ (void) s2255_set_mode(channel, &mode);
ret = 0;
out_s_fmt:
mutex_unlock(&q->vb_lock);
@@ -1092,15 +1097,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
return rc;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidioc_cgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct s2255_fh *fh = priv;
-
- return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
-}
-#endif
-
/* write to the configuration pipe, synchronously */
static int s2255_write_config(struct usb_device *udev, unsigned char *pbuf,
int size)
@@ -1197,72 +1193,68 @@ static void s2255_print_cfg(struct s2255_dev *sdev, struct s2255_mode *mode)
* When the restart parameter is set, we sleep for ONE frame to allow the
* DSP time to get the new frame
*/
-static int s2255_set_mode(struct s2255_dev *dev, unsigned long chn,
+static int s2255_set_mode(struct s2255_channel *channel,
struct s2255_mode *mode)
{
int res;
__le32 *buffer;
unsigned long chn_rev;
- mutex_lock(&dev->lock);
- chn_rev = G_chnmap[chn];
- dprintk(3, "%s channel %lu\n", __func__, chn);
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
+ dprintk(3, "%s channel: %d\n", __func__, channel->idx);
/* if JPEG, set the quality */
if ((mode->color & MASK_COLOR) == COLOR_JPG) {
mode->color &= ~MASK_COLOR;
mode->color |= COLOR_JPG;
mode->color &= ~MASK_JPG_QUALITY;
- mode->color |= (dev->jc[chn].quality << 8);
+ mode->color |= (channel->jc.quality << 8);
}
/* save the mode */
- dev->mode[chn] = *mode;
- dev->req_image_size[chn] = get_transfer_size(mode);
- dprintk(1, "%s: reqsize %ld\n", __func__, dev->req_image_size[chn]);
+ channel->mode = *mode;
+ channel->req_image_size = get_transfer_size(mode);
+ dprintk(1, "%s: reqsize %ld\n", __func__, channel->req_image_size);
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
- mutex_unlock(&dev->lock);
return -ENOMEM;
}
/* set the mode */
buffer[0] = IN_DATA_TOKEN;
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_SET_MODE;
- memcpy(&buffer[3], &dev->mode[chn], sizeof(struct s2255_mode));
- dev->setmode_ready[chn] = 0;
+ memcpy(&buffer[3], &channel->mode, sizeof(struct s2255_mode));
+ channel->setmode_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
if (debug)
s2255_print_cfg(dev, mode);
kfree(buffer);
/* wait at least 3 frames before continuing */
if (mode->restart) {
- wait_event_timeout(dev->wait_setmode[chn],
- (dev->setmode_ready[chn] != 0),
+ wait_event_timeout(channel->wait_setmode,
+ (channel->setmode_ready != 0),
msecs_to_jiffies(S2255_SETMODE_TIMEOUT));
- if (dev->setmode_ready[chn] != 1) {
+ if (channel->setmode_ready != 1) {
printk(KERN_DEBUG "s2255: no set mode response\n");
res = -EFAULT;
}
}
/* clear the restart flag */
- dev->mode[chn].restart = 0;
- mutex_unlock(&dev->lock);
- dprintk(1, "%s chn %lu, result: %d\n", __func__, chn, res);
+ channel->mode.restart = 0;
+ dprintk(1, "%s chn %d, result: %d\n", __func__, channel->idx, res);
return res;
}
-static int s2255_cmd_status(struct s2255_dev *dev, unsigned long chn,
- u32 *pstatus)
+static int s2255_cmd_status(struct s2255_channel *channel, u32 *pstatus)
{
int res;
__le32 *buffer;
u32 chn_rev;
- mutex_lock(&dev->lock);
- chn_rev = G_chnmap[chn];
- dprintk(4, "%s chan %lu\n", __func__, chn);
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
+ dprintk(4, "%s chan %d\n", __func__, channel->idx);
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
- mutex_unlock(&dev->lock);
return -ENOMEM;
}
/* form the get vid status command */
@@ -1270,19 +1262,18 @@ static int s2255_cmd_status(struct s2255_dev *dev, unsigned long chn,
buffer[1] = (__le32) cpu_to_le32(chn_rev);
buffer[2] = CMD_STATUS;
*pstatus = 0;
- dev->vidstatus_ready[chn] = 0;
+ channel->vidstatus_ready = 0;
res = s2255_write_config(dev->udev, (unsigned char *)buffer, 512);
kfree(buffer);
- wait_event_timeout(dev->wait_vidstatus[chn],
- (dev->vidstatus_ready[chn] != 0),
+ wait_event_timeout(channel->wait_vidstatus,
+ (channel->vidstatus_ready != 0),
msecs_to_jiffies(S2255_VIDSTATUS_TIMEOUT));
- if (dev->vidstatus_ready[chn] != 1) {
+ if (channel->vidstatus_ready != 1) {
printk(KERN_DEBUG "s2255: no vidstatus response\n");
res = -EFAULT;
}
- *pstatus = dev->vidstatus[chn];
+ *pstatus = channel->vidstatus;
dprintk(4, "%s, vid status %d\n", __func__, *pstatus);
- mutex_unlock(&dev->lock);
return res;
}
@@ -1291,9 +1282,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
int res;
struct s2255_fh *fh = priv;
struct s2255_dev *dev = fh->dev;
- struct s2255_mode *new_mode;
- struct s2255_mode *old_mode;
- int chn;
+ struct s2255_channel *channel = fh->channel;
int j;
dprintk(4, "%s\n", __func__);
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
@@ -1305,51 +1294,32 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
return -EINVAL;
}
- if (!res_get(dev, fh)) {
+ if (!res_get(fh)) {
s2255_dev_err(&dev->udev->dev, "stream busy\n");
return -EBUSY;
}
-
- /* send a set mode command everytime with restart.
- in case we switch resolutions or other parameters */
- chn = fh->channel;
- new_mode = &fh->mode;
- old_mode = &fh->dev->mode[chn];
-
- if ((new_mode->color & MASK_COLOR) != (old_mode->color & MASK_COLOR))
- new_mode->restart = 1;
- else if (new_mode->scale != old_mode->scale)
- new_mode->restart = 1;
- else if (new_mode->format != old_mode->format)
- new_mode->restart = 1;
-
- s2255_set_mode(dev, chn, new_mode);
- new_mode->restart = 0;
- *old_mode = *new_mode;
- dev->cur_fmt[chn] = fh->fmt;
- dev->last_frame[chn] = -1;
- dev->bad_payload[chn] = 0;
- dev->cur_frame[chn] = 0;
- dev->frame_count[chn] = 0;
+ channel->last_frame = -1;
+ channel->bad_payload = 0;
+ channel->cur_frame = 0;
+ channel->frame_count = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- dev->buffer[chn].frame[j].ulState = S2255_READ_IDLE;
- dev->buffer[chn].frame[j].cur_size = 0;
+ channel->buffer.frame[j].ulState = S2255_READ_IDLE;
+ channel->buffer.frame[j].cur_size = 0;
}
res = videobuf_streamon(&fh->vb_vidq);
if (res == 0) {
- s2255_start_acquire(dev, chn);
- dev->b_acquire[chn] = 1;
- } else {
- res_free(dev, fh);
- }
+ s2255_start_acquire(channel);
+ channel->b_acquire = 1;
+ } else
+ res_free(fh);
+
return res;
}
static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- dprintk(4, "%s\n, channel: %d", __func__, fh->channel);
+ dprintk(4, "%s\n, channel: %d", __func__, fh->channel->idx);
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
printk(KERN_ERR "invalid fh type0\n");
return -EINVAL;
@@ -1358,16 +1328,16 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
printk(KERN_ERR "invalid type i\n");
return -EINVAL;
}
- s2255_stop_acquire(dev, fh->channel);
+ s2255_stop_acquire(fh->channel);
videobuf_streamoff(&fh->vb_vidq);
- res_free(dev, fh);
+ res_free(fh);
return 0;
}
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
{
struct s2255_fh *fh = priv;
- struct s2255_mode *mode;
+ struct s2255_mode mode;
struct videobuf_queue *q = &fh->vb_vidq;
int ret = 0;
mutex_lock(&q->vb_lock);
@@ -1376,29 +1346,32 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *i)
ret = -EBUSY;
goto out_s_std;
}
- if (res_locked(fh->dev, fh)) {
+ if (res_locked(fh)) {
dprintk(1, "can't change standard after started\n");
ret = -EBUSY;
goto out_s_std;
}
- mode = &fh->mode;
+ mode = fh->channel->mode;
if (*i & V4L2_STD_NTSC) {
dprintk(4, "%s NTSC\n", __func__);
/* if changing format, reset frame decimation/intervals */
- if (mode->format != FORMAT_NTSC) {
- mode->format = FORMAT_NTSC;
- mode->fdec = FDEC_1;
+ if (mode.format != FORMAT_NTSC) {
+ mode.restart = 1;
+ mode.format = FORMAT_NTSC;
+ mode.fdec = FDEC_1;
}
} else if (*i & V4L2_STD_PAL) {
dprintk(4, "%s PAL\n", __func__);
- mode->format = FORMAT_PAL;
- if (mode->format != FORMAT_PAL) {
- mode->format = FORMAT_PAL;
- mode->fdec = FDEC_1;
+ if (mode.format != FORMAT_PAL) {
+ mode.restart = 1;
+ mode.format = FORMAT_PAL;
+ mode.fdec = FDEC_1;
}
} else {
ret = -EINVAL;
}
+ if (mode.restart)
+ s2255_set_mode(fh->channel, &mode);
out_s_std:
mutex_unlock(&q->vb_lock);
return ret;
@@ -1416,6 +1389,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
{
struct s2255_fh *fh = priv;
struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
u32 status = 0;
if (inp->index != 0)
return -EINVAL;
@@ -1424,7 +1398,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
inp->status = 0;
if (dev->dsp_fw_ver >= S2255_MIN_DSP_STATUS) {
int rc;
- rc = s2255_cmd_status(dev, fh->channel, &status);
+ rc = s2255_cmd_status(fh->channel, &status);
dprintk(4, "s2255_cmd_status rc: %d status %x\n", rc, status);
if (rc == 0)
inp->status = (status & 0x01) ? 0
@@ -1436,7 +1410,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
strlcpy(inp->name, "Composite", sizeof(inp->name));
break;
case 0x2257:
- strlcpy(inp->name, (fh->channel < 2) ? "Composite" : "S-Video",
+ strlcpy(inp->name, (channel->idx < 2) ? "Composite" : "S-Video",
sizeof(inp->name));
break;
}
@@ -1460,6 +1434,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
struct s2255_fh *fh = priv;
+ struct s2255_channel *channel = fh->channel;
struct s2255_dev *dev = fh->dev;
switch (qc->id) {
case V4L2_CID_BRIGHTNESS:
@@ -1477,7 +1452,7 @@ static int vidioc_queryctrl(struct file *file, void *priv,
case V4L2_CID_PRIVATE_COLORFILTER:
if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
return -EINVAL;
- if ((dev->pid == 0x2257) && (fh->channel > 1))
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
return -EINVAL;
strlcpy(qc->name, "Color Filter", sizeof(qc->name));
qc->type = V4L2_CTRL_TYPE_MENU;
@@ -1499,25 +1474,26 @@ static int vidioc_g_ctrl(struct file *file, void *priv,
{
struct s2255_fh *fh = priv;
struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- ctrl->value = fh->mode.bright;
+ ctrl->value = channel->mode.bright;
break;
case V4L2_CID_CONTRAST:
- ctrl->value = fh->mode.contrast;
+ ctrl->value = channel->mode.contrast;
break;
case V4L2_CID_SATURATION:
- ctrl->value = fh->mode.saturation;
+ ctrl->value = channel->mode.saturation;
break;
case V4L2_CID_HUE:
- ctrl->value = fh->mode.hue;
+ ctrl->value = channel->mode.hue;
break;
case V4L2_CID_PRIVATE_COLORFILTER:
if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
return -EINVAL;
- if ((dev->pid == 0x2257) && (fh->channel > 1))
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
return -EINVAL;
- ctrl->value = !((fh->mode.color & MASK_INPUT_TYPE) >> 16);
+ ctrl->value = !((channel->mode.color & MASK_INPUT_TYPE) >> 16);
break;
default:
return -EINVAL;
@@ -1530,41 +1506,42 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- struct s2255_mode *mode;
- mode = &fh->mode;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ struct s2255_mode mode;
+ mode = channel->mode;
dprintk(4, "%s\n", __func__);
/* update the mode to the corresponding value */
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- mode->bright = ctrl->value;
+ mode.bright = ctrl->value;
break;
case V4L2_CID_CONTRAST:
- mode->contrast = ctrl->value;
+ mode.contrast = ctrl->value;
break;
case V4L2_CID_HUE:
- mode->hue = ctrl->value;
+ mode.hue = ctrl->value;
break;
case V4L2_CID_SATURATION:
- mode->saturation = ctrl->value;
+ mode.saturation = ctrl->value;
break;
case V4L2_CID_PRIVATE_COLORFILTER:
if (dev->dsp_fw_ver < S2255_MIN_DSP_COLORFILTER)
return -EINVAL;
- if ((dev->pid == 0x2257) && (fh->channel > 1))
+ if ((dev->pid == 0x2257) && (channel->idx > 1))
return -EINVAL;
- mode->color &= ~MASK_INPUT_TYPE;
- mode->color |= ((ctrl->value ? 0 : 1) << 16);
+ mode.color &= ~MASK_INPUT_TYPE;
+ mode.color |= ((ctrl->value ? 0 : 1) << 16);
break;
default:
return -EINVAL;
}
- mode->restart = 0;
+ mode.restart = 0;
/* set mode here. Note: stream does not need restarted.
some V4L programs restart stream unnecessarily
after a s_crtl.
*/
- s2255_set_mode(dev, fh->channel, mode);
+ s2255_set_mode(fh->channel, &mode);
return 0;
}
@@ -1572,8 +1549,8 @@ static int vidioc_g_jpegcomp(struct file *file, void *priv,
struct v4l2_jpegcompression *jc)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
- *jc = dev->jc[fh->channel];
+ struct s2255_channel *channel = fh->channel;
+ *jc = channel->jc;
dprintk(2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
@@ -1582,10 +1559,10 @@ static int vidioc_s_jpegcomp(struct file *file, void *priv,
struct v4l2_jpegcompression *jc)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
if (jc->quality < 0 || jc->quality > 100)
return -EINVAL;
- dev->jc[fh->channel].quality = jc->quality;
+ channel->jc.quality = jc->quality;
dprintk(2, "%s: quality %d\n", __func__, jc->quality);
return 0;
}
@@ -1594,17 +1571,17 @@ static int vidioc_g_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
__u32 def_num, def_dem;
+ struct s2255_channel *channel = fh->channel;
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
memset(sp, 0, sizeof(struct v4l2_streamparm));
sp->parm.capture.capability = V4L2_CAP_TIMEPERFRAME;
- sp->parm.capture.capturemode = dev->cap_parm[fh->channel].capturemode;
- def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
- def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+ sp->parm.capture.capturemode = channel->cap_parm.capturemode;
+ def_num = (channel->mode.format == FORMAT_NTSC) ? 1001 : 1000;
+ def_dem = (channel->mode.format == FORMAT_NTSC) ? 30000 : 25000;
sp->parm.capture.timeperframe.denominator = def_dem;
- switch (fh->mode.fdec) {
+ switch (channel->mode.fdec) {
default:
case FDEC_1:
sp->parm.capture.timeperframe.numerator = def_num;
@@ -1630,17 +1607,19 @@ static int vidioc_s_parm(struct file *file, void *priv,
struct v4l2_streamparm *sp)
{
struct s2255_fh *fh = priv;
- struct s2255_dev *dev = fh->dev;
+ struct s2255_channel *channel = fh->channel;
+ struct s2255_mode mode;
int fdec = FDEC_1;
__u32 def_num, def_dem;
if (sp->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
+ mode = channel->mode;
/* high quality capture mode requires a stream restart */
- if (dev->cap_parm[fh->channel].capturemode
- != sp->parm.capture.capturemode && res_locked(fh->dev, fh))
+ if (channel->cap_parm.capturemode
+ != sp->parm.capture.capturemode && res_locked(fh))
return -EBUSY;
- def_num = (fh->mode.format == FORMAT_NTSC) ? 1001 : 1000;
- def_dem = (fh->mode.format == FORMAT_NTSC) ? 30000 : 25000;
+ def_num = (mode.format == FORMAT_NTSC) ? 1001 : 1000;
+ def_dem = (mode.format == FORMAT_NTSC) ? 30000 : 25000;
if (def_dem != sp->parm.capture.timeperframe.denominator)
sp->parm.capture.timeperframe.numerator = def_num;
else if (sp->parm.capture.timeperframe.numerator <= def_num)
@@ -1655,9 +1634,9 @@ static int vidioc_s_parm(struct file *file, void *priv,
sp->parm.capture.timeperframe.numerator = def_num * 5;
fdec = FDEC_5;
}
- fh->mode.fdec = fdec;
+ mode.fdec = fdec;
sp->parm.capture.timeperframe.denominator = def_dem;
- s2255_set_mode(dev, fh->channel, &fh->mode);
+ s2255_set_mode(channel, &mode);
dprintk(4, "%s capture mode, %d timeperframe %d/%d, fdec %d\n",
__func__,
sp->parm.capture.capturemode,
@@ -1707,24 +1686,13 @@ static int vidioc_enum_frameintervals(struct file *file, void *priv,
static int s2255_open(struct file *file)
{
struct video_device *vdev = video_devdata(file);
- struct s2255_dev *dev = video_drvdata(file);
+ struct s2255_channel *channel = video_drvdata(file);
+ struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
struct s2255_fh *fh;
enum v4l2_buf_type type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- int i = 0;
- int cur_channel = -1;
int state;
dprintk(1, "s2255: open called (dev=%s)\n",
video_device_node_name(vdev));
-
- for (i = 0; i < MAX_CHANNELS; i++) {
- if (&dev->vdev[i] == vdev) {
- cur_channel = i;
- break;
- }
- }
- if (i == MAX_CHANNELS)
- return -ENODEV;
-
/*
* open lock necessary to prevent multiple instances
* of v4l-conf (or other programs) from simultaneously
@@ -1806,29 +1774,26 @@ static int s2255_open(struct file *file)
file->private_data = fh;
fh->dev = dev;
fh->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fh->mode = dev->mode[cur_channel];
- fh->fmt = dev->cur_fmt[cur_channel];
- /* default 4CIF NTSC */
- fh->width = LINE_SZ_4CIFS_NTSC;
- fh->height = NUM_LINES_4CIFS_NTSC * 2;
- fh->channel = cur_channel;
- /* configure channel to default state */
- if (!dev->chn_configured[cur_channel]) {
- s2255_set_mode(dev, cur_channel, &fh->mode);
- dev->chn_configured[cur_channel] = 1;
+ fh->channel = channel;
+ if (!channel->configured) {
+ /* configure channel to default state */
+ channel->fmt = &formats[0];
+ s2255_set_mode(channel, &channel->mode);
+ channel->configured = 1;
}
dprintk(1, "%s: dev=%s type=%s\n", __func__,
video_device_node_name(vdev), v4l2_type_names[type]);
dprintk(2, "%s: fh=0x%08lx, dev=0x%08lx, vidq=0x%08lx\n", __func__,
(unsigned long)fh, (unsigned long)dev,
- (unsigned long)&dev->vidq[cur_channel]);
+ (unsigned long)&channel->vidq);
dprintk(4, "%s: list_empty active=%d\n", __func__,
- list_empty(&dev->vidq[cur_channel].active));
+ list_empty(&channel->vidq.active));
videobuf_queue_vmalloc_init(&fh->vb_vidq, &s2255_video_qops,
NULL, &dev->slock,
fh->type,
V4L2_FIELD_INTERLACED,
- sizeof(struct s2255_buffer), fh);
+ sizeof(struct s2255_buffer),
+ fh, vdev->lock);
return 0;
}
@@ -1865,6 +1830,7 @@ static void s2255_destroy(struct s2255_dev *dev)
mutex_destroy(&dev->open_lock);
mutex_destroy(&dev->lock);
usb_put_dev(dev->udev);
+ v4l2_device_unregister(&dev->v4l2_dev);
dprintk(1, "%s", __func__);
kfree(dev);
}
@@ -1874,14 +1840,15 @@ static int s2255_release(struct file *file)
struct s2255_fh *fh = file->private_data;
struct s2255_dev *dev = fh->dev;
struct video_device *vdev = video_devdata(file);
+ struct s2255_channel *channel = fh->channel;
if (!dev)
return -ENODEV;
/* turn off stream */
if (res_check(fh)) {
- if (dev->b_acquire[fh->channel])
- s2255_stop_acquire(dev, fh->channel);
+ if (channel->b_acquire)
+ s2255_stop_acquire(fh->channel);
videobuf_streamoff(&fh->vb_vidq);
- res_free(dev, fh);
+ res_free(fh);
}
videobuf_mmap_free(&fh->vb_vidq);
dprintk(1, "%s (dev=%s)\n", __func__, video_device_node_name(vdev));
@@ -1909,7 +1876,7 @@ static const struct v4l2_file_operations s2255_fops_v4l = {
.open = s2255_open,
.release = s2255_release,
.poll = s2255_poll,
- .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = s2255_mmap_v4l,
};
@@ -1933,9 +1900,6 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidioc_cgmbuf,
-#endif
.vidioc_s_jpegcomp = vidioc_s_jpegcomp,
.vidioc_g_jpegcomp = vidioc_g_jpegcomp,
.vidioc_s_parm = vidioc_s_parm,
@@ -1945,9 +1909,10 @@ static const struct v4l2_ioctl_ops s2255_ioctl_ops = {
static void s2255_video_device_release(struct video_device *vdev)
{
- struct s2255_dev *dev = video_get_drvdata(vdev);
- dprintk(4, "%s, chnls: %d \n", __func__, atomic_read(&dev->channels));
- if (atomic_dec_and_test(&dev->channels))
+ struct s2255_dev *dev = to_s2255_dev(vdev->v4l2_dev);
+ dprintk(4, "%s, chnls: %d \n", __func__,
+ atomic_read(&dev->num_channels));
+ if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
return;
}
@@ -1966,47 +1931,49 @@ static int s2255_probe_v4l(struct s2255_dev *dev)
int ret;
int i;
int cur_nr = video_nr;
+ struct s2255_channel *channel;
ret = v4l2_device_register(&dev->interface->dev, &dev->v4l2_dev);
if (ret)
return ret;
/* initialize all video 4 linux */
/* register 4 video devices */
for (i = 0; i < MAX_CHANNELS; i++) {
- INIT_LIST_HEAD(&dev->vidq[i].active);
- dev->vidq[i].dev = dev;
- dev->vidq[i].channel = i;
+ channel = &dev->channel[i];
+ INIT_LIST_HEAD(&channel->vidq.active);
+ channel->vidq.dev = dev;
/* register 4 video devices */
- memcpy(&dev->vdev[i], &template, sizeof(struct video_device));
- dev->vdev[i].v4l2_dev = &dev->v4l2_dev;
- video_set_drvdata(&dev->vdev[i], dev);
+ channel->vdev = template;
+ channel->vdev.lock = &dev->lock;
+ channel->vdev.v4l2_dev = &dev->v4l2_dev;
+ video_set_drvdata(&channel->vdev, channel);
if (video_nr == -1)
- ret = video_register_device(&dev->vdev[i],
+ ret = video_register_device(&channel->vdev,
VFL_TYPE_GRABBER,
video_nr);
else
- ret = video_register_device(&dev->vdev[i],
+ ret = video_register_device(&channel->vdev,
VFL_TYPE_GRABBER,
cur_nr + i);
+
if (ret) {
dev_err(&dev->udev->dev,
"failed to register video device!\n");
break;
}
- atomic_inc(&dev->channels);
+ atomic_inc(&dev->num_channels);
v4l2_info(&dev->v4l2_dev, "V4L2 device registered as %s\n",
- video_device_node_name(&dev->vdev[i]));
+ video_device_node_name(&channel->vdev));
}
-
printk(KERN_INFO "Sensoray 2255 V4L driver Revision: %d.%d\n",
S2255_MAJOR_VERSION,
S2255_MINOR_VERSION);
/* if no channels registered, return error and probe will fail*/
- if (atomic_read(&dev->channels) == 0) {
+ if (atomic_read(&dev->num_channels) == 0) {
v4l2_device_unregister(&dev->v4l2_dev);
return ret;
}
- if (atomic_read(&dev->channels) != MAX_CHANNELS)
+ if (atomic_read(&dev->num_channels) != MAX_CHANNELS)
printk(KERN_WARNING "s2255: Not all channels available.\n");
return 0;
}
@@ -2033,12 +2000,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
s32 idx = -1;
struct s2255_framei *frm;
unsigned char *pdata;
-
+ struct s2255_channel *channel;
dprintk(100, "buffer to user\n");
-
- idx = dev->cur_frame[dev->cc];
- frm = &dev->buffer[dev->cc].frame[idx];
-
+ channel = &dev->channel[dev->cc];
+ idx = channel->cur_frame;
+ frm = &channel->buffer.frame[idx];
if (frm->ulState == S2255_READ_IDLE) {
int jj;
unsigned int cc;
@@ -2063,16 +2029,18 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
}
/* reverse it */
dev->cc = G_chnmap[cc];
+ channel = &dev->channel[dev->cc];
payload = pdword[3];
- if (payload > dev->req_image_size[dev->cc]) {
- dev->bad_payload[dev->cc]++;
+ if (payload > channel->req_image_size) {
+ channel->bad_payload++;
/* discard the bad frame */
return -EINVAL;
}
- dev->pkt_size[dev->cc] = payload;
- dev->jpg_size[dev->cc] = pdword[4];
+ channel->pkt_size = payload;
+ channel->jpg_size = pdword[4];
break;
case S2255_MARKER_RESPONSE:
+
pdata += DEF_USB_BLOCK;
jj += DEF_USB_BLOCK;
if (pdword[1] >= MAX_CHANNELS)
@@ -2080,12 +2048,13 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
cc = G_chnmap[pdword[1]];
if (cc >= MAX_CHANNELS)
break;
+ channel = &dev->channel[cc];
switch (pdword[2]) {
case S2255_RESPONSE_SETMODE:
/* check if channel valid */
/* set mode ready */
- dev->setmode_ready[cc] = 1;
- wake_up(&dev->wait_setmode[cc]);
+ channel->setmode_ready = 1;
+ wake_up(&channel->wait_setmode);
dprintk(5, "setmode ready %d\n", cc);
break;
case S2255_RESPONSE_FW:
@@ -2099,9 +2068,9 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
wake_up(&dev->fw_data->wait_fw);
break;
case S2255_RESPONSE_STATUS:
- dev->vidstatus[cc] = pdword[3];
- dev->vidstatus_ready[cc] = 1;
- wake_up(&dev->wait_vidstatus[cc]);
+ channel->vidstatus = pdword[3];
+ channel->vidstatus_ready = 1;
+ wake_up(&channel->wait_vidstatus);
dprintk(5, "got vidstatus %x chan %d\n",
pdword[3], cc);
break;
@@ -2118,13 +2087,11 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
if (!bframe)
return -EINVAL;
}
-
-
- idx = dev->cur_frame[dev->cc];
- frm = &dev->buffer[dev->cc].frame[idx];
-
+ channel = &dev->channel[dev->cc];
+ idx = channel->cur_frame;
+ frm = &channel->buffer.frame[idx];
/* search done. now find out if should be acquiring on this channel */
- if (!dev->b_acquire[dev->cc]) {
+ if (!channel->b_acquire) {
/* we found a frame, but this channel is turned off */
frm->ulState = S2255_READ_IDLE;
return -EINVAL;
@@ -2149,30 +2116,28 @@ static int save_frame(struct s2255_dev *dev, struct s2255_pipeinfo *pipe_info)
copy_size = (pipe_info->cur_transfer_size - offset);
- size = dev->pkt_size[dev->cc] - PREFIX_SIZE;
+ size = channel->pkt_size - PREFIX_SIZE;
/* sanity check on pdest */
- if ((copy_size + frm->cur_size) < dev->req_image_size[dev->cc])
+ if ((copy_size + frm->cur_size) < channel->req_image_size)
memcpy(pdest, psrc, copy_size);
frm->cur_size += copy_size;
dprintk(4, "cur_size size %lu size %lu \n", frm->cur_size, size);
if (frm->cur_size >= size) {
-
- u32 cc = dev->cc;
dprintk(2, "****************[%d]Buffer[%d]full*************\n",
- cc, idx);
- dev->last_frame[cc] = dev->cur_frame[cc];
- dev->cur_frame[cc]++;
+ dev->cc, idx);
+ channel->last_frame = channel->cur_frame;
+ channel->cur_frame++;
/* end of system frame ring buffer, start at zero */
- if ((dev->cur_frame[cc] == SYS_FRAMES) ||
- (dev->cur_frame[cc] == dev->buffer[cc].dwFrames))
- dev->cur_frame[cc] = 0;
+ if ((channel->cur_frame == SYS_FRAMES) ||
+ (channel->cur_frame == channel->buffer.dwFrames))
+ channel->cur_frame = 0;
/* frame ready */
- if (dev->b_acquire[cc])
- s2255_got_frame(dev, cc, dev->jpg_size[cc]);
- dev->frame_count[cc]++;
+ if (channel->b_acquire)
+ s2255_got_frame(channel, channel->jpg_size);
+ channel->frame_count++;
frm->ulState = S2255_READ_IDLE;
frm->cur_size = 0;
@@ -2245,16 +2210,12 @@ static int s2255_get_fx2fw(struct s2255_dev *dev)
* Create the system ring buffer to copy frames into from the
* usb read pipe.
*/
-static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
+static int s2255_create_sys_buffers(struct s2255_channel *channel)
{
unsigned long i;
unsigned long reqsize;
dprintk(1, "create sys buffers\n");
- if (chn >= MAX_CHANNELS)
- return -1;
-
- dev->buffer[chn].dwFrames = SYS_FRAMES;
-
+ channel->buffer.dwFrames = SYS_FRAMES;
/* always allocate maximum size(PAL) for system buffers */
reqsize = SYS_FRAMES_MAXSIZE;
@@ -2263,42 +2224,40 @@ static int s2255_create_sys_buffers(struct s2255_dev *dev, unsigned long chn)
for (i = 0; i < SYS_FRAMES; i++) {
/* allocate the frames */
- dev->buffer[chn].frame[i].lpvbits = vmalloc(reqsize);
-
- dprintk(1, "valloc %p chan %lu, idx %lu, pdata %p\n",
- &dev->buffer[chn].frame[i], chn, i,
- dev->buffer[chn].frame[i].lpvbits);
- dev->buffer[chn].frame[i].size = reqsize;
- if (dev->buffer[chn].frame[i].lpvbits == NULL) {
+ channel->buffer.frame[i].lpvbits = vmalloc(reqsize);
+ dprintk(1, "valloc %p chan %d, idx %lu, pdata %p\n",
+ &channel->buffer.frame[i], channel->idx, i,
+ channel->buffer.frame[i].lpvbits);
+ channel->buffer.frame[i].size = reqsize;
+ if (channel->buffer.frame[i].lpvbits == NULL) {
printk(KERN_INFO "out of memory. using less frames\n");
- dev->buffer[chn].dwFrames = i;
+ channel->buffer.dwFrames = i;
break;
}
}
/* make sure internal states are set */
for (i = 0; i < SYS_FRAMES; i++) {
- dev->buffer[chn].frame[i].ulState = 0;
- dev->buffer[chn].frame[i].cur_size = 0;
+ channel->buffer.frame[i].ulState = 0;
+ channel->buffer.frame[i].cur_size = 0;
}
- dev->cur_frame[chn] = 0;
- dev->last_frame[chn] = -1;
+ channel->cur_frame = 0;
+ channel->last_frame = -1;
return 0;
}
-static int s2255_release_sys_buffers(struct s2255_dev *dev,
- unsigned long channel)
+static int s2255_release_sys_buffers(struct s2255_channel *channel)
{
unsigned long i;
dprintk(1, "release sys buffers\n");
for (i = 0; i < SYS_FRAMES; i++) {
- if (dev->buffer[channel].frame[i].lpvbits) {
+ if (channel->buffer.frame[i].lpvbits) {
dprintk(1, "vfree %p\n",
- dev->buffer[channel].frame[i].lpvbits);
- vfree(dev->buffer[channel].frame[i].lpvbits);
+ channel->buffer.frame[i].lpvbits);
+ vfree(channel->buffer.frame[i].lpvbits);
}
- dev->buffer[channel].frame[i].lpvbits = NULL;
+ channel->buffer.frame[i].lpvbits = NULL;
}
return 0;
}
@@ -2335,17 +2294,20 @@ static int s2255_board_init(struct s2255_dev *dev)
fw_ver & 0xff);
for (j = 0; j < MAX_CHANNELS; j++) {
- dev->b_acquire[j] = 0;
- dev->mode[j] = mode_def;
+ struct s2255_channel *channel = &dev->channel[j];
+ channel->b_acquire = 0;
+ channel->mode = mode_def;
if (dev->pid == 0x2257 && j > 1)
- dev->mode[j].color |= (1 << 16);
- dev->jc[j].quality = S2255_DEF_JPEG_QUAL;
- dev->cur_fmt[j] = &formats[0];
- dev->mode[j].restart = 1;
- dev->req_image_size[j] = get_transfer_size(&mode_def);
- dev->frame_count[j] = 0;
+ channel->mode.color |= (1 << 16);
+ channel->jc.quality = S2255_DEF_JPEG_QUAL;
+ channel->width = LINE_SZ_4CIFS_NTSC;
+ channel->height = NUM_LINES_4CIFS_NTSC * 2;
+ channel->fmt = &formats[0];
+ channel->mode.restart = 1;
+ channel->req_image_size = get_transfer_size(&mode_def);
+ channel->frame_count = 0;
/* create the system buffers */
- s2255_create_sys_buffers(dev, j);
+ s2255_create_sys_buffers(channel);
}
/* start read pipe */
s2255_start_readpipe(dev);
@@ -2359,14 +2321,12 @@ static int s2255_board_shutdown(struct s2255_dev *dev)
dprintk(1, "%s: dev: %p", __func__, dev);
for (i = 0; i < MAX_CHANNELS; i++) {
- if (dev->b_acquire[i])
- s2255_stop_acquire(dev, i);
+ if (dev->channel[i].b_acquire)
+ s2255_stop_acquire(&dev->channel[i]);
}
-
s2255_stop_readpipe(dev);
-
for (i = 0; i < MAX_CHANNELS; i++)
- s2255_release_sys_buffers(dev, i);
+ s2255_release_sys_buffers(&dev->channel[i]);
/* release transfer buffer */
kfree(dev->pipe.transfer_buffer);
return 0;
@@ -2459,29 +2419,26 @@ static int s2255_start_readpipe(struct s2255_dev *dev)
}
/* starts acquisition process */
-static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
+static int s2255_start_acquire(struct s2255_channel *channel)
{
unsigned char *buffer;
int res;
unsigned long chn_rev;
int j;
- if (chn >= MAX_CHANNELS) {
- dprintk(2, "start acquire failed, bad channel %lu\n", chn);
- return -1;
- }
- chn_rev = G_chnmap[chn];
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
return -ENOMEM;
}
- dev->last_frame[chn] = -1;
- dev->bad_payload[chn] = 0;
- dev->cur_frame[chn] = 0;
+ channel->last_frame = -1;
+ channel->bad_payload = 0;
+ channel->cur_frame = 0;
for (j = 0; j < SYS_FRAMES; j++) {
- dev->buffer[chn].frame[j].ulState = 0;
- dev->buffer[chn].frame[j].cur_size = 0;
+ channel->buffer.frame[j].ulState = 0;
+ channel->buffer.frame[j].cur_size = 0;
}
/* send the start command */
@@ -2492,21 +2449,18 @@ static int s2255_start_acquire(struct s2255_dev *dev, unsigned long chn)
if (res != 0)
dev_err(&dev->udev->dev, "CMD_START error\n");
- dprintk(2, "start acquire exit[%lu] %d \n", chn, res);
+ dprintk(2, "start acquire exit[%d] %d \n", channel->idx, res);
kfree(buffer);
return 0;
}
-static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
+static int s2255_stop_acquire(struct s2255_channel *channel)
{
unsigned char *buffer;
int res;
unsigned long chn_rev;
- if (chn >= MAX_CHANNELS) {
- dprintk(2, "stop acquire failed, bad channel %lu\n", chn);
- return -1;
- }
- chn_rev = G_chnmap[chn];
+ struct s2255_dev *dev = to_s2255_dev(channel->vdev.v4l2_dev);
+ chn_rev = G_chnmap[channel->idx];
buffer = kzalloc(512, GFP_KERNEL);
if (buffer == NULL) {
dev_err(&dev->udev->dev, "out of mem\n");
@@ -2520,8 +2474,8 @@ static int s2255_stop_acquire(struct s2255_dev *dev, unsigned long chn)
if (res != 0)
dev_err(&dev->udev->dev, "CMD_STOP error\n");
kfree(buffer);
- dev->b_acquire[chn] = 0;
- dprintk(4, "%s: chn %lu, res %d\n", __func__, chn, res);
+ channel->b_acquire = 0;
+ dprintk(4, "%s: chn %d, res %d\n", __func__, channel->idx, res);
return res;
}
@@ -2575,7 +2529,7 @@ static int s2255_probe(struct usb_interface *interface,
s2255_dev_err(&interface->dev, "out of memory\n");
return -ENOMEM;
}
- atomic_set(&dev->channels, 0);
+ atomic_set(&dev->num_channels, 0);
dev->pid = id->idProduct;
dev->fw_data = kzalloc(sizeof(struct s2255_fw), GFP_KERNEL);
if (!dev->fw_data)
@@ -2612,8 +2566,10 @@ static int s2255_probe(struct usb_interface *interface,
dev->timer.data = (unsigned long)dev->fw_data;
init_waitqueue_head(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
- init_waitqueue_head(&dev->wait_setmode[i]);
- init_waitqueue_head(&dev->wait_vidstatus[i]);
+ struct s2255_channel *channel = &dev->channel[i];
+ dev->channel[i].idx = i;
+ init_waitqueue_head(&channel->wait_setmode);
+ init_waitqueue_head(&channel->wait_vidstatus);
}
dev->fw_data->fw_urb = usb_alloc_urb(0, GFP_KERNEL);
@@ -2651,7 +2607,7 @@ static int s2255_probe(struct usb_interface *interface,
printk(KERN_INFO "s2255: f2255usb.bin out of date.\n");
if (dev->pid == 0x2257 && *pRel < S2255_MIN_DSP_COLORFILTER)
printk(KERN_WARNING "s2255: 2257 requires firmware %d"
- "or above.\n", S2255_MIN_DSP_COLORFILTER);
+ " or above.\n", S2255_MIN_DSP_COLORFILTER);
}
usb_reset_device(dev->udev);
/* load 2255 board specific */
@@ -2693,25 +2649,25 @@ static void s2255_disconnect(struct usb_interface *interface)
{
struct s2255_dev *dev = to_s2255_dev(usb_get_intfdata(interface));
int i;
- int channels = atomic_read(&dev->channels);
- v4l2_device_unregister(&dev->v4l2_dev);
+ int channels = atomic_read(&dev->num_channels);
+ mutex_lock(&dev->lock);
+ v4l2_device_disconnect(&dev->v4l2_dev);
+ mutex_unlock(&dev->lock);
/*see comments in the uvc_driver.c usb disconnect function */
- atomic_inc(&dev->channels);
+ atomic_inc(&dev->num_channels);
/* unregister each video device. */
- for (i = 0; i < channels; i++) {
- if (video_is_registered(&dev->vdev[i]))
- video_unregister_device(&dev->vdev[i]);
- }
+ for (i = 0; i < channels; i++)
+ video_unregister_device(&dev->channel[i].vdev);
/* wake up any of our timers */
atomic_set(&dev->fw_data->fw_state, S2255_FW_DISCONNECTING);
wake_up(&dev->fw_data->wait_fw);
for (i = 0; i < MAX_CHANNELS; i++) {
- dev->setmode_ready[i] = 1;
- wake_up(&dev->wait_setmode[i]);
- dev->vidstatus_ready[i] = 1;
- wake_up(&dev->wait_vidstatus[i]);
+ dev->channel[i].setmode_ready = 1;
+ wake_up(&dev->channel[i].wait_setmode);
+ dev->channel[i].vidstatus_ready = 1;
+ wake_up(&dev->channel[i].wait_vidstatus);
}
- if (atomic_dec_and_test(&dev->channels))
+ if (atomic_dec_and_test(&dev->num_channels))
s2255_destroy(dev);
dev_info(&interface->dev, "%s\n", __func__);
}
diff --git a/drivers/media/video/s5p-fimc/Makefile b/drivers/media/video/s5p-fimc/Makefile
new file mode 100644
index 000000000000..7ea1b1403b1e
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/Makefile
@@ -0,0 +1,3 @@
+
+obj-$(CONFIG_VIDEO_SAMSUNG_S5P_FIMC) := s5p-fimc.o
+s5p-fimc-y := fimc-core.o fimc-reg.o fimc-capture.o
diff --git a/drivers/media/video/s5p-fimc/fimc-capture.c b/drivers/media/video/s5p-fimc/fimc-capture.c
new file mode 100644
index 000000000000..2f500809f53d
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-capture.c
@@ -0,0 +1,864 @@
+/*
+ * Samsung S5P SoC series camera interface (camera capture) driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <linux/i2c.h>
+
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/videobuf-core.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "fimc-core.h"
+
+static struct v4l2_subdev *fimc_subdev_register(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *isp_info)
+{
+ struct i2c_adapter *i2c_adap;
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct v4l2_subdev *sd = NULL;
+
+ i2c_adap = i2c_get_adapter(isp_info->i2c_bus_num);
+ if (!i2c_adap)
+ return ERR_PTR(-ENOMEM);
+
+ sd = v4l2_i2c_new_subdev_board(&vid_cap->v4l2_dev, i2c_adap,
+ isp_info->board_info, NULL);
+ if (!sd) {
+ v4l2_err(&vid_cap->v4l2_dev, "failed to acquire subdev\n");
+ return NULL;
+ }
+
+ v4l2_info(&vid_cap->v4l2_dev, "subdevice %s registered successfuly\n",
+ isp_info->board_info->type);
+
+ return sd;
+}
+
+static void fimc_subdev_unregister(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct i2c_client *client;
+
+ if (vid_cap->input_index < 0)
+ return; /* Subdevice already released or not registered. */
+
+ if (vid_cap->sd) {
+ v4l2_device_unregister_subdev(vid_cap->sd);
+ client = v4l2_get_subdevdata(vid_cap->sd);
+ i2c_unregister_device(client);
+ i2c_put_adapter(client->adapter);
+ vid_cap->sd = NULL;
+ }
+
+ vid_cap->input_index = -1;
+}
+
+/**
+ * fimc_subdev_attach - attach v4l2_subdev to camera host interface
+ *
+ * @fimc: FIMC device information
+ * @index: index to the array of available subdevices,
+ * -1 for full array search or non negative value
+ * to select specific subdevice
+ */
+static int fimc_subdev_attach(struct fimc_dev *fimc, int index)
+{
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+ struct s3c_platform_fimc *pdata = fimc->pdata;
+ struct s3c_fimc_isp_info *isp_info;
+ struct v4l2_subdev *sd;
+ int i;
+
+ for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i) {
+ isp_info = pdata->isp_info[i];
+
+ if (!isp_info || (index >= 0 && i != index))
+ continue;
+
+ sd = fimc_subdev_register(fimc, isp_info);
+ if (sd) {
+ vid_cap->sd = sd;
+ vid_cap->input_index = i;
+
+ return 0;
+ }
+ }
+
+ vid_cap->input_index = -1;
+ vid_cap->sd = NULL;
+ v4l2_err(&vid_cap->v4l2_dev, "fimc%d: sensor attach failed\n",
+ fimc->id);
+ return -ENODEV;
+}
+
+static int fimc_isp_subdev_init(struct fimc_dev *fimc, int index)
+{
+ struct s3c_fimc_isp_info *isp_info;
+ int ret;
+
+ ret = fimc_subdev_attach(fimc, index);
+ if (ret)
+ return ret;
+
+ isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
+ ret = fimc_hw_set_camera_polarity(fimc, isp_info);
+ if (!ret) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
+ s_power, 1);
+ if (!ret)
+ return ret;
+ }
+
+ fimc_subdev_unregister(fimc);
+ err("ISP initialization failed: %d", ret);
+ return ret;
+}
+
+/*
+ * At least one buffer on the pending_buf_q queue is required.
+ * Locking: The caller holds fimc->slock spinlock.
+ */
+int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
+ struct fimc_vid_buffer *fimc_vb)
+{
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ struct fimc_ctx *ctx = cap->ctx;
+ int ret = 0;
+
+ BUG_ON(!fimc || !fimc_vb);
+
+ ret = fimc_prepare_addr(ctx, fimc_vb, &ctx->d_frame,
+ &fimc_vb->paddr);
+ if (ret)
+ return ret;
+
+ if (test_bit(ST_CAPT_STREAM, &fimc->state)) {
+ fimc_pending_queue_add(cap, fimc_vb);
+ } else {
+ /* Setup the buffer directly for processing. */
+ int buf_id = (cap->reqbufs_count == 1) ? -1 : cap->buf_index;
+ fimc_hw_set_output_addr(fimc, &fimc_vb->paddr, buf_id);
+
+ fimc_vb->index = cap->buf_index;
+ active_queue_add(cap, fimc_vb);
+
+ if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+ cap->buf_index = 0;
+ }
+ return ret;
+}
+
+static int fimc_stop_capture(struct fimc_dev *fimc)
+{
+ unsigned long flags;
+ struct fimc_vid_cap *cap;
+ int ret;
+
+ cap = &fimc->vid_cap;
+
+ if (!fimc_capture_active(fimc))
+ return 0;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ set_bit(ST_CAPT_SHUT, &fimc->state);
+ fimc_deactivate_capture(fimc);
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ wait_event_timeout(fimc->irq_queue,
+ test_bit(ST_CAPT_SHUT, &fimc->state),
+ FIMC_SHUTDOWN_TIMEOUT);
+
+ ret = v4l2_subdev_call(cap->sd, video, s_stream, 0);
+ if (ret)
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "s_stream(0) failed\n");
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ fimc->state &= ~(1 << ST_CAPT_RUN | 1 << ST_CAPT_PEND |
+ 1 << ST_CAPT_STREAM);
+
+ fimc->vid_cap.active_buf_cnt = 0;
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ dbg("state: 0x%lx", fimc->state);
+ return 0;
+}
+
+static int fimc_capture_open(struct file *file)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+ int ret = 0;
+
+ dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+ /* Return if the corresponding video mem2mem node is already opened. */
+ if (fimc_m2m_active(fimc))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (++fimc->vid_cap.refcnt == 1) {
+ ret = fimc_isp_subdev_init(fimc, -1);
+ if (ret) {
+ fimc->vid_cap.refcnt--;
+ ret = -EIO;
+ }
+ }
+
+ file->private_data = fimc->vid_cap.ctx;
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_capture_close(struct file *file)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ dbg("pid: %d, state: 0x%lx", task_pid_nr(current), fimc->state);
+
+ if (--fimc->vid_cap.refcnt == 0) {
+ fimc_stop_capture(fimc);
+
+ videobuf_stop(&fimc->vid_cap.vbq);
+ videobuf_mmap_free(&fimc->vid_cap.vbq);
+
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "releasing ISP\n");
+ v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+ fimc_subdev_unregister(fimc);
+ }
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static unsigned int fimc_capture_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return POLLERR;
+
+ ret = videobuf_poll_stream(file, &cap->vbq, wait);
+ mutex_unlock(&fimc->lock);
+
+ return ret;
+}
+
+static int fimc_capture_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_mmap_mapper(&cap->vbq, vma);
+ mutex_unlock(&fimc->lock);
+
+ return ret;
+}
+
+/* video device file operations */
+static const struct v4l2_file_operations fimc_capture_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_capture_open,
+ .release = fimc_capture_close,
+ .poll = fimc_capture_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_capture_mmap,
+};
+
+static int fimc_vidioc_querycap_capture(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING | V4L2_CAP_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+/* Synchronize formats of the camera interface input and attached sensor. */
+static int sync_capture_fmt(struct fimc_ctx *ctx)
+{
+ struct fimc_frame *frame = &ctx->s_frame;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct v4l2_mbus_framefmt *fmt = &fimc->vid_cap.fmt;
+ int ret;
+
+ fmt->width = ctx->d_frame.o_width;
+ fmt->height = ctx->d_frame.o_height;
+
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_mbus_fmt, fmt);
+ if (ret == -ENOIOCTLCMD) {
+ err("s_mbus_fmt failed");
+ return ret;
+ }
+ dbg("w: %d, h: %d, code= %d", fmt->width, fmt->height, fmt->code);
+
+ frame->fmt = find_mbus_format(fmt, FMT_FLAGS_CAM);
+ if (!frame->fmt) {
+ err("fimc source format not found\n");
+ return -EINVAL;
+ }
+
+ frame->f_width = fmt->width;
+ frame->f_height = fmt->height;
+ frame->width = fmt->width;
+ frame->height = fmt->height;
+ frame->o_width = fmt->width;
+ frame->o_height = fmt->height;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+
+ return 0;
+}
+
+static int fimc_cap_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_frame *frame;
+ struct v4l2_pix_format *pix;
+ int ret;
+
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ ret = fimc_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (fimc_capture_active(fimc)) {
+ ret = -EBUSY;
+ goto sf_unlock;
+ }
+
+ frame = &ctx->d_frame;
+
+ pix = &f->fmt.pix;
+ frame->fmt = find_format(f, FMT_FLAGS_M2M | FMT_FLAGS_CAM);
+ if (!frame->fmt) {
+ err("fimc target format not found\n");
+ ret = -EINVAL;
+ goto sf_unlock;
+ }
+
+ /* Output DMA frame pixel size and offsets. */
+ frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
+ frame->f_height = pix->height;
+ frame->width = pix->width;
+ frame->height = pix->height;
+ frame->o_width = pix->width;
+ frame->o_height = pix->height;
+ frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+
+ ret = sync_capture_fmt(ctx);
+
+ ctx->state |= (FIMC_PARAMS | FIMC_DST_FMT);
+
+sf_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct s3c_platform_fimc *pldata = ctx->fimc_dev->pdata;
+ struct s3c_fimc_isp_info *isp_info;
+
+ if (i->index >= FIMC_MAX_CAMIF_CLIENTS)
+ return -EINVAL;
+
+ isp_info = pldata->isp_info[i->index];
+ if (isp_info == NULL)
+ return -EINVAL;
+
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+ strncpy(i->name, isp_info->board_info->type, 32);
+ return 0;
+}
+
+static int fimc_cap_s_input(struct file *file, void *priv,
+ unsigned int i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct s3c_platform_fimc *pdata = fimc->pdata;
+ int ret;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (i >= FIMC_MAX_CAMIF_CLIENTS || !pdata->isp_info[i]) {
+ ret = -EINVAL;
+ goto si_unlock;
+ }
+
+ if (fimc->vid_cap.sd) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core, s_power, 0);
+ if (ret)
+ err("s_power failed: %d", ret);
+ }
+
+ /* Release the attached sensor subdevice. */
+ fimc_subdev_unregister(fimc);
+
+ ret = fimc_isp_subdev_init(fimc, i);
+
+si_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_g_input(struct file *file, void *priv,
+ unsigned int *i)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
+ *i = cap->input_index;
+ return 0;
+}
+
+static int fimc_cap_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct s3c_fimc_isp_info *isp_info;
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (fimc_capture_active(fimc) || !fimc->vid_cap.sd)
+ goto s_unlock;
+
+ if (!(ctx->state & FIMC_DST_FMT)) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "Format is not set\n");
+ ret = -EINVAL;
+ goto s_unlock;
+ }
+
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, video, s_stream, 1);
+ if (ret && ret != -ENOIOCTLCMD)
+ goto s_unlock;
+
+ ret = fimc_prepare_config(ctx, ctx->state);
+ if (ret)
+ goto s_unlock;
+
+ isp_info = fimc->pdata->isp_info[fimc->vid_cap.input_index];
+ fimc_hw_set_camera_type(fimc, isp_info);
+ fimc_hw_set_camera_source(fimc, isp_info);
+ fimc_hw_set_camera_offset(fimc, &ctx->s_frame);
+
+ if (ctx->state & FIMC_PARAMS) {
+ ret = fimc_set_scaler_info(ctx);
+ if (ret) {
+ err("Scaler setup error");
+ goto s_unlock;
+ }
+ fimc_hw_set_input_path(ctx);
+ fimc_hw_set_scaler(ctx);
+ fimc_hw_set_target_format(ctx);
+ fimc_hw_set_rotation(ctx);
+ fimc_hw_set_effect(ctx);
+ }
+
+ fimc_hw_set_output_path(ctx);
+ fimc_hw_set_out_dma(ctx);
+
+ INIT_LIST_HEAD(&fimc->vid_cap.pending_buf_q);
+ INIT_LIST_HEAD(&fimc->vid_cap.active_buf_q);
+ fimc->vid_cap.active_buf_cnt = 0;
+ fimc->vid_cap.frame_count = 0;
+ fimc->vid_cap.buf_index = fimc_hw_get_frame_index(fimc);
+
+ set_bit(ST_CAPT_PEND, &fimc->state);
+ ret = videobuf_streamon(&fimc->vid_cap.vbq);
+
+s_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ unsigned long flags;
+ int ret;
+
+ spin_lock_irqsave(&fimc->slock, flags);
+ if (!fimc_capture_running(fimc) && !fimc_capture_pending(fimc)) {
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ dbg("state: 0x%lx", fimc->state);
+ return -EINVAL;
+ }
+ spin_unlock_irqrestore(&fimc->slock, flags);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ fimc_stop_capture(fimc);
+ ret = videobuf_streamoff(&cap->vbq);
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_reqbufs(&cap->vbq, reqbufs);
+ if (!ret)
+ cap->reqbufs_count = reqbufs->count;
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_vid_cap *cap = &ctx->fimc_dev->vid_cap;
+
+ if (fimc_capture_active(ctx->fimc_dev))
+ return -EBUSY;
+
+ return videobuf_querybuf(&cap->vbq, buf);
+}
+
+static int fimc_cap_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ int ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_qbuf(&cap->vbq, buf);
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_cap_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret;
+
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+
+ ret = videobuf_dqbuf(&ctx->fimc_dev->vid_cap.vbq, buf,
+ file->f_flags & O_NONBLOCK);
+
+ mutex_unlock(&ctx->fimc_dev->lock);
+ return ret;
+}
+
+static int fimc_cap_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret = -EINVAL;
+
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+
+ /* Allow any controls but 90/270 rotation while streaming */
+ if (!fimc_capture_active(ctx->fimc_dev) ||
+ ctrl->id != V4L2_CID_ROTATE ||
+ (ctrl->value != 90 && ctrl->value != 270)) {
+ ret = check_ctrl_val(ctx, ctrl);
+ if (!ret) {
+ ret = fimc_s_ctrl(ctx, ctrl);
+ if (!ret)
+ ctx->state |= FIMC_PARAMS;
+ }
+ }
+ if (ret == -EINVAL)
+ ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+ core, s_ctrl, ctrl);
+
+ mutex_unlock(&ctx->fimc_dev->lock);
+ return ret;
+}
+
+static int fimc_cap_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = fh;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ if (cr->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ f = &ctx->s_frame;
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = f->o_width;
+ cr->bounds.height = f->o_height;
+ cr->defrect = cr->bounds;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static int fimc_cap_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ f = &ctx->s_frame;
+ cr->c.left = f->offs_h;
+ cr->c.top = f->offs_v;
+ cr->c.width = f->width;
+ cr->c.height = f->height;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static int fimc_cap_s_crop(struct file *file, void *fh,
+ struct v4l2_crop *cr)
+{
+ struct fimc_frame *f;
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = -EINVAL;
+
+ if (fimc_capture_active(fimc))
+ return -EBUSY;
+
+ ret = fimc_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ if (!(ctx->state & FIMC_DST_FMT)) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev,
+ "Capture color format not set\n");
+ goto sc_unlock;
+ }
+
+ f = &ctx->s_frame;
+ /* Check for the pixel scaling ratio when cropping input image. */
+ ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
+ if (ret) {
+ v4l2_err(&fimc->vid_cap.v4l2_dev, "Out of the scaler range");
+ } else {
+ ret = 0;
+ f->offs_h = cr->c.left;
+ f->offs_v = cr->c.top;
+ f->width = cr->c.width;
+ f->height = cr->c.height;
+ }
+
+sc_unlock:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+
+static const struct v4l2_ioctl_ops fimc_capture_ioctl_ops = {
+ .vidioc_querycap = fimc_vidioc_querycap_capture,
+
+ .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt,
+ .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt,
+ .vidioc_s_fmt_vid_cap = fimc_cap_s_fmt,
+ .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt,
+
+ .vidioc_reqbufs = fimc_cap_reqbufs,
+ .vidioc_querybuf = fimc_cap_querybuf,
+
+ .vidioc_qbuf = fimc_cap_qbuf,
+ .vidioc_dqbuf = fimc_cap_dqbuf,
+
+ .vidioc_streamon = fimc_cap_streamon,
+ .vidioc_streamoff = fimc_cap_streamoff,
+
+ .vidioc_queryctrl = fimc_vidioc_queryctrl,
+ .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
+ .vidioc_s_ctrl = fimc_cap_s_ctrl,
+
+ .vidioc_g_crop = fimc_cap_g_crop,
+ .vidioc_s_crop = fimc_cap_s_crop,
+ .vidioc_cropcap = fimc_cap_cropcap,
+
+ .vidioc_enum_input = fimc_cap_enum_input,
+ .vidioc_s_input = fimc_cap_s_input,
+ .vidioc_g_input = fimc_cap_g_input,
+};
+
+int fimc_register_capture_device(struct fimc_dev *fimc)
+{
+ struct v4l2_device *v4l2_dev = &fimc->vid_cap.v4l2_dev;
+ struct video_device *vfd;
+ struct fimc_vid_cap *vid_cap;
+ struct fimc_ctx *ctx;
+ struct v4l2_format f;
+ int ret;
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ ctx->fimc_dev = fimc;
+ ctx->in_path = FIMC_CAMERA;
+ ctx->out_path = FIMC_DMA;
+ ctx->state = FIMC_CTX_CAP;
+
+ f.fmt.pix.pixelformat = V4L2_PIX_FMT_RGB24;
+ ctx->d_frame.fmt = find_format(&f, FMT_FLAGS_M2M);
+
+ if (!v4l2_dev->name[0])
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+ "%s.capture", dev_name(&fimc->pdev->dev));
+
+ ret = v4l2_device_register(NULL, v4l2_dev);
+ if (ret)
+ goto err_info;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+ goto err_v4l2_reg;
+ }
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s:cap",
+ dev_name(&fimc->pdev->dev));
+
+ vfd->fops = &fimc_capture_fops;
+ vfd->ioctl_ops = &fimc_capture_ioctl_ops;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+ video_set_drvdata(vfd, fimc);
+
+ vid_cap = &fimc->vid_cap;
+ vid_cap->vfd = vfd;
+ vid_cap->active_buf_cnt = 0;
+ vid_cap->reqbufs_count = 0;
+ vid_cap->refcnt = 0;
+ /* The default color format for image sensor. */
+ vid_cap->fmt.code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+ INIT_LIST_HEAD(&vid_cap->pending_buf_q);
+ INIT_LIST_HEAD(&vid_cap->active_buf_q);
+ spin_lock_init(&ctx->slock);
+ vid_cap->ctx = ctx;
+
+ videobuf_queue_dma_contig_init(&vid_cap->vbq, &fimc_qops,
+ vid_cap->v4l2_dev.dev, &fimc->irqlock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct fimc_vid_buffer), (void *)ctx, NULL);
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(v4l2_dev, "Failed to register video device\n");
+ goto err_vd_reg;
+ }
+
+ v4l2_info(v4l2_dev,
+ "FIMC capture driver registered as /dev/video%d\n",
+ vfd->num);
+
+ return 0;
+
+err_vd_reg:
+ video_device_release(vfd);
+err_v4l2_reg:
+ v4l2_device_unregister(v4l2_dev);
+err_info:
+ dev_err(&fimc->pdev->dev, "failed to install\n");
+ return ret;
+}
+
+void fimc_unregister_capture_device(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *capture = &fimc->vid_cap;
+
+ if (capture->vfd)
+ video_unregister_device(capture->vfd);
+
+ kfree(capture->ctx);
+}
diff --git a/drivers/media/video/s5p-fimc/fimc-core.c b/drivers/media/video/s5p-fimc/fimc-core.c
new file mode 100644
index 000000000000..817aa66627f6
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-core.c
@@ -0,0 +1,1844 @@
+/*
+ * S5P camera interface (video postprocessor) driver
+ *
+ * Copyright (c) 2010 Samsung Electronics Co., Ltd
+ *
+ * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published
+ * by the Free Software Foundation, either version 2 of the License,
+ * or (at your option) any later version.
+ */
+
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/version.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/bug.h>
+#include <linux/interrupt.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/list.h>
+#include <linux/io.h>
+#include <linux/slab.h>
+#include <linux/clk.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf-dma-contig.h>
+
+#include "fimc-core.h"
+
+static char *fimc_clock_name[NUM_FIMC_CLOCKS] = { "sclk_fimc", "fimc" };
+
+static struct fimc_fmt fimc_formats[] = {
+ {
+ .name = "RGB565",
+ .fourcc = V4L2_PIX_FMT_RGB565X,
+ .depth = 16,
+ .color = S5P_FIMC_RGB565,
+ .buff_cnt = 1,
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .flags = FMT_FLAGS_M2M,
+ }, {
+ .name = "BGR666",
+ .fourcc = V4L2_PIX_FMT_BGR666,
+ .depth = 32,
+ .color = S5P_FIMC_RGB666,
+ .buff_cnt = 1,
+ .planes_cnt = 1,
+ .flags = FMT_FLAGS_M2M,
+ }, {
+ .name = "XRGB-8-8-8-8, 32 bpp",
+ .fourcc = V4L2_PIX_FMT_RGB32,
+ .depth = 32,
+ .color = S5P_FIMC_RGB888,
+ .buff_cnt = 1,
+ .planes_cnt = 1,
+ .flags = FMT_FLAGS_M2M,
+ }, {
+ .name = "YUV 4:2:2 packed, YCbYCr",
+ .fourcc = V4L2_PIX_FMT_YUYV,
+ .depth = 16,
+ .color = S5P_FIMC_YCBYCR422,
+ .buff_cnt = 1,
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+ }, {
+ .name = "YUV 4:2:2 packed, CbYCrY",
+ .fourcc = V4L2_PIX_FMT_UYVY,
+ .depth = 16,
+ .color = S5P_FIMC_CBYCRY422,
+ .buff_cnt = 1,
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+ }, {
+ .name = "YUV 4:2:2 packed, CrYCbY",
+ .fourcc = V4L2_PIX_FMT_VYUY,
+ .depth = 16,
+ .color = S5P_FIMC_CRYCBY422,
+ .buff_cnt = 1,
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+ }, {
+ .name = "YUV 4:2:2 packed, YCrYCb",
+ .fourcc = V4L2_PIX_FMT_YVYU,
+ .depth = 16,
+ .color = S5P_FIMC_YCRYCB422,
+ .buff_cnt = 1,
+ .planes_cnt = 1,
+ .mbus_code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .flags = FMT_FLAGS_M2M | FMT_FLAGS_CAM,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/Cb/Cr",
+ .fourcc = V4L2_PIX_FMT_YUV422P,
+ .depth = 12,
+ .color = S5P_FIMC_YCBCR422,
+ .buff_cnt = 1,
+ .planes_cnt = 3,
+ .flags = FMT_FLAGS_M2M,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV16,
+ .depth = 16,
+ .color = S5P_FIMC_YCBCR422,
+ .buff_cnt = 1,
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
+ }, {
+ .name = "YUV 4:2:2 planar, Y/CrCb",
+ .fourcc = V4L2_PIX_FMT_NV61,
+ .depth = 16,
+ .color = S5P_FIMC_RGB565,
+ .buff_cnt = 1,
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
+ }, {
+ .name = "YUV 4:2:0 planar, YCbCr",
+ .fourcc = V4L2_PIX_FMT_YUV420,
+ .depth = 12,
+ .color = S5P_FIMC_YCBCR420,
+ .buff_cnt = 1,
+ .planes_cnt = 3,
+ .flags = FMT_FLAGS_M2M,
+ }, {
+ .name = "YUV 4:2:0 planar, Y/CbCr",
+ .fourcc = V4L2_PIX_FMT_NV12,
+ .depth = 12,
+ .color = S5P_FIMC_YCBCR420,
+ .buff_cnt = 1,
+ .planes_cnt = 2,
+ .flags = FMT_FLAGS_M2M,
+ },
+};
+
+static struct v4l2_queryctrl fimc_ctrls[] = {
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal flip",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ }, {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical flip",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0,
+ }, {
+ .id = V4L2_CID_ROTATE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Rotation (CCW)",
+ .minimum = 0,
+ .maximum = 270,
+ .step = 90,
+ .default_value = 0,
+ },
+};
+
+
+static struct v4l2_queryctrl *get_ctrl(int id)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_ctrls); ++i)
+ if (id == fimc_ctrls[i].id)
+ return &fimc_ctrls[i];
+ return NULL;
+}
+
+int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f)
+{
+ if (r->width > f->width) {
+ if (f->width > (r->width * SCALER_MAX_HRATIO))
+ return -EINVAL;
+ } else {
+ if ((f->width * SCALER_MAX_HRATIO) < r->width)
+ return -EINVAL;
+ }
+
+ if (r->height > f->height) {
+ if (f->height > (r->height * SCALER_MAX_VRATIO))
+ return -EINVAL;
+ } else {
+ if ((f->height * SCALER_MAX_VRATIO) < r->height)
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int fimc_get_scaler_factor(u32 src, u32 tar, u32 *ratio, u32 *shift)
+{
+ u32 sh = 6;
+
+ if (src >= 64 * tar)
+ return -EINVAL;
+
+ while (sh--) {
+ u32 tmp = 1 << sh;
+ if (src >= tar * tmp) {
+ *shift = sh, *ratio = tmp;
+ return 0;
+ }
+ }
+
+ *shift = 0, *ratio = 1;
+
+ dbg("s: %d, t: %d, shift: %d, ratio: %d",
+ src, tar, *shift, *ratio);
+ return 0;
+}
+
+int fimc_set_scaler_info(struct fimc_ctx *ctx)
+{
+ struct fimc_scaler *sc = &ctx->scaler;
+ struct fimc_frame *s_frame = &ctx->s_frame;
+ struct fimc_frame *d_frame = &ctx->d_frame;
+ int tx, ty, sx, sy;
+ int ret;
+
+ if (ctx->rotation == 90 || ctx->rotation == 270) {
+ ty = d_frame->width;
+ tx = d_frame->height;
+ } else {
+ tx = d_frame->width;
+ ty = d_frame->height;
+ }
+ if (tx <= 0 || ty <= 0) {
+ v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
+ "invalid target size: %d x %d", tx, ty);
+ return -EINVAL;
+ }
+
+ sx = s_frame->width;
+ sy = s_frame->height;
+ if (sx <= 0 || sy <= 0) {
+ err("invalid source size: %d x %d", sx, sy);
+ return -EINVAL;
+ }
+
+ sc->real_width = sx;
+ sc->real_height = sy;
+ dbg("sx= %d, sy= %d, tx= %d, ty= %d", sx, sy, tx, ty);
+
+ ret = fimc_get_scaler_factor(sx, tx, &sc->pre_hratio, &sc->hfactor);
+ if (ret)
+ return ret;
+
+ ret = fimc_get_scaler_factor(sy, ty, &sc->pre_vratio, &sc->vfactor);
+ if (ret)
+ return ret;
+
+ sc->pre_dst_width = sx / sc->pre_hratio;
+ sc->pre_dst_height = sy / sc->pre_vratio;
+
+ sc->main_hratio = (sx << 8) / (tx << sc->hfactor);
+ sc->main_vratio = (sy << 8) / (ty << sc->vfactor);
+
+ sc->scaleup_h = (tx >= sx) ? 1 : 0;
+ sc->scaleup_v = (ty >= sy) ? 1 : 0;
+
+ /* check to see if input and output size/format differ */
+ if (s_frame->fmt->color == d_frame->fmt->color
+ && s_frame->width == d_frame->width
+ && s_frame->height == d_frame->height)
+ sc->copy_mode = 1;
+ else
+ sc->copy_mode = 0;
+
+ return 0;
+}
+
+static void fimc_capture_handler(struct fimc_dev *fimc)
+{
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ struct fimc_vid_buffer *v_buf = NULL;
+
+ if (!list_empty(&cap->active_buf_q)) {
+ v_buf = active_queue_pop(cap);
+ fimc_buf_finish(fimc, v_buf);
+ }
+
+ if (test_and_clear_bit(ST_CAPT_SHUT, &fimc->state)) {
+ wake_up(&fimc->irq_queue);
+ return;
+ }
+
+ if (!list_empty(&cap->pending_buf_q)) {
+
+ v_buf = pending_queue_pop(cap);
+ fimc_hw_set_output_addr(fimc, &v_buf->paddr, cap->buf_index);
+ v_buf->index = cap->buf_index;
+
+ dbg("hw ptr: %d, sw ptr: %d",
+ fimc_hw_get_frame_index(fimc), cap->buf_index);
+
+ spin_lock(&fimc->irqlock);
+ v_buf->vb.state = VIDEOBUF_ACTIVE;
+ spin_unlock(&fimc->irqlock);
+
+ /* Move the buffer to the capture active queue */
+ active_queue_add(cap, v_buf);
+
+ dbg("next frame: %d, done frame: %d",
+ fimc_hw_get_frame_index(fimc), v_buf->index);
+
+ if (++cap->buf_index >= FIMC_MAX_OUT_BUFS)
+ cap->buf_index = 0;
+
+ } else if (test_and_clear_bit(ST_CAPT_STREAM, &fimc->state) &&
+ cap->active_buf_cnt <= 1) {
+ fimc_deactivate_capture(fimc);
+ }
+
+ dbg("frame: %d, active_buf_cnt= %d",
+ fimc_hw_get_frame_index(fimc), cap->active_buf_cnt);
+}
+
+static irqreturn_t fimc_isr(int irq, void *priv)
+{
+ struct fimc_vid_buffer *src_buf, *dst_buf;
+ struct fimc_ctx *ctx;
+ struct fimc_dev *fimc = priv;
+
+ BUG_ON(!fimc);
+ fimc_hw_clear_irq(fimc);
+
+ spin_lock(&fimc->slock);
+
+ if (test_and_clear_bit(ST_M2M_PEND, &fimc->state)) {
+ ctx = v4l2_m2m_get_curr_priv(fimc->m2m.m2m_dev);
+ if (!ctx || !ctx->m2m_ctx)
+ goto isr_unlock;
+ src_buf = v4l2_m2m_src_buf_remove(ctx->m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->m2m_ctx);
+ if (src_buf && dst_buf) {
+ spin_lock(&fimc->irqlock);
+ src_buf->vb.state = dst_buf->vb.state = VIDEOBUF_DONE;
+ wake_up(&src_buf->vb.done);
+ wake_up(&dst_buf->vb.done);
+ spin_unlock(&fimc->irqlock);
+ v4l2_m2m_job_finish(fimc->m2m.m2m_dev, ctx->m2m_ctx);
+ }
+ goto isr_unlock;
+
+ }
+
+ if (test_bit(ST_CAPT_RUN, &fimc->state))
+ fimc_capture_handler(fimc);
+
+ if (test_and_clear_bit(ST_CAPT_PEND, &fimc->state)) {
+ set_bit(ST_CAPT_RUN, &fimc->state);
+ wake_up(&fimc->irq_queue);
+ }
+
+isr_unlock:
+ spin_unlock(&fimc->slock);
+ return IRQ_HANDLED;
+}
+
+/* The color format (planes_cnt, buff_cnt) must be already configured. */
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+ struct fimc_frame *frame, struct fimc_addr *paddr)
+{
+ int ret = 0;
+ u32 pix_size;
+
+ if (buf == NULL || frame == NULL)
+ return -EINVAL;
+
+ pix_size = frame->width * frame->height;
+
+ dbg("buff_cnt= %d, planes_cnt= %d, frame->size= %d, pix_size= %d",
+ frame->fmt->buff_cnt, frame->fmt->planes_cnt,
+ frame->size, pix_size);
+
+ if (frame->fmt->buff_cnt == 1) {
+ paddr->y = videobuf_to_dma_contig(&buf->vb);
+ switch (frame->fmt->planes_cnt) {
+ case 1:
+ paddr->cb = 0;
+ paddr->cr = 0;
+ break;
+ case 2:
+ /* decompose Y into Y/Cb */
+ paddr->cb = (u32)(paddr->y + pix_size);
+ paddr->cr = 0;
+ break;
+ case 3:
+ paddr->cb = (u32)(paddr->y + pix_size);
+ /* decompose Y into Y/Cb/Cr */
+ if (S5P_FIMC_YCBCR420 == frame->fmt->color)
+ paddr->cr = (u32)(paddr->cb
+ + (pix_size >> 2));
+ else /* 422 */
+ paddr->cr = (u32)(paddr->cb
+ + (pix_size >> 1));
+ break;
+ default:
+ return -EINVAL;
+ }
+ }
+
+ dbg("PHYS_ADDR: y= 0x%X cb= 0x%X cr= 0x%X ret= %d",
+ paddr->y, paddr->cb, paddr->cr, ret);
+
+ return ret;
+}
+
+/* Set order for 1 and 2 plane YCBCR 4:2:2 formats. */
+static void fimc_set_yuv_order(struct fimc_ctx *ctx)
+{
+ /* The one only mode supported in SoC. */
+ ctx->in_order_2p = S5P_FIMC_LSB_CRCB;
+ ctx->out_order_2p = S5P_FIMC_LSB_CRCB;
+
+ /* Set order for 1 plane input formats. */
+ switch (ctx->s_frame.fmt->color) {
+ case S5P_FIMC_YCRYCB422:
+ ctx->in_order_1p = S5P_FIMC_IN_YCRYCB;
+ break;
+ case S5P_FIMC_CBYCRY422:
+ ctx->in_order_1p = S5P_FIMC_IN_CBYCRY;
+ break;
+ case S5P_FIMC_CRYCBY422:
+ ctx->in_order_1p = S5P_FIMC_IN_CRYCBY;
+ break;
+ case S5P_FIMC_YCBYCR422:
+ default:
+ ctx->in_order_1p = S5P_FIMC_IN_YCBYCR;
+ break;
+ }
+ dbg("ctx->in_order_1p= %d", ctx->in_order_1p);
+
+ switch (ctx->d_frame.fmt->color) {
+ case S5P_FIMC_YCRYCB422:
+ ctx->out_order_1p = S5P_FIMC_OUT_YCRYCB;
+ break;
+ case S5P_FIMC_CBYCRY422:
+ ctx->out_order_1p = S5P_FIMC_OUT_CBYCRY;
+ break;
+ case S5P_FIMC_CRYCBY422:
+ ctx->out_order_1p = S5P_FIMC_OUT_CRYCBY;
+ break;
+ case S5P_FIMC_YCBYCR422:
+ default:
+ ctx->out_order_1p = S5P_FIMC_OUT_YCBYCR;
+ break;
+ }
+ dbg("ctx->out_order_1p= %d", ctx->out_order_1p);
+}
+
+static void fimc_prepare_dma_offset(struct fimc_ctx *ctx, struct fimc_frame *f)
+{
+ struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+
+ f->dma_offset.y_h = f->offs_h;
+ if (!variant->pix_hoff)
+ f->dma_offset.y_h *= (f->fmt->depth >> 3);
+
+ f->dma_offset.y_v = f->offs_v;
+
+ f->dma_offset.cb_h = f->offs_h;
+ f->dma_offset.cb_v = f->offs_v;
+
+ f->dma_offset.cr_h = f->offs_h;
+ f->dma_offset.cr_v = f->offs_v;
+
+ if (!variant->pix_hoff) {
+ if (f->fmt->planes_cnt == 3) {
+ f->dma_offset.cb_h >>= 1;
+ f->dma_offset.cr_h >>= 1;
+ }
+ if (f->fmt->color == S5P_FIMC_YCBCR420) {
+ f->dma_offset.cb_v >>= 1;
+ f->dma_offset.cr_v >>= 1;
+ }
+ }
+
+ dbg("in_offset: color= %d, y_h= %d, y_v= %d",
+ f->fmt->color, f->dma_offset.y_h, f->dma_offset.y_v);
+}
+
+/**
+ * fimc_prepare_config - check dimensions, operation and color mode
+ * and pre-calculate offset and the scaling coefficients.
+ *
+ * @ctx: hardware context information
+ * @flags: flags indicating which parameters to check/update
+ *
+ * Return: 0 if dimensions are valid or non zero otherwise.
+ */
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags)
+{
+ struct fimc_frame *s_frame, *d_frame;
+ struct fimc_vid_buffer *buf = NULL;
+ int ret = 0;
+
+ s_frame = &ctx->s_frame;
+ d_frame = &ctx->d_frame;
+
+ if (flags & FIMC_PARAMS) {
+ /* Prepare the DMA offset ratios for scaler. */
+ fimc_prepare_dma_offset(ctx, &ctx->s_frame);
+ fimc_prepare_dma_offset(ctx, &ctx->d_frame);
+
+ if (s_frame->height > (SCALER_MAX_VRATIO * d_frame->height) ||
+ s_frame->width > (SCALER_MAX_HRATIO * d_frame->width)) {
+ err("out of scaler range");
+ return -EINVAL;
+ }
+ fimc_set_yuv_order(ctx);
+ }
+
+ /* Input DMA mode is not allowed when the scaler is disabled. */
+ ctx->scaler.enabled = 1;
+
+ if (flags & FIMC_SRC_ADDR) {
+ buf = v4l2_m2m_next_src_buf(ctx->m2m_ctx);
+ ret = fimc_prepare_addr(ctx, buf, s_frame, &s_frame->paddr);
+ if (ret)
+ return ret;
+ }
+
+ if (flags & FIMC_DST_ADDR) {
+ buf = v4l2_m2m_next_dst_buf(ctx->m2m_ctx);
+ ret = fimc_prepare_addr(ctx, buf, d_frame, &d_frame->paddr);
+ }
+
+ return ret;
+}
+
+static void fimc_dma_run(void *priv)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc;
+ unsigned long flags;
+ u32 ret;
+
+ if (WARN(!ctx, "null hardware context\n"))
+ return;
+
+ fimc = ctx->fimc_dev;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ set_bit(ST_M2M_PEND, &fimc->state);
+
+ ctx->state |= (FIMC_SRC_ADDR | FIMC_DST_ADDR);
+ ret = fimc_prepare_config(ctx, ctx->state);
+ if (ret) {
+ err("Wrong parameters");
+ goto dma_unlock;
+ }
+ /* Reconfigure hardware if the context has changed. */
+ if (fimc->m2m.ctx != ctx) {
+ ctx->state |= FIMC_PARAMS;
+ fimc->m2m.ctx = ctx;
+ }
+
+ fimc_hw_set_input_addr(fimc, &ctx->s_frame.paddr);
+
+ if (ctx->state & FIMC_PARAMS) {
+ fimc_hw_set_input_path(ctx);
+ fimc_hw_set_in_dma(ctx);
+ if (fimc_set_scaler_info(ctx)) {
+ err("Scaler setup error");
+ goto dma_unlock;
+ }
+ fimc_hw_set_scaler(ctx);
+ fimc_hw_set_target_format(ctx);
+ fimc_hw_set_rotation(ctx);
+ fimc_hw_set_effect(ctx);
+ }
+
+ fimc_hw_set_output_path(ctx);
+ if (ctx->state & (FIMC_DST_ADDR | FIMC_PARAMS))
+ fimc_hw_set_output_addr(fimc, &ctx->d_frame.paddr, -1);
+
+ if (ctx->state & FIMC_PARAMS)
+ fimc_hw_set_out_dma(ctx);
+
+ fimc_activate_capture(ctx);
+
+ ctx->state &= (FIMC_CTX_M2M | FIMC_CTX_CAP);
+ fimc_hw_activate_input_dma(fimc, true);
+
+dma_unlock:
+ spin_unlock_irqrestore(&ctx->slock, flags);
+}
+
+static void fimc_job_abort(void *priv)
+{
+ /* Nothing done in job_abort. */
+}
+
+static void fimc_buf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int fimc_buf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct fimc_ctx *ctx = vq->priv_data;
+ struct fimc_frame *frame;
+
+ frame = ctx_get_frame(ctx, vq->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ *size = (frame->width * frame->height * frame->fmt->depth) >> 3;
+ if (0 == *count)
+ *count = 1;
+ return 0;
+}
+
+static int fimc_buf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct fimc_ctx *ctx = vq->priv_data;
+ struct v4l2_device *v4l2_dev = &ctx->fimc_dev->m2m.v4l2_dev;
+ struct fimc_frame *frame;
+ int ret;
+
+ frame = ctx_get_frame(ctx, vq->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (vb->baddr) {
+ if (vb->bsize < frame->size) {
+ v4l2_err(v4l2_dev,
+ "User-provided buffer too small (%d < %d)\n",
+ vb->bsize, frame->size);
+ WARN_ON(1);
+ return -EINVAL;
+ }
+ } else if (vb->state != VIDEOBUF_NEEDS_INIT
+ && vb->bsize < frame->size) {
+ return -EINVAL;
+ }
+
+ vb->width = frame->width;
+ vb->height = frame->height;
+ vb->bytesperline = (frame->width * frame->fmt->depth) >> 3;
+ vb->size = frame->size;
+ vb->field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == vb->state) {
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret) {
+ v4l2_err(v4l2_dev, "Iolock failed\n");
+ fimc_buf_release(vq, vb);
+ return ret;
+ }
+ }
+ vb->state = VIDEOBUF_PREPARED;
+
+ return 0;
+}
+
+static void fimc_buf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct fimc_ctx *ctx = vq->priv_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_vid_cap *cap = &fimc->vid_cap;
+ unsigned long flags;
+
+ dbg("ctx: %p, ctx->state: 0x%x", ctx, ctx->state);
+
+ if ((ctx->state & FIMC_CTX_M2M) && ctx->m2m_ctx) {
+ v4l2_m2m_buf_queue(ctx->m2m_ctx, vq, vb);
+ } else if (ctx->state & FIMC_CTX_CAP) {
+ spin_lock_irqsave(&fimc->slock, flags);
+ fimc_vid_cap_buf_queue(fimc, (struct fimc_vid_buffer *)vb);
+
+ dbg("fimc->cap.active_buf_cnt: %d",
+ fimc->vid_cap.active_buf_cnt);
+
+ if (cap->active_buf_cnt >= cap->reqbufs_count ||
+ cap->active_buf_cnt >= FIMC_MAX_OUT_BUFS) {
+ if (!test_and_set_bit(ST_CAPT_STREAM, &fimc->state))
+ fimc_activate_capture(ctx);
+ }
+ spin_unlock_irqrestore(&fimc->slock, flags);
+ }
+}
+
+struct videobuf_queue_ops fimc_qops = {
+ .buf_setup = fimc_buf_setup,
+ .buf_prepare = fimc_buf_prepare,
+ .buf_queue = fimc_buf_queue,
+ .buf_release = fimc_buf_release,
+};
+
+static int fimc_m2m_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ strncpy(cap->driver, fimc->pdev->name, sizeof(cap->driver) - 1);
+ strncpy(cap->card, fimc->pdev->name, sizeof(cap->card) - 1);
+ cap->bus_info[0] = 0;
+ cap->version = KERNEL_VERSION(1, 0, 0);
+ cap->capabilities = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_VIDEO_OUTPUT;
+
+ return 0;
+}
+
+int fimc_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ struct fimc_fmt *fmt;
+
+ if (f->index >= ARRAY_SIZE(fimc_formats))
+ return -EINVAL;
+
+ fmt = &fimc_formats[f->index];
+ strncpy(f->description, fmt->name, sizeof(f->description) - 1);
+ f->pixelformat = fmt->fourcc;
+
+ return 0;
+}
+
+int fimc_vidioc_g_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_frame *frame;
+
+ frame = ctx_get_frame(ctx, f->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ f->fmt.pix.width = frame->width;
+ f->fmt.pix.height = frame->height;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.pixelformat = frame->fmt->fourcc;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask)
+{
+ struct fimc_fmt *fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
+ fmt = &fimc_formats[i];
+ if (fmt->fourcc == f->fmt.pix.pixelformat &&
+ (fmt->flags & mask))
+ break;
+ }
+
+ return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
+}
+
+struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
+ unsigned int mask)
+{
+ struct fimc_fmt *fmt;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(fimc_formats); ++i) {
+ fmt = &fimc_formats[i];
+ if (fmt->mbus_code == f->code && (fmt->flags & mask))
+ break;
+ }
+
+ return (i == ARRAY_SIZE(fimc_formats)) ? NULL : fmt;
+}
+
+
+int fimc_vidioc_try_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct samsung_fimc_variant *variant = fimc->variant;
+ struct v4l2_pix_format *pix = &f->fmt.pix;
+ struct fimc_fmt *fmt;
+ u32 max_width, mod_x, mod_y, mask;
+ int ret = -EINVAL, is_output = 0;
+
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ if (ctx->state & FIMC_CTX_CAP)
+ return -EINVAL;
+ is_output = 1;
+ } else if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ return -EINVAL;
+ }
+
+ dbg("w: %d, h: %d, bpl: %d",
+ pix->width, pix->height, pix->bytesperline);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ mask = is_output ? FMT_FLAGS_M2M : FMT_FLAGS_M2M | FMT_FLAGS_CAM;
+ fmt = find_format(f, mask);
+ if (!fmt) {
+ v4l2_err(&fimc->m2m.v4l2_dev, "Fourcc format (0x%X) invalid.\n",
+ pix->pixelformat);
+ goto tf_out;
+ }
+
+ if (pix->field == V4L2_FIELD_ANY)
+ pix->field = V4L2_FIELD_NONE;
+ else if (V4L2_FIELD_NONE != pix->field)
+ goto tf_out;
+
+ if (is_output) {
+ max_width = variant->pix_limit->scaler_dis_w;
+ mod_x = ffs(variant->min_inp_pixsize) - 1;
+ } else {
+ max_width = variant->pix_limit->out_rot_dis_w;
+ mod_x = ffs(variant->min_out_pixsize) - 1;
+ }
+
+ if (tiled_fmt(fmt)) {
+ mod_x = 6; /* 64 x 32 pixels tile */
+ mod_y = 5;
+ } else {
+ if (fimc->id == 1 && fimc->variant->pix_hoff)
+ mod_y = fimc_fmt_is_rgb(fmt->color) ? 0 : 1;
+ else
+ mod_y = mod_x;
+ }
+
+ dbg("mod_x: %d, mod_y: %d, max_w: %d", mod_x, mod_y, max_width);
+
+ v4l_bound_align_image(&pix->width, 16, max_width, mod_x,
+ &pix->height, 8, variant->pix_limit->scaler_dis_w, mod_y, 0);
+
+ if (pix->bytesperline == 0 ||
+ (pix->bytesperline * 8 / fmt->depth) > pix->width)
+ pix->bytesperline = (pix->width * fmt->depth) >> 3;
+
+ if (pix->sizeimage == 0)
+ pix->sizeimage = pix->height * pix->bytesperline;
+
+ dbg("w: %d, h: %d, bpl: %d, depth: %d",
+ pix->width, pix->height, pix->bytesperline, fmt->depth);
+
+ ret = 0;
+
+tf_out:
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_m2m_s_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct v4l2_device *v4l2_dev = &fimc->m2m.v4l2_dev;
+ struct videobuf_queue *vq;
+ struct fimc_frame *frame;
+ struct v4l2_pix_format *pix;
+ unsigned long flags;
+ int ret = 0;
+
+ ret = fimc_vidioc_try_fmt(file, priv, f);
+ if (ret)
+ return ret;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ vq = v4l2_m2m_get_vq(ctx->m2m_ctx, f->type);
+ mutex_lock(&vq->vb_lock);
+
+ if (videobuf_queue_is_busy(vq)) {
+ v4l2_err(v4l2_dev, "%s: queue (%d) busy\n", __func__, f->type);
+ ret = -EBUSY;
+ goto sf_out;
+ }
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ if (f->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) {
+ frame = &ctx->s_frame;
+ ctx->state |= FIMC_SRC_FMT;
+ } else if (f->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ frame = &ctx->d_frame;
+ ctx->state |= FIMC_DST_FMT;
+ } else {
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
+ "Wrong buffer/video queue type (%d)\n", f->type);
+ ret = -EINVAL;
+ goto sf_out;
+ }
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ pix = &f->fmt.pix;
+ frame->fmt = find_format(f, FMT_FLAGS_M2M);
+ if (!frame->fmt) {
+ ret = -EINVAL;
+ goto sf_out;
+ }
+
+ frame->f_width = pix->bytesperline * 8 / frame->fmt->depth;
+ frame->f_height = pix->height;
+ frame->width = pix->width;
+ frame->height = pix->height;
+ frame->o_width = pix->width;
+ frame->o_height = pix->height;
+ frame->offs_h = 0;
+ frame->offs_v = 0;
+ frame->size = (pix->width * pix->height * frame->fmt->depth) >> 3;
+ vq->field = pix->field;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ ctx->state |= FIMC_PARAMS;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ dbg("f_w: %d, f_h: %d", frame->f_width, frame->f_height);
+
+sf_out:
+ mutex_unlock(&vq->vb_lock);
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+static int fimc_m2m_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *reqbufs)
+{
+ struct fimc_ctx *ctx = priv;
+ return v4l2_m2m_reqbufs(file, ctx->m2m_ctx, reqbufs);
+}
+
+static int fimc_m2m_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ return v4l2_m2m_querybuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_qbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+
+ return v4l2_m2m_qbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct fimc_ctx *ctx = priv;
+ return v4l2_m2m_dqbuf(file, ctx->m2m_ctx, buf);
+}
+
+static int fimc_m2m_streamon(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_ctx *ctx = priv;
+ return v4l2_m2m_streamon(file, ctx->m2m_ctx, type);
+}
+
+static int fimc_m2m_streamoff(struct file *file, void *priv,
+ enum v4l2_buf_type type)
+{
+ struct fimc_ctx *ctx = priv;
+ return v4l2_m2m_streamoff(file, ctx->m2m_ctx, type);
+}
+
+int fimc_vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct fimc_ctx *ctx = priv;
+ struct v4l2_queryctrl *c;
+ int ret = -EINVAL;
+
+ c = get_ctrl(qc->id);
+ if (c) {
+ *qc = *c;
+ return 0;
+ }
+
+ if (ctx->state & FIMC_CTX_CAP) {
+ if (mutex_lock_interruptible(&ctx->fimc_dev->lock))
+ return -ERESTARTSYS;
+ ret = v4l2_subdev_call(ctx->fimc_dev->vid_cap.sd,
+ core, queryctrl, qc);
+ mutex_unlock(&ctx->fimc_dev->lock);
+ }
+ return ret;
+}
+
+int fimc_vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ int ret = 0;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ ctrl->value = (FLIP_X_AXIS & ctx->flip) ? 1 : 0;
+ break;
+ case V4L2_CID_VFLIP:
+ ctrl->value = (FLIP_Y_AXIS & ctx->flip) ? 1 : 0;
+ break;
+ case V4L2_CID_ROTATE:
+ ctrl->value = ctx->rotation;
+ break;
+ default:
+ if (ctx->state & FIMC_CTX_CAP) {
+ ret = v4l2_subdev_call(fimc->vid_cap.sd, core,
+ g_ctrl, ctrl);
+ } else {
+ v4l2_err(&fimc->m2m.v4l2_dev,
+ "Invalid control\n");
+ ret = -EINVAL;
+ }
+ }
+ dbg("ctrl->value= %d", ctrl->value);
+
+ mutex_unlock(&fimc->lock);
+ return ret;
+}
+
+int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct v4l2_queryctrl *c;
+ c = get_ctrl(ctrl->id);
+ if (!c)
+ return -EINVAL;
+
+ if (ctrl->value < c->minimum || ctrl->value > c->maximum
+ || (c->step != 0 && ctrl->value % c->step != 0)) {
+ v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
+ "Invalid control value\n");
+ return -ERANGE;
+ }
+
+ return 0;
+}
+
+int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl)
+{
+ struct samsung_fimc_variant *variant = ctx->fimc_dev->variant;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ unsigned long flags;
+
+ if (ctx->rotation != 0 &&
+ (ctrl->id == V4L2_CID_HFLIP || ctrl->id == V4L2_CID_VFLIP)) {
+ v4l2_err(&fimc->m2m.v4l2_dev,
+ "Simultaneous flip and rotation is not supported\n");
+ return -EINVAL;
+ }
+
+ spin_lock_irqsave(&ctx->slock, flags);
+
+ switch (ctrl->id) {
+ case V4L2_CID_HFLIP:
+ if (ctrl->value)
+ ctx->flip |= FLIP_X_AXIS;
+ else
+ ctx->flip &= ~FLIP_X_AXIS;
+ break;
+
+ case V4L2_CID_VFLIP:
+ if (ctrl->value)
+ ctx->flip |= FLIP_Y_AXIS;
+ else
+ ctx->flip &= ~FLIP_Y_AXIS;
+ break;
+
+ case V4L2_CID_ROTATE:
+ /* Check for the output rotator availability */
+ if ((ctrl->value == 90 || ctrl->value == 270) &&
+ (ctx->in_path == FIMC_DMA && !variant->has_out_rot)) {
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ return -EINVAL;
+ } else {
+ ctx->rotation = ctrl->value;
+ }
+ break;
+
+ default:
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ v4l2_err(&fimc->m2m.v4l2_dev, "Invalid control\n");
+ return -EINVAL;
+ }
+ ctx->state |= FIMC_PARAMS;
+ spin_unlock_irqrestore(&ctx->slock, flags);
+
+ return 0;
+}
+
+static int fimc_m2m_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct fimc_ctx *ctx = priv;
+ int ret = 0;
+
+ ret = check_ctrl_val(ctx, ctrl);
+ if (ret)
+ return ret;
+
+ ret = fimc_s_ctrl(ctx, ctrl);
+ return 0;
+}
+
+static int fimc_m2m_cropcap(struct file *file, void *fh,
+ struct v4l2_cropcap *cr)
+{
+ struct fimc_frame *frame;
+ struct fimc_ctx *ctx = fh;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ cr->bounds.left = 0;
+ cr->bounds.top = 0;
+ cr->bounds.width = frame->f_width;
+ cr->bounds.height = frame->f_height;
+ cr->defrect = cr->bounds;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static int fimc_m2m_g_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_frame *frame;
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ frame = ctx_get_frame(ctx, cr->type);
+ if (IS_ERR(frame))
+ return PTR_ERR(frame);
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ cr->c.left = frame->offs_h;
+ cr->c.top = frame->offs_v;
+ cr->c.width = frame->width;
+ cr->c.height = frame->height;
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr)
+{
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ struct fimc_frame *f;
+ u32 min_size, halign;
+
+ if (cr->c.top < 0 || cr->c.left < 0) {
+ v4l2_err(&fimc->m2m.v4l2_dev,
+ "doesn't support negative values for top & left\n");
+ return -EINVAL;
+ }
+
+ if (cr->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ f = (ctx->state & FIMC_CTX_CAP) ? &ctx->s_frame : &ctx->d_frame;
+ else if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
+ ctx->state & FIMC_CTX_M2M)
+ f = &ctx->s_frame;
+ else
+ return -EINVAL;
+
+ min_size = (f == &ctx->s_frame) ?
+ fimc->variant->min_inp_pixsize : fimc->variant->min_out_pixsize;
+
+ if (ctx->state & FIMC_CTX_M2M) {
+ if (fimc->id == 1 && fimc->variant->pix_hoff)
+ halign = fimc_fmt_is_rgb(f->fmt->color) ? 0 : 1;
+ else
+ halign = ffs(min_size) - 1;
+ /* there are more strict aligment requirements at camera interface */
+ } else {
+ min_size = 16;
+ halign = 4;
+ }
+
+ v4l_bound_align_image(&cr->c.width, min_size, f->o_width,
+ ffs(min_size) - 1,
+ &cr->c.height, min_size, f->o_height,
+ halign, 64/(ALIGN(f->fmt->depth, 8)));
+
+ /* adjust left/top if cropping rectangle is out of bounds */
+ if (cr->c.left + cr->c.width > f->o_width)
+ cr->c.left = f->o_width - cr->c.width;
+ if (cr->c.top + cr->c.height > f->o_height)
+ cr->c.top = f->o_height - cr->c.height;
+
+ cr->c.left = round_down(cr->c.left, min_size);
+ cr->c.top = round_down(cr->c.top,
+ ctx->state & FIMC_CTX_M2M ? 8 : 16);
+
+ dbg("l:%d, t:%d, w:%d, h:%d, f_w: %d, f_h: %d",
+ cr->c.left, cr->c.top, cr->c.width, cr->c.height,
+ f->f_width, f->f_height);
+
+ return 0;
+}
+
+
+static int fimc_m2m_s_crop(struct file *file, void *fh, struct v4l2_crop *cr)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+ unsigned long flags;
+ struct fimc_frame *f;
+ int ret;
+
+ ret = fimc_try_crop(ctx, cr);
+ if (ret)
+ return ret;
+
+ f = (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT) ?
+ &ctx->s_frame : &ctx->d_frame;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ spin_lock_irqsave(&ctx->slock, flags);
+ if (~ctx->state & (FIMC_SRC_FMT | FIMC_DST_FMT)) {
+ /* Check to see if scaling ratio is within supported range */
+ if (cr->type == V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ ret = fimc_check_scaler_ratio(&cr->c, &ctx->d_frame);
+ else
+ ret = fimc_check_scaler_ratio(&cr->c, &ctx->s_frame);
+ if (ret) {
+ v4l2_err(&fimc->m2m.v4l2_dev, "Out of scaler range");
+ ret = -EINVAL;
+ goto scr_unlock;
+ }
+ }
+ ctx->state |= FIMC_PARAMS;
+
+ f->offs_h = cr->c.left;
+ f->offs_v = cr->c.top;
+ f->width = cr->c.width;
+ f->height = cr->c.height;
+
+scr_unlock:
+ spin_unlock_irqrestore(&ctx->slock, flags);
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops fimc_m2m_ioctl_ops = {
+ .vidioc_querycap = fimc_m2m_querycap,
+
+ .vidioc_enum_fmt_vid_cap = fimc_vidioc_enum_fmt,
+ .vidioc_enum_fmt_vid_out = fimc_vidioc_enum_fmt,
+
+ .vidioc_g_fmt_vid_cap = fimc_vidioc_g_fmt,
+ .vidioc_g_fmt_vid_out = fimc_vidioc_g_fmt,
+
+ .vidioc_try_fmt_vid_cap = fimc_vidioc_try_fmt,
+ .vidioc_try_fmt_vid_out = fimc_vidioc_try_fmt,
+
+ .vidioc_s_fmt_vid_cap = fimc_m2m_s_fmt,
+ .vidioc_s_fmt_vid_out = fimc_m2m_s_fmt,
+
+ .vidioc_reqbufs = fimc_m2m_reqbufs,
+ .vidioc_querybuf = fimc_m2m_querybuf,
+
+ .vidioc_qbuf = fimc_m2m_qbuf,
+ .vidioc_dqbuf = fimc_m2m_dqbuf,
+
+ .vidioc_streamon = fimc_m2m_streamon,
+ .vidioc_streamoff = fimc_m2m_streamoff,
+
+ .vidioc_queryctrl = fimc_vidioc_queryctrl,
+ .vidioc_g_ctrl = fimc_vidioc_g_ctrl,
+ .vidioc_s_ctrl = fimc_m2m_s_ctrl,
+
+ .vidioc_g_crop = fimc_m2m_g_crop,
+ .vidioc_s_crop = fimc_m2m_s_crop,
+ .vidioc_cropcap = fimc_m2m_cropcap
+
+};
+
+static void queue_init(void *priv, struct videobuf_queue *vq,
+ enum v4l2_buf_type type)
+{
+ struct fimc_ctx *ctx = priv;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ videobuf_queue_dma_contig_init(vq, &fimc_qops,
+ &fimc->pdev->dev,
+ &fimc->irqlock, type, V4L2_FIELD_NONE,
+ sizeof(struct fimc_vid_buffer), priv, NULL);
+}
+
+static int fimc_m2m_open(struct file *file)
+{
+ struct fimc_dev *fimc = video_drvdata(file);
+ struct fimc_ctx *ctx = NULL;
+ int err = 0;
+
+ if (mutex_lock_interruptible(&fimc->lock))
+ return -ERESTARTSYS;
+
+ dbg("pid: %d, state: 0x%lx, refcnt: %d",
+ task_pid_nr(current), fimc->state, fimc->vid_cap.refcnt);
+
+ /*
+ * Return if the corresponding video capture node
+ * is already opened.
+ */
+ if (fimc->vid_cap.refcnt > 0) {
+ err = -EBUSY;
+ goto err_unlock;
+ }
+
+ fimc->m2m.refcnt++;
+ set_bit(ST_OUTDMA_RUN, &fimc->state);
+
+ ctx = kzalloc(sizeof *ctx, GFP_KERNEL);
+ if (!ctx) {
+ err = -ENOMEM;
+ goto err_unlock;
+ }
+
+ file->private_data = ctx;
+ ctx->fimc_dev = fimc;
+ /* Default color format */
+ ctx->s_frame.fmt = &fimc_formats[0];
+ ctx->d_frame.fmt = &fimc_formats[0];
+ /* Setup the device context for mem2mem mode. */
+ ctx->state = FIMC_CTX_M2M;
+ ctx->flags = 0;
+ ctx->in_path = FIMC_DMA;
+ ctx->out_path = FIMC_DMA;
+ spin_lock_init(&ctx->slock);
+
+ ctx->m2m_ctx = v4l2_m2m_ctx_init(ctx, fimc->m2m.m2m_dev, queue_init);
+ if (IS_ERR(ctx->m2m_ctx)) {
+ err = PTR_ERR(ctx->m2m_ctx);
+ kfree(ctx);
+ }
+
+err_unlock:
+ mutex_unlock(&fimc->lock);
+ return err;
+}
+
+static int fimc_m2m_release(struct file *file)
+{
+ struct fimc_ctx *ctx = file->private_data;
+ struct fimc_dev *fimc = ctx->fimc_dev;
+
+ mutex_lock(&fimc->lock);
+
+ dbg("pid: %d, state: 0x%lx, refcnt= %d",
+ task_pid_nr(current), fimc->state, fimc->m2m.refcnt);
+
+ v4l2_m2m_ctx_release(ctx->m2m_ctx);
+ kfree(ctx);
+ if (--fimc->m2m.refcnt <= 0)
+ clear_bit(ST_OUTDMA_RUN, &fimc->state);
+
+ mutex_unlock(&fimc->lock);
+ return 0;
+}
+
+static unsigned int fimc_m2m_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct fimc_ctx *ctx = file->private_data;
+
+ return v4l2_m2m_poll(file, ctx->m2m_ctx, wait);
+}
+
+
+static int fimc_m2m_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct fimc_ctx *ctx = file->private_data;
+
+ return v4l2_m2m_mmap(file, ctx->m2m_ctx, vma);
+}
+
+static const struct v4l2_file_operations fimc_m2m_fops = {
+ .owner = THIS_MODULE,
+ .open = fimc_m2m_open,
+ .release = fimc_m2m_release,
+ .poll = fimc_m2m_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = fimc_m2m_mmap,
+};
+
+static struct v4l2_m2m_ops m2m_ops = {
+ .device_run = fimc_dma_run,
+ .job_abort = fimc_job_abort,
+};
+
+
+static int fimc_register_m2m_device(struct fimc_dev *fimc)
+{
+ struct video_device *vfd;
+ struct platform_device *pdev;
+ struct v4l2_device *v4l2_dev;
+ int ret = 0;
+
+ if (!fimc)
+ return -ENODEV;
+
+ pdev = fimc->pdev;
+ v4l2_dev = &fimc->m2m.v4l2_dev;
+
+ /* set name if it is empty */
+ if (!v4l2_dev->name[0])
+ snprintf(v4l2_dev->name, sizeof(v4l2_dev->name),
+ "%s.m2m", dev_name(&pdev->dev));
+
+ ret = v4l2_device_register(&pdev->dev, v4l2_dev);
+ if (ret)
+ goto err_m2m_r1;
+
+ vfd = video_device_alloc();
+ if (!vfd) {
+ v4l2_err(v4l2_dev, "Failed to allocate video device\n");
+ goto err_m2m_r1;
+ }
+
+ vfd->fops = &fimc_m2m_fops;
+ vfd->ioctl_ops = &fimc_m2m_ioctl_ops;
+ vfd->minor = -1;
+ vfd->release = video_device_release;
+
+ snprintf(vfd->name, sizeof(vfd->name), "%s:m2m", dev_name(&pdev->dev));
+
+ video_set_drvdata(vfd, fimc);
+ platform_set_drvdata(pdev, fimc);
+
+ fimc->m2m.vfd = vfd;
+ fimc->m2m.m2m_dev = v4l2_m2m_init(&m2m_ops);
+ if (IS_ERR(fimc->m2m.m2m_dev)) {
+ v4l2_err(v4l2_dev, "failed to initialize v4l2-m2m device\n");
+ ret = PTR_ERR(fimc->m2m.m2m_dev);
+ goto err_m2m_r2;
+ }
+
+ ret = video_register_device(vfd, VFL_TYPE_GRABBER, -1);
+ if (ret) {
+ v4l2_err(v4l2_dev,
+ "%s(): failed to register video device\n", __func__);
+ goto err_m2m_r3;
+ }
+ v4l2_info(v4l2_dev,
+ "FIMC m2m driver registered as /dev/video%d\n", vfd->num);
+
+ return 0;
+
+err_m2m_r3:
+ v4l2_m2m_release(fimc->m2m.m2m_dev);
+err_m2m_r2:
+ video_device_release(fimc->m2m.vfd);
+err_m2m_r1:
+ v4l2_device_unregister(v4l2_dev);
+
+ return ret;
+}
+
+static void fimc_unregister_m2m_device(struct fimc_dev *fimc)
+{
+ if (fimc) {
+ v4l2_m2m_release(fimc->m2m.m2m_dev);
+ video_unregister_device(fimc->m2m.vfd);
+
+ v4l2_device_unregister(&fimc->m2m.v4l2_dev);
+ }
+}
+
+static void fimc_clk_release(struct fimc_dev *fimc)
+{
+ int i;
+ for (i = 0; i < NUM_FIMC_CLOCKS; i++) {
+ if (fimc->clock[i]) {
+ clk_disable(fimc->clock[i]);
+ clk_put(fimc->clock[i]);
+ }
+ }
+}
+
+static int fimc_clk_get(struct fimc_dev *fimc)
+{
+ int i;
+ for (i = 0; i < NUM_FIMC_CLOCKS; i++) {
+ fimc->clock[i] = clk_get(&fimc->pdev->dev, fimc_clock_name[i]);
+ if (IS_ERR(fimc->clock[i])) {
+ dev_err(&fimc->pdev->dev,
+ "failed to get fimc clock: %s\n",
+ fimc_clock_name[i]);
+ return -ENXIO;
+ }
+ clk_enable(fimc->clock[i]);
+ }
+ return 0;
+}
+
+static int fimc_probe(struct platform_device *pdev)
+{
+ struct fimc_dev *fimc;
+ struct resource *res;
+ struct samsung_fimc_driverdata *drv_data;
+ int ret = 0;
+
+ dev_dbg(&pdev->dev, "%s():\n", __func__);
+
+ drv_data = (struct samsung_fimc_driverdata *)
+ platform_get_device_id(pdev)->driver_data;
+
+ if (pdev->id >= drv_data->num_entities) {
+ dev_err(&pdev->dev, "Invalid platform device id: %d\n",
+ pdev->id);
+ return -EINVAL;
+ }
+
+ fimc = kzalloc(sizeof(struct fimc_dev), GFP_KERNEL);
+ if (!fimc)
+ return -ENOMEM;
+
+ fimc->id = pdev->id;
+ fimc->variant = drv_data->variant[fimc->id];
+ fimc->pdev = pdev;
+ fimc->pdata = pdev->dev.platform_data;
+ fimc->state = ST_IDLE;
+
+ spin_lock_init(&fimc->irqlock);
+ init_waitqueue_head(&fimc->irq_queue);
+ spin_lock_init(&fimc->slock);
+
+ mutex_init(&fimc->lock);
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to find the registers\n");
+ ret = -ENOENT;
+ goto err_info;
+ }
+
+ fimc->regs_res = request_mem_region(res->start, resource_size(res),
+ dev_name(&pdev->dev));
+ if (!fimc->regs_res) {
+ dev_err(&pdev->dev, "failed to obtain register region\n");
+ ret = -ENOENT;
+ goto err_info;
+ }
+
+ fimc->regs = ioremap(res->start, resource_size(res));
+ if (!fimc->regs) {
+ dev_err(&pdev->dev, "failed to map registers\n");
+ ret = -ENXIO;
+ goto err_req_region;
+ }
+
+ ret = fimc_clk_get(fimc);
+ if (ret)
+ goto err_regs_unmap;
+ clk_set_rate(fimc->clock[0], drv_data->lclk_frequency);
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ if (!res) {
+ dev_err(&pdev->dev, "failed to get IRQ resource\n");
+ ret = -ENXIO;
+ goto err_clk;
+ }
+ fimc->irq = res->start;
+
+ fimc_hw_reset(fimc);
+
+ ret = request_irq(fimc->irq, fimc_isr, 0, pdev->name, fimc);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to install irq (%d)\n", ret);
+ goto err_clk;
+ }
+
+ ret = fimc_register_m2m_device(fimc);
+ if (ret)
+ goto err_irq;
+
+ /* At least one camera sensor is required to register capture node */
+ if (fimc->pdata) {
+ int i;
+ for (i = 0; i < FIMC_MAX_CAMIF_CLIENTS; ++i)
+ if (fimc->pdata->isp_info[i])
+ break;
+
+ if (i < FIMC_MAX_CAMIF_CLIENTS) {
+ ret = fimc_register_capture_device(fimc);
+ if (ret)
+ goto err_m2m;
+ }
+ }
+
+ /*
+ * Exclude the additional output DMA address registers by masking
+ * them out on HW revisions that provide extended capabilites.
+ */
+ if (fimc->variant->out_buf_count > 4)
+ fimc_hw_set_dma_seq(fimc, 0xF);
+
+ dev_dbg(&pdev->dev, "%s(): fimc-%d registered successfully\n",
+ __func__, fimc->id);
+
+ return 0;
+
+err_m2m:
+ fimc_unregister_m2m_device(fimc);
+err_irq:
+ free_irq(fimc->irq, fimc);
+err_clk:
+ fimc_clk_release(fimc);
+err_regs_unmap:
+ iounmap(fimc->regs);
+err_req_region:
+ release_resource(fimc->regs_res);
+ kfree(fimc->regs_res);
+err_info:
+ kfree(fimc);
+
+ return ret;
+}
+
+static int __devexit fimc_remove(struct platform_device *pdev)
+{
+ struct fimc_dev *fimc =
+ (struct fimc_dev *)platform_get_drvdata(pdev);
+
+ free_irq(fimc->irq, fimc);
+ fimc_hw_reset(fimc);
+
+ fimc_unregister_m2m_device(fimc);
+ fimc_unregister_capture_device(fimc);
+
+ fimc_clk_release(fimc);
+ iounmap(fimc->regs);
+ release_resource(fimc->regs_res);
+ kfree(fimc->regs_res);
+ kfree(fimc);
+
+ dev_info(&pdev->dev, "%s driver unloaded\n", pdev->name);
+ return 0;
+}
+
+/* Image pixel limits, similar across several FIMC HW revisions. */
+static struct fimc_pix_limit s5p_pix_limit[3] = {
+ [0] = {
+ .scaler_en_w = 3264,
+ .scaler_dis_w = 8192,
+ .in_rot_en_h = 1920,
+ .in_rot_dis_w = 8192,
+ .out_rot_en_w = 1920,
+ .out_rot_dis_w = 4224,
+ },
+ [1] = {
+ .scaler_en_w = 4224,
+ .scaler_dis_w = 8192,
+ .in_rot_en_h = 1920,
+ .in_rot_dis_w = 8192,
+ .out_rot_en_w = 1920,
+ .out_rot_dis_w = 4224,
+ },
+ [2] = {
+ .scaler_en_w = 1920,
+ .scaler_dis_w = 8192,
+ .in_rot_en_h = 1280,
+ .in_rot_dis_w = 8192,
+ .out_rot_en_w = 1280,
+ .out_rot_dis_w = 1920,
+ },
+};
+
+static struct samsung_fimc_variant fimc0_variant_s5p = {
+ .has_inp_rot = 1,
+ .has_out_rot = 1,
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 8,
+ .out_buf_count = 4,
+ .pix_limit = &s5p_pix_limit[0],
+};
+
+static struct samsung_fimc_variant fimc2_variant_s5p = {
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 8,
+ .out_buf_count = 4,
+ .pix_limit = &s5p_pix_limit[1],
+};
+
+static struct samsung_fimc_variant fimc0_variant_s5pv210 = {
+ .pix_hoff = 1,
+ .has_inp_rot = 1,
+ .has_out_rot = 1,
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 8,
+ .out_buf_count = 4,
+ .pix_limit = &s5p_pix_limit[1],
+};
+
+static struct samsung_fimc_variant fimc1_variant_s5pv210 = {
+ .pix_hoff = 1,
+ .has_inp_rot = 1,
+ .has_out_rot = 1,
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 1,
+ .out_buf_count = 4,
+ .pix_limit = &s5p_pix_limit[2],
+};
+
+static struct samsung_fimc_variant fimc2_variant_s5pv210 = {
+ .pix_hoff = 1,
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 8,
+ .out_buf_count = 4,
+ .pix_limit = &s5p_pix_limit[2],
+};
+
+static struct samsung_fimc_variant fimc0_variant_s5pv310 = {
+ .pix_hoff = 1,
+ .has_inp_rot = 1,
+ .has_out_rot = 1,
+ .has_cistatus2 = 1,
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 1,
+ .out_buf_count = 32,
+ .pix_limit = &s5p_pix_limit[1],
+};
+
+static struct samsung_fimc_variant fimc2_variant_s5pv310 = {
+ .pix_hoff = 1,
+ .has_cistatus2 = 1,
+ .min_inp_pixsize = 16,
+ .min_out_pixsize = 16,
+ .hor_offs_align = 1,
+ .out_buf_count = 32,
+ .pix_limit = &s5p_pix_limit[2],
+};
+
+/* S5PC100 */
+static struct samsung_fimc_driverdata fimc_drvdata_s5p = {
+ .variant = {
+ [0] = &fimc0_variant_s5p,
+ [1] = &fimc0_variant_s5p,
+ [2] = &fimc2_variant_s5p,
+ },
+ .num_entities = 3,
+ .lclk_frequency = 133000000UL,
+};
+
+/* S5PV210, S5PC110 */
+static struct samsung_fimc_driverdata fimc_drvdata_s5pv210 = {
+ .variant = {
+ [0] = &fimc0_variant_s5pv210,
+ [1] = &fimc1_variant_s5pv210,
+ [2] = &fimc2_variant_s5pv210,
+ },
+ .num_entities = 3,
+ .lclk_frequency = 166000000UL,
+};
+
+/* S5PV310, S5PC210 */
+static struct samsung_fimc_driverdata fimc_drvdata_s5pv310 = {
+ .variant = {
+ [0] = &fimc0_variant_s5pv310,
+ [1] = &fimc0_variant_s5pv310,
+ [2] = &fimc0_variant_s5pv310,
+ [3] = &fimc2_variant_s5pv310,
+ },
+ .num_entities = 4,
+ .lclk_frequency = 166000000UL,
+};
+
+static struct platform_device_id fimc_driver_ids[] = {
+ {
+ .name = "s5p-fimc",
+ .driver_data = (unsigned long)&fimc_drvdata_s5p,
+ }, {
+ .name = "s5pv210-fimc",
+ .driver_data = (unsigned long)&fimc_drvdata_s5pv210,
+ }, {
+ .name = "s5pv310-fimc",
+ .driver_data = (unsigned long)&fimc_drvdata_s5pv310,
+ },
+ {},
+};
+MODULE_DEVICE_TABLE(platform, fimc_driver_ids);
+
+static struct platform_driver fimc_driver = {
+ .probe = fimc_probe,
+ .remove = __devexit_p(fimc_remove),
+ .id_table = fimc_driver_ids,
+ .driver = {
+ .name = MODULE_NAME,
+ .owner = THIS_MODULE,
+ }
+};
+
+static int __init fimc_init(void)
+{
+ int ret = platform_driver_register(&fimc_driver);
+ if (ret)
+ err("platform_driver_register failed: %d\n", ret);
+ return ret;
+}
+
+static void __exit fimc_exit(void)
+{
+ platform_driver_unregister(&fimc_driver);
+}
+
+module_init(fimc_init);
+module_exit(fimc_exit);
+
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_DESCRIPTION("S5P FIMC camera host interface/video postprocessor driver");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/s5p-fimc/fimc-core.h b/drivers/media/video/s5p-fimc/fimc-core.h
new file mode 100644
index 000000000000..4f047d35f8ad
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-core.h
@@ -0,0 +1,698 @@
+/*
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ * Sylwester Nawrocki, <s.nawrocki@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef FIMC_CORE_H_
+#define FIMC_CORE_H_
+
+/*#define DEBUG*/
+
+#include <linux/sched.h>
+#include <linux/types.h>
+#include <linux/videodev2.h>
+#include <media/videobuf-core.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-mediabus.h>
+#include <media/s3c_fimc.h>
+
+#include "regs-fimc.h"
+
+#define err(fmt, args...) \
+ printk(KERN_ERR "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+
+#ifdef DEBUG
+#define dbg(fmt, args...) \
+ printk(KERN_DEBUG "%s:%d: " fmt "\n", __func__, __LINE__, ##args)
+#else
+#define dbg(fmt, args...)
+#endif
+
+/* Time to wait for next frame VSYNC interrupt while stopping operation. */
+#define FIMC_SHUTDOWN_TIMEOUT ((100*HZ)/1000)
+#define NUM_FIMC_CLOCKS 2
+#define MODULE_NAME "s5p-fimc"
+#define FIMC_MAX_DEVS 4
+#define FIMC_MAX_OUT_BUFS 4
+#define SCALER_MAX_HRATIO 64
+#define SCALER_MAX_VRATIO 64
+#define DMA_MIN_SIZE 8
+
+/* FIMC device state flags */
+enum fimc_dev_flags {
+ /* for m2m node */
+ ST_IDLE,
+ ST_OUTDMA_RUN,
+ ST_M2M_PEND,
+ /* for capture node */
+ ST_CAPT_PEND,
+ ST_CAPT_RUN,
+ ST_CAPT_STREAM,
+ ST_CAPT_SHUT,
+};
+
+#define fimc_m2m_active(dev) test_bit(ST_OUTDMA_RUN, &(dev)->state)
+#define fimc_m2m_pending(dev) test_bit(ST_M2M_PEND, &(dev)->state)
+
+#define fimc_capture_running(dev) test_bit(ST_CAPT_RUN, &(dev)->state)
+#define fimc_capture_pending(dev) test_bit(ST_CAPT_PEND, &(dev)->state)
+
+#define fimc_capture_active(dev) \
+ (test_bit(ST_CAPT_RUN, &(dev)->state) || \
+ test_bit(ST_CAPT_PEND, &(dev)->state))
+
+#define fimc_capture_streaming(dev) \
+ test_bit(ST_CAPT_STREAM, &(dev)->state)
+
+#define fimc_buf_finish(dev, vid_buf) do { \
+ spin_lock(&(dev)->irqlock); \
+ (vid_buf)->vb.state = VIDEOBUF_DONE; \
+ spin_unlock(&(dev)->irqlock); \
+ wake_up(&(vid_buf)->vb.done); \
+} while (0)
+
+enum fimc_datapath {
+ FIMC_CAMERA,
+ FIMC_DMA,
+ FIMC_LCDFIFO,
+ FIMC_WRITEBACK
+};
+
+enum fimc_color_fmt {
+ S5P_FIMC_RGB565 = 0x10,
+ S5P_FIMC_RGB666,
+ S5P_FIMC_RGB888,
+ S5P_FIMC_RGB30_LOCAL,
+ S5P_FIMC_YCBCR420 = 0x20,
+ S5P_FIMC_YCBCR422,
+ S5P_FIMC_YCBYCR422,
+ S5P_FIMC_YCRYCB422,
+ S5P_FIMC_CBYCRY422,
+ S5P_FIMC_CRYCBY422,
+ S5P_FIMC_YCBCR444_LOCAL,
+};
+
+#define fimc_fmt_is_rgb(x) ((x) & 0x10)
+
+/* Y/Cb/Cr components order at DMA output for 1 plane YCbCr 4:2:2 formats. */
+#define S5P_FIMC_OUT_CRYCBY S5P_CIOCTRL_ORDER422_CRYCBY
+#define S5P_FIMC_OUT_CBYCRY S5P_CIOCTRL_ORDER422_YCRYCB
+#define S5P_FIMC_OUT_YCRYCB S5P_CIOCTRL_ORDER422_CBYCRY
+#define S5P_FIMC_OUT_YCBYCR S5P_CIOCTRL_ORDER422_YCBYCR
+
+/* Input Y/Cb/Cr components order for 1 plane YCbCr 4:2:2 color formats. */
+#define S5P_FIMC_IN_CRYCBY S5P_MSCTRL_ORDER422_CRYCBY
+#define S5P_FIMC_IN_CBYCRY S5P_MSCTRL_ORDER422_YCRYCB
+#define S5P_FIMC_IN_YCRYCB S5P_MSCTRL_ORDER422_CBYCRY
+#define S5P_FIMC_IN_YCBYCR S5P_MSCTRL_ORDER422_YCBYCR
+
+/* Cb/Cr chrominance components order for 2 plane Y/CbCr 4:2:2 formats. */
+#define S5P_FIMC_LSB_CRCB S5P_CIOCTRL_ORDER422_2P_LSB_CRCB
+
+/* The embedded image effect selection */
+#define S5P_FIMC_EFFECT_ORIGINAL S5P_CIIMGEFF_FIN_BYPASS
+#define S5P_FIMC_EFFECT_ARBITRARY S5P_CIIMGEFF_FIN_ARBITRARY
+#define S5P_FIMC_EFFECT_NEGATIVE S5P_CIIMGEFF_FIN_NEGATIVE
+#define S5P_FIMC_EFFECT_ARTFREEZE S5P_CIIMGEFF_FIN_ARTFREEZE
+#define S5P_FIMC_EFFECT_EMBOSSING S5P_CIIMGEFF_FIN_EMBOSSING
+#define S5P_FIMC_EFFECT_SIKHOUETTE S5P_CIIMGEFF_FIN_SILHOUETTE
+
+/* The hardware context state. */
+#define FIMC_PARAMS (1 << 0)
+#define FIMC_SRC_ADDR (1 << 1)
+#define FIMC_DST_ADDR (1 << 2)
+#define FIMC_SRC_FMT (1 << 3)
+#define FIMC_DST_FMT (1 << 4)
+#define FIMC_CTX_M2M (1 << 5)
+#define FIMC_CTX_CAP (1 << 6)
+
+/* Image conversion flags */
+#define FIMC_IN_DMA_ACCESS_TILED (1 << 0)
+#define FIMC_IN_DMA_ACCESS_LINEAR (0 << 0)
+#define FIMC_OUT_DMA_ACCESS_TILED (1 << 1)
+#define FIMC_OUT_DMA_ACCESS_LINEAR (0 << 1)
+#define FIMC_SCAN_MODE_PROGRESSIVE (0 << 2)
+#define FIMC_SCAN_MODE_INTERLACED (1 << 2)
+/*
+ * YCbCr data dynamic range for RGB-YUV color conversion.
+ * Y/Cb/Cr: (0 ~ 255) */
+#define FIMC_COLOR_RANGE_WIDE (0 << 3)
+/* Y (16 ~ 235), Cb/Cr (16 ~ 240) */
+#define FIMC_COLOR_RANGE_NARROW (1 << 3)
+
+#define FLIP_NONE 0
+#define FLIP_X_AXIS 1
+#define FLIP_Y_AXIS 2
+#define FLIP_XY_AXIS (FLIP_X_AXIS | FLIP_Y_AXIS)
+
+/**
+ * struct fimc_fmt - the driver's internal color format data
+ * @mbus_code: Media Bus pixel code, -1 if not applicable
+ * @name: format description
+ * @fourcc: the fourcc code for this format, 0 if not applicable
+ * @color: the corresponding fimc_color_fmt
+ * @depth: driver's private 'number of bits per pixel'
+ * @buff_cnt: number of physically non-contiguous data planes
+ * @planes_cnt: number of physically contiguous data planes
+ */
+struct fimc_fmt {
+ enum v4l2_mbus_pixelcode mbus_code;
+ char *name;
+ u32 fourcc;
+ u32 color;
+ u16 buff_cnt;
+ u16 planes_cnt;
+ u16 depth;
+ u16 flags;
+#define FMT_FLAGS_CAM (1 << 0)
+#define FMT_FLAGS_M2M (1 << 1)
+};
+
+/**
+ * struct fimc_dma_offset - pixel offset information for DMA
+ * @y_h: y value horizontal offset
+ * @y_v: y value vertical offset
+ * @cb_h: cb value horizontal offset
+ * @cb_v: cb value vertical offset
+ * @cr_h: cr value horizontal offset
+ * @cr_v: cr value vertical offset
+ */
+struct fimc_dma_offset {
+ int y_h;
+ int y_v;
+ int cb_h;
+ int cb_v;
+ int cr_h;
+ int cr_v;
+};
+
+/**
+ * struct fimc_effect - the configuration data for the "Arbitrary" image effect
+ * @type: effect type
+ * @pat_cb: cr value when type is "arbitrary"
+ * @pat_cr: cr value when type is "arbitrary"
+ */
+struct fimc_effect {
+ u32 type;
+ u8 pat_cb;
+ u8 pat_cr;
+};
+
+/**
+ * struct fimc_scaler - the configuration data for FIMC inetrnal scaler
+ *
+ * @scaleup_h: flag indicating scaling up horizontally
+ * @scaleup_v: flag indicating scaling up vertically
+ * @copy_mode: flag indicating transparent DMA transfer (no scaling
+ * and color format conversion)
+ * @enabled: flag indicating if the scaler is used
+ * @hfactor: horizontal shift factor
+ * @vfactor: vertical shift factor
+ * @pre_hratio: horizontal ratio of the prescaler
+ * @pre_vratio: vertical ratio of the prescaler
+ * @pre_dst_width: the prescaler's destination width
+ * @pre_dst_height: the prescaler's destination height
+ * @main_hratio: the main scaler's horizontal ratio
+ * @main_vratio: the main scaler's vertical ratio
+ * @real_width: source pixel (width - offset)
+ * @real_height: source pixel (height - offset)
+ */
+struct fimc_scaler {
+ unsigned int scaleup_h:1;
+ unsigned int scaleup_v:1;
+ unsigned int copy_mode:1;
+ unsigned int enabled:1;
+ u32 hfactor;
+ u32 vfactor;
+ u32 pre_hratio;
+ u32 pre_vratio;
+ u32 pre_dst_width;
+ u32 pre_dst_height;
+ u32 main_hratio;
+ u32 main_vratio;
+ u32 real_width;
+ u32 real_height;
+};
+
+/**
+ * struct fimc_addr - the FIMC physical address set for DMA
+ *
+ * @y: luminance plane physical address
+ * @cb: Cb plane physical address
+ * @cr: Cr plane physical address
+ */
+struct fimc_addr {
+ u32 y;
+ u32 cb;
+ u32 cr;
+};
+
+/**
+ * struct fimc_vid_buffer - the driver's video buffer
+ * @vb: v4l videobuf buffer
+ * @paddr: precalculated physical address set
+ * @index: buffer index for the output DMA engine
+ */
+struct fimc_vid_buffer {
+ struct videobuf_buffer vb;
+ struct fimc_addr paddr;
+ int index;
+};
+
+/**
+ * struct fimc_frame - source/target frame properties
+ * @f_width: image full width (virtual screen size)
+ * @f_height: image full height (virtual screen size)
+ * @o_width: original image width as set by S_FMT
+ * @o_height: original image height as set by S_FMT
+ * @offs_h: image horizontal pixel offset
+ * @offs_v: image vertical pixel offset
+ * @width: image pixel width
+ * @height: image pixel weight
+ * @paddr: image frame buffer physical addresses
+ * @buf_cnt: number of buffers depending on a color format
+ * @size: image size in bytes
+ * @color: color format
+ * @dma_offset: DMA offset in bytes
+ */
+struct fimc_frame {
+ u32 f_width;
+ u32 f_height;
+ u32 o_width;
+ u32 o_height;
+ u32 offs_h;
+ u32 offs_v;
+ u32 width;
+ u32 height;
+ u32 size;
+ struct fimc_addr paddr;
+ struct fimc_dma_offset dma_offset;
+ struct fimc_fmt *fmt;
+};
+
+/**
+ * struct fimc_m2m_device - v4l2 memory-to-memory device data
+ * @vfd: the video device node for v4l2 m2m mode
+ * @v4l2_dev: v4l2 device for m2m mode
+ * @m2m_dev: v4l2 memory-to-memory device data
+ * @ctx: hardware context data
+ * @refcnt: the reference counter
+ */
+struct fimc_m2m_device {
+ struct video_device *vfd;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ struct fimc_ctx *ctx;
+ int refcnt;
+};
+
+/**
+ * struct fimc_vid_cap - camera capture device information
+ * @ctx: hardware context data
+ * @vfd: video device node for camera capture mode
+ * @v4l2_dev: v4l2_device struct to manage subdevs
+ * @sd: pointer to camera sensor subdevice currently in use
+ * @fmt: Media Bus format configured at selected image sensor
+ * @pending_buf_q: the pending buffer queue head
+ * @active_buf_q: the queue head of buffers scheduled in hardware
+ * @vbq: the capture am video buffer queue
+ * @active_buf_cnt: number of video buffers scheduled in hardware
+ * @buf_index: index for managing the output DMA buffers
+ * @frame_count: the frame counter for statistics
+ * @reqbufs_count: the number of buffers requested in REQBUFS ioctl
+ * @input_index: input (camera sensor) index
+ * @refcnt: driver's private reference counter
+ */
+struct fimc_vid_cap {
+ struct fimc_ctx *ctx;
+ struct video_device *vfd;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_subdev *sd;
+ struct v4l2_mbus_framefmt fmt;
+ struct list_head pending_buf_q;
+ struct list_head active_buf_q;
+ struct videobuf_queue vbq;
+ int active_buf_cnt;
+ int buf_index;
+ unsigned int frame_count;
+ unsigned int reqbufs_count;
+ int input_index;
+ int refcnt;
+};
+
+/**
+ * struct fimc_pix_limit - image pixel size limits in various IP configurations
+ *
+ * @scaler_en_w: max input pixel width when the scaler is enabled
+ * @scaler_dis_w: max input pixel width when the scaler is disabled
+ * @in_rot_en_h: max input width with the input rotator is on
+ * @in_rot_dis_w: max input width with the input rotator is off
+ * @out_rot_en_w: max output width with the output rotator on
+ * @out_rot_dis_w: max output width with the output rotator off
+ */
+struct fimc_pix_limit {
+ u16 scaler_en_w;
+ u16 scaler_dis_w;
+ u16 in_rot_en_h;
+ u16 in_rot_dis_w;
+ u16 out_rot_en_w;
+ u16 out_rot_dis_w;
+};
+
+/**
+ * struct samsung_fimc_variant - camera interface variant information
+ *
+ * @pix_hoff: indicate whether horizontal offset is in pixels or in bytes
+ * @has_inp_rot: set if has input rotator
+ * @has_out_rot: set if has output rotator
+ * @has_cistatus2: 1 if CISTATUS2 register is present in this IP revision
+ * @pix_limit: pixel size constraints for the scaler
+ * @min_inp_pixsize: minimum input pixel size
+ * @min_out_pixsize: minimum output pixel size
+ * @hor_offs_align: horizontal pixel offset aligment
+ * @out_buf_count: the number of buffers in output DMA sequence
+ */
+struct samsung_fimc_variant {
+ unsigned int pix_hoff:1;
+ unsigned int has_inp_rot:1;
+ unsigned int has_out_rot:1;
+ unsigned int has_cistatus2:1;
+ struct fimc_pix_limit *pix_limit;
+ u16 min_inp_pixsize;
+ u16 min_out_pixsize;
+ u16 hor_offs_align;
+ u16 out_buf_count;
+};
+
+/**
+ * struct samsung_fimc_driverdata - per device type driver data for init time.
+ *
+ * @variant: the variant information for this driver.
+ * @dev_cnt: number of fimc sub-devices available in SoC
+ * @lclk_frequency: fimc bus clock frequency
+ */
+struct samsung_fimc_driverdata {
+ struct samsung_fimc_variant *variant[FIMC_MAX_DEVS];
+ unsigned long lclk_frequency;
+ int num_entities;
+};
+
+struct fimc_ctx;
+
+/**
+ * struct fimc_dev - abstraction for FIMC entity
+ *
+ * @slock: the spinlock protecting this data structure
+ * @lock: the mutex protecting this data structure
+ * @pdev: pointer to the FIMC platform device
+ * @pdata: pointer to the device platform data
+ * @id: FIMC device index (0..2)
+ * @clock[]: the clocks required for FIMC operation
+ * @regs: the mapped hardware registers
+ * @regs_res: the resource claimed for IO registers
+ * @irq: interrupt number of the FIMC subdevice
+ * @irqlock: spinlock protecting videobuffer queue
+ * @irq_queue:
+ * @m2m: memory-to-memory V4L2 device information
+ * @vid_cap: camera capture device information
+ * @state: flags used to synchronize m2m and capture mode operation
+ */
+struct fimc_dev {
+ spinlock_t slock;
+ struct mutex lock;
+ struct platform_device *pdev;
+ struct s3c_platform_fimc *pdata;
+ struct samsung_fimc_variant *variant;
+ int id;
+ struct clk *clock[NUM_FIMC_CLOCKS];
+ void __iomem *regs;
+ struct resource *regs_res;
+ int irq;
+ spinlock_t irqlock;
+ wait_queue_head_t irq_queue;
+ struct fimc_m2m_device m2m;
+ struct fimc_vid_cap vid_cap;
+ unsigned long state;
+};
+
+/**
+ * fimc_ctx - the device context data
+ *
+ * @lock: mutex protecting this data structure
+ * @s_frame: source frame properties
+ * @d_frame: destination frame properties
+ * @out_order_1p: output 1-plane YCBCR order
+ * @out_order_2p: output 2-plane YCBCR order
+ * @in_order_1p input 1-plane YCBCR order
+ * @in_order_2p: input 2-plane YCBCR order
+ * @in_path: input mode (DMA or camera)
+ * @out_path: output mode (DMA or FIFO)
+ * @scaler: image scaler properties
+ * @effect: image effect
+ * @rotation: image clockwise rotation in degrees
+ * @flip: image flip mode
+ * @flags: additional flags for image conversion
+ * @state: flags to keep track of user configuration
+ * @fimc_dev: the FIMC device this context applies to
+ * @m2m_ctx: memory-to-memory device context
+ */
+struct fimc_ctx {
+ spinlock_t slock;
+ struct fimc_frame s_frame;
+ struct fimc_frame d_frame;
+ u32 out_order_1p;
+ u32 out_order_2p;
+ u32 in_order_1p;
+ u32 in_order_2p;
+ enum fimc_datapath in_path;
+ enum fimc_datapath out_path;
+ struct fimc_scaler scaler;
+ struct fimc_effect effect;
+ int rotation;
+ u32 flip;
+ u32 flags;
+ u32 state;
+ struct fimc_dev *fimc_dev;
+ struct v4l2_m2m_ctx *m2m_ctx;
+};
+
+extern struct videobuf_queue_ops fimc_qops;
+
+static inline int tiled_fmt(struct fimc_fmt *fmt)
+{
+ return 0;
+}
+
+static inline void fimc_hw_clear_irq(struct fimc_dev *dev)
+{
+ u32 cfg = readl(dev->regs + S5P_CIGCTRL);
+ cfg |= S5P_CIGCTRL_IRQ_CLR;
+ writel(cfg, dev->regs + S5P_CIGCTRL);
+}
+
+static inline void fimc_hw_enable_scaler(struct fimc_dev *dev, bool on)
+{
+ u32 cfg = readl(dev->regs + S5P_CISCCTRL);
+ if (on)
+ cfg |= S5P_CISCCTRL_SCALERSTART;
+ else
+ cfg &= ~S5P_CISCCTRL_SCALERSTART;
+ writel(cfg, dev->regs + S5P_CISCCTRL);
+}
+
+static inline void fimc_hw_activate_input_dma(struct fimc_dev *dev, bool on)
+{
+ u32 cfg = readl(dev->regs + S5P_MSCTRL);
+ if (on)
+ cfg |= S5P_MSCTRL_ENVID;
+ else
+ cfg &= ~S5P_MSCTRL_ENVID;
+ writel(cfg, dev->regs + S5P_MSCTRL);
+}
+
+static inline void fimc_hw_dis_capture(struct fimc_dev *dev)
+{
+ u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
+ cfg &= ~(S5P_CIIMGCPT_IMGCPTEN | S5P_CIIMGCPT_IMGCPTEN_SC);
+ writel(cfg, dev->regs + S5P_CIIMGCPT);
+}
+
+/**
+ * fimc_hw_set_dma_seq - configure output DMA buffer sequence
+ * @mask: each bit corresponds to one of 32 output buffer registers set
+ * 1 to include buffer in the sequence, 0 to disable
+ *
+ * This function mask output DMA ring buffers, i.e. it allows to configure
+ * which of the output buffer address registers will be used by the DMA
+ * engine.
+ */
+static inline void fimc_hw_set_dma_seq(struct fimc_dev *dev, u32 mask)
+{
+ writel(mask, dev->regs + S5P_CIFCNTSEQ);
+}
+
+static inline struct fimc_frame *ctx_get_frame(struct fimc_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ struct fimc_frame *frame;
+
+ if (V4L2_BUF_TYPE_VIDEO_OUTPUT == type) {
+ if (ctx->state & FIMC_CTX_M2M)
+ frame = &ctx->s_frame;
+ else
+ return ERR_PTR(-EINVAL);
+ } else if (V4L2_BUF_TYPE_VIDEO_CAPTURE == type) {
+ frame = &ctx->d_frame;
+ } else {
+ v4l2_err(&ctx->fimc_dev->m2m.v4l2_dev,
+ "Wrong buffer/video queue type (%d)\n", type);
+ return ERR_PTR(-EINVAL);
+ }
+
+ return frame;
+}
+
+/* Return an index to the buffer actually being written. */
+static inline u32 fimc_hw_get_frame_index(struct fimc_dev *dev)
+{
+ u32 reg;
+
+ if (dev->variant->has_cistatus2) {
+ reg = readl(dev->regs + S5P_CISTATUS2) & 0x3F;
+ return reg > 0 ? --reg : reg;
+ } else {
+ reg = readl(dev->regs + S5P_CISTATUS);
+ return (reg & S5P_CISTATUS_FRAMECNT_MASK) >>
+ S5P_CISTATUS_FRAMECNT_SHIFT;
+ }
+}
+
+/* -----------------------------------------------------*/
+/* fimc-reg.c */
+void fimc_hw_reset(struct fimc_dev *fimc);
+void fimc_hw_set_rotation(struct fimc_ctx *ctx);
+void fimc_hw_set_target_format(struct fimc_ctx *ctx);
+void fimc_hw_set_out_dma(struct fimc_ctx *ctx);
+void fimc_hw_en_lastirq(struct fimc_dev *fimc, int enable);
+void fimc_hw_en_irq(struct fimc_dev *fimc, int enable);
+void fimc_hw_set_scaler(struct fimc_ctx *ctx);
+void fimc_hw_en_capture(struct fimc_ctx *ctx);
+void fimc_hw_set_effect(struct fimc_ctx *ctx);
+void fimc_hw_set_in_dma(struct fimc_ctx *ctx);
+void fimc_hw_set_input_path(struct fimc_ctx *ctx);
+void fimc_hw_set_output_path(struct fimc_ctx *ctx);
+void fimc_hw_set_input_addr(struct fimc_dev *fimc, struct fimc_addr *paddr);
+void fimc_hw_set_output_addr(struct fimc_dev *fimc, struct fimc_addr *paddr,
+ int index);
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f);
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam);
+
+/* -----------------------------------------------------*/
+/* fimc-core.c */
+int fimc_vidioc_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f);
+int fimc_vidioc_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *f);
+int fimc_vidioc_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *f);
+int fimc_vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *qc);
+int fimc_vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctrl);
+
+int fimc_try_crop(struct fimc_ctx *ctx, struct v4l2_crop *cr);
+int check_ctrl_val(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
+int fimc_s_ctrl(struct fimc_ctx *ctx, struct v4l2_control *ctrl);
+
+struct fimc_fmt *find_format(struct v4l2_format *f, unsigned int mask);
+struct fimc_fmt *find_mbus_format(struct v4l2_mbus_framefmt *f,
+ unsigned int mask);
+
+int fimc_check_scaler_ratio(struct v4l2_rect *r, struct fimc_frame *f);
+int fimc_set_scaler_info(struct fimc_ctx *ctx);
+int fimc_prepare_config(struct fimc_ctx *ctx, u32 flags);
+int fimc_prepare_addr(struct fimc_ctx *ctx, struct fimc_vid_buffer *buf,
+ struct fimc_frame *frame, struct fimc_addr *paddr);
+
+/* -----------------------------------------------------*/
+/* fimc-capture.c */
+int fimc_register_capture_device(struct fimc_dev *fimc);
+void fimc_unregister_capture_device(struct fimc_dev *fimc);
+int fimc_sensor_sd_init(struct fimc_dev *fimc, int index);
+int fimc_vid_cap_buf_queue(struct fimc_dev *fimc,
+ struct fimc_vid_buffer *fimc_vb);
+
+/* Locking: the caller holds fimc->slock */
+static inline void fimc_activate_capture(struct fimc_ctx *ctx)
+{
+ fimc_hw_enable_scaler(ctx->fimc_dev, ctx->scaler.enabled);
+ fimc_hw_en_capture(ctx);
+}
+
+static inline void fimc_deactivate_capture(struct fimc_dev *fimc)
+{
+ fimc_hw_en_lastirq(fimc, true);
+ fimc_hw_dis_capture(fimc);
+ fimc_hw_enable_scaler(fimc, false);
+ fimc_hw_en_lastirq(fimc, false);
+}
+
+/*
+ * Add video buffer to the active buffers queue.
+ * The caller holds irqlock spinlock.
+ */
+static inline void active_queue_add(struct fimc_vid_cap *vid_cap,
+ struct fimc_vid_buffer *buf)
+{
+ buf->vb.state = VIDEOBUF_ACTIVE;
+ list_add_tail(&buf->vb.queue, &vid_cap->active_buf_q);
+ vid_cap->active_buf_cnt++;
+}
+
+/*
+ * Pop a video buffer from the capture active buffers queue
+ * Locking: Need to be called with dev->slock held.
+ */
+static inline struct fimc_vid_buffer *
+active_queue_pop(struct fimc_vid_cap *vid_cap)
+{
+ struct fimc_vid_buffer *buf;
+ buf = list_entry(vid_cap->active_buf_q.next,
+ struct fimc_vid_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ vid_cap->active_buf_cnt--;
+ return buf;
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline void fimc_pending_queue_add(struct fimc_vid_cap *vid_cap,
+ struct fimc_vid_buffer *buf)
+{
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vid_cap->pending_buf_q);
+}
+
+/* Add video buffer to the capture pending buffers queue */
+static inline struct fimc_vid_buffer *
+pending_queue_pop(struct fimc_vid_cap *vid_cap)
+{
+ struct fimc_vid_buffer *buf;
+ buf = list_entry(vid_cap->pending_buf_q.next,
+ struct fimc_vid_buffer, vb.queue);
+ list_del(&buf->vb.queue);
+ return buf;
+}
+
+
+#endif /* FIMC_CORE_H_ */
diff --git a/drivers/media/video/s5p-fimc/fimc-reg.c b/drivers/media/video/s5p-fimc/fimc-reg.c
new file mode 100644
index 000000000000..511631a2e5c3
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/fimc-reg.c
@@ -0,0 +1,668 @@
+/*
+ * Register interface file for Samsung Camera Interface (FIMC) driver
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ * Sylwester Nawrocki, s.nawrocki@samsung.com
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+*/
+
+#include <linux/io.h>
+#include <linux/delay.h>
+#include <mach/map.h>
+#include <media/s3c_fimc.h>
+
+#include "fimc-core.h"
+
+
+void fimc_hw_reset(struct fimc_dev *dev)
+{
+ u32 cfg;
+
+ cfg = readl(dev->regs + S5P_CISRCFMT);
+ cfg |= S5P_CISRCFMT_ITU601_8BIT;
+ writel(cfg, dev->regs + S5P_CISRCFMT);
+
+ /* Software reset. */
+ cfg = readl(dev->regs + S5P_CIGCTRL);
+ cfg |= (S5P_CIGCTRL_SWRST | S5P_CIGCTRL_IRQ_LEVEL);
+ writel(cfg, dev->regs + S5P_CIGCTRL);
+ udelay(1000);
+
+ cfg = readl(dev->regs + S5P_CIGCTRL);
+ cfg &= ~S5P_CIGCTRL_SWRST;
+ writel(cfg, dev->regs + S5P_CIGCTRL);
+}
+
+static u32 fimc_hw_get_in_flip(u32 ctx_flip)
+{
+ u32 flip = S5P_MSCTRL_FLIP_NORMAL;
+
+ switch (ctx_flip) {
+ case FLIP_X_AXIS:
+ flip = S5P_MSCTRL_FLIP_X_MIRROR;
+ break;
+ case FLIP_Y_AXIS:
+ flip = S5P_MSCTRL_FLIP_Y_MIRROR;
+ break;
+ case FLIP_XY_AXIS:
+ flip = S5P_MSCTRL_FLIP_180;
+ break;
+ }
+
+ return flip;
+}
+
+static u32 fimc_hw_get_target_flip(u32 ctx_flip)
+{
+ u32 flip = S5P_CITRGFMT_FLIP_NORMAL;
+
+ switch (ctx_flip) {
+ case FLIP_X_AXIS:
+ flip = S5P_CITRGFMT_FLIP_X_MIRROR;
+ break;
+ case FLIP_Y_AXIS:
+ flip = S5P_CITRGFMT_FLIP_Y_MIRROR;
+ break;
+ case FLIP_XY_AXIS:
+ flip = S5P_CITRGFMT_FLIP_180;
+ break;
+ case FLIP_NONE:
+ break;
+
+ }
+ return flip;
+}
+
+void fimc_hw_set_rotation(struct fimc_ctx *ctx)
+{
+ u32 cfg, flip;
+ struct fimc_dev *dev = ctx->fimc_dev;
+
+ cfg = readl(dev->regs + S5P_CITRGFMT);
+ cfg &= ~(S5P_CITRGFMT_INROT90 | S5P_CITRGFMT_OUTROT90 |
+ S5P_CITRGFMT_FLIP_180);
+
+ flip = readl(dev->regs + S5P_MSCTRL);
+ flip &= ~S5P_MSCTRL_FLIP_MASK;
+
+ /*
+ * The input and output rotator cannot work simultaneously.
+ * Use the output rotator in output DMA mode or the input rotator
+ * in direct fifo output mode.
+ */
+ if (ctx->rotation == 90 || ctx->rotation == 270) {
+ if (ctx->out_path == FIMC_LCDFIFO) {
+ cfg |= S5P_CITRGFMT_INROT90;
+ if (ctx->rotation == 270)
+ flip |= S5P_MSCTRL_FLIP_180;
+ } else {
+ cfg |= S5P_CITRGFMT_OUTROT90;
+ if (ctx->rotation == 270)
+ cfg |= S5P_CITRGFMT_FLIP_180;
+ }
+ } else if (ctx->rotation == 180) {
+ if (ctx->out_path == FIMC_LCDFIFO)
+ flip |= S5P_MSCTRL_FLIP_180;
+ else
+ cfg |= S5P_CITRGFMT_FLIP_180;
+ }
+ if (ctx->rotation == 180 || ctx->rotation == 270)
+ writel(flip, dev->regs + S5P_MSCTRL);
+
+ cfg |= fimc_hw_get_target_flip(ctx->flip);
+ writel(cfg, dev->regs + S5P_CITRGFMT);
+}
+
+void fimc_hw_set_target_format(struct fimc_ctx *ctx)
+{
+ u32 cfg;
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_frame *frame = &ctx->d_frame;
+
+ dbg("w= %d, h= %d color: %d", frame->width,
+ frame->height, frame->fmt->color);
+
+ cfg = readl(dev->regs + S5P_CITRGFMT);
+ cfg &= ~(S5P_CITRGFMT_FMT_MASK | S5P_CITRGFMT_HSIZE_MASK |
+ S5P_CITRGFMT_VSIZE_MASK);
+
+ switch (frame->fmt->color) {
+ case S5P_FIMC_RGB565:
+ case S5P_FIMC_RGB666:
+ case S5P_FIMC_RGB888:
+ cfg |= S5P_CITRGFMT_RGB;
+ break;
+ case S5P_FIMC_YCBCR420:
+ cfg |= S5P_CITRGFMT_YCBCR420;
+ break;
+ case S5P_FIMC_YCBYCR422:
+ case S5P_FIMC_YCRYCB422:
+ case S5P_FIMC_CBYCRY422:
+ case S5P_FIMC_CRYCBY422:
+ if (frame->fmt->planes_cnt == 1)
+ cfg |= S5P_CITRGFMT_YCBCR422_1P;
+ else
+ cfg |= S5P_CITRGFMT_YCBCR422;
+ break;
+ default:
+ break;
+ }
+
+ if (ctx->rotation == 90 || ctx->rotation == 270) {
+ cfg |= S5P_CITRGFMT_HSIZE(frame->height);
+ cfg |= S5P_CITRGFMT_VSIZE(frame->width);
+ } else {
+
+ cfg |= S5P_CITRGFMT_HSIZE(frame->width);
+ cfg |= S5P_CITRGFMT_VSIZE(frame->height);
+ }
+
+ writel(cfg, dev->regs + S5P_CITRGFMT);
+
+ cfg = readl(dev->regs + S5P_CITAREA) & ~S5P_CITAREA_MASK;
+ cfg |= (frame->width * frame->height);
+ writel(cfg, dev->regs + S5P_CITAREA);
+}
+
+static void fimc_hw_set_out_dma_size(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_frame *frame = &ctx->d_frame;
+ u32 cfg;
+
+ cfg = S5P_ORIG_SIZE_HOR(frame->f_width);
+ cfg |= S5P_ORIG_SIZE_VER(frame->f_height);
+ writel(cfg, dev->regs + S5P_ORGOSIZE);
+
+ /* Select color space conversion equation (HD/SD size).*/
+ cfg = readl(dev->regs + S5P_CIGCTRL);
+ if (frame->f_width >= 1280) /* HD */
+ cfg |= S5P_CIGCTRL_CSC_ITU601_709;
+ else /* SD */
+ cfg &= ~S5P_CIGCTRL_CSC_ITU601_709;
+ writel(cfg, dev->regs + S5P_CIGCTRL);
+
+}
+
+void fimc_hw_set_out_dma(struct fimc_ctx *ctx)
+{
+ u32 cfg;
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_frame *frame = &ctx->d_frame;
+ struct fimc_dma_offset *offset = &frame->dma_offset;
+
+ /* Set the input dma offsets. */
+ cfg = 0;
+ cfg |= S5P_CIO_OFFS_HOR(offset->y_h);
+ cfg |= S5P_CIO_OFFS_VER(offset->y_v);
+ writel(cfg, dev->regs + S5P_CIOYOFF);
+
+ cfg = 0;
+ cfg |= S5P_CIO_OFFS_HOR(offset->cb_h);
+ cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
+ writel(cfg, dev->regs + S5P_CIOCBOFF);
+
+ cfg = 0;
+ cfg |= S5P_CIO_OFFS_HOR(offset->cr_h);
+ cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
+ writel(cfg, dev->regs + S5P_CIOCROFF);
+
+ fimc_hw_set_out_dma_size(ctx);
+
+ /* Configure chroma components order. */
+ cfg = readl(dev->regs + S5P_CIOCTRL);
+
+ cfg &= ~(S5P_CIOCTRL_ORDER2P_MASK | S5P_CIOCTRL_ORDER422_MASK |
+ S5P_CIOCTRL_YCBCR_PLANE_MASK);
+
+ if (frame->fmt->planes_cnt == 1)
+ cfg |= ctx->out_order_1p;
+ else if (frame->fmt->planes_cnt == 2)
+ cfg |= ctx->out_order_2p | S5P_CIOCTRL_YCBCR_2PLANE;
+ else if (frame->fmt->planes_cnt == 3)
+ cfg |= S5P_CIOCTRL_YCBCR_3PLANE;
+
+ writel(cfg, dev->regs + S5P_CIOCTRL);
+}
+
+static void fimc_hw_en_autoload(struct fimc_dev *dev, int enable)
+{
+ u32 cfg = readl(dev->regs + S5P_ORGISIZE);
+ if (enable)
+ cfg |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+ else
+ cfg &= ~S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+ writel(cfg, dev->regs + S5P_ORGISIZE);
+}
+
+void fimc_hw_en_lastirq(struct fimc_dev *dev, int enable)
+{
+ u32 cfg = readl(dev->regs + S5P_CIOCTRL);
+ if (enable)
+ cfg |= S5P_CIOCTRL_LASTIRQ_ENABLE;
+ else
+ cfg &= ~S5P_CIOCTRL_LASTIRQ_ENABLE;
+ writel(cfg, dev->regs + S5P_CIOCTRL);
+}
+
+static void fimc_hw_set_prescaler(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_scaler *sc = &ctx->scaler;
+ u32 cfg, shfactor;
+
+ shfactor = 10 - (sc->hfactor + sc->vfactor);
+
+ cfg = S5P_CISCPRERATIO_SHFACTOR(shfactor);
+ cfg |= S5P_CISCPRERATIO_HOR(sc->pre_hratio);
+ cfg |= S5P_CISCPRERATIO_VER(sc->pre_vratio);
+ writel(cfg, dev->regs + S5P_CISCPRERATIO);
+
+ cfg = S5P_CISCPREDST_WIDTH(sc->pre_dst_width);
+ cfg |= S5P_CISCPREDST_HEIGHT(sc->pre_dst_height);
+ writel(cfg, dev->regs + S5P_CISCPREDST);
+}
+
+void fimc_hw_set_scaler(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_scaler *sc = &ctx->scaler;
+ struct fimc_frame *src_frame = &ctx->s_frame;
+ struct fimc_frame *dst_frame = &ctx->d_frame;
+ u32 cfg = 0;
+
+ fimc_hw_set_prescaler(ctx);
+
+ if (!(ctx->flags & FIMC_COLOR_RANGE_NARROW))
+ cfg |= (S5P_CISCCTRL_CSCR2Y_WIDE | S5P_CISCCTRL_CSCY2R_WIDE);
+
+ if (!sc->enabled)
+ cfg |= S5P_CISCCTRL_SCALERBYPASS;
+
+ if (sc->scaleup_h)
+ cfg |= S5P_CISCCTRL_SCALEUP_H;
+
+ if (sc->scaleup_v)
+ cfg |= S5P_CISCCTRL_SCALEUP_V;
+
+ if (sc->copy_mode)
+ cfg |= S5P_CISCCTRL_ONE2ONE;
+
+
+ if (ctx->in_path == FIMC_DMA) {
+ if (src_frame->fmt->color == S5P_FIMC_RGB565)
+ cfg |= S5P_CISCCTRL_INRGB_FMT_RGB565;
+ else if (src_frame->fmt->color == S5P_FIMC_RGB666)
+ cfg |= S5P_CISCCTRL_INRGB_FMT_RGB666;
+ else if (src_frame->fmt->color == S5P_FIMC_RGB888)
+ cfg |= S5P_CISCCTRL_INRGB_FMT_RGB888;
+ }
+
+ if (ctx->out_path == FIMC_DMA) {
+ if (dst_frame->fmt->color == S5P_FIMC_RGB565)
+ cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB565;
+ else if (dst_frame->fmt->color == S5P_FIMC_RGB666)
+ cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB666;
+ else if (dst_frame->fmt->color == S5P_FIMC_RGB888)
+ cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
+ } else {
+ cfg |= S5P_CISCCTRL_OUTRGB_FMT_RGB888;
+
+ if (ctx->flags & FIMC_SCAN_MODE_INTERLACED)
+ cfg |= S5P_CISCCTRL_INTERLACE;
+ }
+
+ dbg("main_hratio= 0x%X main_vratio= 0x%X",
+ sc->main_hratio, sc->main_vratio);
+
+ cfg |= S5P_CISCCTRL_SC_HORRATIO(sc->main_hratio);
+ cfg |= S5P_CISCCTRL_SC_VERRATIO(sc->main_vratio);
+
+ writel(cfg, dev->regs + S5P_CISCCTRL);
+}
+
+void fimc_hw_en_capture(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+
+ u32 cfg = readl(dev->regs + S5P_CIIMGCPT);
+
+ if (ctx->out_path == FIMC_DMA) {
+ /* one shot mode */
+ cfg |= S5P_CIIMGCPT_CPT_FREN_ENABLE | S5P_CIIMGCPT_IMGCPTEN;
+ } else {
+ /* Continous frame capture mode (freerun). */
+ cfg &= ~(S5P_CIIMGCPT_CPT_FREN_ENABLE |
+ S5P_CIIMGCPT_CPT_FRMOD_CNT);
+ cfg |= S5P_CIIMGCPT_IMGCPTEN;
+ }
+
+ if (ctx->scaler.enabled)
+ cfg |= S5P_CIIMGCPT_IMGCPTEN_SC;
+
+ writel(cfg | S5P_CIIMGCPT_IMGCPTEN, dev->regs + S5P_CIIMGCPT);
+}
+
+void fimc_hw_set_effect(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_effect *effect = &ctx->effect;
+ u32 cfg = (S5P_CIIMGEFF_IE_ENABLE | S5P_CIIMGEFF_IE_SC_AFTER);
+
+ cfg |= effect->type;
+
+ if (effect->type == S5P_FIMC_EFFECT_ARBITRARY) {
+ cfg |= S5P_CIIMGEFF_PAT_CB(effect->pat_cb);
+ cfg |= S5P_CIIMGEFF_PAT_CR(effect->pat_cr);
+ }
+
+ writel(cfg, dev->regs + S5P_CIIMGEFF);
+}
+
+static void fimc_hw_set_in_dma_size(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_frame *frame = &ctx->s_frame;
+ u32 cfg_o = 0;
+ u32 cfg_r = 0;
+
+ if (FIMC_LCDFIFO == ctx->out_path)
+ cfg_r |= S5P_CIREAL_ISIZE_AUTOLOAD_EN;
+
+ cfg_o |= S5P_ORIG_SIZE_HOR(frame->f_width);
+ cfg_o |= S5P_ORIG_SIZE_VER(frame->f_height);
+ cfg_r |= S5P_CIREAL_ISIZE_WIDTH(frame->width);
+ cfg_r |= S5P_CIREAL_ISIZE_HEIGHT(frame->height);
+
+ writel(cfg_o, dev->regs + S5P_ORGISIZE);
+ writel(cfg_r, dev->regs + S5P_CIREAL_ISIZE);
+}
+
+void fimc_hw_set_in_dma(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+ struct fimc_frame *frame = &ctx->s_frame;
+ struct fimc_dma_offset *offset = &frame->dma_offset;
+ u32 cfg;
+
+ /* Set the pixel offsets. */
+ cfg = S5P_CIO_OFFS_HOR(offset->y_h);
+ cfg |= S5P_CIO_OFFS_VER(offset->y_v);
+ writel(cfg, dev->regs + S5P_CIIYOFF);
+
+ cfg = S5P_CIO_OFFS_HOR(offset->cb_h);
+ cfg |= S5P_CIO_OFFS_VER(offset->cb_v);
+ writel(cfg, dev->regs + S5P_CIICBOFF);
+
+ cfg = S5P_CIO_OFFS_HOR(offset->cr_h);
+ cfg |= S5P_CIO_OFFS_VER(offset->cr_v);
+ writel(cfg, dev->regs + S5P_CIICROFF);
+
+ /* Input original and real size. */
+ fimc_hw_set_in_dma_size(ctx);
+
+ /* Use DMA autoload only in FIFO mode. */
+ fimc_hw_en_autoload(dev, ctx->out_path == FIMC_LCDFIFO);
+
+ /* Set the input DMA to process single frame only. */
+ cfg = readl(dev->regs + S5P_MSCTRL);
+ cfg &= ~(S5P_MSCTRL_FLIP_MASK
+ | S5P_MSCTRL_INFORMAT_MASK
+ | S5P_MSCTRL_IN_BURST_COUNT_MASK
+ | S5P_MSCTRL_INPUT_MASK
+ | S5P_MSCTRL_C_INT_IN_MASK
+ | S5P_MSCTRL_2P_IN_ORDER_MASK);
+
+ cfg |= (S5P_MSCTRL_FRAME_COUNT(1) | S5P_MSCTRL_INPUT_MEMORY);
+
+ switch (frame->fmt->color) {
+ case S5P_FIMC_RGB565:
+ case S5P_FIMC_RGB666:
+ case S5P_FIMC_RGB888:
+ cfg |= S5P_MSCTRL_INFORMAT_RGB;
+ break;
+ case S5P_FIMC_YCBCR420:
+ cfg |= S5P_MSCTRL_INFORMAT_YCBCR420;
+
+ if (frame->fmt->planes_cnt == 2)
+ cfg |= ctx->in_order_2p | S5P_MSCTRL_C_INT_IN_2PLANE;
+ else
+ cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
+
+ break;
+ case S5P_FIMC_YCBYCR422:
+ case S5P_FIMC_YCRYCB422:
+ case S5P_FIMC_CBYCRY422:
+ case S5P_FIMC_CRYCBY422:
+ if (frame->fmt->planes_cnt == 1) {
+ cfg |= ctx->in_order_1p
+ | S5P_MSCTRL_INFORMAT_YCBCR422_1P;
+ } else {
+ cfg |= S5P_MSCTRL_INFORMAT_YCBCR422;
+
+ if (frame->fmt->planes_cnt == 2)
+ cfg |= ctx->in_order_2p
+ | S5P_MSCTRL_C_INT_IN_2PLANE;
+ else
+ cfg |= S5P_MSCTRL_C_INT_IN_3PLANE;
+ }
+ break;
+ default:
+ break;
+ }
+
+ /*
+ * Input DMA flip mode (and rotation).
+ * Do not allow simultaneous rotation and flipping.
+ */
+ if (!ctx->rotation && ctx->out_path == FIMC_LCDFIFO)
+ cfg |= fimc_hw_get_in_flip(ctx->flip);
+
+ writel(cfg, dev->regs + S5P_MSCTRL);
+
+ /* Input/output DMA linear/tiled mode. */
+ cfg = readl(dev->regs + S5P_CIDMAPARAM);
+ cfg &= ~S5P_CIDMAPARAM_TILE_MASK;
+
+ if (tiled_fmt(ctx->s_frame.fmt))
+ cfg |= S5P_CIDMAPARAM_R_64X32;
+
+ if (tiled_fmt(ctx->d_frame.fmt))
+ cfg |= S5P_CIDMAPARAM_W_64X32;
+
+ writel(cfg, dev->regs + S5P_CIDMAPARAM);
+}
+
+
+void fimc_hw_set_input_path(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+
+ u32 cfg = readl(dev->regs + S5P_MSCTRL);
+ cfg &= ~S5P_MSCTRL_INPUT_MASK;
+
+ if (ctx->in_path == FIMC_DMA)
+ cfg |= S5P_MSCTRL_INPUT_MEMORY;
+ else
+ cfg |= S5P_MSCTRL_INPUT_EXTCAM;
+
+ writel(cfg, dev->regs + S5P_MSCTRL);
+}
+
+void fimc_hw_set_output_path(struct fimc_ctx *ctx)
+{
+ struct fimc_dev *dev = ctx->fimc_dev;
+
+ u32 cfg = readl(dev->regs + S5P_CISCCTRL);
+ cfg &= ~S5P_CISCCTRL_LCDPATHEN_FIFO;
+ if (ctx->out_path == FIMC_LCDFIFO)
+ cfg |= S5P_CISCCTRL_LCDPATHEN_FIFO;
+ writel(cfg, dev->regs + S5P_CISCCTRL);
+}
+
+void fimc_hw_set_input_addr(struct fimc_dev *dev, struct fimc_addr *paddr)
+{
+ u32 cfg = readl(dev->regs + S5P_CIREAL_ISIZE);
+ cfg |= S5P_CIREAL_ISIZE_ADDR_CH_DIS;
+ writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
+
+ writel(paddr->y, dev->regs + S5P_CIIYSA(0));
+ writel(paddr->cb, dev->regs + S5P_CIICBSA(0));
+ writel(paddr->cr, dev->regs + S5P_CIICRSA(0));
+
+ cfg &= ~S5P_CIREAL_ISIZE_ADDR_CH_DIS;
+ writel(cfg, dev->regs + S5P_CIREAL_ISIZE);
+}
+
+void fimc_hw_set_output_addr(struct fimc_dev *dev,
+ struct fimc_addr *paddr, int index)
+{
+ int i = (index == -1) ? 0 : index;
+ do {
+ writel(paddr->y, dev->regs + S5P_CIOYSA(i));
+ writel(paddr->cb, dev->regs + S5P_CIOCBSA(i));
+ writel(paddr->cr, dev->regs + S5P_CIOCRSA(i));
+ dbg("dst_buf[%d]: 0x%X, cb: 0x%X, cr: 0x%X",
+ i, paddr->y, paddr->cb, paddr->cr);
+ } while (index == -1 && ++i < FIMC_MAX_OUT_BUFS);
+}
+
+int fimc_hw_set_camera_polarity(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ u32 cfg = readl(fimc->regs + S5P_CIGCTRL);
+
+ cfg &= ~(S5P_CIGCTRL_INVPOLPCLK | S5P_CIGCTRL_INVPOLVSYNC |
+ S5P_CIGCTRL_INVPOLHREF | S5P_CIGCTRL_INVPOLHSYNC);
+
+ if (cam->flags & FIMC_CLK_INV_PCLK)
+ cfg |= S5P_CIGCTRL_INVPOLPCLK;
+
+ if (cam->flags & FIMC_CLK_INV_VSYNC)
+ cfg |= S5P_CIGCTRL_INVPOLVSYNC;
+
+ if (cam->flags & FIMC_CLK_INV_HREF)
+ cfg |= S5P_CIGCTRL_INVPOLHREF;
+
+ if (cam->flags & FIMC_CLK_INV_HSYNC)
+ cfg |= S5P_CIGCTRL_INVPOLHSYNC;
+
+ writel(cfg, fimc->regs + S5P_CIGCTRL);
+
+ return 0;
+}
+
+int fimc_hw_set_camera_source(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ struct fimc_frame *f = &fimc->vid_cap.ctx->s_frame;
+ u32 cfg = 0;
+
+ if (cam->bus_type == FIMC_ITU_601 || cam->bus_type == FIMC_ITU_656) {
+
+ switch (fimc->vid_cap.fmt.code) {
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_YCBYCR;
+ break;
+ case V4L2_MBUS_FMT_YVYU8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_YCRYCB;
+ break;
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_CRYCBY;
+ break;
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ cfg = S5P_CISRCFMT_ORDER422_CBYCRY;
+ break;
+ default:
+ err("camera image format not supported: %d",
+ fimc->vid_cap.fmt.code);
+ return -EINVAL;
+ }
+
+ if (cam->bus_type == FIMC_ITU_601) {
+ if (cam->bus_width == 8) {
+ cfg |= S5P_CISRCFMT_ITU601_8BIT;
+ } else if (cam->bus_width == 16) {
+ cfg |= S5P_CISRCFMT_ITU601_16BIT;
+ } else {
+ err("invalid bus width: %d", cam->bus_width);
+ return -EINVAL;
+ }
+ } /* else defaults to ITU-R BT.656 8-bit */
+ }
+
+ cfg |= S5P_CISRCFMT_HSIZE(f->o_width) | S5P_CISRCFMT_VSIZE(f->o_height);
+ writel(cfg, fimc->regs + S5P_CISRCFMT);
+ return 0;
+}
+
+
+int fimc_hw_set_camera_offset(struct fimc_dev *fimc, struct fimc_frame *f)
+{
+ u32 hoff2, voff2;
+
+ u32 cfg = readl(fimc->regs + S5P_CIWDOFST);
+
+ cfg &= ~(S5P_CIWDOFST_HOROFF_MASK | S5P_CIWDOFST_VEROFF_MASK);
+ cfg |= S5P_CIWDOFST_OFF_EN |
+ S5P_CIWDOFST_HOROFF(f->offs_h) |
+ S5P_CIWDOFST_VEROFF(f->offs_v);
+
+ writel(cfg, fimc->regs + S5P_CIWDOFST);
+
+ /* See CIWDOFSTn register description in the datasheet for details. */
+ hoff2 = f->o_width - f->width - f->offs_h;
+ voff2 = f->o_height - f->height - f->offs_v;
+ cfg = S5P_CIWDOFST2_HOROFF(hoff2) | S5P_CIWDOFST2_VEROFF(voff2);
+
+ writel(cfg, fimc->regs + S5P_CIWDOFST2);
+ return 0;
+}
+
+int fimc_hw_set_camera_type(struct fimc_dev *fimc,
+ struct s3c_fimc_isp_info *cam)
+{
+ u32 cfg, tmp;
+ struct fimc_vid_cap *vid_cap = &fimc->vid_cap;
+
+ cfg = readl(fimc->regs + S5P_CIGCTRL);
+
+ /* Select ITU B interface, disable Writeback path and test pattern. */
+ cfg &= ~(S5P_CIGCTRL_TESTPAT_MASK | S5P_CIGCTRL_SELCAM_ITU_A |
+ S5P_CIGCTRL_SELCAM_MIPI | S5P_CIGCTRL_CAMIF_SELWB |
+ S5P_CIGCTRL_SELCAM_MIPI_A);
+
+ if (cam->bus_type == FIMC_MIPI_CSI2) {
+ cfg |= S5P_CIGCTRL_SELCAM_MIPI;
+
+ if (cam->mux_id == 0)
+ cfg |= S5P_CIGCTRL_SELCAM_MIPI_A;
+
+ /* TODO: add remaining supported formats. */
+ if (vid_cap->fmt.code == V4L2_MBUS_FMT_VYUY8_2X8) {
+ tmp = S5P_CSIIMGFMT_YCBCR422_8BIT;
+ } else {
+ err("camera image format not supported: %d",
+ vid_cap->fmt.code);
+ return -EINVAL;
+ }
+ writel(tmp | (0x1 << 8), fimc->regs + S5P_CSIIMGFMT);
+
+ } else if (cam->bus_type == FIMC_ITU_601 ||
+ cam->bus_type == FIMC_ITU_656) {
+ if (cam->mux_id == 0) /* ITU-A, ITU-B: 0, 1 */
+ cfg |= S5P_CIGCTRL_SELCAM_ITU_A;
+ } else if (cam->bus_type == FIMC_LCD_WB) {
+ cfg |= S5P_CIGCTRL_CAMIF_SELWB;
+ } else {
+ err("invalid camera bus type selected\n");
+ return -EINVAL;
+ }
+ writel(cfg, fimc->regs + S5P_CIGCTRL);
+
+ return 0;
+}
diff --git a/drivers/media/video/s5p-fimc/regs-fimc.h b/drivers/media/video/s5p-fimc/regs-fimc.h
new file mode 100644
index 000000000000..57e33f84fcfa
--- /dev/null
+++ b/drivers/media/video/s5p-fimc/regs-fimc.h
@@ -0,0 +1,288 @@
+/*
+ * Register definition file for Samsung Camera Interface (FIMC) driver
+ *
+ * Copyright (c) 2010 Samsung Electronics
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef REGS_FIMC_H_
+#define REGS_FIMC_H_
+
+/* Input source format */
+#define S5P_CISRCFMT 0x00
+#define S5P_CISRCFMT_ITU601_8BIT (1 << 31)
+#define S5P_CISRCFMT_ITU601_16BIT (1 << 29)
+#define S5P_CISRCFMT_ORDER422_YCBYCR (0 << 14)
+#define S5P_CISRCFMT_ORDER422_YCRYCB (1 << 14)
+#define S5P_CISRCFMT_ORDER422_CBYCRY (2 << 14)
+#define S5P_CISRCFMT_ORDER422_CRYCBY (3 << 14)
+#define S5P_CISRCFMT_HSIZE(x) ((x) << 16)
+#define S5P_CISRCFMT_VSIZE(x) ((x) << 0)
+
+/* Window offset */
+#define S5P_CIWDOFST 0x04
+#define S5P_CIWDOFST_OFF_EN (1 << 31)
+#define S5P_CIWDOFST_CLROVFIY (1 << 30)
+#define S5P_CIWDOFST_CLROVRLB (1 << 29)
+#define S5P_CIWDOFST_HOROFF_MASK (0x7ff << 16)
+#define S5P_CIWDOFST_CLROVFICB (1 << 15)
+#define S5P_CIWDOFST_CLROVFICR (1 << 14)
+#define S5P_CIWDOFST_HOROFF(x) ((x) << 16)
+#define S5P_CIWDOFST_VEROFF(x) ((x) << 0)
+#define S5P_CIWDOFST_VEROFF_MASK (0xfff << 0)
+
+/* Global control */
+#define S5P_CIGCTRL 0x08
+#define S5P_CIGCTRL_SWRST (1 << 31)
+#define S5P_CIGCTRL_CAMRST_A (1 << 30)
+#define S5P_CIGCTRL_SELCAM_ITU_A (1 << 29)
+#define S5P_CIGCTRL_TESTPAT_NORMAL (0 << 27)
+#define S5P_CIGCTRL_TESTPAT_COLOR_BAR (1 << 27)
+#define S5P_CIGCTRL_TESTPAT_HOR_INC (2 << 27)
+#define S5P_CIGCTRL_TESTPAT_VER_INC (3 << 27)
+#define S5P_CIGCTRL_TESTPAT_MASK (3 << 27)
+#define S5P_CIGCTRL_TESTPAT_SHIFT (27)
+#define S5P_CIGCTRL_INVPOLPCLK (1 << 26)
+#define S5P_CIGCTRL_INVPOLVSYNC (1 << 25)
+#define S5P_CIGCTRL_INVPOLHREF (1 << 24)
+#define S5P_CIGCTRL_IRQ_OVFEN (1 << 22)
+#define S5P_CIGCTRL_HREF_MASK (1 << 21)
+#define S5P_CIGCTRL_IRQ_LEVEL (1 << 20)
+#define S5P_CIGCTRL_IRQ_CLR (1 << 19)
+#define S5P_CIGCTRL_IRQ_ENABLE (1 << 16)
+#define S5P_CIGCTRL_SHDW_DISABLE (1 << 12)
+#define S5P_CIGCTRL_SELCAM_MIPI_A (1 << 7)
+#define S5P_CIGCTRL_CAMIF_SELWB (1 << 6)
+/* 0 - ITU601; 1 - ITU709 */
+#define S5P_CIGCTRL_CSC_ITU601_709 (1 << 5)
+#define S5P_CIGCTRL_INVPOLHSYNC (1 << 4)
+#define S5P_CIGCTRL_SELCAM_MIPI (1 << 3)
+#define S5P_CIGCTRL_INTERLACE (1 << 0)
+
+/* Window offset 2 */
+#define S5P_CIWDOFST2 0x14
+#define S5P_CIWDOFST2_HOROFF_MASK (0xfff << 16)
+#define S5P_CIWDOFST2_VEROFF_MASK (0xfff << 0)
+#define S5P_CIWDOFST2_HOROFF(x) ((x) << 16)
+#define S5P_CIWDOFST2_VEROFF(x) ((x) << 0)
+
+/* Output DMA Y/Cb/Cr plane start addresses */
+#define S5P_CIOYSA(n) (0x18 + (n) * 4)
+#define S5P_CIOCBSA(n) (0x28 + (n) * 4)
+#define S5P_CIOCRSA(n) (0x38 + (n) * 4)
+
+/* Target image format */
+#define S5P_CITRGFMT 0x48
+#define S5P_CITRGFMT_INROT90 (1 << 31)
+#define S5P_CITRGFMT_YCBCR420 (0 << 29)
+#define S5P_CITRGFMT_YCBCR422 (1 << 29)
+#define S5P_CITRGFMT_YCBCR422_1P (2 << 29)
+#define S5P_CITRGFMT_RGB (3 << 29)
+#define S5P_CITRGFMT_FMT_MASK (3 << 29)
+#define S5P_CITRGFMT_HSIZE_MASK (0xfff << 16)
+#define S5P_CITRGFMT_FLIP_SHIFT (14)
+#define S5P_CITRGFMT_FLIP_NORMAL (0 << 14)
+#define S5P_CITRGFMT_FLIP_X_MIRROR (1 << 14)
+#define S5P_CITRGFMT_FLIP_Y_MIRROR (2 << 14)
+#define S5P_CITRGFMT_FLIP_180 (3 << 14)
+#define S5P_CITRGFMT_FLIP_MASK (3 << 14)
+#define S5P_CITRGFMT_OUTROT90 (1 << 13)
+#define S5P_CITRGFMT_VSIZE_MASK (0xfff << 0)
+#define S5P_CITRGFMT_HSIZE(x) ((x) << 16)
+#define S5P_CITRGFMT_VSIZE(x) ((x) << 0)
+
+/* Output DMA control */
+#define S5P_CIOCTRL 0x4c
+#define S5P_CIOCTRL_ORDER422_MASK (3 << 0)
+#define S5P_CIOCTRL_ORDER422_CRYCBY (0 << 0)
+#define S5P_CIOCTRL_ORDER422_YCRYCB (1 << 0)
+#define S5P_CIOCTRL_ORDER422_CBYCRY (2 << 0)
+#define S5P_CIOCTRL_ORDER422_YCBYCR (3 << 0)
+#define S5P_CIOCTRL_LASTIRQ_ENABLE (1 << 2)
+#define S5P_CIOCTRL_YCBCR_3PLANE (0 << 3)
+#define S5P_CIOCTRL_YCBCR_2PLANE (1 << 3)
+#define S5P_CIOCTRL_YCBCR_PLANE_MASK (1 << 3)
+#define S5P_CIOCTRL_ORDER2P_SHIFT (24)
+#define S5P_CIOCTRL_ORDER2P_MASK (3 << 24)
+#define S5P_CIOCTRL_ORDER422_2P_LSB_CRCB (0 << 24)
+
+/* Pre-scaler control 1 */
+#define S5P_CISCPRERATIO 0x50
+#define S5P_CISCPRERATIO_SHFACTOR(x) ((x) << 28)
+#define S5P_CISCPRERATIO_HOR(x) ((x) << 16)
+#define S5P_CISCPRERATIO_VER(x) ((x) << 0)
+
+#define S5P_CISCPREDST 0x54
+#define S5P_CISCPREDST_WIDTH(x) ((x) << 16)
+#define S5P_CISCPREDST_HEIGHT(x) ((x) << 0)
+
+/* Main scaler control */
+#define S5P_CISCCTRL 0x58
+#define S5P_CISCCTRL_SCALERBYPASS (1 << 31)
+#define S5P_CISCCTRL_SCALEUP_H (1 << 30)
+#define S5P_CISCCTRL_SCALEUP_V (1 << 29)
+#define S5P_CISCCTRL_CSCR2Y_WIDE (1 << 28)
+#define S5P_CISCCTRL_CSCY2R_WIDE (1 << 27)
+#define S5P_CISCCTRL_LCDPATHEN_FIFO (1 << 26)
+#define S5P_CISCCTRL_INTERLACE (1 << 25)
+#define S5P_CISCCTRL_SCALERSTART (1 << 15)
+#define S5P_CISCCTRL_INRGB_FMT_RGB565 (0 << 13)
+#define S5P_CISCCTRL_INRGB_FMT_RGB666 (1 << 13)
+#define S5P_CISCCTRL_INRGB_FMT_RGB888 (2 << 13)
+#define S5P_CISCCTRL_INRGB_FMT_MASK (3 << 13)
+#define S5P_CISCCTRL_OUTRGB_FMT_RGB565 (0 << 11)
+#define S5P_CISCCTRL_OUTRGB_FMT_RGB666 (1 << 11)
+#define S5P_CISCCTRL_OUTRGB_FMT_RGB888 (2 << 11)
+#define S5P_CISCCTRL_OUTRGB_FMT_MASK (3 << 11)
+#define S5P_CISCCTRL_RGB_EXT (1 << 10)
+#define S5P_CISCCTRL_ONE2ONE (1 << 9)
+#define S5P_CISCCTRL_SC_HORRATIO(x) ((x) << 16)
+#define S5P_CISCCTRL_SC_VERRATIO(x) ((x) << 0)
+
+/* Target area */
+#define S5P_CITAREA 0x5c
+#define S5P_CITAREA_MASK 0x0fffffff
+
+/* General status */
+#define S5P_CISTATUS 0x64
+#define S5P_CISTATUS_OVFIY (1 << 31)
+#define S5P_CISTATUS_OVFICB (1 << 30)
+#define S5P_CISTATUS_OVFICR (1 << 29)
+#define S5P_CISTATUS_VSYNC (1 << 28)
+#define S5P_CISTATUS_FRAMECNT_MASK (3 << 26)
+#define S5P_CISTATUS_FRAMECNT_SHIFT 26
+#define S5P_CISTATUS_WINOFF_EN (1 << 25)
+#define S5P_CISTATUS_IMGCPT_EN (1 << 22)
+#define S5P_CISTATUS_IMGCPT_SCEN (1 << 21)
+#define S5P_CISTATUS_VSYNC_A (1 << 20)
+#define S5P_CISTATUS_VSYNC_B (1 << 19)
+#define S5P_CISTATUS_OVRLB (1 << 18)
+#define S5P_CISTATUS_FRAME_END (1 << 17)
+#define S5P_CISTATUS_LASTCAPT_END (1 << 16)
+#define S5P_CISTATUS_VVALID_A (1 << 15)
+#define S5P_CISTATUS_VVALID_B (1 << 14)
+
+/* Indexes to the last and the currently processed buffer. */
+#define S5P_CISTATUS2 0x68
+
+/* Image capture control */
+#define S5P_CIIMGCPT 0xc0
+#define S5P_CIIMGCPT_IMGCPTEN (1 << 31)
+#define S5P_CIIMGCPT_IMGCPTEN_SC (1 << 30)
+#define S5P_CIIMGCPT_CPT_FREN_ENABLE (1 << 25)
+#define S5P_CIIMGCPT_CPT_FRMOD_CNT (1 << 18)
+
+/* Frame capture sequence */
+#define S5P_CICPTSEQ 0xc4
+
+/* Image effect */
+#define S5P_CIIMGEFF 0xd0
+#define S5P_CIIMGEFF_IE_DISABLE (0 << 30)
+#define S5P_CIIMGEFF_IE_ENABLE (1 << 30)
+#define S5P_CIIMGEFF_IE_SC_BEFORE (0 << 29)
+#define S5P_CIIMGEFF_IE_SC_AFTER (1 << 29)
+#define S5P_CIIMGEFF_FIN_BYPASS (0 << 26)
+#define S5P_CIIMGEFF_FIN_ARBITRARY (1 << 26)
+#define S5P_CIIMGEFF_FIN_NEGATIVE (2 << 26)
+#define S5P_CIIMGEFF_FIN_ARTFREEZE (3 << 26)
+#define S5P_CIIMGEFF_FIN_EMBOSSING (4 << 26)
+#define S5P_CIIMGEFF_FIN_SILHOUETTE (5 << 26)
+#define S5P_CIIMGEFF_FIN_MASK (7 << 26)
+#define S5P_CIIMGEFF_PAT_CBCR_MASK ((0xff < 13) | (0xff < 0))
+#define S5P_CIIMGEFF_PAT_CB(x) ((x) << 13)
+#define S5P_CIIMGEFF_PAT_CR(x) ((x) << 0)
+
+/* Input DMA Y/Cb/Cr plane start address 0/1 */
+#define S5P_CIIYSA(n) (0xd4 + (n) * 0x70)
+#define S5P_CIICBSA(n) (0xd8 + (n) * 0x70)
+#define S5P_CIICRSA(n) (0xdc + (n) * 0x70)
+
+/* Real input DMA image size */
+#define S5P_CIREAL_ISIZE 0xf8
+#define S5P_CIREAL_ISIZE_AUTOLOAD_EN (1 << 31)
+#define S5P_CIREAL_ISIZE_ADDR_CH_DIS (1 << 30)
+#define S5P_CIREAL_ISIZE_HEIGHT(x) ((x) << 16)
+#define S5P_CIREAL_ISIZE_WIDTH(x) ((x) << 0)
+
+
+/* Input DMA control */
+#define S5P_MSCTRL 0xfc
+#define S5P_MSCTRL_IN_BURST_COUNT_MASK (3 << 24)
+#define S5P_MSCTRL_2P_IN_ORDER_MASK (3 << 16)
+#define S5P_MSCTRL_2P_IN_ORDER_SHIFT 16
+#define S5P_MSCTRL_C_INT_IN_3PLANE (0 << 15)
+#define S5P_MSCTRL_C_INT_IN_2PLANE (1 << 15)
+#define S5P_MSCTRL_C_INT_IN_MASK (1 << 15)
+#define S5P_MSCTRL_FLIP_SHIFT 13
+#define S5P_MSCTRL_FLIP_MASK (3 << 13)
+#define S5P_MSCTRL_FLIP_NORMAL (0 << 13)
+#define S5P_MSCTRL_FLIP_X_MIRROR (1 << 13)
+#define S5P_MSCTRL_FLIP_Y_MIRROR (2 << 13)
+#define S5P_MSCTRL_FLIP_180 (3 << 13)
+#define S5P_MSCTRL_ORDER422_SHIFT 4
+#define S5P_MSCTRL_ORDER422_CRYCBY (0 << 4)
+#define S5P_MSCTRL_ORDER422_YCRYCB (1 << 4)
+#define S5P_MSCTRL_ORDER422_CBYCRY (2 << 4)
+#define S5P_MSCTRL_ORDER422_YCBYCR (3 << 4)
+#define S5P_MSCTRL_ORDER422_MASK (3 << 4)
+#define S5P_MSCTRL_INPUT_EXTCAM (0 << 3)
+#define S5P_MSCTRL_INPUT_MEMORY (1 << 3)
+#define S5P_MSCTRL_INPUT_MASK (1 << 3)
+#define S5P_MSCTRL_INFORMAT_YCBCR420 (0 << 1)
+#define S5P_MSCTRL_INFORMAT_YCBCR422 (1 << 1)
+#define S5P_MSCTRL_INFORMAT_YCBCR422_1P (2 << 1)
+#define S5P_MSCTRL_INFORMAT_RGB (3 << 1)
+#define S5P_MSCTRL_INFORMAT_MASK (3 << 1)
+#define S5P_MSCTRL_ENVID (1 << 0)
+#define S5P_MSCTRL_FRAME_COUNT(x) ((x) << 24)
+
+/* Output DMA Y/Cb/Cr offset */
+#define S5P_CIOYOFF 0x168
+#define S5P_CIOCBOFF 0x16c
+#define S5P_CIOCROFF 0x170
+
+/* Input DMA Y/Cb/Cr offset */
+#define S5P_CIIYOFF 0x174
+#define S5P_CIICBOFF 0x178
+#define S5P_CIICROFF 0x17c
+
+#define S5P_CIO_OFFS_VER(x) ((x) << 16)
+#define S5P_CIO_OFFS_HOR(x) ((x) << 0)
+
+/* Input DMA original image size */
+#define S5P_ORGISIZE 0x180
+
+/* Output DMA original image size */
+#define S5P_ORGOSIZE 0x184
+
+#define S5P_ORIG_SIZE_VER(x) ((x) << 16)
+#define S5P_ORIG_SIZE_HOR(x) ((x) << 0)
+
+/* Real output DMA image size (extension register) */
+#define S5P_CIEXTEN 0x188
+
+#define S5P_CIDMAPARAM 0x18c
+#define S5P_CIDMAPARAM_R_LINEAR (0 << 29)
+#define S5P_CIDMAPARAM_R_64X32 (3 << 29)
+#define S5P_CIDMAPARAM_W_LINEAR (0 << 13)
+#define S5P_CIDMAPARAM_W_64X32 (3 << 13)
+#define S5P_CIDMAPARAM_TILE_MASK ((3 << 29) | (3 << 13))
+
+/* MIPI CSI image format */
+#define S5P_CSIIMGFMT 0x194
+#define S5P_CSIIMGFMT_YCBCR422_8BIT 0x1e
+#define S5P_CSIIMGFMT_RAW8 0x2a
+#define S5P_CSIIMGFMT_RAW10 0x2b
+#define S5P_CSIIMGFMT_RAW12 0x2c
+#define S5P_CSIIMGFMT_USER1 0x30
+#define S5P_CSIIMGFMT_USER2 0x31
+#define S5P_CSIIMGFMT_USER3 0x32
+#define S5P_CSIIMGFMT_USER4 0x33
+
+/* Output frame buffer sequence mask */
+#define S5P_CIFCNTSEQ 0x1FC
+
+#endif /* REGS_FIMC_H_ */
diff --git a/drivers/media/video/saa5246a.c b/drivers/media/video/saa5246a.c
deleted file mode 100644
index 6b3b09ef8978..000000000000
--- a/drivers/media/video/saa5246a.c
+++ /dev/null
@@ -1,1123 +0,0 @@
-/*
- * Driver for the SAA5246A or SAA5281 Teletext (=Videotext) decoder chips from
- * Philips.
- *
- * Only capturing of Teletext pages is tested. The videotext chips also have a
- * TV output but my hardware doesn't use it. For this reason this driver does
- * not support changing any TV display settings.
- *
- * Copyright (C) 2004 Michael Geng <linux@MichaelGeng.de>
- *
- * Derived from
- *
- * saa5249 driver
- * Copyright (C) 1998 Richard Guenther
- * <richard.guenther@student.uni-tuebingen.de>
- *
- * with changes by
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * and
- *
- * vtx.c
- * Copyright (C) 1994-97 Martin Buck <martin-2.buck@student.uni-ulm.de>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/slab.h>
-#include <linux/mutex.h>
-#include <linux/videotext.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv.h>
-
-MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
-MODULE_DESCRIPTION("Philips SAA5246A, SAA5281 Teletext decoder driver");
-MODULE_LICENSE("GPL");
-
-#define MAJOR_VERSION 1 /* driver major version number */
-#define MINOR_VERSION 8 /* driver minor version number */
-
-/* Number of DAUs = number of pages that can be searched at the same time. */
-#define NUM_DAUS 4
-
-#define NUM_ROWS_PER_PAGE 40
-
-/* first column is 0 (not 1) */
-#define POS_TIME_START 32
-#define POS_TIME_END 39
-
-#define POS_HEADER_START 7
-#define POS_HEADER_END 31
-
-/* Returns 'true' if the part of the videotext page described with req contains
- (at least parts of) the time field */
-#define REQ_CONTAINS_TIME(p_req) \
- ((p_req)->start <= POS_TIME_END && \
- (p_req)->end >= POS_TIME_START)
-
-/* Returns 'true' if the part of the videotext page described with req contains
- (at least parts of) the page header */
-#define REQ_CONTAINS_HEADER(p_req) \
- ((p_req)->start <= POS_HEADER_END && \
- (p_req)->end >= POS_HEADER_START)
-
-/*****************************************************************************/
-/* Mode register numbers of the SAA5246A */
-/*****************************************************************************/
-#define SAA5246A_REGISTER_R0 0
-#define SAA5246A_REGISTER_R1 1
-#define SAA5246A_REGISTER_R2 2
-#define SAA5246A_REGISTER_R3 3
-#define SAA5246A_REGISTER_R4 4
-#define SAA5246A_REGISTER_R5 5
-#define SAA5246A_REGISTER_R6 6
-#define SAA5246A_REGISTER_R7 7
-#define SAA5246A_REGISTER_R8 8
-#define SAA5246A_REGISTER_R9 9
-#define SAA5246A_REGISTER_R10 10
-#define SAA5246A_REGISTER_R11 11
-#define SAA5246A_REGISTER_R11B 11
-
-/* SAA5246A mode registers often autoincrement to the next register.
- Therefore we use variable argument lists. The following macro indicates
- the end of a command list. */
-#define COMMAND_END (-1)
-
-/*****************************************************************************/
-/* Contents of the mode registers of the SAA5246A */
-/*****************************************************************************/
-/* Register R0 (Advanced Control) */
-#define R0_SELECT_R11 0x00
-#define R0_SELECT_R11B 0x01
-
-#define R0_PLL_TIME_CONSTANT_LONG 0x00
-#define R0_PLL_TIME_CONSTANT_SHORT 0x02
-
-#define R0_ENABLE_nODD_EVEN_OUTPUT 0x00
-#define R0_DISABLE_nODD_EVEN_OUTPUT 0x04
-
-#define R0_ENABLE_HDR_POLL 0x00
-#define R0_DISABLE_HDR_POLL 0x10
-
-#define R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x00
-#define R0_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED 0x20
-
-#define R0_NO_FREE_RUN_PLL 0x00
-#define R0_FREE_RUN_PLL 0x40
-
-#define R0_NO_AUTOMATIC_FASTEXT_PROMPT 0x00
-#define R0_AUTOMATIC_FASTEXT_PROMPT 0x80
-
-/* Register R1 (Mode) */
-#define R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES 0x00
-#define R1_NON_INTERLACED_312_313_LINES 0x01
-#define R1_NON_INTERLACED_312_312_LINES 0x02
-#define R1_FFB_LEADING_EDGE_IN_FIRST_BROAD_PULSE 0x03
-#define R1_FFB_LEADING_EDGE_IN_SECOND_BROAD_PULSE 0x07
-
-#define R1_DEW 0x00
-#define R1_FULL_FIELD 0x08
-
-#define R1_EXTENDED_PACKET_DISABLE 0x00
-#define R1_EXTENDED_PACKET_ENABLE 0x10
-
-#define R1_DAUS_ALL_ON 0x00
-#define R1_DAUS_ALL_OFF 0x20
-
-#define R1_7_BITS_PLUS_PARITY 0x00
-#define R1_8_BITS_NO_PARITY 0x40
-
-#define R1_VCS_TO_SCS 0x00
-#define R1_NO_VCS_TO_SCS 0x80
-
-/* Register R2 (Page request address) */
-#define R2_IN_R3_SELECT_PAGE_HUNDREDS 0x00
-#define R2_IN_R3_SELECT_PAGE_TENS 0x01
-#define R2_IN_R3_SELECT_PAGE_UNITS 0x02
-#define R2_IN_R3_SELECT_HOURS_TENS 0x03
-#define R2_IN_R3_SELECT_HOURS_UNITS 0x04
-#define R2_IN_R3_SELECT_MINUTES_TENS 0x05
-#define R2_IN_R3_SELECT_MINUTES_UNITS 0x06
-
-#define R2_DAU_0 0x00
-#define R2_DAU_1 0x10
-#define R2_DAU_2 0x20
-#define R2_DAU_3 0x30
-
-#define R2_BANK_0 0x00
-#define R2_BANK 1 0x40
-
-#define R2_HAMMING_CHECK_ON 0x80
-#define R2_HAMMING_CHECK_OFF 0x00
-
-/* Register R3 (Page request data) */
-#define R3_PAGE_HUNDREDS_0 0x00
-#define R3_PAGE_HUNDREDS_1 0x01
-#define R3_PAGE_HUNDREDS_2 0x02
-#define R3_PAGE_HUNDREDS_3 0x03
-#define R3_PAGE_HUNDREDS_4 0x04
-#define R3_PAGE_HUNDREDS_5 0x05
-#define R3_PAGE_HUNDREDS_6 0x06
-#define R3_PAGE_HUNDREDS_7 0x07
-
-#define R3_HOLD_PAGE 0x00
-#define R3_UPDATE_PAGE 0x08
-
-#define R3_PAGE_HUNDREDS_DO_NOT_CARE 0x00
-#define R3_PAGE_HUNDREDS_DO_CARE 0x10
-
-#define R3_PAGE_TENS_DO_NOT_CARE 0x00
-#define R3_PAGE_TENS_DO_CARE 0x10
-
-#define R3_PAGE_UNITS_DO_NOT_CARE 0x00
-#define R3_PAGE_UNITS_DO_CARE 0x10
-
-#define R3_HOURS_TENS_DO_NOT_CARE 0x00
-#define R3_HOURS_TENS_DO_CARE 0x10
-
-#define R3_HOURS_UNITS_DO_NOT_CARE 0x00
-#define R3_HOURS_UNITS_DO_CARE 0x10
-
-#define R3_MINUTES_TENS_DO_NOT_CARE 0x00
-#define R3_MINUTES_TENS_DO_CARE 0x10
-
-#define R3_MINUTES_UNITS_DO_NOT_CARE 0x00
-#define R3_MINUTES_UNITS_DO_CARE 0x10
-
-/* Register R4 (Display chapter) */
-#define R4_DISPLAY_PAGE_0 0x00
-#define R4_DISPLAY_PAGE_1 0x01
-#define R4_DISPLAY_PAGE_2 0x02
-#define R4_DISPLAY_PAGE_3 0x03
-#define R4_DISPLAY_PAGE_4 0x04
-#define R4_DISPLAY_PAGE_5 0x05
-#define R4_DISPLAY_PAGE_6 0x06
-#define R4_DISPLAY_PAGE_7 0x07
-
-/* Register R5 (Normal display control) */
-#define R5_PICTURE_INSIDE_BOXING_OFF 0x00
-#define R5_PICTURE_INSIDE_BOXING_ON 0x01
-
-#define R5_PICTURE_OUTSIDE_BOXING_OFF 0x00
-#define R5_PICTURE_OUTSIDE_BOXING_ON 0x02
-
-#define R5_TEXT_INSIDE_BOXING_OFF 0x00
-#define R5_TEXT_INSIDE_BOXING_ON 0x04
-
-#define R5_TEXT_OUTSIDE_BOXING_OFF 0x00
-#define R5_TEXT_OUTSIDE_BOXING_ON 0x08
-
-#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_OFF 0x00
-#define R5_CONTRAST_REDUCTION_INSIDE_BOXING_ON 0x10
-
-#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00
-#define R5_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON 0x20
-
-#define R5_BACKGROUND_COLOR_INSIDE_BOXING_OFF 0x00
-#define R5_BACKGROUND_COLOR_INSIDE_BOXING_ON 0x40
-
-#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF 0x00
-#define R5_BACKGROUND_COLOR_OUTSIDE_BOXING_ON 0x80
-
-/* Register R6 (Newsflash display) */
-#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_PICTURE_INSIDE_BOXING_ON 0x01
-
-#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_PICTURE_OUTSIDE_BOXING_ON 0x02
-
-#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_TEXT_INSIDE_BOXING_ON 0x04
-
-#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_TEXT_OUTSIDE_BOXING_ON 0x08
-
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_INSIDE_BOXING_ON 0x10
-
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_CONTRAST_REDUCTION_OUTSIDE_BOXING_ON 0x20
-
-#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_BACKGROUND_COLOR_INSIDE_BOXING_ON 0x40
-
-#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_OFF 0x00
-#define R6_NEWSFLASH_BACKGROUND_COLOR_OUTSIDE_BOXING_ON 0x80
-
-/* Register R7 (Display mode) */
-#define R7_BOX_OFF_ROW_0 0x00
-#define R7_BOX_ON_ROW_0 0x01
-
-#define R7_BOX_OFF_ROW_1_TO_23 0x00
-#define R7_BOX_ON_ROW_1_TO_23 0x02
-
-#define R7_BOX_OFF_ROW_24 0x00
-#define R7_BOX_ON_ROW_24 0x04
-
-#define R7_SINGLE_HEIGHT 0x00
-#define R7_DOUBLE_HEIGHT 0x08
-
-#define R7_TOP_HALF 0x00
-#define R7_BOTTOM_HALF 0x10
-
-#define R7_REVEAL_OFF 0x00
-#define R7_REVEAL_ON 0x20
-
-#define R7_CURSER_OFF 0x00
-#define R7_CURSER_ON 0x40
-
-#define R7_STATUS_BOTTOM 0x00
-#define R7_STATUS_TOP 0x80
-
-/* Register R8 (Active chapter) */
-#define R8_ACTIVE_CHAPTER_0 0x00
-#define R8_ACTIVE_CHAPTER_1 0x01
-#define R8_ACTIVE_CHAPTER_2 0x02
-#define R8_ACTIVE_CHAPTER_3 0x03
-#define R8_ACTIVE_CHAPTER_4 0x04
-#define R8_ACTIVE_CHAPTER_5 0x05
-#define R8_ACTIVE_CHAPTER_6 0x06
-#define R8_ACTIVE_CHAPTER_7 0x07
-
-#define R8_CLEAR_MEMORY 0x08
-#define R8_DO_NOT_CLEAR_MEMORY 0x00
-
-/* Register R9 (Curser row) */
-#define R9_CURSER_ROW_0 0x00
-#define R9_CURSER_ROW_1 0x01
-#define R9_CURSER_ROW_2 0x02
-#define R9_CURSER_ROW_25 0x19
-
-/* Register R10 (Curser column) */
-#define R10_CURSER_COLUMN_0 0x00
-#define R10_CURSER_COLUMN_6 0x06
-#define R10_CURSER_COLUMN_8 0x08
-
-/*****************************************************************************/
-/* Row 25 control data in column 0 to 9 */
-/*****************************************************************************/
-#define ROW25_COLUMN0_PAGE_UNITS 0x0F
-
-#define ROW25_COLUMN1_PAGE_TENS 0x0F
-
-#define ROW25_COLUMN2_MINUTES_UNITS 0x0F
-
-#define ROW25_COLUMN3_MINUTES_TENS 0x07
-#define ROW25_COLUMN3_DELETE_PAGE 0x08
-
-#define ROW25_COLUMN4_HOUR_UNITS 0x0F
-
-#define ROW25_COLUMN5_HOUR_TENS 0x03
-#define ROW25_COLUMN5_INSERT_HEADLINE 0x04
-#define ROW25_COLUMN5_INSERT_SUBTITLE 0x08
-
-#define ROW25_COLUMN6_SUPPRESS_HEADER 0x01
-#define ROW25_COLUMN6_UPDATE_PAGE 0x02
-#define ROW25_COLUMN6_INTERRUPTED_SEQUENCE 0x04
-#define ROW25_COLUMN6_SUPPRESS_DISPLAY 0x08
-
-#define ROW25_COLUMN7_SERIAL_MODE 0x01
-#define ROW25_COLUMN7_CHARACTER_SET 0x0E
-
-#define ROW25_COLUMN8_PAGE_HUNDREDS 0x07
-#define ROW25_COLUMN8_PAGE_NOT_FOUND 0x10
-
-#define ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR 0x20
-
-#define ROW25_COLUMN0_TO_7_HAMMING_ERROR 0x10
-
-/*****************************************************************************/
-/* Helper macros for extracting page, hour and minute digits */
-/*****************************************************************************/
-/* BYTE_POS 0 is at row 0, column 0,
- BYTE_POS 1 is at row 0, column 1,
- BYTE_POS 40 is at row 1, column 0, (with NUM_ROWS_PER_PAGE = 40)
- BYTE_POS 41 is at row 1, column 1, (with NUM_ROWS_PER_PAGE = 40),
- ... */
-#define ROW(BYTE_POS) (BYTE_POS / NUM_ROWS_PER_PAGE)
-#define COLUMN(BYTE_POS) (BYTE_POS % NUM_ROWS_PER_PAGE)
-
-/*****************************************************************************/
-/* Helper macros for extracting page, hour and minute digits */
-/*****************************************************************************/
-/* Macros for extracting hundreds, tens and units of a page number which
- must be in the range 0 ... 0x799.
- Note that page is coded in hexadecimal, i.e. 0x123 means page 123.
- page 0x.. means page 8.. */
-#define HUNDREDS_OF_PAGE(page) (((page) / 0x100) & 0x7)
-#define TENS_OF_PAGE(page) (((page) / 0x10) & 0xF)
-#define UNITS_OF_PAGE(page) ((page) & 0xF)
-
-/* Macros for extracting tens and units of a hour information which
- must be in the range 0 ... 0x24.
- Note that hour is coded in hexadecimal, i.e. 0x12 means 12 hours */
-#define TENS_OF_HOUR(hour) ((hour) / 0x10)
-#define UNITS_OF_HOUR(hour) ((hour) & 0xF)
-
-/* Macros for extracting tens and units of a minute information which
- must be in the range 0 ... 0x59.
- Note that minute is coded in hexadecimal, i.e. 0x12 means 12 minutes */
-#define TENS_OF_MINUTE(minute) ((minute) / 0x10)
-#define UNITS_OF_MINUTE(minute) ((minute) & 0xF)
-
-#define HOUR_MAX 0x23
-#define MINUTE_MAX 0x59
-#define PAGE_MAX 0x8FF
-
-
-struct saa5246a_device
-{
- struct v4l2_subdev sd;
- struct video_device *vdev;
- u8 pgbuf[NUM_DAUS][VTX_VIRTUALSIZE];
- int is_searching[NUM_DAUS];
- unsigned long in_use;
- struct mutex lock;
-};
-
-static inline struct saa5246a_device *to_dev(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct saa5246a_device, sd);
-}
-
-static struct video_device saa_template; /* Declared near bottom */
-
-/*
- * I2C interfaces
- */
-
-static int i2c_sendbuf(struct saa5246a_device *t, int reg, int count, u8 *data)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
- char buf[64];
-
- buf[0] = reg;
- memcpy(buf+1, data, count);
-
- if (i2c_master_send(client, buf, count + 1) == count + 1)
- return 0;
- return -1;
-}
-
-static int i2c_senddata(struct saa5246a_device *t, ...)
-{
- unsigned char buf[64];
- int v;
- int ct = 0;
- va_list argp;
- va_start(argp, t);
-
- while ((v = va_arg(argp, int)) != -1)
- buf[ct++] = v;
-
- va_end(argp);
- return i2c_sendbuf(t, buf[0], ct-1, buf+1);
-}
-
-/* Get count number of bytes from I²C-device at address adr, store them in buf.
- * Start & stop handshaking is done by this routine, ack will be sent after the
- * last byte to inhibit further sending of data. If uaccess is 'true', data is
- * written to user-space with put_user. Returns -1 if I²C-device didn't send
- * acknowledge, 0 otherwise
- */
-static int i2c_getdata(struct saa5246a_device *t, int count, u8 *buf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
-
- if (i2c_master_recv(client, buf, count) != count)
- return -1;
- return 0;
-}
-
-/* When a page is found then the not FOUND bit in one of the status registers
- * of the SAA5264A chip is cleared. Unfortunately this bit is not set
- * automatically when a new page is requested. Instead this function must be
- * called after a page has been requested.
- *
- * Return value: 0 if successful
- */
-static int saa5246a_clear_found_bit(struct saa5246a_device *t,
- unsigned char dau_no)
-{
- unsigned char row_25_column_8;
-
- if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-
- dau_no |
- R8_DO_NOT_CLEAR_MEMORY,
-
- R9_CURSER_ROW_25,
-
- R10_CURSER_COLUMN_8,
-
- COMMAND_END) ||
- i2c_getdata(t, 1, &row_25_column_8))
- {
- return -EIO;
- }
- row_25_column_8 |= ROW25_COLUMN8_PAGE_NOT_FOUND;
- if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-
- dau_no |
- R8_DO_NOT_CLEAR_MEMORY,
-
- R9_CURSER_ROW_25,
-
- R10_CURSER_COLUMN_8,
-
- row_25_column_8,
-
- COMMAND_END))
- {
- return -EIO;
- }
-
- return 0;
-}
-
-/* Requests one videotext page as described in req. The fields of req are
- * checked and an error is returned if something is invalid.
- *
- * Return value: 0 if successful
- */
-static int saa5246a_request_page(struct saa5246a_device *t,
- vtx_pagereq_t *req)
-{
- if (req->pagemask < 0 || req->pagemask >= PGMASK_MAX)
- return -EINVAL;
- if (req->pagemask & PGMASK_PAGE)
- if (req->page < 0 || req->page > PAGE_MAX)
- return -EINVAL;
- if (req->pagemask & PGMASK_HOUR)
- if (req->hour < 0 || req->hour > HOUR_MAX)
- return -EINVAL;
- if (req->pagemask & PGMASK_MINUTE)
- if (req->minute < 0 || req->minute > MINUTE_MAX)
- return -EINVAL;
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
- return -EINVAL;
-
- if (i2c_senddata(t, SAA5246A_REGISTER_R2,
-
- R2_IN_R3_SELECT_PAGE_HUNDREDS |
- req->pgbuf << 4 |
- R2_BANK_0 |
- R2_HAMMING_CHECK_OFF,
-
- HUNDREDS_OF_PAGE(req->page) |
- R3_HOLD_PAGE |
- (req->pagemask & PG_HUND ?
- R3_PAGE_HUNDREDS_DO_CARE :
- R3_PAGE_HUNDREDS_DO_NOT_CARE),
-
- TENS_OF_PAGE(req->page) |
- (req->pagemask & PG_TEN ?
- R3_PAGE_TENS_DO_CARE :
- R3_PAGE_TENS_DO_NOT_CARE),
-
- UNITS_OF_PAGE(req->page) |
- (req->pagemask & PG_UNIT ?
- R3_PAGE_UNITS_DO_CARE :
- R3_PAGE_UNITS_DO_NOT_CARE),
-
- TENS_OF_HOUR(req->hour) |
- (req->pagemask & HR_TEN ?
- R3_HOURS_TENS_DO_CARE :
- R3_HOURS_TENS_DO_NOT_CARE),
-
- UNITS_OF_HOUR(req->hour) |
- (req->pagemask & HR_UNIT ?
- R3_HOURS_UNITS_DO_CARE :
- R3_HOURS_UNITS_DO_NOT_CARE),
-
- TENS_OF_MINUTE(req->minute) |
- (req->pagemask & MIN_TEN ?
- R3_MINUTES_TENS_DO_CARE :
- R3_MINUTES_TENS_DO_NOT_CARE),
-
- UNITS_OF_MINUTE(req->minute) |
- (req->pagemask & MIN_UNIT ?
- R3_MINUTES_UNITS_DO_CARE :
- R3_MINUTES_UNITS_DO_NOT_CARE),
-
- COMMAND_END) || i2c_senddata(t, SAA5246A_REGISTER_R2,
-
- R2_IN_R3_SELECT_PAGE_HUNDREDS |
- req->pgbuf << 4 |
- R2_BANK_0 |
- R2_HAMMING_CHECK_OFF,
-
- HUNDREDS_OF_PAGE(req->page) |
- R3_UPDATE_PAGE |
- (req->pagemask & PG_HUND ?
- R3_PAGE_HUNDREDS_DO_CARE :
- R3_PAGE_HUNDREDS_DO_NOT_CARE),
-
- COMMAND_END))
- {
- return -EIO;
- }
-
- t->is_searching[req->pgbuf] = true;
- return 0;
-}
-
-/* This routine decodes the page number from the infobits contained in line 25.
- *
- * Parameters:
- * infobits: must be bits 0 to 9 of column 25
- *
- * Return value: page number coded in hexadecimal, i. e. page 123 is coded 0x123
- */
-static inline int saa5246a_extract_pagenum_from_infobits(
- unsigned char infobits[10])
-{
- int page_hundreds, page_tens, page_units;
-
- page_units = infobits[0] & ROW25_COLUMN0_PAGE_UNITS;
- page_tens = infobits[1] & ROW25_COLUMN1_PAGE_TENS;
- page_hundreds = infobits[8] & ROW25_COLUMN8_PAGE_HUNDREDS;
-
- /* page 0x.. means page 8.. */
- if (page_hundreds == 0)
- page_hundreds = 8;
-
- return((page_hundreds << 8) | (page_tens << 4) | page_units);
-}
-
-/* Decodes the hour from the infobits contained in line 25.
- *
- * Parameters:
- * infobits: must be bits 0 to 9 of column 25
- *
- * Return: hour coded in hexadecimal, i. e. 12h is coded 0x12
- */
-static inline int saa5246a_extract_hour_from_infobits(
- unsigned char infobits[10])
-{
- int hour_tens, hour_units;
-
- hour_units = infobits[4] & ROW25_COLUMN4_HOUR_UNITS;
- hour_tens = infobits[5] & ROW25_COLUMN5_HOUR_TENS;
-
- return((hour_tens << 4) | hour_units);
-}
-
-/* Decodes the minutes from the infobits contained in line 25.
- *
- * Parameters:
- * infobits: must be bits 0 to 9 of column 25
- *
- * Return: minutes coded in hexadecimal, i. e. 10min is coded 0x10
- */
-static inline int saa5246a_extract_minutes_from_infobits(
- unsigned char infobits[10])
-{
- int minutes_tens, minutes_units;
-
- minutes_units = infobits[2] & ROW25_COLUMN2_MINUTES_UNITS;
- minutes_tens = infobits[3] & ROW25_COLUMN3_MINUTES_TENS;
-
- return((minutes_tens << 4) | minutes_units);
-}
-
-/* Reads the status bits contained in the first 10 columns of the first line
- * and extracts the information into info.
- *
- * Return value: 0 if successful
- */
-static inline int saa5246a_get_status(struct saa5246a_device *t,
- vtx_pageinfo_t *info, unsigned char dau_no)
-{
- unsigned char infobits[10];
- int column;
-
- if (dau_no >= NUM_DAUS)
- return -EINVAL;
-
- if (i2c_senddata(t, SAA5246A_REGISTER_R8,
-
- dau_no |
- R8_DO_NOT_CLEAR_MEMORY,
-
- R9_CURSER_ROW_25,
-
- R10_CURSER_COLUMN_0,
-
- COMMAND_END) ||
- i2c_getdata(t, 10, infobits))
- {
- return -EIO;
- }
-
- info->pagenum = saa5246a_extract_pagenum_from_infobits(infobits);
- info->hour = saa5246a_extract_hour_from_infobits(infobits);
- info->minute = saa5246a_extract_minutes_from_infobits(infobits);
- info->charset = ((infobits[7] & ROW25_COLUMN7_CHARACTER_SET) >> 1);
- info->delete = !!(infobits[3] & ROW25_COLUMN3_DELETE_PAGE);
- info->headline = !!(infobits[5] & ROW25_COLUMN5_INSERT_HEADLINE);
- info->subtitle = !!(infobits[5] & ROW25_COLUMN5_INSERT_SUBTITLE);
- info->supp_header = !!(infobits[6] & ROW25_COLUMN6_SUPPRESS_HEADER);
- info->update = !!(infobits[6] & ROW25_COLUMN6_UPDATE_PAGE);
- info->inter_seq = !!(infobits[6] & ROW25_COLUMN6_INTERRUPTED_SEQUENCE);
- info->dis_disp = !!(infobits[6] & ROW25_COLUMN6_SUPPRESS_DISPLAY);
- info->serial = !!(infobits[7] & ROW25_COLUMN7_SERIAL_MODE);
- info->notfound = !!(infobits[8] & ROW25_COLUMN8_PAGE_NOT_FOUND);
- info->pblf = !!(infobits[9] & ROW25_COLUMN9_PAGE_BEING_LOOKED_FOR);
- info->hamming = 0;
- for (column = 0; column <= 7; column++) {
- if (infobits[column] & ROW25_COLUMN0_TO_7_HAMMING_ERROR) {
- info->hamming = 1;
- break;
- }
- }
- if (!info->hamming && !info->notfound)
- t->is_searching[dau_no] = false;
- return 0;
-}
-
-/* Reads 1 videotext page buffer of the SAA5246A.
- *
- * req is used both as input and as output. It contains information which part
- * must be read. The videotext page is copied into req->buffer.
- *
- * Return value: 0 if successful
- */
-static inline int saa5246a_get_page(struct saa5246a_device *t,
- vtx_pagereq_t *req)
-{
- int start, end, size;
- char *buf;
- int err;
-
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS ||
- req->start < 0 || req->start > req->end || req->end >= VTX_PAGESIZE)
- return -EINVAL;
-
- buf = kmalloc(VTX_PAGESIZE, GFP_KERNEL);
- if (!buf)
- return -ENOMEM;
-
- /* Read "normal" part of page */
- err = -EIO;
-
- end = min(req->end, VTX_PAGESIZE - 1);
- if (i2c_senddata(t, SAA5246A_REGISTER_R8,
- req->pgbuf | R8_DO_NOT_CLEAR_MEMORY,
- ROW(req->start), COLUMN(req->start), COMMAND_END))
- goto out;
- if (i2c_getdata(t, end - req->start + 1, buf))
- goto out;
- err = -EFAULT;
- if (copy_to_user(req->buffer, buf, end - req->start + 1))
- goto out;
-
- /* Always get the time from buffer 4, since this stupid SAA5246A only
- * updates the currently displayed buffer...
- */
- if (REQ_CONTAINS_TIME(req)) {
- start = max(req->start, POS_TIME_START);
- end = min(req->end, POS_TIME_END);
- size = end - start + 1;
- err = -EINVAL;
- if (size < 0)
- goto out;
- err = -EIO;
- if (i2c_senddata(t, SAA5246A_REGISTER_R8,
- R8_ACTIVE_CHAPTER_4 | R8_DO_NOT_CLEAR_MEMORY,
- R9_CURSER_ROW_0, start, COMMAND_END))
- goto out;
- if (i2c_getdata(t, size, buf))
- goto out;
- err = -EFAULT;
- if (copy_to_user(req->buffer + start - req->start, buf, size))
- goto out;
- }
- /* Insert the header from buffer 4 only, if acquisition circuit is still searching for a page */
- if (REQ_CONTAINS_HEADER(req) && t->is_searching[req->pgbuf]) {
- start = max(req->start, POS_HEADER_START);
- end = min(req->end, POS_HEADER_END);
- size = end - start + 1;
- err = -EINVAL;
- if (size < 0)
- goto out;
- err = -EIO;
- if (i2c_senddata(t, SAA5246A_REGISTER_R8,
- R8_ACTIVE_CHAPTER_4 | R8_DO_NOT_CLEAR_MEMORY,
- R9_CURSER_ROW_0, start, COMMAND_END))
- goto out;
- if (i2c_getdata(t, end - start + 1, buf))
- goto out;
- err = -EFAULT;
- if (copy_to_user(req->buffer + start - req->start, buf, size))
- goto out;
- }
- err = 0;
-out:
- kfree(buf);
- return err;
-}
-
-/* Stops the acquisition circuit given in dau_no. The page buffer associated
- * with this acquisition circuit will no more be updated. The other daus are
- * not affected.
- *
- * Return value: 0 if successful
- */
-static inline int saa5246a_stop_dau(struct saa5246a_device *t,
- unsigned char dau_no)
-{
- if (dau_no >= NUM_DAUS)
- return -EINVAL;
- if (i2c_senddata(t, SAA5246A_REGISTER_R2,
-
- R2_IN_R3_SELECT_PAGE_HUNDREDS |
- dau_no << 4 |
- R2_BANK_0 |
- R2_HAMMING_CHECK_OFF,
-
- R3_PAGE_HUNDREDS_0 |
- R3_HOLD_PAGE |
- R3_PAGE_HUNDREDS_DO_NOT_CARE,
-
- COMMAND_END))
- {
- return -EIO;
- }
- t->is_searching[dau_no] = false;
- return 0;
-}
-
-/* Handles ioctls defined in videotext.h
- *
- * Returns 0 if successful
- */
-static long do_saa5246a_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
- struct saa5246a_device *t = video_drvdata(file);
-
- switch(cmd)
- {
- case VTXIOCGETINFO:
- {
- vtx_info_t *info = arg;
-
- info->version_major = MAJOR_VERSION;
- info->version_minor = MINOR_VERSION;
- info->numpages = NUM_DAUS;
- return 0;
- }
-
- case VTXIOCCLRPAGE:
- {
- vtx_pagereq_t *req = arg;
-
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
- return -EINVAL;
- memset(t->pgbuf[req->pgbuf], ' ', sizeof(t->pgbuf[0]));
- return 0;
- }
-
- case VTXIOCCLRFOUND:
- {
- vtx_pagereq_t *req = arg;
-
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
- return -EINVAL;
- return(saa5246a_clear_found_bit(t, req->pgbuf));
- }
-
- case VTXIOCPAGEREQ:
- {
- vtx_pagereq_t *req = arg;
-
- return(saa5246a_request_page(t, req));
- }
-
- case VTXIOCGETSTAT:
- {
- vtx_pagereq_t *req = arg;
- vtx_pageinfo_t info;
- int rval;
-
- if ((rval = saa5246a_get_status(t, &info, req->pgbuf)))
- return rval;
- if(copy_to_user(req->buffer, &info,
- sizeof(vtx_pageinfo_t)))
- return -EFAULT;
- return 0;
- }
-
- case VTXIOCGETPAGE:
- {
- vtx_pagereq_t *req = arg;
-
- return(saa5246a_get_page(t, req));
- }
-
- case VTXIOCSTOPDAU:
- {
- vtx_pagereq_t *req = arg;
-
- return(saa5246a_stop_dau(t, req->pgbuf));
- }
-
- case VTXIOCPUTPAGE:
- case VTXIOCSETDISP:
- case VTXIOCPUTSTAT:
- return 0;
-
- case VTXIOCCLRCACHE:
- {
- return 0;
- }
-
- case VTXIOCSETVIRT:
- {
- /* I do not know what "virtual mode" means */
- return 0;
- }
- }
- return -EINVAL;
-}
-
-/*
- * Translates old vtx IOCTLs to new ones
- *
- * This keeps new kernel versions compatible with old userspace programs.
- */
-static inline unsigned int vtx_fix_command(unsigned int cmd)
-{
- switch (cmd) {
- case VTXIOCGETINFO_OLD:
- cmd = VTXIOCGETINFO;
- break;
- case VTXIOCCLRPAGE_OLD:
- cmd = VTXIOCCLRPAGE;
- break;
- case VTXIOCCLRFOUND_OLD:
- cmd = VTXIOCCLRFOUND;
- break;
- case VTXIOCPAGEREQ_OLD:
- cmd = VTXIOCPAGEREQ;
- break;
- case VTXIOCGETSTAT_OLD:
- cmd = VTXIOCGETSTAT;
- break;
- case VTXIOCGETPAGE_OLD:
- cmd = VTXIOCGETPAGE;
- break;
- case VTXIOCSTOPDAU_OLD:
- cmd = VTXIOCSTOPDAU;
- break;
- case VTXIOCPUTPAGE_OLD:
- cmd = VTXIOCPUTPAGE;
- break;
- case VTXIOCSETDISP_OLD:
- cmd = VTXIOCSETDISP;
- break;
- case VTXIOCPUTSTAT_OLD:
- cmd = VTXIOCPUTSTAT;
- break;
- case VTXIOCCLRCACHE_OLD:
- cmd = VTXIOCCLRCACHE;
- break;
- case VTXIOCSETVIRT_OLD:
- cmd = VTXIOCSETVIRT;
- break;
- }
- return cmd;
-}
-
-/*
- * Handle the locking
- */
-static long saa5246a_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct saa5246a_device *t = video_drvdata(file);
- long err;
-
- cmd = vtx_fix_command(cmd);
- mutex_lock(&t->lock);
- err = video_usercopy(file, cmd, arg, do_saa5246a_ioctl);
- mutex_unlock(&t->lock);
- return err;
-}
-
-static int saa5246a_open(struct file *file)
-{
- struct saa5246a_device *t = video_drvdata(file);
-
- if (test_and_set_bit(0, &t->in_use))
- return -EBUSY;
-
- if (i2c_senddata(t, SAA5246A_REGISTER_R0,
- R0_SELECT_R11 |
- R0_PLL_TIME_CONSTANT_LONG |
- R0_ENABLE_nODD_EVEN_OUTPUT |
- R0_ENABLE_HDR_POLL |
- R0_DO_NOT_FORCE_nODD_EVEN_LOW_IF_PICTURE_DISPLAYED |
- R0_NO_FREE_RUN_PLL |
- R0_NO_AUTOMATIC_FASTEXT_PROMPT,
-
- R1_NON_INTERLACED_312_312_LINES |
- R1_DEW |
- R1_EXTENDED_PACKET_DISABLE |
- R1_DAUS_ALL_ON |
- R1_8_BITS_NO_PARITY |
- R1_VCS_TO_SCS,
-
- COMMAND_END) ||
- i2c_senddata(t, SAA5246A_REGISTER_R4,
-
- /* We do not care much for the TV display but nevertheless we
- * need the currently displayed page later because only on that
- * page the time is updated. */
- R4_DISPLAY_PAGE_4,
-
- COMMAND_END))
- {
- clear_bit(0, &t->in_use);
- return -EIO;
- }
- return 0;
-}
-
-static int saa5246a_release(struct file *file)
-{
- struct saa5246a_device *t = video_drvdata(file);
-
- /* Stop all acquisition circuits. */
- i2c_senddata(t, SAA5246A_REGISTER_R1,
-
- R1_INTERLACED_312_AND_HALF_312_AND_HALF_LINES |
- R1_DEW |
- R1_EXTENDED_PACKET_DISABLE |
- R1_DAUS_ALL_OFF |
- R1_8_BITS_NO_PARITY |
- R1_VCS_TO_SCS,
-
- COMMAND_END);
- clear_bit(0, &t->in_use);
- return 0;
-}
-
-static const struct v4l2_file_operations saa_fops = {
- .owner = THIS_MODULE,
- .open = saa5246a_open,
- .release = saa5246a_release,
- .ioctl = saa5246a_ioctl,
-};
-
-static struct video_device saa_template =
-{
- .name = "saa5246a",
- .fops = &saa_fops,
- .release = video_device_release,
-};
-
-static int saa5246a_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_SAA5246A, 0);
-}
-
-static const struct v4l2_subdev_core_ops saa5246a_core_ops = {
- .g_chip_ident = saa5246a_g_chip_ident,
-};
-
-static const struct v4l2_subdev_ops saa5246a_ops = {
- .core = &saa5246a_core_ops,
-};
-
-
-static int saa5246a_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int pgbuf;
- int err;
- struct saa5246a_device *t;
- struct v4l2_subdev *sd;
-
- v4l_info(client, "chip found @ 0x%x (%s)\n",
- client->addr << 1, client->adapter->name);
- v4l_info(client, "VideoText version %d.%d\n",
- MAJOR_VERSION, MINOR_VERSION);
- t = kzalloc(sizeof(*t), GFP_KERNEL);
- if (t == NULL)
- return -ENOMEM;
- sd = &t->sd;
- v4l2_i2c_subdev_init(sd, client, &saa5246a_ops);
- mutex_init(&t->lock);
-
- /* Now create a video4linux device */
- t->vdev = video_device_alloc();
- if (t->vdev == NULL) {
- kfree(t);
- return -ENOMEM;
- }
- memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
-
- for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
- memset(t->pgbuf[pgbuf], ' ', sizeof(t->pgbuf[0]));
- t->is_searching[pgbuf] = false;
- }
- video_set_drvdata(t->vdev, t);
-
- /* Register it */
- err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
- if (err < 0) {
- video_device_release(t->vdev);
- kfree(t);
- return err;
- }
- return 0;
-}
-
-static int saa5246a_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct saa5246a_device *t = to_dev(sd);
-
- video_unregister_device(t->vdev);
- v4l2_device_unregister_subdev(sd);
- kfree(t);
- return 0;
-}
-
-static const struct i2c_device_id saa5246a_id[] = {
- { "saa5246a", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, saa5246a_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa5246a",
- .probe = saa5246a_probe,
- .remove = saa5246a_remove,
- .id_table = saa5246a_id,
-};
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
deleted file mode 100644
index 31ff27df4cbf..000000000000
--- a/drivers/media/video/saa5249.c
+++ /dev/null
@@ -1,650 +0,0 @@
-/*
- * Modified in order to keep it compatible both with new and old videotext IOCTLs by
- * Michael Geng <linux@MichaelGeng.de>
- *
- * Cleaned up to use existing videodev interface and allow the idea
- * of multiple teletext decoders on the video4linux iface. Changed i2c
- * to cover addressing clashes on device busses. It's also rebuilt so
- * you can add arbitary multiple teletext devices to Linux video4linux
- * now (well 32 anyway).
- *
- * Alan Cox <alan@lxorguk.ukuu.org.uk>
- *
- * The original driver was heavily modified to match the i2c interface
- * It was truncated to use the WinTV boards, too.
- *
- * Copyright (c) 1998 Richard Guenther <richard.guenther@student.uni-tuebingen.de>
- *
- * Derived From
- *
- * vtx.c:
- * This is a loadable character-device-driver for videotext-interfaces
- * (aka teletext). Please check the Makefile/README for a list of supported
- * interfaces.
- *
- * Copyright (c) 1994-97 Martin Buck <martin-2.buck@student.uni-ulm.de>
- *
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
- * USA.
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/i2c.h>
-#include <linux/mutex.h>
-#include <linux/delay.h>
-#include <linux/videotext.h>
-#include <linux/videodev2.h>
-#include <linux/slab.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv.h>
-
-MODULE_AUTHOR("Michael Geng <linux@MichaelGeng.de>");
-MODULE_DESCRIPTION("Philips SAA5249 Teletext decoder driver");
-MODULE_LICENSE("GPL");
-
-
-#define VTX_VER_MAJ 1
-#define VTX_VER_MIN 8
-
-
-#define NUM_DAUS 4
-#define NUM_BUFS 8
-
-static const int disp_modes[8][3] =
-{
- { 0x46, 0x03, 0x03 }, /* DISPOFF */
- { 0x46, 0xcc, 0xcc }, /* DISPNORM */
- { 0x44, 0x0f, 0x0f }, /* DISPTRANS */
- { 0x46, 0xcc, 0x46 }, /* DISPINS */
- { 0x44, 0x03, 0x03 }, /* DISPOFF, interlaced */
- { 0x44, 0xcc, 0xcc }, /* DISPNORM, interlaced */
- { 0x44, 0x0f, 0x0f }, /* DISPTRANS, interlaced */
- { 0x44, 0xcc, 0x46 } /* DISPINS, interlaced */
-};
-
-
-
-#define PAGE_WAIT msecs_to_jiffies(300) /* Time between requesting page and */
- /* checking status bits */
-#define PGBUF_EXPIRE msecs_to_jiffies(15000) /* Time to wait before retransmitting */
- /* page regardless of infobits */
-typedef struct {
- u8 pgbuf[VTX_VIRTUALSIZE]; /* Page-buffer */
- u8 laststat[10]; /* Last value of infobits for DAU */
- u8 sregs[7]; /* Page-request registers */
- unsigned long expire; /* Time when page will be expired */
- unsigned clrfound : 1; /* VTXIOCCLRFOUND has been called */
- unsigned stopped : 1; /* VTXIOCSTOPDAU has been called */
-} vdau_t;
-
-struct saa5249_device
-{
- struct v4l2_subdev sd;
- struct video_device *vdev;
- vdau_t vdau[NUM_DAUS]; /* Data for virtual DAUs (the 5249 only has one */
- /* real DAU, so we have to simulate some more) */
- int vtx_use_count;
- int is_searching[NUM_DAUS];
- int disp_mode;
- int virtual_mode;
- unsigned long in_use;
- struct mutex lock;
-};
-
-static inline struct saa5249_device *to_dev(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct saa5249_device, sd);
-}
-
-
-#define CCTWR 34 /* I²C write/read-address of vtx-chip */
-#define CCTRD 35
-#define NOACK_REPEAT 10 /* Retry access this many times on failure */
-#define CLEAR_DELAY msecs_to_jiffies(50) /* Time required to clear a page */
-#define READY_TIMEOUT msecs_to_jiffies(30) /* Time to wait for ready signal of I2C-bus interface */
-#define INIT_DELAY 500 /* Time in usec to wait at initialization of CEA interface */
-#define START_DELAY 10 /* Time in usec to wait before starting write-cycle (CEA) */
-
-#define VTX_DEV_MINOR 0
-
-static struct video_device saa_template; /* Declared near bottom */
-
-/*
- * Wait the given number of jiffies (10ms). This calls the scheduler, so the actual
- * delay may be longer.
- */
-
-static void jdelay(unsigned long delay)
-{
- sigset_t oldblocked = current->blocked;
-
- spin_lock_irq(&current->sighand->siglock);
- sigfillset(&current->blocked);
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
- msleep_interruptible(jiffies_to_msecs(delay));
-
- spin_lock_irq(&current->sighand->siglock);
- current->blocked = oldblocked;
- recalc_sigpending();
- spin_unlock_irq(&current->sighand->siglock);
-}
-
-
-/*
- * I2C interfaces
- */
-
-static int i2c_sendbuf(struct saa5249_device *t, int reg, int count, u8 *data)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
- char buf[64];
-
- buf[0] = reg;
- memcpy(buf+1, data, count);
-
- if (i2c_master_send(client, buf, count + 1) == count + 1)
- return 0;
- return -1;
-}
-
-static int i2c_senddata(struct saa5249_device *t, ...)
-{
- unsigned char buf[64];
- int v;
- int ct = 0;
- va_list argp;
- va_start(argp,t);
-
- while ((v = va_arg(argp, int)) != -1)
- buf[ct++] = v;
-
- va_end(argp);
- return i2c_sendbuf(t, buf[0], ct-1, buf+1);
-}
-
-/* Get count number of bytes from I²C-device at address adr, store them in buf. Start & stop
- * handshaking is done by this routine, ack will be sent after the last byte to inhibit further
- * sending of data. If uaccess is 'true', data is written to user-space with put_user.
- * Returns -1 if I²C-device didn't send acknowledge, 0 otherwise
- */
-
-static int i2c_getdata(struct saa5249_device *t, int count, u8 *buf)
-{
- struct i2c_client *client = v4l2_get_subdevdata(&t->sd);
-
- if (i2c_master_recv(client, buf, count) != count)
- return -1;
- return 0;
-}
-
-
-/*
- * Standard character-device-driver functions
- */
-
-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);
-
- switch (cmd) {
- case VTXIOCGETINFO:
- {
- vtx_info_t *info = arg;
- info->version_major = VTX_VER_MAJ;
- info->version_minor = VTX_VER_MIN;
- info->numpages = NUM_DAUS;
- /*info->cct_type = CCT_TYPE;*/
- return 0;
- }
-
- case VTXIOCCLRPAGE:
- {
- vtx_pagereq_t *req = arg;
-
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
- return -EINVAL;
- memset(t->vdau[req->pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
- t->vdau[req->pgbuf].clrfound = true;
- return 0;
- }
-
- case VTXIOCCLRFOUND:
- {
- vtx_pagereq_t *req = arg;
-
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
- return -EINVAL;
- t->vdau[req->pgbuf].clrfound = true;
- return 0;
- }
-
- case VTXIOCPAGEREQ:
- {
- vtx_pagereq_t *req = arg;
- if (!(req->pagemask & PGMASK_PAGE))
- req->page = 0;
- if (!(req->pagemask & PGMASK_HOUR))
- req->hour = 0;
- if (!(req->pagemask & PGMASK_MINUTE))
- req->minute = 0;
- if (req->page < 0 || req->page > 0x8ff) /* 7FF ?? */
- return -EINVAL;
- req->page &= 0x7ff;
- if (req->hour < 0 || req->hour > 0x3f || req->minute < 0 || req->minute > 0x7f ||
- req->pagemask < 0 || req->pagemask >= PGMASK_MAX || req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
- return -EINVAL;
- t->vdau[req->pgbuf].sregs[0] = (req->pagemask & PG_HUND ? 0x10 : 0) | (req->page / 0x100);
- t->vdau[req->pgbuf].sregs[1] = (req->pagemask & PG_TEN ? 0x10 : 0) | ((req->page / 0x10) & 0xf);
- t->vdau[req->pgbuf].sregs[2] = (req->pagemask & PG_UNIT ? 0x10 : 0) | (req->page & 0xf);
- t->vdau[req->pgbuf].sregs[3] = (req->pagemask & HR_TEN ? 0x10 : 0) | (req->hour / 0x10);
- t->vdau[req->pgbuf].sregs[4] = (req->pagemask & HR_UNIT ? 0x10 : 0) | (req->hour & 0xf);
- t->vdau[req->pgbuf].sregs[5] = (req->pagemask & MIN_TEN ? 0x10 : 0) | (req->minute / 0x10);
- t->vdau[req->pgbuf].sregs[6] = (req->pagemask & MIN_UNIT ? 0x10 : 0) | (req->minute & 0xf);
- t->vdau[req->pgbuf].stopped = false;
- t->vdau[req->pgbuf].clrfound = true;
- t->is_searching[req->pgbuf] = true;
- return 0;
- }
-
- case VTXIOCGETSTAT:
- {
- vtx_pagereq_t *req = arg;
- u8 infobits[10];
- vtx_pageinfo_t info;
- int a;
-
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
- return -EINVAL;
- if (!t->vdau[req->pgbuf].stopped) {
- if (i2c_senddata(t, 2, 0, -1) ||
- i2c_sendbuf(t, 3, sizeof(t->vdau[0].sregs), t->vdau[req->pgbuf].sregs) ||
- i2c_senddata(t, 8, 0, 25, 0, ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', ' ', -1) ||
- i2c_senddata(t, 2, 0, t->vdau[req->pgbuf].sregs[0] | 8, -1) ||
- i2c_senddata(t, 8, 0, 25, 0, -1))
- return -EIO;
- jdelay(PAGE_WAIT);
- if (i2c_getdata(t, 10, infobits))
- return -EIO;
-
- if (!(infobits[8] & 0x10) && !(infobits[7] & 0xf0) && /* check FOUND-bit */
- (memcmp(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits)) ||
- time_after_eq(jiffies, t->vdau[req->pgbuf].expire)))
- { /* check if new page arrived */
- if (i2c_senddata(t, 8, 0, 0, 0, -1) ||
- i2c_getdata(t, VTX_PAGESIZE, t->vdau[req->pgbuf].pgbuf))
- return -EIO;
- t->vdau[req->pgbuf].expire = jiffies + PGBUF_EXPIRE;
- memset(t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE, ' ', VTX_VIRTUALSIZE - VTX_PAGESIZE);
- if (t->virtual_mode) {
- /* Packet X/24 */
- if (i2c_senddata(t, 8, 0, 0x20, 0, -1) ||
- i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 20 * 40))
- return -EIO;
- /* Packet X/27/0 */
- if (i2c_senddata(t, 8, 0, 0x21, 0, -1) ||
- i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 16 * 40))
- return -EIO;
- /* Packet 8/30/0...8/30/15
- * FIXME: AFAIK, the 5249 does hamming-decoding for some bytes in packet 8/30,
- * so we should undo this here.
- */
- if (i2c_senddata(t, 8, 0, 0x22, 0, -1) ||
- i2c_getdata(t, 40, t->vdau[req->pgbuf].pgbuf + VTX_PAGESIZE + 23 * 40))
- return -EIO;
- }
- t->vdau[req->pgbuf].clrfound = false;
- memcpy(t->vdau[req->pgbuf].laststat, infobits, sizeof(infobits));
- } else {
- memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
- }
- } else {
- memcpy(infobits, t->vdau[req->pgbuf].laststat, sizeof(infobits));
- }
-
- info.pagenum = ((infobits[8] << 8) & 0x700) | ((infobits[1] << 4) & 0xf0) | (infobits[0] & 0x0f);
- if (info.pagenum < 0x100)
- info.pagenum += 0x800;
- info.hour = ((infobits[5] << 4) & 0x30) | (infobits[4] & 0x0f);
- info.minute = ((infobits[3] << 4) & 0x70) | (infobits[2] & 0x0f);
- info.charset = ((infobits[7] >> 1) & 7);
- info.delete = !!(infobits[3] & 8);
- info.headline = !!(infobits[5] & 4);
- info.subtitle = !!(infobits[5] & 8);
- info.supp_header = !!(infobits[6] & 1);
- info.update = !!(infobits[6] & 2);
- info.inter_seq = !!(infobits[6] & 4);
- info.dis_disp = !!(infobits[6] & 8);
- info.serial = !!(infobits[7] & 1);
- info.notfound = !!(infobits[8] & 0x10);
- info.pblf = !!(infobits[9] & 0x20);
- info.hamming = 0;
- for (a = 0; a <= 7; a++) {
- if (infobits[a] & 0xf0) {
- info.hamming = 1;
- break;
- }
- }
- if (t->vdau[req->pgbuf].clrfound)
- info.notfound = 1;
- if (copy_to_user(req->buffer, &info, sizeof(vtx_pageinfo_t)))
- return -EFAULT;
- if (!info.hamming && !info.notfound)
- t->is_searching[req->pgbuf] = false;
- return 0;
- }
-
- case VTXIOCGETPAGE:
- {
- vtx_pagereq_t *req = arg;
- int start, end;
-
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS || req->start < 0 ||
- req->start > req->end || req->end >= (virtual_mode ? VTX_VIRTUALSIZE : VTX_PAGESIZE))
- return -EINVAL;
- if (copy_to_user(req->buffer, &t->vdau[req->pgbuf].pgbuf[req->start], req->end - req->start + 1))
- return -EFAULT;
-
- /*
- * Always read the time directly from SAA5249
- */
-
- if (req->start <= 39 && req->end >= 32) {
- int len;
- char buf[16];
- start = max(req->start, 32);
- end = min(req->end, 39);
- len = end - start + 1;
- if (i2c_senddata(t, 8, 0, 0, start, -1) ||
- i2c_getdata(t, len, buf))
- return -EIO;
- if (copy_to_user(req->buffer + start - req->start, buf, len))
- return -EFAULT;
- }
- /* Insert the current header if DAU is still searching for a page */
- if (req->start <= 31 && req->end >= 7 && t->is_searching[req->pgbuf]) {
- char buf[32];
- int len;
-
- start = max(req->start, 7);
- end = min(req->end, 31);
- len = end - start + 1;
- if (i2c_senddata(t, 8, 0, 0, start, -1) ||
- i2c_getdata(t, len, buf))
- return -EIO;
- if (copy_to_user(req->buffer + start - req->start, buf, len))
- return -EFAULT;
- }
- return 0;
- }
-
- case VTXIOCSTOPDAU:
- {
- vtx_pagereq_t *req = arg;
-
- if (req->pgbuf < 0 || req->pgbuf >= NUM_DAUS)
- return -EINVAL;
- t->vdau[req->pgbuf].stopped = true;
- t->is_searching[req->pgbuf] = false;
- return 0;
- }
-
- case VTXIOCPUTPAGE:
- case VTXIOCSETDISP:
- case VTXIOCPUTSTAT:
- return 0;
-
- case VTXIOCCLRCACHE:
- {
- if (i2c_senddata(t, 0, NUM_DAUS, 0, 8, -1) || i2c_senddata(t, 11,
- ' ', ' ', ' ', ' ', ' ', ' ',
- ' ', ' ', ' ', ' ', ' ', ' ',
- ' ', ' ', ' ', ' ', ' ', ' ',
- ' ', ' ', ' ', ' ', ' ', ' ',
- -1))
- return -EIO;
- if (i2c_senddata(t, 3, 0x20, -1))
- return -EIO;
- jdelay(10 * CLEAR_DELAY); /* I have no idea how long we have to wait here */
- return 0;
- }
-
- case VTXIOCSETVIRT:
- {
- /* The SAA5249 has virtual-row reception turned on always */
- t->virtual_mode = (int)(long)arg;
- return 0;
- }
- }
- return -EINVAL;
-}
-
-/*
- * Translates old vtx IOCTLs to new ones
- *
- * This keeps new kernel versions compatible with old userspace programs.
- */
-static inline unsigned int vtx_fix_command(unsigned int cmd)
-{
- switch (cmd) {
- case VTXIOCGETINFO_OLD:
- cmd = VTXIOCGETINFO;
- break;
- case VTXIOCCLRPAGE_OLD:
- cmd = VTXIOCCLRPAGE;
- break;
- case VTXIOCCLRFOUND_OLD:
- cmd = VTXIOCCLRFOUND;
- break;
- case VTXIOCPAGEREQ_OLD:
- cmd = VTXIOCPAGEREQ;
- break;
- case VTXIOCGETSTAT_OLD:
- cmd = VTXIOCGETSTAT;
- break;
- case VTXIOCGETPAGE_OLD:
- cmd = VTXIOCGETPAGE;
- break;
- case VTXIOCSTOPDAU_OLD:
- cmd = VTXIOCSTOPDAU;
- break;
- case VTXIOCPUTPAGE_OLD:
- cmd = VTXIOCPUTPAGE;
- break;
- case VTXIOCSETDISP_OLD:
- cmd = VTXIOCSETDISP;
- break;
- case VTXIOCPUTSTAT_OLD:
- cmd = VTXIOCPUTSTAT;
- break;
- case VTXIOCCLRCACHE_OLD:
- cmd = VTXIOCCLRCACHE;
- break;
- case VTXIOCSETVIRT_OLD:
- cmd = VTXIOCSETVIRT;
- break;
- }
- return cmd;
-}
-
-/*
- * Handle the locking
- */
-
-static long saa5249_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- struct saa5249_device *t = video_drvdata(file);
- long err;
-
- cmd = vtx_fix_command(cmd);
- mutex_lock(&t->lock);
- err = video_usercopy(file, cmd, arg, do_saa5249_ioctl);
- mutex_unlock(&t->lock);
- return err;
-}
-
-static int saa5249_open(struct file *file)
-{
- struct saa5249_device *t = video_drvdata(file);
- int pgbuf;
-
- if (test_and_set_bit(0, &t->in_use))
- return -EBUSY;
-
- if (i2c_senddata(t, 0, 0, -1) || /* Select R11 */
- /* Turn off parity checks (we do this ourselves) */
- i2c_senddata(t, 1, disp_modes[t->disp_mode][0], 0, -1) ||
- /* Display TV-picture, no virtual rows */
- i2c_senddata(t, 4, NUM_DAUS, disp_modes[t->disp_mode][1], disp_modes[t->disp_mode][2], 7, -1))
- /* Set display to page 4 */
- {
- clear_bit(0, &t->in_use);
- return -EIO;
- }
-
- for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
- memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
- memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
- memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
- t->vdau[pgbuf].expire = 0;
- t->vdau[pgbuf].clrfound = true;
- t->vdau[pgbuf].stopped = true;
- t->is_searching[pgbuf] = false;
- }
- t->virtual_mode = false;
- return 0;
-}
-
-
-
-static int saa5249_release(struct file *file)
-{
- struct saa5249_device *t = video_drvdata(file);
-
- i2c_senddata(t, 1, 0x20, -1); /* Turn off CCT */
- i2c_senddata(t, 5, 3, 3, -1); /* Turn off TV-display */
- clear_bit(0, &t->in_use);
- return 0;
-}
-
-static const struct v4l2_file_operations saa_fops = {
- .owner = THIS_MODULE,
- .open = saa5249_open,
- .release = saa5249_release,
- .ioctl = saa5249_ioctl,
-};
-
-static struct video_device saa_template =
-{
- .name = "saa5249",
- .fops = &saa_fops,
- .release = video_device_release,
-};
-
-static int saa5249_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_SAA5249, 0);
-}
-
-static const struct v4l2_subdev_core_ops saa5249_core_ops = {
- .g_chip_ident = saa5249_g_chip_ident,
-};
-
-static const struct v4l2_subdev_ops saa5249_ops = {
- .core = &saa5249_core_ops,
-};
-
-static int saa5249_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- int pgbuf;
- int err;
- struct saa5249_device *t;
- struct v4l2_subdev *sd;
-
- v4l_info(client, "chip found @ 0x%x (%s)\n",
- client->addr << 1, client->adapter->name);
- v4l_info(client, "VideoText version %d.%d\n",
- VTX_VER_MAJ, VTX_VER_MIN);
- t = kzalloc(sizeof(*t), GFP_KERNEL);
- if (t == NULL)
- return -ENOMEM;
- sd = &t->sd;
- v4l2_i2c_subdev_init(sd, client, &saa5249_ops);
- mutex_init(&t->lock);
-
- /* Now create a video4linux device */
- t->vdev = video_device_alloc();
- if (t->vdev == NULL) {
- kfree(t);
- kfree(client);
- return -ENOMEM;
- }
- memcpy(t->vdev, &saa_template, sizeof(*t->vdev));
-
- for (pgbuf = 0; pgbuf < NUM_DAUS; pgbuf++) {
- memset(t->vdau[pgbuf].pgbuf, ' ', sizeof(t->vdau[0].pgbuf));
- memset(t->vdau[pgbuf].sregs, 0, sizeof(t->vdau[0].sregs));
- memset(t->vdau[pgbuf].laststat, 0, sizeof(t->vdau[0].laststat));
- t->vdau[pgbuf].expire = 0;
- t->vdau[pgbuf].clrfound = true;
- t->vdau[pgbuf].stopped = true;
- t->is_searching[pgbuf] = false;
- }
- video_set_drvdata(t->vdev, t);
-
- /* Register it */
- err = video_register_device(t->vdev, VFL_TYPE_VTX, -1);
- if (err < 0) {
- video_device_release(t->vdev);
- kfree(t);
- return err;
- }
- return 0;
-}
-
-static int saa5249_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
- struct saa5249_device *t = to_dev(sd);
-
- video_unregister_device(t->vdev);
- v4l2_device_unregister_subdev(sd);
- kfree(t);
- return 0;
-}
-
-static const struct i2c_device_id saa5249_id[] = {
- { "saa5249", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, saa5249_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa5249",
- .probe = saa5249_probe,
- .remove = saa5249_remove,
- .id_table = saa5249_id,
-};
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index c3e96f070973..99a2ac16f9e5 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -31,10 +31,9 @@
#include <linux/wait.h>
#include <asm/uaccess.h>
-#include <media/rds.h>
+#include <media/saa6588.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
/* insmod options */
@@ -182,7 +181,7 @@ static int block_to_user_buf(struct saa6588 *s, unsigned char __user *user_buf)
return 1;
}
-static void read_from_buf(struct saa6588 *s, struct rds_command *a)
+static void read_from_buf(struct saa6588 *s, struct saa6588_command *a)
{
unsigned long flags;
@@ -393,25 +392,25 @@ static void saa6588_configure(struct saa6588 *s)
static long saa6588_ioctl(struct v4l2_subdev *sd, unsigned int cmd, void *arg)
{
struct saa6588 *s = to_saa6588(sd);
- struct rds_command *a = arg;
+ struct saa6588_command *a = arg;
switch (cmd) {
/* --- open() for /dev/radio --- */
- case RDS_CMD_OPEN:
+ case SAA6588_CMD_OPEN:
a->result = 0; /* return error if chip doesn't work ??? */
break;
/* --- close() for /dev/radio --- */
- case RDS_CMD_CLOSE:
+ case SAA6588_CMD_CLOSE:
s->data_available_for_read = 1;
wake_up_interruptible(&s->read_queue);
a->result = 0;
break;
/* --- read() for /dev/radio --- */
- case RDS_CMD_READ:
+ case SAA6588_CMD_READ:
read_from_buf(s, a);
break;
/* --- poll() for /dev/radio --- */
- case RDS_CMD_POLL:
+ case SAA6588_CMD_POLL:
a->result = 0;
if (s->data_available_for_read) {
a->result |= POLLIN | POLLRDNORM;
@@ -430,7 +429,7 @@ static int saa6588_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
{
struct saa6588 *s = to_saa6588(sd);
- vt->capability |= V4L2_TUNER_CAP_RDS;
+ vt->capability |= V4L2_TUNER_CAP_RDS | V4L2_TUNER_CAP_RDS_BLOCK_IO;
if (s->sync)
vt->rxsubchans |= V4L2_TUNER_SUB_RDS;
return 0;
@@ -530,9 +529,25 @@ static const struct i2c_device_id saa6588_id[] = {
};
MODULE_DEVICE_TABLE(i2c, saa6588_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa6588",
- .probe = saa6588_probe,
- .remove = saa6588_remove,
- .id_table = saa6588_id,
+static struct i2c_driver saa6588_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa6588",
+ },
+ .probe = saa6588_probe,
+ .remove = saa6588_remove,
+ .id_table = saa6588_id,
};
+
+static __init int init_saa6588(void)
+{
+ return i2c_add_driver(&saa6588_driver);
+}
+
+static __exit void exit_saa6588(void)
+{
+ i2c_del_driver(&saa6588_driver);
+}
+
+module_init(init_saa6588);
+module_exit(exit_saa6588);
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 3bca744e43af..7913f93979b8 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -36,7 +36,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("Philips SAA7110 video decoder driver");
MODULE_AUTHOR("Pauline Middelink");
@@ -505,9 +504,25 @@ static const struct i2c_device_id saa7110_id[] = {
};
MODULE_DEVICE_TABLE(i2c, saa7110_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa7110",
- .probe = saa7110_probe,
- .remove = saa7110_remove,
- .id_table = saa7110_id,
+static struct i2c_driver saa7110_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa7110",
+ },
+ .probe = saa7110_probe,
+ .remove = saa7110_remove,
+ .id_table = saa7110_id,
};
+
+static __init int init_saa7110(void)
+{
+ return i2c_add_driver(&saa7110_driver);
+}
+
+static __exit void exit_saa7110(void)
+{
+ i2c_del_driver(&saa7110_driver);
+}
+
+module_init(init_saa7110);
+module_exit(exit_saa7110);
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 53b6fcde3800..f35459d1f42f 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -45,8 +45,8 @@
#include <linux/i2c.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/saa7115.h>
#include <asm/div64.h>
@@ -65,16 +65,19 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
struct saa711x_state {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+
+ struct {
+ /* chroma gain control cluster */
+ struct v4l2_ctrl *agc;
+ struct v4l2_ctrl *gain;
+ };
+
v4l2_std_id std;
int input;
int output;
int enable;
int radio;
- int bright;
- int contrast;
- int hue;
- int sat;
- int chroma_agc;
int width;
int height;
u32 ident;
@@ -90,6 +93,11 @@ static inline struct saa711x_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct saa711x_state, sd);
}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct saa711x_state, hdl)->sd;
+}
+
/* ----------------------------------------------------------------------- */
static inline int saa711x_write(struct v4l2_subdev *sd, u8 reg, u8 value)
@@ -741,96 +749,53 @@ static int saa711x_s_clock_freq(struct v4l2_subdev *sd, u32 freq)
return 0;
}
-static int saa711x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int saa711x_g_volatile_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
struct saa711x_state *state = to_state(sd);
- u8 val;
switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- if (ctrl->value < 0 || ctrl->value > 255) {
- v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- state->bright = ctrl->value;
- saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, state->bright);
- break;
-
- case V4L2_CID_CONTRAST:
- if (ctrl->value < 0 || ctrl->value > 127) {
- v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- state->contrast = ctrl->value;
- saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, state->contrast);
- break;
-
- case V4L2_CID_SATURATION:
- if (ctrl->value < 0 || ctrl->value > 127) {
- v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- state->sat = ctrl->value;
- saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, state->sat);
- break;
-
- case V4L2_CID_HUE:
- if (ctrl->value < -128 || ctrl->value > 127) {
- v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- state->hue = ctrl->value;
- saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, state->hue);
- break;
case V4L2_CID_CHROMA_AGC:
- val = saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL);
- state->chroma_agc = ctrl->value;
- if (ctrl->value)
- val &= 0x7f;
- else
- val |= 0x80;
- saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, val);
- break;
- case V4L2_CID_CHROMA_GAIN:
- /* Chroma gain cannot be set when AGC is enabled */
- if (state->chroma_agc == 1)
- return -EINVAL;
- saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, ctrl->value | 0x80);
+ /* chroma gain cluster */
+ if (state->agc->cur.val)
+ state->gain->cur.val =
+ saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f;
break;
- default:
- return -EINVAL;
}
-
return 0;
}
-static int saa711x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int saa711x_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
struct saa711x_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- ctrl->value = state->bright;
+ saa711x_write(sd, R_0A_LUMA_BRIGHT_CNTL, ctrl->val);
break;
+
case V4L2_CID_CONTRAST:
- ctrl->value = state->contrast;
+ saa711x_write(sd, R_0B_LUMA_CONTRAST_CNTL, ctrl->val);
break;
+
case V4L2_CID_SATURATION:
- ctrl->value = state->sat;
+ saa711x_write(sd, R_0C_CHROMA_SAT_CNTL, ctrl->val);
break;
+
case V4L2_CID_HUE:
- ctrl->value = state->hue;
+ saa711x_write(sd, R_0D_CHROMA_HUE_CNTL, ctrl->val);
break;
+
case V4L2_CID_CHROMA_AGC:
- ctrl->value = state->chroma_agc;
- break;
- case V4L2_CID_CHROMA_GAIN:
- ctrl->value = saa711x_read(sd, R_0F_CHROMA_GAIN_CNTL) & 0x7f;
+ /* chroma gain cluster */
+ if (state->agc->val)
+ saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val);
+ else
+ saa711x_write(sd, R_0F_CHROMA_GAIN_CNTL, state->gain->val | 0x80);
+ v4l2_ctrl_activate(state->gain, !state->agc->val);
break;
+
default:
return -EINVAL;
}
@@ -1117,13 +1082,6 @@ static int saa711x_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int saa711x_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- return saa711x_g_sliced_fmt(sd, &fmt->fmt.sliced);
-}
-
static int saa711x_s_raw_fmt(struct v4l2_subdev *sd, struct v4l2_vbi_format *fmt)
{
saa711x_set_lcr(sd, NULL);
@@ -1136,12 +1094,13 @@ static int saa711x_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int saa711x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int saa711x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ if (fmt->code != V4L2_MBUS_FMT_FIXED)
return -EINVAL;
-
- return saa711x_set_size(sd, fmt->fmt.pix.width, fmt->fmt.pix.height);
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+ return saa711x_set_size(sd, fmt->width, fmt->height);
}
/* Decode the sliced VBI data stream as created by the saa7115.
@@ -1229,25 +1188,6 @@ static int saa711x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
-static int saa711x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_BRIGHTNESS:
- return v4l2_ctrl_query_fill(qc, 0, 255, 1, 128);
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- return v4l2_ctrl_query_fill(qc, 0, 127, 1, 64);
- case V4L2_CID_HUE:
- return v4l2_ctrl_query_fill(qc, -128, 127, 1, 0);
- case V4L2_CID_CHROMA_AGC:
- return v4l2_ctrl_query_fill(qc, 0, 1, 1, 1);
- case V4L2_CID_CHROMA_GAIN:
- return v4l2_ctrl_query_fill(qc, 0, 127, 1, 48);
- default:
- return -EINVAL;
- }
-}
-
static int saa711x_s_std(struct v4l2_subdev *sd, v4l2_std_id std)
{
struct saa711x_state *state = to_state(sd);
@@ -1408,8 +1348,17 @@ static int saa711x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std)
int reg1e;
*std = V4L2_STD_ALL;
- if (state->ident != V4L2_IDENT_SAA7115)
+ if (state->ident != V4L2_IDENT_SAA7115) {
+ int reg1f = saa711x_read(sd, R_1F_STATUS_BYTE_2_VD_DEC);
+
+ if (reg1f & 0x20)
+ *std = V4L2_STD_525_60;
+ else
+ *std = V4L2_STD_625_50;
+
return 0;
+ }
+
reg1e = saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC);
switch (reg1e & 0x03) {
@@ -1524,17 +1473,27 @@ static int saa711x_log_status(struct v4l2_subdev *sd)
break;
}
v4l2_info(sd, "Width, Height: %d, %d\n", state->width, state->height);
+ v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
return 0;
}
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops saa711x_ctrl_ops = {
+ .s_ctrl = saa711x_s_ctrl,
+ .g_volatile_ctrl = saa711x_g_volatile_ctrl,
+};
+
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,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
.s_std = saa711x_s_std,
.reset = saa711x_reset,
.s_gpio = saa711x_s_gpio,
@@ -1556,8 +1515,7 @@ static const struct v4l2_subdev_audio_ops saa711x_audio_ops = {
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,
+ .s_mbus_fmt = saa711x_s_mbus_fmt,
.s_stream = saa711x_s_stream,
.querystd = saa711x_querystd,
.g_input_status = saa711x_g_input_status,
@@ -1586,8 +1544,9 @@ static int saa711x_probe(struct i2c_client *client,
{
struct saa711x_state *state;
struct v4l2_subdev *sd;
- int i;
- char name[17];
+ struct v4l2_ctrl_handler *hdl;
+ int i;
+ char name[17];
char chip_id;
int autodetect = !id || id->driver_data == 1;
@@ -1626,15 +1585,38 @@ static int saa711x_probe(struct i2c_client *client,
return -ENOMEM;
sd = &state->sd;
v4l2_i2c_subdev_init(sd, client, &saa711x_ops);
+
+ hdl = &state->hdl;
+ v4l2_ctrl_handler_init(hdl, 6);
+ /* add in ascending ID order */
+ v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 127, 1, 64);
+ v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ state->agc = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+ V4L2_CID_CHROMA_AGC, 0, 1, 1, 1);
+ state->gain = v4l2_ctrl_new_std(hdl, &saa711x_ctrl_ops,
+ V4L2_CID_CHROMA_GAIN, 0, 127, 1, 40);
+ state->gain->is_volatile = 1;
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(state);
+ return err;
+ }
+ state->agc->flags |= V4L2_CTRL_FLAG_UPDATE;
+ v4l2_ctrl_cluster(2, &state->agc);
+
state->input = -1;
state->output = SAA7115_IPORT_ON;
state->enable = 1;
state->radio = 0;
- state->bright = 128;
- state->contrast = 64;
- state->hue = 0;
- state->sat = 64;
- state->chroma_agc = 1;
switch (chip_id) {
case '1':
state->ident = V4L2_IDENT_SAA7111;
@@ -1682,6 +1664,7 @@ static int saa711x_probe(struct i2c_client *client,
if (state->ident > V4L2_IDENT_SAA7111A)
saa711x_writeregs(sd, saa7115_init_misc);
saa711x_set_v4lstd(sd, V4L2_STD_NTSC);
+ v4l2_ctrl_handler_setup(hdl);
v4l2_dbg(1, debug, sd, "status: (1E) 0x%02x, (1F) 0x%02x\n",
saa711x_read(sd, R_1E_STATUS_BYTE_1_VD_DEC),
@@ -1696,11 +1679,12 @@ static int saa711x_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
kfree(to_state(sd));
return 0;
}
-static const struct i2c_device_id saa7115_id[] = {
+static const struct i2c_device_id saa711x_id[] = {
{ "saa7115_auto", 1 }, /* autodetect */
{ "saa7111", 0 },
{ "saa7113", 0 },
@@ -1709,11 +1693,27 @@ static const struct i2c_device_id saa7115_id[] = {
{ "saa7118", 0 },
{ }
};
-MODULE_DEVICE_TABLE(i2c, saa7115_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa7115",
- .probe = saa711x_probe,
- .remove = saa711x_remove,
- .id_table = saa7115_id,
+MODULE_DEVICE_TABLE(i2c, saa711x_id);
+
+static struct i2c_driver saa711x_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa7115",
+ },
+ .probe = saa711x_probe,
+ .remove = saa711x_remove,
+ .id_table = saa711x_id,
};
+
+static __init int init_saa711x(void)
+{
+ return i2c_add_driver(&saa711x_driver);
+}
+
+static __exit void exit_saa711x(void)
+{
+ i2c_del_driver(&saa711x_driver);
+}
+
+module_init(init_saa711x);
+module_exit(exit_saa711x);
diff --git a/drivers/media/video/saa7127.c b/drivers/media/video/saa7127.c
index 87986ad62f86..ad964616c9d2 100644
--- a/drivers/media/video/saa7127.c
+++ b/drivers/media/video/saa7127.c
@@ -55,7 +55,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/saa7127.h>
static int debug;
@@ -645,13 +644,6 @@ static int saa7127_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int saa7127_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- return saa7127_g_sliced_fmt(sd, &fmt->fmt.sliced);
-}
-
static int saa7127_s_vbi_data(struct v4l2_subdev *sd, const struct v4l2_sliced_vbi_data *data)
{
switch (data->id) {
@@ -731,7 +723,6 @@ static const struct v4l2_subdev_core_ops saa7127_core_ops = {
};
static const struct v4l2_subdev_video_ops saa7127_video_ops = {
- .g_fmt = saa7127_g_fmt,
.s_std_output = saa7127_s_std_output,
.s_routing = saa7127_s_routing,
.s_stream = saa7127_s_stream,
@@ -851,9 +842,25 @@ static struct i2c_device_id saa7127_id[] = {
};
MODULE_DEVICE_TABLE(i2c, saa7127_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa7127",
- .probe = saa7127_probe,
- .remove = saa7127_remove,
- .id_table = saa7127_id,
+static struct i2c_driver saa7127_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa7127",
+ },
+ .probe = saa7127_probe,
+ .remove = saa7127_remove,
+ .id_table = saa7127_id,
};
+
+static __init int init_saa7127(void)
+{
+ return i2c_add_driver(&saa7127_driver);
+}
+
+static __exit void exit_saa7127(void)
+{
+ i2c_del_driver(&saa7127_driver);
+}
+
+module_init(init_saa7127);
+module_exit(exit_saa7127);
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 22bfd62c9551..380f1b28cfcc 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -1,8 +1,7 @@
config VIDEO_SAA7134
tristate "Philips SAA7134 support"
- depends on VIDEO_DEV && PCI && I2C && INPUT
+ depends on VIDEO_DEV && PCI && I2C
select VIDEOBUF_DMA_SG
- select VIDEO_IR
select VIDEO_TUNER
select VIDEO_TVEEPROM
select CRC32
@@ -25,6 +24,14 @@ config VIDEO_SAA7134_ALSA
To compile this driver as a module, choose M here: the
module will be called saa7134-alsa.
+config VIDEO_SAA7134_RC
+ bool "Philips SAA7134 Remote Controller support"
+ depends on RC_CORE
+ depends on VIDEO_SAA7134
+ default y
+ ---help---
+ Enables Remote Controller support on saa7134 driver.
+
config VIDEO_SAA7134_DVB
tristate "DVB/ATSC Support for saa7134 based TV cards"
depends on VIDEO_SAA7134 && DVB_CORE
diff --git a/drivers/media/video/saa7134/Makefile b/drivers/media/video/saa7134/Makefile
index 604158a8c235..8a5ff4d3cf15 100644
--- a/drivers/media/video/saa7134/Makefile
+++ b/drivers/media/video/saa7134/Makefile
@@ -1,7 +1,8 @@
-saa7134-objs := saa7134-cards.o saa7134-core.o saa7134-i2c.o \
- saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o \
- saa7134-video.o saa7134-input.o
+saa7134-y := saa7134-cards.o saa7134-core.o saa7134-i2c.o
+saa7134-y += saa7134-ts.o saa7134-tvaudio.o saa7134-vbi.o
+saa7134-y += saa7134-video.o
+saa7134-$(CONFIG_VIDEO_SAA7134_RC) += saa7134-input.o
obj-$(CONFIG_VIDEO_SAA7134) += saa6752hs.o saa7134.o saa7134-empress.o
diff --git a/drivers/media/video/saa7134/saa6752hs.c b/drivers/media/video/saa7134/saa6752hs.c
index 1eabff6b2456..f9f29cc93a8a 100644
--- a/drivers/media/video/saa7134/saa6752hs.c
+++ b/drivers/media/video/saa7134/saa6752hs.c
@@ -36,7 +36,6 @@
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <linux/init.h>
#include <linux/crc32.h>
@@ -846,24 +845,28 @@ static int saa6752hs_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_control
return 0;
}
-static int saa6752hs_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int saa6752hs_g_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct saa6752hs_state *h = to_state(sd);
if (h->video_format == SAA6752HS_VF_UNKNOWN)
h->video_format = SAA6752HS_VF_D1;
- f->fmt.pix.width =
- v4l2_format_table[h->video_format].fmt.pix.width;
- f->fmt.pix.height =
- v4l2_format_table[h->video_format].fmt.pix.height;
+ f->width = v4l2_format_table[h->video_format].fmt.pix.width;
+ f->height = v4l2_format_table[h->video_format].fmt.pix.height;
+ f->code = V4L2_MBUS_FMT_FIXED;
+ f->field = V4L2_FIELD_INTERLACED;
+ f->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
-static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int saa6752hs_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct saa6752hs_state *h = to_state(sd);
int dist_352, dist_480, dist_720;
+ if (f->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
+
/*
FIXME: translate and round width/height into EMPRESS
subsample type:
@@ -876,28 +879,30 @@ static int saa6752hs_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
D1 | 720x576 | 720x480
*/
- dist_352 = abs(f->fmt.pix.width - 352);
- dist_480 = abs(f->fmt.pix.width - 480);
- dist_720 = abs(f->fmt.pix.width - 720);
+ dist_352 = abs(f->width - 352);
+ dist_480 = abs(f->width - 480);
+ dist_720 = abs(f->width - 720);
if (dist_720 < dist_480) {
- f->fmt.pix.width = 720;
- f->fmt.pix.height = 576;
+ f->width = 720;
+ f->height = 576;
h->video_format = SAA6752HS_VF_D1;
} else if (dist_480 < dist_352) {
- f->fmt.pix.width = 480;
- f->fmt.pix.height = 576;
+ f->width = 480;
+ f->height = 576;
h->video_format = SAA6752HS_VF_2_3_D1;
} else {
- f->fmt.pix.width = 352;
- if (abs(f->fmt.pix.height - 576) <
- abs(f->fmt.pix.height - 288)) {
- f->fmt.pix.height = 576;
+ f->width = 352;
+ if (abs(f->height - 576) <
+ abs(f->height - 288)) {
+ f->height = 576;
h->video_format = SAA6752HS_VF_1_2_D1;
} else {
- f->fmt.pix.height = 288;
+ f->height = 288;
h->video_format = SAA6752HS_VF_SIF;
}
}
+ f->field = V4L2_FIELD_INTERLACED;
+ f->colorspace = V4L2_COLORSPACE_SMPTE170M;
return 0;
}
@@ -932,8 +937,8 @@ static const struct v4l2_subdev_core_ops saa6752hs_core_ops = {
};
static const struct v4l2_subdev_video_ops saa6752hs_video_ops = {
- .s_fmt = saa6752hs_s_fmt,
- .g_fmt = saa6752hs_g_fmt,
+ .s_mbus_fmt = saa6752hs_s_mbus_fmt,
+ .g_mbus_fmt = saa6752hs_g_mbus_fmt,
};
static const struct v4l2_subdev_ops saa6752hs_ops = {
@@ -986,13 +991,29 @@ static const struct i2c_device_id saa6752hs_id[] = {
};
MODULE_DEVICE_TABLE(i2c, saa6752hs_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa6752hs",
- .probe = saa6752hs_probe,
- .remove = saa6752hs_remove,
- .id_table = saa6752hs_id,
+static struct i2c_driver saa6752hs_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa6752hs",
+ },
+ .probe = saa6752hs_probe,
+ .remove = saa6752hs_remove,
+ .id_table = saa6752hs_id,
};
+static __init int init_saa6752hs(void)
+{
+ return i2c_add_driver(&saa6752hs_driver);
+}
+
+static __exit void exit_saa6752hs(void)
+{
+ i2c_del_driver(&saa6752hs_driver);
+}
+
+module_init(init_saa6752hs);
+module_exit(exit_saa6752hs);
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index d3bd82ad010a..10460fd3ce39 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -630,7 +630,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
/* release the old buffer */
if (substream->runtime->dma_area) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
substream->runtime->dma_area = NULL;
}
@@ -646,12 +646,12 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
return err;
}
- if (0 != (err = videobuf_sg_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
+ if (0 != (err = videobuf_dma_map(&dev->pci->dev, &dev->dmasound.dma))) {
dsp_buffer_free(dev);
return err;
}
if (0 != (err = saa7134_pgtable_alloc(dev->pci,&dev->dmasound.pt))) {
- videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
return err;
}
@@ -660,7 +660,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
dev->dmasound.dma.sglen,
0))) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
return err;
}
@@ -669,7 +669,7 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
byte, but it doesn't work. So I allocate the DMA using the
V4L functions, and force ALSA to use that as the DMA area */
- substream->runtime->dma_area = dev->dmasound.dma.vmalloc;
+ substream->runtime->dma_area = dev->dmasound.dma.vaddr;
substream->runtime->dma_bytes = dev->dmasound.bufsize;
substream->runtime->dma_addr = 0;
@@ -696,7 +696,7 @@ static int snd_card_saa7134_hw_free(struct snd_pcm_substream * substream)
if (substream->runtime->dma_area) {
saa7134_pgtable_free(dev->pci, &dev->dmasound.pt);
- videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
+ videobuf_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
substream->runtime->dma_area = NULL;
}
@@ -1080,7 +1080,7 @@ static int alsa_card_saa7134_create(struct saa7134_dev *dev, int devnum)
/* Card "creation" */
card->private_free = snd_saa7134_free;
- chip = (snd_card_saa7134_t *) card->private_data;
+ chip = card->private_data;
spin_lock_init(&chip->lock);
spin_lock_init(&chip->mixer_lock);
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 72700d4e3941..deb8fcf4aa49 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -3897,6 +3897,40 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x01,
},
},
+ [SAA7134_BOARD_AVERMEDIA_M733A] = {
+ .name = "Avermedia PCI M733A",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 0,
+ .gpiomask = 0x020200000,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ .gpio = 0x00200000,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ .gpio = 0x01,
+ },
+ },
[SAA7134_BOARD_BEHOLD_401] = {
/* Beholder Intl. Ltd. 2008 */
/*Dmitry Belimov <d.belimov@gmail.com> */
@@ -4289,13 +4323,13 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
/* Beholder Intl. Ltd. 2008 */
- /*Dmitry Belimov <d.belimov@gmail.com> */
- .name = "Beholder BeholdTV Columbus TVFM",
+ /* Dmitry Belimov <d.belimov@gmail.com> */
+ .name = "Beholder BeholdTV Columbus TV/FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_ALPS_TSBE5_PAL,
- .radio_type = UNSET,
- .tuner_addr = ADDR_UNSET,
- .radio_addr = ADDR_UNSET,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = 0xc2 >> 1,
+ .radio_addr = 0xc0 >> 1,
.tda9887_conf = TDA9887_PRESENT,
.gpiomask = 0x000A8004,
.inputs = {{
@@ -5142,6 +5176,48 @@ struct saa7134_board saa7134_boards[] = {
.amux = 2,
},
},
+ [SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG] = {
+ .name = "Kworld PCI SBTVD/ISDB-T Full-Seg Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .tuner_addr = ADDR_UNSET,
+ .radio_type = UNSET,
+ .radio_addr = ADDR_UNSET,
+ .gpiomask = 0x8e054000,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+#if 0 /* FIXME */
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ .gpio = 0x200,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ .gpio = 0x200,
+#endif
+ } },
+#if 0
+ .radio = {
+ .name = name_radio,
+ .vmux = 1,
+ .amux = LINE1,
+ .gpio = 0x100,
+ },
+#endif
+ .mute = {
+ .name = name_mute,
+ .vmux = 0,
+ .amux = TV,
+ },
+ },
[SAA7134_BOARD_AVERMEDIA_GO_007_FM_PLUS] = {
.name = "Avermedia AVerTV GO 007 FM Plus",
.audio_clock = 0x00187de7,
@@ -5428,6 +5504,61 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
},
},
+ [SAA7134_BOARD_TECHNOTREND_BUDGET_T3000] = {
+ .name = "TechoTrend TT-budget T-3000",
+ .tuner_type = TUNER_PHILIPS_TD1316,
+ .audio_clock = 0x00187de7,
+ .radio_type = UNSET,
+ .tuner_addr = 0x63,
+ .radio_addr = ADDR_UNSET,
+ .tda9887_conf = TDA9887_PRESENT | TDA9887_PORT1_ACTIVE,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE2,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ },
+ [SAA7134_BOARD_VIDEOMATE_M1F] = {
+ /* Pavel Osnova <pvosnova@gmail.com> */
+ .name = "Compro VideoMate Vista M1F",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .radio_type = TUNER_TEA5767,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = 0x60,
+ .inputs = { {
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ .mute = {
+ .name = name_mute,
+ .amux = TV,
+ },
+ },
};
@@ -5822,6 +5953,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_AVERMEDIA_M135A,
}, {
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x4155,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M733A,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0x4255,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M733A,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = PCI_VENDOR_ID_PHILIPS,
.subdevice = 0x2004,
@@ -6545,6 +6688,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
}, {
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x17de,
+ .subdevice = 0xb136,
+ .driver_data = SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG,
+ }, {
+ .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,
@@ -6585,6 +6734,30 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x6655,
.driver_data = SAA7134_BOARD_LEADTEK_WINFAST_DTV1000S,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x13c2,
+ .subdevice = 0x2804,
+ .driver_data = SAA7134_BOARD_TECHNOTREND_BUDGET_T3000,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7190,
+ .driver_data = SAA7134_BOARD_BEHOLD_H7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
+ .subdevice = 0x7090,
+ .driver_data = SAA7134_BOARD_BEHOLD_A7,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7135,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_M1F,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -6622,18 +6795,6 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = PCI_ANY_ID,
.subdevice = PCI_ANY_ID,
.driver_data = SAA7134_BOARD_UNKNOWN,
- }, {
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
- .subdevice = 0x7190,
- .driver_data = SAA7134_BOARD_BEHOLD_H7,
- }, {
- .vendor = PCI_VENDOR_ID_PHILIPS,
- .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
- .subvendor = 0x5ace, /* Beholder Intl. Ltd. */
- .subdevice = 0x7090,
- .driver_data = SAA7134_BOARD_BEHOLD_A7,
},{
/* --- end of list --- */
}
@@ -6755,6 +6916,30 @@ static inline int saa7134_tda18271_hvr11x0_toggle_agc(struct saa7134_dev *dev,
return 0;
}
+static inline int saa7134_kworld_sbtvd_toggle_agc(struct saa7134_dev *dev,
+ enum tda18271_mode mode)
+{
+ /* toggle AGC switch through GPIO 27 */
+ switch (mode) {
+ case TDA18271_ANALOG:
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+ msleep(20);
+ break;
+ case TDA18271_DIGITAL:
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x14000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x14000);
+ msleep(20);
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x54000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x54000);
+ msleep(30);
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
int command, int arg)
{
@@ -6767,6 +6952,9 @@ static int saa7134_tda8290_18271_callback(struct saa7134_dev *dev,
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
ret = saa7134_tda18271_hvr11x0_toggle_agc(dev, arg);
break;
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ ret = saa7134_kworld_sbtvd_toggle_agc(dev, arg);
+ break;
default:
break;
}
@@ -6786,6 +6974,8 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
switch (dev->board) {
case SAA7134_BOARD_HAUPPAUGE_HVR1150:
case SAA7134_BOARD_HAUPPAUGE_HVR1120:
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
/* tda8290 + tda18271 */
ret = saa7134_tda8290_18271_callback(dev, command, arg);
break;
@@ -6800,6 +6990,7 @@ static int saa7134_tda8290_callback(struct saa7134_dev *dev,
int saa7134_tuner_callback(void *priv, int component, int command, int arg)
{
struct saa7134_dev *dev = priv;
+
if (dev != NULL) {
switch (dev->tuner_type) {
case TUNER_PHILIPS_TDA8290:
@@ -6890,6 +7081,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_VIDEOMATE_TV_PVR:
case SAA7134_BOARD_VIDEOMATE_GOLD_PLUS:
case SAA7134_BOARD_VIDEOMATE_TV_GOLD_PLUSII:
+ case SAA7134_BOARD_VIDEOMATE_M1F:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
@@ -7087,6 +7279,14 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x0000C000, 0x0000C000);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0000C000, 0x0000C000);
break;
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ saa7134_set_gpio(dev, 1, 1);
+ msleep(10);
+ saa7134_set_gpio(dev, 1, 0);
+ msleep(10);
+ saa7134_set_gpio(dev, 1, 1);
+ dev->has_remote = SAA7134_REMOTE_GPIO;
+ break;
}
return 0;
}
@@ -7265,6 +7465,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
case SAA7134_BOARD_ASUS_EUROPA_HYBRID:
+ case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
{
/* The Philips EUROPA based hybrid boards have the tuner
@@ -7455,6 +7656,12 @@ int saa7134_board_init2(struct saa7134_dev *dev)
dev->name);
break;
}
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ saa_writel(SAA7134_GPIO_GPMODE0 >> 2, 0x4000);
+ saa_writel(SAA7134_GPIO_GPSTATUS0 >> 2, 0x4000);
+
+ saa7134_set_gpio(dev, 27, 0);
+ break;
} /* switch() */
/* initialize tuner */
@@ -7465,22 +7672,22 @@ int saa7134_board_init2(struct saa7134_dev *dev)
so we do not need to probe for a radio tuner device. */
if (dev->radio_type != UNSET)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, "tuner",
dev->radio_addr, NULL);
if (has_demod)
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
if (dev->tuner_addr == ADDR_UNSET) {
enum v4l2_i2c_tuner_type type =
has_demod ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, "tuner",
0, v4l2_i2c_tuner_addrs(type));
} else {
v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "tuner", "tuner",
+ &dev->i2c_adap, "tuner",
dev->tuner_addr, NULL);
}
}
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 90f231881297..6abeecff6da7 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -166,8 +166,14 @@ static void request_submodules(struct saa7134_dev *dev)
schedule_work(&dev->request_module_wk);
}
+static void flush_request_submodules(struct saa7134_dev *dev)
+{
+ flush_work_sync(&dev->request_module_wk);
+}
+
#else
#define request_submodules(dev)
+#define flush_request_submodules(dev)
#endif /* CONFIG_MODULES */
/* ------------------------------------------------------------------ */
@@ -255,8 +261,8 @@ void saa7134_dma_free(struct videobuf_queue *q,struct saa7134_buf *buf)
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
BUG_ON(in_interrupt());
- videobuf_waiton(&buf->vb,0,0);
- videobuf_dma_unmap(q, dma);
+ videobuf_waiton(q, &buf->vb, 0, 0);
+ videobuf_dma_unmap(q->dev, dma);
videobuf_dma_free(dma);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
@@ -991,7 +997,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (card_is_empress(dev)) {
struct v4l2_subdev *sd =
v4l2_i2c_new_subdev(&dev->v4l2_dev, &dev->i2c_adap,
- "saa6752hs", "saa6752hs",
+ "saa6752hs",
saa7134_boards[dev->board].empress_addr, NULL);
if (sd)
@@ -1002,7 +1008,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
struct v4l2_subdev *sd;
sd = v4l2_i2c_new_subdev(&dev->v4l2_dev,
- &dev->i2c_adap, "saa6588", "saa6588",
+ &dev->i2c_adap, "saa6588",
0, I2C_ADDRS(saa7134_boards[dev->board].rds_addr));
if (sd) {
printk(KERN_INFO "%s: found RDS decoder\n", dev->name);
@@ -1010,8 +1016,6 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
}
}
- request_submodules(dev);
-
v4l2_prio_init(&dev->prio);
mutex_lock(&saa7134_devlist_lock);
@@ -1066,6 +1070,7 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (saa7134_dmasound_init && !dev->dmasound.priv_data)
saa7134_dmasound_init(dev);
+ request_submodules(dev);
return 0;
fail4:
@@ -1091,6 +1096,8 @@ static void __devexit saa7134_finidev(struct pci_dev *pci_dev)
struct saa7134_dev *dev = container_of(v4l2_dev, struct saa7134_dev, v4l2_dev);
struct saa7134_mpeg_ops *mops;
+ flush_request_submodules(dev);
+
/* Release DMA sound modules if present */
if (saa7134_dmasound_exit && dev->dmasound.priv_data) {
saa7134_dmasound_exit(dev);
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index 31e82be1b7e7..f65cad287b83 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -52,6 +52,7 @@
#include "tda18271.h"
#include "lgdt3305.h"
#include "tda8290.h"
+#include "mb86a20s.h"
#include "zl10353.h"
@@ -228,6 +229,47 @@ static struct mt352_config avermedia_xc3028_mt352_dev = {
.demod_init = mt352_avermedia_xc3028_init,
};
+static struct tda18271_std_map mb86a20s_tda18271_std_map = {
+ .dvbt_6 = { .if_freq = 3300, .agc_mode = 3, .std = 4,
+ .if_lvl = 7, .rfagc_top = 0x37, },
+};
+
+static struct tda18271_config kworld_tda18271_config = {
+ .std_map = &mb86a20s_tda18271_std_map,
+ .gate = TDA18271_GATE_DIGITAL,
+ .config = 3, /* Use tuner callback for AGC */
+
+};
+
+static const struct mb86a20s_config kworld_mb86a20s_config = {
+ .demod_address = 0x10,
+};
+
+static int kworld_sbtvd_gate_ctrl(struct dvb_frontend* fe, int enable)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+
+ unsigned char initmsg[] = {0x45, 0x97};
+ unsigned char msg_enable[] = {0x45, 0xc1};
+ unsigned char msg_disable[] = {0x45, 0x81};
+ struct i2c_msg msg = {.addr = 0x4b, .flags = 0, .buf = initmsg, .len = 2};
+
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ wprintk("could not access the I2C gate\n");
+ return -EIO;
+ }
+ if (enable)
+ msg.buf = msg_enable;
+ else
+ msg.buf = msg_disable;
+ if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
+ wprintk("could not access the I2C gate\n");
+ return -EIO;
+ }
+ msleep(20);
+ return 0;
+}
+
/* ==================================================================
* tda1004x based DVB-T cards, helper functions
*/
@@ -481,6 +523,17 @@ static struct tda1004x_config medion_cardbus = {
.request_firmware = philips_tda1004x_request_firmware
};
+static struct tda1004x_config technotrend_budget_t3000_config = {
+ .demod_address = 0x8,
+ .invert = 1,
+ .invert_oclk = 0,
+ .xtal_freq = TDA10046_XTAL_4M,
+ .agc_config = TDA10046_AGC_DEFAULT,
+ .if_freq = TDA10046_FREQ_3617,
+ .tuner_address = 0x63,
+ .request_firmware = philips_tda1004x_request_firmware
+};
+
/* ------------------------------------------------------------------
* tda 1004x based cards with philips silicon tuner
*/
@@ -1100,7 +1153,7 @@ static int dvb_init(struct saa7134_dev *dev)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
sizeof(struct saa7134_buf),
- dev);
+ dev, NULL);
switch (dev->board) {
case SAA7134_BOARD_PINNACLE_300I_DVBT_PAL:
@@ -1168,6 +1221,18 @@ static int dvb_init(struct saa7134_dev *dev)
fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
}
break;
+ case SAA7134_BOARD_TECHNOTREND_BUDGET_T3000:
+ fe0->dvb.frontend = dvb_attach(tda10046_attach,
+ &technotrend_budget_t3000_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend) {
+ dev->original_demod_sleep = fe0->dvb.frontend->ops.sleep;
+ fe0->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.init = philips_europa_tuner_init;
+ fe0->dvb.frontend->ops.tuner_ops.sleep = philips_europa_tuner_sleep;
+ fe0->dvb.frontend->ops.tuner_ops.set_params = philips_td1316_tuner_set_params;
+ }
+ break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
fe0->dvb.frontend = dvb_attach(tda10046_attach,
&philips_tu1216_61_config,
@@ -1590,6 +1655,25 @@ static int dvb_init(struct saa7134_dev *dev)
&dtv1000s_tda18271_config);
}
break;
+ case SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG:
+ /* Switch to digital mode */
+ saa7134_tuner_callback(dev, 0,
+ TDA18271_CALLBACK_CMD_AGC_ENABLE, 1);
+ fe0->dvb.frontend = dvb_attach(mb86a20s_attach,
+ &kworld_mb86a20s_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &kworld_tda18271_config);
+ fe0->dvb.frontend->ops.i2c_gate_ctrl = kworld_sbtvd_gate_ctrl;
+ }
+
+ /* mb86a20s need to use the I2C gateway */
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index ea877a50f52d..6b8459c7728e 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -21,7 +21,6 @@
#include <linux/list.h>
#include <linux/module.h>
#include <linux/kernel.h>
-#include <linux/smp_lock.h>
#include <linux/delay.h>
#include "saa7134-reg.h"
@@ -223,9 +222,11 @@ static int empress_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_dev *dev = file->private_data;
+ struct v4l2_mbus_framefmt mbus_fmt;
- saa_call_all(dev, video, g_fmt, f);
+ saa_call_all(dev, video, g_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
@@ -236,8 +237,11 @@ static int empress_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct saa7134_dev *dev = file->private_data;
+ struct v4l2_mbus_framefmt mbus_fmt;
- saa_call_all(dev, video, s_fmt, f);
+ v4l2_fill_mbus_format(&mbus_fmt, &f->fmt.pix, V4L2_MBUS_FMT_FIXED);
+ saa_call_all(dev, video, s_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(&f->fmt.pix, &mbus_fmt);
f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
f->fmt.pix.sizeimage = TS_PACKET_SIZE * dev->ts.nr_packets;
@@ -537,7 +541,7 @@ static int empress_init(struct saa7134_dev *dev)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
sizeof(struct saa7134_buf),
- dev);
+ dev, NULL);
empress_signal_update(&dev->empress_workqueue);
return 0;
@@ -549,7 +553,7 @@ static int empress_fini(struct saa7134_dev *dev)
if (NULL == dev->empress_dev)
return 0;
- flush_scheduled_work();
+ flush_work_sync(&dev->empress_workqueue);
video_unregister_device(dev->empress_dev);
dev->empress_dev = NULL;
return 0;
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index da41b6b1e64a..2d3f6d265bbf 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -328,7 +328,6 @@ static struct i2c_algorithm saa7134_algo = {
static struct i2c_adapter saa7134_adap_template = {
.owner = THIS_MODULE,
.name = "saa7134",
- .id = I2C_HW_SAA7134,
.algo = &saa7134_algo,
};
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index e5565e2fd426..dc646e65edb7 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -22,7 +22,6 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
-#include <linux/input.h>
#include <linux/slab.h>
#include "saa7134-reg.h"
@@ -42,41 +41,19 @@ static int pinnacle_remote;
module_param(pinnacle_remote, int, 0644); /* Choose Pinnacle PCTV remote */
MODULE_PARM_DESC(pinnacle_remote, "Specify Pinnacle PCTV remote: 0=coloured, 1=grey (defaults to 0)");
-static int ir_rc5_remote_gap = 885;
-module_param(ir_rc5_remote_gap, int, 0644);
-static int ir_rc5_key_timeout = 115;
-module_param(ir_rc5_key_timeout, int, 0644);
-
-static int repeat_delay = 500;
-module_param(repeat_delay, int, 0644);
-MODULE_PARM_DESC(repeat_delay, "delay before key repeat started");
-static int repeat_period = 33;
-module_param(repeat_period, int, 0644);
-MODULE_PARM_DESC(repeat_period, "repeat period between "
- "keypresses when key is down");
-
-static unsigned int disable_other_ir;
-module_param(disable_other_ir, int, 0644);
-MODULE_PARM_DESC(disable_other_ir, "disable full codes of "
- "alternative remotes from other manufacturers");
-
#define dprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, dev->name , ## arg)
#define i2cdprintk(fmt, arg...) if (ir_debug) \
printk(KERN_DEBUG "%s/ir: " fmt, ir->name , ## arg)
-/* Helper functions for RC5 and NEC decoding at GPIO16 or GPIO18 */
-static int saa7134_rc5_irq(struct saa7134_dev *dev);
-static int saa7134_nec_irq(struct saa7134_dev *dev);
+/* Helper function for raw decoding at GPIO16 or GPIO18 */
static int saa7134_raw_decode_irq(struct saa7134_dev *dev);
-static void nec_task(unsigned long data);
-static void saa7134_nec_timer(unsigned long data);
/* -------------------- GPIO generic keycode builder -------------------- */
static int build_key(struct saa7134_dev *dev)
{
- struct card_ir *ir = dev->remote;
+ struct saa7134_card_ir *ir = dev->remote;
u32 gpio, data;
/* here comes the additional handshake steps for some cards */
@@ -104,25 +81,25 @@ static int build_key(struct saa7134_dev *dev)
switch (dev->board) {
case SAA7134_BOARD_KWORLD_PLUS_TV_ANALOG:
if (data == ir->mask_keycode)
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keyup(ir->dev);
else
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
return 0;
}
if (ir->polling) {
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- ir_input_keydown(ir->dev, &ir->ir, data);
+ rc_keydown_notimeout(ir->dev, data, 0);
} else {
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keyup(ir->dev);
}
}
else { /* IRQ driven mode - handle key press and release in one go */
if ((ir->mask_keydown && (0 != (gpio & ir->mask_keydown))) ||
(ir->mask_keyup && (0 == (gpio & ir->mask_keyup)))) {
- ir_input_keydown(ir->dev, &ir->ir, data);
- ir_input_nokey(ir->dev, &ir->ir);
+ rc_keydown_notimeout(ir->dev, data, 0);
+ rc_keyup(ir->dev);
}
}
@@ -141,8 +118,8 @@ static int get_key_flydvb_trio(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
struct saa7134_dev *dev = ir->c->adapter->algo_data;
if (dev == NULL) {
- dprintk("get_key_flydvb_trio: "
- "gir->c->adapter->algo_data is NULL!\n");
+ i2cdprintk("get_key_flydvb_trio: "
+ "ir->c->adapter->algo_data is NULL!\n");
return -EIO;
}
@@ -195,8 +172,8 @@ static int get_key_msi_tvanywhere_plus(struct IR_i2c *ir, u32 *ir_key,
/* <dev> is needed to access GPIO. Used by the saa_readl macro. */
struct saa7134_dev *dev = ir->c->adapter->algo_data;
if (dev == NULL) {
- dprintk("get_key_msi_tvanywhere_plus: "
- "gir->c->adapter->algo_data is NULL!\n");
+ i2cdprintk("get_key_msi_tvanywhere_plus: "
+ "ir->c->adapter->algo_data is NULL!\n");
return -EIO;
}
@@ -300,22 +277,12 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
i2cdprintk("read error\n");
return -EIO;
}
- /* IR of this card normally decode signals NEC-standard from
- * - Sven IHOO MT 5.1R remote. xxyye718
- * - Sven DVD HD-10xx remote. xxyyf708
- * - BBK ...
- * - mayby others
- * So, skip not our, if disable full codes mode.
- */
- if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir)
- return 0;
- /* Wrong data decode fix */
if (data[9] != (unsigned char)(~data[8]))
return 0;
- *ir_key = data[9];
- *ir_raw = data[9];
+ *ir_raw = ((data[10] << 16) | (data[11] << 8) | (data[9] << 0));
+ *ir_key = *ir_raw;
return 1;
}
@@ -400,7 +367,7 @@ static int get_key_pinnacle_color(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
void saa7134_input_irq(struct saa7134_dev *dev)
{
- struct card_ir *ir;
+ struct saa7134_card_ir *ir;
if (!dev || !dev->remote)
return;
@@ -409,12 +376,8 @@ void saa7134_input_irq(struct saa7134_dev *dev)
if (!ir->running)
return;
- if (ir->nec_gpio) {
- saa7134_nec_irq(dev);
- } else if (!ir->polling && !ir->rc5_gpio && !ir->raw_decode) {
+ if (!ir->polling && !ir->raw_decode) {
build_key(dev);
- } else if (ir->rc5_gpio) {
- saa7134_rc5_irq(dev);
} else if (ir->raw_decode) {
saa7134_raw_decode_irq(dev);
}
@@ -423,66 +386,46 @@ void saa7134_input_irq(struct saa7134_dev *dev)
static void saa7134_input_timer(unsigned long data)
{
struct saa7134_dev *dev = (struct saa7134_dev *)data;
- struct card_ir *ir = dev->remote;
+ struct saa7134_card_ir *ir = dev->remote;
build_key(dev);
mod_timer(&ir->timer, jiffies + msecs_to_jiffies(ir->polling));
}
-void ir_raw_decode_timer_end(unsigned long data)
+static void ir_raw_decode_timer_end(unsigned long data)
{
struct saa7134_dev *dev = (struct saa7134_dev *)data;
- struct card_ir *ir = dev->remote;
+ struct saa7134_card_ir *ir = dev->remote;
ir_raw_event_handle(dev->remote->dev);
- ir->active = 0;
+ ir->active = false;
}
static int __saa7134_ir_start(void *priv)
{
struct saa7134_dev *dev = priv;
- struct card_ir *ir;
+ struct saa7134_card_ir *ir;
- if (!dev)
+ if (!dev || !dev->remote)
return -EINVAL;
ir = dev->remote;
- if (!ir)
- return -EINVAL;
-
if (ir->running)
return 0;
- ir->running = 1;
+ ir->running = true;
+ ir->active = false;
+
if (ir->polling) {
setup_timer(&ir->timer, saa7134_input_timer,
(unsigned long)dev);
- ir->timer.expires = jiffies + HZ;
+ ir->timer.expires = jiffies + HZ;
add_timer(&ir->timer);
- } else if (ir->rc5_gpio) {
- /* set timer_end for code completion */
- init_timer(&ir->timer_end);
- ir->timer_end.function = ir_rc5_timer_end;
- ir->timer_end.data = (unsigned long)ir;
- init_timer(&ir->timer_keyup);
- ir->timer_keyup.function = ir_rc5_timer_keyup;
- ir->timer_keyup.data = (unsigned long)ir;
- ir->shift_by = 2;
- ir->start = 0x2;
- ir->addr = 0x17;
- ir->rc5_key_timeout = ir_rc5_key_timeout;
- ir->rc5_remote_gap = ir_rc5_remote_gap;
- } else if (ir->nec_gpio) {
- setup_timer(&ir->timer_keyup, saa7134_nec_timer,
- (unsigned long)dev);
- tasklet_init(&ir->tlet, nec_task, (unsigned long)dev);
} else if (ir->raw_decode) {
/* set timer_end for code completion */
- init_timer(&ir->timer_end);
- ir->timer_end.function = ir_raw_decode_timer_end;
- ir->timer_end.data = (unsigned long)dev;
- ir->active = 0;
+ setup_timer(&ir->timer, ir_raw_decode_timer_end,
+ (unsigned long)dev);
}
return 0;
@@ -491,29 +434,20 @@ static int __saa7134_ir_start(void *priv)
static void __saa7134_ir_stop(void *priv)
{
struct saa7134_dev *dev = priv;
- struct card_ir *ir;
+ struct saa7134_card_ir *ir;
- if (!dev)
+ if (!dev || !dev->remote)
return;
ir = dev->remote;
- if (!ir)
- return;
-
if (!ir->running)
return;
- if (dev->remote->polling)
- del_timer_sync(&dev->remote->timer);
- else if (ir->rc5_gpio)
- del_timer_sync(&ir->timer_end);
- else if (ir->nec_gpio)
- tasklet_kill(&ir->tlet);
- else if (ir->raw_decode) {
- del_timer_sync(&ir->timer_end);
- ir->active = 0;
- }
- ir->running = 0;
+ if (ir->polling || ir->raw_decode)
+ del_timer_sync(&ir->timer);
+
+ ir->active = false;
+ ir->running = false;
return;
}
@@ -532,71 +466,33 @@ void saa7134_ir_stop(struct saa7134_dev *dev)
__saa7134_ir_stop(dev);
}
-static int saa7134_ir_open(void *priv)
+static int saa7134_ir_open(struct rc_dev *rc)
{
- struct saa7134_dev *dev = priv;
+ struct saa7134_dev *dev = rc->priv;
dev->remote->users++;
return __saa7134_ir_start(dev);
}
-static void saa7134_ir_close(void *priv)
+static void saa7134_ir_close(struct rc_dev *rc)
{
- struct saa7134_dev *dev = priv;
+ struct saa7134_dev *dev = rc->priv;
dev->remote->users--;
if (!dev->remote->users)
__saa7134_ir_stop(dev);
}
-
-int saa7134_ir_change_protocol(void *priv, u64 ir_type)
-{
- struct saa7134_dev *dev = priv;
- struct card_ir *ir = dev->remote;
- u32 nec_gpio, rc5_gpio;
-
- if (ir_type == IR_TYPE_RC5) {
- dprintk("Changing protocol to RC5\n");
- nec_gpio = 0;
- rc5_gpio = 1;
- } else if (ir_type == IR_TYPE_NEC) {
- dprintk("Changing protocol to NEC\n");
- nec_gpio = 1;
- rc5_gpio = 0;
- } else {
- dprintk("IR protocol type %ud is not supported\n",
- (unsigned)ir_type);
- return -EINVAL;
- }
-
- if (ir->running) {
- saa7134_ir_stop(dev);
- ir->nec_gpio = nec_gpio;
- ir->rc5_gpio = rc5_gpio;
- saa7134_ir_start(dev);
- } else {
- ir->nec_gpio = nec_gpio;
- ir->rc5_gpio = rc5_gpio;
- }
-
- return 0;
-}
-
int saa7134_input_init1(struct saa7134_dev *dev)
{
- struct card_ir *ir;
- struct input_dev *input_dev;
+ struct saa7134_card_ir *ir;
+ struct rc_dev *rc;
char *ir_codes = NULL;
u32 mask_keycode = 0;
u32 mask_keydown = 0;
u32 mask_keyup = 0;
- int polling = 0;
- int rc5_gpio = 0;
- int nec_gpio = 0;
- int raw_decode = 0;
- int allow_protocol_change = 0;
- u64 ir_type = IR_TYPE_OTHER;
+ unsigned polling = 0;
+ bool raw_decode = false;
int err;
if (dev->has_remote != SAA7134_REMOTE_GPIO)
@@ -657,11 +553,18 @@ int saa7134_input_init1(struct saa7134_dev *dev)
saa_setb(SAA7134_GPIO_GPSTATUS0, 0x4);
break;
case SAA7134_BOARD_AVERMEDIA_M135A:
- ir_codes = RC_MAP_AVERMEDIA_M135A_RM_JX;
+ ir_codes = RC_MAP_AVERMEDIA_M135A;
mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
mask_keyup = 0x0040000;
mask_keycode = 0xffff;
- raw_decode = 1;
+ raw_decode = true;
+ break;
+ case SAA7134_BOARD_AVERMEDIA_M733A:
+ ir_codes = RC_MAP_AVERMEDIA_M733A_RM_K6;
+ mask_keydown = 0x0040000;
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
break;
case SAA7134_BOARD_AVERMEDIA_777:
case SAA7134_BOARD_AVERMEDIA_A16AR:
@@ -765,8 +668,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
case SAA7134_BOARD_ASUSTeK_P7131_ANALOG:
ir_codes = RC_MAP_ASUS_PC39;
- mask_keydown = 0x0040000;
- rc5_gpio = 1;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
break;
case SAA7134_BOARD_ENCORE_ENLTV:
case SAA7134_BOARD_ENCORE_ENLTV_FM:
@@ -777,9 +682,10 @@ int saa7134_input_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_ENCORE_ENLTV_FM53:
ir_codes = RC_MAP_ENCORE_ENLTV_FM53;
- mask_keydown = 0x0040000;
- mask_keycode = 0x00007f;
- nec_gpio = 1;
+ mask_keydown = 0x0040000; /* Enable GPIO18 line on both edges */
+ mask_keyup = 0x0040000;
+ mask_keycode = 0xffff;
+ raw_decode = true;
break;
case SAA7134_BOARD_10MOONSTVMASTER3:
ir_codes = RC_MAP_ENCORE_ENLTV;
@@ -815,7 +721,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
mask_keyup = 0x020000;
polling = 50; /* ms */
break;
- break;
+ case SAA7134_BOARD_VIDEOMATE_M1F:
+ ir_codes = RC_MAP_VIDEOMATE_M1F;
+ mask_keycode = 0x0ff00;
+ mask_keyup = 0x040000;
+ break;
}
if (NULL == ir_codes) {
printk("%s: Oops: IR config error [card=%d]\n",
@@ -824,24 +734,20 @@ int saa7134_input_init1(struct saa7134_dev *dev)
}
ir = kzalloc(sizeof(*ir), GFP_KERNEL);
- input_dev = input_allocate_device();
- if (!ir || !input_dev) {
+ rc = rc_allocate_device();
+ if (!ir || !rc) {
err = -ENOMEM;
goto err_out_free;
}
- ir->dev = input_dev;
+ ir->dev = rc;
dev->remote = ir;
- ir->running = 0;
-
/* init hardware-specific stuff */
ir->mask_keycode = mask_keycode;
ir->mask_keydown = mask_keydown;
ir->mask_keyup = mask_keyup;
ir->polling = polling;
- ir->rc5_gpio = rc5_gpio;
- ir->nec_gpio = nec_gpio;
ir->raw_decode = raw_decode;
/* init input device */
@@ -850,47 +756,35 @@ int saa7134_input_init1(struct saa7134_dev *dev)
snprintf(ir->phys, sizeof(ir->phys), "pci-%s/ir0",
pci_name(dev->pci));
-
- ir->props.priv = dev;
- ir->props.open = saa7134_ir_open;
- ir->props.close = saa7134_ir_close;
-
+ rc->priv = dev;
+ rc->open = saa7134_ir_open;
+ rc->close = saa7134_ir_close;
if (raw_decode)
- ir->props.driver_type = RC_DRIVER_IR_RAW;
-
- if (!raw_decode && allow_protocol_change) {
- ir->props.allowed_protos = IR_TYPE_RC5 | IR_TYPE_NEC;
- ir->props.change_protocol = saa7134_ir_change_protocol;
- }
+ rc->driver_type = RC_DRIVER_IR_RAW;
- err = ir_input_init(input_dev, &ir->ir, ir_type);
- if (err < 0)
- goto err_out_free;
-
- input_dev->name = ir->name;
- input_dev->phys = ir->phys;
- input_dev->id.bustype = BUS_PCI;
- input_dev->id.version = 1;
+ rc->input_name = ir->name;
+ rc->input_phys = ir->phys;
+ rc->input_id.bustype = BUS_PCI;
+ rc->input_id.version = 1;
if (dev->pci->subsystem_vendor) {
- input_dev->id.vendor = dev->pci->subsystem_vendor;
- input_dev->id.product = dev->pci->subsystem_device;
+ rc->input_id.vendor = dev->pci->subsystem_vendor;
+ rc->input_id.product = dev->pci->subsystem_device;
} else {
- input_dev->id.vendor = dev->pci->vendor;
- input_dev->id.product = dev->pci->device;
+ rc->input_id.vendor = dev->pci->vendor;
+ rc->input_id.product = dev->pci->device;
}
- input_dev->dev.parent = &dev->pci->dev;
+ rc->dev.parent = &dev->pci->dev;
+ rc->map_name = ir_codes;
+ rc->driver_name = MODULE_NAME;
- err = ir_input_register(ir->dev, ir_codes, &ir->props, MODULE_NAME);
+ err = rc_register_device(rc);
if (err)
goto err_out_free;
- /* the remote isn't as bouncy as a keyboard */
- ir->dev->rep[REP_DELAY] = repeat_delay;
- ir->dev->rep[REP_PERIOD] = repeat_period;
-
return 0;
err_out_free:
+ rc_free_device(rc);
dev->remote = NULL;
kfree(ir);
return err;
@@ -902,7 +796,7 @@ void saa7134_input_fini(struct saa7134_dev *dev)
return;
saa7134_ir_stop(dev);
- ir_input_unregister(dev->remote->dev);
+ rc_unregister_device(dev->remote->dev);
kfree(dev->remote);
dev->remote = NULL;
}
@@ -910,14 +804,12 @@ void saa7134_input_fini(struct saa7134_dev *dev)
void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
{
struct i2c_board_info info;
-
struct i2c_msg msg_msi = {
.addr = 0x50,
.flags = I2C_M_RD,
.len = 0,
.buf = NULL,
};
-
int rc;
if (disable_ir) {
@@ -953,13 +845,18 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
dev->init_data.name = "MSI TV@nywhere Plus";
dev->init_data.get_key = get_key_msi_tvanywhere_plus;
dev->init_data.ir_codes = RC_MAP_MSI_TVANYWHERE_PLUS;
+ /*
+ * MSI TV@nyware Plus requires more frequent polling
+ * otherwise it will miss some keypresses
+ */
+ dev->init_data.polling_interval = 50;
info.addr = 0x30;
/* MSI TV@nywhere Plus controller doesn't seem to
respond to probes unless we read something from
an existing device. Weird...
REVISIT: might no longer be needed */
rc = i2c_transfer(&dev->i2c_adap, &msg_msi, 1);
- dprintk(KERN_DEBUG "probe 0x%02x @ %s: %s\n",
+ dprintk("probe 0x%02x @ %s: %s\n",
msg_msi.addr, dev->i2c_adap.name,
(1 == rc) ? "yes" : "no");
break;
@@ -987,7 +884,7 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
dev->init_data.name = "BeholdTV";
dev->init_data.get_key = get_key_beholdm6xx;
dev->init_data.ir_codes = RC_MAP_BEHOLD;
- dev->init_data.type = IR_TYPE_NEC;
+ dev->init_data.type = RC_TYPE_NEC;
info.addr = 0x2d;
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS_501:
@@ -1012,8 +909,8 @@ void saa7134_probe_i2c_ir(struct saa7134_dev *dev)
static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
{
- struct card_ir *ir = dev->remote;
- unsigned long timeout;
+ struct saa7134_card_ir *ir = dev->remote;
+ unsigned long timeout;
int space;
/* Generate initial event */
@@ -1022,7 +919,6 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
space = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
ir_raw_event_store_edge(dev->remote->dev, space ? IR_SPACE : IR_PULSE);
-
/*
* Wait 15 ms from the start of the first IR event before processing
* the event. This time is enough for NEC protocol. May need adjustments
@@ -1030,173 +926,9 @@ static int saa7134_raw_decode_irq(struct saa7134_dev *dev)
*/
if (!ir->active) {
timeout = jiffies + jiffies_to_msecs(15);
- mod_timer(&ir->timer_end, timeout);
- ir->active = 1;
- }
-
- return 1;
-}
-
-static int saa7134_rc5_irq(struct saa7134_dev *dev)
-{
- struct card_ir *ir = dev->remote;
- struct timeval tv;
- u32 gap;
- unsigned long current_jiffies, timeout;
-
- /* get time of bit */
- current_jiffies = jiffies;
- do_gettimeofday(&tv);
-
- /* avoid overflow with gap >1s */
- if (tv.tv_sec - ir->base_time.tv_sec > 1) {
- gap = 200000;
- } else {
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
- }
-
- /* active code => add bit */
- if (ir->active) {
- /* only if in the code (otherwise spurious IRQ or timer
- late) */
- if (ir->last_bit < 28) {
- ir->last_bit = (gap - ir_rc5_remote_gap / 2) /
- ir_rc5_remote_gap;
- ir->code |= 1 << ir->last_bit;
- }
- /* starting new code */
- } else {
- ir->active = 1;
- ir->code = 0;
- ir->base_time = tv;
- ir->last_bit = 0;
-
- timeout = current_jiffies + (500 + 30 * HZ) / 1000;
- mod_timer(&ir->timer_end, timeout);
- }
-
- return 1;
-}
-
-/* On NEC protocol, One has 2.25 ms, and zero has 1.125 ms
- The first pulse (start) has 9 + 4.5 ms
- */
-
-static void saa7134_nec_timer(unsigned long data)
-{
- struct saa7134_dev *dev = (struct saa7134_dev *) data;
- struct card_ir *ir = dev->remote;
-
- dprintk("Cancel key repeat\n");
-
- ir_input_nokey(ir->dev, &ir->ir);
-}
-
-static void nec_task(unsigned long data)
-{
- struct saa7134_dev *dev = (struct saa7134_dev *) data;
- struct card_ir *ir;
- struct timeval tv;
- int count, pulse, oldpulse, gap;
- u32 ircode = 0, not_code = 0;
- int ngap = 0;
-
- if (!data) {
- printk(KERN_ERR "saa713x/ir: Can't recover dev struct\n");
- /* GPIO will be kept disabled */
- return;
+ mod_timer(&ir->timer, timeout);
+ ir->active = true;
}
- ir = dev->remote;
-
- /* rising SAA7134_GPIO_GPRESCAN reads the status */
- saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
- saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
-
- oldpulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2) & ir->mask_keydown;
- pulse = oldpulse;
-
- do_gettimeofday(&tv);
- ir->base_time = tv;
-
- /* Decode NEC pulsecode. This code can take up to 76.5 ms to run.
- Unfortunately, using IRQ to decode pulse didn't work, since it uses
- a pulse train of 38KHz. This means one pulse on each 52 us
- */
- do {
- /* Wait until the end of pulse/space or 5 ms */
- for (count = 0; count < 500; count++) {
- udelay(10);
- /* rising SAA7134_GPIO_GPRESCAN reads the status */
- saa_clearb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
- saa_setb(SAA7134_GPIO_GPMODE3, SAA7134_GPIO_GPRESCAN);
- pulse = saa_readl(SAA7134_GPIO_GPSTATUS0 >> 2)
- & ir->mask_keydown;
- if (pulse != oldpulse)
- break;
- }
-
- do_gettimeofday(&tv);
- gap = 1000000 * (tv.tv_sec - ir->base_time.tv_sec) +
- tv.tv_usec - ir->base_time.tv_usec;
-
- if (!pulse) {
- /* Bit 0 has 560 us, while bit 1 has 1120 us.
- Do something only if bit == 1
- */
- if (ngap && (gap > 560 + 280)) {
- unsigned int shift = ngap - 1;
-
- /* Address first, then command */
- if (shift < 8) {
- shift += 8;
- ircode |= 1 << shift;
- } else if (shift < 16) {
- not_code |= 1 << shift;
- } else if (shift < 24) {
- shift -= 16;
- ircode |= 1 << shift;
- } else {
- shift -= 24;
- not_code |= 1 << shift;
- }
- }
- ngap++;
- }
-
-
- ir->base_time = tv;
-
- /* TIMEOUT - Long pulse */
- if (gap >= 5000)
- break;
- oldpulse = pulse;
- } while (ngap < 32);
-
- if (ngap == 32) {
- /* FIXME: should check if not_code == ~ircode */
- ir->code = ir_extract_bits(ircode, ir->mask_keycode);
-
- dprintk("scancode = 0x%02x (code = 0x%02x, notcode= 0x%02x)\n",
- ir->code, ircode, not_code);
-
- ir_input_keydown(ir->dev, &ir->ir, ir->code);
- } else
- dprintk("Repeat last key\n");
-
- /* Keep repeating the last key */
- mod_timer(&ir->timer_keyup, jiffies + msecs_to_jiffies(150));
-
- saa_setl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
-}
-
-static int saa7134_nec_irq(struct saa7134_dev *dev)
-{
- struct card_ir *ir = dev->remote;
-
- saa_clearl(SAA7134_IRQ2, SAA7134_IRQ2_INTE_GPIO18_P);
- tasklet_schedule(&ir->tlet);
-
return 1;
}
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 3e7d2fd1688f..57e646bb48b3 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -550,16 +550,16 @@ static int tvaudio_thread(void *data)
} else if (0 != dev->last_carrier) {
/* no carrier -- try last detected one as fallback */
carrier = dev->last_carrier;
- dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "
- "using %d.%03d MHz [last detected]\n",
- dev->name, carrier/1000, carrier%1000);
+ dprintk("audio carrier scan failed, "
+ "using %d.%03d MHz [last detected]\n",
+ carrier/1000, carrier%1000);
} else {
/* no carrier + no fallback -- use default */
carrier = default_carrier;
- dprintk(KERN_WARNING "%s/audio: audio carrier scan failed, "
- "using %d.%03d MHz [default]\n",
- dev->name, carrier/1000, carrier%1000);
+ dprintk("audio carrier scan failed, "
+ "using %d.%03d MHz [default]\n",
+ carrier/1000, carrier%1000);
}
tvaudio_setcarrier(dev,carrier,carrier);
dev->automute = 0;
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 45f0ac8f3c0f..776ba2dd7f9f 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -30,7 +30,7 @@
#include "saa7134-reg.h"
#include "saa7134.h"
#include <media/v4l2-common.h>
-#include <media/rds.h>
+#include <media/saa6588.h>
/* ------------------------------------------------------------------ */
@@ -1366,13 +1366,13 @@ static int video_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7134_buf),
- fh);
+ fh, NULL);
videobuf_queue_sg_init(&fh->vbi, &saa7134_vbi_qops,
&dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB,
sizeof(struct saa7134_buf),
- fh);
+ fh, NULL);
saa7134_pgtable_alloc(dev->pci,&fh->pt_cap);
saa7134_pgtable_alloc(dev->pci,&fh->pt_vbi);
@@ -1459,7 +1459,7 @@ static int video_release(struct file *file)
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
- struct rds_command cmd;
+ struct saa6588_command cmd;
unsigned long flags;
/* turn off overlay */
@@ -1494,7 +1494,7 @@ static int video_release(struct file *file)
saa_call_all(dev, core, s_power, 0);
if (fh->radio)
- saa_call_all(dev, core, ioctl, RDS_CMD_CLOSE, &cmd);
+ saa_call_all(dev, core, ioctl, SAA6588_CMD_CLOSE, &cmd);
/* free stuff */
videobuf_mmap_free(&fh->cap);
@@ -1520,14 +1520,14 @@ static ssize_t radio_read(struct file *file, char __user *data,
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
- struct rds_command cmd;
+ struct saa6588_command cmd;
cmd.block_count = count/3;
cmd.buffer = data;
cmd.instance = file;
cmd.result = -ENODEV;
- saa_call_all(dev, core, ioctl, RDS_CMD_READ, &cmd);
+ saa_call_all(dev, core, ioctl, SAA6588_CMD_READ, &cmd);
return cmd.result;
}
@@ -1536,12 +1536,12 @@ static unsigned int radio_poll(struct file *file, poll_table *wait)
{
struct saa7134_fh *fh = file->private_data;
struct saa7134_dev *dev = fh->dev;
- struct rds_command cmd;
+ struct saa6588_command cmd;
cmd.instance = file;
cmd.event_list = wait;
cmd.result = -ENODEV;
- saa_call_all(dev, core, ioctl, RDS_CMD_POLL, &cmd);
+ saa_call_all(dev, core, ioctl, SAA6588_CMD_POLL, &cmd);
return cmd.result;
}
@@ -1748,7 +1748,6 @@ static int saa7134_enum_input(struct file *file, void *priv,
return -EINVAL;
if (NULL == card_in(dev, i->index).name)
return -EINVAL;
- memset(i, 0, sizeof(*i));
i->index = n;
i->type = V4L2_INPUT_TYPE_CAMERA;
strcpy(i->name, card_in(dev, n).name);
@@ -1825,7 +1824,7 @@ static int saa7134_querycap(struct file *file, void *priv,
if ((tuner_type == TUNER_ABSENT) || (tuner_type == UNSET))
cap->capabilities &= ~V4L2_CAP_TUNER;
- return 0;
+ return 0;
}
int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_std_id *id)
@@ -1871,9 +1870,12 @@ int saa7134_s_std_internal(struct saa7134_dev *dev, struct saa7134_fh *fh, v4l2_
else
fixup = V4L2_STD_SECAM;
}
- for (i = 0; i < TVNORMS; i++)
+ for (i = 0; i < TVNORMS; i++) {
if (fixup == tvnorms[i].id)
break;
+ }
+ if (i == TVNORMS)
+ return -EINVAL;
}
*id = tvnorms[i].id;
@@ -1997,9 +1999,12 @@ static int saa7134_g_tuner(struct file *file, void *priv,
if (0 != t->index)
return -EINVAL;
memset(t, 0, sizeof(*t));
- for (n = 0; n < SAA7134_INPUT_MAX; n++)
+ for (n = 0; n < SAA7134_INPUT_MAX; n++) {
if (card_in(dev, n).tv)
break;
+ }
+ if (n == SAA7134_INPUT_MAX)
+ return -EINVAL;
if (NULL != card_in(dev, n).name) {
strcpy(t->name, "Television");
t->type = V4L2_TUNER_ANALOG_TV;
@@ -2205,14 +2210,6 @@ static int saa7134_overlay(struct file *file, void *f, unsigned int on)
return 0;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct saa7134_fh *fh = file->private_data;
- return videobuf_cgmbuf(saa7134_queue(fh), mbuf, 8);
-}
-#endif
-
static int saa7134_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
@@ -2450,9 +2447,6 @@ static const struct v4l2_ioctl_ops video_ioctl_ops = {
.vidioc_streamoff = saa7134_streamoff,
.vidioc_g_tuner = saa7134_g_tuner,
.vidioc_s_tuner = saa7134_s_tuner,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
.vidioc_g_crop = saa7134_g_crop,
.vidioc_s_crop = saa7134_s_crop,
.vidioc_g_fbuf = saa7134_g_fbuf,
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index 3962534267be..5b0a347b0b8f 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -37,7 +37,7 @@
#include <media/v4l2-ioctl.h>
#include <media/v4l2-device.h>
#include <media/tuner.h>
-#include <media/ir-common.h>
+#include <media/rc-core.h>
#include <media/ir-kbd-i2c.h>
#include <media/videobuf-dma-sg.h>
#include <sound/core.h>
@@ -119,6 +119,26 @@ struct saa7134_format {
unsigned int uvswap:1;
};
+struct saa7134_card_ir {
+ struct rc_dev *dev;
+
+ char name[32];
+ char phys[32];
+ unsigned users;
+
+ u32 polling;
+ u32 last_gpio;
+ u32 mask_keycode, mask_keydown, mask_keyup;
+
+ bool running;
+ bool active;
+
+ struct timer_list timer;
+
+ /* IR core raw decoding */
+ u32 raw_decode;
+};
+
/* ----------------------------------------------------------- */
/* card configuration */
@@ -303,6 +323,10 @@ struct saa7134_format {
#define SAA7134_BOARD_HAWELL_HW_404M7 177
#define SAA7134_BOARD_BEHOLD_H7 178
#define SAA7134_BOARD_BEHOLD_A7 179
+#define SAA7134_BOARD_AVERMEDIA_M733A 180
+#define SAA7134_BOARD_TECHNOTREND_BUDGET_T3000 181
+#define SAA7134_BOARD_KWORLD_PCI_SBTVD_FULLSEG 182
+#define SAA7134_BOARD_VIDEOMATE_M1F 183
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
@@ -527,7 +551,7 @@ struct saa7134_dev {
/* infrared remote */
int has_remote;
- struct card_ir *remote;
+ struct saa7134_card_ir *remote;
/* pci i/o */
char name[32];
@@ -808,16 +832,18 @@ void saa7134_irq_oss_done(struct saa7134_dev *dev, unsigned long status);
/* ----------------------------------------------------------- */
/* saa7134-input.c */
+#if defined(CONFIG_VIDEO_SAA7134_RC)
int saa7134_input_init1(struct saa7134_dev *dev);
void saa7134_input_fini(struct saa7134_dev *dev);
void saa7134_input_irq(struct saa7134_dev *dev);
void saa7134_probe_i2c_ir(struct saa7134_dev *dev);
int saa7134_ir_start(struct saa7134_dev *dev);
void saa7134_ir_stop(struct saa7134_dev *dev);
-
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
+#else
+#define saa7134_input_init1(dev) (0)
+#define saa7134_input_fini(dev) (0)
+#define saa7134_input_irq(dev) (0)
+#define saa7134_probe_i2c_ir(dev) (0)
+#define saa7134_ir_start(dev) (0)
+#define saa7134_ir_stop(dev) (0)
+#endif
diff --git a/drivers/media/video/saa7164/Makefile b/drivers/media/video/saa7164/Makefile
index 4b329fd42add..6303a8e60eac 100644
--- a/drivers/media/video/saa7164/Makefile
+++ b/drivers/media/video/saa7164/Makefile
@@ -1,6 +1,6 @@
saa7164-objs := saa7164-cards.o saa7164-core.o saa7164-i2c.o saa7164-dvb.o \
saa7164-fw.o saa7164-bus.o saa7164-cmd.o saa7164-api.o \
- saa7164-buffer.o
+ saa7164-buffer.o saa7164-encoder.o saa7164-vbi.o
obj-$(CONFIG_VIDEO_SAA7164) += saa7164.o
diff --git a/drivers/media/video/saa7164/saa7164-api.c b/drivers/media/video/saa7164/saa7164-api.c
index 3f1262b00cc0..bd86d970f4c2 100644
--- a/drivers/media/video/saa7164/saa7164-api.c
+++ b/drivers/media/video/saa7164/saa7164-api.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,14 +24,774 @@
#include "saa7164.h"
-int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode)
+int saa7164_api_get_load_info(struct saa7164_dev *dev, struct tmFwInfoStruct *i)
{
int ret;
+ if (!(saa_debug & DBGLVL_CPU))
+ return 0;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ i->deviceinst = 0;
+ i->devicespec = 0;
+ i->mode = 0;
+ i->status = 0;
+
+ ret = saa7164_cmd_send(dev, 0, GET_CUR,
+ GET_FW_STATUS_CONTROL, sizeof(struct tmFwInfoStruct), i);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ printk(KERN_INFO "saa7164[%d]-CPU: %d percent", dev->nr, i->CPULoad);
+
+ return ret;
+}
+
+int saa7164_api_collect_debug(struct saa7164_dev *dev)
+{
+ struct tmComResDebugGetData d;
+ u8 more = 255;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ while (more--) {
+
+ memset(&d, 0, sizeof(d));
+
+ ret = saa7164_cmd_send(dev, 0, GET_CUR,
+ GET_DEBUG_DATA_CONTROL, sizeof(d), &d);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n",
+ __func__, ret);
+
+ if (d.dwResult != SAA_OK)
+ break;
+
+ printk(KERN_INFO "saa7164[%d]-FWMSG: %s", dev->nr,
+ d.ucDebugData);
+ }
+
+ return 0;
+}
+
+int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level)
+{
+ struct tmComResDebugSetLevel lvl;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(level=%d)\n", __func__, level);
+
+ /* Retrieve current state */
+ ret = saa7164_cmd_send(dev, 0, GET_CUR,
+ SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_API, "%s() Was %d\n", __func__, lvl.dwDebugLevel);
+
+ lvl.dwDebugLevel = level;
+
+ /* set new state */
+ ret = saa7164_cmd_send(dev, 0, SET_CUR,
+ SET_DEBUG_LEVEL_CONTROL, sizeof(lvl), &lvl);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_set_vbi_format(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResProbeCommit fmt, rsp;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(nr=%d, unitid=0x%x)\n", __func__,
+ port->nr, port->hwcfg.unitid);
+
+ fmt.bmHint = 0;
+ fmt.bFormatIndex = 1;
+ fmt.bFrameIndex = 1;
+
+ /* Probe, see if it can support this format */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+ SET_CUR, SAA_PROBE_CONTROL, sizeof(fmt), &fmt);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() set error, ret = 0x%x\n", __func__, ret);
+
+ /* See of the format change was successful */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+ GET_CUR, SAA_PROBE_CONTROL, sizeof(rsp), &rsp);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() get error, ret = 0x%x\n", __func__, ret);
+ } else {
+ /* Compare requested vs received, should be same */
+ if (memcmp(&fmt, &rsp, sizeof(rsp)) == 0) {
+ dprintk(DBGLVL_API, "SET/PROBE Verified\n");
+
+ /* Ask the device to select the negotiated format */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+ SET_CUR, SAA_COMMIT_CONTROL, sizeof(fmt), &fmt);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() commit error, ret = 0x%x\n",
+ __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid,
+ GET_CUR, SAA_COMMIT_CONTROL, sizeof(rsp), &rsp);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() GET commit error, ret = 0x%x\n",
+ __func__, ret);
+
+ if (memcmp(&fmt, &rsp, sizeof(rsp)) != 0) {
+ printk(KERN_ERR "%s() memcmp error, ret = 0x%x\n",
+ __func__, ret);
+ } else
+ dprintk(DBGLVL_API, "SET/COMMIT Verified\n");
+
+ dprintk(DBGLVL_API, "rsp.bmHint = 0x%x\n", rsp.bmHint);
+ dprintk(DBGLVL_API, "rsp.bFormatIndex = 0x%x\n",
+ rsp.bFormatIndex);
+ dprintk(DBGLVL_API, "rsp.bFrameIndex = 0x%x\n",
+ rsp.bFrameIndex);
+ } else
+ printk(KERN_ERR "%s() compare failed\n", __func__);
+ }
+
+ if (ret == SAA_OK)
+ dprintk(DBGLVL_API, "%s(nr=%d) Success\n", __func__, port->nr);
+
+ return ret;
+}
+
+int saa7164_api_set_gop_size(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResEncVideoGopStructure gs;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ gs.ucRefFrameDist = port->encoder_params.refdist;
+ gs.ucGOPSize = port->encoder_params.gop_size;
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_VIDEO_GOP_STRUCTURE_CONTROL,
+ sizeof(gs), &gs);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_set_encoder(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResEncVideoBitRate vb;
+ struct tmComResEncAudioBitRate ab;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
+ port->hwcfg.sourceid);
+
+ if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
+ port->encoder_profile = EU_PROFILE_PS_DVD;
+ else
+ port->encoder_profile = EU_PROFILE_TS_HQ;
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Resolution */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Establish video bitrates */
+ if (port->encoder_params.bitrate_mode ==
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR)
+ vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_CONSTANT;
+ else
+ vb.ucVideoBitRateMode = EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK;
+ vb.dwVideoBitRate = port->encoder_params.bitrate;
+ vb.dwVideoBitRatePeak = port->encoder_params.bitrate_peak;
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_VIDEO_BIT_RATE_CONTROL,
+ sizeof(struct tmComResEncVideoBitRate),
+ &vb);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Establish audio bitrates */
+ ab.ucAudioBitRateMode = 0;
+ ab.dwAudioBitRate = 384000;
+ ab.dwAudioBitRatePeak = ab.dwAudioBitRate;
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_AUDIO_BIT_RATE_CONTROL,
+ sizeof(struct tmComResEncAudioBitRate),
+ &ab);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+ ret);
+
+ saa7164_api_set_aspect_ratio(port);
+ saa7164_api_set_gop_size(port);
+
+ return ret;
+}
+
+int saa7164_api_get_encoder(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResEncVideoBitRate v;
+ struct tmComResEncAudioBitRate a;
+ struct tmComResEncVideoInputAspectRatio ar;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s() unitid=0x%x\n", __func__,
+ port->hwcfg.sourceid);
+
+ port->encoder_profile = 0;
+ port->video_format = 0;
+ port->video_resolution = 0;
+ port->audio_format = 0;
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_PROFILE_CONTROL, sizeof(u8), &port->encoder_profile);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_VIDEO_RESOLUTION_CONTROL, sizeof(u8),
+ &port->video_resolution);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_VIDEO_FORMAT_CONTROL, sizeof(u8), &port->video_format);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_VIDEO_BIT_RATE_CONTROL, sizeof(v), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_AUDIO_FORMAT_CONTROL, sizeof(u8), &port->audio_format);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_AUDIO_BIT_RATE_CONTROL, sizeof(a), &a);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Aspect Ratio */
+ ar.width = 0;
+ ar.height = 0;
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, GET_CUR,
+ EU_VIDEO_INPUT_ASPECT_CONTROL,
+ sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_ENC, "encoder_profile = %d\n", port->encoder_profile);
+ dprintk(DBGLVL_ENC, "video_format = %d\n", port->video_format);
+ dprintk(DBGLVL_ENC, "audio_format = %d\n", port->audio_format);
+ dprintk(DBGLVL_ENC, "video_resolution= %d\n", port->video_resolution);
+ dprintk(DBGLVL_ENC, "v.ucVideoBitRateMode = %d\n",
+ v.ucVideoBitRateMode);
+ dprintk(DBGLVL_ENC, "v.dwVideoBitRate = %d\n",
+ v.dwVideoBitRate);
+ dprintk(DBGLVL_ENC, "v.dwVideoBitRatePeak = %d\n",
+ v.dwVideoBitRatePeak);
+ dprintk(DBGLVL_ENC, "a.ucVideoBitRateMode = %d\n",
+ a.ucAudioBitRateMode);
+ dprintk(DBGLVL_ENC, "a.dwVideoBitRate = %d\n",
+ a.dwAudioBitRate);
+ dprintk(DBGLVL_ENC, "a.dwVideoBitRatePeak = %d\n",
+ a.dwAudioBitRatePeak);
+ dprintk(DBGLVL_ENC, "aspect.width / height = %d:%d\n",
+ ar.width, ar.height);
+
+ return ret;
+}
+
+int saa7164_api_set_aspect_ratio(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResEncVideoInputAspectRatio ar;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s(%d)\n", __func__,
+ port->encoder_params.ctl_aspect);
+
+ switch (port->encoder_params.ctl_aspect) {
+ case V4L2_MPEG_VIDEO_ASPECT_1x1:
+ ar.width = 1;
+ ar.height = 1;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_4x3:
+ ar.width = 4;
+ ar.height = 3;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_16x9:
+ ar.width = 16;
+ ar.height = 9;
+ break;
+ case V4L2_MPEG_VIDEO_ASPECT_221x100:
+ ar.width = 221;
+ ar.height = 100;
+ break;
+ default:
+ BUG();
+ }
+
+ dprintk(DBGLVL_ENC, "%s(%d) now %d:%d\n", __func__,
+ port->encoder_params.ctl_aspect,
+ ar.width, ar.height);
+
+ /* Aspect Ratio */
+ ret = saa7164_cmd_send(port->dev, port->hwcfg.sourceid, SET_CUR,
+ EU_VIDEO_INPUT_ASPECT_CONTROL,
+ sizeof(struct tmComResEncVideoInputAspectRatio), &ar);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+ u16 val;
+
+ if (ctl == PU_BRIGHTNESS_CONTROL)
+ val = port->ctl_brightness;
+ else
+ if (ctl == PU_CONTRAST_CONTROL)
+ val = port->ctl_contrast;
+ else
+ if (ctl == PU_HUE_CONTROL)
+ val = port->ctl_hue;
+ else
+ if (ctl == PU_SATURATION_CONTROL)
+ val = port->ctl_saturation;
+ else
+ if (ctl == PU_SHARPNESS_CONTROL)
+ val = port->ctl_sharpness;
+ else
+ return -EINVAL;
+
+ dprintk(DBGLVL_ENC, "%s() unitid=0x%x ctl=%d, val=%d\n",
+ __func__, port->encunit.vsourceid, ctl, val);
+
+ ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, SET_CUR,
+ ctl, sizeof(u16), &val);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+ u16 val;
+
+ ret = saa7164_cmd_send(port->dev, port->encunit.vsourceid, GET_CUR,
+ ctl, sizeof(u16), &val);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+ return ret;
+ }
+
+ dprintk(DBGLVL_ENC, "%s() ctl=%d, val=%d\n",
+ __func__, ctl, val);
+
+ if (ctl == PU_BRIGHTNESS_CONTROL)
+ port->ctl_brightness = val;
+ else
+ if (ctl == PU_CONTRAST_CONTROL)
+ port->ctl_contrast = val;
+ else
+ if (ctl == PU_HUE_CONTROL)
+ port->ctl_hue = val;
+ else
+ if (ctl == PU_SATURATION_CONTROL)
+ port->ctl_saturation = val;
+ else
+ if (ctl == PU_SHARPNESS_CONTROL)
+ port->ctl_sharpness = val;
+
+ return ret;
+}
+
+int saa7164_api_set_videomux(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ u8 inputs[] = { 1, 2, 2, 2, 5, 5, 5 };
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s() v_mux=%d a_mux=%d\n",
+ __func__, port->mux_input, inputs[port->mux_input - 1]);
+
+ /* Audio Mute */
+ ret = saa7164_api_audio_mute(port, 1);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Video Mux */
+ ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, SET_CUR,
+ SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Audio Mux */
+ ret = saa7164_cmd_send(port->dev, port->audfeat.sourceid, SET_CUR,
+ SU_INPUT_SELECT_CONTROL, sizeof(u8),
+ &inputs[port->mux_input - 1]);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Audio UnMute */
+ ret = saa7164_api_audio_mute(port, 0);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_audio_mute(struct saa7164_port *port, int mute)
+{
+ struct saa7164_dev *dev = port->dev;
+ u8 v = mute;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(%d)\n", __func__, mute);
+
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+ MUTE_CONTROL, sizeof(u8), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ return ret;
+}
+
+/* 0 = silence, 0xff = full */
+int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level)
+{
+ struct saa7164_dev *dev = port->dev;
+ s16 v, min, max;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(%d)\n", __func__, level);
+
+ /* Obtain the min/max ranges */
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MIN,
+ VOLUME_CONTROL, sizeof(u16), &min);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_MAX,
+ VOLUME_CONTROL, sizeof(u16), &max);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
+ (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
+ level, min, max, v);
+
+ v = level;
+ if (v < min)
+ v = min;
+ if (v > max)
+ v = max;
+
+ /* Left */
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+ (0x01 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Right */
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+ (0x02 << 8) | VOLUME_CONTROL, sizeof(s16), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, GET_CUR,
+ (0x01 << 8) | VOLUME_CONTROL, sizeof(u16), &v);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_API, "%s(%d) min=%d max=%d cur=%d\n", __func__,
+ level, min, max, v);
+
+ return ret;
+}
+
+int saa7164_api_set_audio_std(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResAudioDefaults lvl;
+ struct tmComResTunerStandard tvaudio;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s()\n", __func__);
+
+ /* Establish default levels */
+ lvl.ucDecoderLevel = TMHW_LEV_ADJ_DECLEV_DEFAULT;
+ lvl.ucDecoderFM_Level = TMHW_LEV_ADJ_DECLEV_DEFAULT;
+ lvl.ucMonoLevel = TMHW_LEV_ADJ_MONOLEV_DEFAULT;
+ lvl.ucNICAM_Level = TMHW_LEV_ADJ_NICLEV_DEFAULT;
+ lvl.ucSAP_Level = TMHW_LEV_ADJ_SAPLEV_DEFAULT;
+ lvl.ucADC_Level = TMHW_LEV_ADJ_ADCLEV_DEFAULT;
+ ret = saa7164_cmd_send(port->dev, port->audfeat.unitid, SET_CUR,
+ AUDIO_DEFAULT_CONTROL, sizeof(struct tmComResAudioDefaults),
+ &lvl);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ /* Manually select the appropriate TV audio standard */
+ if (port->encodernorm.id & V4L2_STD_NTSC) {
+ tvaudio.std = TU_STANDARD_NTSC_M;
+ tvaudio.country = 1;
+ } else {
+ tvaudio.std = TU_STANDARD_PAL_I;
+ tvaudio.country = 44;
+ }
+
+ ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
+ TU_STANDARD_CONTROL, sizeof(tvaudio), &tvaudio);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() TU_STANDARD_CONTROL error, ret = 0x%x\n",
+ __func__, ret);
+ return ret;
+}
+
+int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct tmComResTunerStandardAuto p;
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(%d)\n", __func__, autodetect);
+
+ /* Disable TV Audio autodetect if not already set (buggy) */
+ if (autodetect)
+ p.mode = TU_STANDARD_AUTO;
+ else
+ p.mode = TU_STANDARD_MANUAL;
+ ret = saa7164_cmd_send(port->dev, port->tunerunit.unitid, SET_CUR,
+ TU_STANDARD_AUTO_CONTROL, sizeof(p), &p);
+ if (ret != SAA_OK)
+ printk(KERN_ERR
+ "%s() TU_STANDARD_AUTO_CONTROL error, ret = 0x%x\n",
+ __func__, ret);
+
+ return ret;
+}
+
+int saa7164_api_get_videomux(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+
+ ret = saa7164_cmd_send(port->dev, port->vidproc.sourceid, GET_CUR,
+ SU_INPUT_SELECT_CONTROL, sizeof(u8), &port->mux_input);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+
+ dprintk(DBGLVL_ENC, "%s() v_mux=%d\n",
+ __func__, port->mux_input);
+
+ return ret;
+}
+
+int saa7164_api_set_dif(struct saa7164_port *port, u8 reg, u8 val)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ u16 len = 0;
+ u8 buf[256];
+ int ret;
+ u8 mas;
+
+ dprintk(DBGLVL_API, "%s(nr=%d type=%d val=%x)\n", __func__,
+ port->nr, port->type, val);
+
+ if (port->nr == 0)
+ mas = 0xd0;
+ else
+ mas = 0xe0;
+
+ memset(buf, 0, sizeof(buf));
+
+ buf[0x00] = 0x04;
+ buf[0x01] = 0x00;
+ buf[0x02] = 0x00;
+ buf[0x03] = 0x00;
+
+ buf[0x04] = 0x04;
+ buf[0x05] = 0x00;
+ buf[0x06] = 0x00;
+ buf[0x07] = 0x00;
+
+ buf[0x08] = reg;
+ buf[0x09] = 0x26;
+ buf[0x0a] = mas;
+ buf[0x0b] = 0xb0;
+
+ buf[0x0c] = val;
+ buf[0x0d] = 0x00;
+ buf[0x0e] = 0x00;
+ buf[0x0f] = 0x00;
+
+ ret = saa7164_cmd_send(dev, port->ifunit.unitid, GET_LEN,
+ EXU_REGISTER_ACCESS_CONTROL, sizeof(len), &len);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret(1) = 0x%x\n", __func__, ret);
+ return -EIO;
+ }
+
+ ret = saa7164_cmd_send(dev, port->ifunit.unitid, SET_CUR,
+ EXU_REGISTER_ACCESS_CONTROL, len, &buf);
+ if (ret != SAA_OK)
+ printk(KERN_ERR "%s() error, ret(2) = 0x%x\n", __func__, ret);
+#if 0
+ saa7164_dumphex16(dev, buf, 16);
+#endif
+ return ret == SAA_OK ? 0 : -EIO;
+}
+
+/* Disable the IF block AGC controls */
+int saa7164_api_configure_dif(struct saa7164_port *port, u32 std)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret = 0;
+ u8 agc_disable;
+
+ dprintk(DBGLVL_API, "%s(nr=%d, 0x%x)\n", __func__, port->nr, std);
+
+ if (std & V4L2_STD_NTSC) {
+ dprintk(DBGLVL_API, " NTSC\n");
+ saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_I) {
+ dprintk(DBGLVL_API, " PAL-I\n");
+ saa7164_api_set_dif(port, 0x00, 0x08); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_M) {
+ dprintk(DBGLVL_API, " PAL-M\n");
+ saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_N) {
+ dprintk(DBGLVL_API, " PAL-N\n");
+ saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_Nc) {
+ dprintk(DBGLVL_API, " PAL-Nc\n");
+ saa7164_api_set_dif(port, 0x00, 0x01); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_B) {
+ dprintk(DBGLVL_API, " PAL-B\n");
+ saa7164_api_set_dif(port, 0x00, 0x02); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_PAL_DK) {
+ dprintk(DBGLVL_API, " PAL-DK\n");
+ saa7164_api_set_dif(port, 0x00, 0x10); /* Video Standard */
+ agc_disable = 0;
+ } else if (std & V4L2_STD_SECAM_L) {
+ dprintk(DBGLVL_API, " SECAM-L\n");
+ saa7164_api_set_dif(port, 0x00, 0x20); /* Video Standard */
+ agc_disable = 0;
+ } else {
+ /* Unknown standard, assume DTV */
+ dprintk(DBGLVL_API, " Unknown (assuming DTV)\n");
+ /* Undefinded Video Standard */
+ saa7164_api_set_dif(port, 0x00, 0x80);
+ agc_disable = 1;
+ }
+
+ saa7164_api_set_dif(port, 0x48, 0xa0); /* AGC Functions 1 */
+ saa7164_api_set_dif(port, 0xc0, agc_disable); /* AGC Output Disable */
+ saa7164_api_set_dif(port, 0x7c, 0x04); /* CVBS EQ */
+ saa7164_api_set_dif(port, 0x04, 0x01); /* Active */
+ msleep(100);
+ saa7164_api_set_dif(port, 0x04, 0x00); /* Active (again) */
+ msleep(100);
+
+ return ret;
+}
+
+/* Ensure the dif is in the correct state for the operating mode
+ * (analog / dtv). We only configure the diff through the analog encoder
+ * so when we're in digital mode we need to find the appropriate encoder
+ * and use it to configure the DIF.
+ */
+int saa7164_api_initialize_dif(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_port *p = 0;
+ int ret = -EINVAL;
+ u32 std = 0;
+
+ dprintk(DBGLVL_API, "%s(nr=%d type=%d)\n", __func__,
+ port->nr, port->type);
+
+ if (port->type == SAA7164_MPEG_ENCODER) {
+ /* Pick any analog standard to init the diff.
+ * we'll come back during encoder_init'
+ * and set the correct standard if requried.
+ */
+ std = V4L2_STD_NTSC;
+ } else
+ if (port->type == SAA7164_MPEG_DVB) {
+ if (port->nr == SAA7164_PORT_TS1)
+ p = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ p = &dev->ports[SAA7164_PORT_ENC2];
+ } else
+ if (port->type == SAA7164_MPEG_VBI) {
+ std = V4L2_STD_NTSC;
+ if (port->nr == SAA7164_PORT_VBI1)
+ p = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ p = &dev->ports[SAA7164_PORT_ENC2];
+ } else
+ BUG();
+
+ if (p)
+ ret = saa7164_api_configure_dif(p, std);
+
+ return ret;
+}
+
+int saa7164_api_transition_port(struct saa7164_port *port, u8 mode)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ int ret;
+
+ dprintk(DBGLVL_API, "%s(nr=%d unitid=0x%x,%d)\n",
+ __func__, port->nr, port->hwcfg.unitid, mode);
+
ret = saa7164_cmd_send(port->dev, port->hwcfg.unitid, SET_CUR,
SAA_STATE_CONTROL, sizeof(mode), &mode);
if (ret != SAA_OK)
- printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__, ret);
+ printk(KERN_ERR "%s(portnr %d unitid 0x%x) error, ret = 0x%x\n",
+ __func__, port->nr, port->hwcfg.unitid, ret);
return ret;
}
@@ -61,10 +821,45 @@ int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen)
&reg[0], 128, buf);
}
+int saa7164_api_configure_port_vbi(struct saa7164_dev *dev,
+ struct saa7164_port *port)
+{
+ struct tmComResVBIFormatDescrHeader *fmt = &port->vbi_fmt_ntsc;
+
+ dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex);
+ dprintk(DBGLVL_API, " VideoStandard = 0x%x\n", fmt->VideoStandard);
+ dprintk(DBGLVL_API, " StartLine = %d\n", fmt->StartLine);
+ dprintk(DBGLVL_API, " EndLine = %d\n", fmt->EndLine);
+ dprintk(DBGLVL_API, " FieldRate = %d\n", fmt->FieldRate);
+ dprintk(DBGLVL_API, " bNumLines = %d\n", fmt->bNumLines);
+
+ /* Cache the hardware configuration in the port */
+
+ port->bufcounter = port->hwcfg.BARLocation;
+ port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+ port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+ port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+ port->bufptr32l = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+ port->bufptr32h = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ port->bufptr64 = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
+ port->hwcfg.BARLocation);
+
+ dprintk(DBGLVL_API, " = VS_FORMAT_VBI (becomes dev->en[%d])\n",
+ port->nr);
+
+ return 0;
+}
int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
- struct saa7164_tsport *port,
- tmComResTSFormatDescrHeader_t *tsfmt)
+ struct saa7164_port *port,
+ struct tmComResTSFormatDescrHeader *tsfmt)
{
dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", tsfmt->bFormatIndex);
dprintk(DBGLVL_API, " bDataOffset = 0x%x\n", tsfmt->bDataOffset);
@@ -96,39 +891,80 @@ int saa7164_api_configure_port_mpeg2ts(struct saa7164_dev *dev,
return 0;
}
+int saa7164_api_configure_port_mpeg2ps(struct saa7164_dev *dev,
+ struct saa7164_port *port,
+ struct tmComResPSFormatDescrHeader *fmt)
+{
+ dprintk(DBGLVL_API, " bFormatIndex = 0x%x\n", fmt->bFormatIndex);
+ dprintk(DBGLVL_API, " wPacketLength= 0x%x\n", fmt->wPacketLength);
+ dprintk(DBGLVL_API, " wPackLength= 0x%x\n", fmt->wPackLength);
+ dprintk(DBGLVL_API, " bPackDataType= 0x%x\n", fmt->bPackDataType);
+
+ /* Cache the hardware configuration in the port */
+ /* TODO: CHECK THIS in the port config */
+ port->bufcounter = port->hwcfg.BARLocation;
+ port->pitch = port->hwcfg.BARLocation + (2 * sizeof(u32));
+ port->bufsize = port->hwcfg.BARLocation + (3 * sizeof(u32));
+ port->bufoffset = port->hwcfg.BARLocation + (4 * sizeof(u32));
+ port->bufptr32l = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount) + sizeof(u32);
+ port->bufptr32h = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ port->bufptr64 = port->hwcfg.BARLocation +
+ (4 * sizeof(u32)) +
+ (sizeof(u32) * port->hwcfg.buffercount);
+ dprintk(DBGLVL_API, " = port->hwcfg.BARLocation = 0x%x\n",
+ port->hwcfg.BARLocation);
+
+ dprintk(DBGLVL_API, " = VS_FORMAT_MPEGPS (becomes dev->enc[%d])\n",
+ port->nr);
+
+ return 0;
+}
+
int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
{
- struct saa7164_tsport *port = 0;
+ struct saa7164_port *tsport = 0;
+ struct saa7164_port *encport = 0;
+ struct saa7164_port *vbiport = 0;
u32 idx, next_offset;
int i;
- tmComResDescrHeader_t *hdr, *t;
- tmComResExtDevDescrHeader_t *exthdr;
- tmComResPathDescrHeader_t *pathhdr;
- tmComResAntTermDescrHeader_t *anttermhdr;
- tmComResTunerDescrHeader_t *tunerunithdr;
- tmComResDMATermDescrHeader_t *vcoutputtermhdr;
- tmComResTSFormatDescrHeader_t *tsfmt;
+ struct tmComResDescrHeader *hdr, *t;
+ struct tmComResExtDevDescrHeader *exthdr;
+ struct tmComResPathDescrHeader *pathhdr;
+ struct tmComResAntTermDescrHeader *anttermhdr;
+ struct tmComResTunerDescrHeader *tunerunithdr;
+ struct tmComResDMATermDescrHeader *vcoutputtermhdr;
+ struct tmComResTSFormatDescrHeader *tsfmt;
+ struct tmComResPSFormatDescrHeader *psfmt;
+ struct tmComResSelDescrHeader *psel;
+ struct tmComResProcDescrHeader *pdh;
+ struct tmComResAFeatureDescrHeader *afd;
+ struct tmComResEncoderDescrHeader *edh;
+ struct tmComResVBIFormatDescrHeader *vbifmt;
u32 currpath = 0;
dprintk(DBGLVL_API,
- "%s(?,?,%d) sizeof(tmComResDescrHeader_t) = %d bytes\n",
- __func__, len, (u32)sizeof(tmComResDescrHeader_t));
+ "%s(?,?,%d) sizeof(struct tmComResDescrHeader) = %d bytes\n",
+ __func__, len, (u32)sizeof(struct tmComResDescrHeader));
- for (idx = 0; idx < (len - sizeof(tmComResDescrHeader_t)); ) {
+ for (idx = 0; idx < (len - sizeof(struct tmComResDescrHeader));) {
- hdr = (tmComResDescrHeader_t *)(buf + idx);
+ hdr = (struct tmComResDescrHeader *)(buf + idx);
if (hdr->type != CS_INTERFACE)
return SAA_ERR_NOT_SUPPORTED;
- dprintk(DBGLVL_API, "@ 0x%x = \n", idx);
+ dprintk(DBGLVL_API, "@ 0x%x =\n", idx);
switch (hdr->subtype) {
case GENERAL_REQUEST:
dprintk(DBGLVL_API, " GENERAL_REQUEST\n");
break;
case VC_TUNER_PATH:
dprintk(DBGLVL_API, " VC_TUNER_PATH\n");
- pathhdr = (tmComResPathDescrHeader_t *)(buf + idx);
+ pathhdr = (struct tmComResPathDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " pathid = 0x%x\n",
pathhdr->pathid);
currpath = pathhdr->pathid;
@@ -136,7 +972,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
case VC_INPUT_TERMINAL:
dprintk(DBGLVL_API, " VC_INPUT_TERMINAL\n");
anttermhdr =
- (tmComResAntTermDescrHeader_t *)(buf + idx);
+ (struct tmComResAntTermDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " terminalid = 0x%x\n",
anttermhdr->terminalid);
dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
@@ -179,7 +1015,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
case VC_OUTPUT_TERMINAL:
dprintk(DBGLVL_API, " VC_OUTPUT_TERMINAL\n");
vcoutputtermhdr =
- (tmComResDMATermDescrHeader_t *)(buf + idx);
+ (struct tmComResDMATermDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " unitid = 0x%x\n",
vcoutputtermhdr->unitid);
dprintk(DBGLVL_API, " terminaltype = 0x%x\n",
@@ -233,32 +1069,50 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
dprintk(DBGLVL_API, " numformats = 0x%x\n",
vcoutputtermhdr->numformats);
- t = (tmComResDescrHeader_t *)
- ((tmComResDMATermDescrHeader_t *)(buf + idx));
+ t = (struct tmComResDescrHeader *)
+ ((struct tmComResDMATermDescrHeader *)(buf + idx));
next_offset = idx + (vcoutputtermhdr->len);
for (i = 0; i < vcoutputtermhdr->numformats; i++) {
- t = (tmComResDescrHeader_t *)
+ t = (struct tmComResDescrHeader *)
(buf + next_offset);
switch (t->subtype) {
case VS_FORMAT_MPEG2TS:
tsfmt =
- (tmComResTSFormatDescrHeader_t *)t;
+ (struct tmComResTSFormatDescrHeader *)t;
if (currpath == 1)
- port = &dev->ts1;
+ tsport = &dev->ports[SAA7164_PORT_TS1];
else
- port = &dev->ts2;
- memcpy(&port->hwcfg, vcoutputtermhdr,
+ tsport = &dev->ports[SAA7164_PORT_TS2];
+ memcpy(&tsport->hwcfg, vcoutputtermhdr,
sizeof(*vcoutputtermhdr));
saa7164_api_configure_port_mpeg2ts(dev,
- port, tsfmt);
+ tsport, tsfmt);
break;
case VS_FORMAT_MPEG2PS:
- dprintk(DBGLVL_API,
- " = VS_FORMAT_MPEG2PS\n");
+ psfmt =
+ (struct tmComResPSFormatDescrHeader *)t;
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->hwcfg, vcoutputtermhdr,
+ sizeof(*vcoutputtermhdr));
+ saa7164_api_configure_port_mpeg2ps(dev,
+ encport, psfmt);
break;
case VS_FORMAT_VBI:
- dprintk(DBGLVL_API,
- " = VS_FORMAT_VBI\n");
+ vbifmt =
+ (struct tmComResVBIFormatDescrHeader *)t;
+ if (currpath == 1)
+ vbiport = &dev->ports[SAA7164_PORT_VBI1];
+ else
+ vbiport = &dev->ports[SAA7164_PORT_VBI2];
+ memcpy(&vbiport->hwcfg, vcoutputtermhdr,
+ sizeof(*vcoutputtermhdr));
+ memcpy(&vbiport->vbi_fmt_ntsc, vbifmt,
+ sizeof(*vbifmt));
+ saa7164_api_configure_port_vbi(dev,
+ vbiport);
break;
case VS_FORMAT_RDS:
dprintk(DBGLVL_API,
@@ -284,7 +1138,7 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
case TUNER_UNIT:
dprintk(DBGLVL_API, " TUNER_UNIT\n");
tunerunithdr =
- (tmComResTunerDescrHeader_t *)(buf + idx);
+ (struct tmComResTunerDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " unitid = 0x%x\n",
tunerunithdr->unitid);
dprintk(DBGLVL_API, " sourceid = 0x%x\n",
@@ -297,22 +1151,92 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
tunerunithdr->controlsize);
dprintk(DBGLVL_API, " controls = 0x%x\n",
tunerunithdr->controls);
+
+ if (tunerunithdr->unitid == tunerunithdr->iunit) {
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->tunerunit, tunerunithdr,
+ sizeof(struct tmComResTunerDescrHeader));
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d] tuner)\n",
+ encport->nr);
+ }
break;
case VC_SELECTOR_UNIT:
+ psel = (struct tmComResSelDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " VC_SELECTOR_UNIT\n");
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ psel->unitid);
+ dprintk(DBGLVL_API, " nrinpins = 0x%x\n",
+ psel->nrinpins);
+ dprintk(DBGLVL_API, " sourceid = 0x%x\n",
+ psel->sourceid);
break;
case VC_PROCESSING_UNIT:
+ pdh = (struct tmComResProcDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " VC_PROCESSING_UNIT\n");
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ pdh->unitid);
+ dprintk(DBGLVL_API, " sourceid = 0x%x\n",
+ pdh->sourceid);
+ dprintk(DBGLVL_API, " controlsize = 0x%x\n",
+ pdh->controlsize);
+ if (pdh->controlsize == 0x04) {
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->vidproc, pdh,
+ sizeof(struct tmComResProcDescrHeader));
+ dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n",
+ encport->nr);
+ }
break;
case FEATURE_UNIT:
+ afd = (struct tmComResAFeatureDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " FEATURE_UNIT\n");
+ dprintk(DBGLVL_API, " unitid = 0x%x\n",
+ afd->unitid);
+ dprintk(DBGLVL_API, " sourceid = 0x%x\n",
+ afd->sourceid);
+ dprintk(DBGLVL_API, " controlsize = 0x%x\n",
+ afd->controlsize);
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->audfeat, afd,
+ sizeof(struct tmComResAFeatureDescrHeader));
+ dprintk(DBGLVL_API, " (becomes dev->enc[%d])\n",
+ encport->nr);
break;
case ENCODER_UNIT:
+ edh = (struct tmComResEncoderDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " ENCODER_UNIT\n");
+ dprintk(DBGLVL_API, " subtype = 0x%x\n", edh->subtype);
+ dprintk(DBGLVL_API, " unitid = 0x%x\n", edh->unitid);
+ dprintk(DBGLVL_API, " vsourceid = 0x%x\n",
+ edh->vsourceid);
+ dprintk(DBGLVL_API, " asourceid = 0x%x\n",
+ edh->asourceid);
+ dprintk(DBGLVL_API, " iunit = 0x%x\n", edh->iunit);
+ if (edh->iunit == edh->unitid) {
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->encunit, edh,
+ sizeof(struct tmComResEncoderDescrHeader));
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d])\n",
+ encport->nr);
+ }
break;
case EXTENSION_UNIT:
dprintk(DBGLVL_API, " EXTENSION_UNIT\n");
- exthdr = (tmComResExtDevDescrHeader_t *)(buf + idx);
+ exthdr = (struct tmComResExtDevDescrHeader *)(buf + idx);
dprintk(DBGLVL_API, " unitid = 0x%x\n",
exthdr->unitid);
dprintk(DBGLVL_API, " deviceid = 0x%x\n",
@@ -364,6 +1288,17 @@ int saa7164_api_dump_subdevs(struct saa7164_dev *dev, u8 *buf, int len)
exthdr->numgpiogroups);
dprintk(DBGLVL_API, " controlsize = 0x%x\n",
exthdr->controlsize);
+ if (exthdr->devicetype & 0x80) {
+ if (currpath == 1)
+ encport = &dev->ports[SAA7164_PORT_ENC1];
+ else
+ encport = &dev->ports[SAA7164_PORT_ENC2];
+ memcpy(&encport->ifunit, exthdr,
+ sizeof(struct tmComResExtDevDescrHeader));
+ dprintk(DBGLVL_API,
+ " (becomes dev->enc[%d])\n",
+ encport->nr);
+ }
break;
case PVC_INFRARED_UNIT:
dprintk(DBGLVL_API, " PVC_INFRARED_UNIT\n");
@@ -560,12 +1495,11 @@ int saa7164_api_i2c_write(struct saa7164_i2c *bus, u8 addr, u32 datalen,
return ret == SAA_OK ? 0 : -EIO;
}
-
int saa7164_api_modify_gpio(struct saa7164_dev *dev, u8 unitid,
u8 pin, u8 state)
{
int ret;
- tmComResGPIO_t t;
+ struct tmComResGPIO t;
dprintk(DBGLVL_API, "%s(0x%x, %d, %d)\n",
__func__, unitid, pin, state);
@@ -597,5 +1531,3 @@ int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid,
return saa7164_api_modify_gpio(dev, unitid, pin, 0);
}
-
-
diff --git a/drivers/media/video/saa7164/saa7164-buffer.c b/drivers/media/video/saa7164/saa7164-buffer.c
index 5713f3a4b76c..ddd25211c9e8 100644
--- a/drivers/media/video/saa7164/saa7164-buffer.c
+++ b/drivers/media/video/saa7164/saa7164-buffer.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,54 +24,75 @@
#include "saa7164.h"
/* The PCI address space for buffer handling looks like this:
-
- +-u32 wide-------------+
- | +
- +-u64 wide------------------------------------+
- + +
- +----------------------+
- | CurrentBufferPtr + Pointer to current PCI buffer >-+
- +----------------------+ |
- | Unused + |
- +----------------------+ |
- | Pitch + = 188 (bytes) |
- +----------------------+ |
- | PCI buffer size + = pitch * number of lines (312) |
- +----------------------+ |
- |0| Buf0 Write Offset + |
- +----------------------+ v
- |1| Buf1 Write Offset + |
- +----------------------+ |
- |2| Buf2 Write Offset + |
- +----------------------+ |
- |3| Buf3 Write Offset + |
- +----------------------+ |
- ... More write offsets |
- +---------------------------------------------+ |
- +0| set of ptrs to PCI pagetables + |
- +---------------------------------------------+ |
- +1| set of ptrs to PCI pagetables + <--------+
- +---------------------------------------------+
- +2| set of ptrs to PCI pagetables +
- +---------------------------------------------+
- +3| set of ptrs to PCI pagetables + >--+
- +---------------------------------------------+ |
- ... More buffer pointers | +----------------+
- +->| pt[0] TS data |
- | +----------------+
- |
- | +----------------+
- +->| pt[1] TS data |
- | +----------------+
- | etc
+ *
+ * +-u32 wide-------------+
+ * | +
+ * +-u64 wide------------------------------------+
+ * + +
+ * +----------------------+
+ * | CurrentBufferPtr + Pointer to current PCI buffer >-+
+ * +----------------------+ |
+ * | Unused + |
+ * +----------------------+ |
+ * | Pitch + = 188 (bytes) |
+ * +----------------------+ |
+ * | PCI buffer size + = pitch * number of lines (312) |
+ * +----------------------+ |
+ * |0| Buf0 Write Offset + |
+ * +----------------------+ v
+ * |1| Buf1 Write Offset + |
+ * +----------------------+ |
+ * |2| Buf2 Write Offset + |
+ * +----------------------+ |
+ * |3| Buf3 Write Offset + |
+ * +----------------------+ |
+ * ... More write offsets |
+ * +---------------------------------------------+ |
+ * +0| set of ptrs to PCI pagetables + |
+ * +---------------------------------------------+ |
+ * +1| set of ptrs to PCI pagetables + <--------+
+ * +---------------------------------------------+
+ * +2| set of ptrs to PCI pagetables +
+ * +---------------------------------------------+
+ * +3| set of ptrs to PCI pagetables + >--+
+ * +---------------------------------------------+ |
+ * ... More buffer pointers | +----------------+
+ * +->| pt[0] TS data |
+ * | +----------------+
+ * |
+ * | +----------------+
+ * +->| pt[1] TS data |
+ * | +----------------+
+ * | etc
*/
+void saa7164_buffer_display(struct saa7164_buffer *buf)
+{
+ struct saa7164_dev *dev = buf->port->dev;
+ int i;
+
+ dprintk(DBGLVL_BUF, "%s() buffer @ 0x%p nr=%d\n",
+ __func__, buf, buf->idx);
+ dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08llx len = 0x%x\n",
+ buf->cpu, (long long)buf->dma, buf->pci_size);
+ dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08llx len = 0x%x\n",
+ buf->pt_cpu, (long long)buf->pt_dma, buf->pt_size);
+
+ /* Format the Page Table Entries to point into the data buffer */
+ for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) {
+
+ dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n",
+ i, buf->pt_cpu, (u64)*(buf->pt_cpu));
+
+ }
+}
/* Allocate a new buffer structure and associated PCI space in bytes.
* len must be a multiple of sizeof(u64)
*/
-struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port,
+struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_port *port,
u32 len)
{
+ struct tmHWStreamParameters *params = &port->hw_streamingparams;
struct saa7164_buffer *buf = 0;
struct saa7164_dev *dev = port->dev;
int i;
@@ -87,8 +108,12 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port,
goto ret;
}
+ buf->idx = -1;
buf->port = port;
buf->flags = SAA7164_BUFFER_FREE;
+ buf->pos = 0;
+ buf->actual_size = params->pitch * params->numberoflines;
+ buf->crc = 0;
/* TODO: arg len is being ignored */
buf->pci_size = SAA7164_PT_ENTRIES * 0x1000;
buf->pt_size = (SAA7164_PT_ENTRIES * sizeof(u64)) + 0x1000;
@@ -105,19 +130,23 @@ struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port,
goto fail2;
/* init the buffers to a known pattern, easier during debugging */
- memset(buf->cpu, 0xff, buf->pci_size);
- memset(buf->pt_cpu, 0xff, buf->pt_size);
+ memset_io(buf->cpu, 0xff, buf->pci_size);
+ buf->crc = crc32(0, buf->cpu, buf->actual_size);
+ memset_io(buf->pt_cpu, 0xff, buf->pt_size);
- dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p\n", __func__, buf);
+ dprintk(DBGLVL_BUF, "%s() allocated buffer @ 0x%p (%d pageptrs)\n",
+ __func__, buf, params->numpagetables);
dprintk(DBGLVL_BUF, " pci_cpu @ 0x%p dma @ 0x%08lx len = 0x%x\n",
buf->cpu, (long)buf->dma, buf->pci_size);
dprintk(DBGLVL_BUF, " pt_cpu @ 0x%p pt_dma @ 0x%08lx len = 0x%x\n",
buf->pt_cpu, (long)buf->pt_dma, buf->pt_size);
/* Format the Page Table Entries to point into the data buffer */
- for (i = 0 ; i < SAA7164_PT_ENTRIES; i++) {
+ for (i = 0 ; i < params->numpagetables; i++) {
*(buf->pt_cpu + i) = buf->dma + (i * 0x1000); /* TODO */
+ dprintk(DBGLVL_BUF, " pt[%02d] = 0x%p -> 0x%llx\n",
+ i, buf->pt_cpu, (u64)*(buf->pt_cpu));
}
@@ -133,25 +162,161 @@ ret:
return buf;
}
-int saa7164_buffer_dealloc(struct saa7164_tsport *port,
- struct saa7164_buffer *buf)
+int saa7164_buffer_dealloc(struct saa7164_buffer *buf)
{
- struct saa7164_dev *dev = port->dev;
+ struct saa7164_dev *dev;
- if ((buf == 0) || (port == 0))
+ if (!buf || !buf->port)
return SAA_ERR_BAD_PARAMETER;
+ dev = buf->port->dev;
- dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n", __func__, buf);
+ dprintk(DBGLVL_BUF, "%s() deallocating buffer @ 0x%p\n",
+ __func__, buf);
if (buf->flags != SAA7164_BUFFER_FREE)
log_warn(" freeing a non-free buffer\n");
- pci_free_consistent(port->dev->pci, buf->pci_size, buf->cpu, buf->dma);
- pci_free_consistent(port->dev->pci, buf->pt_size, buf->pt_cpu,
- buf->pt_dma);
+ pci_free_consistent(dev->pci, buf->pci_size, buf->cpu, buf->dma);
+ pci_free_consistent(dev->pci, buf->pt_size, buf->pt_cpu, buf->pt_dma);
kfree(buf);
return SAA_OK;
}
+int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ if ((i < 0) || (i >= port->hwcfg.buffercount))
+ return -EINVAL;
+
+ dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
+
+ saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
+
+ return 0;
+}
+
+/* Write a buffer into the hardware */
+int saa7164_buffer_activate(struct saa7164_buffer *buf, int i)
+{
+ struct saa7164_port *port = buf->port;
+ struct saa7164_dev *dev = port->dev;
+
+ if ((i < 0) || (i >= port->hwcfg.buffercount))
+ return -EINVAL;
+
+ dprintk(DBGLVL_BUF, "%s(idx = %d)\n", __func__, i);
+
+ buf->idx = i; /* Note of which buffer list index position we occupy */
+ buf->flags = SAA7164_BUFFER_BUSY;
+ buf->pos = 0;
+
+ /* TODO: Review this in light of 32v64 assignments */
+ saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
+ saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i), buf->pt_dma);
+ saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0);
+
+ dprintk(DBGLVL_BUF, " buf[%d] offset 0x%llx (0x%x) "
+ "buf 0x%llx/%llx (0x%x/%x) nr=%d\n",
+ buf->idx,
+ (u64)port->bufoffset + (i * sizeof(u32)),
+ saa7164_readl(port->bufoffset + (sizeof(u32) * i)),
+ (u64)port->bufptr32h + ((sizeof(u32) * 2) * i),
+ (u64)port->bufptr32l + ((sizeof(u32) * 2) * i),
+ saa7164_readl(port->bufptr32h + ((sizeof(u32) * i) * 2)),
+ saa7164_readl(port->bufptr32l + ((sizeof(u32) * i) * 2)),
+ buf->idx);
+
+ return 0;
+}
+
+int saa7164_buffer_cfg_port(struct saa7164_port *port)
+{
+ struct tmHWStreamParameters *params = &port->hw_streamingparams;
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct list_head *c, *n;
+ int i = 0;
+
+ dprintk(DBGLVL_BUF, "%s(port=%d)\n", __func__, port->nr);
+
+ saa7164_writel(port->bufcounter, 0);
+ saa7164_writel(port->pitch, params->pitch);
+ saa7164_writel(port->bufsize, params->pitch * params->numberoflines);
+
+ dprintk(DBGLVL_BUF, " configured:\n");
+ dprintk(DBGLVL_BUF, " lmmio 0x%p\n", dev->lmmio);
+ dprintk(DBGLVL_BUF, " bufcounter 0x%x = 0x%x\n", port->bufcounter,
+ saa7164_readl(port->bufcounter));
+
+ dprintk(DBGLVL_BUF, " pitch 0x%x = %d\n", port->pitch,
+ saa7164_readl(port->pitch));
+
+ dprintk(DBGLVL_BUF, " bufsize 0x%x = %d\n", port->bufsize,
+ saa7164_readl(port->bufsize));
+
+ dprintk(DBGLVL_BUF, " buffercount = %d\n", port->hwcfg.buffercount);
+ dprintk(DBGLVL_BUF, " bufoffset = 0x%x\n", port->bufoffset);
+ dprintk(DBGLVL_BUF, " bufptr32h = 0x%x\n", port->bufptr32h);
+ dprintk(DBGLVL_BUF, " bufptr32l = 0x%x\n", port->bufptr32l);
+
+ /* Poke the buffers and offsets into PCI space */
+ mutex_lock(&port->dmaqueue_lock);
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+ buf = list_entry(c, struct saa7164_buffer, list);
+
+ if (buf->flags != SAA7164_BUFFER_FREE)
+ BUG();
+
+ /* Place the buffer in the h/w queue */
+ saa7164_buffer_activate(buf, i);
+
+ /* Don't exceed the device maximum # bufs */
+ if (i++ > port->hwcfg.buffercount)
+ BUG();
+
+ }
+ mutex_unlock(&port->dmaqueue_lock);
+
+ return 0;
+}
+
+struct saa7164_user_buffer *saa7164_buffer_alloc_user(struct saa7164_dev *dev,
+ u32 len)
+{
+ struct saa7164_user_buffer *buf;
+
+ buf = kzalloc(sizeof(struct saa7164_user_buffer), GFP_KERNEL);
+ if (buf == 0)
+ return 0;
+
+ buf->data = kzalloc(len, GFP_KERNEL);
+
+ if (buf->data == 0) {
+ kfree(buf);
+ return 0;
+ }
+
+ buf->actual_size = len;
+ buf->pos = 0;
+ buf->crc = 0;
+
+ dprintk(DBGLVL_BUF, "%s() allocated user buffer @ 0x%p\n",
+ __func__, buf);
+
+ return buf;
+}
+
+void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf)
+{
+ if (!buf)
+ return;
+
+ kfree(buf->data);
+ buf->data = 0;
+
+ kfree(buf);
+}
+
diff --git a/drivers/media/video/saa7164/saa7164-bus.c b/drivers/media/video/saa7164/saa7164-bus.c
index 83a04640a25a..b2b0d97101d0 100644
--- a/drivers/media/video/saa7164/saa7164-bus.c
+++ b/drivers/media/video/saa7164/saa7164-bus.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -26,7 +26,7 @@
*/
int saa7164_bus_setup(struct saa7164_dev *dev)
{
- tmComResBusInfo_t *b = &dev->bus;
+ struct tmComResBusInfo *b = &dev->bus;
mutex_init(&b->lock);
@@ -43,24 +43,19 @@ int saa7164_bus_setup(struct saa7164_dev *dev)
b->m_dwSizeGetRing = SAA_DEVICE_BUFFERBLOCKSIZE;
- b->m_pdwSetWritePos = (u32 *)((u8 *)(dev->bmmio +
- ((u32)dev->intfdesc.BARLocation) + (2 * sizeof(u64))));
+ b->m_dwSetWritePos = ((u32)dev->intfdesc.BARLocation) +
+ (2 * sizeof(u64));
+ b->m_dwSetReadPos = b->m_dwSetWritePos + (1 * sizeof(u32));
- b->m_pdwSetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos +
- 1 * sizeof(u32));
-
- b->m_pdwGetWritePos = (u32 *)((u8 *)b->m_pdwSetWritePos +
- 2 * sizeof(u32));
-
- b->m_pdwGetReadPos = (u32 *)((u8 *)b->m_pdwSetWritePos +
- 3 * sizeof(u32));
+ b->m_dwGetWritePos = b->m_dwSetWritePos + (2 * sizeof(u32));
+ b->m_dwGetReadPos = b->m_dwSetWritePos + (3 * sizeof(u32));
return 0;
}
void saa7164_bus_dump(struct saa7164_dev *dev)
{
- tmComResBusInfo_t *b = &dev->bus;
+ struct tmComResBusInfo *b = &dev->bus;
dprintk(DBGLVL_BUS, "Dumping the bus structure:\n");
dprintk(DBGLVL_BUS, " .type = %d\n", b->Type);
@@ -71,20 +66,48 @@ void saa7164_bus_dump(struct saa7164_dev *dev)
dprintk(DBGLVL_BUS, " .m_pdwGetRing = 0x%p\n", b->m_pdwGetRing);
dprintk(DBGLVL_BUS, " .m_dwSizeGetRing = 0x%x\n", b->m_dwSizeGetRing);
- dprintk(DBGLVL_BUS, " .m_pdwSetWritePos = 0x%p (0x%08x)\n",
- b->m_pdwSetWritePos, *b->m_pdwSetWritePos);
+ dprintk(DBGLVL_BUS, " .m_dwSetReadPos = 0x%x (0x%08x)\n",
+ b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
+
+ dprintk(DBGLVL_BUS, " .m_dwSetWritePos = 0x%x (0x%08x)\n",
+ b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
+
+ dprintk(DBGLVL_BUS, " .m_dwGetReadPos = 0x%x (0x%08x)\n",
+ b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
+
+ dprintk(DBGLVL_BUS, " .m_dwGetWritePos = 0x%x (0x%08x)\n",
+ b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
+
+}
+
+/* Intensionally throw a BUG() if the state of the message bus looks corrupt */
+void saa7164_bus_verify(struct saa7164_dev *dev)
+{
+ struct tmComResBusInfo *b = &dev->bus;
+ int bug = 0;
- dprintk(DBGLVL_BUS, " .m_pdwSetReadPos = 0x%p (0x%08x)\n",
- b->m_pdwSetReadPos, *b->m_pdwSetReadPos);
+ if (saa7164_readl(b->m_dwSetReadPos) > b->m_dwSizeSetRing)
+ bug++;
- dprintk(DBGLVL_BUS, " .m_pdwGetWritePos = 0x%p (0x%08x)\n",
- b->m_pdwGetWritePos, *b->m_pdwGetWritePos);
+ if (saa7164_readl(b->m_dwSetWritePos) > b->m_dwSizeSetRing)
+ bug++;
- dprintk(DBGLVL_BUS, " .m_pdwGetReadPos = 0x%p (0x%08x)\n",
- b->m_pdwGetReadPos, *b->m_pdwGetReadPos);
+ if (saa7164_readl(b->m_dwGetReadPos) > b->m_dwSizeGetRing)
+ bug++;
+
+ if (saa7164_readl(b->m_dwGetWritePos) > b->m_dwSizeGetRing)
+ bug++;
+
+ if (bug) {
+ saa_debug = 0xffff; /* Ensure we get the bus dump */
+ saa7164_bus_dump(dev);
+ saa_debug = 1024; /* Ensure we get the bus dump */
+ BUG();
+ }
}
-void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
+void saa7164_bus_dumpmsg(struct saa7164_dev *dev, struct tmComResInfo* m,
+ void *buf)
{
dprintk(DBGLVL_BUS, "Dumping msg structure:\n");
dprintk(DBGLVL_BUS, " .id = %d\n", m->id);
@@ -100,7 +123,7 @@ void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
/*
* Places a command or a response on the bus. The implementation does not
* know if it is a command or a response it just places the data on the
- * bus depending on the bus information given in the tmComResBusInfo_t
+ * bus depending on the bus information given in the struct tmComResBusInfo
* structure. If the command or response does not fit into the bus ring
* buffer it will be refused.
*
@@ -108,10 +131,11 @@ void saa7164_bus_dumpmsg(struct saa7164_dev *dev, tmComResInfo_t* m, void *buf)
* SAA_OK The function executed successfully.
* < 0 One or more members are not initialized.
*/
-int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
+ void *buf)
{
- tmComResBusInfo_t *bus = &dev->bus;
- u32 bytes_to_write, read_distance, timeout, curr_srp, curr_swp;
+ struct tmComResBusInfo *bus = &dev->bus;
+ u32 bytes_to_write, free_write_space, timeout, curr_srp, curr_swp;
u32 new_swp, space_rem;
int ret = SAA_ERR_BAD_PARAMETER;
@@ -122,6 +146,8 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
dprintk(DBGLVL_BUS, "%s()\n", __func__);
+ saa7164_bus_verify(dev);
+
msg->size = cpu_to_le16(msg->size);
msg->command = cpu_to_le16(msg->command);
msg->controlselector = cpu_to_le16(msg->controlselector);
@@ -141,30 +167,30 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
mutex_lock(&bus->lock);
bytes_to_write = sizeof(*msg) + msg->size;
- read_distance = 0;
+ free_write_space = 0;
timeout = SAA_BUS_TIMEOUT;
- curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
- curr_swp = le32_to_cpu(*bus->m_pdwSetWritePos);
+ curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
+ curr_swp = le32_to_cpu(saa7164_readl(bus->m_dwSetWritePos));
/* Deal with ring wrapping issues */
if (curr_srp > curr_swp)
- /* The ring has not wrapped yet */
- read_distance = curr_srp - curr_swp;
- else
/* Deal with the wrapped ring */
- read_distance = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
+ free_write_space = curr_srp - curr_swp;
+ else
+ /* The ring has not wrapped yet */
+ free_write_space = (curr_srp + bus->m_dwSizeSetRing) - curr_swp;
dprintk(DBGLVL_BUS, "%s() bytes_to_write = %d\n", __func__,
bytes_to_write);
- dprintk(DBGLVL_BUS, "%s() read_distance = %d\n", __func__,
- read_distance);
+ dprintk(DBGLVL_BUS, "%s() free_write_space = %d\n", __func__,
+ free_write_space);
dprintk(DBGLVL_BUS, "%s() curr_srp = %x\n", __func__, curr_srp);
dprintk(DBGLVL_BUS, "%s() curr_swp = %x\n", __func__, curr_swp);
/* Process the msg and write the content onto the bus */
- while (bytes_to_write >= read_distance) {
+ while (bytes_to_write >= free_write_space) {
if (timeout-- == 0) {
printk(KERN_ERR "%s() bus timeout\n", __func__);
@@ -177,15 +203,15 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
mdelay(1);
/* Check the space usage again */
- curr_srp = le32_to_cpu(*bus->m_pdwSetReadPos);
+ curr_srp = le32_to_cpu(saa7164_readl(bus->m_dwSetReadPos));
/* Deal with ring wrapping issues */
if (curr_srp > curr_swp)
- /* Read didn't wrap around the buffer */
- read_distance = curr_srp - curr_swp;
- else
/* Deal with the wrapped ring */
- read_distance = (curr_srp + bus->m_dwSizeSetRing) -
+ free_write_space = curr_srp - curr_swp;
+ else
+ /* Read didn't wrap around the buffer */
+ free_write_space = (curr_srp + bus->m_dwSizeSetRing) -
curr_swp;
}
@@ -257,37 +283,38 @@ int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
dprintk(DBGLVL_BUS, "%s() new_swp = %x\n", __func__, new_swp);
- /* TODO: Convert all of the direct PCI writes into
- * saa7164_writel/b calls for consistency.
- */
-
/* Update the bus write position */
- *bus->m_pdwSetWritePos = cpu_to_le32(new_swp);
+ saa7164_writel(bus->m_dwSetWritePos, cpu_to_le32(new_swp));
ret = SAA_OK;
out:
+ saa7164_bus_dump(dev);
mutex_unlock(&bus->lock);
+ saa7164_bus_verify(dev);
return ret;
}
/*
* Receive a command or a response from the bus. The implementation does not
* know if it is a command or a response it simply dequeues the data,
- * depending on the bus information given in the tmComResBusInfo_t structure.
+ * depending on the bus information given in the struct tmComResBusInfo
+ * structure.
*
* Return Value:
* 0 The function executed successfully.
* < 0 One or more members are not initialized.
*/
-int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
- int peekonly)
+int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
+ void *buf, int peekonly)
{
- tmComResBusInfo_t *bus = &dev->bus;
+ struct tmComResBusInfo *bus = &dev->bus;
u32 bytes_to_read, write_distance, curr_grp, curr_gwp,
new_grp, buf_size, space_rem;
- tmComResInfo_t msg_tmp;
+ struct tmComResInfo msg_tmp;
int ret = SAA_ERR_BAD_PARAMETER;
+ saa7164_bus_verify(dev);
+
if (msg == 0)
return ret;
@@ -309,11 +336,10 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
/* Peek the bus to see if a msg exists, if it's not what we're expecting
* then return cleanly else read the message from the bus.
*/
- curr_gwp = le32_to_cpu(*bus->m_pdwGetWritePos);
- curr_grp = le32_to_cpu(*bus->m_pdwGetReadPos);
+ curr_gwp = le32_to_cpu(saa7164_readl(bus->m_dwGetWritePos));
+ curr_grp = le32_to_cpu(saa7164_readl(bus->m_dwGetReadPos));
if (curr_gwp == curr_grp) {
- dprintk(DBGLVL_BUS, "%s() No message on the bus\n", __func__);
ret = SAA_ERR_EMPTY;
goto out;
}
@@ -434,7 +460,7 @@ int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf,
}
/* Update the read positions, adjusting the ring */
- *bus->m_pdwGetReadPos = cpu_to_le32(new_grp);
+ saa7164_writel(bus->m_dwGetReadPos, cpu_to_le32(new_grp));
peekout:
msg->size = le16_to_cpu(msg->size);
@@ -443,6 +469,7 @@ peekout:
ret = SAA_OK;
out:
mutex_unlock(&bus->lock);
+ saa7164_bus_verify(dev);
return ret;
}
diff --git a/drivers/media/video/saa7164/saa7164-cards.c b/drivers/media/video/saa7164/saa7164-cards.c
index a3c299405f46..69822a4e7275 100644
--- a/drivers/media/video/saa7164/saa7164-cards.c
+++ b/drivers/media/video/saa7164/saa7164-cards.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -55,6 +55,10 @@ struct saa7164_board saa7164_boards[] = {
.name = "Hauppauge WinTV-HVR2200",
.porta = SAA7164_MPEG_DVB,
.portb = SAA7164_MPEG_DVB,
+ .portc = SAA7164_MPEG_ENCODER,
+ .portd = SAA7164_MPEG_ENCODER,
+ .porte = SAA7164_MPEG_VBI,
+ .portf = SAA7164_MPEG_VBI,
.chiprev = SAA7164_CHIP_REV3,
.unit = {{
.id = 0x1d,
@@ -97,6 +101,10 @@ struct saa7164_board saa7164_boards[] = {
.name = "Hauppauge WinTV-HVR2200",
.porta = SAA7164_MPEG_DVB,
.portb = SAA7164_MPEG_DVB,
+ .portc = SAA7164_MPEG_ENCODER,
+ .portd = SAA7164_MPEG_ENCODER,
+ .porte = SAA7164_MPEG_VBI,
+ .portf = SAA7164_MPEG_VBI,
.chiprev = SAA7164_CHIP_REV2,
.unit = {{
.id = 0x06,
@@ -139,6 +147,10 @@ struct saa7164_board saa7164_boards[] = {
.name = "Hauppauge WinTV-HVR2200",
.porta = SAA7164_MPEG_DVB,
.portb = SAA7164_MPEG_DVB,
+ .portc = SAA7164_MPEG_ENCODER,
+ .portd = SAA7164_MPEG_ENCODER,
+ .porte = SAA7164_MPEG_VBI,
+ .portf = SAA7164_MPEG_VBI,
.chiprev = SAA7164_CHIP_REV2,
.unit = {{
.id = 0x1d,
@@ -195,6 +207,12 @@ struct saa7164_board saa7164_boards[] = {
.name = "Hauppauge WinTV-HVR2250",
.porta = SAA7164_MPEG_DVB,
.portb = SAA7164_MPEG_DVB,
+ .portc = SAA7164_MPEG_ENCODER,
+ .portd = SAA7164_MPEG_ENCODER,
+ .portc = SAA7164_MPEG_ENCODER,
+ .portd = SAA7164_MPEG_ENCODER,
+ .porte = SAA7164_MPEG_VBI,
+ .portf = SAA7164_MPEG_VBI,
.chiprev = SAA7164_CHIP_REV3,
.unit = {{
.id = 0x22,
@@ -251,6 +269,12 @@ struct saa7164_board saa7164_boards[] = {
.name = "Hauppauge WinTV-HVR2250",
.porta = SAA7164_MPEG_DVB,
.portb = SAA7164_MPEG_DVB,
+ .portc = SAA7164_MPEG_ENCODER,
+ .portd = SAA7164_MPEG_ENCODER,
+ .porte = SAA7164_MPEG_VBI,
+ .portf = SAA7164_MPEG_VBI,
+ .porte = SAA7164_MPEG_VBI,
+ .portf = SAA7164_MPEG_VBI,
.chiprev = SAA7164_CHIP_REV3,
.unit = {{
.id = 0x28,
@@ -307,6 +331,10 @@ struct saa7164_board saa7164_boards[] = {
.name = "Hauppauge WinTV-HVR2250",
.porta = SAA7164_MPEG_DVB,
.portb = SAA7164_MPEG_DVB,
+ .portc = SAA7164_MPEG_ENCODER,
+ .portd = SAA7164_MPEG_ENCODER,
+ .porte = SAA7164_MPEG_VBI,
+ .portf = SAA7164_MPEG_VBI,
.chiprev = SAA7164_CHIP_REV3,
.unit = {{
.id = 0x26,
@@ -437,8 +465,6 @@ void saa7164_card_list(struct saa7164_dev *dev)
void saa7164_gpio_setup(struct saa7164_dev *dev)
{
-
-
switch (dev->board) {
case SAA7164_BOARD_HAUPPAUGE_HVR2200:
case SAA7164_BOARD_HAUPPAUGE_HVR2200_2:
@@ -456,13 +482,12 @@ void saa7164_gpio_setup(struct saa7164_dev *dev)
saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 2);
saa7164_api_clear_gpiobit(dev, PCIEBRIDGE_UNITID, 3);
- msleep(10);
+ msleep(20);
saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 2);
saa7164_api_set_gpiobit(dev, PCIEBRIDGE_UNITID, 3);
break;
}
-
}
static void hauppauge_eeprom(struct saa7164_dev *dev, u8 *eeprom_data)
diff --git a/drivers/media/video/saa7164/saa7164-cmd.c b/drivers/media/video/saa7164/saa7164-cmd.c
index 9c1d3ac43869..a97ae17b36c2 100644
--- a/drivers/media/video/saa7164/saa7164-cmd.c
+++ b/drivers/media/video/saa7164/saa7164-cmd.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -82,16 +82,17 @@ u32 saa7164_cmd_timeout_get(struct saa7164_dev *dev, u8 seqno)
* -bus/c running buffer. */
int saa7164_irq_dequeue(struct saa7164_dev *dev)
{
- int ret = SAA_OK;
+ int ret = SAA_OK, i = 0;
u32 timeout;
wait_queue_head_t *q = 0;
+ u8 tmp[512];
dprintk(DBGLVL_CMD, "%s()\n", __func__);
/* While any outstand message on the bus exists... */
do {
/* Peek the msg bus */
- tmComResInfo_t tRsp = { 0, 0, 0, 0, 0, 0 };
+ struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 };
ret = saa7164_bus_get(dev, &tRsp, NULL, 1);
if (ret != SAA_OK)
break;
@@ -109,8 +110,22 @@ int saa7164_irq_dequeue(struct saa7164_dev *dev)
printk(KERN_ERR
"%s() found timed out command on the bus\n",
__func__);
+
+ /* Clean the bus */
+ ret = saa7164_bus_get(dev, &tRsp, &tmp, 0);
+ printk(KERN_ERR "%s() ret = %x\n", __func__, ret);
+ if (ret == SAA_ERR_EMPTY)
+ /* Someone else already fetched the response */
+ return SAA_OK;
+
+ if (ret != SAA_OK)
+ return ret;
}
- } while (0);
+
+ /* It's unlikely to have more than 4 or 5 pending messages,
+ * ensure we exit at some point regardless.
+ */
+ } while (i++ < 32);
return ret;
}
@@ -128,7 +143,7 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev)
while (loop) {
- tmComResInfo_t tRsp = { 0, 0, 0, 0, 0, 0 };
+ struct tmComResInfo tRsp = { 0, 0, 0, 0, 0, 0 };
ret = saa7164_bus_get(dev, &tRsp, NULL, 1);
if (ret == SAA_ERR_EMPTY)
return SAA_OK;
@@ -171,9 +186,10 @@ int saa7164_cmd_dequeue(struct saa7164_dev *dev)
return SAA_OK;
}
-int saa7164_cmd_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf)
+int saa7164_cmd_set(struct saa7164_dev *dev, struct tmComResInfo *msg,
+ void *buf)
{
- tmComResBusInfo_t *bus = &dev->bus;
+ struct tmComResBusInfo *bus = &dev->bus;
u8 cmd_sent;
u16 size, idx;
u32 cmds;
@@ -277,7 +293,8 @@ int saa7164_cmd_wait(struct saa7164_dev *dev, u8 seqno)
* We typically are signalled in < 50ms but it can
* take MUCH longer.
*/
- wait_event_timeout(*q, dev->cmds[seqno].signalled, (HZ * waitsecs));
+ wait_event_timeout(*q, dev->cmds[seqno].signalled,
+ (HZ * waitsecs));
r = time_before(jiffies, stamp + (HZ * waitsecs));
if (r)
ret = SAA_OK;
@@ -324,11 +341,11 @@ void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno)
mutex_unlock(&dev->lock);
}
-int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, tmComResCmd_t command,
+int saa7164_cmd_send(struct saa7164_dev *dev, u8 id, enum tmComResCmd command,
u16 controlselector, u16 size, void *buf)
{
- tmComResInfo_t command_t, *pcommand_t;
- tmComResInfo_t response_t, *presponse_t;
+ struct tmComResInfo command_t, *pcommand_t;
+ struct tmComResInfo response_t, *presponse_t;
u8 errdata[256];
u16 resp_dsize;
u16 data_recd;
diff --git a/drivers/media/video/saa7164/saa7164-core.c b/drivers/media/video/saa7164/saa7164-core.c
index e6aa0fbd1e91..58af67f2278b 100644
--- a/drivers/media/video/saa7164/saa7164-core.c
+++ b/drivers/media/video/saa7164/saa7164-core.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -30,6 +30,9 @@
#include <linux/delay.h>
#include <asm/div64.h>
+#ifdef CONFIG_PROC_FS
+#include <linux/proc_fs.h>
+#endif
#include "saa7164.h"
MODULE_DESCRIPTION("Driver for NXP SAA7164 based TV cards");
@@ -37,26 +40,51 @@ MODULE_AUTHOR("Steven Toth <stoth@kernellabs.com>");
MODULE_LICENSE("GPL");
/*
- 1 Basic
- 2
- 4 i2c
- 8 api
- 16 cmd
- 32 bus
+ * 1 Basic
+ * 2
+ * 4 i2c
+ * 8 api
+ * 16 cmd
+ * 32 bus
*/
unsigned int saa_debug;
module_param_named(debug, saa_debug, int, 0644);
MODULE_PARM_DESC(debug, "enable debug messages");
+unsigned int fw_debug;
+module_param(fw_debug, int, 0644);
+MODULE_PARM_DESC(fw_debug, "Firware debug level def:2");
+
+unsigned int encoder_buffers = SAA7164_MAX_ENCODER_BUFFERS;
+module_param(encoder_buffers, int, 0644);
+MODULE_PARM_DESC(encoder_buffers, "Total buffers in read queue 16-512 def:64");
+
+unsigned int vbi_buffers = SAA7164_MAX_VBI_BUFFERS;
+module_param(vbi_buffers, int, 0644);
+MODULE_PARM_DESC(vbi_buffers, "Total buffers in read queue 16-512 def:64");
+
unsigned int waitsecs = 10;
module_param(waitsecs, int, 0644);
-MODULE_PARM_DESC(debug, "timeout on firmware messages");
+MODULE_PARM_DESC(waitsecs, "timeout on firmware messages");
static unsigned int card[] = {[0 ... (SAA7164_MAXBOARDS - 1)] = UNSET };
module_param_array(card, int, NULL, 0444);
MODULE_PARM_DESC(card, "card type");
+unsigned int print_histogram = 64;
+module_param(print_histogram, int, 0644);
+MODULE_PARM_DESC(print_histogram, "print histogram values once");
+
+unsigned int crc_checking = 1;
+module_param(crc_checking, int, 0644);
+MODULE_PARM_DESC(crc_checking, "enable crc sanity checking on buffers");
+
+unsigned int guard_checking = 1;
+module_param(guard_checking, int, 0644);
+MODULE_PARM_DESC(guard_checking,
+ "enable dma sanity checking for buffer overruns");
+
static unsigned int saa7164_devcount;
static DEFINE_MUTEX(devlist);
@@ -64,6 +92,445 @@ LIST_HEAD(saa7164_devlist);
#define INT_SIZE 16
+void saa7164_dumphex16FF(struct saa7164_dev *dev, u8 *buf, int len)
+{
+ int i;
+ u8 tmp[16];
+ memset(&tmp[0], 0xff, sizeof(tmp));
+
+ printk(KERN_INFO "--------------------> "
+ "00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+
+ for (i = 0; i < len; i += 16) {
+ if (memcmp(&tmp, buf + i, sizeof(tmp)) != 0) {
+ printk(KERN_INFO " [0x%08x] "
+ "%02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n", i,
+ *(buf+i+0), *(buf+i+1), *(buf+i+2), *(buf+i+3),
+ *(buf+i+4), *(buf+i+5), *(buf+i+6), *(buf+i+7),
+ *(buf+i+8), *(buf+i+9), *(buf+i+10), *(buf+i+11),
+ *(buf+i+12), *(buf+i+13), *(buf+i+14), *(buf+i+15));
+ }
+ }
+}
+
+static void saa7164_pack_verifier(struct saa7164_buffer *buf)
+{
+ u8 *p = (u8 *)buf->cpu;
+ int i;
+
+ for (i = 0; i < buf->actual_size; i += 2048) {
+
+ if ((*(p + i + 0) != 0x00) || (*(p + i + 1) != 0x00) ||
+ (*(p + i + 2) != 0x01) || (*(p + i + 3) != 0xBA)) {
+ printk(KERN_ERR "No pack at 0x%x\n", i);
+#if 0
+ saa7164_dumphex16FF(buf->port->dev, (p + i), 32);
+#endif
+ }
+ }
+}
+
+#define FIXED_VIDEO_PID 0xf1
+#define FIXED_AUDIO_PID 0xf2
+
+static void saa7164_ts_verifier(struct saa7164_buffer *buf)
+{
+ struct saa7164_port *port = buf->port;
+ u32 i;
+ u8 cc, a;
+ u16 pid;
+ u8 __iomem *bufcpu = (u8 *)buf->cpu;
+
+ port->sync_errors = 0;
+ port->v_cc_errors = 0;
+ port->a_cc_errors = 0;
+
+ for (i = 0; i < buf->actual_size; i += 188) {
+ if (*(bufcpu + i) != 0x47)
+ port->sync_errors++;
+
+ /* TODO: Query pid lower 8 bits, ignoring upper bits intensionally */
+ pid = ((*(bufcpu + i + 1) & 0x1f) << 8) | *(bufcpu + i + 2);
+ cc = *(bufcpu + i + 3) & 0x0f;
+
+ if (pid == FIXED_VIDEO_PID) {
+ a = ((port->last_v_cc + 1) & 0x0f);
+ if (a != cc) {
+ printk(KERN_ERR "video cc last = %x current = %x i = %d\n",
+ port->last_v_cc, cc, i);
+ port->v_cc_errors++;
+ }
+
+ port->last_v_cc = cc;
+ } else
+ if (pid == FIXED_AUDIO_PID) {
+ a = ((port->last_a_cc + 1) & 0x0f);
+ if (a != cc) {
+ printk(KERN_ERR "audio cc last = %x current = %x i = %d\n",
+ port->last_a_cc, cc, i);
+ port->a_cc_errors++;
+ }
+
+ port->last_a_cc = cc;
+ }
+
+ }
+
+ /* Only report errors if we've been through this function atleast
+ * once already and the cached cc values are primed. First time through
+ * always generates errors.
+ */
+ if (port->v_cc_errors && (port->done_first_interrupt > 1))
+ printk(KERN_ERR "video pid cc, %d errors\n", port->v_cc_errors);
+
+ if (port->a_cc_errors && (port->done_first_interrupt > 1))
+ printk(KERN_ERR "audio pid cc, %d errors\n", port->a_cc_errors);
+
+ if (port->sync_errors && (port->done_first_interrupt > 1))
+ printk(KERN_ERR "sync_errors = %d\n", port->sync_errors);
+
+ if (port->done_first_interrupt == 1)
+ port->done_first_interrupt++;
+}
+
+static void saa7164_histogram_reset(struct saa7164_histogram *hg, char *name)
+{
+ int i;
+
+ memset(hg, 0, sizeof(struct saa7164_histogram));
+ strcpy(hg->name, name);
+
+ /* First 30ms x 1ms */
+ for (i = 0; i < 30; i++)
+ hg->counter1[0 + i].val = i;
+
+ /* 30 - 200ms x 10ms */
+ for (i = 0; i < 18; i++)
+ hg->counter1[30 + i].val = 30 + (i * 10);
+
+ /* 200 - 2000ms x 100ms */
+ for (i = 0; i < 15; i++)
+ hg->counter1[48 + i].val = 200 + (i * 200);
+
+ /* Catch all massive value (2secs) */
+ hg->counter1[55].val = 2000;
+
+ /* Catch all massive value (4secs) */
+ hg->counter1[56].val = 4000;
+
+ /* Catch all massive value (8secs) */
+ hg->counter1[57].val = 8000;
+
+ /* Catch all massive value (15secs) */
+ hg->counter1[58].val = 15000;
+
+ /* Catch all massive value (30secs) */
+ hg->counter1[59].val = 30000;
+
+ /* Catch all massive value (60secs) */
+ hg->counter1[60].val = 60000;
+
+ /* Catch all massive value (5mins) */
+ hg->counter1[61].val = 300000;
+
+ /* Catch all massive value (15mins) */
+ hg->counter1[62].val = 900000;
+
+ /* Catch all massive values (1hr) */
+ hg->counter1[63].val = 3600000;
+}
+
+void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val)
+{
+ int i;
+ for (i = 0; i < 64; i++) {
+ if (val <= hg->counter1[i].val) {
+ hg->counter1[i].count++;
+ hg->counter1[i].update_time = jiffies;
+ break;
+ }
+ }
+}
+
+static void saa7164_histogram_print(struct saa7164_port *port,
+ struct saa7164_histogram *hg)
+{
+ u32 entries = 0;
+ int i;
+
+ printk(KERN_ERR "Histogram named %s (ms, count, last_update_jiffy)\n", hg->name);
+ for (i = 0; i < 64; i++) {
+ if (hg->counter1[i].count == 0)
+ continue;
+
+ printk(KERN_ERR " %4d %12d %Ld\n",
+ hg->counter1[i].val,
+ hg->counter1[i].count,
+ hg->counter1[i].update_time);
+
+ entries++;
+ }
+ printk(KERN_ERR "Total: %d\n", entries);
+}
+
+static void saa7164_work_enchandler_helper(struct saa7164_port *port, int bufnr)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf = 0;
+ struct saa7164_user_buffer *ubuf = 0;
+ struct list_head *c, *n;
+ int i = 0;
+ u8 __iomem *p;
+
+ mutex_lock(&port->dmaqueue_lock);
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+
+ buf = list_entry(c, struct saa7164_buffer, list);
+ if (i++ > port->hwcfg.buffercount) {
+ printk(KERN_ERR "%s() illegal i count %d\n",
+ __func__, i);
+ break;
+ }
+
+ if (buf->idx == bufnr) {
+
+ /* Found the buffer, deal with it */
+ dprintk(DBGLVL_IRQ, "%s() bufnr: %d\n", __func__, bufnr);
+
+ if (crc_checking) {
+ /* Throw a new checksum on the dma buffer */
+ buf->crc = crc32(0, buf->cpu, buf->actual_size);
+ }
+
+ if (guard_checking) {
+ p = (u8 *)buf->cpu;
+ if ((*(p + buf->actual_size + 0) != 0xff) ||
+ (*(p + buf->actual_size + 1) != 0xff) ||
+ (*(p + buf->actual_size + 2) != 0xff) ||
+ (*(p + buf->actual_size + 3) != 0xff) ||
+ (*(p + buf->actual_size + 0x10) != 0xff) ||
+ (*(p + buf->actual_size + 0x11) != 0xff) ||
+ (*(p + buf->actual_size + 0x12) != 0xff) ||
+ (*(p + buf->actual_size + 0x13) != 0xff)) {
+ printk(KERN_ERR "%s() buf %p guard buffer breach\n",
+ __func__, buf);
+#if 0
+ saa7164_dumphex16FF(dev, (p + buf->actual_size) - 32 , 64);
+#endif
+ }
+ }
+
+ if ((port->nr != SAA7164_PORT_VBI1) && (port->nr != SAA7164_PORT_VBI2)) {
+ /* Validate the incoming buffer content */
+ if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_TS)
+ saa7164_ts_verifier(buf);
+ else if (port->encoder_params.stream_type == V4L2_MPEG_STREAM_TYPE_MPEG2_PS)
+ saa7164_pack_verifier(buf);
+ }
+
+ /* find a free user buffer and clone to it */
+ if (!list_empty(&port->list_buf_free.list)) {
+
+ /* Pull the first buffer from the used list */
+ ubuf = list_first_entry(&port->list_buf_free.list,
+ struct saa7164_user_buffer, list);
+
+ if (buf->actual_size <= ubuf->actual_size) {
+
+ memcpy_fromio(ubuf->data, buf->cpu,
+ ubuf->actual_size);
+
+ if (crc_checking) {
+ /* Throw a new checksum on the read buffer */
+ ubuf->crc = crc32(0, ubuf->data, ubuf->actual_size);
+ }
+
+ /* Requeue the buffer on the free list */
+ ubuf->pos = 0;
+
+ list_move_tail(&ubuf->list,
+ &port->list_buf_used.list);
+
+ /* Flag any userland waiters */
+ wake_up_interruptible(&port->wait_read);
+
+ } else {
+ printk(KERN_ERR "buf %p bufsize fails match\n", buf);
+ }
+
+ } else
+ printk(KERN_ERR "encirq no free buffers, increase param encoder_buffers\n");
+
+ /* Ensure offset into buffer remains 0, fill buffer
+ * with known bad data. We check for this data at a later point
+ * in time. */
+ saa7164_buffer_zero_offsets(port, bufnr);
+ memset_io(buf->cpu, 0xff, buf->pci_size);
+ if (crc_checking) {
+ /* Throw yet aanother new checksum on the dma buffer */
+ buf->crc = crc32(0, buf->cpu, buf->actual_size);
+ }
+
+ break;
+ }
+ }
+ mutex_unlock(&port->dmaqueue_lock);
+}
+
+static void saa7164_work_enchandler(struct work_struct *w)
+{
+ struct saa7164_port *port =
+ container_of(w, struct saa7164_port, workenc);
+ struct saa7164_dev *dev = port->dev;
+
+ u32 wp, mcb, rp, cnt = 0;
+
+ port->last_svc_msecs_diff = port->last_svc_msecs;
+ port->last_svc_msecs = jiffies_to_msecs(jiffies);
+
+ port->last_svc_msecs_diff = port->last_svc_msecs -
+ port->last_svc_msecs_diff;
+
+ saa7164_histogram_update(&port->svc_interval,
+ port->last_svc_msecs_diff);
+
+ port->last_irq_svc_msecs_diff = port->last_svc_msecs -
+ port->last_irq_msecs;
+
+ saa7164_histogram_update(&port->irq_svc_interval,
+ port->last_irq_svc_msecs_diff);
+
+ dprintk(DBGLVL_IRQ,
+ "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
+ __func__,
+ port->last_svc_msecs_diff,
+ port->last_irq_svc_msecs_diff,
+ port->last_svc_wp,
+ port->last_svc_rp
+ );
+
+ /* Current write position */
+ wp = saa7164_readl(port->bufcounter);
+ if (wp > (port->hwcfg.buffercount - 1)) {
+ printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
+ return;
+ }
+
+ /* Most current complete buffer */
+ if (wp == 0)
+ mcb = (port->hwcfg.buffercount - 1);
+ else
+ mcb = wp - 1;
+
+ while (1) {
+ if (port->done_first_interrupt == 0) {
+ port->done_first_interrupt++;
+ rp = mcb;
+ } else
+ rp = (port->last_svc_rp + 1) % 8;
+
+ if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
+ printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
+ break;
+ }
+
+ saa7164_work_enchandler_helper(port, rp);
+ port->last_svc_rp = rp;
+ cnt++;
+
+ if (rp == mcb)
+ break;
+ }
+
+ /* TODO: Convert this into a /proc/saa7164 style readable file */
+ if (print_histogram == port->nr) {
+ saa7164_histogram_print(port, &port->irq_interval);
+ saa7164_histogram_print(port, &port->svc_interval);
+ saa7164_histogram_print(port, &port->irq_svc_interval);
+ saa7164_histogram_print(port, &port->read_interval);
+ saa7164_histogram_print(port, &port->poll_interval);
+ /* TODO: fix this to preserve any previous state */
+ print_histogram = 64 + port->nr;
+ }
+}
+
+static void saa7164_work_vbihandler(struct work_struct *w)
+{
+ struct saa7164_port *port =
+ container_of(w, struct saa7164_port, workenc);
+ struct saa7164_dev *dev = port->dev;
+
+ u32 wp, mcb, rp, cnt = 0;
+
+ port->last_svc_msecs_diff = port->last_svc_msecs;
+ port->last_svc_msecs = jiffies_to_msecs(jiffies);
+ port->last_svc_msecs_diff = port->last_svc_msecs -
+ port->last_svc_msecs_diff;
+
+ saa7164_histogram_update(&port->svc_interval,
+ port->last_svc_msecs_diff);
+
+ port->last_irq_svc_msecs_diff = port->last_svc_msecs -
+ port->last_irq_msecs;
+
+ saa7164_histogram_update(&port->irq_svc_interval,
+ port->last_irq_svc_msecs_diff);
+
+ dprintk(DBGLVL_IRQ,
+ "%s() %Ldms elapsed irq->deferred %Ldms wp: %d rp: %d\n",
+ __func__,
+ port->last_svc_msecs_diff,
+ port->last_irq_svc_msecs_diff,
+ port->last_svc_wp,
+ port->last_svc_rp
+ );
+
+ /* Current write position */
+ wp = saa7164_readl(port->bufcounter);
+ if (wp > (port->hwcfg.buffercount - 1)) {
+ printk(KERN_ERR "%s() illegal buf count %d\n", __func__, wp);
+ return;
+ }
+
+ /* Most current complete buffer */
+ if (wp == 0)
+ mcb = (port->hwcfg.buffercount - 1);
+ else
+ mcb = wp - 1;
+
+ while (1) {
+ if (port->done_first_interrupt == 0) {
+ port->done_first_interrupt++;
+ rp = mcb;
+ } else
+ rp = (port->last_svc_rp + 1) % 8;
+
+ if ((rp < 0) || (rp > (port->hwcfg.buffercount - 1))) {
+ printk(KERN_ERR "%s() illegal rp count %d\n", __func__, rp);
+ break;
+ }
+
+ saa7164_work_enchandler_helper(port, rp);
+ port->last_svc_rp = rp;
+ cnt++;
+
+ if (rp == mcb)
+ break;
+ }
+
+ /* TODO: Convert this into a /proc/saa7164 style readable file */
+ if (print_histogram == port->nr) {
+ saa7164_histogram_print(port, &port->irq_interval);
+ saa7164_histogram_print(port, &port->svc_interval);
+ saa7164_histogram_print(port, &port->irq_svc_interval);
+ saa7164_histogram_print(port, &port->read_interval);
+ saa7164_histogram_print(port, &port->poll_interval);
+ /* TODO: fix this to preserve any previous state */
+ print_histogram = 64 + port->nr;
+ }
+}
+
static void saa7164_work_cmdhandler(struct work_struct *w)
{
struct saa7164_dev *dev = container_of(w, struct saa7164_dev, workcmd);
@@ -74,7 +541,7 @@ static void saa7164_work_cmdhandler(struct work_struct *w)
static void saa7164_buffer_deliver(struct saa7164_buffer *buf)
{
- struct saa7164_tsport *port = buf->port;
+ struct saa7164_port *port = buf->port;
/* Feed the transport payload into the kernel demux */
dvb_dmx_swfilter_packets(&port->dvb.demux, (u8 *)buf->cpu,
@@ -82,7 +549,56 @@ static void saa7164_buffer_deliver(struct saa7164_buffer *buf)
}
-static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port)
+static irqreturn_t saa7164_irq_vbi(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ /* Store old time */
+ port->last_irq_msecs_diff = port->last_irq_msecs;
+
+ /* Collect new stats */
+ port->last_irq_msecs = jiffies_to_msecs(jiffies);
+
+ /* Calculate stats */
+ port->last_irq_msecs_diff = port->last_irq_msecs -
+ port->last_irq_msecs_diff;
+
+ saa7164_histogram_update(&port->irq_interval,
+ port->last_irq_msecs_diff);
+
+ dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
+ port->last_irq_msecs_diff);
+
+ /* Tis calls the vbi irq handler */
+ schedule_work(&port->workenc);
+ return 0;
+}
+
+static irqreturn_t saa7164_irq_encoder(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ /* Store old time */
+ port->last_irq_msecs_diff = port->last_irq_msecs;
+
+ /* Collect new stats */
+ port->last_irq_msecs = jiffies_to_msecs(jiffies);
+
+ /* Calculate stats */
+ port->last_irq_msecs_diff = port->last_irq_msecs -
+ port->last_irq_msecs_diff;
+
+ saa7164_histogram_update(&port->irq_interval,
+ port->last_irq_msecs_diff);
+
+ dprintk(DBGLVL_IRQ, "%s() %Ldms elapsed\n", __func__,
+ port->last_irq_msecs_diff);
+
+ schedule_work(&port->workenc);
+ return 0;
+}
+
+static irqreturn_t saa7164_irq_ts(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
struct saa7164_buffer *buf;
@@ -96,7 +612,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port)
/* Find the previous buffer to the current write point */
if (wp == 0)
- rp = 7;
+ rp = (port->hwcfg.buffercount - 1);
else
rp = wp - 1;
@@ -107,7 +623,7 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port)
if (i++ > port->hwcfg.buffercount)
BUG();
- if (buf->nr == rp) {
+ if (buf->idx == rp) {
/* Found the buffer, deal with it */
dprintk(DBGLVL_IRQ, "%s() wp: %d processing: %d\n",
__func__, wp, rp);
@@ -123,6 +639,13 @@ static irqreturn_t saa7164_irq_ts(struct saa7164_tsport *port)
static irqreturn_t saa7164_irq(int irq, void *dev_id)
{
struct saa7164_dev *dev = dev_id;
+ struct saa7164_port *porta = &dev->ports[SAA7164_PORT_TS1];
+ struct saa7164_port *portb = &dev->ports[SAA7164_PORT_TS2];
+ struct saa7164_port *portc = &dev->ports[SAA7164_PORT_ENC1];
+ struct saa7164_port *portd = &dev->ports[SAA7164_PORT_ENC2];
+ struct saa7164_port *porte = &dev->ports[SAA7164_PORT_VBI1];
+ struct saa7164_port *portf = &dev->ports[SAA7164_PORT_VBI2];
+
u32 intid, intstat[INT_SIZE/4];
int i, handled = 0, bit;
@@ -132,8 +655,8 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id)
goto out;
}
- /* Check that the hardware is accessable. If the status bytes are
- * 0xFF then the device is not accessable, the the IRQ belongs
+ /* Check that the hardware is accessible. If the status bytes are
+ * 0xFF then the device is not accessible, the the IRQ belongs
* to another driver.
* 4 x u32 interrupt registers.
*/
@@ -168,17 +691,35 @@ static irqreturn_t saa7164_irq(int irq, void *dev_id)
if (intid == dev->intfdesc.bInterruptId) {
/* A response to an cmd/api call */
schedule_work(&dev->workcmd);
- } else if (intid ==
- dev->ts1.hwcfg.interruptid) {
+ } else if (intid == porta->hwcfg.interruptid) {
/* Transport path 1 */
- saa7164_irq_ts(&dev->ts1);
+ saa7164_irq_ts(porta);
- } else if (intid ==
- dev->ts2.hwcfg.interruptid) {
+ } else if (intid == portb->hwcfg.interruptid) {
/* Transport path 2 */
- saa7164_irq_ts(&dev->ts2);
+ saa7164_irq_ts(portb);
+
+ } else if (intid == portc->hwcfg.interruptid) {
+
+ /* Encoder path 1 */
+ saa7164_irq_encoder(portc);
+
+ } else if (intid == portd->hwcfg.interruptid) {
+
+ /* Encoder path 2 */
+ saa7164_irq_encoder(portd);
+
+ } else if (intid == porte->hwcfg.interruptid) {
+
+ /* VBI path 1 */
+ saa7164_irq_vbi(porte);
+
+ } else if (intid == portf->hwcfg.interruptid) {
+
+ /* VBI path 2 */
+ saa7164_irq_vbi(portf);
} else {
/* Find the function */
@@ -286,8 +827,8 @@ void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr)
static void saa7164_dump_hwdesc(struct saa7164_dev *dev)
{
- dprintk(1, "@0x%p hwdesc sizeof(tmComResHWDescr_t) = %d bytes\n",
- &dev->hwdesc, (u32)sizeof(tmComResHWDescr_t));
+ dprintk(1, "@0x%p hwdesc sizeof(struct tmComResHWDescr) = %d bytes\n",
+ &dev->hwdesc, (u32)sizeof(struct tmComResHWDescr));
dprintk(1, " .bLength = 0x%x\n", dev->hwdesc.bLength);
dprintk(1, " .bDescriptorType = 0x%x\n", dev->hwdesc.bDescriptorType);
@@ -317,8 +858,8 @@ static void saa7164_dump_hwdesc(struct saa7164_dev *dev)
static void saa7164_dump_intfdesc(struct saa7164_dev *dev)
{
dprintk(1, "@0x%p intfdesc "
- "sizeof(tmComResInterfaceDescr_t) = %d bytes\n",
- &dev->intfdesc, (u32)sizeof(tmComResInterfaceDescr_t));
+ "sizeof(struct tmComResInterfaceDescr) = %d bytes\n",
+ &dev->intfdesc, (u32)sizeof(struct tmComResInterfaceDescr));
dprintk(1, " .bLength = 0x%x\n", dev->intfdesc.bLength);
dprintk(1, " .bDescriptorType = 0x%x\n", dev->intfdesc.bDescriptorType);
@@ -338,8 +879,8 @@ static void saa7164_dump_intfdesc(struct saa7164_dev *dev)
static void saa7164_dump_busdesc(struct saa7164_dev *dev)
{
- dprintk(1, "@0x%p busdesc sizeof(tmComResBusDescr_t) = %d bytes\n",
- &dev->busdesc, (u32)sizeof(tmComResBusDescr_t));
+ dprintk(1, "@0x%p busdesc sizeof(struct tmComResBusDescr) = %d bytes\n",
+ &dev->busdesc, (u32)sizeof(struct tmComResBusDescr));
dprintk(1, " .CommandRing = 0x%016Lx\n", dev->busdesc.CommandRing);
dprintk(1, " .ResponseRing = 0x%016Lx\n", dev->busdesc.ResponseRing);
@@ -356,23 +897,23 @@ static void saa7164_dump_busdesc(struct saa7164_dev *dev)
*/
static void saa7164_get_descriptors(struct saa7164_dev *dev)
{
- memcpy(&dev->hwdesc, dev->bmmio, sizeof(tmComResHWDescr_t));
- memcpy(&dev->intfdesc, dev->bmmio + sizeof(tmComResHWDescr_t),
- sizeof(tmComResInterfaceDescr_t));
- memcpy(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation,
- sizeof(tmComResBusDescr_t));
-
- if (dev->hwdesc.bLength != sizeof(tmComResHWDescr_t)) {
- printk(KERN_ERR "Structure tmComResHWDescr_t is mangled\n");
+ memcpy_fromio(&dev->hwdesc, dev->bmmio, sizeof(struct tmComResHWDescr));
+ memcpy_fromio(&dev->intfdesc, dev->bmmio + sizeof(struct tmComResHWDescr),
+ sizeof(struct tmComResInterfaceDescr));
+ memcpy_fromio(&dev->busdesc, dev->bmmio + dev->intfdesc.BARLocation,
+ sizeof(struct tmComResBusDescr));
+
+ if (dev->hwdesc.bLength != sizeof(struct tmComResHWDescr)) {
+ printk(KERN_ERR "Structure struct tmComResHWDescr is mangled\n");
printk(KERN_ERR "Need %x got %d\n", dev->hwdesc.bLength,
- (u32)sizeof(tmComResHWDescr_t));
+ (u32)sizeof(struct tmComResHWDescr));
} else
saa7164_dump_hwdesc(dev);
- if (dev->intfdesc.bLength != sizeof(tmComResInterfaceDescr_t)) {
- printk(KERN_ERR "struct tmComResInterfaceDescr_t is mangled\n");
+ if (dev->intfdesc.bLength != sizeof(struct tmComResInterfaceDescr)) {
+ printk(KERN_ERR "struct struct tmComResInterfaceDescr is mangled\n");
printk(KERN_ERR "Need %x got %d\n", dev->intfdesc.bLength,
- (u32)sizeof(tmComResInterfaceDescr_t));
+ (u32)sizeof(struct tmComResInterfaceDescr));
} else
saa7164_dump_intfdesc(dev);
@@ -402,6 +943,56 @@ static int get_resources(struct saa7164_dev *dev)
return -EBUSY;
}
+static int saa7164_port_init(struct saa7164_dev *dev, int portnr)
+{
+ struct saa7164_port *port = 0;
+
+ if ((portnr < 0) || (portnr >= SAA7164_MAX_PORTS))
+ BUG();
+
+ port = &dev->ports[portnr];
+
+ port->dev = dev;
+ port->nr = portnr;
+
+ if ((portnr == SAA7164_PORT_TS1) || (portnr == SAA7164_PORT_TS2))
+ port->type = SAA7164_MPEG_DVB;
+ else
+ if ((portnr == SAA7164_PORT_ENC1) || (portnr == SAA7164_PORT_ENC2)) {
+ port->type = SAA7164_MPEG_ENCODER;
+
+ /* We need a deferred interrupt handler for cmd handling */
+ INIT_WORK(&port->workenc, saa7164_work_enchandler);
+ } else if ((portnr == SAA7164_PORT_VBI1) || (portnr == SAA7164_PORT_VBI2)) {
+ port->type = SAA7164_MPEG_VBI;
+
+ /* We need a deferred interrupt handler for cmd handling */
+ INIT_WORK(&port->workenc, saa7164_work_vbihandler);
+ } else
+ BUG();
+
+ /* Init all the critical resources */
+ mutex_init(&port->dvb.lock);
+ INIT_LIST_HEAD(&port->dmaqueue.list);
+ mutex_init(&port->dmaqueue_lock);
+
+ INIT_LIST_HEAD(&port->list_buf_used.list);
+ INIT_LIST_HEAD(&port->list_buf_free.list);
+ init_waitqueue_head(&port->wait_read);
+
+
+ saa7164_histogram_reset(&port->irq_interval, "irq intervals");
+ saa7164_histogram_reset(&port->svc_interval, "deferred intervals");
+ saa7164_histogram_reset(&port->irq_svc_interval,
+ "irq to deferred intervals");
+ saa7164_histogram_reset(&port->read_interval,
+ "encoder/vbi read() intervals");
+ saa7164_histogram_reset(&port->poll_interval,
+ "encoder/vbi poll() intervals");
+
+ return 0;
+}
+
static int saa7164_dev_setup(struct saa7164_dev *dev)
{
int i;
@@ -410,7 +1001,7 @@ static int saa7164_dev_setup(struct saa7164_dev *dev)
atomic_inc(&dev->refcount);
dev->nr = saa7164_devcount++;
- sprintf(dev->name, "saa7164[%d]", dev->nr);
+ snprintf(dev->name, sizeof(dev->name), "saa7164[%d]", dev->nr);
mutex_lock(&devlist);
list_add_tail(&dev->devlist, &saa7164_devlist);
@@ -443,23 +1034,13 @@ static int saa7164_dev_setup(struct saa7164_dev *dev)
dev->i2c_bus[2].dev = dev;
dev->i2c_bus[2].nr = 2;
- /* Transport port A Defaults / setup */
- dev->ts1.dev = dev;
- dev->ts1.nr = 0;
- mutex_init(&dev->ts1.dvb.lock);
- INIT_LIST_HEAD(&dev->ts1.dmaqueue.list);
- INIT_LIST_HEAD(&dev->ts1.dummy_dmaqueue.list);
- mutex_init(&dev->ts1.dmaqueue_lock);
- mutex_init(&dev->ts1.dummy_dmaqueue_lock);
-
- /* Transport port B Defaults / setup */
- dev->ts2.dev = dev;
- dev->ts2.nr = 1;
- mutex_init(&dev->ts2.dvb.lock);
- INIT_LIST_HEAD(&dev->ts2.dmaqueue.list);
- INIT_LIST_HEAD(&dev->ts2.dummy_dmaqueue.list);
- mutex_init(&dev->ts2.dmaqueue_lock);
- mutex_init(&dev->ts2.dummy_dmaqueue_lock);
+ /* Transport + Encoder ports 1, 2, 3, 4 - Defaults / setup */
+ saa7164_port_init(dev, SAA7164_PORT_TS1);
+ saa7164_port_init(dev, SAA7164_PORT_TS2);
+ saa7164_port_init(dev, SAA7164_PORT_ENC1);
+ saa7164_port_init(dev, SAA7164_PORT_ENC2);
+ saa7164_port_init(dev, SAA7164_PORT_VBI1);
+ saa7164_port_init(dev, SAA7164_PORT_VBI2);
if (get_resources(dev) < 0) {
printk(KERN_ERR "CORE %s No more PCIe resources for "
@@ -516,6 +1097,132 @@ static void saa7164_dev_unregister(struct saa7164_dev *dev)
return;
}
+#ifdef CONFIG_PROC_FS
+static int saa7164_proc_show(struct seq_file *m, void *v)
+{
+ struct saa7164_dev *dev;
+ struct tmComResBusInfo *b;
+ struct list_head *list;
+ int i, c;
+
+ if (saa7164_devcount == 0)
+ return 0;
+
+ list_for_each(list, &saa7164_devlist) {
+ dev = list_entry(list, struct saa7164_dev, devlist);
+ seq_printf(m, "%s = %p\n", dev->name, dev);
+
+ /* Lock the bus from any other access */
+ b = &dev->bus;
+ mutex_lock(&b->lock);
+
+ seq_printf(m, " .m_pdwSetWritePos = 0x%x (0x%08x)\n",
+ b->m_dwSetReadPos, saa7164_readl(b->m_dwSetReadPos));
+
+ seq_printf(m, " .m_pdwSetReadPos = 0x%x (0x%08x)\n",
+ b->m_dwSetWritePos, saa7164_readl(b->m_dwSetWritePos));
+
+ seq_printf(m, " .m_pdwGetWritePos = 0x%x (0x%08x)\n",
+ b->m_dwGetReadPos, saa7164_readl(b->m_dwGetReadPos));
+
+ seq_printf(m, " .m_pdwGetReadPos = 0x%x (0x%08x)\n",
+ b->m_dwGetWritePos, saa7164_readl(b->m_dwGetWritePos));
+ c = 0;
+ seq_printf(m, "\n Set Ring:\n");
+ seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+ for (i = 0; i < b->m_dwSizeSetRing; i++) {
+ if (c == 0)
+ seq_printf(m, " %04x:", i);
+
+ seq_printf(m, " %02x", *(b->m_pdwSetRing + i));
+
+ if (++c == 16) {
+ seq_printf(m, "\n");
+ c = 0;
+ }
+ }
+
+ c = 0;
+ seq_printf(m, "\n Get Ring:\n");
+ seq_printf(m, "\n addr 00 01 02 03 04 05 06 07 08 09 0a 0b 0c 0d 0e 0f\n");
+ for (i = 0; i < b->m_dwSizeGetRing; i++) {
+ if (c == 0)
+ seq_printf(m, " %04x:", i);
+
+ seq_printf(m, " %02x", *(b->m_pdwGetRing + i));
+
+ if (++c == 16) {
+ seq_printf(m, "\n");
+ c = 0;
+ }
+ }
+
+ mutex_unlock(&b->lock);
+
+ }
+
+ return 0;
+}
+
+static int saa7164_proc_open(struct inode *inode, struct file *filp)
+{
+ return single_open(filp, saa7164_proc_show, NULL);
+}
+
+static const struct file_operations saa7164_proc_fops = {
+ .open = saa7164_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int saa7164_proc_create(void)
+{
+ struct proc_dir_entry *pe;
+
+ pe = proc_create("saa7164", S_IRUGO, NULL, &saa7164_proc_fops);
+ if (!pe)
+ return -ENOMEM;
+
+ return 0;
+}
+#endif
+
+static int saa7164_thread_function(void *data)
+{
+ struct saa7164_dev *dev = data;
+ struct tmFwInfoStruct fwinfo;
+ u64 last_poll_time = 0;
+
+ dprintk(DBGLVL_THR, "thread started\n");
+
+ set_freezable();
+
+ while (1) {
+ msleep_interruptible(100);
+ if (kthread_should_stop())
+ break;
+ try_to_freeze();
+
+ dprintk(DBGLVL_THR, "thread running\n");
+
+ /* Dump the firmware debug message to console */
+ /* Polling this costs us 1-2% of the arm CPU */
+ /* convert this into a respnde to interrupt 0x7a */
+ saa7164_api_collect_debug(dev);
+
+ /* Monitor CPU load every 1 second */
+ if ((last_poll_time + 1000 /* ms */) < jiffies_to_msecs(jiffies)) {
+ saa7164_api_get_load_info(dev, &fwinfo);
+ last_poll_time = jiffies_to_msecs(jiffies);
+ }
+
+ }
+
+ dprintk(DBGLVL_THR, "thread exiting\n");
+ return 0;
+}
+
static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
const struct pci_device_id *pci_id)
{
@@ -622,7 +1329,6 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
saa7164_gpio_setup(dev);
saa7164_card_setup(dev);
-
/* Parse the dynamic device configuration, find various
* media endpoints (MPEG, WMV, PS, TS) and cache their
* configuration details into the driver, so we can
@@ -633,7 +1339,7 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
/* Begin to create the video sub-systems and register funcs */
if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB) {
- if (saa7164_dvb_register(&dev->ts1) < 0) {
+ if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS1]) < 0) {
printk(KERN_ERR "%s() Failed to register "
"dvb adapters on porta\n",
__func__);
@@ -641,13 +1347,50 @@ static int __devinit saa7164_initdev(struct pci_dev *pci_dev,
}
if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB) {
- if (saa7164_dvb_register(&dev->ts2) < 0) {
+ if (saa7164_dvb_register(&dev->ports[SAA7164_PORT_TS2]) < 0) {
printk(KERN_ERR"%s() Failed to register "
"dvb adapters on portb\n",
__func__);
}
}
+ if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER) {
+ if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC1]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "mpeg encoder\n", __func__);
+ }
+ }
+
+ if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER) {
+ if (saa7164_encoder_register(&dev->ports[SAA7164_PORT_ENC2]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "mpeg encoder\n", __func__);
+ }
+ }
+
+ if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI) {
+ if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI1]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "vbi device\n", __func__);
+ }
+ }
+
+ if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI) {
+ if (saa7164_vbi_register(&dev->ports[SAA7164_PORT_VBI2]) < 0) {
+ printk(KERN_ERR"%s() Failed to register "
+ "vbi device\n", __func__);
+ }
+ }
+ saa7164_api_set_debug(dev, fw_debug);
+
+ if (fw_debug) {
+ dev->kthread = kthread_run(saa7164_thread_function, dev,
+ "saa7164 debug");
+ if (!dev->kthread)
+ printk(KERN_ERR "%s() Failed to create "
+ "debug kernel thread\n", __func__);
+ }
+
} /* != BOARD_UNKNOWN */
else
printk(KERN_ERR "%s() Unsupported board detected, "
@@ -675,13 +1418,49 @@ static void __devexit saa7164_finidev(struct pci_dev *pci_dev)
{
struct saa7164_dev *dev = pci_get_drvdata(pci_dev);
+ if (dev->board != SAA7164_BOARD_UNKNOWN) {
+ if (fw_debug && dev->kthread) {
+ kthread_stop(dev->kthread);
+ dev->kthread = NULL;
+ }
+ if (dev->firmwareloaded)
+ saa7164_api_set_debug(dev, 0x00);
+ }
+
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].irq_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].svc_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].irq_svc_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].read_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_ENC1],
+ &dev->ports[SAA7164_PORT_ENC1].poll_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI1],
+ &dev->ports[SAA7164_PORT_VBI1].read_interval);
+ saa7164_histogram_print(&dev->ports[SAA7164_PORT_VBI2],
+ &dev->ports[SAA7164_PORT_VBI2].poll_interval);
+
saa7164_shutdown(dev);
if (saa7164_boards[dev->board].porta == SAA7164_MPEG_DVB)
- saa7164_dvb_unregister(&dev->ts1);
+ saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS1]);
if (saa7164_boards[dev->board].portb == SAA7164_MPEG_DVB)
- saa7164_dvb_unregister(&dev->ts2);
+ saa7164_dvb_unregister(&dev->ports[SAA7164_PORT_TS2]);
+
+ if (saa7164_boards[dev->board].portc == SAA7164_MPEG_ENCODER)
+ saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC1]);
+
+ if (saa7164_boards[dev->board].portd == SAA7164_MPEG_ENCODER)
+ saa7164_encoder_unregister(&dev->ports[SAA7164_PORT_ENC2]);
+
+ if (saa7164_boards[dev->board].porte == SAA7164_MPEG_VBI)
+ saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI1]);
+
+ if (saa7164_boards[dev->board].portf == SAA7164_MPEG_VBI)
+ saa7164_vbi_unregister(&dev->ports[SAA7164_PORT_VBI2]);
saa7164_i2c_unregister(&dev->i2c_bus[0]);
saa7164_i2c_unregister(&dev->i2c_bus[1]);
@@ -727,11 +1506,18 @@ static struct pci_driver saa7164_pci_driver = {
static int __init saa7164_init(void)
{
printk(KERN_INFO "saa7164 driver loaded\n");
+
+#ifdef CONFIG_PROC_FS
+ saa7164_proc_create();
+#endif
return pci_register_driver(&saa7164_pci_driver);
}
static void __exit saa7164_fini(void)
{
+#ifdef CONFIG_PROC_FS
+ remove_proc_entry("saa7164", NULL);
+#endif
pci_unregister_driver(&saa7164_pci_driver);
}
diff --git a/drivers/media/video/saa7164/saa7164-dvb.c b/drivers/media/video/saa7164/saa7164-dvb.c
index cf099c59b38e..b305a01b3bde 100644
--- a/drivers/media/video/saa7164/saa7164-dvb.c
+++ b/drivers/media/video/saa7164/saa7164-dvb.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -82,7 +82,7 @@ static struct s5h1411_config hauppauge_s5h1411_config = {
.mpeg_timing = S5H1411_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
};
-static int saa7164_dvb_stop_tsport(struct saa7164_tsport *port)
+static int saa7164_dvb_stop_port(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
int ret;
@@ -100,7 +100,7 @@ static int saa7164_dvb_stop_tsport(struct saa7164_tsport *port)
return ret;
}
-static int saa7164_dvb_acquire_tsport(struct saa7164_tsport *port)
+static int saa7164_dvb_acquire_port(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
int ret;
@@ -118,7 +118,7 @@ static int saa7164_dvb_acquire_tsport(struct saa7164_tsport *port)
return ret;
}
-static int saa7164_dvb_pause_tsport(struct saa7164_tsport *port)
+static int saa7164_dvb_pause_port(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
int ret;
@@ -140,90 +140,38 @@ static int saa7164_dvb_pause_tsport(struct saa7164_tsport *port)
* the part through AVStream / KS Windows stages, forwards or backwards.
* States are: stopped, acquired (h/w), paused, started.
*/
-static int saa7164_dvb_stop_streaming(struct saa7164_tsport *port)
+static int saa7164_dvb_stop_streaming(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
- int ret;
-
- dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
-
- ret = saa7164_dvb_pause_tsport(port);
- ret = saa7164_dvb_acquire_tsport(port);
- ret = saa7164_dvb_stop_tsport(port);
-
- return ret;
-}
-
-static int saa7164_dvb_cfg_tsport(struct saa7164_tsport *port)
-{
- tmHWStreamParameters_t *params = &port->hw_streamingparams;
- struct saa7164_dev *dev = port->dev;
struct saa7164_buffer *buf;
- struct list_head *c, *n;
- int i = 0;
+ struct list_head *p, *q;
+ int ret;
dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
- saa7164_writel(port->pitch, params->pitch);
- saa7164_writel(port->bufsize, params->pitch * params->numberoflines);
+ ret = saa7164_dvb_pause_port(port);
+ ret = saa7164_dvb_acquire_port(port);
+ ret = saa7164_dvb_stop_port(port);
- dprintk(DBGLVL_DVB, " configured:\n");
- dprintk(DBGLVL_DVB, " lmmio 0x%p\n", dev->lmmio);
- dprintk(DBGLVL_DVB, " bufcounter 0x%x = 0x%x\n", port->bufcounter,
- saa7164_readl(port->bufcounter));
-
- dprintk(DBGLVL_DVB, " pitch 0x%x = %d\n", port->pitch,
- saa7164_readl(port->pitch));
-
- dprintk(DBGLVL_DVB, " bufsize 0x%x = %d\n", port->bufsize,
- saa7164_readl(port->bufsize));
-
- dprintk(DBGLVL_DVB, " buffercount = %d\n", port->hwcfg.buffercount);
- dprintk(DBGLVL_DVB, " bufoffset = 0x%x\n", port->bufoffset);
- dprintk(DBGLVL_DVB, " bufptr32h = 0x%x\n", port->bufptr32h);
- dprintk(DBGLVL_DVB, " bufptr32l = 0x%x\n", port->bufptr32l);
-
- /* Poke the buffers and offsets into PCI space */
+ /* Mark the hardware buffers as free */
mutex_lock(&port->dmaqueue_lock);
- list_for_each_safe(c, n, &port->dmaqueue.list) {
- buf = list_entry(c, struct saa7164_buffer, list);
-
- /* TODO: Review this in light of 32v64 assignments */
- saa7164_writel(port->bufoffset + (sizeof(u32) * i), 0);
- saa7164_writel(port->bufptr32h + ((sizeof(u32) * 2) * i),
- buf->pt_dma);
- saa7164_writel(port->bufptr32l + ((sizeof(u32) * 2) * i), 0);
-
- dprintk(DBGLVL_DVB,
- " buf[%d] offset 0x%llx (0x%x) "
- "buf 0x%llx/%llx (0x%x/%x)\n",
- i,
- (u64)port->bufoffset + (i * sizeof(u32)),
- saa7164_readl(port->bufoffset + (sizeof(u32) * i)),
- (u64)port->bufptr32h + ((sizeof(u32) * 2) * i),
- (u64)port->bufptr32l + ((sizeof(u32) * 2) * i),
- saa7164_readl(port->bufptr32h + ((sizeof(u32) * i)
- * 2)),
- saa7164_readl(port->bufptr32l + ((sizeof(u32) * i)
- * 2)));
-
- if (i++ > port->hwcfg.buffercount)
- BUG();
-
+ list_for_each_safe(p, q, &port->dmaqueue.list) {
+ buf = list_entry(p, struct saa7164_buffer, list);
+ buf->flags = SAA7164_BUFFER_FREE;
}
mutex_unlock(&port->dmaqueue_lock);
- return 0;
+ return ret;
}
-static int saa7164_dvb_start_tsport(struct saa7164_tsport *port)
+static int saa7164_dvb_start_port(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
int ret = 0, result;
dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
- saa7164_dvb_cfg_tsport(port);
+ saa7164_buffer_cfg_port(port);
/* Acquire the hardware */
result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
@@ -284,7 +232,7 @@ out:
static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv;
+ struct saa7164_port *port = (struct saa7164_port *) demux->priv;
struct saa7164_dvb *dvb = &port->dvb;
struct saa7164_dev *dev = port->dev;
int ret = 0;
@@ -298,7 +246,7 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
mutex_lock(&dvb->lock);
if (dvb->feeding++ == 0) {
/* Start transport */
- ret = saa7164_dvb_start_tsport(port);
+ ret = saa7164_dvb_start_port(port);
}
mutex_unlock(&dvb->lock);
dprintk(DBGLVL_DVB, "%s(port=%d) now feeding = %d\n",
@@ -311,7 +259,7 @@ static int saa7164_dvb_start_feed(struct dvb_demux_feed *feed)
static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed)
{
struct dvb_demux *demux = feed->demux;
- struct saa7164_tsport *port = (struct saa7164_tsport *) demux->priv;
+ struct saa7164_port *port = (struct saa7164_port *) demux->priv;
struct saa7164_dvb *dvb = &port->dvb;
struct saa7164_dev *dev = port->dev;
int ret = 0;
@@ -332,7 +280,7 @@ static int saa7164_dvb_stop_feed(struct dvb_demux_feed *feed)
return ret;
}
-static int dvb_register(struct saa7164_tsport *port)
+static int dvb_register(struct saa7164_port *port)
{
struct saa7164_dvb *dvb = &port->dvb;
struct saa7164_dev *dev = port->dev;
@@ -341,6 +289,9 @@ static int dvb_register(struct saa7164_tsport *port)
dprintk(DBGLVL_DVB, "%s(port=%d)\n", __func__, port->nr);
+ if (port->type != SAA7164_MPEG_DVB)
+ BUG();
+
/* Sanity check that the PCI configuration space is active */
if (port->hwcfg.BARLocation == 0) {
result = -ENOMEM;
@@ -378,7 +329,6 @@ static int dvb_register(struct saa7164_tsport *port)
DRIVER_NAME, result);
goto fail_adapter;
}
- buf->nr = i;
mutex_lock(&port->dmaqueue_lock);
list_add_tail(&buf->list, &port->dmaqueue.list);
@@ -473,7 +423,7 @@ fail_adapter:
return result;
}
-int saa7164_dvb_unregister(struct saa7164_tsport *port)
+int saa7164_dvb_unregister(struct saa7164_port *port)
{
struct saa7164_dvb *dvb = &port->dvb;
struct saa7164_dev *dev = port->dev;
@@ -482,12 +432,15 @@ int saa7164_dvb_unregister(struct saa7164_tsport *port)
dprintk(DBGLVL_DVB, "%s()\n", __func__);
+ if (port->type != SAA7164_MPEG_DVB)
+ BUG();
+
/* Remove any allocated buffers */
mutex_lock(&port->dmaqueue_lock);
list_for_each_safe(c, n, &port->dmaqueue.list) {
b = list_entry(c, struct saa7164_buffer, list);
list_del(c);
- saa7164_buffer_dealloc(port, b);
+ saa7164_buffer_dealloc(b);
}
mutex_unlock(&port->dmaqueue_lock);
@@ -508,7 +461,7 @@ int saa7164_dvb_unregister(struct saa7164_tsport *port)
/* All the DVB attach calls go here, this function get's modified
* for each new card.
*/
-int saa7164_dvb_register(struct saa7164_tsport *port)
+int saa7164_dvb_register(struct saa7164_port *port)
{
struct saa7164_dev *dev = port->dev;
struct saa7164_dvb *dvb = &port->dvb;
@@ -588,8 +541,6 @@ int saa7164_dvb_register(struct saa7164_tsport *port)
return -1;
}
- /* Put the analog decoder in standby to keep it quiet */
-
/* register everything */
ret = dvb_register(port);
if (ret < 0) {
diff --git a/drivers/media/video/saa7164/saa7164-encoder.c b/drivers/media/video/saa7164/saa7164-encoder.c
new file mode 100644
index 000000000000..1838408cd5cb
--- /dev/null
+++ b/drivers/media/video/saa7164/saa7164-encoder.c
@@ -0,0 +1,1510 @@
+/*
+ * Driver for the NXP SAA7164 PCIe bridge
+ *
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "saa7164.h"
+
+#define ENCODER_MAX_BITRATE 6500000
+#define ENCODER_MIN_BITRATE 1000000
+#define ENCODER_DEF_BITRATE 5000000
+
+static struct saa7164_tvnorm saa7164_tvnorms[] = {
+ {
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
+ }, {
+ .name = "NTSC-JP",
+ .id = V4L2_STD_NTSC_M_JP,
+ }
+};
+
+static const u32 saa7164_v4l2_ctrls[] = {
+ V4L2_CID_BRIGHTNESS,
+ V4L2_CID_CONTRAST,
+ V4L2_CID_SATURATION,
+ V4L2_CID_HUE,
+ V4L2_CID_AUDIO_VOLUME,
+ V4L2_CID_SHARPNESS,
+ V4L2_CID_MPEG_STREAM_TYPE,
+ V4L2_CID_MPEG_VIDEO_ASPECT,
+ V4L2_CID_MPEG_VIDEO_B_FRAMES,
+ V4L2_CID_MPEG_VIDEO_GOP_SIZE,
+ V4L2_CID_MPEG_AUDIO_MUTE,
+ V4L2_CID_MPEG_VIDEO_BITRATE_MODE,
+ V4L2_CID_MPEG_VIDEO_BITRATE,
+ V4L2_CID_MPEG_VIDEO_BITRATE_PEAK,
+ 0
+};
+
+/* Take the encoder configuration form the port struct and
+ * flush it to the hardware.
+ */
+static void saa7164_encoder_configure(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ port->encoder_params.width = port->width;
+ port->encoder_params.height = port->height;
+ port->encoder_params.is_50hz =
+ (port->encodernorm.id & V4L2_STD_625_50) != 0;
+
+ /* Set up the DIF (enable it) for analog mode by default */
+ saa7164_api_initialize_dif(port);
+
+ /* Configure the correct video standard */
+ saa7164_api_configure_dif(port, port->encodernorm.id);
+
+ /* Ensure the audio decoder is correct configured */
+ saa7164_api_set_audio_std(port);
+}
+
+static int saa7164_encoder_buffers_dealloc(struct saa7164_port *port)
+{
+ struct list_head *c, *n, *p, *q, *l, *v;
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct saa7164_user_buffer *ubuf;
+
+ /* Remove any allocated buffers */
+ mutex_lock(&port->dmaqueue_lock);
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) dmaqueue\n", __func__, port->nr);
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+ buf = list_entry(c, struct saa7164_buffer, list);
+ list_del(c);
+ saa7164_buffer_dealloc(buf);
+ }
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) used\n", __func__, port->nr);
+ list_for_each_safe(p, q, &port->list_buf_used.list) {
+ ubuf = list_entry(p, struct saa7164_user_buffer, list);
+ list_del(p);
+ saa7164_buffer_dealloc_user(ubuf);
+ }
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) free\n", __func__, port->nr);
+ list_for_each_safe(l, v, &port->list_buf_free.list) {
+ ubuf = list_entry(l, struct saa7164_user_buffer, list);
+ list_del(l);
+ saa7164_buffer_dealloc_user(ubuf);
+ }
+
+ mutex_unlock(&port->dmaqueue_lock);
+ dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
+
+ return 0;
+}
+
+/* Dynamic buffer switch at encoder start time */
+static int saa7164_encoder_buffers_alloc(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct saa7164_user_buffer *ubuf;
+ struct tmHWStreamParameters *params = &port->hw_streamingparams;
+ int result = -ENODEV, i;
+ int len = 0;
+
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ if (port->encoder_params.stream_type ==
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS) {
+ dprintk(DBGLVL_ENC,
+ "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_PS\n",
+ __func__);
+ params->samplesperline = 128;
+ params->numberoflines = 256;
+ params->pitch = 128;
+ params->numpagetables = 2 +
+ ((SAA7164_PS_NUMBER_OF_LINES * 128) / PAGE_SIZE);
+ } else
+ if (port->encoder_params.stream_type ==
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS) {
+ dprintk(DBGLVL_ENC,
+ "%s() type=V4L2_MPEG_STREAM_TYPE_MPEG2_TS\n",
+ __func__);
+ params->samplesperline = 188;
+ params->numberoflines = 312;
+ params->pitch = 188;
+ params->numpagetables = 2 +
+ ((SAA7164_TS_NUMBER_OF_LINES * 188) / PAGE_SIZE);
+ } else
+ BUG();
+
+ /* Init and establish defaults */
+ params->bitspersample = 8;
+ params->linethreshold = 0;
+ params->pagetablelistvirt = 0;
+ params->pagetablelistphys = 0;
+ params->numpagetableentries = port->hwcfg.buffercount;
+
+ /* Allocate the PCI resources, buffers (hard) */
+ for (i = 0; i < port->hwcfg.buffercount; i++) {
+ buf = saa7164_buffer_alloc(port,
+ params->numberoflines *
+ params->pitch);
+
+ if (!buf) {
+ printk(KERN_ERR "%s() failed "
+ "(errno = %d), unable to allocate buffer\n",
+ __func__, result);
+ result = -ENOMEM;
+ goto failed;
+ } else {
+
+ mutex_lock(&port->dmaqueue_lock);
+ list_add_tail(&buf->list, &port->dmaqueue.list);
+ mutex_unlock(&port->dmaqueue_lock);
+
+ }
+ }
+
+ /* Allocate some kenrel kernel buffers for copying
+ * to userpsace.
+ */
+ len = params->numberoflines * params->pitch;
+
+ if (encoder_buffers < 16)
+ encoder_buffers = 16;
+ if (encoder_buffers > 512)
+ encoder_buffers = 512;
+
+ for (i = 0; i < encoder_buffers; i++) {
+
+ ubuf = saa7164_buffer_alloc_user(dev, len);
+ if (ubuf) {
+ mutex_lock(&port->dmaqueue_lock);
+ list_add_tail(&ubuf->list, &port->list_buf_free.list);
+ mutex_unlock(&port->dmaqueue_lock);
+ }
+
+ }
+
+ result = 0;
+
+failed:
+ return result;
+}
+
+static int saa7164_encoder_initialize(struct saa7164_port *port)
+{
+ saa7164_encoder_configure(port);
+ return 0;
+}
+
+/* -- V4L2 --------------------------------------------------------- */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+ unsigned int i;
+
+ dprintk(DBGLVL_ENC, "%s(id=0x%x)\n", __func__, (u32)*id);
+
+ for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
+ if (*id & saa7164_tvnorms[i].id)
+ break;
+ }
+ if (i == ARRAY_SIZE(saa7164_tvnorms))
+ return -EINVAL;
+
+ port->encodernorm = saa7164_tvnorms[i];
+
+ /* Update the audio decoder while is not running in
+ * auto detect mode.
+ */
+ saa7164_api_set_audio_std(port);
+
+ dprintk(DBGLVL_ENC, "%s(id=0x%x) OK\n", __func__, (u32)*id);
+
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ int n;
+
+ char *inputs[] = { "tuner", "composite", "svideo", "aux",
+ "composite 2", "svideo 2", "aux 2" };
+
+ if (i->index >= 7)
+ return -EINVAL;
+
+ strcpy(i->name, inputs[i->index]);
+
+ if (i->index == 0)
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
+ i->std |= saa7164_tvnorms[n].id;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ if (saa7164_api_get_videomux(port) != SAA_OK)
+ return -EIO;
+
+ *i = (port->mux_input - 1);
+
+ dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, *i);
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_ENC, "%s() input=%d\n", __func__, i);
+
+ if (i >= 7)
+ return -EINVAL;
+
+ port->mux_input = i + 1;
+
+ if (saa7164_api_set_videomux(port) != SAA_OK)
+ return -EIO;
+
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ strcpy(t->name, "tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
+
+ dprintk(DBGLVL_ENC, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ /* Update the A/V core */
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = port->freq;
+
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_port *tsport;
+ struct dvb_frontend *fe;
+
+ /* TODO: Pull this for the std */
+ struct analog_parameters params = {
+ .mode = V4L2_TUNER_ANALOG_TV,
+ .audmode = V4L2_TUNER_MODE_STEREO,
+ .std = port->encodernorm.id,
+ .frequency = f->frequency
+ };
+
+ /* Stop the encoder */
+ dprintk(DBGLVL_ENC, "%s() frequency=%d tuner=%d\n", __func__,
+ f->frequency, f->tuner);
+
+ if (f->tuner != 0)
+ return -EINVAL;
+
+ if (f->type != V4L2_TUNER_ANALOG_TV)
+ return -EINVAL;
+
+ port->freq = f->frequency;
+
+ /* Update the hardware */
+ if (port->nr == SAA7164_PORT_ENC1)
+ tsport = &dev->ports[SAA7164_PORT_TS1];
+ else
+ if (port->nr == SAA7164_PORT_ENC2)
+ tsport = &dev->ports[SAA7164_PORT_TS2];
+ else
+ BUG();
+
+ fe = tsport->dvb.frontend;
+
+ if (fe && fe->ops.tuner_ops.set_analog_params)
+ fe->ops.tuner_ops.set_analog_params(fe, &params);
+ else
+ printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+ saa7164_encoder_initialize(port);
+
+ return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
+ ctl->id, ctl->value);
+
+ switch (ctl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctl->value = port->ctl_brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctl->value = port->ctl_contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctl->value = port->ctl_saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctl->value = port->ctl_hue;
+ break;
+ case V4L2_CID_SHARPNESS:
+ ctl->value = port->ctl_sharpness;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ ctl->value = port->ctl_volume;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+ int ret = 0;
+
+ dprintk(DBGLVL_ENC, "%s(id=%d, value=%d)\n", __func__,
+ ctl->id, ctl->value);
+
+ switch (ctl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_brightness = ctl->value;
+ saa7164_api_set_usercontrol(port,
+ PU_BRIGHTNESS_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_CONTRAST:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_contrast = ctl->value;
+ saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_SATURATION:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_saturation = ctl->value;
+ saa7164_api_set_usercontrol(port,
+ PU_SATURATION_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_HUE:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_hue = ctl->value;
+ saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_SHARPNESS:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_sharpness = ctl->value;
+ saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ if ((ctl->value >= -83) && (ctl->value <= 24)) {
+ port->ctl_volume = ctl->value;
+ saa7164_api_set_audio_volume(port, port->ctl_volume);
+ } else
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int saa7164_get_ctrl(struct saa7164_port *port,
+ struct v4l2_ext_control *ctrl)
+{
+ struct saa7164_encoder_params *params = &port->encoder_params;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ ctrl->value = params->bitrate;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ ctrl->value = params->stream_type;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ ctrl->value = params->ctl_mute;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ ctrl->value = params->ctl_aspect;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ ctrl->value = params->bitrate_mode;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ ctrl->value = params->refdist;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ ctrl->value = params->bitrate_peak;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctrl->value = params->gop_size;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = saa7164_get_ctrl(port, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+
+ }
+
+ return -EINVAL;
+}
+
+static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+ int ret = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
+ (ctrl->value <= ENCODER_MAX_BITRATE))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
+ (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ if ((ctrl->value >= 0) &&
+ (ctrl->value <= 1))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
+ (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ if ((ctrl->value >= 0) &&
+ (ctrl->value <= 255))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ if ((ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_VBR) ||
+ (ctrl->value == V4L2_MPEG_VIDEO_BITRATE_MODE_CBR))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ if ((ctrl->value >= 1) &&
+ (ctrl->value <= 3))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ if ((ctrl->value >= ENCODER_MIN_BITRATE) &&
+ (ctrl->value <= ENCODER_MAX_BITRATE))
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = saa7164_try_ctrl(ctrl, 0);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+
+ return -EINVAL;
+}
+
+static int saa7164_set_ctrl(struct saa7164_port *port,
+ struct v4l2_ext_control *ctrl)
+{
+ struct saa7164_encoder_params *params = &port->encoder_params;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ params->bitrate = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ params->stream_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ params->ctl_mute = ctrl->value;
+ ret = saa7164_api_audio_mute(port, params->ctl_mute);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+ ret);
+ ret = -EIO;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ params->ctl_aspect = ctrl->value;
+ ret = saa7164_api_set_aspect_ratio(port);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+ ret);
+ ret = -EIO;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ params->bitrate_mode = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ params->refdist = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ params->bitrate_peak = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ params->gop_size = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* TODO: Update the hardware */
+
+ return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = saa7164_try_ctrl(ctrl, 0);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ err = saa7164_set_ctrl(port, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ strcpy(cap->driver, dev->name);
+ strlcpy(cap->card, saa7164_boards[dev->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ 0;
+
+ cap->capabilities |= V4L2_CAP_TUNER;
+ cap->version = 0;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ port->ts_packet_size * port->ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = port->width;
+ f->fmt.pix.height = port->height;
+
+ dprintk(DBGLVL_ENC, "VIDIOC_G_FMT: w: %d, h: %d\n",
+ port->width, port->height);
+
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ port->ts_packet_size * port->ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(DBGLVL_ENC, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+ port->width, port->height);
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ port->ts_packet_size * port->ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+
+ dprintk(DBGLVL_ENC, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+
+ return 0;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ return 0;
+}
+
+static int fill_queryctrl(struct saa7164_encoder_params *params,
+ struct v4l2_queryctrl *c)
+{
+ switch (c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
+ case V4L2_CID_SHARPNESS:
+ return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
+ case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
+ case V4L2_CID_MPEG_VIDEO_BITRATE:
+ return v4l2_ctrl_query_fill(c,
+ ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
+ 100000, ENCODER_DEF_BITRATE);
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(c,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+ 1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(c,
+ V4L2_MPEG_VIDEO_ASPECT_1x1,
+ V4L2_MPEG_VIDEO_ASPECT_221x100,
+ 1, V4L2_MPEG_VIDEO_ASPECT_4x3);
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return v4l2_ctrl_query_fill(c,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_VBR,
+ V4L2_MPEG_VIDEO_BITRATE_MODE_CBR,
+ 1, V4L2_MPEG_VIDEO_BITRATE_MODE_VBR);
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ return v4l2_ctrl_query_fill(c,
+ 1, 3, 1, 1);
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK:
+ return v4l2_ctrl_query_fill(c,
+ ENCODER_MIN_BITRATE, ENCODER_MAX_BITRATE,
+ 100000, ENCODER_DEF_BITRATE);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ struct saa7164_encoder_fh *fh = priv;
+ struct saa7164_port *port = fh->port;
+ int i, next;
+ u32 id = c->id;
+
+ memset(c, 0, sizeof(*c));
+
+ next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
+ c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+ for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
+ if (next) {
+ if (c->id < saa7164_v4l2_ctrls[i])
+ c->id = saa7164_v4l2_ctrls[i];
+ else
+ continue;
+ }
+
+ if (c->id == saa7164_v4l2_ctrls[i])
+ return fill_queryctrl(&port->encoder_params, c);
+
+ if (c->id < saa7164_v4l2_ctrls[i])
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int saa7164_encoder_stop_port(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+
+ ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+ if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
+ __func__, ret);
+ ret = -EIO;
+ } else {
+ dprintk(DBGLVL_ENC, "%s() Stopped\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int saa7164_encoder_acquire_port(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+
+ ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+ if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
+ __func__, ret);
+ ret = -EIO;
+ } else {
+ dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int saa7164_encoder_pause_port(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+
+ ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+ if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
+ __func__, ret);
+ ret = -EIO;
+ } else {
+ dprintk(DBGLVL_ENC, "%s() Paused\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/* Firmware is very windows centric, meaning you have to transition
+ * the part through AVStream / KS Windows stages, forwards or backwards.
+ * States are: stopped, acquired (h/w), paused, started.
+ * We have to leave here will all of the soft buffers on the free list,
+ * else the cfg_post() func won't have soft buffers to correctly configure.
+ */
+static int saa7164_encoder_stop_streaming(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct saa7164_user_buffer *ubuf;
+ struct list_head *c, *n;
+ int ret;
+
+ dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+ ret = saa7164_encoder_pause_port(port);
+ ret = saa7164_encoder_acquire_port(port);
+ ret = saa7164_encoder_stop_port(port);
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) Hardware stopped\n", __func__,
+ port->nr);
+
+ /* Reset the state of any allocated buffer resources */
+ mutex_lock(&port->dmaqueue_lock);
+
+ /* Reset the hard and soft buffer state */
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+ buf = list_entry(c, struct saa7164_buffer, list);
+ buf->flags = SAA7164_BUFFER_FREE;
+ buf->pos = 0;
+ }
+
+ list_for_each_safe(c, n, &port->list_buf_used.list) {
+ ubuf = list_entry(c, struct saa7164_user_buffer, list);
+ ubuf->pos = 0;
+ list_move_tail(&ubuf->list, &port->list_buf_free.list);
+ }
+
+ mutex_unlock(&port->dmaqueue_lock);
+
+ /* Free any allocated resources */
+ saa7164_encoder_buffers_dealloc(port);
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) Released\n", __func__, port->nr);
+
+ return ret;
+}
+
+static int saa7164_encoder_start_streaming(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int result, ret = 0;
+
+ dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+ port->done_first_interrupt = 0;
+
+ /* allocate all of the PCIe DMA buffer resources on the fly,
+ * allowing switching between TS and PS payloads without
+ * requiring a complete driver reload.
+ */
+ saa7164_encoder_buffers_alloc(port);
+
+ /* Configure the encoder with any cache values */
+ saa7164_api_set_encoder(port);
+ saa7164_api_get_encoder(port);
+
+ /* Place the empty buffers on the hardware */
+ saa7164_buffer_cfg_port(port);
+
+ /* Acquire the hardware */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
+ __func__, result);
+
+ /* Stop the hardware, regardless */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() acquire/forced stop transition "
+ "failed, res = 0x%x\n", __func__, result);
+ }
+ ret = -EIO;
+ goto out;
+ } else
+ dprintk(DBGLVL_ENC, "%s() Acquired\n", __func__);
+
+ /* Pause the hardware */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
+ __func__, result);
+
+ /* Stop the hardware, regardless */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() pause/forced stop transition "
+ "failed, res = 0x%x\n", __func__, result);
+ }
+
+ ret = -EIO;
+ goto out;
+ } else
+ dprintk(DBGLVL_ENC, "%s() Paused\n", __func__);
+
+ /* Start the hardware */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
+ __func__, result);
+
+ /* Stop the hardware, regardless */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() run/forced stop transition "
+ "failed, res = 0x%x\n", __func__, result);
+ }
+
+ ret = -EIO;
+ } else
+ dprintk(DBGLVL_ENC, "%s() Running\n", __func__);
+
+out:
+ return ret;
+}
+
+static int fops_open(struct file *file)
+{
+ struct saa7164_dev *dev;
+ struct saa7164_port *port;
+ struct saa7164_encoder_fh *fh;
+
+ port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
+ if (!port)
+ return -ENODEV;
+
+ dev = port->dev;
+
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+
+ file->private_data = fh;
+ fh->port = port;
+
+ return 0;
+}
+
+static int fops_release(struct file *file)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ /* Shut device down on last close */
+ if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+ if (atomic_dec_return(&port->v4l_reader_count) == 0) {
+ /* stop mpeg capture then cancel buffers */
+ saa7164_encoder_stop_streaming(port);
+ }
+ }
+
+ file->private_data = NULL;
+ kfree(fh);
+
+ return 0;
+}
+
+struct saa7164_user_buffer *saa7164_enc_next_buf(struct saa7164_port *port)
+{
+ struct saa7164_user_buffer *ubuf = 0;
+ struct saa7164_dev *dev = port->dev;
+ u32 crc;
+
+ mutex_lock(&port->dmaqueue_lock);
+ if (!list_empty(&port->list_buf_used.list)) {
+ ubuf = list_first_entry(&port->list_buf_used.list,
+ struct saa7164_user_buffer, list);
+
+ if (crc_checking) {
+ crc = crc32(0, ubuf->data, ubuf->actual_size);
+ if (crc != ubuf->crc) {
+ printk(KERN_ERR
+ "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
+ __func__,
+ ubuf, ubuf->crc, crc);
+ }
+ }
+
+ }
+ mutex_unlock(&port->dmaqueue_lock);
+
+ dprintk(DBGLVL_ENC, "%s() returns %p\n", __func__, ubuf);
+
+ return ubuf;
+}
+
+static ssize_t fops_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ struct saa7164_encoder_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_user_buffer *ubuf = NULL;
+ struct saa7164_dev *dev = port->dev;
+ int ret = 0;
+ int rem, cnt;
+ u8 *p;
+
+ port->last_read_msecs_diff = port->last_read_msecs;
+ port->last_read_msecs = jiffies_to_msecs(jiffies);
+ port->last_read_msecs_diff = port->last_read_msecs -
+ port->last_read_msecs_diff;
+
+ saa7164_histogram_update(&port->read_interval,
+ port->last_read_msecs_diff);
+
+ if (*pos) {
+ printk(KERN_ERR "%s() ESPIPE\n", __func__);
+ return -ESPIPE;
+ }
+
+ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+ if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+
+ if (saa7164_encoder_initialize(port) < 0) {
+ printk(KERN_ERR "%s() EINVAL\n", __func__);
+ return -EINVAL;
+ }
+
+ saa7164_encoder_start_streaming(port);
+ msleep(200);
+ }
+ }
+
+ /* blocking wait for buffer */
+ if ((file->f_flags & O_NONBLOCK) == 0) {
+ if (wait_event_interruptible(port->wait_read,
+ saa7164_enc_next_buf(port))) {
+ printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
+ return -ERESTARTSYS;
+ }
+ }
+
+ /* Pull the first buffer from the used list */
+ ubuf = saa7164_enc_next_buf(port);
+
+ while ((count > 0) && ubuf) {
+
+ /* set remaining bytes to copy */
+ rem = ubuf->actual_size - ubuf->pos;
+ cnt = rem > count ? count : rem;
+
+ p = ubuf->data + ubuf->pos;
+
+ dprintk(DBGLVL_ENC,
+ "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
+ __func__, (int)count, cnt, rem, ubuf, ubuf->pos);
+
+ if (copy_to_user(buffer, p, cnt)) {
+ printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
+ if (!ret) {
+ printk(KERN_ERR "%s() EFAULT\n", __func__);
+ ret = -EFAULT;
+ }
+ goto err;
+ }
+
+ ubuf->pos += cnt;
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+
+ if (ubuf->pos > ubuf->actual_size)
+ printk(KERN_ERR "read() pos > actual, huh?\n");
+
+ if (ubuf->pos == ubuf->actual_size) {
+
+ /* finished with current buffer, take next buffer */
+
+ /* Requeue the buffer on the free list */
+ ubuf->pos = 0;
+
+ mutex_lock(&port->dmaqueue_lock);
+ list_move_tail(&ubuf->list, &port->list_buf_free.list);
+ mutex_unlock(&port->dmaqueue_lock);
+
+ /* Dequeue next */
+ if ((file->f_flags & O_NONBLOCK) == 0) {
+ if (wait_event_interruptible(port->wait_read,
+ saa7164_enc_next_buf(port))) {
+ break;
+ }
+ }
+ ubuf = saa7164_enc_next_buf(port);
+ }
+ }
+err:
+ if (!ret && !ubuf)
+ ret = -EAGAIN;
+
+ return ret;
+}
+
+static unsigned int fops_poll(struct file *file, poll_table *wait)
+{
+ struct saa7164_encoder_fh *fh =
+ (struct saa7164_encoder_fh *)file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_user_buffer *ubuf;
+ unsigned int mask = 0;
+
+ port->last_poll_msecs_diff = port->last_poll_msecs;
+ port->last_poll_msecs = jiffies_to_msecs(jiffies);
+ port->last_poll_msecs_diff = port->last_poll_msecs -
+ port->last_poll_msecs_diff;
+
+ saa7164_histogram_update(&port->poll_interval,
+ port->last_poll_msecs_diff);
+
+ if (!video_is_registered(port->v4l_device))
+ return -EIO;
+
+ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+ if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+ if (saa7164_encoder_initialize(port) < 0)
+ return -EINVAL;
+ saa7164_encoder_start_streaming(port);
+ msleep(200);
+ }
+ }
+
+ /* blocking wait for buffer */
+ if ((file->f_flags & O_NONBLOCK) == 0) {
+ if (wait_event_interruptible(port->wait_read,
+ saa7164_enc_next_buf(port))) {
+ return -ERESTARTSYS;
+ }
+ }
+
+ /* Pull the first buffer from the used list */
+ ubuf = list_first_entry(&port->list_buf_used.list,
+ struct saa7164_user_buffer, list);
+
+ if (ubuf)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+
+static const struct v4l2_file_operations mpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = fops_open,
+ .release = fops_release,
+ .read = fops_read,
+ .poll = fops_poll,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+int saa7164_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_dbg_chip_ident *chip)
+{
+ struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+ struct saa7164_dev *dev = port->dev;
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ return 0;
+}
+
+int saa7164_g_register(struct file *file, void *fh,
+ struct v4l2_dbg_register *reg)
+{
+ struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+ struct saa7164_dev *dev = port->dev;
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ return 0;
+}
+
+int saa7164_s_register(struct file *file, void *fh,
+ struct v4l2_dbg_register *reg)
+{
+ struct saa7164_port *port = ((struct saa7164_encoder_fh *)fh)->port;
+ struct saa7164_dev *dev = port->dev;
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ return 0;
+}
+
+static const struct v4l2_ioctl_ops mpeg_ioctl_ops = {
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_g_chip_ident = saa7164_g_chip_ident,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .vidioc_g_register = saa7164_g_register,
+ .vidioc_s_register = saa7164_s_register,
+#endif
+};
+
+static struct video_device saa7164_mpeg_template = {
+ .name = "saa7164",
+ .fops = &mpeg_fops,
+ .ioctl_ops = &mpeg_ioctl_ops,
+ .minor = -1,
+ .tvnorms = SAA7164_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static struct video_device *saa7164_encoder_alloc(
+ struct saa7164_port *port,
+ struct pci_dev *pci,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+
+ *vfd = *template;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+ type, saa7164_boards[dev->board].name);
+
+ vfd->parent = &pci->dev;
+ vfd->release = video_device_release;
+ return vfd;
+}
+
+int saa7164_encoder_register(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int result = -ENODEV;
+
+ dprintk(DBGLVL_ENC, "%s()\n", __func__);
+
+ if (port->type != SAA7164_MPEG_ENCODER)
+ BUG();
+
+ /* Sanity check that the PCI configuration space is active */
+ if (port->hwcfg.BARLocation == 0) {
+ printk(KERN_ERR "%s() failed "
+ "(errno = %d), NO PCI configuration\n",
+ __func__, result);
+ result = -ENOMEM;
+ goto failed;
+ }
+
+ /* Establish encoder defaults here */
+ /* Set default TV standard */
+ port->encodernorm = saa7164_tvnorms[0];
+ port->width = 720;
+ port->mux_input = 1; /* Composite */
+ port->video_format = EU_VIDEO_FORMAT_MPEG_2;
+ port->audio_format = 0;
+ port->video_resolution = 0;
+ port->ctl_brightness = 127;
+ port->ctl_contrast = 66;
+ port->ctl_hue = 128;
+ port->ctl_saturation = 62;
+ port->ctl_sharpness = 8;
+ port->encoder_params.bitrate = ENCODER_DEF_BITRATE;
+ port->encoder_params.bitrate_peak = ENCODER_DEF_BITRATE;
+ port->encoder_params.bitrate_mode = V4L2_MPEG_VIDEO_BITRATE_MODE_CBR;
+ port->encoder_params.stream_type = V4L2_MPEG_STREAM_TYPE_MPEG2_PS;
+ port->encoder_params.ctl_mute = 0;
+ port->encoder_params.ctl_aspect = V4L2_MPEG_VIDEO_ASPECT_4x3;
+ port->encoder_params.refdist = 1;
+ port->encoder_params.gop_size = SAA7164_ENCODER_DEFAULT_GOP_SIZE;
+
+ if (port->encodernorm.id & V4L2_STD_525_60)
+ port->height = 480;
+ else
+ port->height = 576;
+
+ /* Allocate and register the video device node */
+ port->v4l_device = saa7164_encoder_alloc(port,
+ dev->pci, &saa7164_mpeg_template, "mpeg");
+
+ if (port->v4l_device == NULL) {
+ printk(KERN_INFO "%s: can't allocate mpeg device\n",
+ dev->name);
+ result = -ENOMEM;
+ goto failed;
+ }
+
+ video_set_drvdata(port->v4l_device, port);
+ result = video_register_device(port->v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (result < 0) {
+ printk(KERN_INFO "%s: can't register mpeg device\n",
+ dev->name);
+ /* TODO: We're going to leak here if we don't dealloc
+ The buffers above. The unreg function can't deal wit it.
+ */
+ goto failed;
+ }
+
+ printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
+ dev->name, port->v4l_device->num);
+
+ /* Configure the hardware defaults */
+ saa7164_api_set_videomux(port);
+ saa7164_api_set_usercontrol(port, PU_BRIGHTNESS_CONTROL);
+ saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+ saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+ saa7164_api_set_usercontrol(port, PU_SATURATION_CONTROL);
+ saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+ saa7164_api_audio_mute(port, 0);
+ saa7164_api_set_audio_volume(port, 20);
+ saa7164_api_set_aspect_ratio(port);
+
+ /* Disable audio standard detection, it's buggy */
+ saa7164_api_set_audio_detection(port, 0);
+
+ saa7164_api_set_encoder(port);
+ saa7164_api_get_encoder(port);
+
+ result = 0;
+failed:
+ return result;
+}
+
+void saa7164_encoder_unregister(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_ENC, "%s(port=%d)\n", __func__, port->nr);
+
+ if (port->type != SAA7164_MPEG_ENCODER)
+ BUG();
+
+ if (port->v4l_device) {
+ if (port->v4l_device->minor != -1)
+ video_unregister_device(port->v4l_device);
+ else
+ video_device_release(port->v4l_device);
+
+ port->v4l_device = NULL;
+ }
+
+ dprintk(DBGLVL_ENC, "%s(port=%d) done\n", __func__, port->nr);
+}
+
diff --git a/drivers/media/video/saa7164/saa7164-fw.c b/drivers/media/video/saa7164/saa7164-fw.c
index 270245d275ab..ebed6f786a23 100644
--- a/drivers/media/video/saa7164/saa7164-fw.c
+++ b/drivers/media/video/saa7164/saa7164-fw.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,11 +24,11 @@
#include "saa7164.h"
-#define SAA7164_REV2_FIRMWARE "v4l-saa7164-1.0.2.fw"
-#define SAA7164_REV2_FIRMWARE_SIZE 3978608
+#define SAA7164_REV2_FIRMWARE "NXP7164-2010-03-10.1.fw"
+#define SAA7164_REV2_FIRMWARE_SIZE 4019072
-#define SAA7164_REV3_FIRMWARE "v4l-saa7164-1.0.3.fw"
-#define SAA7164_REV3_FIRMWARE_SIZE 3978608
+#define SAA7164_REV3_FIRMWARE "NXP7164-2010-03-10.1.fw"
+#define SAA7164_REV3_FIRMWARE_SIZE 4019072
struct fw_header {
u32 firmwaresize;
@@ -178,7 +178,7 @@ int saa7164_downloadimage(struct saa7164_dev *dev, u8 *src, u32 srcsize,
goto out;
}
- msleep(10);
+ msleep(10); /* Checkpatch throws a < 20ms warning */
if (timeout++ > 60)
break;
}
@@ -235,7 +235,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
while (err_flags != SAA_DEVICE_IMAGE_BOOTING) {
dprintk(DBGLVL_FW, "%s() err_flags = %x\n",
__func__, err_flags);
- msleep(10);
+ msleep(10); /* Checkpatch throws a < 20ms warning */
if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) {
printk(KERN_ERR "%s() firmware corrupt\n",
@@ -294,7 +294,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
while (err_flags != SAA_DEVICE_IMAGE_BOOTING) {
dprintk(DBGLVL_FW, "%s() err_flags2 = %x\n",
__func__, err_flags);
- msleep(10);
+ msleep(10); /* Checkpatch throws a < 20ms warning */
if (err_flags & SAA_DEVICE_IMAGE_CORRUPT) {
printk(KERN_ERR
@@ -365,7 +365,7 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
first_timeout = SAA_DEVICE_TIMEOUT;
while (first_timeout) {
- msleep(10);
+ msleep(10); /* Checkpatch throws a < 20ms warning */
version =
saa7164_getcurrentfirmwareversion(dev);
@@ -604,11 +604,10 @@ int saa7164_downloadfirmware(struct saa7164_dev *dev)
}
}
+ dev->firmwareloaded = 1;
ret = 0;
out:
- if (fw)
- release_firmware(fw);
-
+ release_firmware(fw);
return ret;
}
diff --git a/drivers/media/video/saa7164/saa7164-i2c.c b/drivers/media/video/saa7164/saa7164-i2c.c
index e1ae9b01bf0f..26148f76cba2 100644
--- a/drivers/media/video/saa7164/saa7164-i2c.c
+++ b/drivers/media/video/saa7164/saa7164-i2c.c
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -23,7 +23,7 @@
#include <linux/moduleparam.h>
#include <linux/init.h>
#include <linux/delay.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include "saa7164.h"
@@ -65,7 +65,7 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg *msgs, int num)
}
return num;
- err:
+err:
return retval;
}
diff --git a/drivers/media/video/saa7164/saa7164-reg.h b/drivers/media/video/saa7164/saa7164-reg.h
index 06be4c13d5b1..2bbf81583d33 100644
--- a/drivers/media/video/saa7164/saa7164-reg.h
+++ b/drivers/media/video/saa7164/saa7164-reg.h
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -60,6 +60,7 @@
#define GET_STRING_CONTROL 0x03
#define GET_LANGUAGE_CONTROL 0x05
#define SET_POWER_CONTROL 0x07
+#define GET_FW_STATUS_CONTROL 0x08
#define GET_FW_VERSION_CONTROL 0x09
#define SET_DEBUG_LEVEL_CONTROL 0x0B
#define GET_DEBUG_DATA_CONTROL 0x0C
@@ -156,11 +157,63 @@
#define EXU_INTERRUPT_CONTROL 0x03
/* State Transition and args */
+#define SAA_PROBE_CONTROL 0x01
+#define SAA_COMMIT_CONTROL 0x02
#define SAA_STATE_CONTROL 0x03
#define SAA_DMASTATE_STOP 0x00
#define SAA_DMASTATE_ACQUIRE 0x01
#define SAA_DMASTATE_PAUSE 0x02
#define SAA_DMASTATE_RUN 0x03
-/* Hardware registers */
-
+/* A/V Mux Input Selector */
+#define SU_INPUT_SELECT_CONTROL 0x01
+
+/* Encoder Profiles */
+#define EU_PROFILE_PS_DVD 0x06
+#define EU_PROFILE_TS_HQ 0x09
+#define EU_VIDEO_FORMAT_MPEG_2 0x02
+
+/* Tuner */
+#define TU_AUDIO_MODE_CONTROL 0x17
+
+/* Video Formats */
+#define TU_STANDARD_CONTROL 0x00
+#define TU_STANDARD_AUTO_CONTROL 0x01
+#define TU_STANDARD_NONE 0x00
+#define TU_STANDARD_NTSC_M 0x01
+#define TU_STANDARD_PAL_I 0x08
+#define TU_STANDARD_MANUAL 0x00
+#define TU_STANDARD_AUTO 0x01
+
+/* Video Controls */
+#define PU_BRIGHTNESS_CONTROL 0x02
+#define PU_CONTRAST_CONTROL 0x03
+#define PU_HUE_CONTROL 0x06
+#define PU_SATURATION_CONTROL 0x07
+#define PU_SHARPNESS_CONTROL 0x08
+
+/* Audio Controls */
+#define MUTE_CONTROL 0x01
+#define VOLUME_CONTROL 0x02
+#define AUDIO_DEFAULT_CONTROL 0x0D
+
+/* Default Volume Levels */
+#define TMHW_LEV_ADJ_DECLEV_DEFAULT 0x00
+#define TMHW_LEV_ADJ_MONOLEV_DEFAULT 0x00
+#define TMHW_LEV_ADJ_NICLEV_DEFAULT 0x00
+#define TMHW_LEV_ADJ_SAPLEV_DEFAULT 0x00
+#define TMHW_LEV_ADJ_ADCLEV_DEFAULT 0x00
+
+/* Encoder Related Commands */
+#define EU_PROFILE_CONTROL 0x00
+#define EU_VIDEO_FORMAT_CONTROL 0x01
+#define EU_VIDEO_BIT_RATE_CONTROL 0x02
+#define EU_VIDEO_RESOLUTION_CONTROL 0x03
+#define EU_VIDEO_GOP_STRUCTURE_CONTROL 0x04
+#define EU_VIDEO_INPUT_ASPECT_CONTROL 0x0A
+#define EU_AUDIO_FORMAT_CONTROL 0x0C
+#define EU_AUDIO_BIT_RATE_CONTROL 0x0D
+
+/* Firmware Debugging */
+#define SET_DEBUG_LEVEL_CONTROL 0x0B
+#define GET_DEBUG_DATA_CONTROL 0x0C
diff --git a/drivers/media/video/saa7164/saa7164-types.h b/drivers/media/video/saa7164/saa7164-types.h
index 99093f23aae5..df1d2997fa6c 100644
--- a/drivers/media/video/saa7164/saa7164-types.h
+++ b/drivers/media/video/saa7164/saa7164-types.h
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -24,7 +24,7 @@
/* Some structues are passed directly to/from the firmware and
* have strict alignment requirements. This is one of them.
*/
-typedef struct {
+struct tmComResHWDescr {
u8 bLength;
u8 bDescriptorType;
u8 bDescriptorSubtype;
@@ -37,14 +37,14 @@ typedef struct {
u32 dwHostMemoryRegionSize;
u32 dwHostHibernatMemRegion;
u32 dwHostHibernatMemRegionSize;
-} __attribute__((packed)) tmComResHWDescr_t;
+} __attribute__((packed));
/* This is DWORD aligned on windows but I can't find the right
* gcc syntax to match the binary data from the device.
* I've manually padded with Reserved[3] bytes to match the hardware,
* but this could break if GCC decies to pack in a different way.
*/
-typedef struct {
+struct tmComResInterfaceDescr {
u8 bLength;
u8 bDescriptorType;
u8 bDescriptorSubtype;
@@ -56,52 +56,52 @@ typedef struct {
u8 bDebugInterruptId;
u8 BARLocation;
u8 Reserved[3];
-} tmComResInterfaceDescr_t;
+};
-typedef struct {
+struct tmComResBusDescr {
u64 CommandRing;
u64 ResponseRing;
u32 CommandWrite;
u32 CommandRead;
u32 ResponseWrite;
u32 ResponseRead;
-} tmComResBusDescr_t;
+};
-typedef enum {
+enum tmBusType {
NONE = 0,
TYPE_BUS_PCI = 1,
TYPE_BUS_PCIe = 2,
TYPE_BUS_USB = 3,
TYPE_BUS_I2C = 4
-} tmBusType_t;
+};
-typedef struct {
- tmBusType_t Type;
+struct tmComResBusInfo {
+ enum tmBusType Type;
u16 m_wMaxReqSize;
u8 *m_pdwSetRing;
u32 m_dwSizeSetRing;
u8 *m_pdwGetRing;
u32 m_dwSizeGetRing;
- u32 *m_pdwSetWritePos;
- u32 *m_pdwSetReadPos;
- u32 *m_pdwGetWritePos;
- u32 *m_pdwGetReadPos;
+ u32 m_dwSetWritePos;
+ u32 m_dwSetReadPos;
+ u32 m_dwGetWritePos;
+ u32 m_dwGetReadPos;
/* All access is protected */
struct mutex lock;
-} tmComResBusInfo_t;
+};
-typedef struct {
+struct tmComResInfo {
u8 id;
u8 flags;
u16 size;
u32 command;
u16 controlselector;
u8 seqno;
-} __attribute__((packed)) tmComResInfo_t;
+} __attribute__((packed));
-typedef enum {
+enum tmComResCmd {
SET_CUR = 0x01,
GET_CUR = 0x81,
GET_MIN = 0x82,
@@ -110,7 +110,7 @@ typedef enum {
GET_LEN = 0x85,
GET_INFO = 0x86,
GET_DEF = 0x87
-} tmComResCmd_t;
+};
struct cmd {
u8 seqno;
@@ -121,20 +121,20 @@ struct cmd {
wait_queue_head_t wait;
};
-typedef struct {
+struct tmDescriptor {
u32 pathid;
u32 size;
void *descriptor;
-} tmDescriptor_t;
+};
-typedef struct {
+struct tmComResDescrHeader {
u8 len;
u8 type;
u8 subtype;
u8 unitid;
-} __attribute__((packed)) tmComResDescrHeader_t;
+} __attribute__((packed));
-typedef struct {
+struct tmComResExtDevDescrHeader {
u8 len;
u8 type;
u8 subtype;
@@ -144,22 +144,22 @@ typedef struct {
u32 numgpiopins;
u8 numgpiogroups;
u8 controlsize;
-} __attribute__((packed)) tmComResExtDevDescrHeader_t;
+} __attribute__((packed));
-typedef struct {
+struct tmComResGPIO {
u32 pin;
u8 state;
-} __attribute__((packed)) tmComResGPIO_t;
+} __attribute__((packed));
-typedef struct {
+struct tmComResPathDescrHeader {
u8 len;
u8 type;
u8 subtype;
u8 pathid;
-} __attribute__((packed)) tmComResPathDescrHeader_t;
+} __attribute__((packed));
/* terminaltype */
-typedef enum {
+enum tmComResTermType {
ITT_ANTENNA = 0x0203,
LINE_CONNECTOR = 0x0603,
SPDIF_CONNECTOR = 0x0605,
@@ -167,9 +167,9 @@ typedef enum {
SVIDEO_CONNECTOR = 0x0402,
COMPONENT_CONNECTOR = 0x0403,
STANDARD_DMA = 0xF101
-} tmComResTermType_t;
+};
-typedef struct {
+struct tmComResAntTermDescrHeader {
u8 len;
u8 type;
u8 subtype;
@@ -178,9 +178,9 @@ typedef struct {
u8 assocterminal;
u8 iterminal;
u8 controlsize;
-} __attribute__((packed)) tmComResAntTermDescrHeader_t;
+} __attribute__((packed));
-typedef struct {
+struct tmComResTunerDescrHeader {
u8 len;
u8 type;
u8 subtype;
@@ -190,9 +190,9 @@ typedef struct {
u32 tuningstandards;
u8 controlsize;
u32 controls;
-} __attribute__((packed)) tmComResTunerDescrHeader_t;
+} __attribute__((packed));
-typedef enum {
+enum tmBufferFlag {
/* the buffer does not contain any valid data */
TM_BUFFER_FLAG_EMPTY,
@@ -201,23 +201,23 @@ typedef enum {
/* the buffer is the dummy buffer - TODO??? */
TM_BUFFER_FLAG_DUMMY_BUFFER
-} tmBufferFlag_t;
+};
-typedef struct {
+struct tmBuffer {
u64 *pagetablevirt;
u64 pagetablephys;
u16 offset;
u8 *context;
u64 timestamp;
- tmBufferFlag_t BufferFlag_t;
+ enum tmBufferFlag BufferFlag;
u32 lostbuffers;
u32 validbuffers;
u64 *dummypagevirt;
u64 dummypagephys;
u64 *addressvirt;
-} tmBuffer_t;
+};
-typedef struct {
+struct tmHWStreamParameters {
u32 bitspersample;
u32 samplesperline;
u32 numberoflines;
@@ -227,15 +227,15 @@ typedef struct {
u64 *pagetablelistphys;
u32 numpagetables;
u32 numpagetableentries;
-} tmHWStreamParameters_t;
+};
-typedef struct {
- tmHWStreamParameters_t HWStreamParameters_t;
+struct tmStreamParameters {
+ struct tmHWStreamParameters HWStreamParameters;
u64 qwDummyPageTablePhys;
u64 *pDummyPageTableVirt;
-} tmStreamParameters_t;
+};
-typedef struct {
+struct tmComResDMATermDescrHeader {
u8 len;
u8 type;
u8 subtyle;
@@ -251,7 +251,7 @@ typedef struct {
u8 metadatasize;
u8 numformats;
u8 controlsize;
-} __attribute__((packed)) tmComResDMATermDescrHeader_t;
+} __attribute__((packed));
/*
*
@@ -274,7 +274,7 @@ typedef struct {
* Data is to be ignored by the application.
*
*/
-typedef struct {
+struct tmComResTSFormatDescrHeader {
u8 len;
u8 type;
u8 subtype;
@@ -283,5 +283,160 @@ typedef struct {
u8 bPacketLength;
u8 bStrideLength;
u8 guidStrideFormat[16];
-} __attribute__((packed)) tmComResTSFormatDescrHeader_t;
+} __attribute__((packed));
+
+/* Encoder related structures */
+
+/* A/V Mux Selector */
+struct tmComResSelDescrHeader {
+ u8 len;
+ u8 type;
+ u8 subtype;
+ u8 unitid;
+ u8 nrinpins;
+ u8 sourceid;
+} __attribute__((packed));
+
+/* A/V Audio processor definitions */
+struct tmComResProcDescrHeader {
+ u8 len;
+ u8 type;
+ u8 subtype;
+ u8 unitid;
+ u8 sourceid;
+ u16 wreserved;
+ u8 controlsize;
+} __attribute__((packed));
+
+/* Video bitrate control message */
+#define EU_VIDEO_BIT_RATE_MODE_CONSTANT (0)
+#define EU_VIDEO_BIT_RATE_MODE_VARIABLE_AVERAGE (1)
+#define EU_VIDEO_BIT_RATE_MODE_VARIABLE_PEAK (2)
+struct tmComResEncVideoBitRate {
+ u8 ucVideoBitRateMode;
+ u32 dwVideoBitRate;
+ u32 dwVideoBitRatePeak;
+} __attribute__((packed));
+
+/* Video Encoder Aspect Ratio message */
+struct tmComResEncVideoInputAspectRatio {
+ u8 width;
+ u8 height;
+} __attribute__((packed));
+
+/* Video Encoder GOP IBP message */
+/* 1. IPPPPPPPPPPPPPP */
+/* 2. IBPBPBPBPBPBPBP */
+/* 3. IBBPBBPBBPBBP */
+#define SAA7164_ENCODER_DEFAULT_GOP_DIST (1)
+#define SAA7164_ENCODER_DEFAULT_GOP_SIZE (15)
+struct tmComResEncVideoGopStructure {
+ u8 ucGOPSize; /* GOP Size 12, 15 */
+ u8 ucRefFrameDist; /* Reference Frame Distance */
+} __attribute__((packed));
+
+/* Encoder processor definition */
+struct tmComResEncoderDescrHeader {
+ u8 len;
+ u8 type;
+ u8 subtype;
+ u8 unitid;
+ u8 vsourceid;
+ u8 asourceid;
+ u8 iunit;
+ u32 dwmControlCap;
+ u32 dwmProfileCap;
+ u32 dwmVidFormatCap;
+ u8 bmVidBitrateCap;
+ u16 wmVidResolutionsCap;
+ u16 wmVidFrmRateCap;
+ u32 dwmAudFormatCap;
+ u8 bmAudBitrateCap;
+} __attribute__((packed));
+
+/* Audio processor definition */
+struct tmComResAFeatureDescrHeader {
+ u8 len;
+ u8 type;
+ u8 subtype;
+ u8 unitid;
+ u8 sourceid;
+ u8 controlsize;
+} __attribute__((packed));
+
+/* Audio control messages */
+struct tmComResAudioDefaults {
+ u8 ucDecoderLevel;
+ u8 ucDecoderFM_Level;
+ u8 ucMonoLevel;
+ u8 ucNICAM_Level;
+ u8 ucSAP_Level;
+ u8 ucADC_Level;
+} __attribute__((packed));
+
+/* Audio bitrate control message */
+struct tmComResEncAudioBitRate {
+ u8 ucAudioBitRateMode;
+ u32 dwAudioBitRate;
+ u32 dwAudioBitRatePeak;
+} __attribute__((packed));
+
+/* Tuner / AV Decoder messages */
+struct tmComResTunerStandard {
+ u8 std;
+ u32 country;
+} __attribute__((packed));
+
+struct tmComResTunerStandardAuto {
+ u8 mode;
+} __attribute__((packed));
+
+/* EEPROM definition for PS stream types */
+struct tmComResPSFormatDescrHeader {
+ u8 len;
+ u8 type;
+ u8 subtype;
+ u8 bFormatIndex;
+ u16 wPacketLength;
+ u16 wPackLength;
+ u8 bPackDataType;
+} __attribute__((packed));
+
+/* VBI control structure */
+struct tmComResVBIFormatDescrHeader {
+ u8 len;
+ u8 type;
+ u8 subtype; /* VS_FORMAT_VBI */
+ u8 bFormatIndex;
+ u32 VideoStandard; /* See KS_AnalogVideoStandard, NTSC = 1 */
+ u8 StartLine; /* NTSC Start = 10 */
+ u8 EndLine; /* NTSC = 21 */
+ u8 FieldRate; /* 60 for NTSC */
+ u8 bNumLines; /* Unsed - scheduled for removal */
+} __attribute__((packed));
+
+struct tmComResProbeCommit {
+ u16 bmHint;
+ u8 bFormatIndex;
+ u8 bFrameIndex;
+} __attribute__((packed));
+
+struct tmComResDebugSetLevel {
+ u32 dwDebugLevel;
+} __attribute__((packed));
+
+struct tmComResDebugGetData {
+ u32 dwResult;
+ u8 ucDebugData[256];
+} __attribute__((packed));
+struct tmFwInfoStruct {
+ u32 status;
+ u32 mode;
+ u32 devicespec;
+ u32 deviceinst;
+ u32 CPULoad;
+ u32 RemainHeap;
+ u32 CPUClock;
+ u32 RAMSpeed;
+} __attribute__((packed));
diff --git a/drivers/media/video/saa7164/saa7164-vbi.c b/drivers/media/video/saa7164/saa7164-vbi.c
new file mode 100644
index 000000000000..8abbe6d661e4
--- /dev/null
+++ b/drivers/media/video/saa7164/saa7164-vbi.c
@@ -0,0 +1,1384 @@
+/*
+ * Driver for the NXP SAA7164 PCIe bridge
+ *
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "saa7164.h"
+
+static struct saa7164_tvnorm saa7164_tvnorms[] = {
+ {
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
+ }, {
+ .name = "NTSC-JP",
+ .id = V4L2_STD_NTSC_M_JP,
+ }
+};
+
+static const u32 saa7164_v4l2_ctrls[] = {
+ 0
+};
+
+/* Take the encoder configuration from the port struct and
+ * flush it to the hardware.
+ */
+static void saa7164_vbi_configure(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+ port->vbi_params.width = port->width;
+ port->vbi_params.height = port->height;
+ port->vbi_params.is_50hz =
+ (port->encodernorm.id & V4L2_STD_625_50) != 0;
+
+ /* Set up the DIF (enable it) for analog mode by default */
+ saa7164_api_initialize_dif(port);
+
+ /* Configure the correct video standard */
+#if 0
+ saa7164_api_configure_dif(port, port->encodernorm.id);
+#endif
+
+#if 0
+ /* Ensure the audio decoder is correct configured */
+ saa7164_api_set_audio_std(port);
+#endif
+ dprintk(DBGLVL_VBI, "%s() ends\n", __func__);
+}
+
+static int saa7164_vbi_buffers_dealloc(struct saa7164_port *port)
+{
+ struct list_head *c, *n, *p, *q, *l, *v;
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct saa7164_user_buffer *ubuf;
+
+ /* Remove any allocated buffers */
+ mutex_lock(&port->dmaqueue_lock);
+
+ dprintk(DBGLVL_VBI, "%s(port=%d) dmaqueue\n", __func__, port->nr);
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+ buf = list_entry(c, struct saa7164_buffer, list);
+ list_del(c);
+ saa7164_buffer_dealloc(buf);
+ }
+
+ dprintk(DBGLVL_VBI, "%s(port=%d) used\n", __func__, port->nr);
+ list_for_each_safe(p, q, &port->list_buf_used.list) {
+ ubuf = list_entry(p, struct saa7164_user_buffer, list);
+ list_del(p);
+ saa7164_buffer_dealloc_user(ubuf);
+ }
+
+ dprintk(DBGLVL_VBI, "%s(port=%d) free\n", __func__, port->nr);
+ list_for_each_safe(l, v, &port->list_buf_free.list) {
+ ubuf = list_entry(l, struct saa7164_user_buffer, list);
+ list_del(l);
+ saa7164_buffer_dealloc_user(ubuf);
+ }
+
+ mutex_unlock(&port->dmaqueue_lock);
+ dprintk(DBGLVL_VBI, "%s(port=%d) done\n", __func__, port->nr);
+
+ return 0;
+}
+
+/* Dynamic buffer switch at vbi start time */
+static int saa7164_vbi_buffers_alloc(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct saa7164_user_buffer *ubuf;
+ struct tmHWStreamParameters *params = &port->hw_streamingparams;
+ int result = -ENODEV, i;
+ int len = 0;
+
+ dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+ /* TODO: NTSC SPECIFIC */
+ /* Init and establish defaults */
+ params->samplesperline = 1440;
+ params->numberoflines = 12;
+ params->numberoflines = 18;
+ params->pitch = 1600;
+ params->pitch = 1440;
+ params->numpagetables = 2 +
+ ((params->numberoflines * params->pitch) / PAGE_SIZE);
+ params->bitspersample = 8;
+ params->linethreshold = 0;
+ params->pagetablelistvirt = 0;
+ params->pagetablelistphys = 0;
+ params->numpagetableentries = port->hwcfg.buffercount;
+
+ /* Allocate the PCI resources, buffers (hard) */
+ for (i = 0; i < port->hwcfg.buffercount; i++) {
+ buf = saa7164_buffer_alloc(port,
+ params->numberoflines *
+ params->pitch);
+
+ if (!buf) {
+ printk(KERN_ERR "%s() failed "
+ "(errno = %d), unable to allocate buffer\n",
+ __func__, result);
+ result = -ENOMEM;
+ goto failed;
+ } else {
+
+ mutex_lock(&port->dmaqueue_lock);
+ list_add_tail(&buf->list, &port->dmaqueue.list);
+ mutex_unlock(&port->dmaqueue_lock);
+
+ }
+ }
+
+ /* Allocate some kenrel kernel buffers for copying
+ * to userpsace.
+ */
+ len = params->numberoflines * params->pitch;
+
+ if (vbi_buffers < 16)
+ vbi_buffers = 16;
+ if (vbi_buffers > 512)
+ vbi_buffers = 512;
+
+ for (i = 0; i < vbi_buffers; i++) {
+
+ ubuf = saa7164_buffer_alloc_user(dev, len);
+ if (ubuf) {
+ mutex_lock(&port->dmaqueue_lock);
+ list_add_tail(&ubuf->list, &port->list_buf_free.list);
+ mutex_unlock(&port->dmaqueue_lock);
+ }
+
+ }
+
+ result = 0;
+
+failed:
+ return result;
+}
+
+
+static int saa7164_vbi_initialize(struct saa7164_port *port)
+{
+ saa7164_vbi_configure(port);
+ return 0;
+}
+
+/* -- V4L2 --------------------------------------------------------- */
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+ unsigned int i;
+
+ dprintk(DBGLVL_VBI, "%s(id=0x%x)\n", __func__, (u32)*id);
+
+ for (i = 0; i < ARRAY_SIZE(saa7164_tvnorms); i++) {
+ if (*id & saa7164_tvnorms[i].id)
+ break;
+ }
+ if (i == ARRAY_SIZE(saa7164_tvnorms))
+ return -EINVAL;
+
+ port->encodernorm = saa7164_tvnorms[i];
+
+ /* Update the audio decoder while is not running in
+ * auto detect mode.
+ */
+ saa7164_api_set_audio_std(port);
+
+ dprintk(DBGLVL_VBI, "%s(id=0x%x) OK\n", __func__, (u32)*id);
+
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *priv,
+ struct v4l2_input *i)
+{
+ int n;
+
+ char *inputs[] = { "tuner", "composite", "svideo", "aux",
+ "composite 2", "svideo 2", "aux 2" };
+
+ if (i->index >= 7)
+ return -EINVAL;
+
+ strcpy(i->name, inputs[i->index]);
+
+ if (i->index == 0)
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ for (n = 0; n < ARRAY_SIZE(saa7164_tvnorms); n++)
+ i->std |= saa7164_tvnorms[n].id;
+
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ if (saa7164_api_get_videomux(port) != SAA_OK)
+ return -EIO;
+
+ *i = (port->mux_input - 1);
+
+ dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, *i);
+
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_VBI, "%s() input=%d\n", __func__, i);
+
+ if (i >= 7)
+ return -EINVAL;
+
+ port->mux_input = i + 1;
+
+ if (saa7164_api_set_videomux(port) != SAA_OK)
+ return -EIO;
+
+ return 0;
+}
+
+static int vidioc_g_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ if (0 != t->index)
+ return -EINVAL;
+
+ strcpy(t->name, "tuner");
+ t->type = V4L2_TUNER_ANALOG_TV;
+ t->capability = V4L2_TUNER_CAP_NORM | V4L2_TUNER_CAP_STEREO;
+
+ dprintk(DBGLVL_VBI, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+ return 0;
+}
+
+static int vidioc_s_tuner(struct file *file, void *priv,
+ struct v4l2_tuner *t)
+{
+ /* Update the A/V core */
+ return 0;
+}
+
+static int vidioc_g_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = port->freq;
+
+ return 0;
+}
+
+static int vidioc_s_frequency(struct file *file, void *priv,
+ struct v4l2_frequency *f)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_port *tsport;
+ struct dvb_frontend *fe;
+
+ /* TODO: Pull this for the std */
+ struct analog_parameters params = {
+ .mode = V4L2_TUNER_ANALOG_TV,
+ .audmode = V4L2_TUNER_MODE_STEREO,
+ .std = port->encodernorm.id,
+ .frequency = f->frequency
+ };
+
+ /* Stop the encoder */
+ dprintk(DBGLVL_VBI, "%s() frequency=%d tuner=%d\n", __func__,
+ f->frequency, f->tuner);
+
+ if (f->tuner != 0)
+ return -EINVAL;
+
+ if (f->type != V4L2_TUNER_ANALOG_TV)
+ return -EINVAL;
+
+ port->freq = f->frequency;
+
+ /* Update the hardware */
+ if (port->nr == SAA7164_PORT_VBI1)
+ tsport = &dev->ports[SAA7164_PORT_TS1];
+ else
+ if (port->nr == SAA7164_PORT_VBI2)
+ tsport = &dev->ports[SAA7164_PORT_TS2];
+ else
+ BUG();
+
+ fe = tsport->dvb.frontend;
+
+ if (fe && fe->ops.tuner_ops.set_analog_params)
+ fe->ops.tuner_ops.set_analog_params(fe, &params);
+ else
+ printk(KERN_ERR "%s() No analog tuner, aborting\n", __func__);
+
+ saa7164_vbi_initialize(port);
+
+ return 0;
+}
+
+static int vidioc_g_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__,
+ ctl->id, ctl->value);
+
+ switch (ctl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctl->value = port->ctl_brightness;
+ break;
+ case V4L2_CID_CONTRAST:
+ ctl->value = port->ctl_contrast;
+ break;
+ case V4L2_CID_SATURATION:
+ ctl->value = port->ctl_saturation;
+ break;
+ case V4L2_CID_HUE:
+ ctl->value = port->ctl_hue;
+ break;
+ case V4L2_CID_SHARPNESS:
+ ctl->value = port->ctl_sharpness;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ ctl->value = port->ctl_volume;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int vidioc_s_ctrl(struct file *file, void *priv,
+ struct v4l2_control *ctl)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+ int ret = 0;
+
+ dprintk(DBGLVL_VBI, "%s(id=%d, value=%d)\n", __func__,
+ ctl->id, ctl->value);
+
+ switch (ctl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_brightness = ctl->value;
+ saa7164_api_set_usercontrol(port,
+ PU_BRIGHTNESS_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_CONTRAST:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_contrast = ctl->value;
+ saa7164_api_set_usercontrol(port, PU_CONTRAST_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_SATURATION:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_saturation = ctl->value;
+ saa7164_api_set_usercontrol(port,
+ PU_SATURATION_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_HUE:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_hue = ctl->value;
+ saa7164_api_set_usercontrol(port, PU_HUE_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_SHARPNESS:
+ if ((ctl->value >= 0) && (ctl->value <= 255)) {
+ port->ctl_sharpness = ctl->value;
+ saa7164_api_set_usercontrol(port, PU_SHARPNESS_CONTROL);
+ } else
+ ret = -EINVAL;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ if ((ctl->value >= -83) && (ctl->value <= 24)) {
+ port->ctl_volume = ctl->value;
+ saa7164_api_set_audio_volume(port, port->ctl_volume);
+ } else
+ ret = -EINVAL;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int saa7164_get_ctrl(struct saa7164_port *port,
+ struct v4l2_ext_control *ctrl)
+{
+ struct saa7164_vbi_params *params = &port->vbi_params;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ ctrl->value = params->stream_type;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ ctrl->value = params->ctl_mute;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ ctrl->value = params->ctl_aspect;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ ctrl->value = params->refdist;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ ctrl->value = params->gop_size;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int vidioc_g_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = saa7164_get_ctrl(port, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+
+ }
+
+ return -EINVAL;
+}
+
+static int saa7164_try_ctrl(struct v4l2_ext_control *ctrl, int ac3)
+{
+ int ret = -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ if ((ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_PS) ||
+ (ctrl->value == V4L2_MPEG_STREAM_TYPE_MPEG2_TS))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ if ((ctrl->value >= 0) &&
+ (ctrl->value <= 1))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ if ((ctrl->value >= V4L2_MPEG_VIDEO_ASPECT_1x1) &&
+ (ctrl->value <= V4L2_MPEG_VIDEO_ASPECT_221x100))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ if ((ctrl->value >= 0) &&
+ (ctrl->value <= 255))
+ ret = 0;
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ if ((ctrl->value >= 1) &&
+ (ctrl->value <= 3))
+ ret = 0;
+ break;
+ default:
+ ret = -EINVAL;
+ }
+
+ return ret;
+}
+
+static int vidioc_try_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = saa7164_try_ctrl(ctrl, 0);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+ }
+
+ return -EINVAL;
+}
+
+static int saa7164_set_ctrl(struct saa7164_port *port,
+ struct v4l2_ext_control *ctrl)
+{
+ struct saa7164_vbi_params *params = &port->vbi_params;
+ int ret = 0;
+
+ switch (ctrl->id) {
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ params->stream_type = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ params->ctl_mute = ctrl->value;
+ ret = saa7164_api_audio_mute(port, params->ctl_mute);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+ ret);
+ ret = -EIO;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ params->ctl_aspect = ctrl->value;
+ ret = saa7164_api_set_aspect_ratio(port);
+ if (ret != SAA_OK) {
+ printk(KERN_ERR "%s() error, ret = 0x%x\n", __func__,
+ ret);
+ ret = -EIO;
+ }
+ break;
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ params->refdist = ctrl->value;
+ break;
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ params->gop_size = ctrl->value;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* TODO: Update the hardware */
+
+ return ret;
+}
+
+static int vidioc_s_ext_ctrls(struct file *file, void *priv,
+ struct v4l2_ext_controls *ctrls)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ int i, err = 0;
+
+ if (ctrls->ctrl_class == V4L2_CTRL_CLASS_MPEG) {
+ for (i = 0; i < ctrls->count; i++) {
+ struct v4l2_ext_control *ctrl = ctrls->controls + i;
+
+ err = saa7164_try_ctrl(ctrl, 0);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ err = saa7164_set_ctrl(port, ctrl);
+ if (err) {
+ ctrls->error_idx = i;
+ break;
+ }
+ }
+ return err;
+
+ }
+
+ return -EINVAL;
+}
+
+static int vidioc_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ strcpy(cap->driver, dev->name);
+ strlcpy(cap->card, saa7164_boards[dev->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+
+ cap->capabilities =
+ V4L2_CAP_VBI_CAPTURE |
+ V4L2_CAP_READWRITE |
+ 0;
+
+ cap->capabilities |= V4L2_CAP_TUNER;
+ cap->version = 0;
+
+ return 0;
+}
+
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index != 0)
+ return -EINVAL;
+
+ strlcpy(f->description, "VBI", sizeof(f->description));
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+
+ return 0;
+}
+
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ port->ts_packet_size * port->ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = port->width;
+ f->fmt.pix.height = port->height;
+
+ dprintk(DBGLVL_VBI, "VIDIOC_G_FMT: w: %d, h: %d\n",
+ port->width, port->height);
+
+ return 0;
+}
+
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ port->ts_packet_size * port->ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(DBGLVL_VBI, "VIDIOC_TRY_FMT: w: %d, h: %d\n",
+ port->width, port->height);
+ return 0;
+}
+
+static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ port->ts_packet_size * port->ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+
+ dprintk(DBGLVL_VBI, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+
+ return 0;
+}
+
+static int vidioc_log_status(struct file *file, void *priv)
+{
+ return 0;
+}
+
+static int fill_queryctrl(struct saa7164_vbi_params *params,
+ struct v4l2_queryctrl *c)
+{
+ switch (c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 127);
+ case V4L2_CID_CONTRAST:
+ return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 66);
+ case V4L2_CID_SATURATION:
+ return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 62);
+ case V4L2_CID_HUE:
+ return v4l2_ctrl_query_fill(c, 0x0, 0xff, 1, 128);
+ case V4L2_CID_SHARPNESS:
+ return v4l2_ctrl_query_fill(c, 0x0, 0x0f, 1, 8);
+ case V4L2_CID_MPEG_AUDIO_MUTE:
+ return v4l2_ctrl_query_fill(c, 0x0, 0x01, 1, 0);
+ case V4L2_CID_AUDIO_VOLUME:
+ return v4l2_ctrl_query_fill(c, -83, 24, 1, 20);
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ return v4l2_ctrl_query_fill(c,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_PS,
+ V4L2_MPEG_STREAM_TYPE_MPEG2_TS,
+ 1, V4L2_MPEG_STREAM_TYPE_MPEG2_PS);
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return v4l2_ctrl_query_fill(c,
+ V4L2_MPEG_VIDEO_ASPECT_1x1,
+ V4L2_MPEG_VIDEO_ASPECT_221x100,
+ 1, V4L2_MPEG_VIDEO_ASPECT_4x3);
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE:
+ return v4l2_ctrl_query_fill(c, 1, 255, 1, 15);
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ return v4l2_ctrl_query_fill(c,
+ 1, 3, 1, 1);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int vidioc_queryctrl(struct file *file, void *priv,
+ struct v4l2_queryctrl *c)
+{
+ struct saa7164_vbi_fh *fh = priv;
+ struct saa7164_port *port = fh->port;
+ int i, next;
+ u32 id = c->id;
+
+ memset(c, 0, sizeof(*c));
+
+ next = !!(id & V4L2_CTRL_FLAG_NEXT_CTRL);
+ c->id = id & ~V4L2_CTRL_FLAG_NEXT_CTRL;
+
+ for (i = 0; i < ARRAY_SIZE(saa7164_v4l2_ctrls); i++) {
+ if (next) {
+ if (c->id < saa7164_v4l2_ctrls[i])
+ c->id = saa7164_v4l2_ctrls[i];
+ else
+ continue;
+ }
+
+ if (c->id == saa7164_v4l2_ctrls[i])
+ return fill_queryctrl(&port->vbi_params, c);
+
+ if (c->id < saa7164_v4l2_ctrls[i])
+ break;
+ }
+
+ return -EINVAL;
+}
+
+static int saa7164_vbi_stop_port(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+
+ ret = saa7164_api_transition_port(port, SAA_DMASTATE_STOP);
+ if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() stop transition failed, ret = 0x%x\n",
+ __func__, ret);
+ ret = -EIO;
+ } else {
+ dprintk(DBGLVL_VBI, "%s() Stopped\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int saa7164_vbi_acquire_port(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+
+ ret = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+ if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() acquire transition failed, ret = 0x%x\n",
+ __func__, ret);
+ ret = -EIO;
+ } else {
+ dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+static int saa7164_vbi_pause_port(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int ret;
+
+ ret = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+ if ((ret != SAA_OK) && (ret != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() pause transition failed, ret = 0x%x\n",
+ __func__, ret);
+ ret = -EIO;
+ } else {
+ dprintk(DBGLVL_VBI, "%s() Paused\n", __func__);
+ ret = 0;
+ }
+
+ return ret;
+}
+
+/* Firmware is very windows centric, meaning you have to transition
+ * the part through AVStream / KS Windows stages, forwards or backwards.
+ * States are: stopped, acquired (h/w), paused, started.
+ * We have to leave here will all of the soft buffers on the free list,
+ * else the cfg_post() func won't have soft buffers to correctly configure.
+ */
+static int saa7164_vbi_stop_streaming(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ struct saa7164_buffer *buf;
+ struct saa7164_user_buffer *ubuf;
+ struct list_head *c, *n;
+ int ret;
+
+ dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+ ret = saa7164_vbi_pause_port(port);
+ ret = saa7164_vbi_acquire_port(port);
+ ret = saa7164_vbi_stop_port(port);
+
+ dprintk(DBGLVL_VBI, "%s(port=%d) Hardware stopped\n", __func__,
+ port->nr);
+
+ /* Reset the state of any allocated buffer resources */
+ mutex_lock(&port->dmaqueue_lock);
+
+ /* Reset the hard and soft buffer state */
+ list_for_each_safe(c, n, &port->dmaqueue.list) {
+ buf = list_entry(c, struct saa7164_buffer, list);
+ buf->flags = SAA7164_BUFFER_FREE;
+ buf->pos = 0;
+ }
+
+ list_for_each_safe(c, n, &port->list_buf_used.list) {
+ ubuf = list_entry(c, struct saa7164_user_buffer, list);
+ ubuf->pos = 0;
+ list_move_tail(&ubuf->list, &port->list_buf_free.list);
+ }
+
+ mutex_unlock(&port->dmaqueue_lock);
+
+ /* Free any allocated resources */
+ saa7164_vbi_buffers_dealloc(port);
+
+ dprintk(DBGLVL_VBI, "%s(port=%d) Released\n", __func__, port->nr);
+
+ return ret;
+}
+
+static int saa7164_vbi_start_streaming(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int result, ret = 0;
+
+ dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+ port->done_first_interrupt = 0;
+
+ /* allocate all of the PCIe DMA buffer resources on the fly,
+ * allowing switching between TS and PS payloads without
+ * requiring a complete driver reload.
+ */
+ saa7164_vbi_buffers_alloc(port);
+
+ /* Configure the encoder with any cache values */
+#if 0
+ saa7164_api_set_encoder(port);
+ saa7164_api_get_encoder(port);
+#endif
+
+ /* Place the empty buffers on the hardware */
+ saa7164_buffer_cfg_port(port);
+
+ /* Negotiate format */
+ if (saa7164_api_set_vbi_format(port) != SAA_OK) {
+ printk(KERN_ERR "%s() No supported VBI format\n", __func__);
+ ret = -EIO;
+ goto out;
+ }
+
+ /* Acquire the hardware */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_ACQUIRE);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() acquire transition failed, res = 0x%x\n",
+ __func__, result);
+
+ ret = -EIO;
+ goto out;
+ } else
+ dprintk(DBGLVL_VBI, "%s() Acquired\n", __func__);
+
+ /* Pause the hardware */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_PAUSE);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() pause transition failed, res = 0x%x\n",
+ __func__, result);
+
+ /* Stop the hardware, regardless */
+ result = saa7164_vbi_stop_port(port);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() pause/forced stop transition "
+ "failed, res = 0x%x\n", __func__, result);
+ }
+
+ ret = -EIO;
+ goto out;
+ } else
+ dprintk(DBGLVL_VBI, "%s() Paused\n", __func__);
+
+ /* Start the hardware */
+ result = saa7164_api_transition_port(port, SAA_DMASTATE_RUN);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() run transition failed, result = 0x%x\n",
+ __func__, result);
+
+ /* Stop the hardware, regardless */
+ result = saa7164_vbi_acquire_port(port);
+ result = saa7164_vbi_stop_port(port);
+ if ((result != SAA_OK) && (result != SAA_ERR_ALREADY_STOPPED)) {
+ printk(KERN_ERR "%s() run/forced stop transition "
+ "failed, res = 0x%x\n", __func__, result);
+ }
+
+ ret = -EIO;
+ } else
+ dprintk(DBGLVL_VBI, "%s() Running\n", __func__);
+
+out:
+ return ret;
+}
+
+int saa7164_vbi_fmt(struct file *file, void *priv, struct v4l2_format *f)
+{
+ /* ntsc */
+ f->fmt.vbi.samples_per_line = 1600;
+ f->fmt.vbi.samples_per_line = 1440;
+ f->fmt.vbi.sampling_rate = 27000000;
+ f->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
+ f->fmt.vbi.offset = 0;
+ f->fmt.vbi.flags = 0;
+ f->fmt.vbi.start[0] = 10;
+ f->fmt.vbi.count[0] = 18;
+ f->fmt.vbi.start[1] = 263 + 10 + 1;
+ f->fmt.vbi.count[1] = 18;
+ return 0;
+}
+
+static int fops_open(struct file *file)
+{
+ struct saa7164_dev *dev;
+ struct saa7164_port *port;
+ struct saa7164_vbi_fh *fh;
+
+ port = (struct saa7164_port *)video_get_drvdata(video_devdata(file));
+ if (!port)
+ return -ENODEV;
+
+ dev = port->dev;
+
+ dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+
+ file->private_data = fh;
+ fh->port = port;
+
+ return 0;
+}
+
+static int fops_release(struct file *file)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+ /* Shut device down on last close */
+ if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+ if (atomic_dec_return(&port->v4l_reader_count) == 0) {
+ /* stop vbi capture then cancel buffers */
+ saa7164_vbi_stop_streaming(port);
+ }
+ }
+
+ file->private_data = NULL;
+ kfree(fh);
+
+ return 0;
+}
+
+struct saa7164_user_buffer *saa7164_vbi_next_buf(struct saa7164_port *port)
+{
+ struct saa7164_user_buffer *ubuf = 0;
+ struct saa7164_dev *dev = port->dev;
+ u32 crc;
+
+ mutex_lock(&port->dmaqueue_lock);
+ if (!list_empty(&port->list_buf_used.list)) {
+ ubuf = list_first_entry(&port->list_buf_used.list,
+ struct saa7164_user_buffer, list);
+
+ if (crc_checking) {
+ crc = crc32(0, ubuf->data, ubuf->actual_size);
+ if (crc != ubuf->crc) {
+ printk(KERN_ERR "%s() ubuf %p crc became invalid, was 0x%x became 0x%x\n",
+ __func__,
+ ubuf, ubuf->crc, crc);
+ }
+ }
+
+ }
+ mutex_unlock(&port->dmaqueue_lock);
+
+ dprintk(DBGLVL_VBI, "%s() returns %p\n", __func__, ubuf);
+
+ return ubuf;
+}
+
+static ssize_t fops_read(struct file *file, char __user *buffer,
+ size_t count, loff_t *pos)
+{
+ struct saa7164_vbi_fh *fh = file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_user_buffer *ubuf = NULL;
+ struct saa7164_dev *dev = port->dev;
+ int ret = 0;
+ int rem, cnt;
+ u8 *p;
+
+ port->last_read_msecs_diff = port->last_read_msecs;
+ port->last_read_msecs = jiffies_to_msecs(jiffies);
+ port->last_read_msecs_diff = port->last_read_msecs -
+ port->last_read_msecs_diff;
+
+ saa7164_histogram_update(&port->read_interval,
+ port->last_read_msecs_diff);
+
+ if (*pos) {
+ printk(KERN_ERR "%s() ESPIPE\n", __func__);
+ return -ESPIPE;
+ }
+
+ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+ if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+
+ if (saa7164_vbi_initialize(port) < 0) {
+ printk(KERN_ERR "%s() EINVAL\n", __func__);
+ return -EINVAL;
+ }
+
+ saa7164_vbi_start_streaming(port);
+ msleep(200);
+ }
+ }
+
+ /* blocking wait for buffer */
+ if ((file->f_flags & O_NONBLOCK) == 0) {
+ if (wait_event_interruptible(port->wait_read,
+ saa7164_vbi_next_buf(port))) {
+ printk(KERN_ERR "%s() ERESTARTSYS\n", __func__);
+ return -ERESTARTSYS;
+ }
+ }
+
+ /* Pull the first buffer from the used list */
+ ubuf = saa7164_vbi_next_buf(port);
+
+ while ((count > 0) && ubuf) {
+
+ /* set remaining bytes to copy */
+ rem = ubuf->actual_size - ubuf->pos;
+ cnt = rem > count ? count : rem;
+
+ p = ubuf->data + ubuf->pos;
+
+ dprintk(DBGLVL_VBI,
+ "%s() count=%d cnt=%d rem=%d buf=%p buf->pos=%d\n",
+ __func__, (int)count, cnt, rem, ubuf, ubuf->pos);
+
+ if (copy_to_user(buffer, p, cnt)) {
+ printk(KERN_ERR "%s() copy_to_user failed\n", __func__);
+ if (!ret) {
+ printk(KERN_ERR "%s() EFAULT\n", __func__);
+ ret = -EFAULT;
+ }
+ goto err;
+ }
+
+ ubuf->pos += cnt;
+ count -= cnt;
+ buffer += cnt;
+ ret += cnt;
+
+ if (ubuf->pos > ubuf->actual_size)
+ printk(KERN_ERR "read() pos > actual, huh?\n");
+
+ if (ubuf->pos == ubuf->actual_size) {
+
+ /* finished with current buffer, take next buffer */
+
+ /* Requeue the buffer on the free list */
+ ubuf->pos = 0;
+
+ mutex_lock(&port->dmaqueue_lock);
+ list_move_tail(&ubuf->list, &port->list_buf_free.list);
+ mutex_unlock(&port->dmaqueue_lock);
+
+ /* Dequeue next */
+ if ((file->f_flags & O_NONBLOCK) == 0) {
+ if (wait_event_interruptible(port->wait_read,
+ saa7164_vbi_next_buf(port))) {
+ break;
+ }
+ }
+ ubuf = saa7164_vbi_next_buf(port);
+ }
+ }
+err:
+ if (!ret && !ubuf) {
+ printk(KERN_ERR "%s() EAGAIN\n", __func__);
+ ret = -EAGAIN;
+ }
+
+ return ret;
+}
+
+static unsigned int fops_poll(struct file *file, poll_table *wait)
+{
+ struct saa7164_vbi_fh *fh = (struct saa7164_vbi_fh *)file->private_data;
+ struct saa7164_port *port = fh->port;
+ struct saa7164_user_buffer *ubuf;
+ unsigned int mask = 0;
+
+ port->last_poll_msecs_diff = port->last_poll_msecs;
+ port->last_poll_msecs = jiffies_to_msecs(jiffies);
+ port->last_poll_msecs_diff = port->last_poll_msecs -
+ port->last_poll_msecs_diff;
+
+ saa7164_histogram_update(&port->poll_interval,
+ port->last_poll_msecs_diff);
+
+ if (!video_is_registered(port->v4l_device))
+ return -EIO;
+
+ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+ if (atomic_inc_return(&port->v4l_reader_count) == 1) {
+ if (saa7164_vbi_initialize(port) < 0)
+ return -EINVAL;
+ saa7164_vbi_start_streaming(port);
+ msleep(200);
+ }
+ }
+
+ /* blocking wait for buffer */
+ if ((file->f_flags & O_NONBLOCK) == 0) {
+ if (wait_event_interruptible(port->wait_read,
+ saa7164_vbi_next_buf(port))) {
+ return -ERESTARTSYS;
+ }
+ }
+
+ /* Pull the first buffer from the used list */
+ ubuf = list_first_entry(&port->list_buf_used.list,
+ struct saa7164_user_buffer, list);
+
+ if (ubuf)
+ mask |= POLLIN | POLLRDNORM;
+
+ return mask;
+}
+static const struct v4l2_file_operations vbi_fops = {
+ .owner = THIS_MODULE,
+ .open = fops_open,
+ .release = fops_release,
+ .read = fops_read,
+ .poll = fops_poll,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+static const struct v4l2_ioctl_ops vbi_ioctl_ops = {
+ .vidioc_s_std = vidioc_s_std,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_g_tuner = vidioc_g_tuner,
+ .vidioc_s_tuner = vidioc_s_tuner,
+ .vidioc_g_frequency = vidioc_g_frequency,
+ .vidioc_s_frequency = vidioc_s_frequency,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_fmt_vid_cap = vidioc_enum_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = vidioc_g_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = vidioc_try_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = vidioc_s_fmt_vid_cap,
+ .vidioc_g_ext_ctrls = vidioc_g_ext_ctrls,
+ .vidioc_s_ext_ctrls = vidioc_s_ext_ctrls,
+ .vidioc_try_ext_ctrls = vidioc_try_ext_ctrls,
+ .vidioc_log_status = vidioc_log_status,
+ .vidioc_queryctrl = vidioc_queryctrl,
+#if 0
+ .vidioc_g_chip_ident = saa7164_g_chip_ident,
+#endif
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+#if 0
+ .vidioc_g_register = saa7164_g_register,
+ .vidioc_s_register = saa7164_s_register,
+#endif
+#endif
+ .vidioc_g_fmt_vbi_cap = saa7164_vbi_fmt,
+ .vidioc_try_fmt_vbi_cap = saa7164_vbi_fmt,
+ .vidioc_s_fmt_vbi_cap = saa7164_vbi_fmt,
+};
+
+static struct video_device saa7164_vbi_template = {
+ .name = "saa7164",
+ .fops = &vbi_fops,
+ .ioctl_ops = &vbi_ioctl_ops,
+ .minor = -1,
+ .tvnorms = SAA7164_NORMS,
+ .current_norm = V4L2_STD_NTSC_M,
+};
+
+static struct video_device *saa7164_vbi_alloc(
+ struct saa7164_port *port,
+ struct pci_dev *pci,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+
+ *vfd = *template;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+ type, saa7164_boards[dev->board].name);
+
+ vfd->parent = &pci->dev;
+ vfd->release = video_device_release;
+ return vfd;
+}
+
+int saa7164_vbi_register(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+ int result = -ENODEV;
+
+ dprintk(DBGLVL_VBI, "%s()\n", __func__);
+
+ if (port->type != SAA7164_MPEG_VBI)
+ BUG();
+
+ /* Sanity check that the PCI configuration space is active */
+ if (port->hwcfg.BARLocation == 0) {
+ printk(KERN_ERR "%s() failed "
+ "(errno = %d), NO PCI configuration\n",
+ __func__, result);
+ result = -ENOMEM;
+ goto failed;
+ }
+
+ /* Establish VBI defaults here */
+
+ /* Allocate and register the video device node */
+ port->v4l_device = saa7164_vbi_alloc(port,
+ dev->pci, &saa7164_vbi_template, "vbi");
+
+ if (port->v4l_device == NULL) {
+ printk(KERN_INFO "%s: can't allocate vbi device\n",
+ dev->name);
+ result = -ENOMEM;
+ goto failed;
+ }
+
+ video_set_drvdata(port->v4l_device, port);
+ result = video_register_device(port->v4l_device,
+ VFL_TYPE_VBI, -1);
+ if (result < 0) {
+ printk(KERN_INFO "%s: can't register vbi device\n",
+ dev->name);
+ /* TODO: We're going to leak here if we don't dealloc
+ The buffers above. The unreg function can't deal wit it.
+ */
+ goto failed;
+ }
+
+ printk(KERN_INFO "%s: registered device vbi%d [vbi]\n",
+ dev->name, port->v4l_device->num);
+
+ /* Configure the hardware defaults */
+
+ result = 0;
+failed:
+ return result;
+}
+
+void saa7164_vbi_unregister(struct saa7164_port *port)
+{
+ struct saa7164_dev *dev = port->dev;
+
+ dprintk(DBGLVL_VBI, "%s(port=%d)\n", __func__, port->nr);
+
+ if (port->type != SAA7164_MPEG_VBI)
+ BUG();
+
+ if (port->v4l_device) {
+ if (port->v4l_device->minor != -1)
+ video_unregister_device(port->v4l_device);
+ else
+ video_device_release(port->v4l_device);
+
+ port->v4l_device = NULL;
+ }
+
+}
diff --git a/drivers/media/video/saa7164/saa7164.h b/drivers/media/video/saa7164/saa7164.h
index 42660b546f0e..16745d2fb349 100644
--- a/drivers/media/video/saa7164/saa7164.h
+++ b/drivers/media/video/saa7164/saa7164.h
@@ -1,7 +1,7 @@
/*
* Driver for the NXP SAA7164 PCIe bridge
*
- * Copyright (c) 2009 Steven Toth <stoth@kernellabs.com>
+ * Copyright (c) 2010 Steven Toth <stoth@kernellabs.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -48,18 +48,28 @@
#include <linux/i2c.h>
#include <linux/i2c-algo-bit.h>
#include <linux/kdev_t.h>
+#include <linux/version.h>
+#include <linux/mutex.h>
+#include <linux/crc32.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/videobuf-dma-sg.h>
#include <media/videobuf-dvb.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dvb_net.h>
+#include <dvbdev.h>
+#include <dmxdev.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
#include "saa7164-reg.h"
#include "saa7164-types.h"
-#include <linux/version.h>
-#include <linux/mutex.h>
-
#define SAA7164_MAXBOARDS 8
#define UNSET (-1U)
@@ -76,7 +86,19 @@
#define SAA7164_MAX_UNITS 8
#define SAA7164_TS_NUMBER_OF_LINES 312
+#define SAA7164_PS_NUMBER_OF_LINES 256
#define SAA7164_PT_ENTRIES 16 /* (312 * 188) / 4096 */
+#define SAA7164_MAX_ENCODER_BUFFERS 64 /* max 5secs of latency at 6Mbps */
+#define SAA7164_MAX_VBI_BUFFERS 64
+
+/* Port related defines */
+#define SAA7164_PORT_TS1 (0)
+#define SAA7164_PORT_TS2 (SAA7164_PORT_TS1 + 1)
+#define SAA7164_PORT_ENC1 (SAA7164_PORT_TS2 + 1)
+#define SAA7164_PORT_ENC2 (SAA7164_PORT_ENC1 + 1)
+#define SAA7164_PORT_VBI1 (SAA7164_PORT_ENC2 + 1)
+#define SAA7164_PORT_VBI2 (SAA7164_PORT_VBI1 + 1)
+#define SAA7164_MAX_PORTS (SAA7164_PORT_VBI2 + 1)
#define DBGLVL_FW 4
#define DBGLVL_DVB 8
@@ -86,10 +108,19 @@
#define DBGLVL_BUS 128
#define DBGLVL_IRQ 256
#define DBGLVL_BUF 512
+#define DBGLVL_ENC 1024
+#define DBGLVL_VBI 2048
+#define DBGLVL_THR 4096
+#define DBGLVL_CPU 8192
+
+#define SAA7164_NORMS \
+ (V4L2_STD_NTSC_M | V4L2_STD_NTSC_M_JP | V4L2_STD_NTSC_443)
enum port_t {
SAA7164_MPEG_UNDEFINED = 0,
SAA7164_MPEG_DVB,
+ SAA7164_MPEG_ENCODER,
+ SAA7164_MPEG_VBI,
};
enum saa7164_i2c_bus_nr {
@@ -134,7 +165,8 @@ struct saa7164_unit {
struct saa7164_board {
char *name;
- enum port_t porta, portb;
+ enum port_t porta, portb, portc,
+ portd, porte, portf;
enum {
SAA7164_CHIP_UNDEFINED = 0,
SAA7164_CHIP_REV2,
@@ -149,6 +181,38 @@ struct saa7164_subid {
u32 card;
};
+struct saa7164_encoder_fh {
+ struct saa7164_port *port;
+ atomic_t v4l_reading;
+};
+
+struct saa7164_vbi_fh {
+ struct saa7164_port *port;
+ atomic_t v4l_reading;
+};
+
+struct saa7164_histogram_bucket {
+ u32 val;
+ u32 count;
+ u64 update_time;
+};
+
+struct saa7164_histogram {
+ char name[32];
+ struct saa7164_histogram_bucket counter1[64];
+};
+
+struct saa7164_user_buffer {
+ struct list_head list;
+
+ /* Attributes */
+ u8 *data;
+ u32 pos;
+ u32 actual_size;
+
+ u32 crc;
+};
+
struct saa7164_fw_status {
/* RISC Core details */
@@ -191,14 +255,58 @@ struct saa7164_i2c {
u32 i2c_rc;
};
-struct saa7164_tsport;
+struct saa7164_ctrl {
+ struct v4l2_queryctrl v;
+};
+
+struct saa7164_tvnorm {
+ char *name;
+ v4l2_std_id id;
+};
+
+struct saa7164_encoder_params {
+ struct saa7164_tvnorm encodernorm;
+ u32 height;
+ u32 width;
+ u32 is_50hz;
+ u32 bitrate; /* bps */
+ u32 bitrate_peak; /* bps */
+ u32 bitrate_mode;
+ u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
+
+ u32 audio_sampling_freq;
+ u32 ctl_mute;
+ u32 ctl_aspect;
+ u32 refdist;
+ u32 gop_size;
+};
+
+struct saa7164_vbi_params {
+ struct saa7164_tvnorm encodernorm;
+ u32 height;
+ u32 width;
+ u32 is_50hz;
+ u32 bitrate; /* bps */
+ u32 bitrate_peak; /* bps */
+ u32 bitrate_mode;
+ u32 stream_type; /* V4L2_MPEG_STREAM_TYPE_MPEG2_TS */
+
+ u32 audio_sampling_freq;
+ u32 ctl_mute;
+ u32 ctl_aspect;
+ u32 refdist;
+ u32 gop_size;
+};
+
+struct saa7164_port;
struct saa7164_buffer {
struct list_head list;
- u32 nr;
+ /* Note of which h/w buffer list index position we occupy */
+ int idx;
- struct saa7164_tsport *port;
+ struct saa7164_port *port;
/* Hardware Specific */
/* PCI Memory allocations */
@@ -206,28 +314,33 @@ struct saa7164_buffer {
/* A block of page align PCI memory */
u32 pci_size; /* PCI allocation size in bytes */
- u64 *cpu; /* Virtual address */
+ u64 __iomem *cpu; /* Virtual address */
dma_addr_t dma; /* Physical address */
+ u32 crc; /* Checksum for the entire buffer data */
/* A page table that splits the block into a number of entries */
u32 pt_size; /* PCI allocation size in bytes */
- u64 *pt_cpu; /* Virtual address */
+ u64 __iomem *pt_cpu; /* Virtual address */
dma_addr_t pt_dma; /* Physical address */
+
+ /* Encoder fops */
+ u32 pos;
+ u32 actual_size;
};
-struct saa7164_tsport {
+struct saa7164_port {
struct saa7164_dev *dev;
- int nr;
enum port_t type;
+ int nr;
- struct saa7164_dvb dvb;
+ /* --- Generic port attributes --- */
- /* HW related stream parameters */
- tmHWStreamParameters_t hw_streamingparams;
+ /* HW stream parameters */
+ struct tmHWStreamParameters hw_streamingparams;
/* DMA configuration values, is seeded during initialization */
- tmComResDMATermDescrHeader_t hwcfg;
+ struct tmComResDMATermDescrHeader hwcfg;
/* hardware specific registers */
u32 bufcounter;
@@ -239,11 +352,76 @@ struct saa7164_tsport {
u64 bufptr64;
u32 numpte; /* Number of entries in array, only valid in head */
+
struct mutex dmaqueue_lock;
- struct mutex dummy_dmaqueue_lock;
struct saa7164_buffer dmaqueue;
- struct saa7164_buffer dummy_dmaqueue;
+ u64 last_irq_msecs, last_svc_msecs;
+ u64 last_irq_msecs_diff, last_svc_msecs_diff;
+ u32 last_svc_wp;
+ u32 last_svc_rp;
+ u64 last_irq_svc_msecs_diff;
+ u64 last_read_msecs, last_read_msecs_diff;
+ u64 last_poll_msecs, last_poll_msecs_diff;
+
+ struct saa7164_histogram irq_interval;
+ struct saa7164_histogram svc_interval;
+ struct saa7164_histogram irq_svc_interval;
+ struct saa7164_histogram read_interval;
+ struct saa7164_histogram poll_interval;
+
+ /* --- DVB Transport Specific --- */
+ struct saa7164_dvb dvb;
+
+ /* --- Encoder/V4L related attributes --- */
+ /* Encoder */
+ /* Defaults established in saa7164-encoder.c */
+ struct saa7164_tvnorm encodernorm;
+ u32 height;
+ u32 width;
+ u32 freq;
+ u32 ts_packet_size;
+ u32 ts_packet_count;
+ u8 mux_input;
+ u8 encoder_profile;
+ u8 video_format;
+ u8 audio_format;
+ u8 video_resolution;
+ u16 ctl_brightness;
+ u16 ctl_contrast;
+ u16 ctl_hue;
+ u16 ctl_saturation;
+ u16 ctl_sharpness;
+ s8 ctl_volume;
+
+ struct tmComResAFeatureDescrHeader audfeat;
+ struct tmComResEncoderDescrHeader encunit;
+ struct tmComResProcDescrHeader vidproc;
+ struct tmComResExtDevDescrHeader ifunit;
+ struct tmComResTunerDescrHeader tunerunit;
+
+ struct work_struct workenc;
+
+ /* V4L Encoder Video */
+ struct saa7164_encoder_params encoder_params;
+ struct video_device *v4l_device;
+ atomic_t v4l_reader_count;
+
+ struct saa7164_buffer list_buf_used;
+ struct saa7164_buffer list_buf_free;
+ wait_queue_head_t wait_read;
+
+ /* V4L VBI */
+ struct tmComResVBIFormatDescrHeader vbi_fmt_ntsc;
+ struct saa7164_vbi_params vbi_params;
+
+ /* Debug */
+ u32 sync_errors;
+ u32 v_cc_errors;
+ u32 a_cc_errors;
+ u8 last_v_cc;
+ u8 last_a_cc;
+ u32 done_first_interrupt;
};
struct saa7164_dev {
@@ -264,16 +442,17 @@ struct saa7164_dev {
int nr;
int hwrevision;
u32 board;
- char name[32];
+ char name[16];
/* firmware status */
struct saa7164_fw_status fw_status;
+ u32 firmwareloaded;
- tmComResHWDescr_t hwdesc;
- tmComResInterfaceDescr_t intfdesc;
- tmComResBusDescr_t busdesc;
+ struct tmComResHWDescr hwdesc;
+ struct tmComResInterfaceDescr intfdesc;
+ struct tmComResBusDescr busdesc;
- tmComResBusInfo_t bus;
+ struct tmComResBusInfo bus;
/* Interrupt status and ack registers */
u32 int_status;
@@ -286,15 +465,22 @@ struct saa7164_dev {
struct saa7164_i2c i2c_bus[3];
/* Transport related */
- struct saa7164_tsport ts1, ts2;
+ struct saa7164_port ports[SAA7164_MAX_PORTS];
/* Deferred command/api interrupts handling */
struct work_struct workcmd;
+ /* A kernel thread to monitor the firmware log, used
+ * only in debug mode.
+ */
+ struct task_struct *kthread;
+
};
extern struct list_head saa7164_devlist;
extern unsigned int waitsecs;
+extern unsigned int encoder_buffers;
+extern unsigned int vbi_buffers;
/* ----------------------------------------------------------- */
/* saa7164-core.c */
@@ -302,6 +488,7 @@ void saa7164_dumpregs(struct saa7164_dev *dev, u32 addr);
void saa7164_dumphex16(struct saa7164_dev *dev, u8 *buf, int len);
void saa7164_getfirmwarestatus(struct saa7164_dev *dev);
u32 saa7164_getcurrentfirmwareversion(struct saa7164_dev *dev);
+void saa7164_histogram_update(struct saa7164_histogram *hg, u32 val);
/* ----------------------------------------------------------- */
/* saa7164-fw.c */
@@ -318,14 +505,15 @@ extern void saa7164_call_i2c_clients(struct saa7164_i2c *bus,
/* saa7164-bus.c */
int saa7164_bus_setup(struct saa7164_dev *dev);
void saa7164_bus_dump(struct saa7164_dev *dev);
-int saa7164_bus_set(struct saa7164_dev *dev, tmComResInfo_t* msg, void *buf);
-int saa7164_bus_get(struct saa7164_dev *dev, tmComResInfo_t* msg,
+int saa7164_bus_set(struct saa7164_dev *dev, struct tmComResInfo* msg,
+ void *buf);
+int saa7164_bus_get(struct saa7164_dev *dev, struct tmComResInfo* msg,
void *buf, int peekonly);
/* ----------------------------------------------------------- */
/* saa7164-cmd.c */
int saa7164_cmd_send(struct saa7164_dev *dev,
- u8 id, tmComResCmd_t command, u16 controlselector,
+ u8 id, enum tmComResCmd command, u16 controlselector,
u16 size, void *buf);
void saa7164_cmd_signal(struct saa7164_dev *dev, u8 seqno);
int saa7164_irq_dequeue(struct saa7164_dev *dev);
@@ -343,7 +531,25 @@ int saa7164_api_dif_write(struct saa7164_i2c *bus, u8 addr,
int saa7164_api_read_eeprom(struct saa7164_dev *dev, u8 *buf, int buflen);
int saa7164_api_set_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
int saa7164_api_clear_gpiobit(struct saa7164_dev *dev, u8 unitid, u8 pin);
-int saa7164_api_transition_port(struct saa7164_tsport *port, u8 mode);
+int saa7164_api_transition_port(struct saa7164_port *port, u8 mode);
+int saa7164_api_initialize_dif(struct saa7164_port *port);
+int saa7164_api_configure_dif(struct saa7164_port *port, u32 std);
+int saa7164_api_set_encoder(struct saa7164_port *port);
+int saa7164_api_get_encoder(struct saa7164_port *port);
+int saa7164_api_set_aspect_ratio(struct saa7164_port *port);
+int saa7164_api_set_usercontrol(struct saa7164_port *port, u8 ctl);
+int saa7164_api_get_usercontrol(struct saa7164_port *port, u8 ctl);
+int saa7164_api_set_videomux(struct saa7164_port *port);
+int saa7164_api_audio_mute(struct saa7164_port *port, int mute);
+int saa7164_api_set_audio_volume(struct saa7164_port *port, s8 level);
+int saa7164_api_set_audio_std(struct saa7164_port *port);
+int saa7164_api_set_audio_detection(struct saa7164_port *port, int autodetect);
+int saa7164_api_get_videomux(struct saa7164_port *port);
+int saa7164_api_set_vbi_format(struct saa7164_port *port);
+int saa7164_api_set_debug(struct saa7164_dev *dev, u8 level);
+int saa7164_api_collect_debug(struct saa7164_dev *dev);
+int saa7164_api_get_load_info(struct saa7164_dev *dev,
+ struct tmFwInfoStruct *i);
/* ----------------------------------------------------------- */
/* saa7164-cards.c */
@@ -363,18 +569,36 @@ extern char *saa7164_unitid_name(struct saa7164_dev *dev, u8 unitid);
/* ----------------------------------------------------------- */
/* saa7164-dvb.c */
-extern int saa7164_dvb_register(struct saa7164_tsport *port);
-extern int saa7164_dvb_unregister(struct saa7164_tsport *port);
+extern int saa7164_dvb_register(struct saa7164_port *port);
+extern int saa7164_dvb_unregister(struct saa7164_port *port);
/* ----------------------------------------------------------- */
/* saa7164-buffer.c */
-extern struct saa7164_buffer *saa7164_buffer_alloc(struct saa7164_tsport *port,
- u32 len);
-extern int saa7164_buffer_dealloc(struct saa7164_tsport *port,
- struct saa7164_buffer *buf);
+extern struct saa7164_buffer *saa7164_buffer_alloc(
+ struct saa7164_port *port, u32 len);
+extern int saa7164_buffer_dealloc(struct saa7164_buffer *buf);
+extern void saa7164_buffer_display(struct saa7164_buffer *buf);
+extern int saa7164_buffer_activate(struct saa7164_buffer *buf, int i);
+extern int saa7164_buffer_cfg_port(struct saa7164_port *port);
+extern struct saa7164_user_buffer *saa7164_buffer_alloc_user(
+ struct saa7164_dev *dev, u32 len);
+extern void saa7164_buffer_dealloc_user(struct saa7164_user_buffer *buf);
+extern int saa7164_buffer_zero_offsets(struct saa7164_port *port, int i);
+
+/* ----------------------------------------------------------- */
+/* saa7164-encoder.c */
+int saa7164_encoder_register(struct saa7164_port *port);
+void saa7164_encoder_unregister(struct saa7164_port *port);
+
+/* ----------------------------------------------------------- */
+/* saa7164-vbi.c */
+int saa7164_vbi_register(struct saa7164_port *port);
+void saa7164_vbi_unregister(struct saa7164_port *port);
/* ----------------------------------------------------------- */
+extern unsigned int crc_checking;
+
extern unsigned int saa_debug;
#define dprintk(level, fmt, arg...)\
do { if (saa_debug & level)\
@@ -394,7 +618,6 @@ extern unsigned int saa_debug;
#define saa7164_readl(reg) readl(dev->lmmio + ((reg) >> 2))
#define saa7164_writel(reg, value) writel((value), dev->lmmio + ((reg) >> 2))
-
#define saa7164_readb(reg) readl(dev->bmmio + (reg))
#define saa7164_writeb(reg, value) writel((value), dev->bmmio + (reg))
diff --git a/drivers/media/video/saa717x.c b/drivers/media/video/saa717x.c
index d521c648e157..b6172c2c517e 100644
--- a/drivers/media/video/saa717x.c
+++ b/drivers/media/video/saa717x.c
@@ -38,7 +38,7 @@
#include <linux/videodev2.h>
#include <linux/i2c.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
@@ -55,14 +55,11 @@ MODULE_PARM_DESC(debug, "Debug level (0-1)");
struct saa717x_state {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
v4l2_std_id std;
int input;
int enable;
int radio;
- int bright;
- int contrast;
- int hue;
- int sat;
int playback;
int audio;
int tuner_audio_mode;
@@ -81,6 +78,11 @@ static inline struct saa717x_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct saa717x_state, sd);
}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct saa717x_state, hdl)->sd;
+}
+
/* ----------------------------------------------------------------------- */
/* for audio mode */
@@ -774,29 +776,6 @@ static void set_audio_mode(struct v4l2_subdev *sd, int audio_mode)
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 v4l2_subdev *sd,
- struct saa717x_state *decoder)
-{
- /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
- 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(sd, 0x10b, decoder->contrast);
-
- /* saturation? 7fh(max)-40h(ITU)-0h(color off)
- c0h (-1.0 inverse chrominance)
- 80h (-2.0 inverse chrominance) */
- saa717x_write(sd, 0x10c, decoder->sat);
-
- /* color hue (phase) control
- 7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
- saa717x_write(sd, 0x10d, decoder->hue);
-}
-
/* write regs to set audio volume, bass and treble */
static int set_audio_regs(struct v4l2_subdev *sd,
struct saa717x_state *decoder)
@@ -829,9 +808,9 @@ static int set_audio_regs(struct v4l2_subdev *sd,
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);
+ val = decoder->audio_main_bass & 0x1f;
+ val |= (decoder->audio_main_treble & 0x1f) << 5;
saa717x_write(sd, 0x488, val);
return 0;
}
@@ -893,218 +872,55 @@ static void set_v_scale(struct v4l2_subdev *sd, int task, int yscale)
saa717x_write(sd, 0x71 + task_shift, yscale >> 8);
}
-static int saa717x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int saa717x_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
struct saa717x_state *state = to_state(sd);
switch (ctrl->id) {
case V4L2_CID_BRIGHTNESS:
- if (ctrl->value < 0 || ctrl->value > 255) {
- v4l2_err(sd, "invalid brightness setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- state->bright = ctrl->value;
- 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) {
- v4l2_err(sd, "invalid contrast setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- state->contrast = ctrl->value;
- 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) {
- v4l2_err(sd, "invalid saturation setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- state->sat = ctrl->value;
- v4l2_dbg(1, debug, sd, "sat:%d\n", state->sat);
- saa717x_write(sd, 0x10c, state->sat);
- break;
-
- case V4L2_CID_HUE:
- if (ctrl->value < -128 || ctrl->value > 127) {
- v4l2_err(sd, "invalid hue setting %d\n", ctrl->value);
- return -ERANGE;
- }
-
- state->hue = ctrl->value;
- 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(sd, state);
- break;
-
- case V4L2_CID_AUDIO_VOLUME:
- state->audio_main_volume = ctrl->value;
- set_audio_regs(sd, state);
- break;
-
- case V4L2_CID_AUDIO_BALANCE:
- state->audio_main_balance = ctrl->value;
- set_audio_regs(sd, state);
- break;
-
- case V4L2_CID_AUDIO_TREBLE:
- state->audio_main_treble = ctrl->value;
- set_audio_regs(sd, state);
- break;
-
- case V4L2_CID_AUDIO_BASS:
- state->audio_main_bass = ctrl->value;
- set_audio_regs(sd, state);
- break;
-
- default:
- return -EINVAL;
- }
-
- return 0;
-}
-
-static int saa717x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct saa717x_state *state = to_state(sd);
-
- switch (ctrl->id) {
- case V4L2_CID_BRIGHTNESS:
- ctrl->value = state->bright;
- break;
+ saa717x_write(sd, 0x10a, ctrl->val);
+ return 0;
case V4L2_CID_CONTRAST:
- ctrl->value = state->contrast;
- break;
+ saa717x_write(sd, 0x10b, ctrl->val);
+ return 0;
case V4L2_CID_SATURATION:
- ctrl->value = state->sat;
- break;
+ saa717x_write(sd, 0x10c, ctrl->val);
+ return 0;
case V4L2_CID_HUE:
- ctrl->value = state->hue;
- break;
+ saa717x_write(sd, 0x10d, ctrl->val);
+ return 0;
case V4L2_CID_AUDIO_MUTE:
- ctrl->value = state->audio_main_mute;
+ state->audio_main_mute = ctrl->val;
break;
case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = state->audio_main_volume;
+ state->audio_main_volume = ctrl->val;
break;
case V4L2_CID_AUDIO_BALANCE:
- ctrl->value = state->audio_main_balance;
+ state->audio_main_balance = ctrl->val;
break;
case V4L2_CID_AUDIO_TREBLE:
- ctrl->value = state->audio_main_treble;
+ state->audio_main_treble = ctrl->val;
break;
case V4L2_CID_AUDIO_BASS:
- ctrl->value = state->audio_main_bass;
+ state->audio_main_bass = ctrl->val;
break;
default:
- return -EINVAL;
+ return 0;
}
-
+ set_audio_regs(sd, state);
return 0;
}
-static struct v4l2_queryctrl saa717x_qctrl[] = {
- {
- .id = V4L2_CID_BRIGHTNESS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Brightness",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 128,
- .flags = 0,
- }, {
- .id = V4L2_CID_CONTRAST,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Contrast",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_SATURATION,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Saturation",
- .minimum = 0,
- .maximum = 255,
- .step = 1,
- .default_value = 64,
- .flags = 0,
- }, {
- .id = V4L2_CID_HUE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Hue",
- .minimum = -128,
- .maximum = 127,
- .step = 1,
- .default_value = 0,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_VOLUME,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535 / 100,
- .default_value = 58880,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535 / 100,
- .default_value = 32768,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_MUTE,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- }, {
- .id = V4L2_CID_AUDIO_BASS,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Bass",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535 / 100,
- .default_value = 32768,
- }, {
- .id = V4L2_CID_AUDIO_TREBLE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "Treble",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535 / 100,
- .default_value = 32768,
- },
-};
-
static int saa717x_s_video_routing(struct v4l2_subdev *sd,
u32 input, u32 output, u32 config)
{
@@ -1158,18 +974,6 @@ static int saa717x_s_video_routing(struct v4l2_subdev *sd,
return 0;
}
-static int saa717x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- int i;
-
- 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;
-}
-
#ifdef CONFIG_VIDEO_ADV_DEBUG
static int saa717x_g_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *reg)
{
@@ -1199,28 +1003,32 @@ static int saa717x_s_register(struct v4l2_subdev *sd, struct v4l2_dbg_register *
}
#endif
-static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
+static int saa717x_s_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *fmt)
{
- struct v4l2_pix_format *pix;
int prescale, h_scale, v_scale;
- pix = &fmt->fmt.pix;
v4l2_dbg(1, debug, sd, "decoder set size\n");
+ if (fmt->code != V4L2_MBUS_FMT_FIXED)
+ return -EINVAL;
+
/* FIXME need better bounds checking here */
- if (pix->width < 1 || pix->width > 1440)
+ if (fmt->width < 1 || fmt->width > 1440)
return -EINVAL;
- if (pix->height < 1 || pix->height > 960)
+ if (fmt->height < 1 || fmt->height > 960)
return -EINVAL;
+ fmt->field = V4L2_FIELD_INTERLACED;
+ fmt->colorspace = V4L2_COLORSPACE_SMPTE170M;
+
/* scaling setting */
/* NTSC and interlace only */
- prescale = SAA717X_NTSC_WIDTH / pix->width;
+ prescale = SAA717X_NTSC_WIDTH / fmt->width;
if (prescale == 0)
prescale = 1;
- h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
+ h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / fmt->width;
/* interlace */
- v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
+ v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / fmt->height;
/* Horizontal prescaling etc */
set_h_prescale(sd, 0, prescale);
@@ -1241,19 +1049,19 @@ static int saa717x_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
/* 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));
+ saa717x_write(sd, 0x5C, (u8)(fmt->width & 0xFF));
+ saa717x_write(sd, 0x5D, (u8)((fmt->width >> 8) & 0xFF));
/* TASK B */
- saa717x_write(sd, 0x9C, (u8)(pix->width & 0xFF));
- saa717x_write(sd, 0x9D, (u8)((pix->width >> 8) & 0xFF));
+ saa717x_write(sd, 0x9C, (u8)(fmt->width & 0xFF));
+ saa717x_write(sd, 0x9D, (u8)((fmt->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));
+ saa717x_write(sd, 0x5E, (u8)(fmt->height & 0xFF));
+ saa717x_write(sd, 0x5F, (u8)((fmt->height >> 8) & 0xFF));
/* TASK B */
- saa717x_write(sd, 0x9E, (u8)(pix->height & 0xFF));
- saa717x_write(sd, 0x9F, (u8)((pix->height >> 8) & 0xFF));
+ saa717x_write(sd, 0x9E, (u8)(fmt->height & 0xFF));
+ saa717x_write(sd, 0x9F, (u8)((fmt->height >> 8) & 0xFF));
return 0;
}
@@ -1382,17 +1190,34 @@ static int saa717x_g_tuner(struct v4l2_subdev *sd, struct v4l2_tuner *vt)
return 0;
}
+static int saa717x_log_status(struct v4l2_subdev *sd)
+{
+ struct saa717x_state *state = to_state(sd);
+
+ v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
+ return 0;
+}
+
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops saa717x_ctrl_ops = {
+ .s_ctrl = saa717x_s_ctrl,
+};
+
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,
.s_std = saa717x_s_std,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
+ .log_status = saa717x_log_status,
};
static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
@@ -1403,7 +1228,7 @@ static const struct v4l2_subdev_tuner_ops saa717x_tuner_ops = {
static const struct v4l2_subdev_video_ops saa717x_video_ops = {
.s_routing = saa717x_s_video_routing,
- .s_fmt = saa717x_s_fmt,
+ .s_mbus_fmt = saa717x_s_mbus_fmt,
.s_stream = saa717x_s_stream,
};
@@ -1428,6 +1253,7 @@ static int saa717x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct saa717x_state *decoder;
+ struct v4l2_ctrl_handler *hdl;
struct v4l2_subdev *sd;
u8 id = 0;
char *p = "";
@@ -1463,16 +1289,41 @@ static int saa717x_probe(struct i2c_client *client,
p = "saa7171";
v4l2_info(sd, "%s found @ 0x%x (%s)\n", p,
client->addr << 1, client->adapter->name);
+
+ hdl = &decoder->hdl;
+ v4l2_ctrl_handler_init(hdl, 9);
+ /* add in ascending ID order */
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_BRIGHTNESS, 0, 255, 1, 128);
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_CONTRAST, 0, 255, 1, 68);
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_SATURATION, 0, 255, 1, 64);
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_HUE, -128, 127, 1, 0);
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 42000);
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_AUDIO_BASS, -16, 15, 1, 0);
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_AUDIO_TREBLE, -16, 15, 1, 0);
+ v4l2_ctrl_new_std(hdl, &saa717x_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ sd->ctrl_handler = hdl;
+ if (hdl->error) {
+ int err = hdl->error;
+
+ v4l2_ctrl_handler_free(hdl);
+ kfree(decoder);
+ return err;
+ }
+
decoder->std = V4L2_STD_NTSC;
decoder->input = -1;
decoder->enable = 1;
- /* tune these parameters */
- decoder->bright = 0x80;
- decoder->contrast = 0x44;
- decoder->sat = 0x40;
- decoder->hue = 0x00;
-
/* FIXME!! */
decoder->playback = 0; /* initially capture mode used */
decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
@@ -1483,23 +1334,13 @@ static int saa717x_probe(struct i2c_client *client,
/* set volume, bass and treble */
decoder->audio_main_vol_l = 6;
decoder->audio_main_vol_r = 6;
- decoder->audio_main_bass = 0;
- decoder->audio_main_treble = 0;
- decoder->audio_main_mute = 0;
- decoder->audio_main_balance = 32768;
- /* normalize (24 to -40 (not -84) -> 65535 to 0) */
- decoder->audio_main_volume =
- (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
v4l2_dbg(1, debug, sd, "writing init values\n");
/* FIXME!! */
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(sd, decoder);
+
+ v4l2_ctrl_handler_setup(hdl);
set_current_state(TASK_INTERRUPTIBLE);
schedule_timeout(2*HZ);
@@ -1511,6 +1352,7 @@ static int saa717x_remove(struct i2c_client *client)
struct v4l2_subdev *sd = i2c_get_clientdata(client);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(sd->ctrl_handler);
kfree(to_state(sd));
return 0;
}
@@ -1523,9 +1365,25 @@ static const struct i2c_device_id saa717x_id[] = {
};
MODULE_DEVICE_TABLE(i2c, saa717x_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa717x",
- .probe = saa717x_probe,
- .remove = saa717x_remove,
- .id_table = saa717x_id,
+static struct i2c_driver saa717x_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa717x",
+ },
+ .probe = saa717x_probe,
+ .remove = saa717x_remove,
+ .id_table = saa717x_id,
};
+
+static __init int init_saa717x(void)
+{
+ return i2c_add_driver(&saa717x_driver);
+}
+
+static __exit void exit_saa717x(void)
+{
+ i2c_del_driver(&saa717x_driver);
+}
+
+module_init(init_saa717x);
+module_exit(exit_saa717x);
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 77db20392910..96f56c2f11f3 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -30,11 +30,9 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("Philips SAA7185 video encoder driver");
MODULE_AUTHOR("Dave Perks");
@@ -366,9 +364,25 @@ static const struct i2c_device_id saa7185_id[] = {
};
MODULE_DEVICE_TABLE(i2c, saa7185_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa7185",
- .probe = saa7185_probe,
- .remove = saa7185_remove,
- .id_table = saa7185_id,
+static struct i2c_driver saa7185_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa7185",
+ },
+ .probe = saa7185_probe,
+ .remove = saa7185_remove,
+ .id_table = saa7185_id,
};
+
+static __init int init_saa7185(void)
+{
+ return i2c_add_driver(&saa7185_driver);
+}
+
+static __exit void exit_saa7185(void)
+{
+ i2c_del_driver(&saa7185_driver);
+}
+
+module_init(init_saa7185);
+module_exit(exit_saa7185);
diff --git a/drivers/media/video/saa7191.c b/drivers/media/video/saa7191.c
index a2513772196b..211fa25a1239 100644
--- a/drivers/media/video/saa7191.c
+++ b/drivers/media/video/saa7191.c
@@ -23,7 +23,6 @@
#include <linux/i2c.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include "saa7191.h"
@@ -647,9 +646,25 @@ static const struct i2c_device_id saa7191_id[] = {
};
MODULE_DEVICE_TABLE(i2c, saa7191_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "saa7191",
- .probe = saa7191_probe,
- .remove = saa7191_remove,
- .id_table = saa7191_id,
+static struct i2c_driver saa7191_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "saa7191",
+ },
+ .probe = saa7191_probe,
+ .remove = saa7191_remove,
+ .id_table = saa7191_id,
};
+
+static __init int init_saa7191(void)
+{
+ return i2c_add_driver(&saa7191_driver);
+}
+
+static __exit void exit_saa7191(void)
+{
+ i2c_del_driver(&saa7191_driver);
+}
+
+module_init(init_saa7191);
+module_exit(exit_saa7191);
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
deleted file mode 100644
index 41d0166c0f95..000000000000
--- a/drivers/media/video/se401.c
+++ /dev/null
@@ -1,1493 +0,0 @@
-/*
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- *
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 driver.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- *
- * Thanks to Endpoints Inc. (www.endpoints.com) for making documentation on
- * their chipset available and supporting me while writing this driver.
- * - Jeroen Vreeken
- */
-
-static const char version[] = "0.24";
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
-#include <linux/usb.h>
-#include "se401.h"
-
-static int flickerless;
-static int video_nr = -1;
-
-static struct usb_device_id device_table[] = {
- { USB_DEVICE(0x03e8, 0x0004) },/* Endpoints/Aox SE401 */
- { USB_DEVICE(0x0471, 0x030b) },/* Philips PCVC665K */
- { USB_DEVICE(0x047d, 0x5001) },/* Kensington 67014 */
- { USB_DEVICE(0x047d, 0x5002) },/* Kensington 6701(5/7) */
- { USB_DEVICE(0x047d, 0x5003) },/* Kensington 67016 */
- { }
-};
-
-MODULE_DEVICE_TABLE(usb, device_table);
-
-MODULE_AUTHOR("Jeroen Vreeken <pe1rxq@amsat.org>");
-MODULE_DESCRIPTION("SE401 USB Camera Driver");
-MODULE_LICENSE("GPL");
-module_param(flickerless, int, 0);
-MODULE_PARM_DESC(flickerless,
- "Net frequency to adjust exposure time to (0/50/60)");
-module_param(video_nr, int, 0);
-
-static struct usb_driver se401_driver;
-
-
-/**********************************************************************
- *
- * Memory management
- *
- **********************************************************************/
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-
-
-/****************************************************************************
- *
- * se401 register read/write functions
- *
- ***************************************************************************/
-
-static int se401_sndctrl(int set, struct usb_se401 *se401, unsigned short req,
- unsigned short value, unsigned char *cp, int size)
-{
- return usb_control_msg(
- se401->dev,
- set ? usb_sndctrlpipe(se401->dev, 0) : usb_rcvctrlpipe(se401->dev, 0),
- req,
- (set ? USB_DIR_OUT : USB_DIR_IN) | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- 0,
- cp,
- size,
- 1000
- );
-}
-
-static int se401_set_feature(struct usb_se401 *se401, unsigned short selector,
- unsigned short param)
-{
- /* specs say that the selector (address) should go in the value field
- and the param in index, but in the logs of the windows driver they do
- this the other way around...
- */
- return usb_control_msg(
- se401->dev,
- usb_sndctrlpipe(se401->dev, 0),
- SE401_REQ_SET_EXT_FEATURE,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- param,
- selector,
- NULL,
- 0,
- 1000
- );
-}
-
-static unsigned short se401_get_feature(struct usb_se401 *se401,
- unsigned short selector)
-{
- /* For 'set' the selecetor should be in index, not sure if the spec is
- wrong here to....
- */
- unsigned char cp[2];
- usb_control_msg(
- se401->dev,
- usb_rcvctrlpipe(se401->dev, 0),
- SE401_REQ_GET_EXT_FEATURE,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0,
- selector,
- cp,
- 2,
- 1000
- );
- return cp[0]+cp[1]*256;
-}
-
-/****************************************************************************
- *
- * Camera control
- *
- ***************************************************************************/
-
-
-static int se401_send_pict(struct usb_se401 *se401)
-{
- /* integration time low */
- se401_set_feature(se401, HV7131_REG_TITL, se401->expose_l);
- /* integration time mid */
- se401_set_feature(se401, HV7131_REG_TITM, se401->expose_m);
- /* integration time mid */
- se401_set_feature(se401, HV7131_REG_TITU, se401->expose_h);
- /* reset level value */
- se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
- /* red color gain */
- se401_set_feature(se401, HV7131_REG_ARCG, se401->rgain);
- /* green color gain */
- se401_set_feature(se401, HV7131_REG_AGCG, se401->ggain);
- /* blue color gain */
- se401_set_feature(se401, HV7131_REG_ABCG, se401->bgain);
-
- return 0;
-}
-
-static void se401_set_exposure(struct usb_se401 *se401, int brightness)
-{
- int integration = brightness << 5;
-
- if (flickerless == 50)
- integration = integration-integration % 106667;
- if (flickerless == 60)
- integration = integration-integration % 88889;
- se401->brightness = integration >> 5;
- se401->expose_h = (integration >> 16) & 0xff;
- se401->expose_m = (integration >> 8) & 0xff;
- se401->expose_l = integration & 0xff;
-}
-
-static int se401_get_pict(struct usb_se401 *se401, struct video_picture *p)
-{
- p->brightness = se401->brightness;
- if (se401->enhance)
- p->whiteness = 32768;
- else
- p->whiteness = 0;
-
- p->colour = 65535;
- p->contrast = 65535;
- p->hue = se401->rgain << 10;
- p->palette = se401->palette;
- p->depth = 3; /* rgb24 */
- return 0;
-}
-
-
-static int se401_set_pict(struct usb_se401 *se401, struct video_picture *p)
-{
- if (p->palette != VIDEO_PALETTE_RGB24)
- return 1;
- se401->palette = p->palette;
- if (p->hue != se401->hue) {
- se401->rgain = p->hue >> 10;
- se401->bgain = 0x40-(p->hue >> 10);
- se401->hue = p->hue;
- }
- if (p->brightness != se401->brightness)
- se401_set_exposure(se401, p->brightness);
-
- if (p->whiteness >= 32768)
- se401->enhance = 1;
- else
- se401->enhance = 0;
- se401_send_pict(se401);
- se401_send_pict(se401);
- return 0;
-}
-
-/*
- Hyundai have some really nice docs about this and other sensor related
- stuff on their homepage: www.hei.co.kr
-*/
-static void se401_auto_resetlevel(struct usb_se401 *se401)
-{
- unsigned int ahrc, alrc;
- int oldreset = se401->resetlevel;
-
- /* For some reason this normally read-only register doesn't get reset
- to zero after reading them just once...
- */
- se401_get_feature(se401, HV7131_REG_HIREFNOH);
- se401_get_feature(se401, HV7131_REG_HIREFNOL);
- se401_get_feature(se401, HV7131_REG_LOREFNOH);
- se401_get_feature(se401, HV7131_REG_LOREFNOL);
- ahrc = 256*se401_get_feature(se401, HV7131_REG_HIREFNOH) +
- se401_get_feature(se401, HV7131_REG_HIREFNOL);
- alrc = 256*se401_get_feature(se401, HV7131_REG_LOREFNOH) +
- se401_get_feature(se401, HV7131_REG_LOREFNOL);
-
- /* Not an exact science, but it seems to work pretty well... */
- if (alrc > 10) {
- while (alrc >= 10 && se401->resetlevel < 63) {
- se401->resetlevel++;
- alrc /= 2;
- }
- } else if (ahrc > 20) {
- while (ahrc >= 20 && se401->resetlevel > 0) {
- se401->resetlevel--;
- ahrc /= 2;
- }
- }
- if (se401->resetlevel != oldreset)
- se401_set_feature(se401, HV7131_REG_ARLV, se401->resetlevel);
-
- return;
-}
-
-/* irq handler for snapshot button */
-static void se401_button_irq(struct urb *urb)
-{
- struct usb_se401 *se401 = urb->context;
- int status;
-
- if (!se401->dev) {
- dev_info(&urb->dev->dev, "device vapourished\n");
- return;
- }
-
- switch (urb->status) {
- case 0:
- /* success */
- break;
- case -ECONNRESET:
- case -ENOENT:
- case -ESHUTDOWN:
- /* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d",
- __func__, urb->status);
- return;
- default:
- dbg("%s - nonzero urb status received: %d",
- __func__, urb->status);
- goto exit;
- }
-
- if (urb->actual_length >= 2)
- if (se401->button)
- se401->buttonpressed = 1;
-exit:
- status = usb_submit_urb(urb, GFP_ATOMIC);
- if (status)
- err("%s - usb_submit_urb failed with result %d",
- __func__, status);
-}
-
-static void se401_video_irq(struct urb *urb)
-{
- struct usb_se401 *se401 = urb->context;
- int length = urb->actual_length;
-
- /* ohoh... */
- if (!se401->streaming)
- return;
-
- if (!se401->dev) {
- dev_info(&urb->dev->dev, "device vapourished\n");
- return;
- }
-
- /* 0 sized packets happen if we are to fast, but sometimes the camera
- keeps sending them forever...
- */
- if (length && !urb->status) {
- se401->nullpackets = 0;
- switch (se401->scratch[se401->scratch_next].state) {
- case BUFFER_READY:
- case BUFFER_BUSY:
- se401->dropped++;
- break;
- case BUFFER_UNUSED:
- memcpy(se401->scratch[se401->scratch_next].data,
- (unsigned char *)urb->transfer_buffer, length);
- se401->scratch[se401->scratch_next].state
- = BUFFER_READY;
- se401->scratch[se401->scratch_next].offset
- = se401->bayeroffset;
- se401->scratch[se401->scratch_next].length = length;
- if (waitqueue_active(&se401->wq))
- wake_up_interruptible(&se401->wq);
- se401->scratch_overflow = 0;
- se401->scratch_next++;
- if (se401->scratch_next >= SE401_NUMSCRATCH)
- se401->scratch_next = 0;
- break;
- }
- se401->bayeroffset += length;
- if (se401->bayeroffset >= se401->cheight * se401->cwidth)
- se401->bayeroffset = 0;
- } else {
- se401->nullpackets++;
- if (se401->nullpackets > SE401_MAX_NULLPACKETS)
- if (waitqueue_active(&se401->wq))
- wake_up_interruptible(&se401->wq);
- }
-
- /* Resubmit urb for new data */
- urb->status = 0;
- urb->dev = se401->dev;
- if (usb_submit_urb(urb, GFP_KERNEL))
- dev_info(&urb->dev->dev, "urb burned down\n");
- return;
-}
-
-static void se401_send_size(struct usb_se401 *se401, int width, int height)
-{
- int i = 0;
- int mode = 0x03; /* No compression */
- int sendheight = height;
- int sendwidth = width;
-
- /* JangGu compression can only be used with the camera supported sizes,
- but bayer seems to work with any size that fits on the sensor.
- We check if we can use compression with the current size with either
- 4 or 16 times subcapturing, if not we use uncompressed bayer data
- but this will result in cutouts of the maximum size....
- */
- while (i < se401->sizes && !(se401->width[i] == width &&
- se401->height[i] == height))
- i++;
- while (i < se401->sizes) {
- if (se401->width[i] == width * 2 &&
- se401->height[i] == height * 2) {
- sendheight = se401->height[i];
- sendwidth = se401->width[i];
- mode = 0x40;
- }
- if (se401->width[i] == width * 4 &&
- se401->height[i] == height * 4) {
- sendheight = se401->height[i];
- sendwidth = se401->width[i];
- mode = 0x42;
- }
- i++;
- }
-
- se401_sndctrl(1, se401, SE401_REQ_SET_WIDTH, sendwidth, NULL, 0);
- se401_sndctrl(1, se401, SE401_REQ_SET_HEIGHT, sendheight, NULL, 0);
- se401_set_feature(se401, SE401_OPERATINGMODE, mode);
-
- if (mode == 0x03)
- se401->format = FMT_BAYER;
- else
- se401->format = FMT_JANGGU;
-}
-
-/*
- In this function se401_send_pict is called several times,
- for some reason (depending on the state of the sensor and the phase of
- the moon :) doing this only in either place doesn't always work...
-*/
-static int se401_start_stream(struct usb_se401 *se401)
-{
- struct urb *urb;
- int err = 0, i;
- se401->streaming = 1;
-
- se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
- se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-
- /* Set picture settings */
- /* windowed + pix intg */
- se401_set_feature(se401, HV7131_REG_MODE_B, 0x05);
- se401_send_pict(se401);
-
- se401_send_size(se401, se401->cwidth, se401->cheight);
-
- se401_sndctrl(1, se401, SE401_REQ_START_CONTINUOUS_CAPTURE,
- 0, NULL, 0);
-
- /* Do some memory allocation */
- for (i = 0; i < SE401_NUMFRAMES; i++) {
- se401->frame[i].data = se401->fbuf + i * se401->maxframesize;
- se401->frame[i].curpix = 0;
- }
- for (i = 0; i < SE401_NUMSBUF; i++) {
- se401->sbuf[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
- if (!se401->sbuf[i].data) {
- for (i = i - 1; i >= 0; i--) {
- kfree(se401->sbuf[i].data);
- se401->sbuf[i].data = NULL;
- }
- return -ENOMEM;
- }
- }
-
- se401->bayeroffset = 0;
- se401->scratch_next = 0;
- se401->scratch_use = 0;
- se401->scratch_overflow = 0;
- for (i = 0; i < SE401_NUMSCRATCH; i++) {
- se401->scratch[i].data = kmalloc(SE401_PACKETSIZE, GFP_KERNEL);
- if (!se401->scratch[i].data) {
- for (i = i - 1; i >= 0; i--) {
- kfree(se401->scratch[i].data);
- se401->scratch[i].data = NULL;
- }
- goto nomem_sbuf;
- }
- se401->scratch[i].state = BUFFER_UNUSED;
- }
-
- for (i = 0; i < SE401_NUMSBUF; i++) {
- urb = usb_alloc_urb(0, GFP_KERNEL);
- if (!urb) {
- for (i = i - 1; i >= 0; i--) {
- usb_kill_urb(se401->urb[i]);
- usb_free_urb(se401->urb[i]);
- se401->urb[i] = NULL;
- }
- goto nomem_scratch;
- }
-
- usb_fill_bulk_urb(urb, se401->dev,
- usb_rcvbulkpipe(se401->dev, SE401_VIDEO_ENDPOINT),
- se401->sbuf[i].data, SE401_PACKETSIZE,
- se401_video_irq,
- se401);
-
- se401->urb[i] = urb;
-
- err = usb_submit_urb(se401->urb[i], GFP_KERNEL);
- if (err)
- err("urb burned down");
- }
-
- se401->framecount = 0;
-
- return 0;
-
- nomem_scratch:
- for (i = 0; i < SE401_NUMSCRATCH; i++) {
- kfree(se401->scratch[i].data);
- se401->scratch[i].data = NULL;
- }
- nomem_sbuf:
- for (i = 0; i < SE401_NUMSBUF; i++) {
- kfree(se401->sbuf[i].data);
- se401->sbuf[i].data = NULL;
- }
- return -ENOMEM;
-}
-
-static int se401_stop_stream(struct usb_se401 *se401)
-{
- int i;
-
- if (!se401->streaming || !se401->dev)
- return 1;
-
- se401->streaming = 0;
-
- se401_sndctrl(1, se401, SE401_REQ_STOP_CONTINUOUS_CAPTURE, 0, NULL, 0);
-
- se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
- se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
-
- for (i = 0; i < SE401_NUMSBUF; i++)
- if (se401->urb[i]) {
- usb_kill_urb(se401->urb[i]);
- usb_free_urb(se401->urb[i]);
- se401->urb[i] = NULL;
- kfree(se401->sbuf[i].data);
- }
- for (i = 0; i < SE401_NUMSCRATCH; i++) {
- kfree(se401->scratch[i].data);
- se401->scratch[i].data = NULL;
- }
-
- return 0;
-}
-
-static int se401_set_size(struct usb_se401 *se401, int width, int height)
-{
- int wasstreaming = se401->streaming;
- /* Check to see if we need to change */
- if (se401->cwidth == width && se401->cheight == height)
- return 0;
-
- /* Check for a valid mode */
- if (!width || !height)
- return 1;
- if ((width & 1) || (height & 1))
- return 1;
- if (width > se401->width[se401->sizes-1])
- return 1;
- if (height > se401->height[se401->sizes-1])
- return 1;
-
- /* Stop a current stream and start it again at the new size */
- if (wasstreaming)
- se401_stop_stream(se401);
- se401->cwidth = width;
- se401->cheight = height;
- if (wasstreaming)
- se401_start_stream(se401);
- return 0;
-}
-
-
-/****************************************************************************
- *
- * Video Decoding
- *
- ***************************************************************************/
-
-/*
- This shouldn't really be done in a v4l driver....
- But it does make the image look a lot more usable.
- Basically it lifts the dark pixels more than the light pixels.
-*/
-static inline void enhance_picture(unsigned char *frame, int len)
-{
- while (len--) {
- *frame = (((*frame^255)*(*frame^255))/255)^255;
- frame++;
- }
-}
-
-static inline void decode_JangGu_integrate(struct usb_se401 *se401, int data)
-{
- struct se401_frame *frame = &se401->frame[se401->curframe];
- int linelength = se401->cwidth * 3;
-
- if (frame->curlinepix >= linelength) {
- frame->curlinepix = 0;
- frame->curline += linelength;
- }
-
- /* First three are absolute, all others relative.
- * Format is rgb from right to left (mirrorred image),
- * we flip it to get bgr from left to right. */
- if (frame->curlinepix < 3)
- *(frame->curline-frame->curlinepix) = 1 + data * 4;
- else
- *(frame->curline-frame->curlinepix) =
- *(frame->curline-frame->curlinepix + 3) + data * 4;
- frame->curlinepix++;
-}
-
-static inline void decode_JangGu_vlc(struct usb_se401 *se401,
- unsigned char *data, int bit_exp, int packetlength)
-{
- int pos = 0;
- int vlc_cod = 0;
- int vlc_size = 0;
- int vlc_data = 0;
- int bit_cur;
- int bit;
- data += 4;
- while (pos < packetlength) {
- bit_cur = 8;
- while (bit_cur && bit_exp) {
- bit = ((*data) >> (bit_cur-1))&1;
- if (!vlc_cod) {
- if (bit) {
- vlc_size++;
- } else {
- if (!vlc_size)
- decode_JangGu_integrate(se401, 0);
- else {
- vlc_cod = 2;
- vlc_data = 0;
- }
- }
- } else {
- if (vlc_cod == 2) {
- if (!bit)
- vlc_data = -(1 << vlc_size) + 1;
- vlc_cod--;
- }
- vlc_size--;
- vlc_data += bit << vlc_size;
- if (!vlc_size) {
- decode_JangGu_integrate(se401, vlc_data);
- vlc_cod = 0;
- }
- }
- bit_cur--;
- bit_exp--;
- }
- pos++;
- data++;
- }
-}
-
-static inline void decode_JangGu(struct usb_se401 *se401,
- struct se401_scratch *buffer)
-{
- unsigned char *data = buffer->data;
- int len = buffer->length;
- int bit_exp = 0, pix_exp = 0, frameinfo = 0, packetlength = 0, size;
- int datapos = 0;
-
- /* New image? */
- if (!se401->frame[se401->curframe].curpix) {
- se401->frame[se401->curframe].curlinepix = 0;
- se401->frame[se401->curframe].curline =
- se401->frame[se401->curframe].data+
- se401->cwidth * 3 - 1;
- if (se401->frame[se401->curframe].grabstate == FRAME_READY)
- se401->frame[se401->curframe].grabstate = FRAME_GRABBING;
- se401->vlcdatapos = 0;
- }
- while (datapos < len) {
- size = 1024 - se401->vlcdatapos;
- if (size+datapos > len)
- size = len-datapos;
- memcpy(se401->vlcdata+se401->vlcdatapos, data+datapos, size);
- se401->vlcdatapos += size;
- packetlength = 0;
- if (se401->vlcdatapos >= 4) {
- bit_exp = se401->vlcdata[3] + (se401->vlcdata[2] << 8);
- pix_exp = se401->vlcdata[1] +
- ((se401->vlcdata[0] & 0x3f) << 8);
- frameinfo = se401->vlcdata[0] & 0xc0;
- packetlength = ((bit_exp + 47) >> 4) << 1;
- if (packetlength > 1024) {
- se401->vlcdatapos = 0;
- datapos = len;
- packetlength = 0;
- se401->error++;
- se401->frame[se401->curframe].curpix = 0;
- }
- }
- if (packetlength && se401->vlcdatapos >= packetlength) {
- decode_JangGu_vlc(se401, se401->vlcdata, bit_exp,
- packetlength);
- se401->frame[se401->curframe].curpix += pix_exp * 3;
- datapos += size-(se401->vlcdatapos-packetlength);
- se401->vlcdatapos = 0;
- if (se401->frame[se401->curframe].curpix >= se401->cwidth * se401->cheight * 3) {
- if (se401->frame[se401->curframe].curpix == se401->cwidth * se401->cheight * 3) {
- if (se401->frame[se401->curframe].grabstate == FRAME_GRABBING) {
- se401->frame[se401->curframe].grabstate = FRAME_DONE;
- se401->framecount++;
- se401->readcount++;
- }
- if (se401->frame[(se401->curframe + 1) & (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY)
- se401->curframe = (se401->curframe + 1) & (SE401_NUMFRAMES - 1);
- } else
- se401->error++;
- se401->frame[se401->curframe].curpix = 0;
- datapos = len;
- }
- } else
- datapos += size;
- }
-}
-
-static inline void decode_bayer(struct usb_se401 *se401,
- struct se401_scratch *buffer)
-{
- unsigned char *data = buffer->data;
- int len = buffer->length;
- int offset = buffer->offset;
- int datasize = se401->cwidth * se401->cheight;
- struct se401_frame *frame = &se401->frame[se401->curframe];
- unsigned char *framedata = frame->data, *curline, *nextline;
- int width = se401->cwidth;
- int blineoffset = 0, bline;
- int linelength = width * 3, i;
-
-
- if (frame->curpix == 0) {
- if (frame->grabstate == FRAME_READY)
- frame->grabstate = FRAME_GRABBING;
-
- frame->curline = framedata + linelength;
- frame->curlinepix = 0;
- }
-
- if (offset != frame->curpix) {
- /* Regard frame as lost :( */
- frame->curpix = 0;
- se401->error++;
- return;
- }
-
- /* Check if we have to much data */
- if (frame->curpix + len > datasize)
- len = datasize-frame->curpix;
-
- if (se401->cheight % 4)
- blineoffset = 1;
- bline = frame->curpix / se401->cwidth+blineoffset;
-
- curline = frame->curline;
- nextline = curline + linelength;
- if (nextline >= framedata+datasize * 3)
- nextline = curline;
- while (len) {
- if (frame->curlinepix >= width) {
- frame->curlinepix -= width;
- bline = frame->curpix / width + blineoffset;
- curline += linelength*2;
- nextline += linelength*2;
- if (curline >= framedata+datasize * 3) {
- frame->curlinepix++;
- curline -= 3;
- nextline -= 3;
- len--;
- data++;
- frame->curpix++;
- }
- if (nextline >= framedata+datasize*3)
- nextline = curline;
- }
- if (bline & 1) {
- if (frame->curlinepix & 1) {
- *(curline + 2) = *data;
- *(curline - 1) = *data;
- *(nextline + 2) = *data;
- *(nextline - 1) = *data;
- } else {
- *(curline + 1) =
- (*(curline + 1) + *data) / 2;
- *(curline-2) =
- (*(curline - 2) + *data) / 2;
- *(nextline + 1) = *data;
- *(nextline - 2) = *data;
- }
- } else {
- if (frame->curlinepix & 1) {
- *(curline + 1) =
- (*(curline + 1) + *data) / 2;
- *(curline - 2) =
- (*(curline - 2) + *data) / 2;
- *(nextline + 1) = *data;
- *(nextline - 2) = *data;
- } else {
- *curline = *data;
- *(curline - 3) = *data;
- *nextline = *data;
- *(nextline - 3) = *data;
- }
- }
- frame->curlinepix++;
- curline -= 3;
- nextline -= 3;
- len--;
- data++;
- frame->curpix++;
- }
- frame->curline = curline;
-
- if (frame->curpix >= datasize) {
- /* Fix the top line */
- framedata += linelength;
- for (i = 0; i < linelength; i++) {
- framedata--;
- *framedata = *(framedata + linelength);
- }
- /* Fix the left side (green is already present) */
- for (i = 0; i < se401->cheight; i++) {
- *framedata = *(framedata + 3);
- *(framedata + 1) = *(framedata + 4);
- *(framedata + 2) = *(framedata + 5);
- framedata += linelength;
- }
- frame->curpix = 0;
- frame->grabstate = FRAME_DONE;
- se401->framecount++;
- se401->readcount++;
- if (se401->frame[(se401->curframe + 1) &
- (SE401_NUMFRAMES - 1)].grabstate == FRAME_READY) {
- se401->curframe = (se401->curframe+1) &
- (SE401_NUMFRAMES-1);
- }
- }
-}
-
-static int se401_newframe(struct usb_se401 *se401, int framenr)
-{
- DECLARE_WAITQUEUE(wait, current);
- int errors = 0;
-
- while (se401->streaming &&
- (se401->frame[framenr].grabstate == FRAME_READY ||
- se401->frame[framenr].grabstate == FRAME_GRABBING)) {
- if (!se401->frame[framenr].curpix)
- errors++;
-
- wait_interruptible(
- se401->scratch[se401->scratch_use].state != BUFFER_READY,
- &se401->wq, &wait);
- if (se401->nullpackets > SE401_MAX_NULLPACKETS) {
- se401->nullpackets = 0;
- dev_info(&se401->dev->dev,
- "too many null length packets, restarting capture\n");
- se401_stop_stream(se401);
- se401_start_stream(se401);
- } else {
- if (se401->scratch[se401->scratch_use].state !=
- BUFFER_READY) {
- se401->frame[framenr].grabstate = FRAME_ERROR;
- return -EIO;
- }
- se401->scratch[se401->scratch_use].state = BUFFER_BUSY;
- if (se401->format == FMT_JANGGU)
- decode_JangGu(se401,
- &se401->scratch[se401->scratch_use]);
- else
- decode_bayer(se401,
- &se401->scratch[se401->scratch_use]);
-
- se401->scratch[se401->scratch_use].state =
- BUFFER_UNUSED;
- se401->scratch_use++;
- if (se401->scratch_use >= SE401_NUMSCRATCH)
- se401->scratch_use = 0;
- if (errors > SE401_MAX_ERRORS) {
- errors = 0;
- dev_info(&se401->dev->dev,
- "too many errors, restarting capture\n");
- se401_stop_stream(se401);
- se401_start_stream(se401);
- }
- }
- }
-
- if (se401->frame[framenr].grabstate == FRAME_DONE)
- if (se401->enhance)
- enhance_picture(se401->frame[framenr].data,
- se401->cheight * se401->cwidth * 3);
- return 0;
-}
-
-static void usb_se401_remove_disconnected(struct usb_se401 *se401)
-{
- int i;
-
- se401->dev = NULL;
-
- for (i = 0; i < SE401_NUMSBUF; i++)
- if (se401->urb[i]) {
- usb_kill_urb(se401->urb[i]);
- usb_free_urb(se401->urb[i]);
- se401->urb[i] = NULL;
- kfree(se401->sbuf[i].data);
- }
-
- for (i = 0; i < SE401_NUMSCRATCH; i++)
- kfree(se401->scratch[i].data);
-
- if (se401->inturb) {
- usb_kill_urb(se401->inturb);
- usb_free_urb(se401->inturb);
- }
- dev_info(&se401->dev->dev, "%s disconnected", se401->camera_name);
-
- /* Free the memory */
- kfree(se401->width);
- kfree(se401->height);
- kfree(se401);
-}
-
-
-
-/****************************************************************************
- *
- * Video4Linux
- *
- ***************************************************************************/
-
-
-static int se401_open(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct usb_se401 *se401 = (struct usb_se401 *)dev;
- int err = 0;
-
- lock_kernel();
- if (se401->user) {
- unlock_kernel();
- return -EBUSY;
- }
- se401->fbuf = rvmalloc(se401->maxframesize * SE401_NUMFRAMES);
- if (se401->fbuf)
- file->private_data = dev;
- else
- err = -ENOMEM;
- se401->user = !err;
- unlock_kernel();
-
- return err;
-}
-
-static int se401_close(struct file *file)
-{
- struct video_device *dev = file->private_data;
- struct usb_se401 *se401 = (struct usb_se401 *)dev;
- int i;
-
- rvfree(se401->fbuf, se401->maxframesize * SE401_NUMFRAMES);
- if (se401->removed) {
- dev_info(&se401->dev->dev, "device unregistered\n");
- usb_se401_remove_disconnected(se401);
- } else {
- for (i = 0; i < SE401_NUMFRAMES; i++)
- se401->frame[i].grabstate = FRAME_UNUSED;
- if (se401->streaming)
- se401_stop_stream(se401);
- se401->user = 0;
- }
- file->private_data = NULL;
- return 0;
-}
-
-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;
-
- if (!se401->dev)
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
- strcpy(b->name, se401->camera_name);
- b->type = VID_TYPE_CAPTURE;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = se401->width[se401->sizes-1];
- b->maxheight = se401->height[se401->sizes-1];
- b->minwidth = se401->width[0];
- b->minheight = se401->height[0];
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- strcpy(v->name, "Camera");
- return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture *p = arg;
-
- se401_get_pict(se401, p);
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture *p = arg;
-
- if (se401_set_pict(se401, p))
- return -EINVAL;
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
-
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (se401_set_size(se401, vw->width, vw->height))
- return -EINVAL;
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
-
- vw->x = 0; /* FIXME */
- vw->y = 0;
- vw->chromakey = 0;
- vw->flags = 0;
- vw->clipcount = 0;
- vw->width = se401->cwidth;
- vw->height = se401->cheight;
- return 0;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf *vm = arg;
- int i;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = SE401_NUMFRAMES * se401->maxframesize;
- vm->frames = SE401_NUMFRAMES;
- for (i = 0; i < SE401_NUMFRAMES; i++)
- vm->offsets[i] = se401->maxframesize * i;
- return 0;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap *vm = arg;
-
- if (vm->format != VIDEO_PALETTE_RGB24)
- return -EINVAL;
- if (vm->frame >= SE401_NUMFRAMES)
- return -EINVAL;
- if (se401->frame[vm->frame].grabstate != FRAME_UNUSED)
- return -EBUSY;
-
- /* Is this according to the v4l spec??? */
- if (se401_set_size(se401, vm->width, vm->height))
- return -EINVAL;
- se401->frame[vm->frame].grabstate = FRAME_READY;
-
- if (!se401->streaming)
- se401_start_stream(se401);
-
- /* Set the picture properties */
- if (se401->framecount == 0)
- se401_send_pict(se401);
- /* Calibrate the reset level after a few frames. */
- if (se401->framecount % 20 == 1)
- se401_auto_resetlevel(se401);
-
- return 0;
- }
- case VIDIOCSYNC:
- {
- int *frame = arg;
- int ret = 0;
-
- if (*frame < 0 || *frame >= SE401_NUMFRAMES)
- return -EINVAL;
-
- ret = se401_newframe(se401, *frame);
- se401->frame[*frame].grabstate = FRAME_UNUSED;
- return ret;
- }
- case VIDIOCGFBUF:
- {
- struct video_buffer *vb = arg;
-
- memset(vb, 0, sizeof(*vb));
- return 0;
- }
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- return -EINVAL;
- case VIDIOCSFBUF:
- return -EINVAL;
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- return -EINVAL;
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- return -EINVAL;
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
- default:
- return -ENOIOCTLCMD;
- } /* end switch */
-
- return 0;
-}
-
-static long se401_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(file, cmd, arg, se401_do_ioctl);
-}
-
-static ssize_t se401_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- int realcount = count, ret = 0;
- struct video_device *dev = file->private_data;
- struct usb_se401 *se401 = (struct usb_se401 *)dev;
-
-
- if (se401->dev == NULL)
- return -EIO;
- if (realcount > se401->cwidth*se401->cheight*3)
- realcount = se401->cwidth*se401->cheight*3;
-
- /* Shouldn't happen: */
- if (se401->frame[0].grabstate == FRAME_GRABBING)
- return -EBUSY;
- se401->frame[0].grabstate = FRAME_READY;
- se401->frame[1].grabstate = FRAME_UNUSED;
- se401->curframe = 0;
-
- if (!se401->streaming)
- se401_start_stream(se401);
-
- /* Set the picture properties */
- if (se401->framecount == 0)
- se401_send_pict(se401);
- /* Calibrate the reset level after a few frames. */
- if (se401->framecount%20 == 1)
- se401_auto_resetlevel(se401);
-
- ret = se401_newframe(se401, 0);
-
- se401->frame[0].grabstate = FRAME_UNUSED;
- if (ret)
- return ret;
- if (copy_to_user(buf, se401->frame[0].data, realcount))
- return -EFAULT;
-
- return realcount;
-}
-
-static int se401_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *dev = file->private_data;
- struct usb_se401 *se401 = (struct usb_se401 *)dev;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long page, pos;
-
- mutex_lock(&se401->lock);
-
- if (se401->dev == NULL) {
- mutex_unlock(&se401->lock);
- return -EIO;
- }
- if (size > (((SE401_NUMFRAMES * se401->maxframesize) + PAGE_SIZE - 1)
- & ~(PAGE_SIZE - 1))) {
- mutex_unlock(&se401->lock);
- return -EINVAL;
- }
- pos = (unsigned long)se401->fbuf;
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&se401->lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
- mutex_unlock(&se401->lock);
-
- return 0;
-}
-
-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,
-};
-static struct video_device se401_template = {
- .name = "se401 USB camera",
- .fops = &se401_fops,
- .release = video_device_release_empty,
-};
-
-
-
-/***************************/
-static int se401_init(struct usb_se401 *se401, int button)
-{
- int i = 0, rc;
- unsigned char cp[0x40];
- char temp[200];
- int slen;
-
- /* led on */
- se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
-
- /* get camera descriptor */
- rc = se401_sndctrl(0, se401, SE401_REQ_GET_CAMERA_DESCRIPTOR, 0,
- cp, sizeof(cp));
- if (cp[1] != 0x41) {
- err("Wrong descriptor type");
- return 1;
- }
- slen = snprintf(temp, 200, "ExtraFeatures: %d", cp[3]);
-
- se401->sizes = cp[4] + cp[5] * 256;
- se401->width = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
- if (!se401->width)
- return 1;
- se401->height = kmalloc(se401->sizes*sizeof(int), GFP_KERNEL);
- if (!se401->height) {
- kfree(se401->width);
- return 1;
- }
- for (i = 0; i < se401->sizes; i++) {
- se401->width[i] = cp[6 + i * 4 + 0] + cp[6 + i*4 + 1] * 256;
- se401->height[i] = cp[6 + i * 4 + 2] + cp[6 + i * 4 + 3] * 256;
- }
- slen += snprintf(temp + slen, 200 - slen, " Sizes:");
- for (i = 0; i < se401->sizes; i++) {
- slen += snprintf(temp + slen, 200 - slen,
- " %dx%d", se401->width[i], se401->height[i]);
- }
- dev_info(&se401->dev->dev, "%s\n", temp);
- se401->maxframesize = se401->width[se401->sizes-1] *
- se401->height[se401->sizes - 1] * 3;
-
- rc = se401_sndctrl(0, se401, SE401_REQ_GET_WIDTH, 0, cp, sizeof(cp));
- se401->cwidth = cp[0]+cp[1]*256;
- rc = se401_sndctrl(0, se401, SE401_REQ_GET_HEIGHT, 0, cp, sizeof(cp));
- se401->cheight = cp[0]+cp[1]*256;
-
- if (!(cp[2] & SE401_FORMAT_BAYER)) {
- err("Bayer format not supported!");
- return 1;
- }
- /* set output mode (BAYER) */
- se401_sndctrl(1, se401, SE401_REQ_SET_OUTPUT_MODE,
- SE401_FORMAT_BAYER, NULL, 0);
-
- rc = se401_sndctrl(0, se401, SE401_REQ_GET_BRT, 0, cp, sizeof(cp));
- se401->brightness = cp[0]+cp[1]*256;
- /* some default values */
- se401->resetlevel = 0x2d;
- se401->rgain = 0x20;
- se401->ggain = 0x20;
- se401->bgain = 0x20;
- se401_set_exposure(se401, 20000);
- se401->palette = VIDEO_PALETTE_RGB24;
- se401->enhance = 1;
- se401->dropped = 0;
- se401->error = 0;
- se401->framecount = 0;
- se401->readcount = 0;
-
- /* Start interrupt transfers for snapshot button */
- if (button) {
- se401->inturb = usb_alloc_urb(0, GFP_KERNEL);
- if (!se401->inturb) {
- dev_info(&se401->dev->dev,
- "Allocation of inturb failed\n");
- return 1;
- }
- usb_fill_int_urb(se401->inturb, se401->dev,
- usb_rcvintpipe(se401->dev, SE401_BUTTON_ENDPOINT),
- &se401->button, sizeof(se401->button),
- se401_button_irq,
- se401,
- 8
- );
- if (usb_submit_urb(se401->inturb, GFP_KERNEL)) {
- dev_info(&se401->dev->dev, "int urb burned down\n");
- return 1;
- }
- } else
- se401->inturb = NULL;
-
- /* Flash the led */
- se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 1, NULL, 0);
- se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 1, NULL, 0);
- se401_sndctrl(1, se401, SE401_REQ_CAMERA_POWER, 0, NULL, 0);
- se401_sndctrl(1, se401, SE401_REQ_LED_CONTROL, 0, NULL, 0);
-
- return 0;
-}
-
-static int se401_probe(struct usb_interface *intf,
- const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_interface_descriptor *interface;
- struct usb_se401 *se401;
- char *camera_name = NULL;
- int button = 1;
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- interface = &intf->cur_altsetting->desc;
-
- /* Is it an se401? */
- if (le16_to_cpu(dev->descriptor.idVendor) == 0x03e8 &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x0004) {
- camera_name = "Endpoints/Aox SE401";
- } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x0471 &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x030b) {
- camera_name = "Philips PCVC665K";
- } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x5001) {
- camera_name = "Kensington VideoCAM 67014";
- } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x5002) {
- camera_name = "Kensington VideoCAM 6701(5/7)";
- } else if (le16_to_cpu(dev->descriptor.idVendor) == 0x047d &&
- le16_to_cpu(dev->descriptor.idProduct) == 0x5003) {
- camera_name = "Kensington VideoCAM 67016";
- button = 0;
- } else
- return -ENODEV;
-
- /* Checking vendor/product should be enough, but what the hell */
- if (interface->bInterfaceClass != 0x00)
- return -ENODEV;
- if (interface->bInterfaceSubClass != 0x00)
- return -ENODEV;
-
- /* We found one */
- dev_info(&intf->dev, "SE401 camera found: %s\n", camera_name);
-
- se401 = kzalloc(sizeof(*se401), GFP_KERNEL);
- if (se401 == NULL) {
- err("couldn't kmalloc se401 struct");
- return -ENOMEM;
- }
-
- se401->dev = dev;
- se401->iface = interface->bInterfaceNumber;
- se401->camera_name = camera_name;
-
- dev_info(&intf->dev, "firmware version: %02x\n",
- le16_to_cpu(dev->descriptor.bcdDevice) & 255);
-
- if (se401_init(se401, button)) {
- kfree(se401);
- return -EIO;
- }
-
- memcpy(&se401->vdev, &se401_template, sizeof(se401_template));
- memcpy(se401->vdev.name, se401->camera_name,
- strlen(se401->camera_name));
- init_waitqueue_head(&se401->wq);
- mutex_init(&se401->lock);
- wmb();
-
- if (video_register_device(&se401->vdev,
- VFL_TYPE_GRABBER, video_nr) < 0) {
- kfree(se401);
- err("video_register_device failed");
- return -EIO;
- }
- dev_info(&intf->dev, "registered new video device: %s\n",
- video_device_node_name(&se401->vdev));
-
- usb_set_intfdata(intf, se401);
- return 0;
-}
-
-static void se401_disconnect(struct usb_interface *intf)
-{
- struct usb_se401 *se401 = usb_get_intfdata(intf);
-
- usb_set_intfdata(intf, NULL);
- if (se401) {
- video_unregister_device(&se401->vdev);
- if (!se401->user)
- usb_se401_remove_disconnected(se401);
- else {
- se401->frame[0].grabstate = FRAME_ERROR;
- se401->frame[0].grabstate = FRAME_ERROR;
-
- se401->streaming = 0;
-
- wake_up_interruptible(&se401->wq);
- se401->removed = 1;
- }
- }
-}
-
-static struct usb_driver se401_driver = {
- .name = "se401",
- .id_table = device_table,
- .probe = se401_probe,
- .disconnect = se401_disconnect,
-};
-
-
-
-/****************************************************************************
- *
- * Module routines
- *
- ***************************************************************************/
-
-static int __init usb_se401_init(void)
-{
- printk(KERN_INFO "SE401 usb camera driver version %s registering\n",
- version);
- if (flickerless)
- if (flickerless != 50 && flickerless != 60) {
- printk(KERN_ERR "Invallid flickerless value, use 0, 50 or 60.\n");
- return -1;
- }
- return usb_register(&se401_driver);
-}
-
-static void __exit usb_se401_exit(void)
-{
- usb_deregister(&se401_driver);
- printk(KERN_INFO "SE401 driver deregistered\frame");
-}
-
-module_init(usb_se401_init);
-module_exit(usb_se401_exit);
diff --git a/drivers/media/video/se401.h b/drivers/media/video/se401.h
deleted file mode 100644
index bf7d2e9765b0..000000000000
--- a/drivers/media/video/se401.h
+++ /dev/null
@@ -1,236 +0,0 @@
-
-#ifndef __LINUX_se401_H
-#define __LINUX_se401_H
-
-#include <linux/uaccess.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/mutex.h>
-
-#define se401_DEBUG /* Turn on debug messages */
-
-#ifdef se401_DEBUG
-# define PDEBUG(level, fmt, args...) \
-if (debug >= level) \
- info("[" __PRETTY_FUNCTION__ ":%d] " fmt, __LINE__ , ## args)
-#else
-# define PDEBUG(level, fmt, args...) do {} while (0)
-#endif
-
-/* An almost drop-in replacement for sleep_on_interruptible */
-#define wait_interruptible(test, queue, wait) \
-{ \
- add_wait_queue(queue, wait); \
- set_current_state(TASK_INTERRUPTIBLE); \
- if (test) \
- schedule(); \
- remove_wait_queue(queue, wait); \
- set_current_state(TASK_RUNNING); \
- if (signal_pending(current)) \
- break; \
-}
-
-#define SE401_REQ_GET_CAMERA_DESCRIPTOR 0x06
-#define SE401_REQ_START_CONTINUOUS_CAPTURE 0x41
-#define SE401_REQ_STOP_CONTINUOUS_CAPTURE 0x42
-#define SE401_REQ_CAPTURE_FRAME 0x43
-#define SE401_REQ_GET_BRT 0x44
-#define SE401_REQ_SET_BRT 0x45
-#define SE401_REQ_GET_WIDTH 0x4c
-#define SE401_REQ_SET_WIDTH 0x4d
-#define SE401_REQ_GET_HEIGHT 0x4e
-#define SE401_REQ_SET_HEIGHT 0x4f
-#define SE401_REQ_GET_OUTPUT_MODE 0x50
-#define SE401_REQ_SET_OUTPUT_MODE 0x51
-#define SE401_REQ_GET_EXT_FEATURE 0x52
-#define SE401_REQ_SET_EXT_FEATURE 0x53
-#define SE401_REQ_CAMERA_POWER 0x56
-#define SE401_REQ_LED_CONTROL 0x57
-#define SE401_REQ_BIOS 0xff
-
-#define SE401_BIOS_READ 0x07
-
-#define SE401_FORMAT_BAYER 0x40
-
-/* Hyundai hv7131b registers
- 7121 and 7141 should be the same (haven't really checked...) */
-/* Mode registers: */
-#define HV7131_REG_MODE_A 0x00
-#define HV7131_REG_MODE_B 0x01
-#define HV7131_REG_MODE_C 0x02
-/* Frame registers: */
-#define HV7131_REG_FRSU 0x10
-#define HV7131_REG_FRSL 0x11
-#define HV7131_REG_FCSU 0x12
-#define HV7131_REG_FCSL 0x13
-#define HV7131_REG_FWHU 0x14
-#define HV7131_REG_FWHL 0x15
-#define HV7131_REG_FWWU 0x16
-#define HV7131_REG_FWWL 0x17
-/* Timing registers: */
-#define HV7131_REG_THBU 0x20
-#define HV7131_REG_THBL 0x21
-#define HV7131_REG_TVBU 0x22
-#define HV7131_REG_TVBL 0x23
-#define HV7131_REG_TITU 0x25
-#define HV7131_REG_TITM 0x26
-#define HV7131_REG_TITL 0x27
-#define HV7131_REG_TMCD 0x28
-/* Adjust Registers: */
-#define HV7131_REG_ARLV 0x30
-#define HV7131_REG_ARCG 0x31
-#define HV7131_REG_AGCG 0x32
-#define HV7131_REG_ABCG 0x33
-#define HV7131_REG_APBV 0x34
-#define HV7131_REG_ASLP 0x54
-/* Offset Registers: */
-#define HV7131_REG_OFSR 0x50
-#define HV7131_REG_OFSG 0x51
-#define HV7131_REG_OFSB 0x52
-/* REset level statistics registers: */
-#define HV7131_REG_LOREFNOH 0x57
-#define HV7131_REG_LOREFNOL 0x58
-#define HV7131_REG_HIREFNOH 0x59
-#define HV7131_REG_HIREFNOL 0x5a
-
-/* se401 registers */
-#define SE401_OPERATINGMODE 0x2000
-
-
-/* size of usb transfers */
-#define SE401_PACKETSIZE 4096
-/* number of queued bulk transfers to use, should be about 8 */
-#define SE401_NUMSBUF 1
-/* read the usb specs for this one :) */
-#define SE401_VIDEO_ENDPOINT 1
-#define SE401_BUTTON_ENDPOINT 2
-/* number of frames supported by the v4l part */
-#define SE401_NUMFRAMES 2
-/* scratch buffers for passing data to the decoders */
-#define SE401_NUMSCRATCH 32
-/* maximum amount of data in a JangGu packet */
-#define SE401_VLCDATALEN 1024
-/* number of nul sized packets to receive before kicking the camera */
-#define SE401_MAX_NULLPACKETS 4000
-/* number of decoding errors before kicking the camera */
-#define SE401_MAX_ERRORS 200
-
-struct usb_device;
-
-struct se401_sbuf {
- unsigned char *data;
-};
-
-enum {
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
- FRAME_READY, /* Ready to start grabbing */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_ERROR, /* Something bad happened while processing */
-};
-
-enum {
- FMT_BAYER,
- FMT_JANGGU,
-};
-
-enum {
- BUFFER_UNUSED,
- BUFFER_READY,
- BUFFER_BUSY,
- BUFFER_DONE,
-};
-
-struct se401_scratch {
- unsigned char *data;
- volatile int state;
- int offset;
- int length;
-};
-
-struct se401_frame {
- unsigned char *data; /* Frame buffer */
-
- volatile int grabstate; /* State of grabbing */
-
- unsigned char *curline;
- int curlinepix;
- int curpix;
-};
-
-struct usb_se401 {
- struct video_device vdev;
-
- /* Device structure */
- struct usb_device *dev;
-
- unsigned char iface;
-
- char *camera_name;
-
- int change;
- int brightness;
- int hue;
- int rgain;
- int ggain;
- int bgain;
- int expose_h;
- int expose_m;
- int expose_l;
- int resetlevel;
-
- int enhance;
-
- int format;
- int sizes;
- int *width;
- int *height;
- int cwidth; /* current width */
- int cheight; /* current height */
- int palette;
- int maxframesize;
- int cframesize; /* current framesize */
-
- struct mutex lock;
- int user; /* user count for exclusive use */
- int removed; /* device disconnected */
-
- int streaming; /* Are we streaming video? */
-
- char *fbuf; /* Videodev buffer area */
-
- struct urb *urb[SE401_NUMSBUF];
- struct urb *inturb;
-
- int button;
- int buttonpressed;
-
- int curframe; /* Current receiving frame */
- struct se401_frame frame[SE401_NUMFRAMES];
- int readcount;
- int framecount;
- int error;
- int dropped;
-
- int scratch_next;
- int scratch_use;
- int scratch_overflow;
- struct se401_scratch scratch[SE401_NUMSCRATCH];
-
- /* Decoder specific data: */
- unsigned char vlcdata[SE401_VLCDATALEN];
- int vlcdatapos;
- int bayeroffset;
-
- struct se401_sbuf sbuf[SE401_NUMSBUF];
-
- wait_queue_head_t wq; /* Processes waiting */
-
- int nullpackets;
-};
-
-
-
-#endif
-
diff --git a/drivers/media/video/sh_mobile_ceu_camera.c b/drivers/media/video/sh_mobile_ceu_camera.c
index 4ac3b482fbb4..954222bc3458 100644
--- a/drivers/media/video/sh_mobile_ceu_camera.c
+++ b/drivers/media/video/sh_mobile_ceu_camera.c
@@ -245,7 +245,7 @@ static void free_buffer(struct videobuf_queue *vq,
if (in_interrupt())
BUG();
- videobuf_waiton(&buf->vb, 0, 0);
+ videobuf_waiton(vq, &buf->vb, 0, 0);
videobuf_dma_contig_free(vq, &buf->vb);
dev_dbg(dev, "%s freed\n", __func__);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
@@ -633,6 +633,12 @@ static void sh_mobile_ceu_set_rect(struct soc_camera_device *icd)
cdwdr_width *= 2;
}
+ /* CSI2 special configuration */
+ if (pcdev->pdata->csi2_dev) {
+ in_width = ((in_width - 2) * 2);
+ left_offset *= 2;
+ }
+
/* Set CAMOR, CAPWR, CFSZR, take care of CDWDR */
camor = left_offset | (top_offset << 16);
@@ -743,16 +749,16 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
case V4L2_PIX_FMT_NV16:
case V4L2_PIX_FMT_NV61:
switch (cam->code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
value = 0x00000000; /* Cb0, Y0, Cr0, Y1 */
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
value = 0x00000100; /* Cr0, Y0, Cb0, Y1 */
break;
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
value = 0x00000200; /* Y0, Cb0, Y1, Cr0 */
break;
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
value = 0x00000300; /* Y0, Cr0, Y1, Cb0 */
break;
default:
@@ -767,6 +773,11 @@ static int sh_mobile_ceu_set_bus_param(struct soc_camera_device *icd,
value |= common_flags & SOCAM_VSYNC_ACTIVE_LOW ? 1 << 1 : 0;
value |= common_flags & SOCAM_HSYNC_ACTIVE_LOW ? 1 << 0 : 0;
value |= pcdev->is_16bit ? 1 << 12 : 0;
+
+ /* CSI2 mode */
+ if (pcdev->pdata->csi2_dev)
+ value |= 3 << 12;
+
ceu_write(pcdev, CAMCR, value);
ceu_write(pcdev, CAPCR, 0x00300000);
@@ -878,11 +889,13 @@ static bool sh_mobile_ceu_packing_supported(const struct soc_mbus_pixelfmt *fmt)
static int client_g_rect(struct v4l2_subdev *sd, struct v4l2_rect *rect);
-static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
+static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, unsigned int idx,
struct soc_camera_format_xlate *xlate)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct device *dev = icd->dev.parent;
+ struct soc_camera_host *ici = to_soc_camera_host(dev);
+ struct sh_mobile_ceu_dev *pcdev = ici->priv;
int ret, k, n;
int formats = 0;
struct sh_mobile_ceu_cam *cam;
@@ -896,19 +909,19 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
fmt = soc_mbus_get_fmtdesc(code);
if (!fmt) {
- dev_err(icd->dev.parent,
- "Invalid format code #%d: %d\n", idx, code);
+ dev_err(dev, "Invalid format code #%u: %d\n", idx, code);
return -EINVAL;
}
- ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
- if (ret < 0)
- return 0;
+ if (!pcdev->pdata->csi2_dev) {
+ ret = sh_mobile_ceu_try_bus_param(icd, fmt->bits_per_sample);
+ if (ret < 0)
+ return 0;
+ }
if (!icd->host_priv) {
struct v4l2_mbus_framefmt mf;
struct v4l2_rect rect;
- struct device *dev = icd->dev.parent;
int shift = 0;
/* FIXME: subwindow is lost between close / open */
@@ -927,7 +940,8 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
/* Try 2560x1920, 1280x960, 640x480, 320x240 */
mf.width = 2560 >> shift;
mf.height = 1920 >> shift;
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, &mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ s_mbus_fmt, &mf);
if (ret < 0)
return ret;
shift++;
@@ -965,10 +979,10 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
cam->extra_fmt = NULL;
switch (code) {
- case V4L2_MBUS_FMT_YUYV8_2X8_BE:
- case V4L2_MBUS_FMT_YVYU8_2X8_BE:
- case V4L2_MBUS_FMT_YUYV8_2X8_LE:
- case V4L2_MBUS_FMT_YVYU8_2X8_LE:
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ case V4L2_MBUS_FMT_VYUY8_2X8:
+ case V4L2_MBUS_FMT_YUYV8_2X8:
+ case V4L2_MBUS_FMT_YVYU8_2X8:
if (cam->extra_fmt)
break;
@@ -1005,7 +1019,7 @@ static int sh_mobile_ceu_get_formats(struct soc_camera_device *icd, int idx,
xlate->code = code;
xlate++;
dev_dbg(dev, "Providing format %s in pass-through mode\n",
- xlate->host_fmt->name);
+ fmt->name);
}
return formats;
@@ -1228,7 +1242,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
struct v4l2_cropcap cap;
int ret;
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ s_mbus_fmt, mf);
if (ret < 0)
return ret;
@@ -1257,7 +1272,8 @@ static int client_s_fmt(struct soc_camera_device *icd,
tmp_h = min(2 * tmp_h, max_height);
mf->width = tmp_w;
mf->height = tmp_h;
- ret = v4l2_subdev_call(sd, video, s_mbus_fmt, mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ s_mbus_fmt, mf);
dev_geo(dev, "Camera scaled to %ux%u\n",
mf->width, mf->height);
if (ret < 0) {
@@ -1514,7 +1530,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
struct device *dev = icd->dev.parent;
__u32 pixfmt = pix->pixelformat;
const struct soc_camera_format_xlate *xlate;
- unsigned int ceu_sub_width, ceu_sub_height;
+ /* Keep Compiler Happy */
+ unsigned int ceu_sub_width = 0, ceu_sub_height = 0;
u16 scale_v, scale_h;
int ret;
bool image_mode;
@@ -1569,8 +1586,8 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
/* Done with the camera. Now see if we can improve the result */
- dev_geo(dev, "Camera %d fmt %ux%u, requested %ux%u\n",
- ret, mf.width, mf.height, pix->width, pix->height);
+ dev_geo(dev, "fmt %ux%u, requested %ux%u\n",
+ mf.width, mf.height, pix->width, pix->height);
if (ret < 0)
return ret;
@@ -1634,6 +1651,9 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
int width, height;
int ret;
+ dev_geo(icd->dev.parent, "TRY_FMT(pix=0x%x, %ux%u)\n",
+ pixfmt, pix->width, pix->height);
+
xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
if (!xlate) {
dev_warn(icd->dev.parent, "Format %x not found\n", pixfmt);
@@ -1660,7 +1680,7 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
mf.code = xlate->code;
mf.colorspace = pix->colorspace;
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video, try_mbus_fmt, &mf);
if (ret < 0)
return ret;
@@ -1684,7 +1704,8 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
*/
mf.width = 2560;
mf.height = 1920;
- ret = v4l2_subdev_call(sd, video, try_mbus_fmt, &mf);
+ ret = v4l2_device_call_until_err(sd->v4l2_dev, 0, video,
+ try_mbus_fmt, &mf);
if (ret < 0) {
/* Shouldn't actually happen... */
dev_err(icd->dev.parent,
@@ -1699,10 +1720,13 @@ static int sh_mobile_ceu_try_fmt(struct soc_camera_device *icd,
pix->height = height;
}
+ dev_geo(icd->dev.parent, "%s(): return %d, fmt 0x%x, %ux%u\n",
+ __func__, ret, pix->pixelformat, pix->width, pix->height);
+
return ret;
}
-static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
+static int sh_mobile_ceu_reqbufs(struct soc_camera_device *icd,
struct v4l2_requestbuffers *p)
{
int i;
@@ -1716,7 +1740,7 @@ static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
for (i = 0; i < p->count; i++) {
struct sh_mobile_ceu_buffer *buf;
- buf = container_of(icf->vb_vidq.bufs[i],
+ buf = container_of(icd->vb_vidq.bufs[i],
struct sh_mobile_ceu_buffer, vb);
INIT_LIST_HEAD(&buf->vb.queue);
}
@@ -1726,10 +1750,10 @@ static int sh_mobile_ceu_reqbufs(struct soc_camera_file *icf,
static unsigned int sh_mobile_ceu_poll(struct file *file, poll_table *pt)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
struct sh_mobile_ceu_buffer *buf;
- buf = list_entry(icf->vb_vidq.stream.next,
+ buf = list_entry(icd->vb_vidq.stream.next,
struct sh_mobile_ceu_buffer, vb.stream);
poll_wait(file, &buf->vb.done, pt);
@@ -1762,23 +1786,7 @@ static void sh_mobile_ceu_init_videobuf(struct videobuf_queue *q,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
pcdev->field,
sizeof(struct sh_mobile_ceu_buffer),
- icd);
-}
-
-static int sh_mobile_ceu_get_parm(struct soc_camera_device *icd,
- struct v4l2_streamparm *parm)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, video, g_parm, parm);
-}
-
-static int sh_mobile_ceu_set_parm(struct soc_camera_device *icd,
- struct v4l2_streamparm *parm)
-{
- struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
-
- return v4l2_subdev_call(sd, video, s_parm, parm);
+ icd, &icd->video_lock);
}
static int sh_mobile_ceu_get_ctrl(struct soc_camera_device *icd,
@@ -1842,8 +1850,6 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.try_fmt = sh_mobile_ceu_try_fmt,
.set_ctrl = sh_mobile_ceu_set_ctrl,
.get_ctrl = sh_mobile_ceu_get_ctrl,
- .set_parm = sh_mobile_ceu_set_parm,
- .get_parm = sh_mobile_ceu_get_parm,
.reqbufs = sh_mobile_ceu_reqbufs,
.poll = sh_mobile_ceu_poll,
.querycap = sh_mobile_ceu_querycap,
@@ -1853,6 +1859,30 @@ static struct soc_camera_host_ops sh_mobile_ceu_host_ops = {
.num_controls = ARRAY_SIZE(sh_mobile_ceu_controls),
};
+struct bus_wait {
+ struct notifier_block notifier;
+ struct completion completion;
+ struct device *dev;
+};
+
+static int bus_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct bus_wait *wait = container_of(nb, struct bus_wait, notifier);
+
+ if (wait->dev != dev)
+ return NOTIFY_DONE;
+
+ switch (action) {
+ case BUS_NOTIFY_UNBOUND_DRIVER:
+ /* Protect from module unloading */
+ wait_for_completion(&wait->completion);
+ return NOTIFY_OK;
+ }
+ return NOTIFY_DONE;
+}
+
static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
{
struct sh_mobile_ceu_dev *pcdev;
@@ -1860,6 +1890,11 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
void __iomem *base;
unsigned int irq;
int err = 0;
+ struct bus_wait wait = {
+ .completion = COMPLETION_INITIALIZER_ONSTACK(wait.completion),
+ .notifier.notifier_call = bus_notify,
+ };
+ struct device *csi2;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
irq = platform_get_irq(pdev, 0);
@@ -1931,12 +1966,54 @@ static int __devinit sh_mobile_ceu_probe(struct platform_device *pdev)
pcdev->ici.drv_name = dev_name(&pdev->dev);
pcdev->ici.ops = &sh_mobile_ceu_host_ops;
+ /* CSI2 interfacing */
+ csi2 = pcdev->pdata->csi2_dev;
+ if (csi2) {
+ wait.dev = csi2;
+
+ err = bus_register_notifier(&platform_bus_type, &wait.notifier);
+ if (err < 0)
+ goto exit_free_clk;
+
+ /*
+ * From this point the driver module will not unload, until
+ * we complete the completion.
+ */
+
+ if (!csi2->driver) {
+ complete(&wait.completion);
+ /* Either too late, or probing failed */
+ bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+ err = -ENXIO;
+ goto exit_free_clk;
+ }
+
+ /*
+ * The module is still loaded, in the worst case it is hanging
+ * in device release on our completion. So, _now_ dereferencing
+ * the "owner" is safe!
+ */
+
+ err = try_module_get(csi2->driver->owner);
+
+ /* Let notifier complete, if it has been locked */
+ complete(&wait.completion);
+ bus_unregister_notifier(&platform_bus_type, &wait.notifier);
+ if (!err) {
+ err = -ENODEV;
+ goto exit_free_clk;
+ }
+ }
+
err = soc_camera_host_register(&pcdev->ici);
if (err)
- goto exit_free_clk;
+ goto exit_module_put;
return 0;
+exit_module_put:
+ if (csi2 && csi2->driver)
+ module_put(csi2->driver->owner);
exit_free_clk:
pm_runtime_disable(&pdev->dev);
free_irq(pcdev->irq, pcdev);
@@ -1956,6 +2033,7 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
struct soc_camera_host *soc_host = to_soc_camera_host(&pdev->dev);
struct sh_mobile_ceu_dev *pcdev = container_of(soc_host,
struct sh_mobile_ceu_dev, ici);
+ struct device *csi2 = pcdev->pdata->csi2_dev;
soc_camera_host_unregister(soc_host);
pm_runtime_disable(&pdev->dev);
@@ -1963,7 +2041,10 @@ static int __devexit sh_mobile_ceu_remove(struct platform_device *pdev)
if (platform_get_resource(pdev, IORESOURCE_MEM, 1))
dma_release_declared_memory(&pdev->dev);
iounmap(pcdev->base);
+ if (csi2 && csi2->driver)
+ module_put(csi2->driver->owner);
kfree(pcdev);
+
return 0;
}
@@ -1995,6 +2076,8 @@ static struct platform_driver sh_mobile_ceu_driver = {
static int __init sh_mobile_ceu_init(void)
{
+ /* Whatever return code */
+ request_module("sh_mobile_csi2");
return platform_driver_register(&sh_mobile_ceu_driver);
}
diff --git a/drivers/media/video/sh_mobile_csi2.c b/drivers/media/video/sh_mobile_csi2.c
new file mode 100644
index 000000000000..84a646819318
--- /dev/null
+++ b/drivers/media/video/sh_mobile_csi2.c
@@ -0,0 +1,354 @@
+/*
+ * Driver for the SH-Mobile MIPI CSI-2 unit
+ *
+ * Copyright (C) 2010, Guennadi Liakhovetski <g.liakhovetski@gmx.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/delay.h>
+#include <linux/i2c.h>
+#include <linux/io.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/videodev2.h>
+
+#include <media/sh_mobile_csi2.h>
+#include <media/soc_camera.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-mediabus.h>
+#include <media/v4l2-subdev.h>
+
+#define SH_CSI2_TREF 0x00
+#define SH_CSI2_SRST 0x04
+#define SH_CSI2_PHYCNT 0x08
+#define SH_CSI2_CHKSUM 0x0C
+#define SH_CSI2_VCDT 0x10
+
+struct sh_csi2 {
+ struct v4l2_subdev subdev;
+ struct list_head list;
+ struct notifier_block notifier;
+ unsigned int irq;
+ void __iomem *base;
+ struct platform_device *pdev;
+ struct sh_csi2_client_config *client;
+};
+
+static int sh_csi2_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+ struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+
+ if (mf->width > 8188)
+ mf->width = 8188;
+ else if (mf->width & 1)
+ mf->width &= ~1;
+
+ switch (pdata->type) {
+ case SH_CSI2C:
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8: /* YUV422 */
+ case V4L2_MBUS_FMT_YUYV8_1_5X8: /* YUV420 */
+ case V4L2_MBUS_FMT_GREY8_1X8: /* RAW8 */
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ break;
+ default:
+ /* All MIPI CSI-2 devices must support one of primary formats */
+ mf->code = V4L2_MBUS_FMT_YUYV8_2X8;
+ }
+ break;
+ case SH_CSI2I:
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_GREY8_1X8: /* RAW8 */
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ case V4L2_MBUS_FMT_SBGGR10_1X10: /* RAW10 */
+ case V4L2_MBUS_FMT_SBGGR12_1X12: /* RAW12 */
+ break;
+ default:
+ /* All MIPI CSI-2 devices must support one of primary formats */
+ mf->code = V4L2_MBUS_FMT_SBGGR8_1X8;
+ }
+ break;
+ }
+
+ return 0;
+}
+
+/*
+ * We have done our best in try_fmt to try and tell the sensor, which formats
+ * we support. If now the configuration is unsuitable for us we can only
+ * error out.
+ */
+static int sh_csi2_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct sh_csi2 *priv = container_of(sd, struct sh_csi2, subdev);
+ u32 tmp = (priv->client->channel & 3) << 8;
+
+ dev_dbg(sd->v4l2_dev->dev, "%s(%u)\n", __func__, mf->code);
+ if (mf->width > 8188 || mf->width & 1)
+ return -EINVAL;
+
+ switch (mf->code) {
+ case V4L2_MBUS_FMT_UYVY8_2X8:
+ tmp |= 0x1e; /* YUV422 8 bit */
+ break;
+ case V4L2_MBUS_FMT_YUYV8_1_5X8:
+ tmp |= 0x18; /* YUV420 8 bit */
+ break;
+ case V4L2_MBUS_FMT_RGB555_2X8_PADHI_BE:
+ tmp |= 0x21; /* RGB555 */
+ break;
+ case V4L2_MBUS_FMT_RGB565_2X8_BE:
+ tmp |= 0x22; /* RGB565 */
+ break;
+ case V4L2_MBUS_FMT_GREY8_1X8:
+ case V4L2_MBUS_FMT_SBGGR8_1X8:
+ case V4L2_MBUS_FMT_SGRBG8_1X8:
+ tmp |= 0x2a; /* RAW8 */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ iowrite32(tmp, priv->base + SH_CSI2_VCDT);
+
+ return 0;
+}
+
+static struct v4l2_subdev_video_ops sh_csi2_subdev_video_ops = {
+ .s_mbus_fmt = sh_csi2_s_fmt,
+ .try_mbus_fmt = sh_csi2_try_fmt,
+};
+
+static struct v4l2_subdev_core_ops sh_csi2_subdev_core_ops;
+
+static struct v4l2_subdev_ops sh_csi2_subdev_ops = {
+ .core = &sh_csi2_subdev_core_ops,
+ .video = &sh_csi2_subdev_video_ops,
+};
+
+static void sh_csi2_hwinit(struct sh_csi2 *priv)
+{
+ struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+ __u32 tmp = 0x10; /* Enable MIPI CSI clock lane */
+
+ /* Reflect registers immediately */
+ iowrite32(0x00000001, priv->base + SH_CSI2_TREF);
+ /* reset CSI2 harware */
+ iowrite32(0x00000001, priv->base + SH_CSI2_SRST);
+ udelay(5);
+ iowrite32(0x00000000, priv->base + SH_CSI2_SRST);
+
+ if (priv->client->lanes & 3)
+ tmp |= priv->client->lanes & 3;
+ else
+ /* Default - both lanes */
+ tmp |= 3;
+
+ if (priv->client->phy == SH_CSI2_PHY_MAIN)
+ tmp |= 0x8000;
+
+ iowrite32(tmp, priv->base + SH_CSI2_PHYCNT);
+
+ tmp = 0;
+ if (pdata->flags & SH_CSI2_ECC)
+ tmp |= 2;
+ if (pdata->flags & SH_CSI2_CRC)
+ tmp |= 1;
+ iowrite32(tmp, priv->base + SH_CSI2_CHKSUM);
+}
+
+static int sh_csi2_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ return 0;
+}
+
+static unsigned long sh_csi2_query_bus_param(struct soc_camera_device *icd)
+{
+ struct soc_camera_link *icl = to_soc_camera_link(icd);
+ const unsigned long flags = SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_MASTER | SOCAM_DATAWIDTH_8 | SOCAM_DATA_ACTIVE_HIGH;
+
+ return soc_camera_apply_sensor_flags(icl, flags);
+}
+
+static int sh_csi2_notify(struct notifier_block *nb,
+ unsigned long action, void *data)
+{
+ struct device *dev = data;
+ struct soc_camera_device *icd = to_soc_camera_dev(dev);
+ struct v4l2_device *v4l2_dev = dev_get_drvdata(dev->parent);
+ struct sh_csi2 *priv =
+ container_of(nb, struct sh_csi2, notifier);
+ struct sh_csi2_pdata *pdata = priv->pdev->dev.platform_data;
+ int ret, i;
+
+ for (i = 0; i < pdata->num_clients; i++)
+ if (&pdata->clients[i].pdev->dev == icd->pdev)
+ break;
+
+ dev_dbg(dev, "%s(%p): action = %lu, found #%d\n", __func__, dev, action, i);
+
+ if (i == pdata->num_clients)
+ return NOTIFY_DONE;
+
+ switch (action) {
+ case BUS_NOTIFY_BOUND_DRIVER:
+ snprintf(priv->subdev.name, V4L2_SUBDEV_NAME_SIZE, "%s%s",
+ dev_name(v4l2_dev->dev), ".mipi-csi");
+ ret = v4l2_device_register_subdev(v4l2_dev, &priv->subdev);
+ dev_dbg(dev, "%s(%p): ret(register_subdev) = %d\n", __func__, priv, ret);
+ if (ret < 0)
+ return NOTIFY_DONE;
+
+ priv->client = pdata->clients + i;
+
+ icd->ops->set_bus_param = sh_csi2_set_bus_param;
+ icd->ops->query_bus_param = sh_csi2_query_bus_param;
+
+ pm_runtime_get_sync(v4l2_get_subdevdata(&priv->subdev));
+
+ sh_csi2_hwinit(priv);
+ break;
+ case BUS_NOTIFY_UNBIND_DRIVER:
+ priv->client = NULL;
+
+ /* Driver is about to be unbound */
+ icd->ops->set_bus_param = NULL;
+ icd->ops->query_bus_param = NULL;
+
+ v4l2_device_unregister_subdev(&priv->subdev);
+
+ pm_runtime_put(v4l2_get_subdevdata(&priv->subdev));
+ break;
+ }
+
+ return NOTIFY_OK;
+}
+
+static __devinit int sh_csi2_probe(struct platform_device *pdev)
+{
+ struct resource *res;
+ unsigned int irq;
+ int ret;
+ struct sh_csi2 *priv;
+ /* Platform data specify the PHY, lanes, ECC, CRC */
+ struct sh_csi2_pdata *pdata = pdev->dev.platform_data;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ /* Interrupt unused so far */
+ irq = platform_get_irq(pdev, 0);
+
+ if (!res || (int)irq <= 0 || !pdata) {
+ dev_err(&pdev->dev, "Not enough CSI2 platform resources.\n");
+ return -ENODEV;
+ }
+
+ /* TODO: Add support for CSI2I. Careful: different register layout! */
+ if (pdata->type != SH_CSI2C) {
+ dev_err(&pdev->dev, "Only CSI2C supported ATM.\n");
+ return -EINVAL;
+ }
+
+ priv = kzalloc(sizeof(struct sh_csi2), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+
+ priv->irq = irq;
+ priv->notifier.notifier_call = sh_csi2_notify;
+
+ /* We MUST attach after the MIPI sensor */
+ ret = bus_register_notifier(&soc_camera_bus_type, &priv->notifier);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "CSI2 cannot register notifier\n");
+ goto ernotify;
+ }
+
+ if (!request_mem_region(res->start, resource_size(res), pdev->name)) {
+ dev_err(&pdev->dev, "CSI2 register region already claimed\n");
+ ret = -EBUSY;
+ goto ereqreg;
+ }
+
+ priv->base = ioremap(res->start, resource_size(res));
+ if (!priv->base) {
+ ret = -ENXIO;
+ dev_err(&pdev->dev, "Unable to ioremap CSI2 registers.\n");
+ goto eremap;
+ }
+
+ priv->pdev = pdev;
+
+ v4l2_subdev_init(&priv->subdev, &sh_csi2_subdev_ops);
+ v4l2_set_subdevdata(&priv->subdev, &pdev->dev);
+
+ platform_set_drvdata(pdev, priv);
+
+ pm_runtime_enable(&pdev->dev);
+
+ dev_dbg(&pdev->dev, "CSI2 probed.\n");
+
+ return 0;
+
+eremap:
+ release_mem_region(res->start, resource_size(res));
+ereqreg:
+ bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+ernotify:
+ kfree(priv);
+
+ return ret;
+}
+
+static __devexit int sh_csi2_remove(struct platform_device *pdev)
+{
+ struct sh_csi2 *priv = platform_get_drvdata(pdev);
+ struct resource *res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+
+ bus_unregister_notifier(&soc_camera_bus_type, &priv->notifier);
+ pm_runtime_disable(&pdev->dev);
+ iounmap(priv->base);
+ release_mem_region(res->start, resource_size(res));
+ platform_set_drvdata(pdev, NULL);
+ kfree(priv);
+
+ return 0;
+}
+
+static struct platform_driver __refdata sh_csi2_pdrv = {
+ .remove = __devexit_p(sh_csi2_remove),
+ .driver = {
+ .name = "sh-mobile-csi2",
+ .owner = THIS_MODULE,
+ },
+};
+
+static int __init sh_csi2_init(void)
+{
+ return platform_driver_probe(&sh_csi2_pdrv, sh_csi2_probe);
+}
+
+static void __exit sh_csi2_exit(void)
+{
+ platform_driver_unregister(&sh_csi2_pdrv);
+}
+
+module_init(sh_csi2_init);
+module_exit(sh_csi2_exit);
+
+MODULE_DESCRIPTION("SH-Mobile MIPI CSI-2 driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <g.liakhovetski@gmx.de>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:sh-mobile-csi2");
diff --git a/drivers/media/video/sh_vou.c b/drivers/media/video/sh_vou.c
index f5b892a2a8ee..07cf0c6c7c1f 100644
--- a/drivers/media/video/sh_vou.c
+++ b/drivers/media/video/sh_vou.c
@@ -18,6 +18,7 @@
#include <linux/kernel.h>
#include <linux/platform_device.h>
#include <linux/pm_runtime.h>
+#include <linux/slab.h>
#include <linux/version.h>
#include <linux/videodev2.h>
@@ -57,7 +58,7 @@ enum sh_vou_status {
};
#define VOU_MAX_IMAGE_WIDTH 720
-#define VOU_MAX_IMAGE_HEIGHT 480
+#define VOU_MAX_IMAGE_HEIGHT 576
struct sh_vou_device {
struct v4l2_device v4l2_dev;
@@ -74,6 +75,7 @@ struct sh_vou_device {
int pix_idx;
struct videobuf_buffer *active;
enum sh_vou_status status;
+ struct mutex fop_lock;
};
struct sh_vou_file {
@@ -229,12 +231,12 @@ static void free_buffer(struct videobuf_queue *vq, struct videobuf_buffer *vb)
BUG_ON(in_interrupt());
/* Wait until this buffer is no longer in STATE_QUEUED or STATE_ACTIVE */
- videobuf_waiton(vb, 0, 0);
+ videobuf_waiton(vq, vb, 0, 0);
videobuf_dma_contig_free(vq, vb);
vb->state = VIDEOBUF_NEEDS_INIT;
}
-/* Locking: caller holds vq->vb_lock mutex */
+/* Locking: caller holds fop_lock mutex */
static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
unsigned int *size)
{
@@ -256,7 +258,7 @@ static int sh_vou_buf_setup(struct videobuf_queue *vq, unsigned int *count,
return 0;
}
-/* Locking: caller holds vq->vb_lock mutex */
+/* Locking: caller holds fop_lock mutex */
static int sh_vou_buf_prepare(struct videobuf_queue *vq,
struct videobuf_buffer *vb,
enum v4l2_field field)
@@ -305,7 +307,7 @@ static int sh_vou_buf_prepare(struct videobuf_queue *vq,
return 0;
}
-/* Locking: caller holds vq->vb_lock mutex and vq->irqlock spinlock */
+/* Locking: caller holds fop_lock mutex and vq->irqlock spinlock */
static void sh_vou_buf_queue(struct videobuf_queue *vq,
struct videobuf_buffer *vb)
{
@@ -527,20 +529,17 @@ struct sh_vou_geometry {
static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
{
/* The compiler cannot know, that best and idx will indeed be set */
- unsigned int best_err = UINT_MAX, best = 0, width_max, height_max;
+ unsigned int best_err = UINT_MAX, best = 0, img_height_max;
int i, idx = 0;
- if (std & V4L2_STD_525_60) {
- width_max = 858;
- height_max = 262;
- } else {
- width_max = 864;
- height_max = 312;
- }
+ if (std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
/* Image width must be a multiple of 4 */
v4l_bound_align_image(&geo->in_width, 0, VOU_MAX_IMAGE_WIDTH, 2,
- &geo->in_height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+ &geo->in_height, 0, img_height_max, 1, 0);
/* Select scales to come as close as possible to the output image */
for (i = ARRAY_SIZE(vou_scale_h_num) - 1; i >= 0; i--) {
@@ -573,7 +572,7 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
unsigned int found = geo->output.height * vou_scale_v_den[i] /
vou_scale_v_num[i];
- if (found > VOU_MAX_IMAGE_HEIGHT)
+ if (found > img_height_max)
/* scales increase */
break;
@@ -597,15 +596,18 @@ static void vou_adjust_input(struct sh_vou_geometry *geo, v4l2_std_id std)
*/
static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
{
- unsigned int best_err = UINT_MAX, best, width_max, height_max;
+ unsigned int best_err = UINT_MAX, best, width_max, height_max,
+ img_height_max;
int i, idx;
if (std & V4L2_STD_525_60) {
width_max = 858;
height_max = 262 * 2;
+ img_height_max = 480;
} else {
width_max = 864;
height_max = 312 * 2;
+ img_height_max = 576;
}
/* Select scales to come as close as possible to the output image */
@@ -644,7 +646,7 @@ static void vou_adjust_output(struct sh_vou_geometry *geo, v4l2_std_id std)
unsigned int found = geo->in_height * vou_scale_v_num[i] /
vou_scale_v_den[i];
- if (found > VOU_MAX_IMAGE_HEIGHT)
+ if (found > img_height_max)
/* scales increase */
break;
@@ -673,11 +675,12 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
struct video_device *vdev = video_devdata(file);
struct sh_vou_device *vou_dev = video_get_drvdata(vdev);
struct v4l2_pix_format *pix = &fmt->fmt.pix;
+ unsigned int img_height_max;
int pix_idx;
struct sh_vou_geometry geo;
struct v4l2_mbus_framefmt mbfmt = {
/* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_INTERLACED,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
};
@@ -701,9 +704,14 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
if (pix_idx == ARRAY_SIZE(vou_fmt))
return -EINVAL;
+ if (vou_dev->std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
+
/* Image width must be a multiple of 4 */
v4l_bound_align_image(&pix->width, 0, VOU_MAX_IMAGE_WIDTH, 2,
- &pix->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+ &pix->height, 0, img_height_max, 1, 0);
geo.in_width = pix->width;
geo.in_height = pix->height;
@@ -724,8 +732,8 @@ static int sh_vou_s_fmt_vid_out(struct file *file, void *priv,
/* Sanity checks */
if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
- (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ (unsigned)mbfmt.height > img_height_max ||
+ mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EIO;
if (mbfmt.width != geo.output.width ||
@@ -936,10 +944,11 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
struct sh_vou_geometry geo;
struct v4l2_mbus_framefmt mbfmt = {
/* Revisit: is this the correct code? */
- .code = V4L2_MBUS_FMT_YUYV8_2X8_LE,
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
.field = V4L2_FIELD_INTERLACED,
.colorspace = V4L2_COLORSPACE_SMPTE170M,
};
+ unsigned int img_height_max;
int ret;
dev_dbg(vou_dev->v4l2_dev.dev, "%s(): %ux%u@%u:%u\n", __func__,
@@ -948,14 +957,19 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
if (a->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
+ if (vou_dev->std & V4L2_STD_525_60)
+ img_height_max = 480;
+ else
+ img_height_max = 576;
+
v4l_bound_align_image(&rect->width, 0, VOU_MAX_IMAGE_WIDTH, 1,
- &rect->height, 0, VOU_MAX_IMAGE_HEIGHT, 1, 0);
+ &rect->height, 0, img_height_max, 1, 0);
if (rect->width + rect->left > VOU_MAX_IMAGE_WIDTH)
rect->left = VOU_MAX_IMAGE_WIDTH - rect->width;
- if (rect->height + rect->top > VOU_MAX_IMAGE_HEIGHT)
- rect->top = VOU_MAX_IMAGE_HEIGHT - rect->height;
+ if (rect->height + rect->top > img_height_max)
+ rect->top = img_height_max - rect->height;
geo.output = *rect;
geo.in_width = pix->width;
@@ -980,8 +994,8 @@ static int sh_vou_s_crop(struct file *file, void *fh, struct v4l2_crop *a)
/* Sanity checks */
if ((unsigned)mbfmt.width > VOU_MAX_IMAGE_WIDTH ||
- (unsigned)mbfmt.height > VOU_MAX_IMAGE_HEIGHT ||
- mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8_LE)
+ (unsigned)mbfmt.height > img_height_max ||
+ mbfmt.code != V4L2_MBUS_FMT_YUYV8_2X8)
return -EIO;
geo.output.width = mbfmt.width;
@@ -1176,7 +1190,8 @@ static int sh_vou_open(struct file *file)
vou_dev->v4l2_dev.dev, &vou_dev->lock,
V4L2_BUF_TYPE_VIDEO_OUTPUT,
V4L2_FIELD_NONE,
- sizeof(struct videobuf_buffer), vdev);
+ sizeof(struct videobuf_buffer), vdev,
+ &vou_dev->fop_lock);
return 0;
}
@@ -1278,7 +1293,7 @@ static const struct v4l2_file_operations sh_vou_fops = {
.owner = THIS_MODULE,
.open = sh_vou_open,
.release = sh_vou_release,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.mmap = sh_vou_mmap,
.poll = sh_vou_poll,
};
@@ -1317,6 +1332,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
INIT_LIST_HEAD(&vou_dev->queue);
spin_lock_init(&vou_dev->lock);
+ mutex_init(&vou_dev->fop_lock);
atomic_set(&vou_dev->use_count, 0);
vou_dev->pdata = vou_pdata;
vou_dev->status = SH_VOU_IDLE;
@@ -1329,13 +1345,13 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
rect->left = 0;
rect->top = 0;
rect->width = VOU_MAX_IMAGE_WIDTH;
- rect->height = VOU_MAX_IMAGE_HEIGHT;
+ rect->height = 480;
pix->width = VOU_MAX_IMAGE_WIDTH;
- pix->height = VOU_MAX_IMAGE_HEIGHT;
+ pix->height = 480;
pix->pixelformat = V4L2_PIX_FMT_YVYU;
pix->field = V4L2_FIELD_NONE;
pix->bytesperline = VOU_MAX_IMAGE_WIDTH * 2;
- pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * VOU_MAX_IMAGE_HEIGHT;
+ pix->sizeimage = VOU_MAX_IMAGE_WIDTH * 2 * 480;
pix->colorspace = V4L2_COLORSPACE_SMPTE170M;
region = request_mem_region(reg_res->start, resource_size(reg_res),
@@ -1374,6 +1390,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
vdev->tvnorms |= V4L2_STD_PAL;
vdev->v4l2_dev = &vou_dev->v4l2_dev;
vdev->release = video_device_release;
+ vdev->lock = &vou_dev->fop_lock;
vou_dev->vdev = vdev;
video_set_drvdata(vdev, vou_dev);
@@ -1392,7 +1409,7 @@ static int __devinit sh_vou_probe(struct platform_device *pdev)
goto ereset;
subdev = v4l2_i2c_new_subdev_board(&vou_dev->v4l2_dev, i2c_adap,
- vou_pdata->module_name, vou_pdata->board_info, NULL);
+ vou_pdata->board_info, NULL);
if (!subdev) {
ret = -ENOMEM;
goto ei2cnd;
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index 28e19daadec9..84984f64b234 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -2189,6 +2189,7 @@ sn9c102_vidioc_enuminput(struct sn9c102_device* cam, void __user * arg)
memset(&i, 0, sizeof(i));
strcpy(i.name, "Camera");
i.type = V4L2_INPUT_TYPE_CAMERA;
+ i.capabilities = V4L2_IN_CAP_STD;
if (copy_to_user(arg, &i, sizeof(i)))
return -EFAULT;
@@ -3238,7 +3239,7 @@ static const struct v4l2_file_operations sn9c102_fops = {
.owner = THIS_MODULE,
.open = sn9c102_open,
.release = sn9c102_release,
- .ioctl = sn9c102_ioctl,
+ .unlocked_ioctl = sn9c102_ioctl,
.read = sn9c102_read,
.poll = sn9c102_poll,
.mmap = sn9c102_mmap,
diff --git a/drivers/media/video/sn9c102/sn9c102_devtable.h b/drivers/media/video/sn9c102/sn9c102_devtable.h
index 522ba3f4c285..b3d2cc729657 100644
--- a/drivers/media/video/sn9c102/sn9c102_devtable.h
+++ b/drivers/media/video/sn9c102/sn9c102_devtable.h
@@ -43,89 +43,81 @@ static const struct usb_device_id sn9c102_id_table[] = {
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6001, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6005, BRIDGE_SN9C102), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6007, BRIDGE_SN9C102), },
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6009, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x600d, BRIDGE_SN9C102), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x6011, BRIDGE_SN9C102), }, OV6650 */
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6019, BRIDGE_SN9C102), },
+#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x6024, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6025, BRIDGE_SN9C102), },
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x6028, BRIDGE_SN9C102), },
{ SN9C102_USB_DEVICE(0x0c45, 0x6029, BRIDGE_SN9C102), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x602a, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), },
+#endif
+ { SN9C102_USB_DEVICE(0x0c45, 0x602b, BRIDGE_SN9C102), }, /* not in sonixb */
#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x602c, BRIDGE_SN9C102), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x602d, BRIDGE_SN9C102), }, HV7131R */
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x602e, BRIDGE_SN9C102), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), },
+#endif
+ { SN9C102_USB_DEVICE(0x0c45, 0x6030, BRIDGE_SN9C102), }, /* not in sonixb */
/* SN9C103 */
- { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6080, BRIDGE_SN9C103), }, non existent ? */
+ { SN9C102_USB_DEVICE(0x0c45, 0x6082, BRIDGE_SN9C103), }, /* not in sonixb */
+#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
/* { SN9C102_USB_DEVICE(0x0c45, 0x6083, BRIDGE_SN9C103), }, HY7131D/E */
- { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6088, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x608a, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x608b, BRIDGE_SN9C103), }, non existent ? */
{ SN9C102_USB_DEVICE(0x0c45, 0x608c, BRIDGE_SN9C103), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x608e, BRIDGE_SN9C103), }, CISVF10 */
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x608f, BRIDGE_SN9C103), },
-#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60a0, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60a2, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60a3, BRIDGE_SN9C103), }, non existent ? */
/* { SN9C102_USB_DEVICE(0x0c45, 0x60a8, BRIDGE_SN9C103), }, PAS106 */
/* { SN9C102_USB_DEVICE(0x0c45, 0x60aa, BRIDGE_SN9C103), }, TAS5130 */
-/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5130 */
- { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ab, BRIDGE_SN9C103), }, TAS5110, non existent */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ac, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ae, BRIDGE_SN9C103), }, non existent ? */
{ SN9C102_USB_DEVICE(0x0c45, 0x60af, BRIDGE_SN9C103), },
-#if !defined CONFIG_USB_GSPCA_SONIXB && !defined CONFIG_USB_GSPCA_SONIXB_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x60b0, BRIDGE_SN9C103), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), }, non existent ? */
#endif
- { SN9C102_USB_DEVICE(0x0c45, 0x60b2, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60b3, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60b8, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ba, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60bb, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60bc, BRIDGE_SN9C103), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60be, BRIDGE_SN9C103), },
/* SN9C105 */
#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
{ SN9C102_USB_DEVICE(0x045e, 0x00f5, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x045e, 0x00f7, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0471, 0x0327, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0471, 0x0328, BRIDGE_SN9C105), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x60c0, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), },
- { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60c2, BRIDGE_SN9C105), }, PO1030 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60c8, BRIDGE_SN9C105), }, OM6801 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60cc, BRIDGE_SN9C105), }, HV7131GP */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ea, BRIDGE_SN9C105), }, non existent ? */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ec, BRIDGE_SN9C105), }, MO4000 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60ef, BRIDGE_SN9C105), }, ICM105C */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x60fa, BRIDGE_SN9C105), }, OV7648 */
{ SN9C102_USB_DEVICE(0x0c45, 0x60fb, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60fc, BRIDGE_SN9C105), },
{ SN9C102_USB_DEVICE(0x0c45, 0x60fe, BRIDGE_SN9C105), },
/* SN9C120 */
{ SN9C102_USB_DEVICE(0x0458, 0x7025, BRIDGE_SN9C120), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), },
- { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), },
- { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), },
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6102, BRIDGE_SN9C120), }, po2030 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x6108, BRIDGE_SN9C120), }, om6801 */
+/* { SN9C102_USB_DEVICE(0x0c45, 0x610f, BRIDGE_SN9C120), }, S5K53BEB */
{ SN9C102_USB_DEVICE(0x0c45, 0x6130, BRIDGE_SN9C120), },
/* { SN9C102_USB_DEVICE(0x0c45, 0x6138, BRIDGE_SN9C120), }, MO8000 */
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x613a, BRIDGE_SN9C120), },
-#endif
{ SN9C102_USB_DEVICE(0x0c45, 0x613b, BRIDGE_SN9C120), },
-#if !defined CONFIG_USB_GSPCA_SONIXJ && !defined CONFIG_USB_GSPCA_SONIXJ_MODULE
{ SN9C102_USB_DEVICE(0x0c45, 0x613c, BRIDGE_SN9C120), },
{ SN9C102_USB_DEVICE(0x0c45, 0x613e, BRIDGE_SN9C120), },
#endif
diff --git a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
index 2782f94cf6f8..2e86fdc86989 100644
--- a/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
+++ b/drivers/media/video/sn9c102/sn9c102_pas202bcb.c
@@ -4,7 +4,6 @@
* *
* Copyright (C) 2004 by Carlos Eduardo Medaglia Dyonisio *
* <medaglia@undl.org.br> *
- * http://cadu.homelinux.com:8080/ *
* *
* Support for SN9C103, DAC Magnitude, exposure and green gain controls *
* added by Luca Risolia <luca.risolia@studio.unibo.it> *
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 494957b10bac..7f38549715b6 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -147,7 +147,7 @@ enum sn9c102_i2c_interface {
struct sn9c102_sensor {
char name[32], /* sensor name */
- maintainer[64]; /* name of the mantainer <email> */
+ maintainer[64]; /* name of the maintainer <email> */
enum sn9c102_bridge supported_bridge; /* supported SN9C1xx bridges */
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
index db1ca0e90d76..a66811b43710 100644
--- a/drivers/media/video/soc_camera.c
+++ b/drivers/media/video/soc_camera.c
@@ -24,6 +24,7 @@
#include <linux/mutex.h>
#include <linux/module.h>
#include <linux/platform_device.h>
+#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#include <linux/pm_runtime.h>
#include <linux/vmalloc.h>
@@ -43,6 +44,51 @@ static LIST_HEAD(hosts);
static LIST_HEAD(devices);
static DEFINE_MUTEX(list_lock); /* Protects the list of hosts */
+static int soc_camera_power_set(struct soc_camera_device *icd,
+ struct soc_camera_link *icl,
+ int power_on)
+{
+ int ret;
+
+ if (power_on) {
+ ret = regulator_bulk_enable(icl->num_regulators,
+ icl->regulators);
+ if (ret < 0) {
+ dev_err(&icd->dev, "Cannot enable regulators\n");
+ return ret;
+ }
+
+ if (icl->power)
+ ret = icl->power(icd->pdev, power_on);
+ if (ret < 0) {
+ dev_err(&icd->dev,
+ "Platform failed to power-on the camera.\n");
+
+ regulator_bulk_disable(icl->num_regulators,
+ icl->regulators);
+ return ret;
+ }
+ } else {
+ ret = 0;
+ if (icl->power)
+ ret = icl->power(icd->pdev, 0);
+ if (ret < 0) {
+ dev_err(&icd->dev,
+ "Platform failed to power-off the camera.\n");
+ return ret;
+ }
+
+ ret = regulator_bulk_disable(icl->num_regulators,
+ icl->regulators);
+ if (ret < 0) {
+ dev_err(&icd->dev, "Cannot disable regulators\n");
+ return ret;
+ }
+ }
+
+ return 0;
+}
+
const struct soc_camera_format_xlate *soc_camera_xlate_by_fourcc(
struct soc_camera_device *icd, unsigned int fourcc)
{
@@ -92,8 +138,7 @@ EXPORT_SYMBOL(soc_camera_apply_sensor_flags);
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_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
@@ -105,8 +150,7 @@ static int soc_camera_try_fmt_vid_cap(struct file *file, void *priv,
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;
+ struct soc_camera_device *icd = file->private_data;
int ret = 0;
if (inp->index != 0)
@@ -141,8 +185,7 @@ 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)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, s_std, *a);
@@ -152,47 +195,59 @@ static int soc_camera_reqbufs(struct file *file, void *priv,
struct v4l2_requestbuffers *p)
{
int ret;
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
- ret = videobuf_reqbufs(&icf->vb_vidq, p);
+ if (icd->streamer && icd->streamer != file)
+ return -EBUSY;
+
+ ret = videobuf_reqbufs(&icd->vb_vidq, p);
if (ret < 0)
return ret;
- return ici->ops->reqbufs(icf, p);
+ ret = ici->ops->reqbufs(icd, p);
+ if (!ret && !icd->streamer)
+ icd->streamer = file;
+
+ return ret;
}
static int soc_camera_querybuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
WARN_ON(priv != file->private_data);
- return videobuf_querybuf(&icf->vb_vidq, p);
+ return videobuf_querybuf(&icd->vb_vidq, p);
}
static int soc_camera_qbuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
WARN_ON(priv != file->private_data);
- return videobuf_qbuf(&icf->vb_vidq, p);
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ return videobuf_qbuf(&icd->vb_vidq, p);
}
static int soc_camera_dqbuf(struct file *file, void *priv,
struct v4l2_buffer *p)
{
- struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = file->private_data;
WARN_ON(priv != file->private_data);
- return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ return videobuf_dqbuf(&icd->vb_vidq, p, file->f_flags & O_NONBLOCK);
}
/* Always entered with .video_lock held */
@@ -200,7 +255,8 @@ static int soc_camera_init_user_formats(struct soc_camera_device *icd)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- int i, fmts = 0, raw_fmts = 0, ret;
+ unsigned int i, fmts = 0, raw_fmts = 0;
+ int ret;
enum v4l2_mbus_pixelcode code;
while (!v4l2_subdev_call(sd, video, enum_mbus_fmt, raw_fmts, &code))
@@ -279,10 +335,9 @@ static void soc_camera_free_user_formats(struct soc_camera_device *icd)
((x) >> 24) & 0xff
/* Called with .vb_lock held, or from the first open(2), see comment there */
-static int soc_camera_set_fmt(struct soc_camera_file *icf,
+static int soc_camera_set_fmt(struct soc_camera_device *icd,
struct v4l2_format *f)
{
- struct soc_camera_device *icd = icf->icd;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct v4l2_pix_format *pix = &f->fmt.pix;
int ret;
@@ -308,7 +363,7 @@ static int soc_camera_set_fmt(struct soc_camera_file *icf,
icd->user_width = pix->width;
icd->user_height = pix->height;
icd->colorspace = pix->colorspace;
- icf->vb_vidq.field =
+ icd->vb_vidq.field =
icd->field = pix->field;
if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
@@ -330,7 +385,6 @@ static int soc_camera_open(struct file *file)
dev);
struct soc_camera_link *icl = to_soc_camera_link(icd);
struct soc_camera_host *ici;
- struct soc_camera_file *icf;
int ret;
if (!icd->ops)
@@ -339,23 +393,11 @@ static int soc_camera_open(struct file *file)
ici = to_soc_camera_host(icd->dev.parent);
- icf = vmalloc(sizeof(*icf));
- if (!icf)
- return -ENOMEM;
-
if (!try_module_get(ici->ops->owner)) {
dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
- ret = -EINVAL;
- goto emgi;
+ return -EINVAL;
}
- /*
- * Protect against icd->ops->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 */
@@ -373,11 +415,9 @@ static int soc_camera_open(struct file *file)
},
};
- if (icl->power) {
- ret = icl->power(icd->pdev, 1);
- if (ret < 0)
- goto epower;
- }
+ ret = soc_camera_power_set(icd, icl, 1);
+ if (ret < 0)
+ goto epower;
/* The camera could have been already on, try to reset */
if (icl->reset)
@@ -400,18 +440,16 @@ static int soc_camera_open(struct file *file)
* apart from someone else calling open() simultaneously, but
* .video_lock is protecting us against it.
*/
- ret = soc_camera_set_fmt(icf, &f);
+ ret = soc_camera_set_fmt(icd, &f);
if (ret < 0)
goto esfmt;
+
+ ici->ops->init_videobuf(&icd->vb_vidq, icd);
}
- file->private_data = icf;
+ file->private_data = icd;
dev_dbg(&icd->dev, "camera device open\n");
- ici->ops->init_videobuf(&icf->vb_vidq, icd);
-
- mutex_unlock(&icd->video_lock);
-
return 0;
/*
@@ -423,24 +461,19 @@ esfmt:
eresume:
ici->ops->remove(icd);
eiciadd:
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
epower:
icd->use_count--;
- mutex_unlock(&icd->video_lock);
module_put(ici->ops->owner);
-emgi:
- vfree(icf);
+
return ret;
}
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_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- mutex_lock(&icd->video_lock);
icd->use_count--;
if (!icd->use_count) {
struct soc_camera_link *icl = to_soc_camera_link(icd);
@@ -450,16 +483,14 @@ static int soc_camera_close(struct file *file)
ici->ops->remove(icd);
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
}
- mutex_unlock(&icd->video_lock);
+ if (icd->streamer == file)
+ icd->streamer = NULL;
module_put(ici->ops->owner);
- vfree(icf);
-
dev_dbg(&icd->dev, "camera device close\n");
return 0;
@@ -468,8 +499,7 @@ static int soc_camera_close(struct file *file)
static ssize_t soc_camera_read(struct file *file, char __user *buf,
size_t count, loff_t *ppos)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
int err = -EINVAL;
dev_err(&icd->dev, "camera device read not implemented\n");
@@ -479,13 +509,15 @@ static ssize_t soc_camera_read(struct file *file, char __user *buf,
static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
int err;
dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
- err = videobuf_mmap_mapper(&icf->vb_vidq, vma);
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ err = videobuf_mmap_mapper(&icd->vb_vidq, vma);
dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
(unsigned long)vma->vm_start,
@@ -497,11 +529,13 @@ static int soc_camera_mmap(struct file *file, struct vm_area_struct *vma)
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_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
- if (list_empty(&icf->vb_vidq.stream)) {
+ if (icd->streamer != file)
+ return -EBUSY;
+
+ if (list_empty(&icd->vb_vidq.stream)) {
dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
return POLLERR;
}
@@ -513,7 +547,7 @@ static struct v4l2_file_operations soc_camera_fops = {
.owner = THIS_MODULE,
.open = soc_camera_open,
.release = soc_camera_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = soc_camera_read,
.mmap = soc_camera_mmap,
.poll = soc_camera_poll,
@@ -522,24 +556,23 @@ static struct v4l2_file_operations soc_camera_fops = {
static int soc_camera_s_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_device *icd = file->private_data;
int ret;
WARN_ON(priv != file->private_data);
- mutex_lock(&icf->vb_vidq.vb_lock);
+ if (icd->streamer && icd->streamer != file)
+ return -EBUSY;
- if (icf->vb_vidq.bufs[0]) {
+ if (icd->vb_vidq.bufs[0]) {
dev_err(&icd->dev, "S_FMT denied: queue initialised\n");
- ret = -EBUSY;
- goto unlock;
+ return -EBUSY;
}
- ret = soc_camera_set_fmt(icf, f);
+ ret = soc_camera_set_fmt(icd, f);
-unlock:
- mutex_unlock(&icf->vb_vidq.vb_lock);
+ if (!ret && !icd->streamer)
+ icd->streamer = file;
return ret;
}
@@ -547,8 +580,7 @@ unlock:
static int soc_camera_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *f)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
const struct soc_mbus_pixelfmt *format;
WARN_ON(priv != file->private_data);
@@ -567,15 +599,14 @@ 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 soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_pix_format *pix = &f->fmt.pix;
WARN_ON(priv != file->private_data);
pix->width = icd->user_width;
pix->height = icd->user_height;
- pix->field = icf->vb_vidq.field;
+ pix->field = icd->vb_vidq.field;
pix->pixelformat = icd->current_fmt->host_fmt->fourcc;
pix->bytesperline = soc_mbus_bytes_per_line(pix->width,
icd->current_fmt->host_fmt);
@@ -591,8 +622,7 @@ static int soc_camera_g_fmt_vid_cap(struct file *file, void *priv,
static int soc_camera_querycap(struct file *file, void *priv,
struct v4l2_capability *cap)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
WARN_ON(priv != file->private_data);
@@ -604,8 +634,7 @@ static int soc_camera_querycap(struct file *file, void *priv,
static int soc_camera_streamon(struct file *file, void *priv,
enum v4l2_buf_type i)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
@@ -614,14 +643,13 @@ static int soc_camera_streamon(struct file *file, void *priv,
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- mutex_lock(&icd->video_lock);
+ if (icd->streamer != file)
+ return -EBUSY;
v4l2_subdev_call(sd, video, s_stream, 1);
/* This calls buf_queue from host driver's videobuf_queue_ops */
- ret = videobuf_streamon(&icf->vb_vidq);
-
- mutex_unlock(&icd->video_lock);
+ ret = videobuf_streamon(&icd->vb_vidq);
return ret;
}
@@ -629,8 +657,7 @@ static int soc_camera_streamon(struct file *file, void *priv,
static int soc_camera_streamoff(struct file *file, void *priv,
enum v4l2_buf_type i)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
WARN_ON(priv != file->private_data);
@@ -638,26 +665,24 @@ static int soc_camera_streamoff(struct file *file, void *priv,
if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- mutex_lock(&icd->video_lock);
+ if (icd->streamer != file)
+ return -EBUSY;
/*
* 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);
+ videobuf_streamoff(&icd->vb_vidq);
v4l2_subdev_call(sd, video, s_stream, 0);
- mutex_unlock(&icd->video_lock);
-
return 0;
}
static int soc_camera_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int i;
@@ -688,8 +713,7 @@ static int soc_camera_queryctrl(struct file *file, void *priv,
static int soc_camera_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
@@ -708,8 +732,7 @@ static int soc_camera_g_ctrl(struct file *file, void *priv,
static int soc_camera_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
int ret;
@@ -728,8 +751,7 @@ static int soc_camera_s_ctrl(struct file *file, void *priv,
static int soc_camera_cropcap(struct file *file, void *fh,
struct v4l2_cropcap *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
return ici->ops->cropcap(icd, a);
@@ -738,14 +760,11 @@ static int soc_camera_cropcap(struct file *file, void *fh,
static int soc_camera_g_crop(struct file *file, void *fh,
struct v4l2_crop *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
int ret;
- mutex_lock(&icf->vb_vidq.vb_lock);
ret = ici->ops->get_crop(icd, a);
- mutex_unlock(&icf->vb_vidq.vb_lock);
return ret;
}
@@ -758,8 +777,7 @@ static int soc_camera_g_crop(struct file *file, void *fh,
static int soc_camera_s_crop(struct file *file, void *fh,
struct v4l2_crop *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
struct v4l2_rect *rect = &a->c;
struct v4l2_crop current_crop;
@@ -771,16 +789,16 @@ static int soc_camera_s_crop(struct file *file, void *fh,
dev_dbg(&icd->dev, "S_CROP(%ux%u@%u:%u)\n",
rect->width, rect->height, rect->left, rect->top);
- /* Cropping is allowed during a running capture, guard consistency */
- mutex_lock(&icf->vb_vidq.vb_lock);
-
/* If get_crop fails, we'll let host and / or client drivers decide */
ret = ici->ops->get_crop(icd, &current_crop);
/* Prohibit window size change with initialised buffers */
- if (icf->vb_vidq.bufs[0] && !ret &&
- (a->c.width != current_crop.c.width ||
- a->c.height != current_crop.c.height)) {
+ if (ret < 0) {
+ dev_err(&icd->dev,
+ "S_CROP denied: getting current crop failed\n");
+ } else if (icd->vb_vidq.bufs[0] &&
+ (a->c.width != current_crop.c.width ||
+ a->c.height != current_crop.c.height)) {
dev_err(&icd->dev,
"S_CROP denied: queue initialised and sizes differ\n");
ret = -EBUSY;
@@ -788,16 +806,13 @@ static int soc_camera_s_crop(struct file *file, void *fh,
ret = ici->ops->set_crop(icd, a);
}
- mutex_unlock(&icf->vb_vidq.vb_lock);
-
return ret;
}
static int soc_camera_g_parm(struct file *file, void *fh,
struct v4l2_streamparm *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
if (ici->ops->get_parm)
@@ -809,8 +824,7 @@ static int soc_camera_g_parm(struct file *file, void *fh,
static int soc_camera_s_parm(struct file *file, void *fh,
struct v4l2_streamparm *a)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
if (ici->ops->set_parm)
@@ -822,8 +836,7 @@ static int soc_camera_s_parm(struct file *file, void *fh,
static int soc_camera_g_chip_ident(struct file *file, void *fh,
struct v4l2_dbg_chip_ident *id)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, g_chip_ident, id);
@@ -833,8 +846,7 @@ static int soc_camera_g_chip_ident(struct file *file, void *fh,
static int soc_camera_g_register(struct file *file, void *fh,
struct v4l2_dbg_register *reg)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, g_register, reg);
@@ -843,8 +855,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_dbg_register *reg)
{
- struct soc_camera_file *icf = file->private_data;
- struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_device *icd = file->private_data;
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
return v4l2_subdev_call(sd, core, s_register, reg);
@@ -894,11 +905,11 @@ static int soc_camera_init_i2c(struct soc_camera_device *icd,
icl->board_info->platform_data = icd;
subdev = v4l2_i2c_new_subdev_board(&ici->v4l2_dev, adap,
- icl->module_name, icl->board_info, NULL);
+ icl->board_info, NULL);
if (!subdev)
goto ei2cnd;
- client = subdev->priv;
+ client = v4l2_get_subdevdata(subdev);
/* Use to_i2c_client(dev) to recover the i2c client */
dev_set_drvdata(&icd->dev, &client->dev);
@@ -939,14 +950,14 @@ static int soc_camera_probe(struct device *dev)
dev_info(dev, "Probing %s\n", dev_name(dev));
- if (icl->power) {
- ret = icl->power(icd->pdev, 1);
- if (ret < 0) {
- dev_err(dev,
- "Platform failed to power-on the camera.\n");
- goto epower;
- }
- }
+ ret = regulator_bulk_get(icd->pdev, icl->num_regulators,
+ icl->regulators);
+ if (ret < 0)
+ goto ereg;
+
+ ret = soc_camera_power_set(icd, icl, 1);
+ if (ret < 0)
+ goto epower;
/* The camera could have been already on, try to reset */
if (icl->reset)
@@ -996,7 +1007,13 @@ static int soc_camera_probe(struct device *dev)
icd->field = V4L2_FIELD_ANY;
- /* ..._video_start() will create a device node, so we have to protect */
+ icd->vdev->lock = &icd->video_lock;
+
+ /*
+ * ..._video_start() will create a device node, video_register_device()
+ * itself is protected against concurrent open() calls, but we also have
+ * to protect our data.
+ */
mutex_lock(&icd->video_lock);
ret = soc_camera_video_start(icd);
@@ -1019,8 +1036,7 @@ static int soc_camera_probe(struct device *dev)
ici->ops->remove(icd);
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
mutex_unlock(&icd->video_lock);
@@ -1042,9 +1058,10 @@ eadddev:
evdc:
ici->ops->remove(icd);
eadd:
- if (icl->power)
- icl->power(icd->pdev, 0);
+ soc_camera_power_set(icd, icl, 0);
epower:
+ regulator_bulk_free(icl->num_regulators, icl->regulators);
+ereg:
return ret;
}
@@ -1061,10 +1078,8 @@ static int soc_camera_remove(struct device *dev)
BUG_ON(!dev->parent);
if (vdev) {
- mutex_lock(&icd->video_lock);
video_unregister_device(vdev);
icd->vdev = NULL;
- mutex_unlock(&icd->video_lock);
}
if (icl->board_info) {
@@ -1079,6 +1094,8 @@ static int soc_camera_remove(struct device *dev)
}
soc_camera_free_user_formats(icd);
+ regulator_bulk_free(icl->num_regulators, icl->regulators);
+
return 0;
}
@@ -1106,13 +1123,14 @@ static int soc_camera_resume(struct device *dev)
return ret;
}
-static struct bus_type soc_camera_bus_type = {
+struct bus_type soc_camera_bus_type = {
.name = "soc-camera",
.probe = soc_camera_probe,
.remove = soc_camera_remove,
.suspend = soc_camera_suspend,
.resume = soc_camera_resume,
};
+EXPORT_SYMBOL_GPL(soc_camera_bus_type);
static struct device_driver ic_drv = {
.name = "camera",
@@ -1143,6 +1161,20 @@ static int default_s_crop(struct soc_camera_device *icd, struct v4l2_crop *a)
return v4l2_subdev_call(sd, video, s_crop, a);
}
+static int default_g_parm(struct soc_camera_device *icd,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, g_parm, parm);
+}
+
+static int default_s_parm(struct soc_camera_device *icd,
+ struct v4l2_streamparm *parm)
+{
+ struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
+ return v4l2_subdev_call(sd, video, s_parm, parm);
+}
+
static void soc_camera_device_init(struct device *dev, void *pdata)
{
dev->platform_data = pdata;
@@ -1174,6 +1206,10 @@ int soc_camera_host_register(struct soc_camera_host *ici)
ici->ops->get_crop = default_g_crop;
if (!ici->ops->cropcap)
ici->ops->cropcap = default_cropcap;
+ if (!ici->ops->set_parm)
+ ici->ops->set_parm = default_s_parm;
+ if (!ici->ops->get_parm)
+ ici->ops->get_parm = default_g_parm;
mutex_lock(&list_lock);
list_for_each_entry(ix, &hosts, list) {
diff --git a/drivers/media/video/soc_camera_platform.c b/drivers/media/video/soc_camera_platform.c
index 10b003a8be83..bf406e89c992 100644
--- a/drivers/media/video/soc_camera_platform.c
+++ b/drivers/media/video/soc_camera_platform.c
@@ -56,8 +56,8 @@ soc_camera_platform_query_bus_param(struct soc_camera_device *icd)
return p->bus_param;
}
-static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
- struct v4l2_mbus_framefmt *mf)
+static int soc_camera_platform_fill_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
@@ -65,13 +65,14 @@ static int soc_camera_platform_try_fmt(struct v4l2_subdev *sd,
mf->height = p->format.height;
mf->code = p->format.code;
mf->colorspace = p->format.colorspace;
+ mf->field = p->format.field;
return 0;
}
static struct v4l2_subdev_core_ops platform_subdev_core_ops;
-static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, int index,
+static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
@@ -83,10 +84,45 @@ static int soc_camera_platform_enum_fmt(struct v4l2_subdev *sd, int index,
return 0;
}
+static int soc_camera_platform_g_crop(struct v4l2_subdev *sd,
+ struct v4l2_crop *a)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ a->c.left = 0;
+ a->c.top = 0;
+ a->c.width = p->format.width;
+ a->c.height = p->format.height;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ return 0;
+}
+
+static int soc_camera_platform_cropcap(struct v4l2_subdev *sd,
+ struct v4l2_cropcap *a)
+{
+ struct soc_camera_platform_info *p = v4l2_get_subdevdata(sd);
+
+ a->bounds.left = 0;
+ a->bounds.top = 0;
+ a->bounds.width = p->format.width;
+ a->bounds.height = p->format.height;
+ a->defrect = a->bounds;
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
static struct v4l2_subdev_video_ops platform_subdev_video_ops = {
.s_stream = soc_camera_platform_s_stream,
- .try_mbus_fmt = soc_camera_platform_try_fmt,
.enum_mbus_fmt = soc_camera_platform_enum_fmt,
+ .cropcap = soc_camera_platform_cropcap,
+ .g_crop = soc_camera_platform_g_crop,
+ .try_mbus_fmt = soc_camera_platform_fill_fmt,
+ .g_mbus_fmt = soc_camera_platform_fill_fmt,
+ .s_mbus_fmt = soc_camera_platform_fill_fmt,
};
static struct v4l2_subdev_ops platform_subdev_ops = {
diff --git a/drivers/media/video/soc_mediabus.c b/drivers/media/video/soc_mediabus.c
index 8b63b6545e76..91391214c682 100644
--- a/drivers/media/video/soc_mediabus.c
+++ b/drivers/media/video/soc_mediabus.c
@@ -18,28 +18,28 @@
#define MBUS_IDX(f) (V4L2_MBUS_FMT_ ## f - V4L2_MBUS_FMT_FIXED - 1)
static const struct soc_mbus_pixelfmt mbus_fmt[] = {
- [MBUS_IDX(YUYV8_2X8_LE)] = {
+ [MBUS_IDX(YUYV8_2X8)] = {
.fourcc = V4L2_PIX_FMT_YUYV,
.name = "YUYV",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YVYU8_2X8_LE)] = {
+ [MBUS_IDX(YVYU8_2X8)] = {
.fourcc = V4L2_PIX_FMT_YVYU,
.name = "YVYU",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YUYV8_2X8_BE)] = {
+ [MBUS_IDX(UYVY8_2X8)] = {
.fourcc = V4L2_PIX_FMT_UYVY,
.name = "UYVY",
.bits_per_sample = 8,
.packing = SOC_MBUS_PACKING_2X8_PADHI,
.order = SOC_MBUS_ORDER_LE,
},
- [MBUS_IDX(YVYU8_2X8_BE)] = {
+ [MBUS_IDX(VYUY8_2X8)] = {
.fourcc = V4L2_PIX_FMT_VYUY,
.name = "VYUY",
.bits_per_sample = 8,
diff --git a/drivers/media/video/sr030pc30.c b/drivers/media/video/sr030pc30.c
new file mode 100644
index 000000000000..c901721a1db3
--- /dev/null
+++ b/drivers/media/video/sr030pc30.c
@@ -0,0 +1,884 @@
+/*
+ * Driver for SiliconFile SR030PC30 VGA (1/10-Inch) Image Sensor with ISP
+ *
+ * Copyright (C) 2010 Samsung Electronics Co., Ltd
+ * Author: Sylwester Nawrocki, s.nawrocki@samsung.com
+ *
+ * Based on original driver authored by Dongsoo Nathaniel Kim
+ * and HeungJun Kim <riverful.kim@samsung.com>.
+ *
+ * Based on mt9v011 Micron Digital Image Sensor driver
+ * Copyright (c) 2009 Mauro Carvalho Chehab (mchehab@redhat.com)
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ */
+
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/slab.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-subdev.h>
+#include <media/v4l2-mediabus.h>
+#include <media/sr030pc30.h>
+
+static int debug;
+module_param(debug, int, 0644);
+
+#define MODULE_NAME "SR030PC30"
+
+/*
+ * Register offsets within a page
+ * b15..b8 - page id, b7..b0 - register address
+ */
+#define POWER_CTRL_REG 0x0001
+#define PAGEMODE_REG 0x03
+#define DEVICE_ID_REG 0x0004
+#define NOON010PC30_ID 0x86
+#define SR030PC30_ID 0x8C
+#define VDO_CTL1_REG 0x0010
+#define SUBSAMPL_NONE_VGA 0
+#define SUBSAMPL_QVGA 0x10
+#define SUBSAMPL_QQVGA 0x20
+#define VDO_CTL2_REG 0x0011
+#define SYNC_CTL_REG 0x0012
+#define WIN_ROWH_REG 0x0020
+#define WIN_ROWL_REG 0x0021
+#define WIN_COLH_REG 0x0022
+#define WIN_COLL_REG 0x0023
+#define WIN_HEIGHTH_REG 0x0024
+#define WIN_HEIGHTL_REG 0x0025
+#define WIN_WIDTHH_REG 0x0026
+#define WIN_WIDTHL_REG 0x0027
+#define HBLANKH_REG 0x0040
+#define HBLANKL_REG 0x0041
+#define VSYNCH_REG 0x0042
+#define VSYNCL_REG 0x0043
+/* page 10 */
+#define ISP_CTL_REG(n) (0x1010 + (n))
+#define YOFS_REG 0x1040
+#define DARK_YOFS_REG 0x1041
+#define AG_ABRTH_REG 0x1050
+#define SAT_CTL_REG 0x1060
+#define BSAT_REG 0x1061
+#define RSAT_REG 0x1062
+#define AG_SAT_TH_REG 0x1063
+/* page 11 */
+#define ZLPF_CTRL_REG 0x1110
+#define ZLPF_CTRL2_REG 0x1112
+#define ZLPF_AGH_THR_REG 0x1121
+#define ZLPF_THR_REG 0x1160
+#define ZLPF_DYN_THR_REG 0x1160
+/* page 12 */
+#define YCLPF_CTL1_REG 0x1240
+#define YCLPF_CTL2_REG 0x1241
+#define YCLPF_THR_REG 0x1250
+#define BLPF_CTL_REG 0x1270
+#define BLPF_THR1_REG 0x1274
+#define BLPF_THR2_REG 0x1275
+/* page 14 - Lens Shading Compensation */
+#define LENS_CTRL_REG 0x1410
+#define LENS_XCEN_REG 0x1420
+#define LENS_YCEN_REG 0x1421
+#define LENS_R_COMP_REG 0x1422
+#define LENS_G_COMP_REG 0x1423
+#define LENS_B_COMP_REG 0x1424
+/* page 15 - Color correction */
+#define CMC_CTL_REG 0x1510
+#define CMC_OFSGH_REG 0x1514
+#define CMC_OFSGL_REG 0x1516
+#define CMC_SIGN_REG 0x1517
+/* Color correction coefficients */
+#define CMC_COEF_REG(n) (0x1530 + (n))
+/* Color correction offset coefficients */
+#define CMC_OFS_REG(n) (0x1540 + (n))
+/* page 16 - Gamma correction */
+#define GMA_CTL_REG 0x1610
+/* Gamma correction coefficients 0.14 */
+#define GMA_COEF_REG(n) (0x1630 + (n))
+/* page 20 - Auto Exposure */
+#define AE_CTL1_REG 0x2010
+#define AE_CTL2_REG 0x2011
+#define AE_FRM_CTL_REG 0x2020
+#define AE_FINE_CTL_REG(n) (0x2028 + (n))
+#define EXP_TIMEH_REG 0x2083
+#define EXP_TIMEM_REG 0x2084
+#define EXP_TIMEL_REG 0x2085
+#define EXP_MMINH_REG 0x2086
+#define EXP_MMINL_REG 0x2087
+#define EXP_MMAXH_REG 0x2088
+#define EXP_MMAXM_REG 0x2089
+#define EXP_MMAXL_REG 0x208A
+/* page 22 - Auto White Balance */
+#define AWB_CTL1_REG 0x2210
+#define AWB_ENABLE 0x80
+#define AWB_CTL2_REG 0x2211
+#define MWB_ENABLE 0x01
+/* RGB gain control (manual WB) when AWB_CTL1[7]=0 */
+#define AWB_RGAIN_REG 0x2280
+#define AWB_GGAIN_REG 0x2281
+#define AWB_BGAIN_REG 0x2282
+#define AWB_RMAX_REG 0x2283
+#define AWB_RMIN_REG 0x2284
+#define AWB_BMAX_REG 0x2285
+#define AWB_BMIN_REG 0x2286
+/* R, B gain range in bright light conditions */
+#define AWB_RMAXB_REG 0x2287
+#define AWB_RMINB_REG 0x2288
+#define AWB_BMAXB_REG 0x2289
+#define AWB_BMINB_REG 0x228A
+/* manual white balance, when AWB_CTL2[0]=1 */
+#define MWB_RGAIN_REG 0x22B2
+#define MWB_BGAIN_REG 0x22B3
+/* the token to mark an array end */
+#define REG_TERM 0xFFFF
+
+/* Minimum and maximum exposure time in ms */
+#define EXPOS_MIN_MS 1
+#define EXPOS_MAX_MS 125
+
+struct sr030pc30_info {
+ struct v4l2_subdev sd;
+ const struct sr030pc30_platform_data *pdata;
+ const struct sr030pc30_format *curr_fmt;
+ const struct sr030pc30_frmsize *curr_win;
+ unsigned int auto_wb:1;
+ unsigned int auto_exp:1;
+ unsigned int hflip:1;
+ unsigned int vflip:1;
+ unsigned int sleep:1;
+ unsigned int exposure;
+ u8 blue_balance;
+ u8 red_balance;
+ u8 i2c_reg_page;
+};
+
+struct sr030pc30_format {
+ enum v4l2_mbus_pixelcode code;
+ enum v4l2_colorspace colorspace;
+ u16 ispctl1_reg;
+};
+
+struct sr030pc30_frmsize {
+ u16 width;
+ u16 height;
+ int vid_ctl1;
+};
+
+struct i2c_regval {
+ u16 addr;
+ u16 val;
+};
+
+static const struct v4l2_queryctrl sr030pc30_ctrl[] = {
+ {
+ .id = V4L2_CID_AUTO_WHITE_BALANCE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Auto White Balance",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ }, {
+ .id = V4L2_CID_RED_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Red Balance",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_BLUE_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Blue Balance",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 64,
+ }, {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Auto Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ }, {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = EXPOS_MIN_MS,
+ .maximum = EXPOS_MAX_MS,
+ .step = 1,
+ .default_value = 1,
+ }, {
+ }
+};
+
+/* supported resolutions */
+static const struct sr030pc30_frmsize sr030pc30_sizes[] = {
+ {
+ .width = 640,
+ .height = 480,
+ .vid_ctl1 = SUBSAMPL_NONE_VGA,
+ }, {
+ .width = 320,
+ .height = 240,
+ .vid_ctl1 = SUBSAMPL_QVGA,
+ }, {
+ .width = 160,
+ .height = 120,
+ .vid_ctl1 = SUBSAMPL_QQVGA,
+ },
+};
+
+/* supported pixel formats */
+static const struct sr030pc30_format sr030pc30_formats[] = {
+ {
+ .code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .ispctl1_reg = 0x03,
+ }, {
+ .code = V4L2_MBUS_FMT_YVYU8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .ispctl1_reg = 0x02,
+ }, {
+ .code = V4L2_MBUS_FMT_VYUY8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .ispctl1_reg = 0,
+ }, {
+ .code = V4L2_MBUS_FMT_UYVY8_2X8,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .ispctl1_reg = 0x01,
+ }, {
+ .code = V4L2_MBUS_FMT_RGB565_2X8_BE,
+ .colorspace = V4L2_COLORSPACE_JPEG,
+ .ispctl1_reg = 0x40,
+ },
+};
+
+static const struct i2c_regval sr030pc30_base_regs[] = {
+ /* Window size and position within pixel matrix */
+ { WIN_ROWH_REG, 0x00 }, { WIN_ROWL_REG, 0x06 },
+ { WIN_COLH_REG, 0x00 }, { WIN_COLL_REG, 0x06 },
+ { WIN_HEIGHTH_REG, 0x01 }, { WIN_HEIGHTL_REG, 0xE0 },
+ { WIN_WIDTHH_REG, 0x02 }, { WIN_WIDTHL_REG, 0x80 },
+ { HBLANKH_REG, 0x01 }, { HBLANKL_REG, 0x50 },
+ { VSYNCH_REG, 0x00 }, { VSYNCL_REG, 0x14 },
+ { SYNC_CTL_REG, 0 },
+ /* Color corection and saturation */
+ { ISP_CTL_REG(0), 0x30 }, { YOFS_REG, 0x80 },
+ { DARK_YOFS_REG, 0x04 }, { AG_ABRTH_REG, 0x78 },
+ { SAT_CTL_REG, 0x1F }, { BSAT_REG, 0x90 },
+ { AG_SAT_TH_REG, 0xF0 }, { 0x1064, 0x80 },
+ { CMC_CTL_REG, 0x03 }, { CMC_OFSGH_REG, 0x3C },
+ { CMC_OFSGL_REG, 0x2C }, { CMC_SIGN_REG, 0x2F },
+ { CMC_COEF_REG(0), 0xCB }, { CMC_OFS_REG(0), 0x87 },
+ { CMC_COEF_REG(1), 0x61 }, { CMC_OFS_REG(1), 0x18 },
+ { CMC_COEF_REG(2), 0x16 }, { CMC_OFS_REG(2), 0x91 },
+ { CMC_COEF_REG(3), 0x23 }, { CMC_OFS_REG(3), 0x94 },
+ { CMC_COEF_REG(4), 0xCE }, { CMC_OFS_REG(4), 0x9f },
+ { CMC_COEF_REG(5), 0x2B }, { CMC_OFS_REG(5), 0x33 },
+ { CMC_COEF_REG(6), 0x01 }, { CMC_OFS_REG(6), 0x00 },
+ { CMC_COEF_REG(7), 0x34 }, { CMC_OFS_REG(7), 0x94 },
+ { CMC_COEF_REG(8), 0x75 }, { CMC_OFS_REG(8), 0x14 },
+ /* Color corection coefficients */
+ { GMA_CTL_REG, 0x03 }, { GMA_COEF_REG(0), 0x00 },
+ { GMA_COEF_REG(1), 0x19 }, { GMA_COEF_REG(2), 0x26 },
+ { GMA_COEF_REG(3), 0x3B }, { GMA_COEF_REG(4), 0x5D },
+ { GMA_COEF_REG(5), 0x79 }, { GMA_COEF_REG(6), 0x8E },
+ { GMA_COEF_REG(7), 0x9F }, { GMA_COEF_REG(8), 0xAF },
+ { GMA_COEF_REG(9), 0xBD }, { GMA_COEF_REG(10), 0xCA },
+ { GMA_COEF_REG(11), 0xDD }, { GMA_COEF_REG(12), 0xEC },
+ { GMA_COEF_REG(13), 0xF7 }, { GMA_COEF_REG(14), 0xFF },
+ /* Noise reduction, Z-LPF, YC-LPF and BLPF filters setup */
+ { ZLPF_CTRL_REG, 0x99 }, { ZLPF_CTRL2_REG, 0x0E },
+ { ZLPF_AGH_THR_REG, 0x29 }, { ZLPF_THR_REG, 0x0F },
+ { ZLPF_DYN_THR_REG, 0x63 }, { YCLPF_CTL1_REG, 0x23 },
+ { YCLPF_CTL2_REG, 0x3B }, { YCLPF_THR_REG, 0x05 },
+ { BLPF_CTL_REG, 0x1D }, { BLPF_THR1_REG, 0x05 },
+ { BLPF_THR2_REG, 0x04 },
+ /* Automatic white balance */
+ { AWB_CTL1_REG, 0xFB }, { AWB_CTL2_REG, 0x26 },
+ { AWB_RMAX_REG, 0x54 }, { AWB_RMIN_REG, 0x2B },
+ { AWB_BMAX_REG, 0x57 }, { AWB_BMIN_REG, 0x29 },
+ { AWB_RMAXB_REG, 0x50 }, { AWB_RMINB_REG, 0x43 },
+ { AWB_BMAXB_REG, 0x30 }, { AWB_BMINB_REG, 0x22 },
+ /* Auto exposure */
+ { AE_CTL1_REG, 0x8C }, { AE_CTL2_REG, 0x04 },
+ { AE_FRM_CTL_REG, 0x01 }, { AE_FINE_CTL_REG(0), 0x3F },
+ { AE_FINE_CTL_REG(1), 0xA3 }, { AE_FINE_CTL_REG(3), 0x34 },
+ /* Lens shading compensation */
+ { LENS_CTRL_REG, 0x01 }, { LENS_XCEN_REG, 0x80 },
+ { LENS_YCEN_REG, 0x70 }, { LENS_R_COMP_REG, 0x53 },
+ { LENS_G_COMP_REG, 0x40 }, { LENS_B_COMP_REG, 0x3e },
+ { REG_TERM, 0 },
+};
+
+static inline struct sr030pc30_info *to_sr030pc30(struct v4l2_subdev *sd)
+{
+ return container_of(sd, struct sr030pc30_info, sd);
+}
+
+static inline int set_i2c_page(struct sr030pc30_info *info,
+ struct i2c_client *client, unsigned int reg)
+{
+ int ret = 0;
+ u32 page = reg >> 8 & 0xFF;
+
+ if (info->i2c_reg_page != page && (reg & 0xFF) != 0x03) {
+ ret = i2c_smbus_write_byte_data(client, PAGEMODE_REG, page);
+ if (!ret)
+ info->i2c_reg_page = page;
+ }
+ return ret;
+}
+
+static int cam_i2c_read(struct v4l2_subdev *sd, u32 reg_addr)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+
+ int ret = set_i2c_page(info, client, reg_addr);
+ if (!ret)
+ ret = i2c_smbus_read_byte_data(client, reg_addr & 0xFF);
+ return ret;
+}
+
+static int cam_i2c_write(struct v4l2_subdev *sd, u32 reg_addr, u32 val)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+
+ int ret = set_i2c_page(info, client, reg_addr);
+ if (!ret)
+ ret = i2c_smbus_write_byte_data(
+ client, reg_addr & 0xFF, val);
+ return ret;
+}
+
+static inline int sr030pc30_bulk_write_reg(struct v4l2_subdev *sd,
+ const struct i2c_regval *msg)
+{
+ while (msg->addr != REG_TERM) {
+ int ret = cam_i2c_write(sd, msg->addr, msg->val);
+ if (ret)
+ return ret;
+ msg++;
+ }
+ return 0;
+}
+
+/* Device reset and sleep mode control */
+static int sr030pc30_pwr_ctrl(struct v4l2_subdev *sd,
+ bool reset, bool sleep)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+ u8 reg = sleep ? 0xF1 : 0xF0;
+ int ret = 0;
+
+ if (reset)
+ ret = cam_i2c_write(sd, POWER_CTRL_REG, reg | 0x02);
+ if (!ret) {
+ ret = cam_i2c_write(sd, POWER_CTRL_REG, reg);
+ if (!ret) {
+ info->sleep = sleep;
+ if (reset)
+ info->i2c_reg_page = -1;
+ }
+ }
+ return ret;
+}
+
+static inline int sr030pc30_enable_autoexposure(struct v4l2_subdev *sd, int on)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+ /* auto anti-flicker is also enabled here */
+ int ret = cam_i2c_write(sd, AE_CTL1_REG, on ? 0xDC : 0x0C);
+ if (!ret)
+ info->auto_exp = on;
+ return ret;
+}
+
+static int sr030pc30_set_exposure(struct v4l2_subdev *sd, int value)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+
+ unsigned long expos = value * info->pdata->clk_rate / (8 * 1000);
+
+ int ret = cam_i2c_write(sd, EXP_TIMEH_REG, expos >> 16 & 0xFF);
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_TIMEM_REG, expos >> 8 & 0xFF);
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_TIMEL_REG, expos & 0xFF);
+ if (!ret) { /* Turn off AE */
+ info->exposure = value;
+ ret = sr030pc30_enable_autoexposure(sd, 0);
+ }
+ return ret;
+}
+
+/* Automatic white balance control */
+static int sr030pc30_enable_autowhitebalance(struct v4l2_subdev *sd, int on)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+
+ int ret = cam_i2c_write(sd, AWB_CTL2_REG, on ? 0x2E : 0x2F);
+ if (!ret)
+ ret = cam_i2c_write(sd, AWB_CTL1_REG, on ? 0xFB : 0x7B);
+ if (!ret)
+ info->auto_wb = on;
+
+ return ret;
+}
+
+static int sr030pc30_set_flip(struct v4l2_subdev *sd)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+
+ s32 reg = cam_i2c_read(sd, VDO_CTL2_REG);
+ if (reg < 0)
+ return reg;
+
+ reg &= 0x7C;
+ if (info->hflip)
+ reg |= 0x01;
+ if (info->vflip)
+ reg |= 0x02;
+ return cam_i2c_write(sd, VDO_CTL2_REG, reg | 0x80);
+}
+
+/* Configure resolution, color format and image flip */
+static int sr030pc30_set_params(struct v4l2_subdev *sd)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+ int ret;
+
+ if (!info->curr_win)
+ return -EINVAL;
+
+ /* Configure the resolution through subsampling */
+ ret = cam_i2c_write(sd, VDO_CTL1_REG,
+ info->curr_win->vid_ctl1);
+
+ if (!ret && info->curr_fmt)
+ ret = cam_i2c_write(sd, ISP_CTL_REG(0),
+ info->curr_fmt->ispctl1_reg);
+ if (!ret)
+ ret = sr030pc30_set_flip(sd);
+
+ return ret;
+}
+
+/* Find nearest matching image pixel size. */
+static int sr030pc30_try_frame_size(struct v4l2_mbus_framefmt *mf)
+{
+ unsigned int min_err = ~0;
+ int i = ARRAY_SIZE(sr030pc30_sizes);
+ const struct sr030pc30_frmsize *fsize = &sr030pc30_sizes[0],
+ *match = NULL;
+ while (i--) {
+ int err = abs(fsize->width - mf->width)
+ + abs(fsize->height - mf->height);
+ if (err < min_err) {
+ min_err = err;
+ match = fsize;
+ }
+ fsize++;
+ }
+ if (match) {
+ mf->width = match->width;
+ mf->height = match->height;
+ return 0;
+ }
+ return -EINVAL;
+}
+
+static int sr030pc30_queryctrl(struct v4l2_subdev *sd,
+ struct v4l2_queryctrl *qc)
+{
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
+ if (qc->id == sr030pc30_ctrl[i].id) {
+ *qc = sr030pc30_ctrl[i];
+ v4l2_dbg(1, debug, sd, "%s id: %d\n",
+ __func__, qc->id);
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+static inline int sr030pc30_set_bluebalance(struct v4l2_subdev *sd, int value)
+{
+ int ret = cam_i2c_write(sd, MWB_BGAIN_REG, value);
+ if (!ret)
+ to_sr030pc30(sd)->blue_balance = value;
+ return ret;
+}
+
+static inline int sr030pc30_set_redbalance(struct v4l2_subdev *sd, int value)
+{
+ int ret = cam_i2c_write(sd, MWB_RGAIN_REG, value);
+ if (!ret)
+ to_sr030pc30(sd)->red_balance = value;
+ return ret;
+}
+
+static int sr030pc30_s_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ int i, ret = 0;
+
+ for (i = 0; i < ARRAY_SIZE(sr030pc30_ctrl); i++)
+ if (ctrl->id == sr030pc30_ctrl[i].id)
+ break;
+
+ if (i == ARRAY_SIZE(sr030pc30_ctrl))
+ return -EINVAL;
+
+ if (ctrl->value < sr030pc30_ctrl[i].minimum ||
+ ctrl->value > sr030pc30_ctrl[i].maximum)
+ return -ERANGE;
+
+ v4l2_dbg(1, debug, sd, "%s: ctrl_id: %d, value: %d\n",
+ __func__, ctrl->id, ctrl->value);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ sr030pc30_enable_autowhitebalance(sd, ctrl->value);
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ret = sr030pc30_set_bluebalance(sd, ctrl->value);
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ret = sr030pc30_set_redbalance(sd, ctrl->value);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ sr030pc30_enable_autoexposure(sd,
+ ctrl->value == V4L2_EXPOSURE_AUTO);
+ break;
+ case V4L2_CID_EXPOSURE:
+ ret = sr030pc30_set_exposure(sd, ctrl->value);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return ret;
+}
+
+static int sr030pc30_g_ctrl(struct v4l2_subdev *sd,
+ struct v4l2_control *ctrl)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+
+ v4l2_dbg(1, debug, sd, "%s: id: %d\n", __func__, ctrl->id);
+
+ switch (ctrl->id) {
+ case V4L2_CID_AUTO_WHITE_BALANCE:
+ ctrl->value = info->auto_wb;
+ break;
+ case V4L2_CID_BLUE_BALANCE:
+ ctrl->value = info->blue_balance;
+ break;
+ case V4L2_CID_RED_BALANCE:
+ ctrl->value = info->red_balance;
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl->value = info->auto_exp;
+ break;
+ case V4L2_CID_EXPOSURE:
+ ctrl->value = info->exposure;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int sr030pc30_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
+ enum v4l2_mbus_pixelcode *code)
+{
+ if (!code || index >= ARRAY_SIZE(sr030pc30_formats))
+ return -EINVAL;
+
+ *code = sr030pc30_formats[index].code;
+ return 0;
+}
+
+static int sr030pc30_g_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+ int ret;
+
+ if (!mf)
+ return -EINVAL;
+
+ if (!info->curr_win || !info->curr_fmt) {
+ ret = sr030pc30_set_params(sd);
+ if (ret)
+ return ret;
+ }
+
+ mf->width = info->curr_win->width;
+ mf->height = info->curr_win->height;
+ mf->code = info->curr_fmt->code;
+ mf->colorspace = info->curr_fmt->colorspace;
+ mf->field = V4L2_FIELD_NONE;
+
+ return 0;
+}
+
+/* Return nearest media bus frame format. */
+static const struct sr030pc30_format *try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ int i = ARRAY_SIZE(sr030pc30_formats);
+
+ sr030pc30_try_frame_size(mf);
+
+ while (i--)
+ if (mf->code == sr030pc30_formats[i].code)
+ break;
+
+ mf->code = sr030pc30_formats[i].code;
+
+ return &sr030pc30_formats[i];
+}
+
+/* Return nearest media bus frame format. */
+static int sr030pc30_try_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ if (!sd || !mf)
+ return -EINVAL;
+
+ try_fmt(sd, mf);
+ return 0;
+}
+
+static int sr030pc30_s_fmt(struct v4l2_subdev *sd,
+ struct v4l2_mbus_framefmt *mf)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+
+ if (!sd || !mf)
+ return -EINVAL;
+
+ info->curr_fmt = try_fmt(sd, mf);
+
+ return sr030pc30_set_params(sd);
+}
+
+static int sr030pc30_base_config(struct v4l2_subdev *sd)
+{
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+ int ret;
+ unsigned long expmin, expmax;
+
+ ret = sr030pc30_bulk_write_reg(sd, sr030pc30_base_regs);
+ if (!ret) {
+ info->curr_fmt = &sr030pc30_formats[0];
+ info->curr_win = &sr030pc30_sizes[0];
+ ret = sr030pc30_set_params(sd);
+ }
+ if (!ret)
+ ret = sr030pc30_pwr_ctrl(sd, false, false);
+
+ if (!ret && !info->pdata)
+ return ret;
+
+ expmin = EXPOS_MIN_MS * info->pdata->clk_rate / (8 * 1000);
+ expmax = EXPOS_MAX_MS * info->pdata->clk_rate / (8 * 1000);
+
+ v4l2_dbg(1, debug, sd, "%s: expmin= %lx, expmax= %lx", __func__,
+ expmin, expmax);
+
+ /* Setting up manual exposure time range */
+ ret = cam_i2c_write(sd, EXP_MMINH_REG, expmin >> 8 & 0xFF);
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_MMINL_REG, expmin & 0xFF);
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_MMAXH_REG, expmax >> 16 & 0xFF);
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_MMAXM_REG, expmax >> 8 & 0xFF);
+ if (!ret)
+ ret = cam_i2c_write(sd, EXP_MMAXL_REG, expmax & 0xFF);
+
+ return ret;
+}
+
+static int sr030pc30_s_stream(struct v4l2_subdev *sd, int enable)
+{
+ return 0;
+}
+
+static int sr030pc30_s_power(struct v4l2_subdev *sd, int on)
+{
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+ const struct sr030pc30_platform_data *pdata = info->pdata;
+ int ret;
+
+ if (WARN(pdata == NULL, "No platform data!\n"))
+ return -ENOMEM;
+
+ /*
+ * Put sensor into power sleep mode before switching off
+ * power and disabling MCLK.
+ */
+ if (!on)
+ sr030pc30_pwr_ctrl(sd, false, true);
+
+ /* set_power controls sensor's power and clock */
+ if (pdata->set_power) {
+ ret = pdata->set_power(&client->dev, on);
+ if (ret)
+ return ret;
+ }
+
+ if (on) {
+ ret = sr030pc30_base_config(sd);
+ } else {
+ info->curr_win = NULL;
+ info->curr_fmt = NULL;
+ }
+
+ return ret;
+}
+
+static const struct v4l2_subdev_core_ops sr030pc30_core_ops = {
+ .s_power = sr030pc30_s_power,
+ .queryctrl = sr030pc30_queryctrl,
+ .s_ctrl = sr030pc30_s_ctrl,
+ .g_ctrl = sr030pc30_g_ctrl,
+};
+
+static const struct v4l2_subdev_video_ops sr030pc30_video_ops = {
+ .s_stream = sr030pc30_s_stream,
+ .g_mbus_fmt = sr030pc30_g_fmt,
+ .s_mbus_fmt = sr030pc30_s_fmt,
+ .try_mbus_fmt = sr030pc30_try_fmt,
+ .enum_mbus_fmt = sr030pc30_enum_fmt,
+};
+
+static const struct v4l2_subdev_ops sr030pc30_ops = {
+ .core = &sr030pc30_core_ops,
+ .video = &sr030pc30_video_ops,
+};
+
+/*
+ * Detect sensor type. Return 0 if SR030PC30 was detected
+ * or -ENODEV otherwise.
+ */
+static int sr030pc30_detect(struct i2c_client *client)
+{
+ const struct sr030pc30_platform_data *pdata
+ = client->dev.platform_data;
+ int ret;
+
+ /* Enable sensor's power and clock */
+ if (pdata->set_power) {
+ ret = pdata->set_power(&client->dev, 1);
+ if (ret)
+ return ret;
+ }
+
+ ret = i2c_smbus_read_byte_data(client, DEVICE_ID_REG);
+
+ if (pdata->set_power)
+ pdata->set_power(&client->dev, 0);
+
+ if (ret < 0) {
+ dev_err(&client->dev, "%s: I2C read failed\n", __func__);
+ return ret;
+ }
+
+ return ret == SR030PC30_ID ? 0 : -ENODEV;
+}
+
+
+static int sr030pc30_probe(struct i2c_client *client,
+ const struct i2c_device_id *id)
+{
+ struct sr030pc30_info *info;
+ struct v4l2_subdev *sd;
+ const struct sr030pc30_platform_data *pdata
+ = client->dev.platform_data;
+ int ret;
+
+ if (!pdata) {
+ dev_err(&client->dev, "No platform data!");
+ return -EIO;
+ }
+
+ ret = sr030pc30_detect(client);
+ if (ret)
+ return ret;
+
+ info = kzalloc(sizeof(*info), GFP_KERNEL);
+ if (!info)
+ return -ENOMEM;
+
+ sd = &info->sd;
+ strcpy(sd->name, MODULE_NAME);
+ info->pdata = client->dev.platform_data;
+
+ v4l2_i2c_subdev_init(sd, client, &sr030pc30_ops);
+
+ info->i2c_reg_page = -1;
+ info->hflip = 1;
+ info->auto_exp = 1;
+ info->exposure = 30;
+
+ return 0;
+}
+
+static int sr030pc30_remove(struct i2c_client *client)
+{
+ struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct sr030pc30_info *info = to_sr030pc30(sd);
+
+ v4l2_device_unregister_subdev(sd);
+ kfree(info);
+ return 0;
+}
+
+static const struct i2c_device_id sr030pc30_id[] = {
+ { MODULE_NAME, 0 },
+ { },
+};
+MODULE_DEVICE_TABLE(i2c, sr030pc30_id);
+
+
+static struct i2c_driver sr030pc30_i2c_driver = {
+ .driver = {
+ .name = MODULE_NAME
+ },
+ .probe = sr030pc30_probe,
+ .remove = sr030pc30_remove,
+ .id_table = sr030pc30_id,
+};
+
+static int __init sr030pc30_init(void)
+{
+ return i2c_add_driver(&sr030pc30_i2c_driver);
+}
+
+static void __exit sr030pc30_exit(void)
+{
+ i2c_del_driver(&sr030pc30_i2c_driver);
+}
+
+module_init(sr030pc30_init);
+module_exit(sr030pc30_exit);
+
+MODULE_DESCRIPTION("Siliconfile SR030PC30 camera driver");
+MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index f07a0f6b71c4..d1a2cefbf55b 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -27,7 +27,6 @@
#include <linux/kernel.h>
#include <linux/errno.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/usb.h>
#include <linux/mm.h>
@@ -231,120 +230,6 @@ static int stk_initialise(struct stk_camera *dev)
return -1;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-
-/* sysfs functions */
-/*FIXME cleanup this */
-
-static ssize_t show_brightness(struct device *class,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- return sprintf(buf, "%X\n", dev->vsettings.brightness);
-}
-
-static ssize_t store_brightness(struct device *class,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- char *endp;
- unsigned long value;
- int ret;
-
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- value = simple_strtoul(buf, &endp, 16);
-
- dev->vsettings.brightness = (int) value;
-
- ret = stk_sensor_set_brightness(dev, value >> 8);
- if (ret)
- return ret;
- else
- return count;
-}
-
-static ssize_t show_hflip(struct device *class,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- return sprintf(buf, "%d\n", dev->vsettings.hflip);
-}
-
-static ssize_t store_hflip(struct device *class,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- if (strncmp(buf, "1", 1) == 0)
- dev->vsettings.hflip = 1;
- else if (strncmp(buf, "0", 1) == 0)
- dev->vsettings.hflip = 0;
- else
- return -EINVAL;
-
- return strlen(buf);
-}
-
-static ssize_t show_vflip(struct device *class,
- struct device_attribute *attr, char *buf)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- return sprintf(buf, "%d\n", dev->vsettings.vflip);
-}
-
-static ssize_t store_vflip(struct device *class,
- struct device_attribute *attr, const char *buf, size_t count)
-{
- struct video_device *vdev = to_video_device(class);
- struct stk_camera *dev = vdev_to_camera(vdev);
-
- if (strncmp(buf, "1", 1) == 0)
- dev->vsettings.vflip = 1;
- else if (strncmp(buf, "0", 1) == 0)
- dev->vsettings.vflip = 0;
- else
- return -EINVAL;
-
- return strlen(buf);
-}
-
-static DEVICE_ATTR(brightness, S_IRUGO | S_IWUGO,
- show_brightness, store_brightness);
-static DEVICE_ATTR(hflip, S_IRUGO | S_IWUGO, show_hflip, store_hflip);
-static DEVICE_ATTR(vflip, S_IRUGO | S_IWUGO, show_vflip, store_vflip);
-
-static int stk_create_sysfs_files(struct video_device *vdev)
-{
- int ret;
-
- ret = device_create_file(&vdev->dev, &dev_attr_brightness);
- ret += device_create_file(&vdev->dev, &dev_attr_hflip);
- ret += device_create_file(&vdev->dev, &dev_attr_vflip);
- if (ret)
- STK_WARNING("Could not create sysfs files\n");
- return ret;
-}
-
-static void stk_remove_sysfs_files(struct video_device *vdev)
-{
- device_remove_file(&vdev->dev, &dev_attr_brightness);
- device_remove_file(&vdev->dev, &dev_attr_hflip);
- device_remove_file(&vdev->dev, &dev_attr_vflip);
-}
-
-#else
-#define stk_create_sysfs_files(a)
-#define stk_remove_sysfs_files(a)
-#endif
-
/* *********************************************** */
/*
* This function is called as an URB transfert is complete (Isochronous pipe).
@@ -673,14 +558,11 @@ static int v4l_stk_open(struct file *fp)
vdev = video_devdata(fp);
dev = vdev_to_camera(vdev);
- lock_kernel();
if (dev == NULL || !is_present(dev)) {
- unlock_kernel();
return -ENXIO;
}
fp->private_data = dev;
usb_autopm_get_interface(dev->interface);
- unlock_kernel();
return 0;
}
@@ -882,7 +764,24 @@ static struct v4l2_queryctrl stk_controls[] = {
.step = 0x0100,
.default_value = 0x6000,
},
- /*TODO: get more controls to work */
+ {
+ .id = V4L2_CID_HFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Horizontal Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Vertical Flip",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ },
};
static int stk_vidioc_queryctrl(struct file *filp,
@@ -910,6 +809,12 @@ static int stk_vidioc_g_ctrl(struct file *filp,
case V4L2_CID_BRIGHTNESS:
c->value = dev->vsettings.brightness;
break;
+ case V4L2_CID_HFLIP:
+ c->value = dev->vsettings.hflip;
+ break;
+ case V4L2_CID_VFLIP:
+ c->value = dev->vsettings.vflip;
+ break;
default:
return -EINVAL;
}
@@ -924,6 +829,12 @@ static int stk_vidioc_s_ctrl(struct file *filp,
case V4L2_CID_BRIGHTNESS:
dev->vsettings.brightness = c->value;
return stk_sensor_set_brightness(dev, c->value >> 8);
+ case V4L2_CID_HFLIP:
+ dev->vsettings.hflip = c->value;
+ return 0;
+ case V4L2_CID_VFLIP:
+ dev->vsettings.vflip = c->value;
+ return 0;
default:
return -EINVAL;
}
@@ -1398,8 +1309,6 @@ static int stk_camera_probe(struct usb_interface *interface,
goto error;
}
- stk_create_sysfs_files(&dev->vdev);
-
return 0;
error:
@@ -1415,7 +1324,6 @@ static void stk_camera_disconnect(struct usb_interface *interface)
unset_present(dev);
wake_up_interruptible(&dev->wait_frame);
- stk_remove_sysfs_files(&dev->vdev);
STK_INFO("Syntek USB2.0 Camera release resources device %s\n",
video_device_node_name(&dev->vdev));
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
deleted file mode 100644
index a057824e7ebc..000000000000
--- a/drivers/media/video/stradis.c
+++ /dev/null
@@ -1,2213 +0,0 @@
-/*
- * stradis.c - stradis 4:2:2 mpeg decoder driver
- *
- * Stradis 4:2:2 MPEG-2 Decoder Driver
- * Copyright (C) 1999 Nathan Laredo <laredo@gnu.org>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/fs.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/mm.h>
-#include <linux/init.h>
-#include <linux/poll.h>
-#include <linux/pci.h>
-#include <linux/signal.h>
-#include <asm/io.h>
-#include <linux/ioport.h>
-#include <asm/pgtable.h>
-#include <asm/page.h>
-#include <linux/sched.h>
-#include <asm/types.h>
-#include <linux/types.h>
-#include <linux/interrupt.h>
-#include <asm/uaccess.h>
-#include <linux/vmalloc.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include "saa7146.h"
-#include "saa7146reg.h"
-#include "ibmmpeg2.h"
-#include "saa7121.h"
-#include "cs8420.h"
-
-#define DEBUG(x) /* debug driver */
-#undef IDEBUG /* debug irq handler */
-#undef MDEBUG /* debug memory management */
-
-#define SAA7146_MAX 6
-
-static struct saa7146 saa7146s[SAA7146_MAX];
-
-static int saa_num; /* number of SAA7146s in use */
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-MODULE_LICENSE("GPL");
-
-#define nDebNormal 0x00480000
-#define nDebNoInc 0x00480000
-#define nDebVideo 0xd0480000
-#define nDebAudio 0xd0400000
-#define nDebDMA 0x02c80000
-
-#define oDebNormal 0x13c80000
-#define oDebNoInc 0x13c80000
-#define oDebVideo 0xd1080000
-#define oDebAudio 0xd1080000
-#define oDebDMA 0x03080000
-
-#define NewCard (saa->boardcfg[3])
-#define ChipControl (saa->boardcfg[1])
-#define NTSCFirstActive (saa->boardcfg[4])
-#define PALFirstActive (saa->boardcfg[5])
-#define NTSCLastActive (saa->boardcfg[54])
-#define PALLastActive (saa->boardcfg[55])
-#define Have2MB (saa->boardcfg[18] & 0x40)
-#define HaveCS8420 (saa->boardcfg[18] & 0x04)
-#define IBMMPEGCD20 (saa->boardcfg[18] & 0x20)
-#define HaveCS3310 (saa->boardcfg[18] & 0x01)
-#define CS3310MaxLvl ((saa->boardcfg[30] << 8) | saa->boardcfg[31])
-#define HaveCS4341 (saa->boardcfg[40] == 2)
-#define SDIType (saa->boardcfg[27])
-#define CurrentMode (saa->boardcfg[2])
-
-#define debNormal (NewCard ? nDebNormal : oDebNormal)
-#define debNoInc (NewCard ? nDebNoInc : oDebNoInc)
-#define debVideo (NewCard ? nDebVideo : oDebVideo)
-#define debAudio (NewCard ? nDebAudio : oDebAudio)
-#define debDMA (NewCard ? nDebDMA : oDebDMA)
-
-#ifdef USE_RESCUE_EEPROM_SDM275
-static unsigned char rescue_eeprom[64] = {
- 0x00, 0x01, 0x04, 0x13, 0x26, 0x0f, 0x10, 0x00, 0x00, 0x00, 0x43, 0x63,
- 0x22, 0x01, 0x29, 0x15, 0x73, 0x00, 0x1f, 'd', 'e', 'c', 'x', 'l',
- 'd', 'v', 'a', 0x02, 0x00, 0x01, 0x00, 0xcc, 0xa4, 0x63, 0x09, 0xe2,
- 0x10, 0x00, 0x0a, 0x00, 0x02, 0x02, 'd', 'e', 'c', 'x', 'l', 'a',
- 0x00, 0x00, 0x42, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
- 0x00, 0x00, 0x00, 0x00,
-};
-#endif
-
-/* ----------------------------------------------------------------------- */
-/* Hardware I2C functions */
-static void I2CWipe(struct saa7146 *saa)
-{
- int i;
- /* set i2c to ~=100kHz, abort transfer, clear busy */
- saawrite(0x600 | SAA7146_I2C_ABORT, SAA7146_I2C_STATUS);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
- saawrite(0x600, SAA7146_I2C_STATUS);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
- saawrite(0x600, SAA7146_I2C_STATUS);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
-}
-
-/* read I2C */
-static int I2CRead(struct saa7146 *saa, unsigned char addr,
- unsigned char subaddr, int dosub)
-{
- int i;
-
- if (saaread(SAA7146_I2C_STATUS) & 0x3c)
- I2CWipe(saa);
- for (i = 0;
- i < 1000 && (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY);
- i++)
- schedule();
- if (i == 1000)
- I2CWipe(saa);
- if (dosub)
- saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 8) |
- ((subaddr & 0xff) << 16) | 0xed, SAA7146_I2C_TRANSFER);
- else
- saawrite(((addr & 0xfe) << 24) | (((addr | 1) & 0xff) << 16) |
- 0xf1, SAA7146_I2C_TRANSFER);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
- /* wait for valid data */
- for (i = 0; i < 1000 &&
- (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
- schedule();
- if (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_ERR)
- return -1;
- if (i == 1000)
- printk("i2c setup read timeout\n");
- saawrite(0x41, SAA7146_I2C_TRANSFER);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) |
- SAA7146_MC2_UPLD_I2C, SAA7146_MC2);
- /* wait for i2c registers to be programmed */
- for (i = 0; i < 1000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_I2C); i++)
- schedule();
- /* wait for valid data */
- for (i = 0; i < 1000 &&
- (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_BUSY); i++)
- schedule();
- if (saaread(SAA7146_I2C_TRANSFER) & SAA7146_I2C_ERR)
- return -1;
- if (i == 1000)
- printk("i2c read timeout\n");
- return ((saaread(SAA7146_I2C_TRANSFER) >> 24) & 0xff);
-}
-
-/* set both to write both bytes, reset it to write only b1 */
-
-static int I2CWrite(struct saa7146 *saa, unsigned char addr, unsigned char b1,
- unsigned char b2, int both)
-{
- int i;
- u32 data;
-
- if (saaread(SAA7146_I2C_STATUS) & 0x3c)
- I2CWipe(saa);
- for (i = 0; i < 1000 &&
- (saaread(SAA7146_I2C_STATUS) & SAA7146_I2C_BUSY); i++)
- schedule();
- if (i == 1000)
- I2CWipe(saa);
- data = ((addr & 0xfe) << 24) | ((b1 & 0xff) << 16);
- if (both)
- data |= ((b2 & 0xff) << 8) | 0xe5;
- else
- data |= 0xd1;
- saawrite(data, SAA7146_I2C_TRANSFER);
- saawrite((SAA7146_MC2_UPLD_I2C << 16) | SAA7146_MC2_UPLD_I2C,
- SAA7146_MC2);
- return 0;
-}
-
-static void attach_inform(struct saa7146 *saa, int id)
-{
- int i;
-
- DEBUG(printk(KERN_DEBUG "stradis%d: i2c: device found=%02x\n", saa->nr,
- id));
- if (id == 0xa0) { /* we have rev2 or later board, fill in info */
- for (i = 0; i < 64; i++)
- saa->boardcfg[i] = I2CRead(saa, 0xa0, i, 1);
-#ifdef USE_RESCUE_EEPROM_SDM275
- if (saa->boardcfg[0] != 0) {
- printk("stradis%d: WARNING: EEPROM STORED VALUES HAVE "
- "BEEN IGNORED\n", saa->nr);
- for (i = 0; i < 64; i++)
- saa->boardcfg[i] = rescue_eeprom[i];
- }
-#endif
- printk("stradis%d: config =", saa->nr);
- for (i = 0; i < 51; i++) {
- printk(" %02x", saa->boardcfg[i]);
- }
- printk("\n");
- }
-}
-
-static void I2CBusScan(struct saa7146 *saa)
-{
- int i;
- for (i = 0; i < 0xff; i += 2)
- if ((I2CRead(saa, i, 0, 0)) >= 0)
- attach_inform(saa, i);
-}
-
-static int debiwait_maxwait;
-
-static int wait_for_debi_done(struct saa7146 *saa)
-{
- int i;
-
- /* wait for registers to be programmed */
- for (i = 0; i < 100000 &&
- !(saaread(SAA7146_MC2) & SAA7146_MC2_UPLD_DEBI); i++)
- saaread(SAA7146_MC2);
- /* wait for transfer to complete */
- for (i = 0; i < 500000 &&
- (saaread(SAA7146_PSR) & SAA7146_PSR_DEBI_S); i++)
- saaread(SAA7146_MC2);
-
- if (i > debiwait_maxwait)
- printk("wait-for-debi-done maxwait: %d\n",
- debiwait_maxwait = i);
-
- if (i == 500000)
- return -1;
-
- return 0;
-}
-
-static int debiwrite(struct saa7146 *saa, u32 config, int addr,
- u32 val, int count)
-{
- u32 cmd;
- if (count <= 0 || count > 32764)
- return -1;
- if (wait_for_debi_done(saa) < 0)
- return -1;
- saawrite(config, SAA7146_DEBI_CONFIG);
- if (count <= 4) /* immediate transfer */
- saawrite(val, SAA7146_DEBI_AD);
- else /* block transfer */
- saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
- saawrite((cmd = (count << 17) | (addr & 0xffff)), SAA7146_DEBI_COMMAND);
- saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
- SAA7146_MC2);
- return 0;
-}
-
-static u32 debiread(struct saa7146 *saa, u32 config, int addr, int count)
-{
- u32 result = 0;
-
- if (count > 32764 || count <= 0)
- return 0;
- if (wait_for_debi_done(saa) < 0)
- return 0;
- saawrite(virt_to_bus(saa->dmadebi), SAA7146_DEBI_AD);
- saawrite((count << 17) | 0x10000 | (addr & 0xffff),
- SAA7146_DEBI_COMMAND);
- saawrite(config, SAA7146_DEBI_CONFIG);
- saawrite((SAA7146_MC2_UPLD_DEBI << 16) | SAA7146_MC2_UPLD_DEBI,
- SAA7146_MC2);
- if (count > 4) /* not an immediate transfer */
- return count;
- wait_for_debi_done(saa);
- result = saaread(SAA7146_DEBI_AD);
- if (count == 1)
- result &= 0xff;
- if (count == 2)
- result &= 0xffff;
- if (count == 3)
- result &= 0xffffff;
- return result;
-}
-
-static void do_irq_send_data(struct saa7146 *saa)
-{
- int split, audbytes, vidbytes;
-
- saawrite(SAA7146_PSR_PIN1, SAA7146_IER);
- /* if special feature mode in effect, disable audio sending */
- if (saa->playmode != VID_PLAY_NORMAL)
- saa->audtail = saa->audhead = 0;
- if (saa->audhead <= saa->audtail)
- audbytes = saa->audtail - saa->audhead;
- else
- audbytes = 65536 - (saa->audhead - saa->audtail);
- if (saa->vidhead <= saa->vidtail)
- vidbytes = saa->vidtail - saa->vidhead;
- else
- vidbytes = 524288 - (saa->vidhead - saa->vidtail);
- if (audbytes == 0 && vidbytes == 0 && saa->osdtail == saa->osdhead) {
- saawrite(0, SAA7146_IER);
- return;
- }
- /* if at least 1 block audio waiting and audio fifo isn't full */
- if (audbytes >= 2048 && (debiread(saa, debNormal, IBM_MP2_AUD_FIFO, 2)
- & 0xff) < 60) {
- if (saa->audhead > saa->audtail)
- split = 65536 - saa->audhead;
- else
- split = 0;
- audbytes = 2048;
- if (split > 0 && split < 2048) {
- memcpy(saa->dmadebi, saa->audbuf + saa->audhead, split);
- saa->audhead = 0;
- audbytes -= split;
- } else
- split = 0;
- memcpy(saa->dmadebi + split, saa->audbuf + saa->audhead,
- audbytes);
- saa->audhead += audbytes;
- saa->audhead &= 0xffff;
- debiwrite(saa, debAudio, (NewCard ? IBM_MP2_AUD_FIFO :
- IBM_MP2_AUD_FIFOW), 0, 2048);
- wake_up_interruptible(&saa->audq);
- /* if at least 1 block video waiting and video fifo isn't full */
- } else if (vidbytes >= 30720 && (debiread(saa, debNormal,
- IBM_MP2_FIFO, 2)) < 16384) {
- if (saa->vidhead > saa->vidtail)
- split = 524288 - saa->vidhead;
- else
- split = 0;
- vidbytes = 30720;
- if (split > 0 && split < 30720) {
- memcpy(saa->dmadebi, saa->vidbuf + saa->vidhead, split);
- saa->vidhead = 0;
- vidbytes -= split;
- } else
- split = 0;
- memcpy(saa->dmadebi + split, saa->vidbuf + saa->vidhead,
- vidbytes);
- saa->vidhead += vidbytes;
- saa->vidhead &= 0x7ffff;
- debiwrite(saa, debVideo, (NewCard ? IBM_MP2_FIFO :
- IBM_MP2_FIFOW), 0, 30720);
- wake_up_interruptible(&saa->vidq);
- }
- saawrite(SAA7146_PSR_DEBI_S | SAA7146_PSR_PIN1, SAA7146_IER);
-}
-
-static void send_osd_data(struct saa7146 *saa)
-{
- int size = saa->osdtail - saa->osdhead;
- if (size > 30720)
- size = 30720;
- /* ensure some multiple of 8 bytes is transferred */
- size = 8 * ((size + 8) >> 3);
- if (size) {
- debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR,
- (saa->osdhead >> 3), 2);
- memcpy(saa->dmadebi, &saa->osdbuf[saa->osdhead], size);
- saa->osdhead += size;
- /* block transfer of next 8 bytes to ~32k bytes */
- debiwrite(saa, debNormal, IBM_MP2_OSD_DATA, 0, size);
- }
- if (saa->osdhead >= saa->osdtail) {
- saa->osdhead = saa->osdtail = 0;
- debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
- }
-}
-
-static irqreturn_t saa7146_irq(int irq, void *dev_id)
-{
- struct saa7146 *saa = dev_id;
- u32 stat, astat;
- int count;
- int handled = 0;
-
- count = 0;
- while (1) {
- /* get/clear interrupt status bits */
- stat = saaread(SAA7146_ISR);
- astat = stat & saaread(SAA7146_IER);
- if (!astat)
- break;
- handled = 1;
- saawrite(astat, SAA7146_ISR);
- if (astat & SAA7146_PSR_DEBI_S) {
- do_irq_send_data(saa);
- }
- if (astat & SAA7146_PSR_PIN1) {
- int istat;
- /* the following read will trigger DEBI_S */
- istat = debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
- if (istat & 1) {
- saawrite(0, SAA7146_IER);
- send_osd_data(saa);
- saawrite(SAA7146_PSR_DEBI_S |
- SAA7146_PSR_PIN1, SAA7146_IER);
- }
- if (istat & 0x20) { /* Video Start */
- saa->vidinfo.frame_count++;
- }
- if (istat & 0x400) { /* Picture Start */
- /* update temporal reference */
- }
- if (istat & 0x200) { /* Picture Resolution Change */
- /* read new resolution */
- }
- if (istat & 0x100) { /* New User Data found */
- /* read new user data */
- }
- if (istat & 0x1000) { /* new GOP/SMPTE */
- /* read new SMPTE */
- }
- if (istat & 0x8000) { /* Sequence Start Code */
- /* reset frame counter, load sizes */
- saa->vidinfo.frame_count = 0;
- saa->vidinfo.h_size = 704;
- saa->vidinfo.v_size = 480;
-#if 0
- if (saa->endmarkhead != saa->endmarktail) {
- saa->audhead =
- saa->endmark[saa->endmarkhead];
- saa->endmarkhead++;
- if (saa->endmarkhead >= MAX_MARKS)
- saa->endmarkhead = 0;
- }
-#endif
- }
- if (istat & 0x4000) { /* Sequence Error Code */
- if (saa->endmarkhead != saa->endmarktail) {
- saa->audhead =
- saa->endmark[saa->endmarkhead];
- saa->endmarkhead++;
- if (saa->endmarkhead >= MAX_MARKS)
- saa->endmarkhead = 0;
- }
- }
- }
-#ifdef IDEBUG
- if (astat & SAA7146_PSR_PPEF) {
- IDEBUG(printk("stradis%d irq: PPEF\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PABO) {
- IDEBUG(printk("stradis%d irq: PABO\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PPED) {
- IDEBUG(printk("stradis%d irq: PPED\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_I1) {
- IDEBUG(printk("stradis%d irq: RPS_I1\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_I0) {
- IDEBUG(printk("stradis%d irq: RPS_I0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_LATE1) {
- IDEBUG(printk("stradis%d irq: RPS_LATE1\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_LATE0) {
- IDEBUG(printk("stradis%d irq: RPS_LATE0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_E1) {
- IDEBUG(printk("stradis%d irq: RPS_E1\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_E0) {
- IDEBUG(printk("stradis%d irq: RPS_E0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_TO1) {
- IDEBUG(printk("stradis%d irq: RPS_TO1\n", saa->nr));
- }
- if (astat & SAA7146_PSR_RPS_TO0) {
- IDEBUG(printk("stradis%d irq: RPS_TO0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_UPLD) {
- IDEBUG(printk("stradis%d irq: UPLD\n", saa->nr));
- }
- if (astat & SAA7146_PSR_DEBI_E) {
- IDEBUG(printk("stradis%d irq: DEBI_E\n", saa->nr));
- }
- if (astat & SAA7146_PSR_I2C_S) {
- IDEBUG(printk("stradis%d irq: I2C_S\n", saa->nr));
- }
- if (astat & SAA7146_PSR_I2C_E) {
- IDEBUG(printk("stradis%d irq: I2C_E\n", saa->nr));
- }
- if (astat & SAA7146_PSR_A2_IN) {
- IDEBUG(printk("stradis%d irq: A2_IN\n", saa->nr));
- }
- if (astat & SAA7146_PSR_A2_OUT) {
- IDEBUG(printk("stradis%d irq: A2_OUT\n", saa->nr));
- }
- if (astat & SAA7146_PSR_A1_IN) {
- IDEBUG(printk("stradis%d irq: A1_IN\n", saa->nr));
- }
- if (astat & SAA7146_PSR_A1_OUT) {
- IDEBUG(printk("stradis%d irq: A1_OUT\n", saa->nr));
- }
- if (astat & SAA7146_PSR_AFOU) {
- IDEBUG(printk("stradis%d irq: AFOU\n", saa->nr));
- }
- if (astat & SAA7146_PSR_V_PE) {
- IDEBUG(printk("stradis%d irq: V_PE\n", saa->nr));
- }
- if (astat & SAA7146_PSR_VFOU) {
- IDEBUG(printk("stradis%d irq: VFOU\n", saa->nr));
- }
- if (astat & SAA7146_PSR_FIDA) {
- IDEBUG(printk("stradis%d irq: FIDA\n", saa->nr));
- }
- if (astat & SAA7146_PSR_FIDB) {
- IDEBUG(printk("stradis%d irq: FIDB\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PIN3) {
- IDEBUG(printk("stradis%d irq: PIN3\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PIN2) {
- IDEBUG(printk("stradis%d irq: PIN2\n", saa->nr));
- }
- if (astat & SAA7146_PSR_PIN0) {
- IDEBUG(printk("stradis%d irq: PIN0\n", saa->nr));
- }
- if (astat & SAA7146_PSR_ECS) {
- IDEBUG(printk("stradis%d irq: ECS\n", saa->nr));
- }
- if (astat & SAA7146_PSR_EC3S) {
- IDEBUG(printk("stradis%d irq: EC3S\n", saa->nr));
- }
- if (astat & SAA7146_PSR_EC0S) {
- IDEBUG(printk("stradis%d irq: EC0S\n", saa->nr));
- }
-#endif
- count++;
- if (count > 15)
- printk(KERN_WARNING "stradis%d: irq loop %d\n",
- saa->nr, count);
- if (count > 20) {
- saawrite(0, SAA7146_IER);
- printk(KERN_ERR
- "stradis%d: IRQ loop cleared\n", saa->nr);
- }
- }
- return IRQ_RETVAL(handled);
-}
-
-static int ibm_send_command(struct saa7146 *saa,
- int command, int data, int chain)
-{
- int i;
-
- if (chain)
- debiwrite(saa, debNormal, IBM_MP2_COMMAND, (command << 1)| 1,2);
- else
- debiwrite(saa, debNormal, IBM_MP2_COMMAND, command << 1, 2);
- debiwrite(saa, debNormal, IBM_MP2_CMD_DATA, data, 2);
- debiwrite(saa, debNormal, IBM_MP2_CMD_STAT, 1, 2);
- for (i = 0; i < 100 &&
- (debiread(saa, debNormal, IBM_MP2_CMD_STAT, 2) & 1); i++)
- schedule();
- if (i == 100)
- return -1;
- return 0;
-}
-
-static void cs4341_setlevel(struct saa7146 *saa, int left, int right)
-{
- I2CWrite(saa, 0x22, 0x03, left > 94 ? 94 : left, 2);
- I2CWrite(saa, 0x22, 0x04, right > 94 ? 94 : right, 2);
-}
-
-static void initialize_cs4341(struct saa7146 *saa)
-{
- int i;
- for (i = 0; i < 200; i++) {
- /* auto mute off, power on, no de-emphasis */
- /* I2S data up to 24-bit 64xFs internal SCLK */
- I2CWrite(saa, 0x22, 0x01, 0x11, 2);
- /* ATAPI mixer settings */
- I2CWrite(saa, 0x22, 0x02, 0x49, 2);
- /* attenuation left 3db */
- I2CWrite(saa, 0x22, 0x03, 0x00, 2);
- /* attenuation right 3db */
- I2CWrite(saa, 0x22, 0x04, 0x00, 2);
- I2CWrite(saa, 0x22, 0x01, 0x10, 2);
- if (I2CRead(saa, 0x22, 0x02, 1) == 0x49)
- break;
- schedule();
- }
- printk("stradis%d: CS4341 initialized (%d)\n", saa->nr, i);
- return;
-}
-
-static void initialize_cs8420(struct saa7146 *saa, int pro)
-{
- int i;
- u8 *sequence;
- if (pro)
- sequence = mode8420pro;
- else
- sequence = mode8420con;
- for (i = 0; i < INIT8420LEN; i++)
- I2CWrite(saa, 0x20, init8420[i * 2], init8420[i * 2 + 1], 2);
- for (i = 0; i < MODE8420LEN; i++)
- I2CWrite(saa, 0x20, sequence[i * 2], sequence[i * 2 + 1], 2);
- printk("stradis%d: CS8420 initialized\n", saa->nr);
-}
-
-static void initialize_saa7121(struct saa7146 *saa, int dopal)
-{
- int i, mod;
- u8 *sequence;
- if (dopal)
- sequence = init7121pal;
- else
- sequence = init7121ntsc;
- mod = saaread(SAA7146_PSR) & 0x08;
- /* initialize PAL/NTSC video encoder */
- for (i = 0; i < INIT7121LEN; i++) {
- if (NewCard) { /* handle new card encoder differences */
- if (sequence[i * 2] == 0x3a)
- I2CWrite(saa, 0x88, 0x3a, 0x13, 2);
- else if (sequence[i * 2] == 0x6b)
- I2CWrite(saa, 0x88, 0x6b, 0x20, 2);
- else if (sequence[i * 2] == 0x6c)
- I2CWrite(saa, 0x88, 0x6c,
- dopal ? 0x09 : 0xf5, 2);
- else if (sequence[i * 2] == 0x6d)
- I2CWrite(saa, 0x88, 0x6d,
- dopal ? 0x20 : 0x00, 2);
- else if (sequence[i * 2] == 0x7a)
- I2CWrite(saa, 0x88, 0x7a,
- dopal ? (PALFirstActive - 1) :
- (NTSCFirstActive - 4), 2);
- else if (sequence[i * 2] == 0x7b)
- I2CWrite(saa, 0x88, 0x7b,
- dopal ? PALLastActive :
- NTSCLastActive, 2);
- else
- I2CWrite(saa, 0x88, sequence[i * 2],
- sequence[i * 2 + 1], 2);
- } else {
- if (sequence[i * 2] == 0x6b && mod)
- I2CWrite(saa, 0x88, 0x6b,
- (sequence[i * 2 + 1] ^ 0x09), 2);
- else if (sequence[i * 2] == 0x7a)
- I2CWrite(saa, 0x88, 0x7a,
- dopal ? (PALFirstActive - 1) :
- (NTSCFirstActive - 4), 2);
- else if (sequence[i * 2] == 0x7b)
- I2CWrite(saa, 0x88, 0x7b,
- dopal ? PALLastActive :
- NTSCLastActive, 2);
- else
- I2CWrite(saa, 0x88, sequence[i * 2],
- sequence[i * 2 + 1], 2);
- }
- }
-}
-
-static void set_genlock_offset(struct saa7146 *saa, int noffset)
-{
- int nCode;
- int PixelsPerLine = 858;
- if (CurrentMode == VIDEO_MODE_PAL)
- PixelsPerLine = 864;
- if (noffset > 500)
- noffset = 500;
- else if (noffset < -500)
- noffset = -500;
- nCode = noffset + 0x100;
- if (nCode == 1)
- nCode = 0x401;
- else if (nCode < 1)
- nCode = 0x400 + PixelsPerLine + nCode;
- debiwrite(saa, debNormal, XILINX_GLDELAY, nCode, 2);
-}
-
-static void set_out_format(struct saa7146 *saa, int mode)
-{
- initialize_saa7121(saa, (mode == VIDEO_MODE_NTSC ? 0 : 1));
- saa->boardcfg[2] = mode;
- /* do not adjust analog video parameters here, use saa7121 init */
- /* you will affect the SDI output on the new card */
- if (mode == VIDEO_MODE_PAL) { /* PAL */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x0808, 2);
- mdelay(50);
- saawrite(0x012002c0, SAA7146_NUM_LINE_BYTE1);
- if (NewCard) {
- debiwrite(saa, debNormal, IBM_MP2_DISP_MODE, 0xe100, 2);
- mdelay(50);
- }
- debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
- NewCard ? 0xe500 : 0x6500, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
- (1 << 8) |
- (NewCard ? PALFirstActive : PALFirstActive - 6), 2);
- } else { /* NTSC */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x0800, 2);
- mdelay(50);
- saawrite(0x00f002c0, SAA7146_NUM_LINE_BYTE1);
- debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
- NewCard ? 0xe100 : 0x6100, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_DLY,
- (1 << 8) |
- (NewCard ? NTSCFirstActive : NTSCFirstActive - 6), 2);
- }
-}
-
-/* Intialize bitmangler to map from a byte value to the mangled word that
- * must be output to program the Xilinx part through the DEBI port.
- * Xilinx Data Bit->DEBI Bit: 0->15 1->7 2->6 3->12 4->11 5->2 6->1 7->0
- * transfer FPGA code, init IBM chip, transfer IBM microcode
- * rev2 card mangles: 0->7 1->6 2->5 3->4 4->3 5->2 6->1 7->0
- */
-static u16 bitmangler[256];
-
-static int initialize_fpga(struct video_code *bitdata)
-{
- int i, num, startindex, failure = 0, loadtwo, loadfile = 0;
- u16 *dmabuf;
- u8 *newdma;
- struct saa7146 *saa;
-
- /* verify fpga code */
- for (startindex = 0; startindex < bitdata->datasize; startindex++)
- if (bitdata->data[startindex] == 255)
- break;
- if (startindex == bitdata->datasize) {
- printk(KERN_INFO "stradis: bad fpga code\n");
- return -1;
- }
- /* initialize all detected cards */
- for (num = 0; num < saa_num; num++) {
- saa = &saa7146s[num];
- if (saa->boardcfg[0] > 20)
- continue; /* card was programmed */
- loadtwo = (saa->boardcfg[18] & 0x10);
- if (!NewCard) /* we have an old board */
- for (i = 0; i < 256; i++)
- bitmangler[i] = ((i & 0x01) << 15) |
- ((i & 0x02) << 6) | ((i & 0x04) << 4) |
- ((i & 0x08) << 9) | ((i & 0x10) << 7) |
- ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
- ((i & 0x80) >> 7);
- else /* else we have a new board */
- for (i = 0; i < 256; i++)
- bitmangler[i] = ((i & 0x01) << 7) |
- ((i & 0x02) << 5) | ((i & 0x04) << 3) |
- ((i & 0x08) << 1) | ((i & 0x10) >> 1) |
- ((i & 0x20) >> 3) | ((i & 0x40) >> 5) |
- ((i & 0x80) >> 7);
-
- dmabuf = (u16 *) saa->dmadebi;
- newdma = (u8 *) saa->dmadebi;
- if (NewCard) { /* SDM2xxx */
- if (!strncmp(bitdata->loadwhat, "decoder2", 8))
- continue; /* fpga not for this card */
- if (!strncmp(&saa->boardcfg[42], bitdata->loadwhat, 8))
- loadfile = 1;
- else if (loadtwo && !strncmp(&saa->boardcfg[19],
- bitdata->loadwhat, 8))
- loadfile = 2;
- else if (!saa->boardcfg[42] && !strncmp("decxl",
- bitdata->loadwhat, 8))
- loadfile = 1; /* special */
- else
- continue; /* fpga not for this card */
- if (loadfile != 1 && loadfile != 2)
- continue; /* skip to next card */
- if (saa->boardcfg[0] && loadfile == 1)
- continue; /* skip to next card */
- if (saa->boardcfg[0] != 1 && loadfile == 2)
- continue; /* skip to next card */
- saa->boardcfg[0]++; /* mark fpga handled */
- printk("stradis%d: loading %s\n", saa->nr,
- bitdata->loadwhat);
- if (loadtwo && loadfile == 2)
- goto send_fpga_stuff;
- /* turn on the Audio interface to set PROG low */
- saawrite(0x00400040, SAA7146_GPIO_CTRL);
- saaread(SAA7146_PSR); /* ensure posted write */
- /* wait for everyone to reset */
- mdelay(10);
- saawrite(0x00400000, SAA7146_GPIO_CTRL);
- } else { /* original card */
- if (strncmp(bitdata->loadwhat, "decoder2", 8))
- continue; /* fpga not for this card */
- /* Pull the Xilinx PROG signal WS3 low */
- saawrite(0x02000200, SAA7146_MC1);
- /* Turn on the Audio interface so can set PROG low */
- saawrite(0x000000c0, SAA7146_ACON1);
- /* Pull the Xilinx INIT signal (GPIO2) low */
- saawrite(0x00400000, SAA7146_GPIO_CTRL);
- /* Make sure everybody resets */
- saaread(SAA7146_PSR); /* ensure posted write */
- mdelay(10);
- /* Release the Xilinx PROG signal */
- saawrite(0x00000000, SAA7146_ACON1);
- /* Turn off the Audio interface */
- saawrite(0x02000000, SAA7146_MC1);
- }
- /* Release Xilinx INIT signal (WS2) */
- saawrite(0x00000000, SAA7146_GPIO_CTRL);
- /* Wait for the INIT to go High */
- for (i = 0;
- i < 10000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
- i++)
- schedule();
- if (i == 1000) {
- printk(KERN_INFO "stradis%d: no fpga INIT\n", saa->nr);
- return -1;
- }
-send_fpga_stuff:
- if (NewCard) {
- for (i = startindex; i < bitdata->datasize; i++)
- newdma[i - startindex] =
- bitmangler[bitdata->data[i]];
- debiwrite(saa, 0x01420000, 0, 0,
- ((bitdata->datasize - startindex) + 5));
- if (loadtwo && loadfile == 1) {
- printk("stradis%d: awaiting 2nd FPGA bitfile\n",
- saa->nr);
- continue; /* skip to next card */
- }
- } else {
- for (i = startindex; i < bitdata->datasize; i++)
- dmabuf[i - startindex] =
- bitmangler[bitdata->data[i]];
- debiwrite(saa, 0x014a0000, 0, 0,
- ((bitdata->datasize - startindex) + 5) * 2);
- }
- for (i = 0;
- i < 1000 && !(saaread(SAA7146_PSR) & SAA7146_PSR_PIN2);
- i++)
- schedule();
- if (i == 1000) {
- printk(KERN_INFO "stradis%d: FPGA load failed\n",
- saa->nr);
- failure++;
- continue;
- }
- if (!NewCard) {
- /* Pull the Xilinx INIT signal (GPIO2) low */
- saawrite(0x00400000, SAA7146_GPIO_CTRL);
- saaread(SAA7146_PSR); /* ensure posted write */
- mdelay(2);
- saawrite(0x00000000, SAA7146_GPIO_CTRL);
- mdelay(2);
- }
- printk(KERN_INFO "stradis%d: FPGA Loaded\n", saa->nr);
- saa->boardcfg[0] = 26; /* mark fpga programmed */
- /* set VXCO to its lowest frequency */
- debiwrite(saa, debNormal, XILINX_PWM, 0, 2);
- if (NewCard) {
- /* mute CS3310 */
- if (HaveCS3310)
- debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
- 0, 2);
- /* set VXCO to PWM mode, release reset, blank on */
- debiwrite(saa, debNormal, XILINX_CTL0, 0xffc4, 2);
- mdelay(10);
- /* unmute CS3310 */
- if (HaveCS3310)
- debiwrite(saa, debNormal, XILINX_CTL0,
- 0x2020, 2);
- }
- /* set source Black */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
- saa->boardcfg[4] = 22; /* set NTSC First Active Line */
- saa->boardcfg[5] = 23; /* set PAL First Active Line */
- saa->boardcfg[54] = 2; /* set NTSC Last Active Line - 256 */
- saa->boardcfg[55] = 54; /* set PAL Last Active Line - 256 */
- set_out_format(saa, VIDEO_MODE_NTSC);
- mdelay(50);
- /* begin IBM chip init */
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
- saaread(SAA7146_PSR); /* wait for reset */
- mdelay(5);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
- debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0x10, 2);
- debiwrite(saa, debNormal, IBM_MP2_CMD_ADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
- if (NewCard) {
- mdelay(5);
- /* set i2s rate converter to 48KHz */
- debiwrite(saa, debNormal, 0x80c0, 6, 2);
- /* we must init CS8420 first since rev b pulls i2s */
- /* master clock low and CS4341 needs i2s master to */
- /* run the i2c port. */
- if (HaveCS8420)
- /* 0=consumer, 1=pro */
- initialize_cs8420(saa, 0);
-
- mdelay(5);
- if (HaveCS4341)
- initialize_cs4341(saa);
- }
- debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
- debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
- if (NewCard)
- set_genlock_offset(saa, 0);
- debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
-#if 0
- /* enable genlock */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x8000, 2);
-#else
- /* disable genlock */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x8080, 2);
-#endif
- }
-
- return failure;
-}
-
-static int do_ibm_reset(struct saa7146 *saa)
-{
- /* failure if decoder not previously programmed */
- if (saa->boardcfg[0] < 37)
- return -EIO;
- /* mute CS3310 */
- if (HaveCS3310)
- debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, 0, 2);
- /* disable interrupts */
- saawrite(0, SAA7146_IER);
- saa->audhead = saa->audtail = 0;
- saa->vidhead = saa->vidtail = 0;
- /* tristate debi bus, disable debi transfers */
- saawrite(0x00880000, SAA7146_MC1);
- /* ensure posted write */
- saaread(SAA7146_MC1);
- mdelay(50);
- /* re-enable debi transfers */
- saawrite(0x00880088, SAA7146_MC1);
- /* set source Black */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x1707, 2);
- /* begin IBM chip init */
- set_out_format(saa, CurrentMode);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 4, 2);
- saaread(SAA7146_PSR); /* wait for reset */
- mdelay(5);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, 0, 2);
- debiread(saa, debNormal, IBM_MP2_CHIP_CONTROL, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_MODE, 0x2e, 2);
- if (NewCard) {
- mdelay(5);
- /* set i2s rate converter to 48KHz */
- debiwrite(saa, debNormal, 0x80c0, 6, 2);
- /* we must init CS8420 first since rev b pulls i2s */
- /* master clock low and CS4341 needs i2s master to */
- /* run the i2c port. */
- if (HaveCS8420)
- /* 0=consumer, 1=pro */
- initialize_cs8420(saa, 1);
-
- mdelay(5);
- if (HaveCS4341)
- initialize_cs4341(saa);
- }
- debiwrite(saa, debNormal, IBM_MP2_INFC_CTL, 0x48, 2);
- debiwrite(saa, debNormal, IBM_MP2_BEEP_CTL, 0xa000, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_LBOR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_TBOR, 0, 2);
- if (NewCard)
- set_genlock_offset(saa, 0);
- debiwrite(saa, debNormal, IBM_MP2_FRNT_ATTEN, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
- debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
- if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
- (ChipControl == 0x43 ? 0xe800 : 0xe000), 1)) {
- printk(KERN_ERR "stradis%d: IBM config failed\n", saa->nr);
- }
- if (HaveCS3310) {
- int i = CS3310MaxLvl;
- debiwrite(saa, debNormal, XILINX_CS3310_CMPLT, ((i << 8)| i),2);
- }
- /* start video decoder */
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- /* 256k vid, 3520 bytes aud */
- debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037, 2);
- debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
- ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
- /* enable buffer threshold irq */
- debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
- /* clear pending interrupts */
- debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
- debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
-
- return 0;
-}
-
-/* load the decoder microcode */
-static int initialize_ibmmpeg2(struct video_code *microcode)
-{
- int i, num;
- struct saa7146 *saa;
-
- for (num = 0; num < saa_num; num++) {
- saa = &saa7146s[num];
- /* check that FPGA is loaded */
- debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0xa55a, 2);
- i = debiread(saa, debNormal, IBM_MP2_OSD_SIZE, 2);
- if (i != 0xa55a) {
- printk(KERN_INFO "stradis%d: %04x != 0xa55a\n",
- saa->nr, i);
-#if 0
- return -1;
-#endif
- }
- if (!strncmp(microcode->loadwhat, "decoder.vid", 11)) {
- if (saa->boardcfg[0] > 27)
- continue; /* skip to next card */
- /* load video control store */
- saa->boardcfg[1] = 0x13; /* no-sync default */
- debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
- debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
- for (i = 0; i < microcode->datasize / 2; i++)
- debiwrite(saa, debNormal, IBM_MP2_PROC_IDATA,
- (microcode->data[i * 2] << 8) |
- microcode->data[i * 2 + 1], 2);
- debiwrite(saa, debNormal, IBM_MP2_PROC_IADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
- ChipControl, 2);
- saa->boardcfg[0] = 28;
- }
- if (!strncmp(microcode->loadwhat, "decoder.aud", 11)) {
- if (saa->boardcfg[0] > 35)
- continue; /* skip to next card */
- /* load audio control store */
- debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 1, 2);
- debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
- for (i = 0; i < microcode->datasize; i++)
- debiwrite(saa, debNormal, IBM_MP2_AUD_IDATA,
- microcode->data[i], 1);
- debiwrite(saa, debNormal, IBM_MP2_AUD_IADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_WR_PROT, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_OSD_SIZE, 0x2000, 2);
- debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4552, 2);
- if (ibm_send_command(saa, IBM_MP2_CONFIG_DECODER,
- 0xe000, 1)) {
- printk(KERN_ERR "stradis%d: IBM config "
- "failed\n", saa->nr);
- return -1;
- }
- /* set PWM to center value */
- if (NewCard) {
- debiwrite(saa, debNormal, XILINX_PWM,
- saa->boardcfg[14] +
- (saa->boardcfg[13] << 8), 2);
- } else
- debiwrite(saa, debNormal, XILINX_PWM, 0x46, 2);
-
- if (HaveCS3310) {
- i = CS3310MaxLvl;
- debiwrite(saa, debNormal, XILINX_CS3310_CMPLT,
- (i << 8) | i, 2);
- }
- printk(KERN_INFO "stradis%d: IBM MPEGCD%d Inited\n",
- saa->nr, 18 + (debiread(saa, debNormal,
- IBM_MP2_CHIP_CONTROL, 2) >> 12));
- /* start video decoder */
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
- ChipControl, 2);
- debiwrite(saa, debNormal, IBM_MP2_RB_THRESHOLD, 0x4037,
- 2); /* 256k vid, 3520 bytes aud */
- debiwrite(saa, debNormal, IBM_MP2_AUD_CTL, 0x4573, 2);
- ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
- /* enable buffer threshold irq */
- debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00c, 2);
- debiread(saa, debNormal, IBM_MP2_HOST_INT, 2);
- /* enable gpio irq */
- saawrite(0x00002000, SAA7146_GPIO_CTRL);
- /* enable decoder output to HPS */
- debiwrite(saa, debNormal, XILINX_CTL0, 0x1711, 2);
- saa->boardcfg[0] = 37;
- }
- }
-
- return 0;
-}
-
-static u32 palette2fmt[] = { /* some of these YUV translations are wrong */
- 0xffffffff, 0x86000000, 0x87000000, 0x80000000, 0x8100000, 0x82000000,
- 0x83000000, 0x00000000, 0x03000000, 0x03000000, 0x0a00000, 0x03000000,
- 0x06000000, 0x00000000, 0x03000000, 0x0a000000, 0x0300000
-};
-static int bpp2fmt[4] = {
- VIDEO_PALETTE_HI240, VIDEO_PALETTE_RGB565, VIDEO_PALETTE_RGB24,
- VIDEO_PALETTE_RGB32
-};
-
-/* I wish I could find a formula to calculate these... */
-static u32 h_prescale[64] = {
- 0x10000000, 0x18040202, 0x18080000, 0x380c0606, 0x38100204, 0x38140808,
- 0x38180000, 0x381c0000, 0x3820161c, 0x38242a3b, 0x38281230, 0x382c4460,
- 0x38301040, 0x38340080, 0x38380000, 0x383c0000, 0x3840fefe, 0x3844ee9f,
- 0x3848ee9f, 0x384cee9f, 0x3850ee9f, 0x38542a3b, 0x38581230, 0x385c0000,
- 0x38600000, 0x38640000, 0x38680000, 0x386c0000, 0x38700000, 0x38740000,
- 0x38780000, 0x387c0000, 0x30800000, 0x38840000, 0x38880000, 0x388c0000,
- 0x38900000, 0x38940000, 0x38980000, 0x389c0000, 0x38a00000, 0x38a40000,
- 0x38a80000, 0x38ac0000, 0x38b00000, 0x38b40000, 0x38b80000, 0x38bc0000,
- 0x38c00000, 0x38c40000, 0x38c80000, 0x38cc0000, 0x38d00000, 0x38d40000,
- 0x38d80000, 0x38dc0000, 0x38e00000, 0x38e40000, 0x38e80000, 0x38ec0000,
- 0x38f00000, 0x38f40000, 0x38f80000, 0x38fc0000,
-};
-static u32 v_gain[64] = {
- 0x016000ff, 0x016100ff, 0x016100ff, 0x016200ff, 0x016200ff, 0x016200ff,
- 0x016200ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff, 0x016300ff,
- 0x016300ff, 0x016300ff, 0x016300ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
- 0x016400ff, 0x016400ff, 0x016400ff, 0x016400ff,
-};
-
-static void saa7146_set_winsize(struct saa7146 *saa)
-{
- u32 format;
- int offset, yacl, ysci;
- saa->win.color_fmt = format =
- (saa->win.depth == 15) ? palette2fmt[VIDEO_PALETTE_RGB555] :
- palette2fmt[bpp2fmt[(saa->win.bpp - 1) & 3]];
- offset = saa->win.x * saa->win.bpp + saa->win.y * saa->win.bpl;
- saawrite(saa->win.vidadr + offset, SAA7146_BASE_EVEN1);
- saawrite(saa->win.vidadr + offset + saa->win.bpl, SAA7146_BASE_ODD1);
- saawrite(saa->win.bpl * 2, SAA7146_PITCH1);
- saawrite(saa->win.vidadr + saa->win.bpl * saa->win.sheight,
- SAA7146_PROT_ADDR1);
- saawrite(0, SAA7146_PAGE1);
- saawrite(format | 0x60, SAA7146_CLIP_FORMAT_CTRL);
- offset = (704 / (saa->win.width - 1)) & 0x3f;
- saawrite(h_prescale[offset], SAA7146_HPS_H_PRESCALE);
- offset = (720896 / saa->win.width) / (offset + 1);
- saawrite((offset << 12) | 0x0c, SAA7146_HPS_H_SCALE);
- if (CurrentMode == VIDEO_MODE_NTSC) {
- yacl = /*(480 / saa->win.height - 1) & 0x3f */ 0;
- ysci = 1024 - (saa->win.height * 1024 / 480);
- } else {
- yacl = /*(576 / saa->win.height - 1) & 0x3f */ 0;
- ysci = 1024 - (saa->win.height * 1024 / 576);
- }
- saawrite((1 << 31) | (ysci << 21) | (yacl << 15), SAA7146_HPS_V_SCALE);
- saawrite(v_gain[yacl], SAA7146_HPS_V_GAIN);
- saawrite(((SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_HPS_V |
- SAA7146_MC2_UPLD_HPS_H) << 16) | (SAA7146_MC2_UPLD_DMA1 |
- SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_HPS_H), SAA7146_MC2);
-}
-
-/* clip_draw_rectangle(cm,x,y,w,h) -- handle clipping an area
- * bitmap is fixed width, 128 bytes (1024 pixels represented)
- * arranged most-sigificant-bit-left in 32-bit words
- * based on saa7146 clipping hardware, it swaps bytes if LE
- * much of this makes up for egcs brain damage -- so if you
- * are wondering "why did he do this?" it is because the C
- * was adjusted to generate the optimal asm output without
- * writing non-portable __asm__ directives.
- */
-
-static void clip_draw_rectangle(u32 *clipmap, int x, int y, int w, int h)
-{
- register int startword, endword;
- register u32 bitsleft, bitsright;
- u32 *temp;
- if (x < 0) {
- w += x;
- x = 0;
- }
- if (y < 0) {
- h += y;
- y = 0;
- }
- if (w <= 0 || h <= 0 || x > 1023 || y > 639)
- return; /* throw away bad clips */
- if (x + w > 1024)
- w = 1024 - x;
- if (y + h > 640)
- h = 640 - y;
- startword = (x >> 5);
- endword = ((x + w) >> 5);
- bitsleft = (0xffffffff >> (x & 31));
- bitsright = (0xffffffff << (~((x + w) - (endword << 5))));
- temp = &clipmap[(y << 5) + startword];
- w = endword - startword;
- if (!w) {
- bitsleft |= bitsright;
- for (y = 0; y < h; y++) {
- *temp |= bitsleft;
- temp += 32;
- }
- } else {
- for (y = 0; y < h; y++) {
- *temp++ |= bitsleft;
- for (x = 1; x < w; x++)
- *temp++ = 0xffffffff;
- *temp |= bitsright;
- temp += (32 - w);
- }
- }
-}
-
-static void make_clip_tab(struct saa7146 *saa, struct video_clip *cr, int ncr)
-{
- int i, width, height;
- u32 *clipmap;
-
- clipmap = saa->dmavid2;
- if ((width = saa->win.width) > 1023)
- width = 1023; /* sanity check */
- if ((height = saa->win.height) > 640)
- height = 639; /* sanity check */
- if (ncr > 0) { /* rectangles pased */
- /* convert rectangular clips to a bitmap */
- memset(clipmap, 0, VIDEO_CLIPMAP_SIZE); /* clear map */
- for (i = 0; i < ncr; i++)
- clip_draw_rectangle(clipmap, cr[i].x, cr[i].y,
- cr[i].width, cr[i].height);
- }
- /* clip against viewing window AND screen
- so we do not have to rely on the user program
- */
- clip_draw_rectangle(clipmap, (saa->win.x + width > saa->win.swidth) ?
- (saa->win.swidth - saa->win.x) : width, 0, 1024, 768);
- clip_draw_rectangle(clipmap, 0,
- (saa->win.y + height > saa->win.sheight) ?
- (saa->win.sheight - saa->win.y) : height, 1024, 768);
- if (saa->win.x < 0)
- clip_draw_rectangle(clipmap, 0, 0, -saa->win.x, 768);
- if (saa->win.y < 0)
- clip_draw_rectangle(clipmap, 0, 0, 1024, -saa->win.y);
-}
-
-static long saa_ioctl(struct file *file,
- unsigned int cmd, unsigned long argl)
-{
- struct saa7146 *saa = file->private_data;
- void __user *arg = (void __user *)argl;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability b;
- strcpy(b.name, saa->video_dev.name);
- b.type = VID_TYPE_CAPTURE | VID_TYPE_OVERLAY |
- VID_TYPE_CLIPPING | VID_TYPE_FRAMERAM |
- VID_TYPE_SCALES;
- b.channels = 1;
- b.audios = 1;
- b.maxwidth = 768;
- b.maxheight = 576;
- b.minwidth = 32;
- b.minheight = 32;
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture p = saa->picture;
- if (saa->win.depth == 8)
- p.palette = VIDEO_PALETTE_HI240;
- if (saa->win.depth == 15)
- p.palette = VIDEO_PALETTE_RGB555;
- if (saa->win.depth == 16)
- p.palette = VIDEO_PALETTE_RGB565;
- if (saa->win.depth == 24)
- p.palette = VIDEO_PALETTE_RGB24;
- if (saa->win.depth == 32)
- p.palette = VIDEO_PALETTE_RGB32;
- if (copy_to_user(arg, &p, sizeof(p)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture p;
- u32 format;
- if (copy_from_user(&p, arg, sizeof(p)))
- return -EFAULT;
- if (p.palette < ARRAY_SIZE(palette2fmt)) {
- format = palette2fmt[p.palette];
- saa->win.color_fmt = format;
- saawrite(format | 0x60,
- SAA7146_CLIP_FORMAT_CTRL);
- }
- saawrite(((p.brightness & 0xff00) << 16) |
- ((p.contrast & 0xfe00) << 7) |
- ((p.colour & 0xfe00) >> 9), SAA7146_BCS_CTRL);
- saa->picture = p;
- /* upload changed registers */
- saawrite(((SAA7146_MC2_UPLD_HPS_H |
- SAA7146_MC2_UPLD_HPS_V) << 16) |
- SAA7146_MC2_UPLD_HPS_H |
- SAA7146_MC2_UPLD_HPS_V, SAA7146_MC2);
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window vw;
- struct video_clip *vcp = NULL;
-
- if (copy_from_user(&vw, arg, sizeof(vw)))
- return -EFAULT;
-
- /* stop capture */
- if (vw.flags || vw.width < 16 || vw.height < 16) {
- saawrite((SAA7146_MC1_TR_E_1 << 16),
- SAA7146_MC1);
- return -EINVAL;
- }
- /* 32-bit align start and adjust width */
- if (saa->win.bpp < 4) {
- int i = vw.x;
- vw.x = (vw.x + 3) & ~3;
- i = vw.x - i;
- vw.width -= i;
- }
- saa->win.x = vw.x;
- saa->win.y = vw.y;
- saa->win.width = vw.width;
- if (saa->win.width > 768)
- saa->win.width = 768;
- saa->win.height = vw.height;
- if (CurrentMode == VIDEO_MODE_NTSC) {
- if (saa->win.height > 480)
- saa->win.height = 480;
- } else {
- if (saa->win.height > 576)
- saa->win.height = 576;
- }
-
- /* stop capture */
- saawrite((SAA7146_MC1_TR_E_1 << 16), SAA7146_MC1);
- saa7146_set_winsize(saa);
-
- /*
- * Do any clips.
- */
- if (vw.clipcount < 0) {
- if (copy_from_user(saa->dmavid2, vw.clips,
- VIDEO_CLIPMAP_SIZE))
- return -EFAULT;
- } else if (vw.clipcount > 16384) {
- return -EINVAL;
- } else if (vw.clipcount > 0) {
- vcp = vmalloc(sizeof(struct video_clip) *
- vw.clipcount);
- if (vcp == NULL)
- return -ENOMEM;
- if (copy_from_user(vcp, vw.clips,
- sizeof(struct video_clip) *
- vw.clipcount)) {
- vfree(vcp);
- return -EFAULT;
- }
- } else /* nothing clipped */
- memset(saa->dmavid2, 0, VIDEO_CLIPMAP_SIZE);
-
- make_clip_tab(saa, vcp, vw.clipcount);
- if (vw.clipcount > 0)
- vfree(vcp);
-
- /* start capture & clip dma if we have an address */
- if ((saa->cap & 3) && saa->win.vidadr != 0)
- saawrite(((SAA7146_MC1_TR_E_1 |
- SAA7146_MC1_TR_E_2) << 16) | 0xffff,
- SAA7146_MC1);
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window vw;
- vw.x = saa->win.x;
- vw.y = saa->win.y;
- vw.width = saa->win.width;
- vw.height = saa->win.height;
- vw.chromakey = 0;
- vw.flags = 0;
- if (copy_to_user(arg, &vw, sizeof(vw)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCCAPTURE:
- {
- int v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- if (v == 0) {
- saa->cap &= ~1;
- saawrite((SAA7146_MC1_TR_E_1 << 16),
- SAA7146_MC1);
- } else {
- if (saa->win.vidadr == 0 || saa->win.width == 0
- || saa->win.height == 0)
- return -EINVAL;
- saa->cap |= 1;
- saawrite((SAA7146_MC1_TR_E_1 << 16) | 0xffff,
- SAA7146_MC1);
- }
- return 0;
- }
- case VIDIOCGFBUF:
- {
- struct video_buffer v;
- v.base = (void *)saa->win.vidadr;
- v.height = saa->win.sheight;
- v.width = saa->win.swidth;
- v.depth = saa->win.depth;
- v.bytesperline = saa->win.bpl;
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
- return 0;
-
- }
- case VIDIOCSFBUF:
- {
- struct video_buffer v;
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- if (v.depth != 8 && v.depth != 15 && v.depth != 16 &&
- v.depth != 24 && v.depth != 32 && v.width > 16 &&
- v.height > 16 && v.bytesperline > 16)
- return -EINVAL;
- if (v.base)
- saa->win.vidadr = (unsigned long)v.base;
- saa->win.sheight = v.height;
- saa->win.swidth = v.width;
- saa->win.bpp = ((v.depth + 7) & 0x38) / 8;
- saa->win.depth = v.depth;
- saa->win.bpl = v.bytesperline;
-
- DEBUG(printk("Display at %p is %d by %d, bytedepth %d, "
- "bpl %d\n", v.base, v.width, v.height,
- saa->win.bpp, saa->win.bpl));
- saa7146_set_winsize(saa);
- return 0;
- }
- case VIDIOCKEY:
- {
- /* Will be handled higher up .. */
- return 0;
- }
-
- case VIDIOCGAUDIO:
- {
- struct video_audio v;
- v = saa->audio_dev;
- v.flags &= ~(VIDEO_AUDIO_MUTE | VIDEO_AUDIO_MUTABLE);
- v.flags |= VIDEO_AUDIO_MUTABLE | VIDEO_AUDIO_VOLUME;
- strcpy(v.name, "MPEG");
- v.mode = VIDEO_SOUND_STEREO;
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCSAUDIO:
- {
- struct video_audio v;
- int i;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- i = (~(v.volume >> 8)) & 0xff;
- if (!HaveCS4341) {
- if (v.flags & VIDEO_AUDIO_MUTE)
- debiwrite(saa, debNormal,
- IBM_MP2_FRNT_ATTEN, 0xffff, 2);
- if (!(v.flags & VIDEO_AUDIO_MUTE))
- debiwrite(saa, debNormal,
- IBM_MP2_FRNT_ATTEN, 0x0000, 2);
- if (v.flags & VIDEO_AUDIO_VOLUME)
- debiwrite(saa, debNormal,
- IBM_MP2_FRNT_ATTEN,
- (i << 8) | i, 2);
- } else {
- if (v.flags & VIDEO_AUDIO_MUTE)
- cs4341_setlevel(saa, 0xff, 0xff);
- if (!(v.flags & VIDEO_AUDIO_MUTE))
- cs4341_setlevel(saa, 0, 0);
- if (v.flags & VIDEO_AUDIO_VOLUME)
- cs4341_setlevel(saa, i, i);
- }
- saa->audio_dev = v;
- return 0;
- }
-
- case VIDIOCGUNIT:
- {
- struct video_unit vu;
- vu.video = saa->video_dev.minor;
- vu.vbi = VIDEO_NO_UNIT;
- vu.radio = VIDEO_NO_UNIT;
- vu.audio = VIDEO_NO_UNIT;
- vu.teletext = VIDEO_NO_UNIT;
- if (copy_to_user(arg, &vu, sizeof(vu)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCSPLAYMODE:
- {
- struct video_play_mode pmode;
- if (copy_from_user((void *)&pmode, arg,
- sizeof(struct video_play_mode)))
- return -EFAULT;
- switch (pmode.mode) {
- case VID_PLAY_VID_OUT_MODE:
- if (pmode.p1 != VIDEO_MODE_NTSC &&
- pmode.p1 != VIDEO_MODE_PAL)
- return -EINVAL;
- set_out_format(saa, pmode.p1);
- return 0;
- case VID_PLAY_GENLOCK:
- debiwrite(saa, debNormal, XILINX_CTL0,
- pmode.p1 ? 0x8000 : 0x8080, 2);
- if (NewCard)
- set_genlock_offset(saa, pmode.p2);
- return 0;
- case VID_PLAY_NORMAL:
- debiwrite(saa, debNormal,
- IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_PAUSE:
- /* IBM removed the PAUSE command */
- /* they say use SINGLE_FRAME now */
- case VID_PLAY_SINGLE_FRAME:
- ibm_send_command(saa, IBM_MP2_SINGLE_FRAME,0,0);
- if (saa->playmode == pmode.mode) {
- debiwrite(saa, debNormal,
- IBM_MP2_CHIP_CONTROL,
- ChipControl, 2);
- }
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_FAST_FORWARD:
- ibm_send_command(saa, IBM_MP2_FAST_FORWARD,0,0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_SLOW_MOTION:
- ibm_send_command(saa, IBM_MP2_SLOW_MOTION,
- pmode.p1, 0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_IMMEDIATE_NORMAL:
- /* ensure transfers resume */
- debiwrite(saa, debNormal,
- IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- ibm_send_command(saa, IBM_MP2_IMED_NORM_PLAY,
- 0, 0);
- saa->playmode = VID_PLAY_NORMAL;
- return 0;
- case VID_PLAY_SWITCH_CHANNELS:
- saa->audhead = saa->audtail = 0;
- saa->vidhead = saa->vidtail = 0;
- ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,1);
- ibm_send_command(saa, IBM_MP2_RESET_AUD_RATE,
- 0, 1);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
- 0, 2);
- ibm_send_command(saa, IBM_MP2_CHANNEL_SWITCH,
- 0, 1);
- debiwrite(saa, debNormal, IBM_MP2_CHIP_CONTROL,
- ChipControl, 2);
- ibm_send_command(saa, IBM_MP2_PLAY, 0, 0);
- saa->playmode = VID_PLAY_NORMAL;
- return 0;
- case VID_PLAY_FREEZE_FRAME:
- ibm_send_command(saa, IBM_MP2_FREEZE_FRAME,0,0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_STILL_MODE:
- ibm_send_command(saa, IBM_MP2_SET_STILL_MODE,
- 0, 0);
- saa->playmode = pmode.mode;
- return 0;
- case VID_PLAY_MASTER_MODE:
- if (pmode.p1 == VID_PLAY_MASTER_NONE)
- saa->boardcfg[1] = 0x13;
- else if (pmode.p1 == VID_PLAY_MASTER_VIDEO)
- saa->boardcfg[1] = 0x23;
- else if (pmode.p1 == VID_PLAY_MASTER_AUDIO)
- saa->boardcfg[1] = 0x43;
- else
- return -EINVAL;
- debiwrite(saa, debNormal,
- IBM_MP2_CHIP_CONTROL, ChipControl, 2);
- return 0;
- case VID_PLAY_ACTIVE_SCANLINES:
- if (CurrentMode == VIDEO_MODE_PAL) {
- if (pmode.p1 < 1 || pmode.p2 > 625)
- return -EINVAL;
- saa->boardcfg[5] = pmode.p1;
- saa->boardcfg[55] = (pmode.p1 +
- (pmode.p2 / 2) - 1) & 0xff;
- } else {
- if (pmode.p1 < 4 || pmode.p2 > 525)
- return -EINVAL;
- saa->boardcfg[4] = pmode.p1;
- saa->boardcfg[54] = (pmode.p1 +
- (pmode.p2 / 2) - 4) & 0xff;
- }
- set_out_format(saa, CurrentMode);
- case VID_PLAY_RESET:
- return do_ibm_reset(saa);
- case VID_PLAY_END_MARK:
- if (saa->endmarktail < saa->endmarkhead) {
- if (saa->endmarkhead -
- saa->endmarktail < 2)
- return -ENOSPC;
- } else if (saa->endmarkhead <=saa->endmarktail){
- if (saa->endmarktail - saa->endmarkhead
- > (MAX_MARKS - 2))
- return -ENOSPC;
- } else
- return -ENOSPC;
- saa->endmark[saa->endmarktail] = saa->audtail;
- saa->endmarktail++;
- if (saa->endmarktail >= MAX_MARKS)
- saa->endmarktail = 0;
- }
- return -EINVAL;
- }
- case VIDIOCSWRITEMODE:
- {
- int mode;
- if (copy_from_user((void *)&mode, arg, sizeof(int)))
- return -EFAULT;
- if (mode == VID_WRITE_MPEG_AUD ||
- mode == VID_WRITE_MPEG_VID ||
- mode == VID_WRITE_CC ||
- mode == VID_WRITE_TTX ||
- mode == VID_WRITE_OSD) {
- saa->writemode = mode;
- return 0;
- }
- return -EINVAL;
- }
- case VIDIOCSMICROCODE:
- {
- struct video_code ucode;
- __u8 *udata;
- int i;
- if (copy_from_user(&ucode, arg, sizeof(ucode)))
- return -EFAULT;
- if (ucode.datasize > 65536 || ucode.datasize < 1024 ||
- strncmp(ucode.loadwhat, "dec", 3))
- return -EINVAL;
- if ((udata = vmalloc(ucode.datasize)) == NULL)
- return -ENOMEM;
- if (copy_from_user(udata, ucode.data, ucode.datasize)) {
- vfree(udata);
- return -EFAULT;
- }
- ucode.data = udata;
- if (!strncmp(ucode.loadwhat, "decoder.aud", 11) ||
- !strncmp(ucode.loadwhat, "decoder.vid", 11))
- i = initialize_ibmmpeg2(&ucode);
- else
- i = initialize_fpga(&ucode);
- vfree(udata);
- if (i)
- return -EINVAL;
- return 0;
-
- }
- case VIDIOCGCHAN: /* this makes xawtv happy */
- {
- struct video_channel v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- v.flags = VIDEO_VC_AUDIO;
- v.tuners = 0;
- v.type = VID_TYPE_MPEG_DECODER;
- v.norm = CurrentMode;
- strcpy(v.name, "MPEG2");
- if (copy_to_user(arg, &v, sizeof(v)))
- return -EFAULT;
- return 0;
- }
- case VIDIOCSCHAN: /* this makes xawtv happy */
- {
- struct video_channel v;
- if (copy_from_user(&v, arg, sizeof(v)))
- return -EFAULT;
- /* do nothing */
- return 0;
- }
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static int saa_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct saa7146 *saa = file->private_data;
- printk(KERN_DEBUG "stradis%d: saa_mmap called\n", saa->nr);
- return -EINVAL;
-}
-
-static ssize_t saa_read(struct file *file, char __user * buf,
- size_t count, loff_t * ppos)
-{
- return -EINVAL;
-}
-
-static ssize_t saa_write(struct file *file, const char __user * buf,
- size_t count, loff_t * ppos)
-{
- struct saa7146 *saa = file->private_data;
- unsigned long todo = count;
- int blocksize, split;
- unsigned long flags;
-
- while (todo > 0) {
- if (saa->writemode == VID_WRITE_MPEG_AUD) {
- spin_lock_irqsave(&saa->lock, flags);
- if (saa->audhead <= saa->audtail)
- blocksize = 65536 -
- (saa->audtail - saa->audhead);
- else
- blocksize = saa->audhead - saa->audtail;
- spin_unlock_irqrestore(&saa->lock, flags);
- if (blocksize < 16384) {
- saawrite(SAA7146_PSR_DEBI_S |
- SAA7146_PSR_PIN1, SAA7146_IER);
- saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
- /* wait for buffer space to open */
- interruptible_sleep_on(&saa->audq);
- }
- spin_lock_irqsave(&saa->lock, flags);
- if (saa->audhead <= saa->audtail) {
- blocksize = 65536 -
- (saa->audtail - saa->audhead);
- split = 65536 - saa->audtail;
- } else {
- blocksize = saa->audhead - saa->audtail;
- split = 65536;
- }
- spin_unlock_irqrestore(&saa->lock, flags);
- blocksize--;
- if (blocksize > todo)
- blocksize = todo;
- /* double check that we really have space */
- if (!blocksize)
- return -ENOSPC;
- if (split < blocksize) {
- if (copy_from_user(saa->audbuf +
- saa->audtail, buf, split))
- return -EFAULT;
- buf += split;
- todo -= split;
- blocksize -= split;
- saa->audtail = 0;
- }
- if (copy_from_user(saa->audbuf + saa->audtail, buf,
- blocksize))
- return -EFAULT;
- saa->audtail += blocksize;
- todo -= blocksize;
- buf += blocksize;
- saa->audtail &= 0xffff;
- } else if (saa->writemode == VID_WRITE_MPEG_VID) {
- spin_lock_irqsave(&saa->lock, flags);
- if (saa->vidhead <= saa->vidtail)
- blocksize = 524288 -
- (saa->vidtail - saa->vidhead);
- else
- blocksize = saa->vidhead - saa->vidtail;
- spin_unlock_irqrestore(&saa->lock, flags);
- if (blocksize < 65536) {
- saawrite(SAA7146_PSR_DEBI_S |
- SAA7146_PSR_PIN1, SAA7146_IER);
- saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
- /* wait for buffer space to open */
- interruptible_sleep_on(&saa->vidq);
- }
- spin_lock_irqsave(&saa->lock, flags);
- if (saa->vidhead <= saa->vidtail) {
- blocksize = 524288 -
- (saa->vidtail - saa->vidhead);
- split = 524288 - saa->vidtail;
- } else {
- blocksize = saa->vidhead - saa->vidtail;
- split = 524288;
- }
- spin_unlock_irqrestore(&saa->lock, flags);
- blocksize--;
- if (blocksize > todo)
- blocksize = todo;
- /* double check that we really have space */
- if (!blocksize)
- return -ENOSPC;
- if (split < blocksize) {
- if (copy_from_user(saa->vidbuf +
- saa->vidtail, buf, split))
- return -EFAULT;
- buf += split;
- todo -= split;
- blocksize -= split;
- saa->vidtail = 0;
- }
- if (copy_from_user(saa->vidbuf + saa->vidtail, buf,
- blocksize))
- return -EFAULT;
- saa->vidtail += blocksize;
- todo -= blocksize;
- buf += blocksize;
- saa->vidtail &= 0x7ffff;
- } else if (saa->writemode == VID_WRITE_OSD) {
- if (count > 131072)
- return -ENOSPC;
- if (copy_from_user(saa->osdbuf, buf, count))
- return -EFAULT;
- buf += count;
- saa->osdhead = 0;
- saa->osdtail = count;
- debiwrite(saa, debNormal, IBM_MP2_OSD_ADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_OSD_LINK_ADDR, 0, 2);
- debiwrite(saa, debNormal, IBM_MP2_MASK0, 0xc00d, 2);
- debiwrite(saa, debNormal, IBM_MP2_DISP_MODE,
- debiread(saa, debNormal,
- IBM_MP2_DISP_MODE, 2) | 1, 2);
- /* trigger osd data transfer */
- saawrite(SAA7146_PSR_DEBI_S |
- SAA7146_PSR_PIN1, SAA7146_IER);
- saawrite(SAA7146_PSR_PIN1, SAA7146_PSR);
- }
- }
- return count;
-}
-
-static int saa_open(struct file *file)
-{
- struct video_device *vdev = video_devdata(file);
- struct saa7146 *saa = container_of(vdev, struct saa7146, video_dev);
-
- lock_kernel();
- file->private_data = saa;
-
- saa->user++;
- if (saa->user > 1) {
- unlock_kernel();
- return 0; /* device open already, don't reset */
- }
- saa->writemode = VID_WRITE_MPEG_VID; /* default to video */
- unlock_kernel();
- return 0;
-}
-
-static int saa_release(struct file *file)
-{
- struct saa7146 *saa = file->private_data;
- saa->user--;
-
- if (saa->user > 0) /* still someone using device */
- return 0;
- saawrite(0x007f0000, SAA7146_MC1); /* stop all overlay dma */
- return 0;
-}
-
-static const struct v4l2_file_operations saa_fops = {
- .owner = THIS_MODULE,
- .open = saa_open,
- .release = saa_release,
- .ioctl = saa_ioctl,
- .read = saa_read,
- .write = saa_write,
- .mmap = saa_mmap,
-};
-
-/* template for video_device-structure */
-static struct video_device saa_template = {
- .name = "SAA7146A",
- .fops = &saa_fops,
- .release = video_device_release_empty,
-};
-
-static int __devinit configure_saa7146(struct pci_dev *pdev, int num)
-{
- int retval;
- struct saa7146 *saa = pci_get_drvdata(pdev);
-
- saa->endmarkhead = saa->endmarktail = 0;
- saa->win.x = saa->win.y = 0;
- saa->win.width = saa->win.cropwidth = 720;
- saa->win.height = saa->win.cropheight = 480;
- saa->win.cropx = saa->win.cropy = 0;
- saa->win.bpp = 2;
- saa->win.depth = 16;
- saa->win.color_fmt = palette2fmt[VIDEO_PALETTE_RGB565];
- saa->win.bpl = 1024 * saa->win.bpp;
- saa->win.swidth = 1024;
- saa->win.sheight = 768;
- saa->picture.brightness = 32768;
- saa->picture.contrast = 38768;
- saa->picture.colour = 32768;
- saa->cap = 0;
- saa->nr = num;
- saa->playmode = VID_PLAY_NORMAL;
- memset(saa->boardcfg, 0, 64); /* clear board config area */
- saa->saa7146_mem = NULL;
- saa->dmavid1 = saa->dmavid2 = saa->dmavid3 = saa->dmaa1in =
- saa->dmaa1out = saa->dmaa2in = saa->dmaa2out =
- saa->pagevid1 = saa->pagevid2 = saa->pagevid3 = saa->pagea1in =
- saa->pagea1out = saa->pagea2in = saa->pagea2out =
- saa->pagedebi = saa->dmaRPS1 = saa->dmaRPS2 = saa->pageRPS1 =
- saa->pageRPS2 = NULL;
- saa->audbuf = saa->vidbuf = saa->osdbuf = saa->dmadebi = NULL;
- saa->audhead = saa->vidtail = 0;
-
- init_waitqueue_head(&saa->i2cq);
- init_waitqueue_head(&saa->audq);
- init_waitqueue_head(&saa->debiq);
- init_waitqueue_head(&saa->vidq);
- spin_lock_init(&saa->lock);
-
- retval = pci_enable_device(pdev);
- if (retval) {
- dev_err(&pdev->dev, "%d: pci_enable_device failed!\n", num);
- goto err;
- }
-
- saa->id = pdev->device;
- saa->irq = pdev->irq;
- saa->saa7146_adr = pci_resource_start(pdev, 0);
- pci_read_config_byte(pdev, PCI_CLASS_REVISION, &saa->revision);
-
- saa->saa7146_mem = ioremap(saa->saa7146_adr, 0x200);
- if (saa->saa7146_mem == NULL) {
- dev_err(&pdev->dev, "%d: ioremap failed!\n", num);
- retval = -EIO;
- goto err;
- }
-
- memcpy(&saa->video_dev, &saa_template, sizeof(saa_template));
- saawrite(0, SAA7146_IER); /* turn off all interrupts */
-
- retval = request_irq(saa->irq, saa7146_irq, IRQF_SHARED | IRQF_DISABLED,
- "stradis", saa);
- if (retval == -EINVAL)
- dev_err(&pdev->dev, "%d: Bad irq number or handler\n", num);
- else if (retval == -EBUSY)
- dev_err(&pdev->dev, "%d: IRQ %ld busy, change your PnP config "
- "in BIOS\n", num, saa->irq);
- if (retval < 0)
- goto errio;
-
- pci_set_master(pdev);
- retval = video_register_device(&saa->video_dev, VFL_TYPE_GRABBER,
- video_nr);
- if (retval < 0) {
- dev_err(&pdev->dev, "%d: error in registering video device!\n",
- num);
- goto errio;
- }
-
- return 0;
-errio:
- iounmap(saa->saa7146_mem);
-err:
- return retval;
-}
-
-static int __devinit init_saa7146(struct pci_dev *pdev)
-{
- struct saa7146 *saa = pci_get_drvdata(pdev);
-
- saa->user = 0;
- /* reset the saa7146 */
- saawrite(0xffff0000, SAA7146_MC1);
- mdelay(5);
- /* enable debi and i2c transfers and pins */
- saawrite(((SAA7146_MC1_EDP | SAA7146_MC1_EI2C |
- SAA7146_MC1_TR_E_DEBI) << 16) | 0xffff, SAA7146_MC1);
- /* ensure proper state of chip */
- saawrite(0x00000000, SAA7146_PAGE1);
- saawrite(0x00f302c0, SAA7146_NUM_LINE_BYTE1);
- saawrite(0x00000000, SAA7146_PAGE2);
- saawrite(0x01400080, SAA7146_NUM_LINE_BYTE2);
- saawrite(0x00000000, SAA7146_DD1_INIT);
- saawrite(0x00000000, SAA7146_DD1_STREAM_B);
- saawrite(0x00000000, SAA7146_DD1_STREAM_A);
- saawrite(0x00000000, SAA7146_BRS_CTRL);
- saawrite(0x80400040, SAA7146_BCS_CTRL);
- saawrite(0x0000e000 /*| (1<<29) */ , SAA7146_HPS_CTRL);
- saawrite(0x00000060, SAA7146_CLIP_FORMAT_CTRL);
- saawrite(0x00000000, SAA7146_ACON1);
- saawrite(0x00000000, SAA7146_ACON2);
- saawrite(0x00000600, SAA7146_I2C_STATUS);
- saawrite(((SAA7146_MC2_UPLD_D1_B | SAA7146_MC2_UPLD_D1_A |
- SAA7146_MC2_UPLD_BRS | SAA7146_MC2_UPLD_HPS_H |
- SAA7146_MC2_UPLD_HPS_V | SAA7146_MC2_UPLD_DMA2 |
- SAA7146_MC2_UPLD_DMA1 | SAA7146_MC2_UPLD_I2C) << 16) | 0xffff,
- SAA7146_MC2);
- /* setup arbitration control registers */
- saawrite(0x1412121a, SAA7146_PCI_BT_V1);
-
- /* allocate 32k dma buffer + 4k for page table */
- if ((saa->dmadebi = kmalloc(32768 + 4096, GFP_KERNEL)) == NULL) {
- dev_err(&pdev->dev, "%d: debi kmalloc failed\n", saa->nr);
- goto err;
- }
-#if 0
- saa->pagedebi = saa->dmadebi + 32768; /* top 4k is for mmu */
- saawrite(virt_to_bus(saa->pagedebi) /*|0x800 */ , SAA7146_DEBI_PAGE);
- for (i = 0; i < 12; i++) /* setup mmu page table */
- saa->pagedebi[i] = virt_to_bus((saa->dmadebi + i * 4096));
-#endif
- saa->audhead = saa->vidhead = saa->osdhead = 0;
- saa->audtail = saa->vidtail = saa->osdtail = 0;
- if (saa->vidbuf == NULL && (saa->vidbuf = vmalloc(524288)) == NULL) {
- dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
- goto err;
- }
- if (saa->audbuf == NULL && (saa->audbuf = vmalloc(65536)) == NULL) {
- dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
- goto errfree;
- }
- if (saa->osdbuf == NULL && (saa->osdbuf = vmalloc(131072)) == NULL) {
- dev_err(&pdev->dev, "%d: malloc failed\n", saa->nr);
- goto errfree;
- }
- /* allocate 81920 byte buffer for clipping */
- if ((saa->dmavid2 = kzalloc(VIDEO_CLIPMAP_SIZE, GFP_KERNEL)) == NULL) {
- dev_err(&pdev->dev, "%d: clip kmalloc failed\n", saa->nr);
- goto errfree;
- }
- /* setup clipping registers */
- saawrite(virt_to_bus(saa->dmavid2), SAA7146_BASE_EVEN2);
- saawrite(virt_to_bus(saa->dmavid2) + 128, SAA7146_BASE_ODD2);
- saawrite(virt_to_bus(saa->dmavid2) + VIDEO_CLIPMAP_SIZE,
- SAA7146_PROT_ADDR2);
- saawrite(256, SAA7146_PITCH2);
- saawrite(4, SAA7146_PAGE2); /* dma direction: read, no byteswap */
- saawrite(((SAA7146_MC2_UPLD_DMA2) << 16) | SAA7146_MC2_UPLD_DMA2,
- SAA7146_MC2);
- I2CBusScan(saa);
-
- return 0;
-errfree:
- vfree(saa->osdbuf);
- vfree(saa->audbuf);
- vfree(saa->vidbuf);
- saa->audbuf = saa->osdbuf = saa->vidbuf = NULL;
-err:
- return -ENOMEM;
-}
-
-static void stradis_release_saa(struct pci_dev *pdev)
-{
- u8 command;
- struct saa7146 *saa = pci_get_drvdata(pdev);
-
- /* turn off all capturing, DMA and IRQs */
- saawrite(0xffff0000, SAA7146_MC1); /* reset chip */
- saawrite(0, SAA7146_MC2);
- saawrite(0, SAA7146_IER);
- saawrite(0xffffffffUL, SAA7146_ISR);
-
- /* disable PCI bus-mastering */
- pci_read_config_byte(pdev, PCI_COMMAND, &command);
- command &= ~PCI_COMMAND_MASTER;
- pci_write_config_byte(pdev, PCI_COMMAND, command);
-
- /* unmap and free memory */
- saa->audhead = saa->audtail = saa->osdhead = 0;
- saa->vidhead = saa->vidtail = saa->osdtail = 0;
- vfree(saa->vidbuf);
- vfree(saa->audbuf);
- vfree(saa->osdbuf);
- kfree(saa->dmavid2);
- saa->audbuf = saa->vidbuf = saa->osdbuf = NULL;
- saa->dmavid2 = NULL;
- kfree(saa->dmadebi);
- kfree(saa->dmavid1);
- kfree(saa->dmavid3);
- kfree(saa->dmaa1in);
- kfree(saa->dmaa1out);
- kfree(saa->dmaa2in);
- kfree(saa->dmaa2out);
- kfree(saa->dmaRPS1);
- kfree(saa->dmaRPS2);
- free_irq(saa->irq, saa);
- if (saa->saa7146_mem)
- iounmap(saa->saa7146_mem);
- if (video_is_registered(&saa->video_dev))
- video_unregister_device(&saa->video_dev);
-}
-
-static int __devinit stradis_probe(struct pci_dev *pdev,
- const struct pci_device_id *ent)
-{
- int retval = -EINVAL;
-
- if (saa_num >= SAA7146_MAX)
- goto err;
-
- if (!pdev->subsystem_vendor)
- dev_info(&pdev->dev, "%d: rev1 decoder\n", saa_num);
- else
- dev_info(&pdev->dev, "%d: SDM2xx found\n", saa_num);
-
- pci_set_drvdata(pdev, &saa7146s[saa_num]);
-
- retval = configure_saa7146(pdev, saa_num);
- if (retval) {
- dev_err(&pdev->dev, "%d: error in configuring\n", saa_num);
- goto err;
- }
-
- if (init_saa7146(pdev) < 0) {
- dev_err(&pdev->dev, "%d: error in initialization\n", saa_num);
- retval = -EIO;
- goto errrel;
- }
-
- saa_num++;
-
- return 0;
-errrel:
- stradis_release_saa(pdev);
-err:
- return retval;
-}
-
-static void __devexit stradis_remove(struct pci_dev *pdev)
-{
- stradis_release_saa(pdev);
-}
-
-static struct pci_device_id stradis_pci_tbl[] = {
- { PCI_DEVICE(PCI_VENDOR_ID_PHILIPS, PCI_DEVICE_ID_PHILIPS_SAA7146) },
- { 0 }
-};
-
-
-static struct pci_driver stradis_driver = {
- .name = "stradis",
- .id_table = stradis_pci_tbl,
- .probe = stradis_probe,
- .remove = __devexit_p(stradis_remove)
-};
-
-static int __init stradis_init(void)
-{
- int retval;
-
- saa_num = 0;
-
- retval = pci_register_driver(&stradis_driver);
- if (retval)
- printk(KERN_ERR "stradis: Unable to register pci driver.\n");
-
- return retval;
-}
-
-static void __exit stradis_exit(void)
-{
- pci_unregister_driver(&stradis_driver);
- printk(KERN_INFO "stradis: module cleanup complete\n");
-}
-
-module_init(stradis_init);
-module_exit(stradis_exit);
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
deleted file mode 100644
index 5938ad8702ef..000000000000
--- a/drivers/media/video/stv680.c
+++ /dev/null
@@ -1,1565 +0,0 @@
-/*
- * STV0680 USB Camera Driver, by Kevin Sisson (kjsisson@bellsouth.net)
- *
- * Thanks to STMicroelectronics for information on the usb commands, and
- * to Steve Miller at STM for his help and encouragement while I was
- * writing this driver.
- *
- * This driver is based heavily on the
- * Endpoints (formerly known as AOX) se401 USB Camera Driver
- * Copyright (c) 2000 Jeroen B. Vreeken (pe1rxq@amsat.org)
- *
- * Still somewhat based on the Linux ov511 driver.
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
- * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- *
- * History:
- * ver 0.1 October, 2001. Initial attempt.
- *
- * ver 0.2 November, 2001. Fixed asbility to resize, added brightness
- * function, made more stable (?)
- *
- * ver 0.21 Nov, 2001. Added gamma correction and white balance,
- * due to Alexander Schwartz. Still trying to
- * improve stablility. Moved stuff into stv680.h
- *
- * ver 0.22 Nov, 2001. Added sharpen function (by Michael Sweet,
- * mike@easysw.com) from GIMP, also used in pencam.
- * Simple, fast, good integer math routine.
- *
- * ver 0.23 Dec, 2001 (gkh)
- * Took out sharpen function, ran code through
- * Lindent, and did other minor tweaks to get
- * things to work properly with 2.5.1
- *
- * ver 0.24 Jan, 2002 (kjs)
- * Fixed the problem with webcam crashing after
- * two pictures. Changed the way pic is halved to
- * improve quality. Got rid of green line around
- * frame. Fix brightness reset when changing size
- * bug. Adjusted gamma filters slightly.
- *
- * ver 0.25 Jan, 2002 (kjs)
- * Fixed a bug in which the driver sometimes attempted
- * to set to a non-supported size. This allowed
- * gnomemeeting to work.
- * Fixed proc entry removal bug.
- */
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/pagemap.h>
-#include <linux/errno.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-#include "stv680.h"
-
-static int video_nr = -1;
-
-static int swapRGB; /* 0 = default for auto select */
-
-/* 0 = default to allow auto select; -1 = swap never, +1 = swap always */
-static int swapRGB_on;
-
-static unsigned int debug;
-
-#define PDEBUG(level, fmt, args...) \
- do { \
- if (debug >= level) \
- printk(KERN_INFO KBUILD_MODNAME " [%s:%d] \n" fmt, \
- __func__, __LINE__ , ## args); \
- } while (0)
-
-
-/*
- * Version Information
- */
-#define DRIVER_VERSION "v0.25"
-#define DRIVER_AUTHOR "Kevin Sisson <kjsisson@bellsouth.net>"
-#define DRIVER_DESC "STV0680 USB Camera Driver"
-
-MODULE_AUTHOR (DRIVER_AUTHOR);
-MODULE_DESCRIPTION (DRIVER_DESC);
-MODULE_LICENSE ("GPL");
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC (debug, "Debug enabled or not");
-module_param(swapRGB_on, int, 0);
-MODULE_PARM_DESC (swapRGB_on, "Red/blue swap: 1=always, 0=auto, -1=never");
-module_param(video_nr, int, 0);
-
-/********************************************************************
- *
- * Memory management
- *
- * This is a shameless copy from the USB-cpia driver (linux kernel
- * version 2.3.29 or so, I have no idea what this code actually does ;).
- * Actually it seems to be a copy of a shameless copy of the bttv-driver.
- * Or that is a copy of a shameless copy of ... (To the powers: is there
- * no generic kernel-function to do this sort of stuff?)
- *
- * Yes, it was a shameless copy from the bttv-driver. IIRC, Alan says
- * there will be one, but apparentely not yet -jerdfelt
- *
- * So I copied it again for the ov511 driver -claudio
- *
- * Same for the se401 driver -Jeroen
- *
- * And the STV0680 driver - Kevin
- ********************************************************************/
-static void *rvmalloc (unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32 (size);
- if (!mem)
- return NULL;
-
- memset (mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- return mem;
-}
-
-static void rvfree (void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree (mem);
-}
-
-
-/*********************************************************************
- * pencam read/write functions
- ********************************************************************/
-
-static int stv_sndctrl (int set, struct usb_stv *stv680, unsigned short req, unsigned short value, unsigned char *buffer, int size)
-{
- int ret = -1;
-
- switch (set) {
- case 0: /* 0xc1 */
- ret = usb_control_msg (stv680->udev,
- usb_rcvctrlpipe (stv680->udev, 0),
- req,
- (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
- value, 0, buffer, size, PENCAM_TIMEOUT);
- break;
-
- case 1: /* 0x41 */
- ret = usb_control_msg (stv680->udev,
- usb_sndctrlpipe (stv680->udev, 0),
- req,
- (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT),
- value, 0, buffer, size, PENCAM_TIMEOUT);
- break;
-
- case 2: /* 0x80 */
- ret = usb_control_msg (stv680->udev,
- usb_rcvctrlpipe (stv680->udev, 0),
- req,
- (USB_DIR_IN | USB_RECIP_DEVICE),
- value, 0, buffer, size, PENCAM_TIMEOUT);
- break;
-
- case 3: /* 0x40 */
- ret = usb_control_msg (stv680->udev,
- usb_sndctrlpipe (stv680->udev, 0),
- req,
- (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE),
- value, 0, buffer, size, PENCAM_TIMEOUT);
- break;
-
- }
- if ((ret < 0) && (req != 0x0a)) {
- PDEBUG (1, "STV(e): usb_control_msg error %i, request = 0x%x, error = %i", set, req, ret);
- }
- return ret;
-}
-
-static int stv_set_config (struct usb_stv *dev, int configuration, int interface, int alternate)
-{
-
- if (configuration != dev->udev->actconfig->desc.bConfigurationValue
- || usb_reset_configuration (dev->udev) < 0) {
- PDEBUG (1, "STV(e): FAILED to reset configuration %i", configuration);
- return -1;
- }
- if (usb_set_interface (dev->udev, interface, alternate) < 0) {
- PDEBUG (1, "STV(e): FAILED to set alternate interface %i", alternate);
- return -1;
- }
- return 0;
-}
-
-static int stv_stop_video (struct usb_stv *dev)
-{
- int i;
- unsigned char *buf;
-
- buf = kmalloc (40, GFP_KERNEL);
- if (buf == NULL) {
- PDEBUG (0, "STV(e): Out of (small buf) memory");
- return -1;
- }
-
- /* this is a high priority command; it stops all lower order commands */
- if ((i = stv_sndctrl (1, dev, 0x04, 0x0000, buf, 0x0)) < 0) {
- i = stv_sndctrl (0, dev, 0x80, 0, buf, 0x02); /* Get Last Error; 2 = busy */
- PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buf[0], buf[1]);
- } else {
- PDEBUG (1, "STV(i): Camera reset to idle mode.");
- }
-
- if ((i = stv_set_config (dev, 1, 0, 0)) < 0)
- PDEBUG (1, "STV(e): Reset config during exit failed");
-
- /* get current mode */
- buf[0] = 0xf0;
- if ((i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08)) != 0x08) /* get mode */
- PDEBUG (0, "STV(e): Stop_video: problem setting original mode");
- if (dev->origMode != buf[0]) {
- memset (buf, 0, 8);
- buf[0] = (unsigned char) dev->origMode;
- if ((i = stv_sndctrl (3, dev, 0x07, 0x0100, buf, 0x08)) != 0x08) {
- PDEBUG (0, "STV(e): Stop_video: Set_Camera_Mode failed");
- i = -1;
- }
- buf[0] = 0xf0;
- i = stv_sndctrl (0, dev, 0x87, 0, buf, 0x08);
- if ((i != 0x08) || (buf[0] != dev->origMode)) {
- PDEBUG (0, "STV(e): camera NOT set to original resolution.");
- i = -1;
- } else
- PDEBUG (0, "STV(i): Camera set to original resolution");
- }
- /* origMode */
- kfree(buf);
- return i;
-}
-
-static int stv_set_video_mode (struct usb_stv *dev)
-{
- int i, stop_video = 1;
- unsigned char *buf;
-
- buf = kmalloc (40, GFP_KERNEL);
- if (buf == NULL) {
- PDEBUG (0, "STV(e): Out of (small buf) memory");
- return -1;
- }
-
- if ((i = stv_set_config (dev, 1, 0, 0)) < 0) {
- kfree(buf);
- return i;
- }
-
- i = stv_sndctrl (2, dev, 0x06, 0x0100, buf, 0x12);
- if (!(i > 0) && (buf[8] == 0x53) && (buf[9] == 0x05)) {
- PDEBUG (1, "STV(e): Could not get descriptor 0100.");
- goto error;
- }
-
- /* set alternate interface 1 */
- if ((i = stv_set_config (dev, 1, 0, 1)) < 0)
- goto error;
-
- if ((i = stv_sndctrl (0, dev, 0x85, 0, buf, 0x10)) != 0x10)
- goto error;
- PDEBUG (1, "STV(i): Setting video mode.");
- /* Switch to Video mode: 0x0100 = VGA (640x480), 0x0000 = CIF (352x288) 0x0300 = QVGA (320x240) */
- if ((i = stv_sndctrl (1, dev, 0x09, dev->VideoMode, buf, 0x0)) < 0) {
- stop_video = 0;
- goto error;
- }
- goto exit;
-
-error:
- kfree(buf);
- if (stop_video == 1)
- stv_stop_video (dev);
- return -1;
-
-exit:
- kfree(buf);
- return 0;
-}
-
-static int stv_init (struct usb_stv *stv680)
-{
- int i = 0;
- unsigned char *buffer;
- unsigned long int bufsize;
-
- buffer = kzalloc (40, GFP_KERNEL);
- if (buffer == NULL) {
- PDEBUG (0, "STV(e): Out of (small buf) memory");
- return -1;
- }
- udelay (100);
-
- /* set config 1, interface 0, alternate 0 */
- if ((i = stv_set_config (stv680, 1, 0, 0)) < 0) {
- kfree(buffer);
- PDEBUG (0, "STV(e): set config 1,0,0 failed");
- return -1;
- }
- /* ping camera to be sure STV0680 is present */
- if ((i = stv_sndctrl (0, stv680, 0x88, 0x5678, buffer, 0x02)) != 0x02)
- goto error;
- if ((buffer[0] != 0x56) || (buffer[1] != 0x78)) {
- PDEBUG (1, "STV(e): camera ping failed!!");
- goto error;
- }
-
- /* get camera descriptor */
- if ((i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x09)) != 0x09)
- goto error;
- i = stv_sndctrl (2, stv680, 0x06, 0x0200, buffer, 0x22);
- if (!(i >= 0) && (buffer[7] == 0xa0) && (buffer[8] == 0x23)) {
- PDEBUG (1, "STV(e): Could not get descriptor 0200.");
- goto error;
- }
- if ((i = stv_sndctrl (0, stv680, 0x8a, 0, buffer, 0x02)) != 0x02)
- goto error;
- if ((i = stv_sndctrl (0, stv680, 0x8b, 0, buffer, 0x24)) != 0x24)
- goto error;
- if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
- goto error;
-
- stv680->SupportedModes = buffer[7];
- i = stv680->SupportedModes;
- stv680->CIF = 0;
- stv680->VGA = 0;
- stv680->QVGA = 0;
- if (i & 1)
- stv680->CIF = 1;
- if (i & 2)
- stv680->VGA = 1;
- if (i & 8)
- stv680->QVGA = 1;
- if (stv680->SupportedModes == 0) {
- PDEBUG (0, "STV(e): There are NO supported STV680 modes!!");
- i = -1;
- goto error;
- } else {
- if (stv680->CIF)
- PDEBUG (0, "STV(i): CIF is supported");
- if (stv680->QVGA)
- PDEBUG (0, "STV(i): QVGA is supported");
- }
- /* FW rev, ASIC rev, sensor ID */
- PDEBUG (1, "STV(i): Firmware rev is %i.%i", buffer[0], buffer[1]);
- PDEBUG (1, "STV(i): ASIC rev is %i.%i", buffer[2], buffer[3]);
- PDEBUG (1, "STV(i): Sensor ID is %i", (buffer[4]*16) + (buffer[5]>>4));
-
- /* set alternate interface 1 */
- if ((i = stv_set_config (stv680, 1, 0, 1)) < 0)
- goto error;
-
- if ((i = stv_sndctrl (0, stv680, 0x85, 0, buffer, 0x10)) != 0x10)
- goto error;
- if ((i = stv_sndctrl (0, stv680, 0x8d, 0, buffer, 0x08)) != 0x08)
- goto error;
- i = buffer[3];
- PDEBUG (0, "STV(i): Camera has %i pictures.", i);
-
- /* get current mode */
- if ((i = stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08)) != 0x08)
- goto error;
- stv680->origMode = buffer[0]; /* 01 = VGA, 03 = QVGA, 00 = CIF */
-
- /* This will attemp CIF mode, if supported. If not, set to QVGA */
- memset (buffer, 0, 8);
- if (stv680->CIF)
- buffer[0] = 0x00;
- else if (stv680->QVGA)
- buffer[0] = 0x03;
- if ((i = stv_sndctrl (3, stv680, 0x07, 0x0100, buffer, 0x08)) != 0x08) {
- PDEBUG (0, "STV(i): Set_Camera_Mode failed");
- i = -1;
- goto error;
- }
- buffer[0] = 0xf0;
- stv_sndctrl (0, stv680, 0x87, 0, buffer, 0x08);
- if (((stv680->CIF == 1) && (buffer[0] != 0x00)) || ((stv680->QVGA == 1) && (buffer[0] != 0x03))) {
- PDEBUG (0, "STV(e): Error setting camera video mode!");
- i = -1;
- goto error;
- } else {
- if (buffer[0] == 0) {
- stv680->VideoMode = 0x0000;
- PDEBUG (0, "STV(i): Video Mode set to CIF");
- }
- if (buffer[0] == 0x03) {
- stv680->VideoMode = 0x0300;
- PDEBUG (0, "STV(i): Video Mode set to QVGA");
- }
- }
- if ((i = stv_sndctrl (0, stv680, 0x8f, 0, buffer, 0x10)) != 0x10)
- goto error;
- bufsize = (buffer[0] << 24) | (buffer[1] << 16) | (buffer[2] << 8) | (buffer[3]);
- stv680->cwidth = (buffer[4] << 8) | (buffer[5]); /* ->camera = 322, 356, 644 */
- stv680->cheight = (buffer[6] << 8) | (buffer[7]); /* ->camera = 242, 292, 484 */
- stv680->origGain = buffer[12];
-
- goto exit;
-
-error:
- i = stv_sndctrl (0, stv680, 0x80, 0, buffer, 0x02); /* Get Last Error */
- PDEBUG (1, "STV(i): last error: %i, command = 0x%x", buffer[0], buffer[1]);
- kfree(buffer);
- return -1;
-
-exit:
- kfree(buffer);
-
- /* video = 320x240, 352x288 */
- if (stv680->CIF == 1) {
- stv680->maxwidth = 352;
- stv680->maxheight = 288;
- stv680->vwidth = 352;
- stv680->vheight = 288;
- }
- if (stv680->QVGA == 1) {
- stv680->maxwidth = 320;
- stv680->maxheight = 240;
- stv680->vwidth = 320;
- stv680->vheight = 240;
- }
-
- stv680->rawbufsize = bufsize; /* must be ./. by 8 */
- stv680->maxframesize = bufsize * 3; /* RGB size */
- PDEBUG (2, "STV(i): cwidth = %i, cheight = %i", stv680->cwidth, stv680->cheight);
- PDEBUG (1, "STV(i): width = %i, height = %i, rawbufsize = %li", stv680->vwidth, stv680->vheight, stv680->rawbufsize);
-
- /* some default values */
- stv680->bulk_in_endpointAddr = 0x82;
- stv680->dropped = 0;
- stv680->error = 0;
- stv680->framecount = 0;
- stv680->readcount = 0;
- stv680->streaming = 0;
- /* bright, white, colour, hue, contrast are set by software, not in stv0680 */
- stv680->brightness = 32767;
- stv680->chgbright = 0;
- stv680->whiteness = 0; /* only for greyscale */
- stv680->colour = 32767;
- stv680->contrast = 32767;
- stv680->hue = 32767;
- stv680->palette = STV_VIDEO_PALETTE;
- stv680->depth = 24; /* rgb24 bits */
- if ((swapRGB_on == 0) && (swapRGB == 0))
- PDEBUG (1, "STV(i): swapRGB is (auto) OFF");
- else if ((swapRGB_on == 0) && (swapRGB == 1))
- PDEBUG (1, "STV(i): swapRGB is (auto) ON");
- else if (swapRGB_on == 1)
- PDEBUG (1, "STV(i): swapRGB is (forced) ON");
- else if (swapRGB_on == -1)
- PDEBUG (1, "STV(i): swapRGB is (forced) OFF");
-
- if (stv_set_video_mode (stv680) < 0) {
- PDEBUG (0, "STV(e): Could not set video mode in stv_init");
- return -1;
- }
-
- return 0;
-}
-
-/***************** last of pencam routines *******************/
-
-/****************************************************************************
- * sysfs
- ***************************************************************************/
-#define stv680_file(name, variable, field) \
-static ssize_t show_##name(struct device *class_dev, \
- struct device_attribute *attr, char *buf) \
-{ \
- struct video_device *vdev = to_video_device(class_dev); \
- struct usb_stv *stv = video_get_drvdata(vdev); \
- return sprintf(buf, field, stv->variable); \
-} \
-static DEVICE_ATTR(name, S_IRUGO, show_##name, NULL);
-
-stv680_file(model, camera_name, "%s\n");
-stv680_file(in_use, user, "%d\n");
-stv680_file(streaming, streaming, "%d\n");
-stv680_file(palette, palette, "%i\n");
-stv680_file(frames_total, readcount, "%d\n");
-stv680_file(frames_read, framecount, "%d\n");
-stv680_file(packets_dropped, dropped, "%d\n");
-stv680_file(decoding_errors, error, "%d\n");
-
-static int stv680_create_sysfs_files(struct video_device *vdev)
-{
- int rc;
-
- rc = device_create_file(&vdev->dev, &dev_attr_model);
- if (rc) goto err;
- rc = device_create_file(&vdev->dev, &dev_attr_in_use);
- if (rc) goto err_model;
- rc = device_create_file(&vdev->dev, &dev_attr_streaming);
- if (rc) goto err_inuse;
- rc = device_create_file(&vdev->dev, &dev_attr_palette);
- if (rc) goto err_stream;
- rc = device_create_file(&vdev->dev, &dev_attr_frames_total);
- if (rc) goto err_pal;
- rc = device_create_file(&vdev->dev, &dev_attr_frames_read);
- if (rc) goto err_framtot;
- rc = device_create_file(&vdev->dev, &dev_attr_packets_dropped);
- if (rc) goto err_framread;
- rc = device_create_file(&vdev->dev, &dev_attr_decoding_errors);
- if (rc) goto err_dropped;
-
- return 0;
-
-err_dropped:
- device_remove_file(&vdev->dev, &dev_attr_packets_dropped);
-err_framread:
- device_remove_file(&vdev->dev, &dev_attr_frames_read);
-err_framtot:
- device_remove_file(&vdev->dev, &dev_attr_frames_total);
-err_pal:
- device_remove_file(&vdev->dev, &dev_attr_palette);
-err_stream:
- device_remove_file(&vdev->dev, &dev_attr_streaming);
-err_inuse:
- device_remove_file(&vdev->dev, &dev_attr_in_use);
-err_model:
- device_remove_file(&vdev->dev, &dev_attr_model);
-err:
- PDEBUG(0, "STV(e): Could not create sysfs files");
- return rc;
-}
-
-static void stv680_remove_sysfs_files(struct video_device *vdev)
-{
- device_remove_file(&vdev->dev, &dev_attr_model);
- device_remove_file(&vdev->dev, &dev_attr_in_use);
- device_remove_file(&vdev->dev, &dev_attr_streaming);
- device_remove_file(&vdev->dev, &dev_attr_palette);
- device_remove_file(&vdev->dev, &dev_attr_frames_total);
- device_remove_file(&vdev->dev, &dev_attr_frames_read);
- device_remove_file(&vdev->dev, &dev_attr_packets_dropped);
- device_remove_file(&vdev->dev, &dev_attr_decoding_errors);
-}
-
-/********************************************************************
- * Camera control
- *******************************************************************/
-
-static int stv680_get_pict (struct usb_stv *stv680, struct video_picture *p)
-{
- /* This sets values for v4l interface. max/min = 65535/0 */
-
- p->brightness = stv680->brightness;
- p->whiteness = stv680->whiteness; /* greyscale */
- p->colour = stv680->colour;
- p->contrast = stv680->contrast;
- p->hue = stv680->hue;
- p->palette = stv680->palette;
- p->depth = stv680->depth;
- return 0;
-}
-
-static int stv680_set_pict (struct usb_stv *stv680, struct video_picture *p)
-{
- /* See above stv680_get_pict */
-
- if (p->palette != STV_VIDEO_PALETTE) {
- PDEBUG (2, "STV(e): Palette set error in _set_pic");
- return 1;
- }
-
- if (stv680->brightness != p->brightness) {
- stv680->chgbright = 1;
- stv680->brightness = p->brightness;
- }
-
- stv680->whiteness = p->whiteness; /* greyscale */
- stv680->colour = p->colour;
- stv680->contrast = p->contrast;
- stv680->hue = p->hue;
- stv680->palette = p->palette;
- stv680->depth = p->depth;
-
- return 0;
-}
-
-static void stv680_video_irq (struct urb *urb)
-{
- struct usb_stv *stv680 = urb->context;
- int length = urb->actual_length;
-
- if (length < stv680->rawbufsize)
- PDEBUG (2, "STV(i): Lost data in transfer: exp %li, got %i", stv680->rawbufsize, length);
-
- /* ohoh... */
- if (!stv680->streaming)
- return;
-
- if (!stv680->udev) {
- PDEBUG (0, "STV(e): device vapourished in video_irq");
- return;
- }
-
- /* 0 sized packets happen if we are to fast, but sometimes the camera
- keeps sending them forever...
- */
- if (length && !urb->status) {
- stv680->nullpackets = 0;
- switch (stv680->scratch[stv680->scratch_next].state) {
- case BUFFER_READY:
- case BUFFER_BUSY:
- stv680->dropped++;
- break;
-
- case BUFFER_UNUSED:
- memcpy (stv680->scratch[stv680->scratch_next].data,
- (unsigned char *) urb->transfer_buffer, length);
- stv680->scratch[stv680->scratch_next].state = BUFFER_READY;
- stv680->scratch[stv680->scratch_next].length = length;
- if (waitqueue_active (&stv680->wq)) {
- wake_up_interruptible (&stv680->wq);
- }
- stv680->scratch_overflow = 0;
- stv680->scratch_next++;
- if (stv680->scratch_next >= STV680_NUMSCRATCH)
- stv680->scratch_next = 0;
- break;
- } /* switch */
- } else {
- stv680->nullpackets++;
- if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
- if (waitqueue_active (&stv680->wq)) {
- wake_up_interruptible (&stv680->wq);
- }
- }
- } /* if - else */
-
- /* Resubmit urb for new data */
- urb->status = 0;
- urb->dev = stv680->udev;
- if (usb_submit_urb (urb, GFP_ATOMIC))
- PDEBUG (0, "STV(e): urb burned down in video irq");
- return;
-} /* _video_irq */
-
-static int stv680_start_stream (struct usb_stv *stv680)
-{
- struct urb *urb;
- int err = 0, i;
-
- stv680->streaming = 1;
-
- /* Do some memory allocation */
- for (i = 0; i < STV680_NUMFRAMES; i++) {
- stv680->frame[i].data = stv680->fbuf + i * stv680->maxframesize;
- stv680->frame[i].curpix = 0;
- }
- /* packet size = 4096 */
- for (i = 0; i < STV680_NUMSBUF; i++) {
- stv680->sbuf[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
- if (stv680->sbuf[i].data == NULL) {
- PDEBUG (0, "STV(e): Could not kmalloc raw data buffer %i", i);
- goto nomem_err;
- }
- }
-
- stv680->scratch_next = 0;
- stv680->scratch_use = 0;
- stv680->scratch_overflow = 0;
- for (i = 0; i < STV680_NUMSCRATCH; i++) {
- stv680->scratch[i].data = kmalloc (stv680->rawbufsize, GFP_KERNEL);
- if (stv680->scratch[i].data == NULL) {
- PDEBUG (0, "STV(e): Could not kmalloc raw scratch buffer %i", i);
- goto nomem_err;
- }
- stv680->scratch[i].state = BUFFER_UNUSED;
- }
-
- for (i = 0; i < STV680_NUMSBUF; i++) {
- urb = usb_alloc_urb (0, GFP_KERNEL);
- if (!urb)
- goto nomem_err;
-
- /* sbuf is urb->transfer_buffer, later gets memcpyed to scratch */
- usb_fill_bulk_urb (urb, stv680->udev,
- usb_rcvbulkpipe (stv680->udev, stv680->bulk_in_endpointAddr),
- stv680->sbuf[i].data, stv680->rawbufsize,
- stv680_video_irq, stv680);
- stv680->urb[i] = urb;
- err = usb_submit_urb (stv680->urb[i], GFP_KERNEL);
- if (err) {
- PDEBUG (0, "STV(e): urb burned down with err "
- "%d in start stream %d", err, i);
- goto nomem_err;
- }
- } /* i STV680_NUMSBUF */
-
- stv680->framecount = 0;
- return 0;
-
- nomem_err:
- for (i = 0; i < STV680_NUMSBUF; i++) {
- usb_kill_urb(stv680->urb[i]);
- usb_free_urb(stv680->urb[i]);
- stv680->urb[i] = NULL;
- kfree(stv680->sbuf[i].data);
- stv680->sbuf[i].data = NULL;
- }
- /* used in irq, free only as all URBs are dead */
- for (i = 0; i < STV680_NUMSCRATCH; i++) {
- kfree(stv680->scratch[i].data);
- stv680->scratch[i].data = NULL;
- }
- return -ENOMEM;
-
-}
-
-static int stv680_stop_stream (struct usb_stv *stv680)
-{
- int i;
-
- if (!stv680->streaming || !stv680->udev)
- return 1;
-
- stv680->streaming = 0;
-
- for (i = 0; i < STV680_NUMSBUF; i++)
- if (stv680->urb[i]) {
- usb_kill_urb (stv680->urb[i]);
- usb_free_urb (stv680->urb[i]);
- stv680->urb[i] = NULL;
- kfree(stv680->sbuf[i].data);
- }
- for (i = 0; i < STV680_NUMSCRATCH; i++) {
- kfree(stv680->scratch[i].data);
- stv680->scratch[i].data = NULL;
- }
-
- return 0;
-}
-
-static int stv680_set_size (struct usb_stv *stv680, int width, int height)
-{
- int wasstreaming = stv680->streaming;
-
- /* Check to see if we need to change */
- if ((stv680->vwidth == width) && (stv680->vheight == height))
- return 0;
-
- PDEBUG (1, "STV(i): size request for %i x %i", width, height);
- /* Check for a valid mode */
- if ((!width || !height) || ((width & 1) || (height & 1))) {
- PDEBUG (1, "STV(e): set_size error: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
- return 1;
- }
-
- if ((width < (stv680->maxwidth / 2)) || (height < (stv680->maxheight / 2))) {
- width = stv680->maxwidth / 2;
- height = stv680->maxheight / 2;
- } else if ((width >= 158) && (width <= 166) && (stv680->QVGA == 1)) {
- width = 160;
- height = 120;
- } else if ((width >= 172) && (width <= 180) && (stv680->CIF == 1)) {
- width = 176;
- height = 144;
- } else if ((width >= 318) && (width <= 350) && (stv680->QVGA == 1)) {
- width = 320;
- height = 240;
- } else if ((width >= 350) && (width <= 358) && (stv680->CIF == 1)) {
- width = 352;
- height = 288;
- } else {
- PDEBUG (1, "STV(e): request for non-supported size: request: v.width = %i, v.height = %i actual: stv.width = %i, stv.height = %i", width, height, stv680->vwidth, stv680->vheight);
- return 1;
- }
-
- /* Stop a current stream and start it again at the new size */
- if (wasstreaming)
- stv680_stop_stream (stv680);
- stv680->vwidth = width;
- stv680->vheight = height;
- PDEBUG (1, "STV(i): size set to %i x %i", stv680->vwidth, stv680->vheight);
- if (wasstreaming)
- stv680_start_stream (stv680);
-
- return 0;
-}
-
-/**********************************************************************
- * Video Decoding
- **********************************************************************/
-
-/******* routines from the pencam program; hey, they work! ********/
-
-/*
- * STV0680 Vision Camera Chipset Driver
- * Copyright (C) 2000 Adam Harrison <adam@antispin.org>
-*/
-
-#define RED 0
-#define GREEN 1
-#define BLUE 2
-#define AD(x, y, w) (((y)*(w)+(x))*3)
-
-static void bayer_unshuffle (struct usb_stv *stv680, struct stv680_scratch *buffer)
-{
- int x, y, i;
- int w = stv680->cwidth;
- int vw = stv680->cwidth, vh = stv680->cheight;
- unsigned int p = 0;
- int colour = 0, bayer = 0;
- unsigned char *raw = buffer->data;
- struct stv680_frame *frame = &stv680->frame[stv680->curframe];
- unsigned char *output = frame->data;
- unsigned char *temp = frame->data;
- int offset = buffer->offset;
-
- if (frame->curpix == 0) {
- if (frame->grabstate == FRAME_READY) {
- frame->grabstate = FRAME_GRABBING;
- }
- }
- if (offset != frame->curpix) { /* Regard frame as lost :( */
- frame->curpix = 0;
- stv680->error++;
- return;
- }
-
- if ((stv680->vwidth == 320) || (stv680->vwidth == 160)) {
- vw = 320;
- vh = 240;
- }
- if ((stv680->vwidth == 352) || (stv680->vwidth == 176)) {
- vw = 352;
- vh = 288;
- }
-
- memset (output, 0, 3 * vw * vh); /* clear output matrix. */
-
- for (y = 0; y < vh; y++) {
- for (x = 0; x < vw; x++) {
- if (x & 1)
- p = *(raw + y * w + (x >> 1));
- else
- p = *(raw + y * w + (x >> 1) + (w >> 1));
-
- if (y & 1)
- bayer = 2;
- else
- bayer = 0;
- if (x & 1)
- bayer++;
-
- switch (bayer) {
- case 0:
- case 3:
- colour = 1;
- break;
- case 1:
- colour = 0;
- break;
- case 2:
- colour = 2;
- break;
- }
- i = (y * vw + x) * 3;
- *(output + i + colour) = (unsigned char) p;
- } /* for x */
-
- } /* for y */
-
- /****** gamma correction plus hardcoded white balance */
- /* Thanks to Alexander Schwartx <alexander.schwartx@gmx.net> for this code.
- Correction values red[], green[], blue[], are generated by
- (pow(i/256.0, GAMMA)*255.0)*white balanceRGB where GAMMA=0.55, 1<i<255.
- White balance (RGB)= 1.0, 1.17, 1.48. Values are calculated as double float and
- converted to unsigned char. Values are in stv680.h */
-
- for (y = 0; y < vh; y++) {
- for (x = 0; x < vw; x++) {
- i = (y * vw + x) * 3;
- *(output + i) = red[*(output + i)];
- *(output + i + 1) = green[*(output + i + 1)];
- *(output + i + 2) = blue[*(output + i + 2)];
- }
- }
-
- /****** bayer demosaic ******/
- for (y = 1; y < (vh - 1); y++) {
- for (x = 1; x < (vw - 1); x++) { /* work out pixel type */
- if (y & 1)
- bayer = 0;
- else
- bayer = 2;
- if (!(x & 1))
- bayer++;
-
- switch (bayer) {
- case 0: /* green. blue lr, red tb */
- *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y, vw) + BLUE) + (int) *(output + AD (x + 1, y, vw) + BLUE)) >> 1;
- *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x, y - 1, vw) + RED) + (int) *(output + AD (x, y + 1, vw) + RED)) >> 1;
- break;
-
- case 1: /* blue. green lrtb, red diagonals */
- *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
- *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y - 1, vw) + RED) + (int) *(output + AD (x - 1, y + 1, vw) + RED) + (int) *(output + AD (x + 1, y - 1, vw) + RED) + (int) *(output + AD (x + 1, y + 1, vw) + RED)) >> 2;
- break;
-
- case 2: /* red. green lrtb, blue diagonals */
- *(output + AD (x, y, vw) + GREEN) = ((int) *(output + AD (x - 1, y, vw) + GREEN) + (int) *(output + AD (x + 1, y, vw) + GREEN) + (int) *(output + AD (x, y - 1, vw) + GREEN) + (int) *(output + AD (x, y + 1, vw) + GREEN)) >> 2;
- *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x - 1, y - 1, vw) + BLUE) + (int) *(output + AD (x + 1, y - 1, vw) + BLUE) + (int) *(output + AD (x - 1, y + 1, vw) + BLUE) + (int) *(output + AD (x + 1, y + 1, vw) + BLUE)) >> 2;
- break;
-
- case 3: /* green. red lr, blue tb */
- *(output + AD (x, y, vw) + RED) = ((int) *(output + AD (x - 1, y, vw) + RED) + (int) *(output + AD (x + 1, y, vw) + RED)) >> 1;
- *(output + AD (x, y, vw) + BLUE) = ((int) *(output + AD (x, y - 1, vw) + BLUE) + (int) *(output + AD (x, y + 1, vw) + BLUE)) >> 1;
- break;
- } /* switch */
- } /* for x */
- } /* for y - end demosaic */
-
- /* fix top and bottom row, left and right side */
- i = vw * 3;
- memcpy (output, (output + i), i);
- memcpy ((output + (vh * i)), (output + ((vh - 1) * i)), i);
- for (y = 0; y < vh; y++) {
- i = y * vw * 3;
- memcpy ((output + i), (output + i + 3), 3);
- memcpy ((output + i + (vw * 3)), (output + i + (vw - 1) * 3), 3);
- }
-
- /* process all raw data, then trim to size if necessary */
- if ((stv680->vwidth == 160) || (stv680->vwidth == 176)) {
- i = 0;
- for (y = 0; y < vh; y++) {
- if (!(y & 1)) {
- for (x = 0; x < vw; x++) {
- p = (y * vw + x) * 3;
- if (!(x & 1)) {
- *(output + i) = *(output + p);
- *(output + i + 1) = *(output + p + 1);
- *(output + i + 2) = *(output + p + 2);
- i += 3;
- }
- } /* for x */
- }
- } /* for y */
- }
- /* reset to proper width */
- if ((stv680->vwidth == 160)) {
- vw = 160;
- vh = 120;
- }
- if ((stv680->vwidth == 176)) {
- vw = 176;
- vh = 144;
- }
-
- /* output is RGB; some programs want BGR */
- /* swapRGB_on=0 -> program decides; swapRGB_on=1, always swap */
- /* swapRGB_on=-1, never swap */
- if (((swapRGB == 1) && (swapRGB_on != -1)) || (swapRGB_on == 1)) {
- for (y = 0; y < vh; y++) {
- for (x = 0; x < vw; x++) {
- i = (y * vw + x) * 3;
- *(temp) = *(output + i);
- *(output + i) = *(output + i + 2);
- *(output + i + 2) = *(temp);
- }
- }
- }
- /* brightness */
- if (stv680->chgbright == 1) {
- if (stv680->brightness >= 32767) {
- p = (stv680->brightness - 32767) / 256;
- for (x = 0; x < (vw * vh * 3); x++) {
- if ((*(output + x) + (unsigned char) p) > 255)
- *(output + x) = 255;
- else
- *(output + x) += (unsigned char) p;
- } /* for */
- } else {
- p = (32767 - stv680->brightness) / 256;
- for (x = 0; x < (vw * vh * 3); x++) {
- if ((unsigned char) p > *(output + x))
- *(output + x) = 0;
- else
- *(output + x) -= (unsigned char) p;
- } /* for */
- } /* else */
- }
- /* if */
- frame->curpix = 0;
- frame->curlinepix = 0;
- frame->grabstate = FRAME_DONE;
- stv680->framecount++;
- stv680->readcount++;
- if (stv680->frame[(stv680->curframe + 1) & (STV680_NUMFRAMES - 1)].grabstate == FRAME_READY) {
- stv680->curframe = (stv680->curframe + 1) & (STV680_NUMFRAMES - 1);
- }
-
-} /* bayer_unshuffle */
-
-/******* end routines from the pencam program *********/
-
-static int stv680_newframe (struct usb_stv *stv680, int framenr)
-{
- int errors = 0;
-
- while (stv680->streaming && (stv680->frame[framenr].grabstate == FRAME_READY || stv680->frame[framenr].grabstate == FRAME_GRABBING)) {
- if (!stv680->frame[framenr].curpix) {
- errors++;
- }
- wait_event_interruptible (stv680->wq, (stv680->scratch[stv680->scratch_use].state == BUFFER_READY));
-
- if (stv680->nullpackets > STV680_MAX_NULLPACKETS) {
- stv680->nullpackets = 0;
- PDEBUG (2, "STV(i): too many null length packets, restarting capture");
- stv680_stop_stream (stv680);
- stv680_start_stream (stv680);
- } else {
- if (stv680->scratch[stv680->scratch_use].state != BUFFER_READY) {
- stv680->frame[framenr].grabstate = FRAME_ERROR;
- PDEBUG (2, "STV(e): FRAME_ERROR in _newframe");
- return -EIO;
- }
- stv680->scratch[stv680->scratch_use].state = BUFFER_BUSY;
-
- bayer_unshuffle (stv680, &stv680->scratch[stv680->scratch_use]);
-
- stv680->scratch[stv680->scratch_use].state = BUFFER_UNUSED;
- stv680->scratch_use++;
- if (stv680->scratch_use >= STV680_NUMSCRATCH)
- stv680->scratch_use = 0;
- if (errors > STV680_MAX_ERRORS) {
- errors = 0;
- PDEBUG (2, "STV(i): too many errors, restarting capture");
- stv680_stop_stream (stv680);
- stv680_start_stream (stv680);
- }
- } /* else */
- } /* while */
- return 0;
-}
-
-/*********************************************************************
- * Video4Linux
- *********************************************************************/
-
-static int stv_open(struct file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct usb_stv *stv680 = video_get_drvdata(dev);
- int err = 0;
-
- /* we are called with the BKL held */
- lock_kernel();
- stv680->user = 1;
- err = stv_init (stv680); /* main initialization routine for camera */
-
- if (err >= 0) {
- stv680->fbuf = rvmalloc (stv680->maxframesize * STV680_NUMFRAMES);
- if (!stv680->fbuf) {
- PDEBUG (0, "STV(e): Could not rvmalloc frame bufer");
- err = -ENOMEM;
- }
- file->private_data = dev;
- }
- if (err)
- stv680->user = 0;
- unlock_kernel();
-
- return err;
-}
-
-static int stv_close(struct file *file)
-{
- struct video_device *dev = file->private_data;
- struct usb_stv *stv680 = video_get_drvdata(dev);
- int i;
-
- for (i = 0; i < STV680_NUMFRAMES; i++)
- stv680->frame[i].grabstate = FRAME_UNUSED;
- if (stv680->streaming)
- stv680_stop_stream (stv680);
-
- if ((i = stv_stop_video (stv680)) < 0)
- PDEBUG (1, "STV(e): stop_video failed in stv_close");
-
- rvfree (stv680->fbuf, stv680->maxframesize * STV680_NUMFRAMES);
- stv680->user = 0;
-
- if (stv680->removed) {
- kfree(stv680);
- stv680 = NULL;
- PDEBUG (0, "STV(i): device unregistered");
- }
- file->private_data = NULL;
- return 0;
-}
-
-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);
-
- if (!stv680->udev)
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:{
- struct video_capability *b = arg;
-
- strcpy (b->name, stv680->camera_name);
- b->type = VID_TYPE_CAPTURE;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = stv680->maxwidth;
- b->maxheight = stv680->maxheight;
- b->minwidth = stv680->maxwidth / 2;
- b->minheight = stv680->maxheight / 2;
- return 0;
- }
- case VIDIOCGCHAN:{
- struct video_channel *v = arg;
-
- if (v->channel != 0)
- return -EINVAL;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- strcpy (v->name, "STV Camera");
- return 0;
- }
- case VIDIOCSCHAN:{
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGPICT:{
- struct video_picture *p = arg;
-
- stv680_get_pict (stv680, p);
- return 0;
- }
- case VIDIOCSPICT:{
- struct video_picture *p = arg;
-
- if (stv680_set_pict (stv680, p))
- return -EINVAL;
- return 0;
- }
- case VIDIOCSWIN:{
- struct video_window *vw = arg;
-
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->width != stv680->vwidth) {
- if (stv680_set_size (stv680, vw->width, vw->height)) {
- PDEBUG (2, "STV(e): failed (from user) set size in VIDIOCSWIN");
- return -EINVAL;
- }
- }
- return 0;
- }
- case VIDIOCGWIN:{
- struct video_window *vw = arg;
-
- vw->x = 0; /* FIXME */
- vw->y = 0;
- vw->chromakey = 0;
- vw->flags = 0;
- vw->clipcount = 0;
- vw->width = stv680->vwidth;
- vw->height = stv680->vheight;
- return 0;
- }
- case VIDIOCGMBUF:{
- struct video_mbuf *vm = arg;
- int i;
-
- memset (vm, 0, sizeof (*vm));
- vm->size = STV680_NUMFRAMES * stv680->maxframesize;
- vm->frames = STV680_NUMFRAMES;
- for (i = 0; i < STV680_NUMFRAMES; i++)
- vm->offsets[i] = stv680->maxframesize * i;
- return 0;
- }
- case VIDIOCMCAPTURE:{
- struct video_mmap *vm = arg;
-
- if (vm->format != STV_VIDEO_PALETTE) {
- PDEBUG (2, "STV(i): VIDIOCMCAPTURE vm.format (%i) != VIDEO_PALETTE (%i)",
- vm->format, STV_VIDEO_PALETTE);
- if ((vm->format == 3) && (swapRGB_on == 0)) {
- PDEBUG (2, "STV(i): VIDIOCMCAPTURE swapRGB is (auto) ON");
- /* this may fix those apps (e.g., xawtv) that want BGR */
- swapRGB = 1;
- }
- return -EINVAL;
- }
- if (vm->frame >= STV680_NUMFRAMES) {
- PDEBUG (2, "STV(e): VIDIOCMCAPTURE vm.frame > NUMFRAMES");
- return -EINVAL;
- }
- if ((stv680->frame[vm->frame].grabstate == FRAME_ERROR)
- || (stv680->frame[vm->frame].grabstate == FRAME_GRABBING)) {
- PDEBUG (2, "STV(e): VIDIOCMCAPTURE grabstate (%i) error",
- stv680->frame[vm->frame].grabstate);
- return -EBUSY;
- }
- /* Is this according to the v4l spec??? */
- if (stv680->vwidth != vm->width) {
- if (stv680_set_size (stv680, vm->width, vm->height)) {
- PDEBUG (2, "STV(e): VIDIOCMCAPTURE set_size failed");
- return -EINVAL;
- }
- }
- stv680->frame[vm->frame].grabstate = FRAME_READY;
-
- if (!stv680->streaming)
- stv680_start_stream (stv680);
-
- return 0;
- }
- case VIDIOCSYNC:{
- int *frame = arg;
- int ret = 0;
-
- if (*frame < 0 || *frame >= STV680_NUMFRAMES) {
- PDEBUG (2, "STV(e): Bad frame # in VIDIOCSYNC");
- return -EINVAL;
- }
- ret = stv680_newframe (stv680, *frame);
- stv680->frame[*frame].grabstate = FRAME_UNUSED;
- return ret;
- }
- case VIDIOCGFBUF:{
- struct video_buffer *vb = arg;
-
- memset (vb, 0, sizeof (*vb));
- return 0;
- }
- case VIDIOCKEY:
- return 0;
- case VIDIOCCAPTURE:
- {
- PDEBUG (2, "STV(e): VIDIOCCAPTURE failed");
- return -EINVAL;
- }
- case VIDIOCSFBUF:
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
- default:
- return -ENOIOCTLCMD;
- } /* end switch */
-
- return 0;
-}
-
-static long stv680_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(file, cmd, arg, stv680_do_ioctl);
-}
-
-static int stv680_mmap (struct file *file, struct vm_area_struct *vma)
-{
- struct video_device *dev = file->private_data;
- struct usb_stv *stv680 = video_get_drvdata(dev);
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long page, pos;
-
- mutex_lock(&stv680->lock);
-
- if (stv680->udev == NULL) {
- mutex_unlock(&stv680->lock);
- return -EIO;
- }
- if (size > (((STV680_NUMFRAMES * stv680->maxframesize) + PAGE_SIZE - 1)
- & ~(PAGE_SIZE - 1))) {
- mutex_unlock(&stv680->lock);
- return -EINVAL;
- }
- pos = (unsigned long) stv680->fbuf;
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED)) {
- mutex_unlock(&stv680->lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
- mutex_unlock(&stv680->lock);
-
- return 0;
-}
-
-static ssize_t stv680_read (struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct video_device *dev = file->private_data;
- unsigned long int realcount = count;
- int ret = 0;
- struct usb_stv *stv680 = video_get_drvdata(dev);
- unsigned long int i;
-
- if (STV680_NUMFRAMES != 2) {
- PDEBUG (0, "STV(e): STV680_NUMFRAMES needs to be 2!");
- return -1;
- }
- if (stv680->udev == NULL)
- return -EIO;
- if (realcount > (stv680->vwidth * stv680->vheight * 3))
- realcount = stv680->vwidth * stv680->vheight * 3;
-
- /* Shouldn't happen: */
- if (stv680->frame[0].grabstate == FRAME_GRABBING) {
- PDEBUG (2, "STV(e): FRAME_GRABBING in stv680_read");
- return -EBUSY;
- }
- stv680->frame[0].grabstate = FRAME_READY;
- stv680->frame[1].grabstate = FRAME_UNUSED;
- stv680->curframe = 0;
-
- if (!stv680->streaming)
- stv680_start_stream (stv680);
-
- if (!stv680->streaming) {
- ret = stv680_newframe (stv680, 0); /* ret should = 0 */
- }
-
- ret = stv680_newframe (stv680, 0);
-
- if (!ret) {
- if ((i = copy_to_user (buf, stv680->frame[0].data, realcount)) != 0) {
- PDEBUG (2, "STV(e): copy_to_user frame 0 failed, ret count = %li", i);
- return -EFAULT;
- }
- } else {
- realcount = ret;
- }
- stv680->frame[0].grabstate = FRAME_UNUSED;
- return realcount;
-} /* stv680_read */
-
-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,
-};
-static struct video_device stv680_template = {
- .name = "STV0680 USB camera",
- .fops = &stv680_fops,
- .release = video_device_release,
-};
-
-static int stv680_probe (struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct usb_host_interface *interface;
- struct usb_stv *stv680 = NULL;
- char *camera_name = NULL;
- int retval = 0;
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1) {
- PDEBUG (0, "STV(e): Number of Configurations != 1");
- return -ENODEV;
- }
-
- interface = &intf->altsetting[0];
- /* Is it a STV680? */
- if ((le16_to_cpu(dev->descriptor.idVendor) == USB_PENCAM_VENDOR_ID) &&
- (le16_to_cpu(dev->descriptor.idProduct) == USB_PENCAM_PRODUCT_ID)) {
- camera_name = "STV0680";
- PDEBUG (0, "STV(i): STV0680 camera found.");
- } else if ((le16_to_cpu(dev->descriptor.idVendor) == USB_CREATIVEGOMINI_VENDOR_ID) &&
- (le16_to_cpu(dev->descriptor.idProduct) == USB_CREATIVEGOMINI_PRODUCT_ID)) {
- camera_name = "Creative WebCam Go Mini";
- PDEBUG (0, "STV(i): Creative WebCam Go Mini found.");
- } else {
- PDEBUG (0, "STV(e): Vendor/Product ID do not match STV0680 or Creative WebCam Go Mini values.");
- PDEBUG (0, "STV(e): Check that the STV0680 or Creative WebCam Go Mini camera is connected to the computer.");
- retval = -ENODEV;
- goto error;
- }
- /* We found one */
- if ((stv680 = kzalloc (sizeof (*stv680), GFP_KERNEL)) == NULL) {
- PDEBUG (0, "STV(e): couldn't kmalloc stv680 struct.");
- retval = -ENOMEM;
- goto error;
- }
-
- stv680->udev = dev;
- stv680->camera_name = camera_name;
-
- stv680->vdev = video_device_alloc();
- if (!stv680->vdev) {
- retval = -ENOMEM;
- goto error;
- }
- memcpy(stv680->vdev, &stv680_template, sizeof(stv680_template));
- stv680->vdev->parent = &intf->dev;
- video_set_drvdata(stv680->vdev, stv680);
-
- memcpy (stv680->vdev->name, stv680->camera_name, strlen (stv680->camera_name));
- init_waitqueue_head (&stv680->wq);
- mutex_init (&stv680->lock);
- wmb ();
-
- if (video_register_device(stv680->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- PDEBUG (0, "STV(e): video_register_device failed");
- retval = -EIO;
- goto error_vdev;
- }
- PDEBUG(0, "STV(i): registered new video device: %s",
- video_device_node_name(stv680->vdev));
-
- usb_set_intfdata (intf, stv680);
- retval = stv680_create_sysfs_files(stv680->vdev);
- if (retval)
- goto error_unreg;
- return 0;
-
-error_unreg:
- video_unregister_device(stv680->vdev);
-error_vdev:
- video_device_release(stv680->vdev);
-error:
- kfree(stv680);
- return retval;
-}
-
-static inline void usb_stv680_remove_disconnected (struct usb_stv *stv680)
-{
- int i;
-
- stv680->udev = NULL;
- stv680->frame[0].grabstate = FRAME_ERROR;
- stv680->frame[1].grabstate = FRAME_ERROR;
- stv680->streaming = 0;
-
- wake_up_interruptible (&stv680->wq);
-
- for (i = 0; i < STV680_NUMSBUF; i++)
- if (stv680->urb[i]) {
- usb_kill_urb (stv680->urb[i]);
- usb_free_urb (stv680->urb[i]);
- stv680->urb[i] = NULL;
- kfree(stv680->sbuf[i].data);
- }
- for (i = 0; i < STV680_NUMSCRATCH; i++)
- kfree(stv680->scratch[i].data);
- PDEBUG (0, "STV(i): %s disconnected", stv680->camera_name);
-
- /* Free the memory */
- kfree(stv680);
-}
-
-static void stv680_disconnect (struct usb_interface *intf)
-{
- struct usb_stv *stv680 = usb_get_intfdata (intf);
-
- usb_set_intfdata (intf, NULL);
-
- if (stv680) {
- /* We don't want people trying to open up the device */
- if (stv680->vdev) {
- stv680_remove_sysfs_files(stv680->vdev);
- video_unregister_device(stv680->vdev);
- stv680->vdev = NULL;
- }
- if (!stv680->user) {
- usb_stv680_remove_disconnected (stv680);
- } else {
- stv680->removed = 1;
- }
- }
-}
-
-static struct usb_driver stv680_driver = {
- .name = "stv680",
- .probe = stv680_probe,
- .disconnect = stv680_disconnect,
- .id_table = device_table
-};
-
-/********************************************************************
- * Module routines
- ********************************************************************/
-
-static int __init usb_stv680_init (void)
-{
- if (usb_register (&stv680_driver) < 0) {
- PDEBUG (0, "STV(e): Could not setup STV0680 driver");
- return -1;
- }
- PDEBUG (0, "STV(i): usb camera driver version %s registering", DRIVER_VERSION);
-
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- return 0;
-}
-
-static void __exit usb_stv680_exit (void)
-{
- usb_deregister (&stv680_driver);
- PDEBUG (0, "STV(i): driver deregistered");
-}
-
-module_init (usb_stv680_init);
-module_exit (usb_stv680_exit);
diff --git a/drivers/media/video/stv680.h b/drivers/media/video/stv680.h
deleted file mode 100644
index a08f1b08a4b0..000000000000
--- a/drivers/media/video/stv680.h
+++ /dev/null
@@ -1,227 +0,0 @@
-/****************************************************************************
- *
- * Filename: stv680.h
- *
- * Description:
- * This is a USB driver for STV0680 based usb video cameras.
- *
- * 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.
- *
- ****************************************************************************/
-
-/* size of usb transfers */
-#define STV680_PACKETSIZE 4096
-
-/* number of queued bulk transfers to use, may have problems if > 1 */
-#define STV680_NUMSBUF 1
-
-/* number of frames supported by the v4l part */
-#define STV680_NUMFRAMES 2
-
-/* scratch buffers for passing data to the decoders: 2 or 4 are good */
-#define STV680_NUMSCRATCH 2
-
-/* number of nul sized packets to receive before kicking the camera */
-#define STV680_MAX_NULLPACKETS 200
-
-/* number of decoding errors before kicking the camera */
-#define STV680_MAX_ERRORS 100
-
-#define USB_PENCAM_VENDOR_ID 0x0553
-#define USB_PENCAM_PRODUCT_ID 0x0202
-
-#define USB_CREATIVEGOMINI_VENDOR_ID 0x041e
-#define USB_CREATIVEGOMINI_PRODUCT_ID 0x4007
-
-#define PENCAM_TIMEOUT 1000
-/* fmt 4 */
-#define STV_VIDEO_PALETTE VIDEO_PALETTE_RGB24
-
-static struct usb_device_id device_table[] = {
- {USB_DEVICE (USB_PENCAM_VENDOR_ID, USB_PENCAM_PRODUCT_ID)},
- {USB_DEVICE (USB_CREATIVEGOMINI_VENDOR_ID, USB_CREATIVEGOMINI_PRODUCT_ID)},
- {}
-};
-MODULE_DEVICE_TABLE (usb, device_table);
-
-struct stv680_sbuf {
- unsigned char *data;
-};
-
-enum {
- FRAME_UNUSED, /* Unused (no MCAPTURE) */
- FRAME_READY, /* Ready to start grabbing */
- FRAME_GRABBING, /* In the process of being grabbed into */
- FRAME_DONE, /* Finished grabbing, but not been synced yet */
- FRAME_ERROR, /* Something bad happened while processing */
-};
-
-enum {
- BUFFER_UNUSED,
- BUFFER_READY,
- BUFFER_BUSY,
- BUFFER_DONE,
-};
-
-/* raw camera data <- sbuf (urb transfer buf) */
-struct stv680_scratch {
- unsigned char *data;
- volatile int state;
- int offset;
- int length;
-};
-
-/* processed data for display ends up here, after bayer */
-struct stv680_frame {
- unsigned char *data; /* Frame buffer */
- volatile int grabstate; /* State of grabbing */
- unsigned char *curline;
- int curlinepix;
- int curpix;
-};
-
-/* this is almost the video structure uvd_t, with extra parameters for stv */
-struct usb_stv {
- struct video_device *vdev;
-
- struct usb_device *udev;
-
- unsigned char bulk_in_endpointAddr; /* __u8 the address of the bulk in endpoint */
- char *camera_name;
-
- unsigned int VideoMode; /* 0x0100 = VGA, 0x0000 = CIF, 0x0300 = QVGA */
- int SupportedModes;
- int CIF;
- int VGA;
- int QVGA;
- int cwidth; /* camera width */
- int cheight; /* camera height */
- int maxwidth; /* max video width */
- int maxheight; /* max video height */
- int vwidth; /* current width for video window */
- int vheight; /* current height for video window */
- unsigned long int rawbufsize;
- unsigned long int maxframesize; /* rawbufsize * 3 for RGB */
-
- int origGain;
- int origMode; /* original camera mode */
-
- struct mutex lock; /* to lock the structure */
- int user; /* user count for exclusive use */
- int removed; /* device disconnected */
- int streaming; /* Are we streaming video? */
- char *fbuf; /* Videodev buffer area */
- struct urb *urb[STV680_NUMSBUF]; /* # of queued bulk transfers */
- int curframe; /* Current receiving frame */
- struct stv680_frame frame[STV680_NUMFRAMES]; /* # frames supported by v4l part */
- int readcount;
- int framecount;
- int error;
- int dropped;
- int scratch_next;
- int scratch_use;
- int scratch_overflow;
- struct stv680_scratch scratch[STV680_NUMSCRATCH]; /* for decoders */
- struct stv680_sbuf sbuf[STV680_NUMSBUF];
-
- unsigned int brightness;
- unsigned int chgbright;
- unsigned int whiteness;
- unsigned int colour;
- unsigned int contrast;
- unsigned int hue;
- unsigned int palette;
- unsigned int depth; /* rgb24 in bits */
-
- wait_queue_head_t wq; /* Processes waiting */
-
- int nullpackets;
-};
-
-
-static const unsigned char red[256] = {
- 0, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
- 18, 18, 18, 18, 18, 18, 18, 25, 30, 35, 38, 42,
- 44, 47, 50, 53, 54, 57, 59, 61, 63, 65, 67, 69,
- 71, 71, 73, 75, 77, 78, 80, 81, 82, 84, 85, 87,
- 88, 89, 90, 91, 93, 94, 95, 97, 98, 98, 99, 101,
- 102, 103, 104, 105, 106, 107, 108, 109, 110, 111, 112, 113,
- 114, 115, 116, 116, 117, 118, 119, 120, 121, 122, 123, 124,
- 125, 125, 126, 127, 128, 129, 129, 130, 131, 132, 133, 134,
- 134, 135, 135, 136, 137, 138, 139, 140, 140, 141, 142, 143,
- 143, 143, 144, 145, 146, 147, 147, 148, 149, 150, 150, 151,
- 152, 152, 152, 153, 154, 154, 155, 156, 157, 157, 158, 159,
- 159, 160, 161, 161, 161, 162, 163, 163, 164, 165, 165, 166,
- 167, 167, 168, 168, 169, 170, 170, 170, 171, 171, 172, 173,
- 173, 174, 174, 175, 176, 176, 177, 178, 178, 179, 179, 179,
- 180, 180, 181, 181, 182, 183, 183, 184, 184, 185, 185, 186,
- 187, 187, 188, 188, 188, 188, 189, 190, 190, 191, 191, 192,
- 192, 193, 193, 194, 195, 195, 196, 196, 197, 197, 197, 197,
- 198, 198, 199, 199, 200, 201, 201, 202, 202, 203, 203, 204,
- 204, 205, 205, 206, 206, 206, 206, 207, 207, 208, 208, 209,
- 209, 210, 210, 211, 211, 212, 212, 213, 213, 214, 214, 215,
- 215, 215, 215, 216, 216, 217, 217, 218, 218, 218, 219, 219,
- 220, 220, 221, 221
-};
-
-static const unsigned char green[256] = {
- 0, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21,
- 21, 21, 21, 21, 21, 21, 21, 28, 34, 39, 43, 47,
- 50, 53, 56, 59, 61, 64, 66, 68, 71, 73, 75, 77,
- 79, 80, 82, 84, 86, 87, 89, 91, 92, 94, 95, 97,
- 98, 100, 101, 102, 104, 105, 106, 108, 109, 110, 111, 113,
- 114, 115, 116, 117, 118, 120, 121, 122, 123, 124, 125, 126,
- 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138,
- 139, 140, 141, 142, 143, 144, 144, 145, 146, 147, 148, 149,
- 150, 151, 151, 152, 153, 154, 155, 156, 156, 157, 158, 159,
- 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
- 169, 170, 170, 171, 172, 172, 173, 174, 175, 175, 176, 177,
- 177, 178, 179, 179, 180, 181, 182, 182, 183, 184, 184, 185,
- 186, 186, 187, 187, 188, 189, 189, 190, 191, 191, 192, 193,
- 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200,
- 201, 201, 202, 202, 203, 204, 204, 205, 205, 206, 206, 207,
- 208, 208, 209, 209, 210, 210, 211, 212, 212, 213, 213, 214,
- 214, 215, 215, 216, 217, 217, 218, 218, 219, 219, 220, 220,
- 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
- 227, 228, 228, 229, 229, 230, 230, 231, 231, 232, 232, 233,
- 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238, 239,
- 239, 240, 240, 241, 241, 242, 242, 243, 243, 243, 244, 244,
- 245, 245, 246, 246
-};
-
-static const unsigned char blue[256] = {
- 0, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
- 23, 23, 23, 23, 23, 23, 23, 30, 37, 42, 47, 51,
- 55, 58, 61, 64, 67, 70, 72, 74, 78, 80, 82, 84,
- 86, 88, 90, 92, 94, 95, 97, 100, 101, 103, 104, 106,
- 107, 110, 111, 112, 114, 115, 116, 118, 119, 121, 122, 124,
- 125, 126, 127, 128, 129, 132, 133, 134, 135, 136, 137, 138,
- 139, 140, 141, 143, 144, 145, 146, 147, 148, 149, 150, 151,
- 152, 154, 155, 156, 157, 158, 158, 159, 160, 161, 162, 163,
- 165, 166, 166, 167, 168, 169, 170, 171, 171, 172, 173, 174,
- 176, 176, 177, 178, 179, 180, 180, 181, 182, 183, 183, 184,
- 185, 187, 187, 188, 189, 189, 190, 191, 192, 192, 193, 194,
- 194, 195, 196, 196, 198, 199, 200, 200, 201, 202, 202, 203,
- 204, 204, 205, 205, 206, 207, 207, 209, 210, 210, 211, 212,
- 212, 213, 213, 214, 215, 215, 216, 217, 217, 218, 218, 220,
- 221, 221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227,
- 228, 228, 229, 229, 231, 231, 232, 233, 233, 234, 234, 235,
- 235, 236, 236, 237, 238, 238, 239, 239, 240, 240, 242, 242,
- 243, 243, 244, 244, 245, 246, 246, 247, 247, 248, 248, 249,
- 249, 250, 250, 251, 251, 253, 253, 254, 254, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
- 255, 255, 255, 255
-};
diff --git a/drivers/media/video/tcm825x.c b/drivers/media/video/tcm825x.c
index b90e9da3167d..54681a535822 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -850,7 +850,6 @@ static int tcm825x_probe(struct i2c_client *client,
const struct i2c_device_id *did)
{
struct tcm825x_sensor *sensor = &tcm825x;
- int rval;
if (i2c_get_clientdata(client))
return -EBUSY;
@@ -871,11 +870,7 @@ static int tcm825x_probe(struct i2c_client *client,
sensor->pix.height = tcm825x_sizes[QVGA].height;
sensor->pix.pixelformat = V4L2_PIX_FMT_RGB565;
- rval = v4l2_int_device_register(sensor->v4l2_int_device);
- if (rval)
- i2c_set_clientdata(client, NULL);
-
- return rval;
+ return v4l2_int_device_register(sensor->v4l2_int_device);
}
static int tcm825x_remove(struct i2c_client *client)
@@ -886,7 +881,6 @@ static int tcm825x_remove(struct i2c_client *client)
return -ENODEV; /* our client isn't attached */
v4l2_int_device_unregister(sensor->v4l2_int_device);
- i2c_set_clientdata(client, NULL);
return 0;
}
diff --git a/drivers/media/video/tda7432.c b/drivers/media/video/tda7432.c
index 80f1cee23fa5..3941f954daf4 100644
--- a/drivers/media/video/tda7432.c
+++ b/drivers/media/video/tda7432.c
@@ -36,7 +36,6 @@
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
#include <media/i2c-addr.h>
-#include <media/v4l2-i2c-drv.h>
#ifndef VIDEO_AUDIO_BALANCE
# define VIDEO_AUDIO_BALANCE 32
@@ -472,9 +471,25 @@ static const struct i2c_device_id tda7432_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tda7432_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tda7432",
- .probe = tda7432_probe,
- .remove = tda7432_remove,
- .id_table = tda7432_id,
+static struct i2c_driver tda7432_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tda7432",
+ },
+ .probe = tda7432_probe,
+ .remove = tda7432_remove,
+ .id_table = tda7432_id,
};
+
+static __init int init_tda7432(void)
+{
+ return i2c_add_driver(&tda7432_driver);
+}
+
+static __exit void exit_tda7432(void)
+{
+ i2c_del_driver(&tda7432_driver);
+}
+
+module_init(init_tda7432);
+module_exit(exit_tda7432);
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index 92d22d8931c1..5d4cf3b3d435 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -32,7 +32,6 @@
#include <linux/i2c.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
MODULE_DESCRIPTION("tda9840 driver");
@@ -199,9 +198,25 @@ static const struct i2c_device_id tda9840_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tda9840_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tda9840",
- .probe = tda9840_probe,
- .remove = tda9840_remove,
- .id_table = tda9840_id,
+static struct i2c_driver tda9840_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tda9840",
+ },
+ .probe = tda9840_probe,
+ .remove = tda9840_remove,
+ .id_table = tda9840_id,
};
+
+static __init int init_tda9840(void)
+{
+ return i2c_add_driver(&tda9840_driver);
+}
+
+static __exit void exit_tda9840(void)
+{
+ i2c_del_driver(&tda9840_driver);
+}
+
+module_init(init_tda9840);
+module_exit(exit_tda9840);
diff --git a/drivers/media/video/tda9875.c b/drivers/media/video/tda9875.c
deleted file mode 100644
index 24e2b7d2ae58..000000000000
--- a/drivers/media/video/tda9875.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * For the TDA9875 chip
- * (The TDA9875 is used on the Diamond DTV2000 french version
- * Other cards probably use these chips as well.)
- * This driver will not complain if used with any
- * other i2c device with the same address.
- *
- * Copyright (c) 2000 Guillaume Delvit based on Gerd Knorr source and
- * Eric Sandeen
- * Copyright (c) 2006 Mauro Carvalho Chehab <mchehab@infradead.org>
- * This code is placed under the terms of the GNU General Public License
- * Based on tda9855.c by Steve VanDeBogart (vandebo@uclink.berkeley.edu)
- * Which was based on tda8425.c by Greg Alexander (c) 1998
- *
- * OPTIONS:
- * debug - set to 1 if you'd like to see debug messages
- *
- * Revision: 0.1 - original version
- */
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/timer.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/i2c.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
-#include <media/i2c-addr.h>
-
-static int debug; /* insmod parameter */
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_LICENSE("GPL");
-
-
-/* This is a superset of the TDA9875 */
-struct tda9875 {
- struct v4l2_subdev sd;
- int rvol, lvol;
- int bass, treble;
-};
-
-static inline struct tda9875 *to_state(struct v4l2_subdev *sd)
-{
- return container_of(sd, struct tda9875, sd);
-}
-
-#define dprintk if (debug) printk
-
-/* The TDA9875 is made by Philips Semiconductor
- * http://www.semiconductors.philips.com
- * TDA9875: I2C-bus controlled DSP audio processor, FM demodulator
- *
- */
-
- /* subaddresses for TDA9875 */
-#define TDA9875_MUT 0x12 /*General mute (value --> 0b11001100*/
-#define TDA9875_CFG 0x01 /* Config register (value --> 0b00000000 */
-#define TDA9875_DACOS 0x13 /*DAC i/o select (ADC) 0b0000100*/
-#define TDA9875_LOSR 0x16 /*Line output select regirter 0b0100 0001*/
-
-#define TDA9875_CH1V 0x0c /*Channel 1 volume (mute)*/
-#define TDA9875_CH2V 0x0d /*Channel 2 volume (mute)*/
-#define TDA9875_SC1 0x14 /*SCART 1 in (mono)*/
-#define TDA9875_SC2 0x15 /*SCART 2 in (mono)*/
-
-#define TDA9875_ADCIS 0x17 /*ADC input select (mono) 0b0110 000*/
-#define TDA9875_AER 0x19 /*Audio effect (AVL+Pseudo) 0b0000 0110*/
-#define TDA9875_MCS 0x18 /*Main channel select (DAC) 0b0000100*/
-#define TDA9875_MVL 0x1a /* Main volume gauche */
-#define TDA9875_MVR 0x1b /* Main volume droite */
-#define TDA9875_MBA 0x1d /* Main Basse */
-#define TDA9875_MTR 0x1e /* Main treble */
-#define TDA9875_ACS 0x1f /* Auxilary channel select (FM) 0b0000000*/
-#define TDA9875_AVL 0x20 /* Auxilary volume gauche */
-#define TDA9875_AVR 0x21 /* Auxilary volume droite */
-#define TDA9875_ABA 0x22 /* Auxilary Basse */
-#define TDA9875_ATR 0x23 /* Auxilary treble */
-
-#define TDA9875_MSR 0x02 /* Monitor select register */
-#define TDA9875_C1MSB 0x03 /* Carrier 1 (FM) frequency register MSB */
-#define TDA9875_C1MIB 0x04 /* Carrier 1 (FM) frequency register (16-8]b */
-#define TDA9875_C1LSB 0x05 /* Carrier 1 (FM) frequency register LSB */
-#define TDA9875_C2MSB 0x06 /* Carrier 2 (nicam) frequency register MSB */
-#define TDA9875_C2MIB 0x07 /* Carrier 2 (nicam) frequency register (16-8]b */
-#define TDA9875_C2LSB 0x08 /* Carrier 2 (nicam) frequency register LSB */
-#define TDA9875_DCR 0x09 /* Demodulateur configuration regirter*/
-#define TDA9875_DEEM 0x0a /* FM de-emphasis regirter*/
-#define TDA9875_FMAT 0x0b /* FM Matrix regirter*/
-
-/* values */
-#define TDA9875_MUTE_ON 0xff /* general mute */
-#define TDA9875_MUTE_OFF 0xcc /* general no mute */
-
-
-
-/* Begin code */
-
-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];
-
- 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)) {
- v4l2_warn(sd, "I/O error, trying (write %d 0x%x)\n",
- subaddr, val);
- return -1;
- }
- return 0;
-}
-
-
-static int i2c_read_register(struct i2c_client *client, int addr, int reg)
-{
- unsigned char write[1];
- unsigned char read[1];
- struct i2c_msg msgs[2] = {
- { addr, 0, 1, write },
- { addr, I2C_M_RD, 1, read }
- };
-
- write[0] = reg;
-
- if (2 != i2c_transfer(client->adapter, msgs, 2)) {
- v4l_warn(client, "I/O error (read2)\n");
- return -1;
- }
- v4l_dbg(1, debug, client, "chip_read2: reg%d=0x%x\n", reg, read[0]);
- return read[0];
-}
-
-static void tda9875_set(struct v4l2_subdev *sd)
-{
- struct tda9875 *tda = to_state(sd);
- unsigned char a;
-
- 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(sd, TDA9875_MVL, a);
- a =tda->rvol & 0xff;
- tda9875_write(sd, TDA9875_MVR, a);
- a =tda->bass & 0xff;
- tda9875_write(sd, TDA9875_MBA, a);
- a =tda->treble & 0xff;
- tda9875_write(sd, TDA9875_MTR, a);
-}
-
-static void do_tda9875_init(struct v4l2_subdev *sd)
-{
- 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_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct tda9875 *t = to_state(sd);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- {
- int left = (t->lvol+84)*606;
- int right = (t->rvol+84)*606;
-
- ctrl->value=max(left,right);
- return 0;
- }
- case V4L2_CID_AUDIO_BALANCE:
- {
- int left = (t->lvol+84)*606;
- int right = (t->rvol+84)*606;
- int volume = max(left,right);
- int balance = (32768*min(left,right))/
- (volume ? volume : 1);
- ctrl->value=(left<right)?
- (65535-balance) : balance;
- return 0;
- }
- case V4L2_CID_AUDIO_BASS:
- ctrl->value = (t->bass+12)*2427; /* min -12 max +15 */
- return 0;
- case V4L2_CID_AUDIO_TREBLE:
- ctrl->value = (t->treble+12)*2730;/* min -12 max +12 */
- return 0;
- }
- return -EINVAL;
-}
-
-static int tda9875_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct tda9875 *t = to_state(sd);
- int chvol = 0, volume = 0, balance = 0, left, right;
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_VOLUME:
- left = (t->lvol+84)*606;
- right = (t->rvol+84)*606;
-
- volume = max(left,right);
- balance = (32768*min(left,right))/
- (volume ? volume : 1);
- balance =(left<right)?
- (65535-balance) : balance;
-
- volume = ctrl->value;
-
- chvol=1;
- break;
- case V4L2_CID_AUDIO_BALANCE:
- left = (t->lvol+84)*606;
- right = (t->rvol+84)*606;
-
- volume=max(left,right);
-
- balance = ctrl->value;
-
- chvol=1;
- break;
- case V4L2_CID_AUDIO_BASS:
- t->bass = ((ctrl->value/2400)-12) & 0xff;
- if (t->bass > 15)
- t->bass = 15;
- if (t->bass < -12)
- t->bass = -12 & 0xff;
- break;
- case V4L2_CID_AUDIO_TREBLE:
- t->treble = ((ctrl->value/2700)-12) & 0xff;
- if (t->treble > 12)
- t->treble = 12;
- if (t->treble < -12)
- t->treble = -12 & 0xff;
- break;
- default:
- return -EINVAL;
- }
-
- if (chvol) {
- left = (min(65536 - balance,32768) *
- volume) / 32768;
- right = (min(balance,32768) *
- volume) / 32768;
- t->lvol = ((left/606)-84) & 0xff;
- if (t->lvol > 24)
- t->lvol = 24;
- if (t->lvol < -84)
- t->lvol = -84 & 0xff;
-
- t->rvol = ((right/606)-84) & 0xff;
- if (t->rvol > 24)
- t->rvol = 24;
- if (t->rvol < -84)
- t->rvol = -84 & 0xff;
- }
-
- tda9875_set(sd);
- return 0;
-}
-
-static int tda9875_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- switch (qc->id) {
- case V4L2_CID_AUDIO_VOLUME:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 58880);
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- return v4l2_ctrl_query_fill(qc, 0, 65535, 65535 / 100, 32768);
- }
- return -EINVAL;
-}
-
-/* ----------------------------------------------------------------------- */
-
-static const struct v4l2_subdev_core_ops tda9875_core_ops = {
- .queryctrl = tda9875_queryctrl,
- .g_ctrl = tda9875_g_ctrl,
- .s_ctrl = tda9875_s_ctrl,
-};
-
-static const struct v4l2_subdev_ops tda9875_ops = {
- .core = &tda9875_core_ops,
-};
-
-/* ----------------------------------------------------------------------- */
-
-
-/* *********************** *
- * i2c interface functions *
- * *********************** */
-
-static int tda9875_checkit(struct i2c_client *client, int addr)
-{
- int dic, rev;
-
- 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 int tda9875_probe(struct i2c_client *client,
- const struct i2c_device_id *id)
-{
- 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;
-}
-
-static int tda9875_remove(struct i2c_client *client)
-{
- struct v4l2_subdev *sd = i2c_get_clientdata(client);
-
- do_tda9875_init(sd);
- v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
- return 0;
-}
-
-static const struct i2c_device_id tda9875_id[] = {
- { "tda9875", 0 },
- { }
-};
-MODULE_DEVICE_TABLE(i2c, tda9875_id);
-
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tda9875",
- .probe = tda9875_probe,
- .remove = tda9875_remove,
- .id_table = tda9875_id,
-};
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index 3021a1e6b7bb..19621ed523ec 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -34,7 +34,6 @@
#include <linux/i2c.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include "tea6415c.h"
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -149,7 +148,7 @@ static int tea6415c_probe(struct i2c_client *client,
/* let's see whether this adapter can support what we need */
if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_WRITE_BYTE))
- return 0;
+ return -EIO;
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
@@ -175,9 +174,25 @@ static const struct i2c_device_id tea6415c_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tea6415c_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tea6415c",
- .probe = tea6415c_probe,
- .remove = tea6415c_remove,
- .id_table = tea6415c_id,
+static struct i2c_driver tea6415c_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tea6415c",
+ },
+ .probe = tea6415c_probe,
+ .remove = tea6415c_remove,
+ .id_table = tea6415c_id,
};
+
+static __init int init_tea6415c(void)
+{
+ return i2c_add_driver(&tea6415c_driver);
+}
+
+static __exit void exit_tea6415c(void)
+{
+ i2c_del_driver(&tea6415c_driver);
+}
+
+module_init(init_tea6415c);
+module_exit(exit_tea6415c);
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 49dafc5e1e2f..5ea840401f21 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -34,7 +34,6 @@
#include <linux/i2c.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include "tea6420.h"
MODULE_AUTHOR("Michael Hunold <michael@mihu.de>");
@@ -157,9 +156,25 @@ static const struct i2c_device_id tea6420_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tea6420_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tea6420",
- .probe = tea6420_probe,
- .remove = tea6420_remove,
- .id_table = tea6420_id,
+static struct i2c_driver tea6420_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tea6420",
+ },
+ .probe = tea6420_probe,
+ .remove = tea6420_remove,
+ .id_table = tea6420_id,
};
+
+static __init int init_tea6420(void)
+{
+ return i2c_add_driver(&tea6420_driver);
+}
+
+static __exit void exit_tea6420(void)
+{
+ i2c_del_driver(&tea6420_driver);
+}
+
+module_init(init_tea6420);
+module_exit(exit_tea6420);
diff --git a/drivers/media/video/timblogiw.c b/drivers/media/video/timblogiw.c
new file mode 100644
index 000000000000..fc611ebeb82c
--- /dev/null
+++ b/drivers/media/video/timblogiw.c
@@ -0,0 +1,893 @@
+/*
+ * timblogiw.c timberdale FPGA LogiWin Video In driver
+ * Copyright (c) 2009-2010 Intel Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* Supports:
+ * Timberdale FPGA LogiWin Video In
+ */
+
+#include <linux/version.h>
+#include <linux/platform_device.h>
+#include <linux/slab.h>
+#include <linux/dmaengine.h>
+#include <linux/scatterlist.h>
+#include <linux/interrupt.h>
+#include <linux/list.h>
+#include <linux/i2c.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/videobuf-dma-contig.h>
+#include <media/timb_video.h>
+
+#define DRIVER_NAME "timb-video"
+
+#define TIMBLOGIWIN_NAME "Timberdale Video-In"
+#define TIMBLOGIW_VERSION_CODE 0x04
+
+#define TIMBLOGIW_LINES_PER_DESC 44
+#define TIMBLOGIW_MAX_VIDEO_MEM 16
+
+#define TIMBLOGIW_HAS_DECODER(lw) (lw->pdata.encoder.module_name)
+
+
+struct timblogiw {
+ struct video_device video_dev;
+ struct v4l2_device v4l2_dev; /* mutual exclusion */
+ struct mutex lock;
+ struct device *dev;
+ struct timb_video_platform_data pdata;
+ struct v4l2_subdev *sd_enc; /* encoder */
+ bool opened;
+};
+
+struct timblogiw_tvnorm {
+ v4l2_std_id std;
+ u16 width;
+ u16 height;
+ u8 fps;
+};
+
+struct timblogiw_fh {
+ struct videobuf_queue vb_vidq;
+ struct timblogiw_tvnorm const *cur_norm;
+ struct list_head capture;
+ struct dma_chan *chan;
+ spinlock_t queue_lock; /* mutual exclusion */
+ unsigned int frame_count;
+};
+
+struct timblogiw_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+ struct scatterlist sg[16];
+ dma_cookie_t cookie;
+ struct timblogiw_fh *fh;
+};
+
+const struct timblogiw_tvnorm timblogiw_tvnorms[] = {
+ {
+ .std = V4L2_STD_PAL,
+ .width = 720,
+ .height = 576,
+ .fps = 25
+ },
+ {
+ .std = V4L2_STD_NTSC,
+ .width = 720,
+ .height = 480,
+ .fps = 30
+ }
+};
+
+static int timblogiw_bytes_per_line(const struct timblogiw_tvnorm *norm)
+{
+ return norm->width * 2;
+}
+
+
+static int timblogiw_frame_size(const struct timblogiw_tvnorm *norm)
+{
+ return norm->height * timblogiw_bytes_per_line(norm);
+}
+
+static const struct timblogiw_tvnorm *timblogiw_get_norm(const v4l2_std_id std)
+{
+ int i;
+ for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++)
+ if (timblogiw_tvnorms[i].std & std)
+ return timblogiw_tvnorms + i;
+
+ /* default to first element */
+ return timblogiw_tvnorms;
+}
+
+static void timblogiw_dma_cb(void *data)
+{
+ struct timblogiw_buffer *buf = data;
+ struct timblogiw_fh *fh = buf->fh;
+ struct videobuf_buffer *vb = &buf->vb;
+
+ spin_lock(&fh->queue_lock);
+
+ /* mark the transfer done */
+ buf->cookie = -1;
+
+ fh->frame_count++;
+
+ if (vb->state != VIDEOBUF_ERROR) {
+ list_del(&vb->queue);
+ do_gettimeofday(&vb->ts);
+ vb->field_count = fh->frame_count * 2;
+ vb->state = VIDEOBUF_DONE;
+
+ wake_up(&vb->done);
+ }
+
+ if (!list_empty(&fh->capture)) {
+ vb = list_entry(fh->capture.next, struct videobuf_buffer,
+ queue);
+ vb->state = VIDEOBUF_ACTIVE;
+ }
+
+ spin_unlock(&fh->queue_lock);
+}
+
+static bool timblogiw_dma_filter_fn(struct dma_chan *chan, void *filter_param)
+{
+ return chan->chan_id == (uintptr_t)filter_param;
+}
+
+/* IOCTL functions */
+
+static int timblogiw_g_fmt(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s entry\n", __func__);
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&lw->lock);
+
+ format->fmt.pix.width = fh->cur_norm->width;
+ format->fmt.pix.height = fh->cur_norm->height;
+ format->fmt.pix.pixelformat = V4L2_PIX_FMT_UYVY;
+ format->fmt.pix.bytesperline = timblogiw_bytes_per_line(fh->cur_norm);
+ format->fmt.pix.sizeimage = timblogiw_frame_size(fh->cur_norm);
+ format->fmt.pix.field = V4L2_FIELD_NONE;
+
+ mutex_unlock(&lw->lock);
+
+ return 0;
+}
+
+static int timblogiw_try_fmt(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct v4l2_pix_format *pix = &format->fmt.pix;
+
+ dev_dbg(&vdev->dev,
+ "%s - width=%d, height=%d, pixelformat=%d, field=%d\n"
+ "bytes per line %d, size image: %d, colorspace: %d\n",
+ __func__,
+ pix->width, pix->height, pix->pixelformat, pix->field,
+ pix->bytesperline, pix->sizeimage, pix->colorspace);
+
+ if (format->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (pix->field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ if (pix->pixelformat != V4L2_PIX_FMT_UYVY)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int timblogiw_s_fmt(struct file *file, void *priv,
+ struct v4l2_format *format)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = priv;
+ struct v4l2_pix_format *pix = &format->fmt.pix;
+ int err;
+
+ mutex_lock(&lw->lock);
+
+ err = timblogiw_try_fmt(file, priv, format);
+ if (err)
+ goto out;
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ dev_err(&vdev->dev, "%s queue busy\n", __func__);
+ err = -EBUSY;
+ goto out;
+ }
+
+ pix->width = fh->cur_norm->width;
+ pix->height = fh->cur_norm->height;
+
+out:
+ mutex_unlock(&lw->lock);
+ return err;
+}
+
+static int timblogiw_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+ memset(cap, 0, sizeof(*cap));
+ strncpy(cap->card, TIMBLOGIWIN_NAME, sizeof(cap->card)-1);
+ strncpy(cap->driver, DRIVER_NAME, sizeof(cap->driver) - 1);
+ strlcpy(cap->bus_info, vdev->name, sizeof(cap->bus_info));
+ cap->version = TIMBLOGIW_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING |
+ V4L2_CAP_READWRITE;
+
+ return 0;
+}
+
+static int timblogiw_enum_fmt(struct file *file, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ dev_dbg(&vdev->dev, "%s, index: %d\n", __func__, fmt->index);
+
+ if (fmt->index != 0)
+ return -EINVAL;
+ memset(fmt, 0, sizeof(*fmt));
+ fmt->index = 0;
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ strncpy(fmt->description, "4:2:2, packed, YUYV",
+ sizeof(fmt->description)-1);
+ fmt->pixelformat = V4L2_PIX_FMT_UYVY;
+
+ return 0;
+}
+
+static int timblogiw_g_parm(struct file *file, void *priv,
+ struct v4l2_streamparm *sp)
+{
+ struct timblogiw_fh *fh = priv;
+ struct v4l2_captureparm *cp = &sp->parm.capture;
+
+ cp->capability = V4L2_CAP_TIMEPERFRAME;
+ cp->timeperframe.numerator = 1;
+ cp->timeperframe.denominator = fh->cur_norm->fps;
+
+ return 0;
+}
+
+static int timblogiw_reqbufs(struct file *file, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_reqbufs(&fh->vb_vidq, rb);
+}
+
+static int timblogiw_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_querybuf(&fh->vb_vidq, b);
+}
+
+static int timblogiw_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_qbuf(&fh->vb_vidq, b);
+}
+
+static int timblogiw_dqbuf(struct file *file, void *priv,
+ struct v4l2_buffer *b)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_dqbuf(&fh->vb_vidq, b, file->f_flags & O_NONBLOCK);
+}
+
+static int timblogiw_g_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ *std = fh->cur_norm->std;
+ return 0;
+}
+
+static int timblogiw_s_std(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = priv;
+ int err = 0;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ mutex_lock(&lw->lock);
+
+ if (TIMBLOGIW_HAS_DECODER(lw))
+ err = v4l2_subdev_call(lw->sd_enc, core, s_std, *std);
+
+ if (!err)
+ fh->cur_norm = timblogiw_get_norm(*std);
+
+ mutex_unlock(&lw->lock);
+
+ return err;
+}
+
+static int timblogiw_enuminput(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ struct video_device *vdev = video_devdata(file);
+ int i;
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->index = 0;
+
+ strncpy(inp->name, "Timb input 1", sizeof(inp->name) - 1);
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+
+ inp->std = 0;
+ for (i = 0; i < ARRAY_SIZE(timblogiw_tvnorms); i++)
+ inp->std |= timblogiw_tvnorms[i].std;
+
+ return 0;
+}
+
+static int timblogiw_g_input(struct file *file, void *priv,
+ unsigned int *input)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+
+ *input = 0;
+
+ return 0;
+}
+
+static int timblogiw_s_input(struct file *file, void *priv, unsigned int input)
+{
+ struct video_device *vdev = video_devdata(file);
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+
+ if (input != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int timblogiw_streamon(struct file *file, void *priv, unsigned int type)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ dev_dbg(&vdev->dev, "%s - No capture device\n", __func__);
+ return -EINVAL;
+ }
+
+ fh->frame_count = 0;
+ return videobuf_streamon(&fh->vb_vidq);
+}
+
+static int timblogiw_streamoff(struct file *file, void *priv,
+ unsigned int type)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s entry\n", __func__);
+
+ if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ return videobuf_streamoff(&fh->vb_vidq);
+}
+
+static int timblogiw_querystd(struct file *file, void *priv, v4l2_std_id *std)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s entry\n", __func__);
+
+ if (TIMBLOGIW_HAS_DECODER(lw))
+ return v4l2_subdev_call(lw->sd_enc, video, querystd, std);
+ else {
+ *std = fh->cur_norm->std;
+ return 0;
+ }
+}
+
+static int timblogiw_enum_framesizes(struct file *file, void *priv,
+ struct v4l2_frmsizeenum *fsize)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = priv;
+
+ dev_dbg(&vdev->dev, "%s - index: %d, format: %d\n", __func__,
+ fsize->index, fsize->pixel_format);
+
+ if ((fsize->index != 0) ||
+ (fsize->pixel_format != V4L2_PIX_FMT_UYVY))
+ return -EINVAL;
+
+ fsize->type = V4L2_FRMSIZE_TYPE_DISCRETE;
+ fsize->discrete.width = fh->cur_norm->width;
+ fsize->discrete.height = fh->cur_norm->height;
+
+ return 0;
+}
+
+/* Video buffer functions */
+
+static int buffer_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct timblogiw_fh *fh = vq->priv_data;
+
+ *size = timblogiw_frame_size(fh->cur_norm);
+
+ if (!*count)
+ *count = 32;
+
+ while (*size * *count > TIMBLOGIW_MAX_VIDEO_MEM * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static int buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct timblogiw_fh *fh = vq->priv_data;
+ struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+ vb);
+ unsigned int data_size = timblogiw_frame_size(fh->cur_norm);
+ int err = 0;
+
+ if (vb->baddr && vb->bsize < data_size)
+ /* User provided buffer, but it is too small */
+ return -ENOMEM;
+
+ vb->size = data_size;
+ vb->width = fh->cur_norm->width;
+ vb->height = fh->cur_norm->height;
+ vb->field = field;
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ int i;
+ unsigned int size;
+ unsigned int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC *
+ timblogiw_bytes_per_line(fh->cur_norm);
+ dma_addr_t addr;
+
+ sg_init_table(buf->sg, ARRAY_SIZE(buf->sg));
+
+ err = videobuf_iolock(vq, vb, NULL);
+ if (err)
+ goto err;
+
+ addr = videobuf_to_dma_contig(vb);
+ for (i = 0, size = 0; size < data_size; i++) {
+ sg_dma_address(buf->sg + i) = addr + size;
+ size += bytes_per_desc;
+ sg_dma_len(buf->sg + i) = (size > data_size) ?
+ (bytes_per_desc - (size - data_size)) :
+ bytes_per_desc;
+ }
+
+ vb->state = VIDEOBUF_PREPARED;
+ buf->cookie = -1;
+ buf->fh = fh;
+ }
+
+ return 0;
+
+err:
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ return err;
+}
+
+static void buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct timblogiw_fh *fh = vq->priv_data;
+ struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+ vb);
+ struct dma_async_tx_descriptor *desc;
+ int sg_elems;
+ int bytes_per_desc = TIMBLOGIW_LINES_PER_DESC *
+ timblogiw_bytes_per_line(fh->cur_norm);
+
+ sg_elems = timblogiw_frame_size(fh->cur_norm) / bytes_per_desc;
+ sg_elems +=
+ (timblogiw_frame_size(fh->cur_norm) % bytes_per_desc) ? 1 : 0;
+
+ if (list_empty(&fh->capture))
+ vb->state = VIDEOBUF_ACTIVE;
+ else
+ vb->state = VIDEOBUF_QUEUED;
+
+ list_add_tail(&vb->queue, &fh->capture);
+
+ spin_unlock_irq(&fh->queue_lock);
+
+ desc = fh->chan->device->device_prep_slave_sg(fh->chan,
+ buf->sg, sg_elems, DMA_FROM_DEVICE,
+ DMA_PREP_INTERRUPT | DMA_COMPL_SKIP_SRC_UNMAP);
+ if (!desc) {
+ spin_lock_irq(&fh->queue_lock);
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_PREPARED;
+ return;
+ }
+
+ desc->callback_param = buf;
+ desc->callback = timblogiw_dma_cb;
+
+ buf->cookie = desc->tx_submit(desc);
+
+ spin_lock_irq(&fh->queue_lock);
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct timblogiw_fh *fh = vq->priv_data;
+ struct timblogiw_buffer *buf = container_of(vb, struct timblogiw_buffer,
+ vb);
+
+ videobuf_waiton(vq, vb, 0, 0);
+ if (buf->cookie >= 0)
+ dma_sync_wait(fh->chan, buf->cookie);
+
+ videobuf_dma_contig_free(vq, vb);
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static struct videobuf_queue_ops timblogiw_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/* Device Operations functions */
+
+static int timblogiw_open(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh;
+ v4l2_std_id std;
+ dma_cap_mask_t mask;
+ int err = 0;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ mutex_lock(&lw->lock);
+ if (lw->opened) {
+ err = -EBUSY;
+ goto out;
+ }
+
+ if (TIMBLOGIW_HAS_DECODER(lw) && !lw->sd_enc) {
+ struct i2c_adapter *adapt;
+
+ /* find the video decoder */
+ adapt = i2c_get_adapter(lw->pdata.i2c_adapter);
+ if (!adapt) {
+ dev_err(&vdev->dev, "No I2C bus #%d\n",
+ lw->pdata.i2c_adapter);
+ err = -ENODEV;
+ goto out;
+ }
+
+ /* now find the encoder */
+ lw->sd_enc = v4l2_i2c_new_subdev_board(&lw->v4l2_dev, adapt,
+ lw->pdata.encoder.info, NULL);
+
+ i2c_put_adapter(adapt);
+
+ if (!lw->sd_enc) {
+ dev_err(&vdev->dev, "Failed to get encoder: %s\n",
+ lw->pdata.encoder.module_name);
+ err = -ENODEV;
+ goto out;
+ }
+ }
+
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (!fh) {
+ err = -ENOMEM;
+ goto out;
+ }
+
+ fh->cur_norm = timblogiw_tvnorms;
+ timblogiw_querystd(file, fh, &std);
+ fh->cur_norm = timblogiw_get_norm(std);
+
+ INIT_LIST_HEAD(&fh->capture);
+ spin_lock_init(&fh->queue_lock);
+
+ dma_cap_zero(mask);
+ dma_cap_set(DMA_SLAVE, mask);
+ dma_cap_set(DMA_PRIVATE, mask);
+
+ /* find the DMA channel */
+ fh->chan = dma_request_channel(mask, timblogiw_dma_filter_fn,
+ (void *)(uintptr_t)lw->pdata.dma_channel);
+ if (!fh->chan) {
+ dev_err(&vdev->dev, "Failed to get DMA channel\n");
+ kfree(fh);
+ err = -ENODEV;
+ goto out;
+ }
+
+ file->private_data = fh;
+ videobuf_queue_dma_contig_init(&fh->vb_vidq,
+ &timblogiw_video_qops, lw->dev, &fh->queue_lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct timblogiw_buffer), fh, NULL);
+
+ lw->opened = true;
+out:
+ mutex_unlock(&lw->lock);
+
+ return err;
+}
+
+static int timblogiw_close(struct file *file)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw *lw = video_get_drvdata(vdev);
+ struct timblogiw_fh *fh = file->private_data;
+
+ dev_dbg(&vdev->dev, "%s: Entry\n", __func__);
+
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
+
+ dma_release_channel(fh->chan);
+
+ kfree(fh);
+
+ mutex_lock(&lw->lock);
+ lw->opened = false;
+ mutex_unlock(&lw->lock);
+ return 0;
+}
+
+static ssize_t timblogiw_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = file->private_data;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_read_stream(&fh->vb_vidq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int timblogiw_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = file->private_data;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_poll_stream(file, &fh->vb_vidq, wait);
+}
+
+static int timblogiw_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct video_device *vdev = video_devdata(file);
+ struct timblogiw_fh *fh = file->private_data;
+
+ dev_dbg(&vdev->dev, "%s: entry\n", __func__);
+
+ return videobuf_mmap_mapper(&fh->vb_vidq, vma);
+}
+
+/* Platform device functions */
+
+static __devinitconst struct v4l2_ioctl_ops timblogiw_ioctl_ops = {
+ .vidioc_querycap = timblogiw_querycap,
+ .vidioc_enum_fmt_vid_cap = timblogiw_enum_fmt,
+ .vidioc_g_fmt_vid_cap = timblogiw_g_fmt,
+ .vidioc_try_fmt_vid_cap = timblogiw_try_fmt,
+ .vidioc_s_fmt_vid_cap = timblogiw_s_fmt,
+ .vidioc_g_parm = timblogiw_g_parm,
+ .vidioc_reqbufs = timblogiw_reqbufs,
+ .vidioc_querybuf = timblogiw_querybuf,
+ .vidioc_qbuf = timblogiw_qbuf,
+ .vidioc_dqbuf = timblogiw_dqbuf,
+ .vidioc_g_std = timblogiw_g_std,
+ .vidioc_s_std = timblogiw_s_std,
+ .vidioc_enum_input = timblogiw_enuminput,
+ .vidioc_g_input = timblogiw_g_input,
+ .vidioc_s_input = timblogiw_s_input,
+ .vidioc_streamon = timblogiw_streamon,
+ .vidioc_streamoff = timblogiw_streamoff,
+ .vidioc_querystd = timblogiw_querystd,
+ .vidioc_enum_framesizes = timblogiw_enum_framesizes,
+};
+
+static __devinitconst struct v4l2_file_operations timblogiw_fops = {
+ .owner = THIS_MODULE,
+ .open = timblogiw_open,
+ .release = timblogiw_close,
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .mmap = timblogiw_mmap,
+ .read = timblogiw_read,
+ .poll = timblogiw_poll,
+};
+
+static __devinitconst struct video_device timblogiw_template = {
+ .name = TIMBLOGIWIN_NAME,
+ .fops = &timblogiw_fops,
+ .ioctl_ops = &timblogiw_ioctl_ops,
+ .release = video_device_release_empty,
+ .minor = -1,
+ .tvnorms = V4L2_STD_PAL | V4L2_STD_NTSC
+};
+
+static int __devinit timblogiw_probe(struct platform_device *pdev)
+{
+ int err;
+ struct timblogiw *lw = NULL;
+ struct timb_video_platform_data *pdata = pdev->dev.platform_data;
+
+ if (!pdata) {
+ dev_err(&pdev->dev, "No platform data\n");
+ err = -EINVAL;
+ goto err;
+ }
+
+ if (!pdata->encoder.module_name)
+ dev_info(&pdev->dev, "Running without decoder\n");
+
+ lw = kzalloc(sizeof(*lw), GFP_KERNEL);
+ if (!lw) {
+ err = -ENOMEM;
+ goto err;
+ }
+
+ if (pdev->dev.parent)
+ lw->dev = pdev->dev.parent;
+ else
+ lw->dev = &pdev->dev;
+
+ memcpy(&lw->pdata, pdata, sizeof(lw->pdata));
+
+ mutex_init(&lw->lock);
+
+ lw->video_dev = timblogiw_template;
+
+ strlcpy(lw->v4l2_dev.name, DRIVER_NAME, sizeof(lw->v4l2_dev.name));
+ err = v4l2_device_register(NULL, &lw->v4l2_dev);
+ if (err)
+ goto err_register;
+
+ lw->video_dev.v4l2_dev = &lw->v4l2_dev;
+
+ platform_set_drvdata(pdev, lw);
+ video_set_drvdata(&lw->video_dev, lw);
+
+ err = video_register_device(&lw->video_dev, VFL_TYPE_GRABBER, 0);
+ if (err) {
+ dev_err(&pdev->dev, "Error reg video: %d\n", err);
+ goto err_request;
+ }
+
+
+ return 0;
+
+err_request:
+ platform_set_drvdata(pdev, NULL);
+ v4l2_device_unregister(&lw->v4l2_dev);
+err_register:
+ kfree(lw);
+err:
+ dev_err(&pdev->dev, "Failed to register: %d\n", err);
+
+ return err;
+}
+
+static int __devexit timblogiw_remove(struct platform_device *pdev)
+{
+ struct timblogiw *lw = platform_get_drvdata(pdev);
+
+ video_unregister_device(&lw->video_dev);
+
+ v4l2_device_unregister(&lw->v4l2_dev);
+
+ kfree(lw);
+
+ platform_set_drvdata(pdev, NULL);
+
+ return 0;
+}
+
+static struct platform_driver timblogiw_platform_driver = {
+ .driver = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ },
+ .probe = timblogiw_probe,
+ .remove = __devexit_p(timblogiw_remove),
+};
+
+/* Module functions */
+
+static int __init timblogiw_init(void)
+{
+ return platform_driver_register(&timblogiw_platform_driver);
+}
+
+static void __exit timblogiw_exit(void)
+{
+ platform_driver_unregister(&timblogiw_platform_driver);
+}
+
+module_init(timblogiw_init);
+module_exit(timblogiw_exit);
+
+MODULE_DESCRIPTION(TIMBLOGIWIN_NAME);
+MODULE_AUTHOR("Pelagicore AB <info@pelagicore.com>");
+MODULE_LICENSE("GPL v2");
+MODULE_ALIAS("platform:"DRIVER_NAME);
diff --git a/drivers/media/video/tlg2300/Kconfig b/drivers/media/video/tlg2300/Kconfig
index 2c29ec659b4e..645d915267e6 100644
--- a/drivers/media/video/tlg2300/Kconfig
+++ b/drivers/media/video/tlg2300/Kconfig
@@ -1,9 +1,9 @@
config VIDEO_TLG2300
tristate "Telegent TLG2300 USB video capture support"
- depends on VIDEO_DEV && I2C && INPUT && SND && DVB_CORE
+ depends on VIDEO_DEV && I2C && SND && DVB_CORE
select VIDEO_TUNER
select VIDEO_TVEEPROM
- select VIDEO_IR
+ depends on RC_CORE
select VIDEOBUF_VMALLOC
select SND_PCM
select VIDEOBUF_DVB
diff --git a/drivers/media/video/tlg2300/pd-main.c b/drivers/media/video/tlg2300/pd-main.c
index 256cc558ba13..99c81a9a4f46 100644
--- a/drivers/media/video/tlg2300/pd-main.c
+++ b/drivers/media/video/tlg2300/pd-main.c
@@ -36,7 +36,6 @@
#include <linux/string.h>
#include <linux/types.h>
#include <linux/firmware.h>
-#include <linux/smp_lock.h>
#include "vendorcmds.h"
#include "pd-common.h"
@@ -227,12 +226,11 @@ static int firmware_download(struct usb_device *udev)
fwlength = fw->size;
- fwbuf = kzalloc(fwlength, GFP_KERNEL);
+ fwbuf = kmemdup(fw->data, fwlength, GFP_KERNEL);
if (!fwbuf) {
ret = -ENOMEM;
goto out;
}
- memcpy(fwbuf, fw->data, fwlength);
max_packet_size = udev->ep_out[0x1]->desc.wMaxPacketSize;
log("\t\t download size : %d", (int)max_packet_size);
@@ -454,7 +452,8 @@ static int poseidon_probe(struct usb_interface *interface,
device_init_wakeup(&udev->dev, 1);
#ifdef CONFIG_PM
- pd->udev->autosuspend_delay = HZ * PM_SUSPEND_DELAY;
+ pm_runtime_set_autosuspend_delay(&pd->udev->dev,
+ 1000 * PM_SUSPEND_DELAY);
usb_enable_autosuspend(pd->udev);
if (in_hibernation(pd)) {
@@ -486,15 +485,11 @@ static void poseidon_disconnect(struct usb_interface *interface)
/*unregister v4l2 device */
v4l2_device_unregister(&pd->v4l2_dev);
- lock_kernel();
- {
- pd_dvb_usb_device_exit(pd);
- poseidon_fm_exit(pd);
+ pd_dvb_usb_device_exit(pd);
+ poseidon_fm_exit(pd);
- poseidon_audio_free(pd);
- pd_video_exit(pd);
- }
- unlock_kernel();
+ poseidon_audio_free(pd);
+ pd_video_exit(pd);
usb_set_intfdata(interface, NULL);
kref_put(&pd->kref, poseidon_delete);
diff --git a/drivers/media/video/tlg2300/pd-video.c b/drivers/media/video/tlg2300/pd-video.c
index d0cc012f7ae6..df33a1d188bb 100644
--- a/drivers/media/video/tlg2300/pd-video.c
+++ b/drivers/media/video/tlg2300/pd-video.c
@@ -512,19 +512,20 @@ int alloc_bulk_urbs_generic(struct urb **urb_array, int num,
int buf_size, gfp_t gfp_flags,
usb_complete_t complete_fn, void *context)
{
- struct urb *urb;
- void *mem;
- int i;
+ int i = 0;
- for (i = 0; i < num; i++) {
- urb = usb_alloc_urb(0, gfp_flags);
+ for (; i < num; i++) {
+ void *mem;
+ struct urb *urb = usb_alloc_urb(0, gfp_flags);
if (urb == NULL)
return i;
mem = usb_alloc_coherent(udev, buf_size, gfp_flags,
&urb->transfer_dma);
- if (mem == NULL)
+ if (mem == NULL) {
+ usb_free_urb(urb);
return i;
+ }
usb_fill_bulk_urb(urb, udev, usb_rcvbulkpipe(udev, ep_addr),
mem, buf_size, complete_fn, context);
@@ -1434,7 +1435,7 @@ static int pd_video_open(struct file *file)
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,/* video is interlacd */
sizeof(struct videobuf_buffer),/*it's enough*/
- front);
+ front, NULL);
} else if (vfd->vfl_type == VFL_TYPE_VBI
&& !(pd->state & POSEIDON_STATE_VBI)) {
front = kzalloc(sizeof(struct front_face), GFP_KERNEL);
@@ -1451,7 +1452,7 @@ static int pd_video_open(struct file *file)
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_NONE, /* vbi is NONE mode */
sizeof(struct videobuf_buffer),
- front);
+ front, NULL);
} else {
/* maybe add FM support here */
log("other ");
diff --git a/drivers/media/video/tlv320aic23b.c b/drivers/media/video/tlv320aic23b.c
index 9ddb32bc7af0..dfc4dd7c5097 100644
--- a/drivers/media/video/tlv320aic23b.c
+++ b/drivers/media/video/tlv320aic23b.c
@@ -29,10 +29,8 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("tlv320aic23b driver");
MODULE_AUTHOR("Scott Alfter, Ulf Eklund, Hans Verkuil");
@@ -199,9 +197,25 @@ static const struct i2c_device_id tlv320aic23b_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tlv320aic23b_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tlv320aic23b",
- .probe = tlv320aic23b_probe,
- .remove = tlv320aic23b_remove,
- .id_table = tlv320aic23b_id,
+static struct i2c_driver tlv320aic23b_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tlv320aic23b",
+ },
+ .probe = tlv320aic23b_probe,
+ .remove = tlv320aic23b_remove,
+ .id_table = tlv320aic23b_id,
};
+
+static __init int init_tlv320aic23b(void)
+{
+ return i2c_add_driver(&tlv320aic23b_driver);
+}
+
+static __exit void exit_tlv320aic23b(void)
+{
+ i2c_del_driver(&tlv320aic23b_driver);
+}
+
+module_init(init_tlv320aic23b);
+module_exit(exit_tlv320aic23b);
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index c4dab6cfd948..1cec1224913f 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -20,7 +20,6 @@
#include <media/tuner-types.h>
#include <media/v4l2-device.h>
#include <media/v4l2-ioctl.h>
-#include <media/v4l2-i2c-drv.h>
#include "mt20xx.h"
#include "tda8290.h"
#include "tea5761.h"
@@ -428,6 +427,7 @@ static void set_type(struct i2c_client *c, unsigned int type,
{
struct tda18271_config cfg = {
.config = t->config,
+ .small_i2c = TDA18271_03_BYTE_CHUNK_INIT,
};
if (!dvb_attach(tda18271_attach, &t->fe, t->i2c->addr,
@@ -1053,12 +1053,6 @@ static int tuner_probe(struct i2c_client *client,
printk(KERN_CONT "%02x ", buffer[i]);
printk("\n");
}
- /* HACK: This test was added to avoid tuner to probe tda9840 and
- tea6415c on the MXB card */
- if (client->adapter->id == I2C_HW_SAA7146 && client->addr < 0x4a) {
- kfree(t);
- return -ENODEV;
- }
/* autodetection code based on the i2c addr */
if (!no_autodetect) {
@@ -1176,16 +1170,32 @@ static const struct i2c_device_id tuner_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tuner_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tuner",
- .probe = tuner_probe,
- .remove = tuner_remove,
- .command = tuner_command,
- .suspend = tuner_suspend,
- .resume = tuner_resume,
- .id_table = tuner_id,
+static struct i2c_driver tuner_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tuner",
+ },
+ .probe = tuner_probe,
+ .remove = tuner_remove,
+ .command = tuner_command,
+ .suspend = tuner_suspend,
+ .resume = tuner_resume,
+ .id_table = tuner_id,
};
+static __init int init_tuner(void)
+{
+ return i2c_add_driver(&tuner_driver);
+}
+
+static __exit void exit_tuner(void)
+{
+ i2c_del_driver(&tuner_driver);
+}
+
+module_init(init_tuner);
+module_exit(exit_tuner);
+
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
* ---------------------------------------------------------------------------
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 800fc1b111ef..a25e2b5e1944 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -35,7 +35,6 @@
#include <media/tvaudio.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/i2c-addr.h>
@@ -1227,18 +1226,6 @@ static int tea6320_initialize(struct CHIPSTATE * chip)
static int tda8425_shift10(int val) { return (val >> 10) | 0xc0; }
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 (c->adapter->id == I2C_HW_B_RIVA)
- memcpy(desc->inputmap, inputmap, sizeof(inputmap));
- return 0;
-}
-
static void tda8425_setmode(struct CHIPSTATE *chip, int mode)
{
int s1 = chip->shadow.bytes[TDA8425_S1+1] & 0xe1;
@@ -1574,7 +1561,6 @@ static struct CHIPDESC chiplist[] = {
.treblereg = TDA8425_TR,
/* callbacks */
- .initialize = tda8425_initialize,
.volfunc = tda8425_shift10,
.bassfunc = tda8425_shift12,
.treblefunc = tda8425_shift12,
@@ -2079,9 +2065,25 @@ static const struct i2c_device_id tvaudio_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tvaudio_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tvaudio",
- .probe = tvaudio_probe,
- .remove = tvaudio_remove,
- .id_table = tvaudio_id,
+static struct i2c_driver tvaudio_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tvaudio",
+ },
+ .probe = tvaudio_probe,
+ .remove = tvaudio_remove,
+ .id_table = tvaudio_id,
};
+
+static __init int init_tvaudio(void)
+{
+ return i2c_add_driver(&tvaudio_driver);
+}
+
+static __exit void exit_tvaudio(void)
+{
+ i2c_del_driver(&tvaudio_driver);
+}
+
+module_init(init_tvaudio);
+module_exit(exit_tvaudio);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index 0a877497b93f..07fabdd9b465 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -267,6 +267,21 @@ hauppauge_tuner[] =
{ TUNER_ABSENT, "Xceive XC4000"},
{ TUNER_ABSENT, "Dibcom 7070"},
{ TUNER_PHILIPS_TDA8290, "NXP 18271C2"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ /* 160-169 */
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_ABSENT, "unknown"},
+ { TUNER_PHILIPS_FQ1236_MK5, "TCL M30WTP-4N-E"},
+ { TUNER_ABSENT, "unknown"},
};
/* Use V4L2_IDENT_AMBIGUOUS for those audio 'chips' that are
diff --git a/drivers/media/video/tvp514x.c b/drivers/media/video/tvp514x.c
index e826114b7fb8..45bcf0358a1d 100644
--- a/drivers/media/video/tvp514x.c
+++ b/drivers/media/video/tvp514x.c
@@ -35,6 +35,7 @@
#include <media/v4l2-device.h>
#include <media/v4l2-common.h>
+#include <media/v4l2-mediabus.h>
#include <media/v4l2-chip-ident.h>
#include <media/tvp514x.h>
@@ -88,9 +89,6 @@ static int tvp514x_s_stream(struct v4l2_subdev *sd, int enable);
* @pdata: Board specific
* @ver: Chip version
* @streaming: TVP5146/47 decoder streaming - enabled or disabled.
- * @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
@@ -105,13 +103,9 @@ struct tvp514x_decoder {
int ver;
int streaming;
- 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;
+ const struct tvp514x_std_info *std_list;
/* Input and Output Routing parameters */
u32 input;
u32 output;
@@ -203,27 +197,12 @@ static struct tvp514x_reg tvp514x_reg_list_default[] = {
};
/**
- * 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[] = {
+static const struct tvp514x_std_info tvp514x_std_list[] = {
/* Standard: STD_NTSC_MJ */
[STD_NTSC_MJ] = {
.width = NTSC_NUM_ACTIVE_PIXELS,
@@ -366,13 +345,13 @@ static int tvp514x_write_regs(struct v4l2_subdev *sd,
}
/**
- * tvp514x_get_current_std() : Get the current standard detected by TVP5146/47
+ * tvp514x_query_current_std() : Query the current standard detected by TVP5146/47
* @sd: ptr to v4l2_subdev struct
*
- * Get current standard detected by TVP5146/47, STD_INVALID if there is no
+ * Returns the current standard detected by TVP5146/47, STD_INVALID if there is no
* standard detected.
*/
-static enum tvp514x_std tvp514x_get_current_std(struct v4l2_subdev *sd)
+static enum tvp514x_std tvp514x_query_current_std(struct v4l2_subdev *sd)
{
u8 std, std_status;
@@ -518,7 +497,7 @@ static int tvp514x_detect(struct v4l2_subdev *sd,
* @std_id: standard V4L2 std_id ioctl enum
*
* Returns the current standard detected by TVP5146/47. If no active input is
- * detected, returns -EINVAL
+ * detected then *std_id is set to 0 and the function returns 0.
*/
static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
{
@@ -530,10 +509,12 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
if (std_id == NULL)
return -EINVAL;
- /* get the current standard */
- current_std = tvp514x_get_current_std(sd);
+ *std_id = V4L2_STD_UNKNOWN;
+
+ /* query the current standard */
+ current_std = tvp514x_query_current_std(sd);
if (current_std == STD_INVALID)
- return -EINVAL;
+ return 0;
input_sel = decoder->input;
@@ -575,12 +556,11 @@ static int tvp514x_querystd(struct v4l2_subdev *sd, v4l2_std_id *std_id)
/* check whether signal is locked */
sync_lock_status = tvp514x_read_reg(sd, REG_STATUS1);
if (lock_mask != (sync_lock_status & lock_mask))
- return -EINVAL; /* No input detected */
+ return 0; /* No input detected */
- decoder->current_std = current_std;
*std_id = decoder->std_list[current_std].standard.id;
- v4l2_dbg(1, debug, sd, "Current STD: %s",
+ v4l2_dbg(1, debug, sd, "Current STD: %s\n",
decoder->std_list[current_std].standard.name);
return 0;
}
@@ -614,7 +594,7 @@ static int tvp514x_s_std(struct v4l2_subdev *sd, v4l2_std_id std_id)
decoder->tvp514x_regs[REG_VIDEO_STD].val =
decoder->std_list[i].video_std;
- v4l2_dbg(1, debug, sd, "Standard set to: %s",
+ v4l2_dbg(1, debug, sd, "Standard set to: %s\n",
decoder->std_list[i].standard.name);
return 0;
}
@@ -637,7 +617,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd,
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;
@@ -721,11 +700,6 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd,
/* 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(sd);
- if (current_std == STD_INVALID)
- continue;
-
sync_lock_status = tvp514x_read_reg(sd,
REG_STATUS1);
if (lock_mask == (sync_lock_status & lock_mask))
@@ -733,15 +707,13 @@ static int tvp514x_s_routing(struct v4l2_subdev *sd,
break;
}
- if ((current_std == STD_INVALID) || (try_count < 0))
+ if (try_count < 0)
return -EINVAL;
- decoder->current_std = current_std;
decoder->input = input;
decoder->output = output;
- v4l2_dbg(1, debug, sd, "Input set to: %d, std : %d",
- input_sel, current_std);
+ v4l2_dbg(1, debug, sd, "Input set to: %d\n", input_sel);
return 0;
}
@@ -794,7 +766,7 @@ tvp514x_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qctrl)
return err;
}
- v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d",
+ v4l2_dbg(1, debug, sd, "Query Control:%s: Min - %d, Max - %d, Def - %d\n",
qctrl->name, qctrl->minimum, qctrl->maximum,
qctrl->default_value);
@@ -851,7 +823,7 @@ tvp514x_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return -EINVAL;
}
- v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Get Control: ID - %d - %d\n",
ctrl->id, ctrl->value);
return 0;
}
@@ -951,163 +923,58 @@ tvp514x_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
return err;
}
- v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d",
+ v4l2_dbg(1, debug, sd, "Set Control: ID - %d - %d\n",
ctrl->id, ctrl->value);
return err;
}
/**
- * tvp514x_enum_fmt_cap() - V4L2 decoder interface handler for enum_fmt
+ * tvp514x_enum_mbus_fmt() - V4L2 decoder interface handler for enum_mbus_fmt
* @sd: pointer to standard V4L2 sub-device structure
- * @fmt: standard V4L2 VIDIOC_ENUM_FMT ioctl structure
+ * @index: index of pixelcode to retrieve
+ * @code: receives the pixelcode
*
- * Implement the VIDIOC_ENUM_FMT ioctl to enumerate supported formats
+ * Enumerates supported mediabus formats
*/
static int
-tvp514x_enum_fmt_cap(struct v4l2_subdev *sd, struct v4l2_fmtdesc *fmt)
+tvp514x_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- int index;
-
- if (fmt == NULL)
+ if (index)
return -EINVAL;
- index = fmt->index;
- if ((index >= decoder->num_fmts) || (index < 0))
- /* Index out of bound */
- return -EINVAL;
-
- if (fmt->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
-
- memcpy(fmt, &decoder->fmt_list[index],
- sizeof(struct v4l2_fmtdesc));
-
- v4l2_dbg(1, debug, sd, "Current FMT: index - %d (%s)",
- decoder->fmt_list[index].index,
- decoder->fmt_list[index].description);
+ *code = V4L2_MBUS_FMT_YUYV10_2X10;
return 0;
}
/**
- * tvp514x_try_fmt_cap() - V4L2 decoder interface handler for try_fmt
+ * tvp514x_mbus_fmt_cap() - V4L2 decoder interface handler for try/s/g_mbus_fmt
* @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
+ * @f: pointer to the mediabus format 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.
+ * Negotiates the image capture size and mediabus format.
*/
static int
-tvp514x_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
+tvp514x_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct tvp514x_decoder *decoder = to_decoder(sd);
- 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)
- /* only capture is supported */
- 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(sd);
- 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)
- /* None of the format matched, select default */
- ifmt = 0;
- 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;
-
- v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d"
- "Width - %d, Height - %d",
- decoder->fmt_list[ifmt].description, pix->bytesperline,
- pix->width, pix->height);
- return 0;
-}
-
-/**
- * tvp514x_s_fmt_cap() - V4L2 decoder interface handler for s_fmt
- * @sd: pointer to standard V4L2 sub-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
-tvp514x_s_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
- struct v4l2_pix_format *pix;
- int rval;
-
- if (f == NULL)
- return -EINVAL;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
+ current_std = decoder->current_std;
- pix = &f->fmt.pix;
- rval = tvp514x_try_fmt_cap(sd, f);
- if (rval)
- return rval;
+ f->code = V4L2_MBUS_FMT_YUYV10_2X10;
+ f->width = decoder->std_list[current_std].width;
+ f->height = decoder->std_list[current_std].height;
+ f->field = V4L2_FIELD_INTERLACED;
+ f->colorspace = V4L2_COLORSPACE_SMPTE170M;
- decoder->pix = *pix;
-
- return rval;
-}
-
-/**
- * tvp514x_g_fmt_cap() - V4L2 decoder interface handler for tvp514x_g_fmt_cap
- * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 v4l2_format structure
- *
- * Returns the decoder's current pixel format in the v4l2_format
- * parameter.
- */
-static int
-tvp514x_g_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
-{
- struct tvp514x_decoder *decoder = to_decoder(sd);
-
- if (f == NULL)
- return -EINVAL;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- /* only capture is supported */
- return -EINVAL;
-
- f->fmt.pix = decoder->pix;
-
- v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d"
- "Width - %d, Height - %d",
- decoder->pix.bytesperline,
- decoder->pix.width, decoder->pix.height);
+ v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d\n",
+ f->width, f->height);
return 0;
}
@@ -1132,15 +999,8 @@ tvp514x_g_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
/* only capture is supported */
return -EINVAL;
- memset(a, 0, sizeof(*a));
- a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
/* get the current standard */
- current_std = tvp514x_get_current_std(sd);
- if (current_std == STD_INVALID)
- return -EINVAL;
-
- decoder->current_std = current_std;
+ current_std = decoder->current_std;
cparm = &a->parm.capture;
cparm->capability = V4L2_CAP_TIMEPERFRAME;
@@ -1175,11 +1035,7 @@ tvp514x_s_parm(struct v4l2_subdev *sd, struct v4l2_streamparm *a)
timeperframe = &a->parm.capture.timeperframe;
/* get the current standard */
- current_std = tvp514x_get_current_std(sd);
- if (current_std == STD_INVALID)
- return -EINVAL;
-
- decoder->current_std = current_std;
+ current_std = decoder->current_std;
*timeperframe =
decoder->std_list[current_std].standard.frameperiod;
@@ -1258,10 +1114,10 @@ static const struct v4l2_subdev_core_ops tvp514x_core_ops = {
static const struct v4l2_subdev_video_ops tvp514x_video_ops = {
.s_routing = tvp514x_s_routing,
.querystd = tvp514x_querystd,
- .enum_fmt = tvp514x_enum_fmt_cap,
- .g_fmt = tvp514x_g_fmt_cap,
- .try_fmt = tvp514x_try_fmt_cap,
- .s_fmt = tvp514x_s_fmt_cap,
+ .enum_mbus_fmt = tvp514x_enum_mbus_fmt,
+ .g_mbus_fmt = tvp514x_mbus_fmt,
+ .try_mbus_fmt = tvp514x_mbus_fmt,
+ .s_mbus_fmt = tvp514x_mbus_fmt,
.g_parm = tvp514x_g_parm,
.s_parm = tvp514x_s_parm,
.s_stream = tvp514x_s_stream,
@@ -1274,22 +1130,6 @@ static const struct v4l2_subdev_ops tvp514x_ops = {
static struct tvp514x_decoder tvp514x_dev = {
.streaming = 0,
-
- .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),
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index 47f0582d50a5..58927664d3ea 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -11,7 +11,6 @@
#include <linux/delay.h>
#include <media/v4l2-device.h>
#include <media/tvp5150.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/v4l2-chip-ident.h>
#include "tvp5150_reg.h"
@@ -277,7 +276,7 @@ static int tvp5150_log_status(struct v4l2_subdev *sd)
static inline void tvp5150_selmux(struct v4l2_subdev *sd)
{
- int opmode=0;
+ int opmode = 0;
struct tvp5150 *decoder = to_tvp5150(sd);
int input = 0;
unsigned char val;
@@ -290,12 +289,10 @@ static inline void tvp5150_selmux(struct v4l2_subdev *sd)
input |= 2;
/* fall through */
case TVP5150_COMPOSITE0:
- opmode=0x30; /* TV Mode */
break;
case TVP5150_SVIDEO:
default:
input |= 1;
- opmode=0; /* Auto Mode */
break;
}
@@ -934,17 +931,6 @@ static int tvp5150_s_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int tvp5150_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- switch (fmt->type) {
- case V4L2_BUF_TYPE_SLICED_VBI_CAPTURE:
- return tvp5150_s_sliced_fmt(sd, &fmt->fmt.sliced);
-
- default:
- return -EINVAL;
- }
-}
-
static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_format *svbi)
{
int i, mask = 0;
@@ -960,13 +946,6 @@ static int tvp5150_g_sliced_fmt(struct v4l2_subdev *sd, struct v4l2_sliced_vbi_f
return 0;
}
-static int tvp5150_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *fmt)
-{
- if (fmt->type != V4L2_BUF_TYPE_SLICED_VBI_CAPTURE)
- return -EINVAL;
- return tvp5150_g_sliced_fmt(sd, &fmt->fmt.sliced);
-}
-
static int tvp5150_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *chip)
{
@@ -1054,8 +1033,6 @@ static const struct v4l2_subdev_tuner_ops tvp5150_tuner_ops = {
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,
};
static const struct v4l2_subdev_vbi_ops tvp5150_vbi_ops = {
@@ -1131,9 +1108,25 @@ static const struct i2c_device_id tvp5150_id[] = {
};
MODULE_DEVICE_TABLE(i2c, tvp5150_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "tvp5150",
- .probe = tvp5150_probe,
- .remove = tvp5150_remove,
- .id_table = tvp5150_id,
+static struct i2c_driver tvp5150_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "tvp5150",
+ },
+ .probe = tvp5150_probe,
+ .remove = tvp5150_remove,
+ .id_table = tvp5150_id,
};
+
+static __init int init_tvp5150(void)
+{
+ return i2c_add_driver(&tvp5150_driver);
+}
+
+static __exit void exit_tvp5150(void)
+{
+ i2c_del_driver(&tvp5150_driver);
+}
+
+module_init(init_tvp5150);
+module_exit(exit_tvp5150);
diff --git a/drivers/media/video/tvp7002.c b/drivers/media/video/tvp7002.c
index 8085ac392446..c799e4eb6fcd 100644
--- a/drivers/media/video/tvp7002.c
+++ b/drivers/media/video/tvp7002.c
@@ -179,7 +179,7 @@ static const struct i2c_reg_value tvp7002_init_default[] = {
/* Register parameters for 480P */
static const struct i2c_reg_value tvp7002_parms_480P[] = {
{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x35, TVP7002_WRITE },
- { TVP7002_HPLL_FDBK_DIV_LSBS, 0x0a, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0xa0, TVP7002_WRITE },
{ TVP7002_HPLL_CRTL, 0x02, TVP7002_WRITE },
{ TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
{ TVP7002_AVID_START_PIXEL_LSBS, 0x91, TVP7002_WRITE },
@@ -223,7 +223,7 @@ static const struct i2c_reg_value tvp7002_parms_576P[] = {
/* Register parameters for 1080I60 */
static const struct i2c_reg_value tvp7002_parms_1080I60[] = {
{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE },
- { TVP7002_HPLL_FDBK_DIV_LSBS, 0x08, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE },
{ TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
{ TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
{ TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
@@ -245,7 +245,7 @@ static const struct i2c_reg_value tvp7002_parms_1080I60[] = {
/* Register parameters for 1080P60 */
static const struct i2c_reg_value tvp7002_parms_1080P60[] = {
{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x89, TVP7002_WRITE },
- { TVP7002_HPLL_FDBK_DIV_LSBS, 0x08, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x80, TVP7002_WRITE },
{ TVP7002_HPLL_CRTL, 0xE0, TVP7002_WRITE },
{ TVP7002_HPLL_PHASE_SEL, 0x14, TVP7002_WRITE },
{ TVP7002_AVID_START_PIXEL_LSBS, 0x06, TVP7002_WRITE },
@@ -289,7 +289,7 @@ static const struct i2c_reg_value tvp7002_parms_1080I50[] = {
/* Register parameters for 720P60 */
static const struct i2c_reg_value tvp7002_parms_720P60[] = {
{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x67, TVP7002_WRITE },
- { TVP7002_HPLL_FDBK_DIV_LSBS, 0x02, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0x20, TVP7002_WRITE },
{ TVP7002_HPLL_CRTL, 0xa0, TVP7002_WRITE },
{ TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE },
{ TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE },
@@ -311,7 +311,7 @@ static const struct i2c_reg_value tvp7002_parms_720P60[] = {
/* Register parameters for 720P50 */
static const struct i2c_reg_value tvp7002_parms_720P50[] = {
{ TVP7002_HPLL_FDBK_DIV_MSBS, 0x7b, TVP7002_WRITE },
- { TVP7002_HPLL_FDBK_DIV_LSBS, 0x0c, TVP7002_WRITE },
+ { TVP7002_HPLL_FDBK_DIV_LSBS, 0xc0, TVP7002_WRITE },
{ TVP7002_HPLL_CRTL, 0x98, TVP7002_WRITE },
{ TVP7002_HPLL_PHASE_SEL, 0x16, TVP7002_WRITE },
{ TVP7002_AVID_START_PIXEL_LSBS, 0x47, TVP7002_WRITE },
@@ -330,19 +330,6 @@ static const struct i2c_reg_value tvp7002_parms_720P50[] = {
{ TVP7002_EOR, 0xff, TVP7002_RESERVED }
};
-/* Struct list for available formats */
-static const struct v4l2_fmtdesc tvp7002_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,
- },
-};
-
-#define NUM_FORMATS ARRAY_SIZE(tvp7002_fmt_list)
-
/* Preset definition for handling device operation */
struct tvp7002_preset_definition {
u32 preset;
@@ -439,7 +426,6 @@ struct tvp7002 {
int ver;
int streaming;
- struct v4l2_pix_format pix;
const struct tvp7002_preset_definition *current_preset;
u8 gain;
};
@@ -695,81 +681,33 @@ static int tvp7002_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
}
/*
- * tvp7002_try_fmt_cap() - V4L2 decoder interface handler for try_fmt
+ * tvp7002_mbus_fmt() - V4L2 decoder interface handler for try/s/g_mbus_fmt
* @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 VIDIOC_TRY_FMT ioctl structure
+ * @f: pointer to mediabus format 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.
+ * Negotiate the image capture size and mediabus format.
+ * There is only one possible format, so this single function works for
+ * get, set and try.
*/
-static int tvp7002_try_fmt_cap(struct v4l2_subdev *sd, struct v4l2_format *f)
+static int tvp7002_mbus_fmt(struct v4l2_subdev *sd, struct v4l2_mbus_framefmt *f)
{
struct tvp7002 *device = to_tvp7002(sd);
struct v4l2_dv_enum_preset e_preset;
- struct v4l2_pix_format *pix;
- int error = 0;
-
- pix = &f->fmt.pix;
+ int error;
/* Calculate height and width based on current standard */
error = v4l_fill_dv_preset_info(device->current_preset->preset, &e_preset);
if (error)
- return -EINVAL;
-
- pix->width = e_preset.width;
- pix->height = e_preset.height;
- pix->pixelformat = V4L2_PIX_FMT_UYVY;
- pix->field = device->current_preset->scanmode;
- pix->bytesperline = pix->width * 2;
- pix->sizeimage = pix->bytesperline * pix->height;
- pix->colorspace = device->current_preset->color_space;
- pix->priv = 0;
-
- v4l2_dbg(1, debug, sd, "Try FMT: pixelformat - %s, bytesperline - %d"
- "Width - %d, Height - %d", "8-bit UYVY 4:2:2 Format",
- pix->bytesperline, pix->width, pix->height);
- return error;
-}
-
-/*
- * tvp7002_s_fmt() - V4L2 decoder interface handler for s_fmt
- * @sd: pointer to standard V4L2 sub-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 tvp7002_s_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
-{
- struct tvp7002 *decoder = to_tvp7002(sd);
- int rval;
-
- rval = tvp7002_try_fmt_cap(sd, f);
- if (!rval)
- decoder->pix = f->fmt.pix;
- return rval;
-}
-
-/*
- * tvp7002_g_fmt() - V4L2 decoder interface handler for tvp7002_g_fmt
- * @sd: pointer to standard V4L2 sub-device structure
- * @f: pointer to standard V4L2 v4l2_format structure
- *
- * Returns the decoder's current pixel format in the v4l2_format
- * parameter.
- */
-static int tvp7002_g_fmt(struct v4l2_subdev *sd, struct v4l2_format *f)
-{
- struct tvp7002 *decoder = to_tvp7002(sd);
+ return error;
- f->fmt.pix = decoder->pix;
+ f->width = e_preset.width;
+ f->height = e_preset.height;
+ f->code = V4L2_MBUS_FMT_YUYV10_1X20;
+ f->field = device->current_preset->scanmode;
+ f->colorspace = device->current_preset->color_space;
- v4l2_dbg(1, debug, sd, "Current FMT: bytesperline - %d"
- "Width - %d, Height - %d",
- decoder->pix.bytesperline,
- decoder->pix.width, decoder->pix.height);
+ v4l2_dbg(1, debug, sd, "MBUS_FMT: Width - %d, Height - %d",
+ f->width, f->height);
return 0;
}
@@ -851,7 +789,7 @@ static int tvp7002_query_dv_preset(struct v4l2_subdev *sd,
* Get the value of a TVP7002 decoder device register.
* Returns zero when successful, -EINVAL if register read fails or
* access to I2C client fails, -EPERM if the call is not allowed
- * by diabled CAP_SYS_ADMIN.
+ * by disabled CAP_SYS_ADMIN.
*/
static int tvp7002_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
@@ -894,21 +832,21 @@ static int tvp7002_s_register(struct v4l2_subdev *sd,
#endif
/*
- * tvp7002_enum_fmt() - Enum supported formats
+ * tvp7002_enum_mbus_fmt() - Enum supported mediabus formats
* @sd: pointer to standard V4L2 sub-device structure
- * @fmtdesc: pointer to format struct
+ * @index: format index
+ * @code: pointer to mediabus format
*
- * Enumerate supported formats.
+ * Enumerate supported mediabus formats.
*/
-static int tvp7002_enum_fmt(struct v4l2_subdev *sd,
- struct v4l2_fmtdesc *fmtdesc)
+static int tvp7002_enum_mbus_fmt(struct v4l2_subdev *sd, unsigned index,
+ enum v4l2_mbus_pixelcode *code)
{
/* Check requested format index is within range */
- if (fmtdesc->index < 0 || fmtdesc->index >= NUM_FORMATS)
+ if (index)
return -EINVAL;
- *fmtdesc = tvp7002_fmt_list[fmtdesc->index];
-
+ *code = V4L2_MBUS_FMT_YUYV10_1X20;
return 0;
}
@@ -1027,9 +965,10 @@ static const struct v4l2_subdev_video_ops tvp7002_video_ops = {
.s_dv_preset = tvp7002_s_dv_preset,
.query_dv_preset = tvp7002_query_dv_preset,
.s_stream = tvp7002_s_stream,
- .g_fmt = tvp7002_g_fmt,
- .s_fmt = tvp7002_s_fmt,
- .enum_fmt = tvp7002_enum_fmt,
+ .g_mbus_fmt = tvp7002_mbus_fmt,
+ .try_mbus_fmt = tvp7002_mbus_fmt,
+ .s_mbus_fmt = tvp7002_mbus_fmt,
+ .enum_mbus_fmt = tvp7002_enum_mbus_fmt,
};
/* V4L2 top level operation handlers */
@@ -1040,17 +979,6 @@ static const struct v4l2_subdev_ops tvp7002_ops = {
static struct tvp7002 tvp7002_dev = {
.streaming = 0,
-
- .pix = {
- .width = 1280,
- .height = 720,
- .pixelformat = V4L2_PIX_FMT_UYVY,
- .field = V4L2_FIELD_NONE,
- .bytesperline = 1280 * 2,
- .sizeimage = 1280 * 2 * 720,
- .colorspace = V4L2_COLORSPACE_REC709,
- },
-
.current_preset = tvp7002_presets,
.gain = 0,
};
diff --git a/drivers/media/video/tw9910.c b/drivers/media/video/tw9910.c
index 76be733eabfd..0347bbe36459 100644
--- a/drivers/media/video/tw9910.c
+++ b/drivers/media/video/tw9910.c
@@ -469,7 +469,7 @@ tw9910_select_norm(struct soc_camera_device *icd, u32 width, u32 height)
*/
static int tw9910_s_stream(struct v4l2_subdev *sd, int enable)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
u8 val;
int ret;
@@ -511,7 +511,7 @@ static int tw9910_set_bus_param(struct soc_camera_device *icd,
unsigned long flags)
{
struct v4l2_subdev *sd = soc_camera_to_subdev(icd);
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
u8 val = VSSL_VVALID | HSSL_DVALID;
/*
@@ -565,7 +565,7 @@ static int tw9910_enum_input(struct soc_camera_device *icd,
static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
struct v4l2_dbg_chip_ident *id)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
id->ident = V4L2_IDENT_TW9910;
@@ -578,7 +578,7 @@ static int tw9910_g_chip_ident(struct v4l2_subdev *sd,
static int tw9910_g_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
int ret;
if (reg->reg > 0xff)
@@ -600,7 +600,7 @@ static int tw9910_g_register(struct v4l2_subdev *sd,
static int tw9910_s_register(struct v4l2_subdev *sd,
struct v4l2_dbg_register *reg)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
if (reg->reg > 0xff ||
reg->val > 0xff)
@@ -613,7 +613,7 @@ static int tw9910_s_register(struct v4l2_subdev *sd,
static int tw9910_s_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
struct v4l2_rect *rect = &a->c;
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
struct soc_camera_device *icd = client->dev.platform_data;
int ret = -EINVAL;
@@ -701,7 +701,7 @@ tw9910_set_fmt_error:
static int tw9910_g_crop(struct v4l2_subdev *sd, struct v4l2_crop *a)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
if (!priv->scale) {
@@ -748,7 +748,7 @@ static int tw9910_cropcap(struct v4l2_subdev *sd, struct v4l2_cropcap *a)
static int tw9910_g_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
if (!priv->scale) {
@@ -768,7 +768,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd,
mf->width = priv->scale->width;
mf->height = priv->scale->height;
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
mf->field = V4L2_FIELD_INTERLACED_BT;
@@ -778,7 +778,7 @@ static int tw9910_g_fmt(struct v4l2_subdev *sd,
static int tw9910_s_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct tw9910_priv *priv = to_tw9910(client);
/* See tw9910_s_crop() - no proper cropping support */
struct v4l2_crop a = {
@@ -797,7 +797,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
/*
* check color format
*/
- if (mf->code != V4L2_MBUS_FMT_YUYV8_2X8_BE)
+ if (mf->code != V4L2_MBUS_FMT_UYVY8_2X8)
return -EINVAL;
mf->colorspace = V4L2_COLORSPACE_JPEG;
@@ -813,7 +813,7 @@ static int tw9910_s_fmt(struct v4l2_subdev *sd,
static int tw9910_try_fmt(struct v4l2_subdev *sd,
struct v4l2_mbus_framefmt *mf)
{
- struct i2c_client *client = sd->priv;
+ struct i2c_client *client = v4l2_get_subdevdata(sd);
struct soc_camera_device *icd = client->dev.platform_data;
const struct tw9910_scale_ctrl *scale;
@@ -824,7 +824,7 @@ static int tw9910_try_fmt(struct v4l2_subdev *sd,
return -EINVAL;
}
- mf->code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ mf->code = V4L2_MBUS_FMT_UYVY8_2X8;
mf->colorspace = V4L2_COLORSPACE_JPEG;
/*
@@ -903,13 +903,13 @@ static struct v4l2_subdev_core_ops tw9910_subdev_core_ops = {
#endif
};
-static int tw9910_enum_fmt(struct v4l2_subdev *sd, int index,
+static int tw9910_enum_fmt(struct v4l2_subdev *sd, unsigned int index,
enum v4l2_mbus_pixelcode *code)
{
if (index)
return -EINVAL;
- *code = V4L2_MBUS_FMT_YUYV8_2X8_BE;
+ *code = V4L2_MBUS_FMT_UYVY8_2X8;
return 0;
}
@@ -977,7 +977,6 @@ static int tw9910_probe(struct i2c_client *client,
ret = tw9910_video_probe(icd, client);
if (ret) {
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
}
@@ -990,7 +989,6 @@ static int tw9910_remove(struct i2c_client *client)
struct soc_camera_device *icd = client->dev.platform_data;
icd->ops = NULL;
- i2c_set_clientdata(client, NULL);
kfree(priv);
return 0;
}
diff --git a/drivers/media/video/upd64031a.c b/drivers/media/video/upd64031a.c
index 36c0c461d8be..f8138c75be8b 100644
--- a/drivers/media/video/upd64031a.c
+++ b/drivers/media/video/upd64031a.c
@@ -28,7 +28,6 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/upd64031a.h>
/* --------------------- read registers functions define -------------------- */
@@ -262,9 +261,25 @@ static const struct i2c_device_id upd64031a_id[] = {
};
MODULE_DEVICE_TABLE(i2c, upd64031a_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "upd64031a",
- .probe = upd64031a_probe,
- .remove = upd64031a_remove,
- .id_table = upd64031a_id,
+static struct i2c_driver upd64031a_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "upd64031a",
+ },
+ .probe = upd64031a_probe,
+ .remove = upd64031a_remove,
+ .id_table = upd64031a_id,
};
+
+static __init int init_upd64031a(void)
+{
+ return i2c_add_driver(&upd64031a_driver);
+}
+
+static __exit void exit_upd64031a(void)
+{
+ i2c_del_driver(&upd64031a_driver);
+}
+
+module_init(init_upd64031a);
+module_exit(exit_upd64031a);
diff --git a/drivers/media/video/upd64083.c b/drivers/media/video/upd64083.c
index c5af93b30a2b..28e0e6b6ca84 100644
--- a/drivers/media/video/upd64083.c
+++ b/drivers/media/video/upd64083.c
@@ -28,7 +28,6 @@
#include <linux/slab.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
#include <media/upd64083.h>
MODULE_DESCRIPTION("uPD64083 driver");
@@ -234,9 +233,25 @@ static const struct i2c_device_id upd64083_id[] = {
};
MODULE_DEVICE_TABLE(i2c, upd64083_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "upd64083",
- .probe = upd64083_probe,
- .remove = upd64083_remove,
- .id_table = upd64083_id,
+static struct i2c_driver upd64083_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "upd64083",
+ },
+ .probe = upd64083_probe,
+ .remove = upd64083_remove,
+ .id_table = upd64083_id,
};
+
+static __init int init_upd64083(void)
+{
+ return i2c_add_driver(&upd64083_driver);
+}
+
+static __exit void exit_upd64083(void)
+{
+ i2c_del_driver(&upd64083_driver);
+}
+
+module_init(init_upd64083);
+module_exit(exit_upd64083);
diff --git a/drivers/media/video/usbvideo/Kconfig b/drivers/media/video/usbvideo/Kconfig
deleted file mode 100644
index adb1c044ad7d..000000000000
--- a/drivers/media/video/usbvideo/Kconfig
+++ /dev/null
@@ -1,53 +0,0 @@
-config VIDEO_USBVIDEO
- tristate
-
-config USB_VICAM
- tristate "USB 3com HomeConnect (aka vicam) support (EXPERIMENTAL)"
- depends on VIDEO_V4L1 && EXPERIMENTAL
- select VIDEO_USBVIDEO
- ---help---
- Say Y here if you have 3com homeconnect camera (vicam).
-
- To compile this driver as a module, choose M here: the
- module will be called vicam.
-
-config USB_IBMCAM
- tristate "USB IBM (Xirlink) C-it Camera support"
- depends on VIDEO_V4L1
- select VIDEO_USBVIDEO
- ---help---
- Say Y here if you want to connect a IBM "C-It" camera, also known as
- "Xirlink PC Camera" to your computer's USB port.
-
- To compile this driver as a module, choose M here: the
- module will be called ibmcam.
-
- This camera has several configuration options which
- can be specified when you load the module. Read
- <file:Documentation/video4linux/ibmcam.txt> to learn more.
-
-config USB_KONICAWC
- tristate "USB Konica Webcam support"
- depends on VIDEO_V4L1
- select VIDEO_USBVIDEO
- ---help---
- Say Y here if you want support for webcams based on a Konica
- chipset. This is known to work with the Intel YC76 webcam.
-
- To compile this driver as a module, choose M here: the
- module will be called konicawc.
-
-config USB_QUICKCAM_MESSENGER
- tristate "USB Logitech Quickcam Messenger (DEPRECATED)"
- depends on VIDEO_V4L1
- select VIDEO_USBVIDEO
- ---help---
- This driver is DEPRECATED please use the gspca stv06xx module
- instead.
-
- Say Y or M here to enable support for the USB Logitech Quickcam
- Messenger webcam.
-
- To compile this driver as a module, choose M here: the
- module will be called quickcam_messenger.
-
diff --git a/drivers/media/video/usbvideo/Makefile b/drivers/media/video/usbvideo/Makefile
deleted file mode 100644
index 4a1b144bee4d..000000000000
--- a/drivers/media/video/usbvideo/Makefile
+++ /dev/null
@@ -1,5 +0,0 @@
-obj-$(CONFIG_VIDEO_USBVIDEO) += usbvideo.o
-obj-$(CONFIG_USB_IBMCAM) += ibmcam.o ultracam.o
-obj-$(CONFIG_USB_KONICAWC) += konicawc.o
-obj-$(CONFIG_USB_VICAM) += vicam.o
-obj-$(CONFIG_USB_QUICKCAM_MESSENGER) += quickcam_messenger.o
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
deleted file mode 100644
index b08549661781..000000000000
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ /dev/null
@@ -1,3977 +0,0 @@
-/*
- * USB IBM C-It Video Camera driver
- *
- * Supports Xirlink C-It Video Camera, IBM PC Camera,
- * IBM NetCamera and Veo Stingray.
- *
- * This driver is based on earlier work of:
- *
- * (C) Copyright 1999 Johannes Erdfelt
- * (C) Copyright 1999 Randy Dunlap
- *
- * 5/24/00 Removed optional (and unnecessary) locking of the driver while
- * the device remains plugged in. Corrected race conditions in ibmcam_open
- * and ibmcam_probe() routines using this as a guideline:
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "usbvideo.h"
-
-#define IBMCAM_VENDOR_ID 0x0545
-#define IBMCAM_PRODUCT_ID 0x8080
-#define NETCAM_PRODUCT_ID 0x8002 /* IBM NetCamera, close to model 2 */
-#define VEO_800C_PRODUCT_ID 0x800C /* Veo Stingray, repackaged Model 2 */
-#define VEO_800D_PRODUCT_ID 0x800D /* Veo Stingray, repackaged Model 4 */
-
-#define MAX_IBMCAM 4 /* How many devices we allow to connect */
-#define USES_IBMCAM_PUTPIXEL 0 /* 0=Fast/oops 1=Slow/secure */
-
-/* Header signatures */
-
-/* Model 1 header: 00 FF 00 xx */
-#define HDRSIG_MODEL1_128x96 0x06 /* U Y V Y ... */
-#define HDRSIG_MODEL1_176x144 0x0e /* U Y V Y ... */
-#define HDRSIG_MODEL1_352x288 0x00 /* V Y U Y ... */
-
-#define IBMCAM_MODEL_1 1 /* XVP-501, 3 interfaces, rev. 0.02 */
-#define IBMCAM_MODEL_2 2 /* KSX-X9903, 2 interfaces, rev. 3.0a */
-#define IBMCAM_MODEL_3 3 /* KSX-X9902, 2 interfaces, rev. 3.01 */
-#define IBMCAM_MODEL_4 4 /* IBM NetCamera, 0545/8002/3.0a */
-
-/* Video sizes supported */
-#define VIDEOSIZE_128x96 VIDEOSIZE(128, 96)
-#define VIDEOSIZE_176x144 VIDEOSIZE(176,144)
-#define VIDEOSIZE_352x288 VIDEOSIZE(352,288)
-#define VIDEOSIZE_320x240 VIDEOSIZE(320,240)
-#define VIDEOSIZE_352x240 VIDEOSIZE(352,240)
-#define VIDEOSIZE_640x480 VIDEOSIZE(640,480)
-#define VIDEOSIZE_160x120 VIDEOSIZE(160,120)
-
-/* Video sizes supported */
-enum {
- SIZE_128x96 = 0,
- SIZE_160x120,
- SIZE_176x144,
- SIZE_320x240,
- SIZE_352x240,
- SIZE_352x288,
- SIZE_640x480,
- /* Add/remove/rearrange items before this line */
- SIZE_LastItem
-};
-
-/*
- * This structure lives in uvd->user field.
- */
-typedef struct {
- int initialized; /* Had we already sent init sequence? */
- int camera_model; /* What type of IBM camera we got? */
- int has_hdr;
-} ibmcam_t;
-#define IBMCAM_T(uvd) ((ibmcam_t *)((uvd)->user_data))
-
-static struct usbvideo *cams;
-
-static int debug;
-
-static int flags; /* = FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
-
-static const int min_canvasWidth = 8;
-static const int min_canvasHeight = 4;
-
-static int lighting = 1; /* Medium */
-
-#define SHARPNESS_MIN 0
-#define SHARPNESS_MAX 6
-static int sharpness = 4; /* Low noise, good details */
-
-#define FRAMERATE_MIN 0
-#define FRAMERATE_MAX 6
-static int framerate = -1;
-
-static int size = SIZE_352x288;
-
-/*
- * Here we define several initialization variables. They may
- * be used to automatically set color, hue, brightness and
- * contrast to desired values. This is particularly useful in
- * case of webcams (which have no controls and no on-screen
- * output) and also when a client V4L software is used that
- * does not have some of those controls. In any case it's
- * good to have startup values as options.
- *
- * These values are all in [0..255] range. This simplifies
- * operation. Note that actual values of V4L variables may
- * be scaled up (as much as << 8). User can see that only
- * on overlay output, however, or through a V4L client.
- */
-static int init_brightness = 128;
-static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
-
-/* Settings for camera model 2 */
-static int init_model2_rg2 = -1;
-static int init_model2_sat = -1;
-static int init_model2_yb = -1;
-
-/* 01.01.08 - Added for RCA video in support -LO */
-/* Settings for camera model 3 */
-static int init_model3_input;
-
-module_param(debug, int, 0);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-module_param(flags, int, 0);
-MODULE_PARM_DESC(flags, "Bitfield: 0=VIDIOCSYNC, 1=B/W, 2=show hints, 3=show stats, 4=test pattern, 5=separate frames, 6=clean frames");
-module_param(framerate, int, 0);
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-module_param(lighting, int, 0);
-MODULE_PARM_DESC(lighting, "Photosensitivity: 0=bright, 1=medium (default), 2=low light");
-module_param(sharpness, int, 0);
-MODULE_PARM_DESC(sharpness, "Model1 noise reduction: 0=smooth, 6=sharp (default=4)");
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Image size: 0=128x96 1=160x120 2=176x144 3=320x240 4=352x240 5=352x288 6=640x480 (default=5)");
-module_param(init_brightness, int, 0);
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
-module_param(init_contrast, int, 0);
-MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-module_param(init_color, int, 0);
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
-module_param(init_hue, int, 0);
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-module_param(hue_correction, int, 0);
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
-
-module_param(init_model2_rg2, int, 0);
-MODULE_PARM_DESC(init_model2_rg2, "Model2 preconfiguration: 0-255 (default=47)");
-module_param(init_model2_sat, int, 0);
-MODULE_PARM_DESC(init_model2_sat, "Model2 preconfiguration: 0-255 (default=52)");
-module_param(init_model2_yb, int, 0);
-MODULE_PARM_DESC(init_model2_yb, "Model2 preconfiguration: 0-255 (default=160)");
-
-/* 01.01.08 - Added for RCA video in support -LO */
-module_param(init_model3_input, int, 0);
-MODULE_PARM_DESC(init_model3_input, "Model3 input: 0=CCD 1=RCA");
-
-MODULE_AUTHOR ("Dmitri");
-MODULE_DESCRIPTION ("IBM/Xirlink C-it USB Camera Driver for Linux (c) 2000");
-MODULE_LICENSE("GPL");
-
-/* Still mysterious i2c commands */
-static const unsigned short unknown_88 = 0x0088;
-static const unsigned short unknown_89 = 0x0089;
-static const unsigned short bright_3x[3] = { 0x0031, 0x0032, 0x0033 };
-static const unsigned short contrast_14 = 0x0014;
-static const unsigned short light_27 = 0x0027;
-static const unsigned short sharp_13 = 0x0013;
-
-/* i2c commands for Model 2 cameras */
-static const unsigned short mod2_brightness = 0x001a; /* $5b .. $ee; default=$5a */
-static const unsigned short mod2_set_framerate = 0x001c; /* 0 (fast).. $1F (slow) */
-static const unsigned short mod2_color_balance_rg2 = 0x001e; /* 0 (red) .. $7F (green) */
-static const unsigned short mod2_saturation = 0x0020; /* 0 (b/w) - $7F (full color) */
-static const unsigned short mod2_color_balance_yb = 0x0022; /* 0..$7F, $50 is about right */
-static const unsigned short mod2_hue = 0x0024; /* 0..$7F, $70 is about right */
-static const unsigned short mod2_sensitivity = 0x0028; /* 0 (min) .. $1F (max) */
-
-struct struct_initData {
- unsigned char req;
- unsigned short value;
- unsigned short index;
-};
-
-/*
- * ibmcam_size_to_videosize()
- *
- * This procedure converts module option 'size' into the actual
- * videosize_t that defines the image size in pixels. We need
- * simplified 'size' because user wants a simple enumerated list
- * of choices, not an infinite set of possibilities.
- */
-static videosize_t ibmcam_size_to_videosize(int size)
-{
- videosize_t vs = VIDEOSIZE_352x288;
- RESTRICT_TO_RANGE(size, 0, (SIZE_LastItem-1));
- switch (size) {
- case SIZE_128x96:
- vs = VIDEOSIZE_128x96;
- break;
- case SIZE_160x120:
- vs = VIDEOSIZE_160x120;
- break;
- case SIZE_176x144:
- vs = VIDEOSIZE_176x144;
- break;
- case SIZE_320x240:
- vs = VIDEOSIZE_320x240;
- break;
- case SIZE_352x240:
- vs = VIDEOSIZE_352x240;
- break;
- case SIZE_352x288:
- vs = VIDEOSIZE_352x288;
- break;
- case SIZE_640x480:
- vs = VIDEOSIZE_640x480;
- break;
- default:
- err("size=%d. is not valid", size);
- break;
- }
- return vs;
-}
-
-/*
- * ibmcam_find_header()
- *
- * Locate one of supported header markers in the queue.
- * Once found, remove all preceding bytes AND the marker (4 bytes)
- * from the data pump queue. Whatever follows must be video lines.
- *
- * History:
- * 1/21/00 Created.
- */
-static enum ParseState ibmcam_find_header(struct uvd *uvd) /* FIXME: Add frame here */
-{
- struct usbvideo_frame *frame;
- ibmcam_t *icam;
-
- if ((uvd->curframe) < 0 || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
- err("ibmcam_find_header: Illegal frame %d.", uvd->curframe);
- return scan_EndParse;
- }
- icam = IBMCAM_T(uvd);
- assert(icam != NULL);
- frame = &uvd->frame[uvd->curframe];
- icam->has_hdr = 0;
- switch (icam->camera_model) {
- case IBMCAM_MODEL_1:
- {
- const int marker_len = 4;
- while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
- (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00))
- {
-#if 0 /* This code helps to detect new frame markers */
- dev_info(&uvd->dev->dev,
- "Header sig: 00 FF 00 %02X\n",
- RING_QUEUE_PEEK(&uvd->dp, 3));
-#endif
- frame->header = RING_QUEUE_PEEK(&uvd->dp, 3);
- if ((frame->header == HDRSIG_MODEL1_128x96) ||
- (frame->header == HDRSIG_MODEL1_176x144) ||
- (frame->header == HDRSIG_MODEL1_352x288))
- {
-#if 0
- dev_info(&uvd->dev->dev,
- "Header found.\n");
-#endif
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
- icam->has_hdr = 1;
- break;
- }
- }
- /* If we are still here then this doesn't look like a header */
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- }
- break;
- }
- case IBMCAM_MODEL_2:
-case IBMCAM_MODEL_4:
- {
- int marker_len = 0;
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- marker_len = 10;
- break;
- default:
- marker_len = 2;
- break;
- }
- while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF))
- {
-#if 0
- dev_info(&uvd->dev->dev, "Header found.\n");
-#endif
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
- icam->has_hdr = 1;
- frame->header = HDRSIG_MODEL1_176x144;
- break;
- }
- /* If we are still here then this doesn't look like a header */
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- }
- break;
- }
- case IBMCAM_MODEL_3:
- { /*
- * Headers: (one precedes every frame). nc=no compression,
- * bq=best quality bf=best frame rate.
- *
- * 176x144: 00 FF 02 { 0A=nc CA=bq EA=bf }
- * 320x240: 00 FF 02 { 08=nc 28=bq 68=bf }
- * 640x480: 00 FF 03 { 08=nc 28=bq 68=bf }
- *
- * Bytes '00 FF' seem to indicate header. Other two bytes
- * encode the frame type. This is a set of bit fields that
- * encode image size, compression type etc. These fields
- * do NOT contain frame number because all frames carry
- * the same header.
- */
- const int marker_len = 4;
- while (RingQueue_GetLength(&uvd->dp) >= marker_len) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xFF) &&
- (RING_QUEUE_PEEK(&uvd->dp, 2) != 0xFF))
- {
- /*
- * Combine 2 bytes of frame type into one
- * easy to use value
- */
- unsigned long byte3, byte4;
-
- byte3 = RING_QUEUE_PEEK(&uvd->dp, 2);
- byte4 = RING_QUEUE_PEEK(&uvd->dp, 3);
- frame->header = (byte3 << 8) | byte4;
-#if 0
- dev_info(&uvd->dev->dev, "Header found.\n");
-#endif
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, marker_len);
- icam->has_hdr = 1;
- break;
- }
- /* If we are still here then this doesn't look like a header */
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- }
- break;
- }
- default:
- break;
- }
- if (!icam->has_hdr) {
- if (uvd->debug > 2)
- dev_info(&uvd->dev->dev,
- "Skipping frame, no header\n");
- return scan_EndParse;
- }
-
- /* Header found */
- icam->has_hdr = 1;
- uvd->stats.header_count++;
- frame->scanstate = ScanState_Lines;
- frame->curline = 0;
-
- if (flags & FLAGS_FORCE_TESTPATTERN) {
- usbvideo_TestPattern(uvd, 1, 1);
- return scan_NextFrame;
- }
- return scan_Continue;
-}
-
-/*
- * ibmcam_parse_lines()
- *
- * Parse one line (interlaced) from the buffer, put
- * decoded RGB value into the current frame buffer
- * and add the written number of bytes (RGB) to
- * the *pcopylen.
- *
- * History:
- * 21-Jan-2000 Created.
- * 12-Oct-2000 Reworked to reflect interlaced nature of the data.
- */
-static enum ParseState ibmcam_parse_lines(
- struct uvd *uvd,
- struct usbvideo_frame *frame,
- long *pcopylen)
-{
- unsigned char *f;
- ibmcam_t *icam;
- unsigned int len, scanLength, scanHeight, order_uv, order_yc;
- int v4l_linesize; /* V4L line offset */
- const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */
- const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */
- const int ccm = 128; /* Color correction median - see below */
- int y, u, v, i, frame_done=0, color_corr;
- static unsigned char lineBuffer[640*3];
- unsigned const char *chromaLine, *lumaLine;
-
- assert(uvd != NULL);
- assert(frame != NULL);
- icam = IBMCAM_T(uvd);
- assert(icam != NULL);
- color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
- RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
- if (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_4) {
- /* Model 4 frame markers do not carry image size identification */
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- case VIDEOSIZE_160x120:
- case VIDEOSIZE_176x144:
- scanLength = VIDEOSIZE_X(uvd->videosize);
- scanHeight = VIDEOSIZE_Y(uvd->videosize);
- break;
- default:
- err("ibmcam_parse_lines: Wrong mode.");
- return scan_Out;
- }
- order_yc = 1; /* order_yc: true=Yc false=cY ('c'=either U or V) */
- order_uv = 1; /* Always true in this algorithm */
- } else {
- switch (frame->header) {
- case HDRSIG_MODEL1_128x96:
- scanLength = 128;
- scanHeight = 96;
- order_uv = 1; /* U Y V Y ... */
- break;
- case HDRSIG_MODEL1_176x144:
- scanLength = 176;
- scanHeight = 144;
- order_uv = 1; /* U Y V Y ... */
- break;
- case HDRSIG_MODEL1_352x288:
- scanLength = 352;
- scanHeight = 288;
- order_uv = 0; /* Y V Y V ... */
- break;
- default:
- err("Unknown header signature 00 FF 00 %02lX", frame->header);
- return scan_NextFrame;
- }
- /* order_yc: true=Yc false=cY ('c'=either U or V) */
- order_yc = (IBMCAM_T(uvd)->camera_model == IBMCAM_MODEL_2);
- }
-
- len = scanLength * 3;
- assert(len <= sizeof(lineBuffer));
-
- /*
- * Lines are organized this way:
- *
- * I420:
- * ~~~~
- * <scanLength->
- * ___________________________________
- * |-----Y-----|---UVUVUV...UVUV-----| \
- * |-----------+---------------------| \
- * |<-- 176 -->|<------ 176*2 ------>| Total 72. lines (interlaced)
- * |... ... | ... | /
- * |<-- 352 -->|<------ 352*2 ------>| Total 144. lines (interlaced)
- * |___________|_____________________| /
- * \ \
- * lumaLine chromaLine
- */
-
- /* Make sure there's enough data for the entire line */
- if (RingQueue_GetLength(&uvd->dp) < len)
- return scan_Out;
-
- /* Suck one line out of the ring queue */
- RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
- /*
- * Make sure that our writing into output buffer
- * will not exceed the buffer. Mind that we may write
- * not into current output scanline but in several after
- * it as well (if we enlarge image vertically.)
- */
- if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
- return scan_NextFrame;
-
- /*
- * Now we are sure that entire line (representing all 'scanLength'
- * pixels from the camera) is available in the buffer. We
- * start copying the line left-aligned to the V4L buffer.
- * If the camera line is shorter then we should pad the V4L
- * buffer with something (black) to complete the line.
- */
- assert(frame->data != NULL);
- f = frame->data + (v4l_linesize * frame->curline);
-
- /*
- * To obtain chrominance data from the 'chromaLine' use this:
- * v = chromaLine[0]; // 0-1:[0], 2-3:[4], 4-5:[8]...
- * u = chromaLine[2]; // 0-1:[2], 2-3:[6], 4-5:[10]...
- *
- * Indices must be calculated this way:
- * v_index = (i >> 1) << 2;
- * u_index = (i >> 1) << 2 + 2;
- *
- * where 'i' is the column number [0..VIDEOSIZE_X(frame->request)-1]
- */
- lumaLine = lineBuffer;
- chromaLine = lineBuffer + scanLength;
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++)
- {
- unsigned char rv, gv, bv; /* RGB components */
-
- /* Check for various visual debugging hints (colorized pixels) */
- if ((flags & FLAGS_DISPLAY_HINTS) && (icam->has_hdr)) {
- /*
- * This is bad and should not happen. This means that
- * we somehow overshoot the line and encountered new
- * frame! Obviously our camera/V4L frame size is out
- * of whack. This cyan dot will help you to figure
- * out where exactly the new frame arrived.
- */
- if (icam->has_hdr == 1) {
- bv = 0; /* Yellow marker */
- gv = 0xFF;
- rv = 0xFF;
- } else {
- bv = 0xFF; /* Cyan marker */
- gv = 0xFF;
- rv = 0;
- }
- icam->has_hdr = 0;
- goto make_pixel;
- }
-
- /*
- * Check if we are still in range. We may be out of range if our
- * V4L canvas is wider or taller than the camera "native" image.
- * Then we quickly fill the remainder of the line with zeros to
- * make black color and quit the horizontal scanning loop.
- */
- if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
- const int j = i * V4L_BYTES_PER_PIXEL;
-#if USES_IBMCAM_PUTPIXEL
- /* Refresh 'f' because we don't use it much with PUTPIXEL */
- f = frame->data + (v4l_linesize * frame->curline) + j;
-#endif
- memset(f, 0, v4l_linesize - j);
- break;
- }
-
- y = lumaLine[i];
- if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
- rv = gv = bv = y;
- else {
- int off_0, off_2;
-
- off_0 = (i >> 1) << 2;
- off_2 = off_0 + 2;
-
- if (order_yc) {
- off_0++;
- off_2++;
- }
- if (!order_uv) {
- off_0 += 2;
- off_2 -= 2;
- }
- u = chromaLine[off_0] + hue_corr;
- v = chromaLine[off_2] + hue2_corr;
-
- /* Apply color correction */
- if (color_corr != 0) {
- /* Magnify up to 2 times, reduce down to zero saturation */
- u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
- v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
- }
- YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
- }
-
- make_pixel:
- /*
- * The purpose of creating the pixel here, in one,
- * dedicated place is that we may need to make the
- * pixel wider and taller than it actually is. This
- * may be used if camera generates small frames for
- * sake of frame rate (or any other reason.)
- *
- * The output data consists of B, G, R bytes
- * (in this order).
- */
-#if USES_IBMCAM_PUTPIXEL
- RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
-#else
- *f++ = bv;
- *f++ = gv;
- *f++ = rv;
-#endif
- /*
- * Typically we do not decide within a legitimate frame
- * that we want to end the frame. However debugging code
- * may detect marker of new frame within the data. Then
- * this condition activates. The 'data' pointer is already
- * pointing at the new marker, so we'd better leave it as is.
- */
- if (frame_done)
- break; /* End scanning of lines */
- }
- /*
- * Account for number of bytes that we wrote into output V4L frame.
- * We do it here, after we are done with the scanline, because we
- * may fill more than one output scanline if we do vertical
- * enlargement.
- */
- frame->curline += 2;
- if (pcopylen != NULL)
- *pcopylen += 2 * v4l_linesize;
- frame->deinterlace = Deinterlace_FillOddLines;
-
- if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
- return scan_NextFrame;
- else
- return scan_Continue;
-}
-
-/*
- * ibmcam_model2_320x240_parse_lines()
- *
- * This procedure deals with a weird RGB format that is produced by IBM
- * camera model 2 in modes 320x240 and above; 'x' below is 159 or 175,
- * depending on horizontal size of the picture:
- *
- * <--- 160 or 176 pairs of RA,RB bytes ----->
- * *-----------------------------------------* \
- * | RA0 | RB0 | RA1 | RB1 | ... | RAx | RBx | \ This is pair of horizontal lines,
- * |-----+-----+-----+-----+ ... +-----+-----| *- or one interlaced line, total
- * | B0 | G0 | B1 | G1 | ... | Bx | Gx | / 120 or 144 such pairs which yield
- * |=====+=====+=====+=====+ ... +=====+=====| / 240 or 288 lines after deinterlacing.
- *
- * Each group of FOUR bytes (RAi, RBi, Bi, Gi) where i=0..frame_width/2-1
- * defines ONE pixel. Therefore this format yields 176x144 "decoded"
- * resolution at best. I do not know why camera sends such format - the
- * previous model (1) just used interlaced I420 and everyone was happy.
- *
- * I do not know what is the difference between RAi and RBi bytes. Both
- * seemingly represent R component, but slightly vary in value (so that
- * the picture looks a bit colored if one or another is used). I use
- * them both as R component in attempt to at least partially recover the
- * lost resolution.
- */
-static enum ParseState ibmcam_model2_320x240_parse_lines(
- struct uvd *uvd,
- struct usbvideo_frame *frame,
- long *pcopylen)
-{
- unsigned char *f, *la, *lb;
- unsigned int len;
- int v4l_linesize; /* V4L line offset */
- int i, j, frame_done=0, color_corr;
- int scanLength, scanHeight;
- static unsigned char lineBuffer[352*2];
-
- switch (uvd->videosize) {
- case VIDEOSIZE_320x240:
- case VIDEOSIZE_352x240:
- case VIDEOSIZE_352x288:
- scanLength = VIDEOSIZE_X(uvd->videosize);
- scanHeight = VIDEOSIZE_Y(uvd->videosize);
- break;
- default:
- err("ibmcam_model2_320x240_parse_lines: Wrong mode.");
- return scan_Out;
- }
-
- color_corr = (uvd->vpic.colour) >> 8; /* 0..+255 */
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
- len = scanLength * 2; /* See explanation above */
- assert(len <= sizeof(lineBuffer));
-
- /* Make sure there's enough data for the entire line */
- if (RingQueue_GetLength(&uvd->dp) < len)
- return scan_Out;
-
- /* Suck one line out of the ring queue */
- RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
- /*
- * Make sure that our writing into output buffer
- * will not exceed the buffer. Mind that we may write
- * not into current output scanline but in several after
- * it as well (if we enlarge image vertically.)
- */
- if ((frame->curline + 2) >= VIDEOSIZE_Y(frame->request))
- return scan_NextFrame;
-
- la = lineBuffer;
- lb = lineBuffer + scanLength;
-
- /*
- * Now we are sure that entire line (representing all
- * VIDEOSIZE_X(frame->request)
- * pixels from the camera) is available in the scratch buffer. We
- * start copying the line left-aligned to the V4L buffer (which
- * might be larger - not smaller, hopefully). If the camera
- * line is shorter then we should pad the V4L buffer with something
- * (black in this case) to complete the line.
- */
- f = frame->data + (v4l_linesize * frame->curline);
-
- /* Fill the 2-line strip */
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
- int y, rv, gv, bv; /* RGB components */
-
- j = i & (~1);
-
- /* Check for various visual debugging hints (colorized pixels) */
- if ((flags & FLAGS_DISPLAY_HINTS) && (IBMCAM_T(uvd)->has_hdr)) {
- if (IBMCAM_T(uvd)->has_hdr == 1) {
- bv = 0; /* Yellow marker */
- gv = 0xFF;
- rv = 0xFF;
- } else {
- bv = 0xFF; /* Cyan marker */
- gv = 0xFF;
- rv = 0;
- }
- IBMCAM_T(uvd)->has_hdr = 0;
- goto make_pixel;
- }
-
- /*
- * Check if we are still in range. We may be out of range if our
- * V4L canvas is wider or taller than the camera "native" image.
- * Then we quickly fill the remainder of the line with zeros to
- * make black color and quit the horizontal scanning loop.
- */
- if (((frame->curline + 2) >= scanHeight) || (i >= scanLength)) {
- const int offset = i * V4L_BYTES_PER_PIXEL;
-#if USES_IBMCAM_PUTPIXEL
- /* Refresh 'f' because we don't use it much with PUTPIXEL */
- f = frame->data + (v4l_linesize * frame->curline) + offset;
-#endif
- memset(f, 0, v4l_linesize - offset);
- break;
- }
-
- /*
- * Here I use RA and RB components, one per physical pixel.
- * This causes fine vertical grid on the picture but may improve
- * horizontal resolution. If you prefer replicating, use this:
- * rv = la[j + 0]; ... or ... rv = la[j + 1];
- * then the pixel will be replicated.
- */
- rv = la[i];
- gv = lb[j + 1];
- bv = lb[j + 0];
-
- y = (rv + gv + bv) / 3; /* Brightness (badly calculated) */
-
- if (flags & FLAGS_MONOCHROME) /* Use monochrome for debugging */
- rv = gv = bv = y;
- else if (color_corr != 128) {
-
- /* Calculate difference between color and brightness */
- rv -= y;
- gv -= y;
- bv -= y;
-
- /* Scale differences */
- rv = (rv * color_corr) / 128;
- gv = (gv * color_corr) / 128;
- bv = (bv * color_corr) / 128;
-
- /* Reapply brightness */
- rv += y;
- gv += y;
- bv += y;
-
- /* Watch for overflows */
- RESTRICT_TO_RANGE(rv, 0, 255);
- RESTRICT_TO_RANGE(gv, 0, 255);
- RESTRICT_TO_RANGE(bv, 0, 255);
- }
-
- make_pixel:
- RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
- }
- /*
- * Account for number of bytes that we wrote into output V4L frame.
- * We do it here, after we are done with the scanline, because we
- * may fill more than one output scanline if we do vertical
- * enlargement.
- */
- frame->curline += 2;
- *pcopylen += v4l_linesize * 2;
- frame->deinterlace = Deinterlace_FillOddLines;
-
- if (frame_done || (frame->curline >= VIDEOSIZE_Y(frame->request)))
- return scan_NextFrame;
- else
- return scan_Continue;
-}
-
-/*
- * ibmcam_model3_parse_lines()
- *
- * | Even lines | Odd Lines |
- * -----------------------------------|
- * |YYY........Y|UYVYUYVY.........UYVY|
- * |YYY........Y|UYVYUYVY.........UYVY|
- * |............|.....................|
- * |YYY........Y|UYVYUYVY.........UYVY|
- * |------------+---------------------|
- *
- * There is one (U, V) chroma pair for every four luma (Y) values. This
- * function reads a pair of lines at a time and obtains missing chroma values
- * from adjacent pixels.
- */
-static enum ParseState ibmcam_model3_parse_lines(
- struct uvd *uvd,
- struct usbvideo_frame *frame,
- long *pcopylen)
-{
- unsigned char *data;
- const unsigned char *color;
- unsigned int len;
- int v4l_linesize; /* V4L line offset */
- const int hue_corr = (uvd->vpic.hue - 0x8000) >> 10; /* -32..+31 */
- const int hue2_corr = (hue_correction - 128) / 4; /* -32..+31 */
- const int ccm = 128; /* Color correction median - see below */
- int i, u, v, rw, data_w=0, data_h=0, color_corr;
- static unsigned char lineBuffer[640*3];
- int line;
-
- color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
- RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
-
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
- /* The header tells us what sort of data is in this frame */
- switch (frame->header) {
- /*
- * Uncompressed modes (that are easy to decode).
- */
- case 0x0308:
- data_w = 640;
- data_h = 480;
- break;
- case 0x0208:
- data_w = 320;
- data_h = 240;
- break;
- case 0x020A:
- data_w = 160;
- data_h = 120;
- break;
- /*
- * Compressed modes (ViCE - that I don't know how to decode).
- */
- case 0x0328: /* 640x480, best quality compression */
- case 0x0368: /* 640x480, best frame rate compression */
- case 0x0228: /* 320x240, best quality compression */
- case 0x0268: /* 320x240, best frame rate compression */
- case 0x02CA: /* 160x120, best quality compression */
- case 0x02EA: /* 160x120, best frame rate compression */
- /* Do nothing with this - not supported */
- err("Unsupported mode $%04lx", frame->header);
- return scan_NextFrame;
- default:
- /* Catch unknown headers, may help in learning new headers */
- err("Strange frame->header=$%08lx", frame->header);
- return scan_NextFrame;
- }
-
- /*
- * Make sure that our writing into output buffer
- * will not exceed the buffer. Note that we may write
- * not into current output scanline but in several after
- * it as well (if we enlarge image vertically.)
- */
- if ((frame->curline + 1) >= data_h) {
- if (uvd->debug >= 3)
- dev_info(&uvd->dev->dev,
- "Reached line %d. (frame is done)\n",
- frame->curline);
- return scan_NextFrame;
- }
-
- /* Make sure that lineBuffer can store two lines of data */
- len = 3 * data_w; /* <y-data> <uyvy-data> */
- assert(len <= sizeof(lineBuffer));
-
- /* Make sure there's enough data for two lines */
- if (RingQueue_GetLength(&uvd->dp) < len)
- return scan_Out;
-
- /* Suck two lines of data out of the ring queue */
- RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
- data = lineBuffer;
- color = data + data_w; /* Point to where color planes begin */
-
- /* Bottom-to-top scanning */
- rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
- RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
-
- /* Iterate over two lines. */
- for (line = 0; line < 2; line++) {
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
- int y;
- int rv, gv, bv; /* RGB components */
-
- if (i >= data_w) {
- RGB24_PUTPIXEL(frame, i, rw, 0, 0, 0);
- continue;
- }
-
- /* first line is YYY...Y; second is UYVY...UYVY */
- y = data[(line == 0) ? i : (i*2 + 1)];
-
- /* Apply static color correction */
- u = color[(i/2)*4] + hue_corr;
- v = color[(i/2)*4 + 2] + hue2_corr;
-
- /* Apply color correction */
- if (color_corr != 0) {
- /* Magnify up to 2 times, reduce down to zero saturation */
- u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
- v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
- }
-
-
- YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
- RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* No deinterlacing */
- }
-
- /* Check for the end of requested data */
- if (rw == 0)
- break;
-
- /* Prepare for the second line */
- rw--;
- data = lineBuffer + data_w;
- }
- frame->deinterlace = Deinterlace_None;
-
- /*
- * Account for number of bytes that we wrote into output V4L frame.
- * We do it here, after we are done with the scanline, because we
- * may fill more than one output scanline if we do vertical
- * enlargement.
- */
- frame->curline += 2;
- *pcopylen += 2 * v4l_linesize;
-
- if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
- if (uvd->debug >= 3) {
- dev_info(&uvd->dev->dev,
- "All requested lines (%ld.) done.\n",
- VIDEOSIZE_Y(frame->request));
- }
- return scan_NextFrame;
- } else
- return scan_Continue;
-}
-
-/*
- * ibmcam_model4_128x96_parse_lines()
- *
- * This decoder is for one strange data format that is produced by Model 4
- * camera only in 128x96 mode. This is RGB format and here is its description.
- * First of all, this is non-interlaced stream, meaning that all scan lines
- * are present in the datastream. There are 96 consecutive blocks of data
- * that describe all 96 lines of the image. Each block is 5*128 bytes long
- * and carries R, G, B components. The format of the block is shown in the
- * code below. First 128*2 bytes are interleaved R and G components. Then
- * we have a gap (junk data) 64 bytes long. Then follow B and something
- * else, also interleaved (this makes another 128*2 bytes). After that
- * probably another 64 bytes of junk follow.
- *
- * History:
- * 10-Feb-2001 Created.
- */
-static enum ParseState ibmcam_model4_128x96_parse_lines(
- struct uvd *uvd,
- struct usbvideo_frame *frame,
- long *pcopylen)
-{
- const unsigned char *data_rv, *data_gv, *data_bv;
- unsigned int len;
- int i, v4l_linesize; /* V4L line offset */
- const int data_w=128, data_h=96;
- static unsigned char lineBuffer[128*5];
-
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
-
- /*
- * Make sure that our writing into output buffer
- * will not exceed the buffer. Note that we may write
- * not into current output scanline but in several after
- * it as well (if we enlarge image vertically.)
- */
- if ((frame->curline + 1) >= data_h) {
- if (uvd->debug >= 3)
- dev_info(&uvd->dev->dev,
- "Reached line %d. (frame is done)\n",
- frame->curline);
- return scan_NextFrame;
- }
-
- /*
- * RGRGRG .... RGRG_____________B?B?B? ... B?B?____________
- * <---- 128*2 ---><---- 64 ---><--- 128*2 ---><--- 64 --->
- */
-
- /* Make sure there's enough data for the entire line */
- len = 5 * data_w;
- assert(len <= sizeof(lineBuffer));
-
- /* Make sure there's enough data for the entire line */
- if (RingQueue_GetLength(&uvd->dp) < len)
- return scan_Out;
-
- /* Suck one line out of the ring queue */
- RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
-
- data_rv = lineBuffer;
- data_gv = lineBuffer + 1;
- data_bv = lineBuffer + data_w*2 + data_w/2;
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
- int rv, gv, bv; /* RGB components */
- if (i < data_w) {
- const int j = i * 2;
- gv = data_rv[j];
- rv = data_gv[j];
- bv = data_bv[j];
- if (flags & FLAGS_MONOCHROME) {
- unsigned long y;
- y = rv + gv + bv;
- y /= 3;
- if (y > 0xFF)
- y = 0xFF;
- rv = gv = bv = (unsigned char) y;
- }
- } else {
- rv = gv = bv = 0;
- }
- RGB24_PUTPIXEL(frame, i, frame->curline, rv, gv, bv);
- }
- frame->deinterlace = Deinterlace_None;
- frame->curline++;
- *pcopylen += v4l_linesize;
-
- if (frame->curline >= VIDEOSIZE_Y(frame->request)) {
- if (uvd->debug >= 3) {
- dev_info(&uvd->dev->dev,
- "All requested lines (%ld.) done.\n",
- VIDEOSIZE_Y(frame->request));
- }
- return scan_NextFrame;
- } else
- return scan_Continue;
-}
-
-/*
- * ibmcam_ProcessIsocData()
- *
- * Generic routine to parse the ring queue data. It employs either
- * ibmcam_find_header() or ibmcam_parse_lines() to do most
- * of work.
- *
- * History:
- * 1/21/00 Created.
- */
-static void ibmcam_ProcessIsocData(struct uvd *uvd,
- struct usbvideo_frame *frame)
-{
- enum ParseState newstate;
- long copylen = 0;
- int mod = IBMCAM_T(uvd)->camera_model;
-
- while (1) {
- newstate = scan_Out;
- if (RingQueue_GetLength(&uvd->dp) > 0) {
- if (frame->scanstate == ScanState_Scanning) {
- newstate = ibmcam_find_header(uvd);
- } else if (frame->scanstate == ScanState_Lines) {
- if ((mod == IBMCAM_MODEL_2) &&
- ((uvd->videosize == VIDEOSIZE_352x288) ||
- (uvd->videosize == VIDEOSIZE_320x240) ||
- (uvd->videosize == VIDEOSIZE_352x240)))
- {
- newstate = ibmcam_model2_320x240_parse_lines(
- uvd, frame, &copylen);
- } else if (mod == IBMCAM_MODEL_4) {
- /*
- * Model 4 cameras (IBM NetCamera) use Model 2 decoder (RGB)
- * for 320x240 and above; 160x120 and 176x144 uses Model 1
- * decoder (YUV), and 128x96 mode uses ???
- */
- if ((uvd->videosize == VIDEOSIZE_352x288) ||
- (uvd->videosize == VIDEOSIZE_320x240) ||
- (uvd->videosize == VIDEOSIZE_352x240))
- {
- newstate = ibmcam_model2_320x240_parse_lines(uvd, frame, &copylen);
- } else if (uvd->videosize == VIDEOSIZE_128x96) {
- newstate = ibmcam_model4_128x96_parse_lines(uvd, frame, &copylen);
- } else {
- newstate = ibmcam_parse_lines(uvd, frame, &copylen);
- }
- } else if (mod == IBMCAM_MODEL_3) {
- newstate = ibmcam_model3_parse_lines(uvd, frame, &copylen);
- } else {
- newstate = ibmcam_parse_lines(uvd, frame, &copylen);
- }
- }
- }
- if (newstate == scan_Continue)
- continue;
- else if ((newstate == scan_NextFrame) || (newstate == scan_Out))
- break;
- else
- return; /* scan_EndParse */
- }
-
- if (newstate == scan_NextFrame) {
- frame->frameState = FrameState_Done;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- if ((mod == IBMCAM_MODEL_2) || (mod == IBMCAM_MODEL_4)) {
- /* Need software contrast adjustment for those cameras */
- frame->flags |= USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST;
- }
- }
-
- /* Update the frame's uncompressed length. */
- frame->seqRead_Length += copylen;
-
-#if 0
- {
- static unsigned char j=0;
- memset(frame->data, j++, uvd->max_frame_size);
- frame->frameState = FrameState_Ready;
- }
-#endif
-}
-
-/*
- * ibmcam_veio()
- *
- * History:
- * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged.
- */
-static int ibmcam_veio(
- struct uvd *uvd,
- unsigned char req,
- unsigned short value,
- unsigned short index)
-{
- static const char proc[] = "ibmcam_veio";
- unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
- int i;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return 0;
-
- if (req == 1) {
- i = usb_control_msg(
- uvd->dev,
- usb_rcvctrlpipe(uvd->dev, 0),
- req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
- value,
- index,
- cp,
- sizeof(cp),
- 1000);
-#if 0
- dev_info(&uvd->dev->dev,
- "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
- "(req=$%02x val=$%04x ind=$%04x)\n",
- cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
- req, value, index);
-#endif
- } else {
- i = usb_control_msg(
- uvd->dev,
- usb_sndctrlpipe(uvd->dev, 0),
- req,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
- value,
- index,
- NULL,
- 0,
- 1000);
- }
- if (i < 0) {
- err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
- proc, i);
- uvd->last_error = i;
- }
- return i;
-}
-
-/*
- * ibmcam_calculate_fps()
- *
- * This procedure roughly calculates the real frame rate based
- * on FPS code (framerate=NNN option). Actual FPS differs
- * slightly depending on lighting conditions, so that actual frame
- * rate is determined by the camera. Since I don't know how to ask
- * the camera what FPS is now I have to use the FPS code instead.
- *
- * The FPS code is in range [0..6], 0 is slowest, 6 is fastest.
- * Corresponding real FPS should be in range [3..30] frames per second.
- * The conversion formula is obvious:
- *
- * real_fps = 3 + (fps_code * 4.5)
- *
- * History:
- * 1/18/00 Created.
- */
-static int ibmcam_calculate_fps(struct uvd *uvd)
-{
- return 3 + framerate*4 + framerate/2;
-}
-
-/*
- * ibmcam_send_FF_04_02()
- *
- * This procedure sends magic 3-command prefix to the camera.
- * The purpose of this prefix is not known.
- *
- * History:
- * 1/2/00 Created.
- */
-static void ibmcam_send_FF_04_02(struct uvd *uvd)
-{
- ibmcam_veio(uvd, 0, 0x00FF, 0x0127);
- ibmcam_veio(uvd, 0, 0x0004, 0x0124);
- ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-}
-
-static void ibmcam_send_00_04_06(struct uvd *uvd)
-{
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x0004, 0x0124);
- ibmcam_veio(uvd, 0, 0x0006, 0x0124);
-}
-
-static void ibmcam_send_x_00(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
-}
-
-static void ibmcam_send_x_00_05(struct uvd *uvd, unsigned short x)
-{
- ibmcam_send_x_00(uvd, x);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
- ibmcam_veio(uvd, 0, 0x0002, 0x0124);
-}
-
-static void ibmcam_send_x_01_00_05(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0001, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02_01(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
- ibmcam_veio(uvd, 0, 0x0002, 0x0124);
- ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-}
-
-static void ibmcam_send_x_00_05_02_08_01(struct uvd *uvd, unsigned short x)
-{
- ibmcam_veio(uvd, 0, x, 0x0127);
- ibmcam_veio(uvd, 0, 0x0000, 0x0124);
- ibmcam_veio(uvd, 0, 0x0005, 0x0124);
- ibmcam_veio(uvd, 0, 0x0002, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0124);
- ibmcam_veio(uvd, 0, 0x0001, 0x0124);
-}
-
-static void ibmcam_Packet_Format1(struct uvd *uvd, unsigned char fkey, unsigned char val)
-{
- ibmcam_send_x_01_00_05(uvd, unknown_88);
- ibmcam_send_x_00_05(uvd, fkey);
- ibmcam_send_x_00_05_02_08_01(uvd, val);
- ibmcam_send_x_00_05(uvd, unknown_88);
- ibmcam_send_x_00_05_02_01(uvd, fkey);
- ibmcam_send_x_00_05(uvd, unknown_89);
- ibmcam_send_x_00(uvd, fkey);
- ibmcam_send_00_04_06(uvd);
- ibmcam_veio(uvd, 1, 0x0000, 0x0126);
- ibmcam_send_FF_04_02(uvd);
-}
-
-static void ibmcam_PacketFormat2(struct uvd *uvd, unsigned char fkey, unsigned char val)
-{
- ibmcam_send_x_01_00_05 (uvd, unknown_88);
- ibmcam_send_x_00_05 (uvd, fkey);
- ibmcam_send_x_00_05_02 (uvd, val);
-}
-
-static void ibmcam_model2_Packet2(struct uvd *uvd)
-{
- ibmcam_veio(uvd, 0, 0x00ff, 0x012d);
- ibmcam_veio(uvd, 0, 0xfea3, 0x0124);
-}
-
-static void ibmcam_model2_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
-{
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x00ff, 0x012e);
- ibmcam_veio(uvd, 0, v1, 0x012f);
- ibmcam_veio(uvd, 0, 0x00ff, 0x0130);
- ibmcam_veio(uvd, 0, 0xc719, 0x0124);
- ibmcam_veio(uvd, 0, v2, 0x0127);
-
- ibmcam_model2_Packet2(uvd);
-}
-
-/*
- * ibmcam_model3_Packet1()
- *
- * 00_0078_012d
- * 00_0097_012f
- * 00_d141_0124
- * 00_0096_0127
- * 00_fea8_0124
-*/
-static void ibmcam_model3_Packet1(struct uvd *uvd, unsigned short v1, unsigned short v2)
-{
- ibmcam_veio(uvd, 0, 0x0078, 0x012d);
- ibmcam_veio(uvd, 0, v1, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, v2, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
-}
-
-static void ibmcam_model4_BrightnessPacket(struct uvd *uvd, int i)
-{
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0026, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, i, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0038, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
-}
-
-/*
- * ibmcam_adjust_contrast()
- *
- * The contrast value changes from 0 (high contrast) to 15 (low contrast).
- * This is in reverse to usual order of things (such as TV controls), so
- * we reverse it again here.
- *
- * TODO: we probably don't need to send the setup 5 times...
- *
- * History:
- * 1/2/00 Created.
- */
-static void ibmcam_adjust_contrast(struct uvd *uvd)
-{
- unsigned char a_contrast = uvd->vpic.contrast >> 12;
- unsigned char new_contrast;
-
- if (a_contrast >= 16)
- a_contrast = 15;
- new_contrast = 15 - a_contrast;
- if (new_contrast == uvd->vpic_old.contrast)
- return;
- uvd->vpic_old.contrast = new_contrast;
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- {
- const int ntries = 5;
- int i;
- for (i=0; i < ntries; i++) {
- ibmcam_Packet_Format1(uvd, contrast_14, new_contrast);
- ibmcam_send_FF_04_02(uvd);
- }
- break;
- }
- case IBMCAM_MODEL_2:
- case IBMCAM_MODEL_4:
- /* Models 2, 4 do not have this control; implemented in software. */
- break;
- case IBMCAM_MODEL_3:
- { /* Preset hardware values */
- static const struct {
- unsigned short cv1;
- unsigned short cv2;
- unsigned short cv3;
- } cv[7] = {
- { 0x05, 0x05, 0x0f }, /* Minimum */
- { 0x04, 0x04, 0x16 },
- { 0x02, 0x03, 0x16 },
- { 0x02, 0x08, 0x16 },
- { 0x01, 0x0c, 0x16 },
- { 0x01, 0x0e, 0x16 },
- { 0x01, 0x10, 0x16 } /* Maximum */
- };
- int i = a_contrast / 2;
- RESTRICT_TO_RANGE(i, 0, 6);
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */
- ibmcam_model3_Packet1(uvd, 0x0067, cv[i].cv1);
- ibmcam_model3_Packet1(uvd, 0x005b, cv[i].cv2);
- ibmcam_model3_Packet1(uvd, 0x005c, cv[i].cv3);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- break;
- }
- default:
- break;
- }
-}
-
-/*
- * ibmcam_change_lighting_conditions()
- *
- * Camera model 1:
- * We have 3 levels of lighting conditions: 0=Bright, 1=Medium, 2=Low.
- *
- * Camera model 2:
- * We have 16 levels of lighting, 0 for bright light and up to 15 for
- * low light. But values above 5 or so are useless because camera is
- * not really capable to produce anything worth viewing at such light.
- * This setting may be altered only in certain camera state.
- *
- * Low lighting forces slower FPS. Lighting is set as a module parameter.
- *
- * History:
- * 1/5/00 Created.
- * 2/20/00 Added support for Model 2 cameras.
- */
-static void ibmcam_change_lighting_conditions(struct uvd *uvd)
-{
- if (debug > 0)
- dev_info(&uvd->dev->dev,
- "%s: Set lighting to %hu.\n", __func__, lighting);
-
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- {
- const int ntries = 5;
- int i;
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, light_27, (unsigned short) lighting);
- break;
- }
- case IBMCAM_MODEL_2:
-#if 0
- /*
- * This command apparently requires camera to be stopped. My
- * experiments showed that it -is- possible to alter the lighting
- * conditions setting "on the fly", but why bother? This setting does
- * not work reliably in all cases, so I decided simply to leave the
- * setting where Xirlink put it - in the camera setup phase. This code
- * is commented out because it does not work at -any- moment, so its
- * presence makes no sense. You may use it for experiments.
- */
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop camera */
- ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Start camera */
-#endif
- break;
- case IBMCAM_MODEL_3:
- case IBMCAM_MODEL_4:
- default:
- break;
- }
-}
-
-/*
- * ibmcam_set_sharpness()
- *
- * Cameras model 1 have internal smoothing feature. It is controlled by value in
- * range [0..6], where 0 is most smooth and 6 is most sharp (raw image, I guess).
- * Recommended value is 4. Cameras model 2 do not have this feature at all.
- */
-static void ibmcam_set_sharpness(struct uvd *uvd)
-{
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- {
- static const unsigned short sa[] = { 0x11, 0x13, 0x16, 0x18, 0x1a, 0x8, 0x0a };
- unsigned short i, sv;
-
- RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
- if (debug > 0)
- dev_info(&uvd->dev->dev, "%s: Set sharpness to %hu.\n",
- __func__, sharpness);
-
- sv = sa[sharpness - SHARPNESS_MIN];
- for (i=0; i < 2; i++) {
- ibmcam_send_x_01_00_05 (uvd, unknown_88);
- ibmcam_send_x_00_05 (uvd, sharp_13);
- ibmcam_send_x_00_05_02 (uvd, sv);
- }
- break;
- }
- case IBMCAM_MODEL_2:
- case IBMCAM_MODEL_4:
- /* Models 2, 4 do not have this control */
- break;
- case IBMCAM_MODEL_3:
- { /*
- * "Use a table of magic numbers.
- * This setting doesn't really change much.
- * But that's how Windows does it."
- */
- static const struct {
- unsigned short sv1;
- unsigned short sv2;
- unsigned short sv3;
- unsigned short sv4;
- } sv[7] = {
- { 0x00, 0x00, 0x05, 0x14 }, /* Smoothest */
- { 0x01, 0x04, 0x05, 0x14 },
- { 0x02, 0x04, 0x05, 0x14 },
- { 0x03, 0x04, 0x05, 0x14 },
- { 0x03, 0x05, 0x05, 0x14 },
- { 0x03, 0x06, 0x05, 0x14 },
- { 0x03, 0x07, 0x05, 0x14 } /* Sharpest */
- };
- RESTRICT_TO_RANGE(sharpness, SHARPNESS_MIN, SHARPNESS_MAX);
- RESTRICT_TO_RANGE(sharpness, 0, 6);
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */
- ibmcam_model3_Packet1(uvd, 0x0060, sv[sharpness].sv1);
- ibmcam_model3_Packet1(uvd, 0x0061, sv[sharpness].sv2);
- ibmcam_model3_Packet1(uvd, 0x0062, sv[sharpness].sv3);
- ibmcam_model3_Packet1(uvd, 0x0063, sv[sharpness].sv4);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- ibmcam_veio(uvd, 0, 0x0001, 0x0113);
- break;
- }
- default:
- break;
- }
-}
-
-/*
- * ibmcam_set_brightness()
- *
- * This procedure changes brightness of the picture.
- */
-static void ibmcam_set_brightness(struct uvd *uvd)
-{
- static const unsigned short n = 1;
-
- if (debug > 0)
- dev_info(&uvd->dev->dev, "%s: Set brightness to %hu.\n",
- __func__, uvd->vpic.brightness);
-
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- {
- unsigned short i, j, bv[3];
- bv[0] = bv[1] = bv[2] = uvd->vpic.brightness >> 10;
- if (bv[0] == (uvd->vpic_old.brightness >> 10))
- return;
- uvd->vpic_old.brightness = bv[0];
- for (j=0; j < 3; j++)
- for (i=0; i < n; i++)
- ibmcam_Packet_Format1(uvd, bright_3x[j], bv[j]);
- break;
- }
- case IBMCAM_MODEL_2:
- {
- unsigned short i, j;
- i = uvd->vpic.brightness >> 12; /* 0 .. 15 */
- j = 0x60 + i * ((0xee - 0x60) / 16); /* 0x60 .. 0xee or so */
- if (uvd->vpic_old.brightness == j)
- break;
- uvd->vpic_old.brightness = j;
- ibmcam_model2_Packet1(uvd, mod2_brightness, j);
- break;
- }
- case IBMCAM_MODEL_3:
- {
- /* Model 3: Brightness range 'i' in [0x0C..0x3F] */
- unsigned short i =
- 0x0C + (uvd->vpic.brightness / (0xFFFF / (0x3F - 0x0C + 1)));
- RESTRICT_TO_RANGE(i, 0x0C, 0x3F);
- if (uvd->vpic_old.brightness == i)
- break;
- uvd->vpic_old.brightness = i;
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */
- ibmcam_model3_Packet1(uvd, 0x0036, i);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- ibmcam_veio(uvd, 0, 0x0001, 0x0113);
- break;
- }
- case IBMCAM_MODEL_4:
- {
- /* Model 4: Brightness range 'i' in [0x04..0xb4] */
- unsigned short i = 0x04 + (uvd->vpic.brightness / (0xFFFF / (0xb4 - 0x04 + 1)));
- RESTRICT_TO_RANGE(i, 0x04, 0xb4);
- if (uvd->vpic_old.brightness == i)
- break;
- uvd->vpic_old.brightness = i;
- ibmcam_model4_BrightnessPacket(uvd, i);
- break;
- }
- default:
- break;
- }
-}
-
-static void ibmcam_set_hue(struct uvd *uvd)
-{
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_2:
- {
- unsigned short hue = uvd->vpic.hue >> 9; /* 0 .. 7F */
- if (uvd->vpic_old.hue == hue)
- return;
- uvd->vpic_old.hue = hue;
- ibmcam_model2_Packet1(uvd, mod2_hue, hue);
- /* ibmcam_model2_Packet1(uvd, mod2_saturation, sat); */
- break;
- }
- case IBMCAM_MODEL_3:
- {
-#if 0 /* This seems not to work. No problem, will fix programmatically */
- unsigned short hue = 0x05 + (uvd->vpic.hue / (0xFFFF / (0x37 - 0x05 + 1)));
- RESTRICT_TO_RANGE(hue, 0x05, 0x37);
- if (uvd->vpic_old.hue == hue)
- return;
- uvd->vpic_old.hue = hue;
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop */
- ibmcam_model3_Packet1(uvd, 0x007e, hue);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- ibmcam_veio(uvd, 0, 0x0001, 0x0113);
-#endif
- break;
- }
- case IBMCAM_MODEL_4:
- {
- unsigned short r_gain, g_gain, b_gain, hue;
-
- /*
- * I am not sure r/g/b_gain variables exactly control gain
- * of those channels. Most likely they subtly change some
- * very internal image processing settings in the camera.
- * In any case, here is what they do, and feel free to tweak:
- *
- * r_gain: seriously affects red gain
- * g_gain: seriously affects green gain
- * b_gain: seriously affects blue gain
- * hue: changes average color from violet (0) to red (0xFF)
- *
- * These settings are preset for a decent white balance in
- * 320x240, 352x288 modes. Low-res modes exhibit higher contrast
- * and therefore may need different values here.
- */
- hue = 20 + (uvd->vpic.hue >> 9);
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- r_gain = 90;
- g_gain = 166;
- b_gain = 175;
- break;
- case VIDEOSIZE_160x120:
- r_gain = 70;
- g_gain = 166;
- b_gain = 185;
- break;
- case VIDEOSIZE_176x144:
- r_gain = 160;
- g_gain = 175;
- b_gain = 185;
- break;
- default:
- r_gain = 120;
- g_gain = 166;
- b_gain = 175;
- break;
- }
- RESTRICT_TO_RANGE(hue, 1, 0x7f);
-
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, g_gain, 0x0127); /* Green gain */
- ibmcam_veio(uvd, 0, r_gain, 0x012e); /* Red gain */
- ibmcam_veio(uvd, 0, b_gain, 0x0130); /* Blue gain */
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, hue, 0x012d); /* Hue */
- ibmcam_veio(uvd, 0, 0xf545, 0x0124);
- break;
- }
- default:
- break;
- }
-}
-
-/*
- * ibmcam_adjust_picture()
- *
- * This procedure gets called from V4L interface to update picture settings.
- * Here we change brightness and contrast.
- */
-static void ibmcam_adjust_picture(struct uvd *uvd)
-{
- ibmcam_adjust_contrast(uvd);
- ibmcam_set_brightness(uvd);
- ibmcam_set_hue(uvd);
-}
-
-static int ibmcam_model1_setup(struct uvd *uvd)
-{
- const int ntries = 5;
- int i;
-
- ibmcam_veio(uvd, 1, 0x00, 0x0128);
- ibmcam_veio(uvd, 1, 0x00, 0x0100);
- ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */
- ibmcam_veio(uvd, 1, 0x00, 0x0100);
- ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */
- ibmcam_veio(uvd, 1, 0x00, 0x0100);
- ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */
- ibmcam_veio(uvd, 0, 0x01, 0x0108);
-
- ibmcam_veio(uvd, 0, 0x03, 0x0112);
- ibmcam_veio(uvd, 1, 0x00, 0x0115);
- ibmcam_veio(uvd, 0, 0x06, 0x0115);
- ibmcam_veio(uvd, 1, 0x00, 0x0116);
- ibmcam_veio(uvd, 0, 0x44, 0x0116);
- ibmcam_veio(uvd, 1, 0x00, 0x0116);
- ibmcam_veio(uvd, 0, 0x40, 0x0116);
- ibmcam_veio(uvd, 1, 0x00, 0x0115);
- ibmcam_veio(uvd, 0, 0x0e, 0x0115);
- ibmcam_veio(uvd, 0, 0x19, 0x012c);
-
- ibmcam_Packet_Format1(uvd, 0x00, 0x1e);
- ibmcam_Packet_Format1(uvd, 0x39, 0x0d);
- ibmcam_Packet_Format1(uvd, 0x39, 0x09);
- ibmcam_Packet_Format1(uvd, 0x3b, 0x00);
- ibmcam_Packet_Format1(uvd, 0x28, 0x22);
- ibmcam_Packet_Format1(uvd, light_27, 0);
- ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
- ibmcam_Packet_Format1(uvd, 0x39, 0x08);
-
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x2c, 0x00);
-
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x30, 0x14);
-
- ibmcam_PacketFormat2(uvd, 0x39, 0x02);
- ibmcam_PacketFormat2(uvd, 0x01, 0xe1);
- ibmcam_PacketFormat2(uvd, 0x02, 0xcd);
- ibmcam_PacketFormat2(uvd, 0x03, 0xcd);
- ibmcam_PacketFormat2(uvd, 0x04, 0xfa);
- ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
- ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
- ibmcam_PacketFormat2(uvd, 0x39, 0x02);
- ibmcam_PacketFormat2(uvd, 0x0a, 0x37);
- ibmcam_PacketFormat2(uvd, 0x0b, 0xb8);
- ibmcam_PacketFormat2(uvd, 0x0c, 0xf3);
- ibmcam_PacketFormat2(uvd, 0x0d, 0xe3);
- ibmcam_PacketFormat2(uvd, 0x0e, 0x0d);
- ibmcam_PacketFormat2(uvd, 0x0f, 0xf2);
- ibmcam_PacketFormat2(uvd, 0x10, 0xd5);
- ibmcam_PacketFormat2(uvd, 0x11, 0xba);
- ibmcam_PacketFormat2(uvd, 0x12, 0x53);
- ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
- ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
- ibmcam_PacketFormat2(uvd, 0x39, 0x02);
- ibmcam_PacketFormat2(uvd, 0x16, 0x00);
- ibmcam_PacketFormat2(uvd, 0x17, 0x28);
- ibmcam_PacketFormat2(uvd, 0x18, 0x7d);
- ibmcam_PacketFormat2(uvd, 0x19, 0xbe);
- ibmcam_PacketFormat2(uvd, 0x3f, 0xff);
- ibmcam_PacketFormat2(uvd, 0x39, 0x00);
-
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x00, 0x18);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x13, 0x18);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x14, 0x06);
-
- /* This is default brightness */
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x31, 0x37);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x32, 0x46);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x33, 0x55);
-
- ibmcam_Packet_Format1(uvd, 0x2e, 0x04);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x2d, 0x04);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x29, 0x80);
- ibmcam_Packet_Format1(uvd, 0x2c, 0x01);
- ibmcam_Packet_Format1(uvd, 0x30, 0x17);
- ibmcam_Packet_Format1(uvd, 0x39, 0x08);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x34, 0x00);
-
- ibmcam_veio(uvd, 0, 0x00, 0x0101);
- ibmcam_veio(uvd, 0, 0x00, 0x010a);
-
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- ibmcam_veio(uvd, 0, 0x80, 0x0103);
- ibmcam_veio(uvd, 0, 0x60, 0x0105);
- ibmcam_veio(uvd, 0, 0x0c, 0x010b);
- ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x0b, 0x011d);
- ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x00, 0x0129);
- break;
- case VIDEOSIZE_176x144:
- ibmcam_veio(uvd, 0, 0xb0, 0x0103);
- ibmcam_veio(uvd, 0, 0x8f, 0x0105);
- ibmcam_veio(uvd, 0, 0x06, 0x010b);
- ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x0d, 0x011d);
- ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x03, 0x0129);
- break;
- case VIDEOSIZE_352x288:
- ibmcam_veio(uvd, 0, 0xb0, 0x0103);
- ibmcam_veio(uvd, 0, 0x90, 0x0105);
- ibmcam_veio(uvd, 0, 0x02, 0x010b);
- ibmcam_veio(uvd, 0, 0x04, 0x011b); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x05, 0x011d);
- ibmcam_veio(uvd, 0, 0x00, 0x011e); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x00, 0x0129);
- break;
- }
-
- ibmcam_veio(uvd, 0, 0xff, 0x012b);
-
- /* This is another brightness - don't know why */
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x31, 0xc3);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x32, 0xd2);
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, 0x33, 0xe1);
-
- /* Default contrast */
- for (i=0; i < ntries; i++)
- ibmcam_Packet_Format1(uvd, contrast_14, 0x0a);
-
- /* Default sharpness */
- for (i=0; i < 2; i++)
- ibmcam_PacketFormat2(uvd, sharp_13, 0x1a); /* Level 4 FIXME */
-
- /* Default lighting conditions */
- ibmcam_Packet_Format1(uvd, light_27, lighting); /* 0=Bright 2=Low */
-
- /* Assorted init */
-
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
- ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x36, 0x0102);
- ibmcam_veio(uvd, 0, 0x1a, 0x0104);
- ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x2b, 0x011c);
- ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */
-#if 0
- ibmcam_veio(uvd, 0, 0x00, 0x0106);
- ibmcam_veio(uvd, 0, 0x38, 0x0107);
-#else
- ibmcam_veio(uvd, 0, 0x02, 0x0106);
- ibmcam_veio(uvd, 0, 0x2a, 0x0107);
-#endif
- break;
- case VIDEOSIZE_176x144:
- ibmcam_Packet_Format1(uvd, 0x2b, 0x1e);
- ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x04, 0x0102);
- ibmcam_veio(uvd, 0, 0x02, 0x0104);
- ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x2b, 0x011c);
- ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x01, 0x0106);
- ibmcam_veio(uvd, 0, 0xca, 0x0107);
- break;
- case VIDEOSIZE_352x288:
- ibmcam_Packet_Format1(uvd, 0x2b, 0x1f);
- ibmcam_veio(uvd, 0, 0xc9, 0x0119); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x80, 0x0109); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x08, 0x0102);
- ibmcam_veio(uvd, 0, 0x01, 0x0104);
- ibmcam_veio(uvd, 0, 0x04, 0x011a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x2f, 0x011c);
- ibmcam_veio(uvd, 0, 0x23, 0x012a); /* Same everywhere */
- ibmcam_veio(uvd, 0, 0x03, 0x0106);
- ibmcam_veio(uvd, 0, 0xf6, 0x0107);
- break;
- }
- return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
-}
-
-static int ibmcam_model2_setup(struct uvd *uvd)
-{
- ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */
- ibmcam_veio(uvd, 1, 0x0000, 0x0116);
- ibmcam_veio(uvd, 0, 0x0060, 0x0116);
- ibmcam_veio(uvd, 0, 0x0002, 0x0112);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0008, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */
- ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */
- ibmcam_veio(uvd, 0, 0x00b9, 0x010a); /* Unique to this mode */
- ibmcam_veio(uvd, 0, 0x0038, 0x0119); /* Unique to this mode */
- ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */
- ibmcam_veio(uvd, 0, 0x0090, 0x0107); /* Unique to every mode*/
- break;
- case VIDEOSIZE_320x240:
- ibmcam_veio(uvd, 0, 0x0028, 0x0103); /* Unique to this mode */
- ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */
- ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */
- ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */
- ibmcam_veio(uvd, 0, 0x0098, 0x0107); /* Unique to every mode*/
- break;
- case VIDEOSIZE_352x240:
- ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */
- ibmcam_veio(uvd, 0, 0x001e, 0x0105); /* 320x240, 352x240 */
- ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */
- ibmcam_veio(uvd, 0, 0x00da, 0x0107); /* Unique to every mode*/
- break;
- case VIDEOSIZE_352x288:
- ibmcam_veio(uvd, 0, 0x002c, 0x0103); /* All except 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0104); /* Same */
- ibmcam_veio(uvd, 0, 0x0024, 0x0105); /* 176x144, 352x288 */
- ibmcam_veio(uvd, 0, 0x0039, 0x010a); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0070, 0x0119); /* All except 176x144 */
- ibmcam_veio(uvd, 0, 0x0003, 0x0106); /* Same */
- ibmcam_veio(uvd, 0, 0x00fe, 0x0107); /* Unique to every mode*/
- break;
- }
- return (CAMERA_IS_OPERATIONAL(uvd) ? 0 : -EFAULT);
-}
-
-/*
- * ibmcam_model1_setup_after_video_if()
- *
- * This code adds finishing touches to the video data interface.
- * Here we configure the frame rate and turn on the LED.
- */
-static void ibmcam_model1_setup_after_video_if(struct uvd *uvd)
-{
- unsigned short internal_frame_rate;
-
- RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
- internal_frame_rate = FRAMERATE_MAX - framerate; /* 0=Fast 6=Slow */
- ibmcam_veio(uvd, 0, 0x01, 0x0100); /* LED On */
- ibmcam_veio(uvd, 0, internal_frame_rate, 0x0111);
- ibmcam_veio(uvd, 0, 0x01, 0x0114);
- ibmcam_veio(uvd, 0, 0xc0, 0x010c);
-}
-
-static void ibmcam_model2_setup_after_video_if(struct uvd *uvd)
-{
- unsigned short setup_model2_rg2, setup_model2_sat, setup_model2_yb;
-
- ibmcam_veio(uvd, 0, 0x0000, 0x0100); /* LED on */
-
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- ibmcam_veio(uvd, 0, 0x0050, 0x0111);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- break;
- case VIDEOSIZE_320x240:
- case VIDEOSIZE_352x240:
- case VIDEOSIZE_352x288:
- ibmcam_veio(uvd, 0, 0x0040, 0x0111);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- break;
- }
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
-
- /*
- * Hardware settings, may affect CMOS sensor; not user controls!
- * -------------------------------------------------------------
- * 0x0004: no effect
- * 0x0006: hardware effect
- * 0x0008: no effect
- * 0x000a: stops video stream, probably important h/w setting
- * 0x000c: changes color in hardware manner (not user setting)
- * 0x0012: changes number of colors (does not affect speed)
- * 0x002a: no effect
- * 0x002c: hardware setting (related to scan lines)
- * 0x002e: stops video stream, probably important h/w setting
- */
- ibmcam_model2_Packet1(uvd, 0x000a, 0x005c);
- ibmcam_model2_Packet1(uvd, 0x0004, 0x0000);
- ibmcam_model2_Packet1(uvd, 0x0006, 0x00fb);
- ibmcam_model2_Packet1(uvd, 0x0008, 0x0000);
- ibmcam_model2_Packet1(uvd, 0x000c, 0x0009);
- ibmcam_model2_Packet1(uvd, 0x0012, 0x000a);
- ibmcam_model2_Packet1(uvd, 0x002a, 0x0000);
- ibmcam_model2_Packet1(uvd, 0x002c, 0x0000);
- ibmcam_model2_Packet1(uvd, 0x002e, 0x0008);
-
- /*
- * Function 0x0030 pops up all over the place. Apparently
- * it is a hardware control register, with every bit assigned to
- * do something.
- */
- ibmcam_model2_Packet1(uvd, 0x0030, 0x0000);
-
- /*
- * Magic control of CMOS sensor. Only lower values like
- * 0-3 work, and picture shifts left or right. Don't change.
- */
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- ibmcam_model2_Packet1(uvd, 0x0014, 0x0002);
- ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
- ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
- break;
- case VIDEOSIZE_320x240:
- ibmcam_model2_Packet1(uvd, 0x0014, 0x0009);
- ibmcam_model2_Packet1(uvd, 0x0016, 0x0005); /* Horizontal shift */
- ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Another hardware setting */
- break;
- case VIDEOSIZE_352x240:
- /* This mode doesn't work as Windows programs it; changed to work */
- ibmcam_model2_Packet1(uvd, 0x0014, 0x0009); /* Windows sets this to 8 */
- ibmcam_model2_Packet1(uvd, 0x0016, 0x0003); /* Horizontal shift */
- ibmcam_model2_Packet1(uvd, 0x0018, 0x0044); /* Windows sets this to 0x0045 */
- break;
- case VIDEOSIZE_352x288:
- ibmcam_model2_Packet1(uvd, 0x0014, 0x0003);
- ibmcam_model2_Packet1(uvd, 0x0016, 0x0002); /* Horizontal shift */
- ibmcam_model2_Packet1(uvd, 0x0018, 0x004a); /* Another hardware setting */
- break;
- }
-
- ibmcam_model2_Packet1(uvd, mod2_brightness, 0x005a);
-
- /*
- * We have our own frame rate setting varying from 0 (slowest) to 6 (fastest).
- * The camera model 2 allows frame rate in range [0..0x1F] where 0 is also the
- * slowest setting. However for all practical reasons high settings make no
- * sense because USB is not fast enough to support high FPS. Be aware that
- * the picture datastream will be severely disrupted if you ask for
- * frame rate faster than allowed for the video size - see below:
- *
- * Allowable ranges (obtained experimentally on OHCI, K6-3, 450 MHz):
- * -----------------------------------------------------------------
- * 176x144: [6..31]
- * 320x240: [8..31]
- * 352x240: [10..31]
- * 352x288: [16..31] I have to raise lower threshold for stability...
- *
- * As usual, slower FPS provides better sensitivity.
- */
- {
- short hw_fps=31, i_framerate;
-
- RESTRICT_TO_RANGE(framerate, FRAMERATE_MIN, FRAMERATE_MAX);
- i_framerate = FRAMERATE_MAX - framerate + FRAMERATE_MIN;
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- hw_fps = 6 + i_framerate*4;
- break;
- case VIDEOSIZE_320x240:
- hw_fps = 8 + i_framerate*3;
- break;
- case VIDEOSIZE_352x240:
- hw_fps = 10 + i_framerate*2;
- break;
- case VIDEOSIZE_352x288:
- hw_fps = 28 + i_framerate/2;
- break;
- }
- if (uvd->debug > 0)
- dev_info(&uvd->dev->dev, "Framerate (hardware): %hd.\n",
- hw_fps);
- RESTRICT_TO_RANGE(hw_fps, 0, 31);
- ibmcam_model2_Packet1(uvd, mod2_set_framerate, hw_fps);
- }
-
- /*
- * This setting does not visibly affect pictures; left it here
- * because it was present in Windows USB data stream. This function
- * does not allow arbitrary values and apparently is a bit mask, to
- * be activated only at appropriate time. Don't change it randomly!
- */
- switch (uvd->videosize) {
- case VIDEOSIZE_176x144:
- ibmcam_model2_Packet1(uvd, 0x0026, 0x00c2);
- break;
- case VIDEOSIZE_320x240:
- ibmcam_model2_Packet1(uvd, 0x0026, 0x0044);
- break;
- case VIDEOSIZE_352x240:
- ibmcam_model2_Packet1(uvd, 0x0026, 0x0046);
- break;
- case VIDEOSIZE_352x288:
- ibmcam_model2_Packet1(uvd, 0x0026, 0x0048);
- break;
- }
-
- ibmcam_model2_Packet1(uvd, mod2_sensitivity, lighting);
-
- if (init_model2_rg2 >= 0) {
- RESTRICT_TO_RANGE(init_model2_rg2, 0, 255);
- setup_model2_rg2 = init_model2_rg2;
- } else
- setup_model2_rg2 = 0x002f;
-
- if (init_model2_sat >= 0) {
- RESTRICT_TO_RANGE(init_model2_sat, 0, 255);
- setup_model2_sat = init_model2_sat;
- } else
- setup_model2_sat = 0x0034;
-
- if (init_model2_yb >= 0) {
- RESTRICT_TO_RANGE(init_model2_yb, 0, 255);
- setup_model2_yb = init_model2_yb;
- } else
- setup_model2_yb = 0x00a0;
-
- ibmcam_model2_Packet1(uvd, mod2_color_balance_rg2, setup_model2_rg2);
- ibmcam_model2_Packet1(uvd, mod2_saturation, setup_model2_sat);
- ibmcam_model2_Packet1(uvd, mod2_color_balance_yb, setup_model2_yb);
- ibmcam_model2_Packet1(uvd, mod2_hue, uvd->vpic.hue >> 9); /* 0 .. 7F */;
-
- /* Hardware control command */
- ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
-
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c); /* Go camera, go! */
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-static void ibmcam_model4_setup_after_video_if(struct uvd *uvd)
-{
- switch (uvd->videosize) {
- case VIDEOSIZE_128x96:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0070, 0x0119);
- ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x005e, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- ibmcam_veio(uvd, 0, 0x0039, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x0028, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x001e, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x000a, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005a, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0043, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0017, 0x0127);
- ibmcam_veio(uvd, 0, 0x0013, 0x012e);
- ibmcam_veio(uvd, 0, 0x0031, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0017, 0x012d);
- ibmcam_veio(uvd, 0, 0x0078, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- case VIDEOSIZE_160x120:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0038, 0x0119);
- ibmcam_veio(uvd, 0, 0x00d8, 0x0107);
- ibmcam_veio(uvd, 0, 0x0002, 0x0106);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x0028, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x001e, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x000b, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005a, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0043, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0025, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0048, 0x0127);
- ibmcam_veio(uvd, 0, 0x0035, 0x012e);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0048, 0x012d);
- ibmcam_veio(uvd, 0, 0x0090, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0001, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- case VIDEOSIZE_176x144:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0038, 0x0119);
- ibmcam_veio(uvd, 0, 0x00d6, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x0018, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00b9, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x002c, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x0024, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0007, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0001, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005e, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0049, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00c7, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0028, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0010, 0x0127);
- ibmcam_veio(uvd, 0, 0x0013, 0x012e);
- ibmcam_veio(uvd, 0, 0x002a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0010, 0x012d);
- ibmcam_veio(uvd, 0, 0x006d, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0001, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- case VIDEOSIZE_320x240:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0070, 0x0119);
- ibmcam_veio(uvd, 0, 0x00d2, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x005e, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x00d0, 0x0111);
- ibmcam_veio(uvd, 0, 0x0039, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x0028, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x001e, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x000a, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005a, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0043, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00eb, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0017, 0x0127);
- ibmcam_veio(uvd, 0, 0x0013, 0x012e);
- ibmcam_veio(uvd, 0, 0x0031, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0017, 0x012d);
- ibmcam_veio(uvd, 0, 0x0078, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- case VIDEOSIZE_352x288:
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x00bc, 0x012c);
- ibmcam_veio(uvd, 0, 0x0080, 0x012b);
- ibmcam_veio(uvd, 0, 0x0000, 0x0108);
- ibmcam_veio(uvd, 0, 0x0001, 0x0133);
- ibmcam_veio(uvd, 0, 0x009b, 0x010f);
- ibmcam_veio(uvd, 0, 0x00bb, 0x010f);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x000a, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x005c, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0004, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00fb, 0x012e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x000c, 0x0127);
- ibmcam_veio(uvd, 0, 0x0009, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0012, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0008, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x002a, 0x012d);
- ibmcam_veio(uvd, 0, 0x0000, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0034, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0070, 0x0119);
- ibmcam_veio(uvd, 0, 0x00f2, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x008c, 0x0107);
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x00c0, 0x0111);
- ibmcam_veio(uvd, 0, 0x0039, 0x010a);
- ibmcam_veio(uvd, 0, 0x0001, 0x0102);
- ibmcam_veio(uvd, 0, 0x002c, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0104);
- ibmcam_veio(uvd, 0, 0x0024, 0x0105);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0016, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0006, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0014, 0x012d);
- ibmcam_veio(uvd, 0, 0x0002, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012e);
- ibmcam_veio(uvd, 0, 0x001a, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a0a, 0x0124);
- ibmcam_veio(uvd, 0, 0x005e, 0x012d);
- ibmcam_veio(uvd, 0, 0x9545, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0127);
- ibmcam_veio(uvd, 0, 0x0018, 0x012e);
- ibmcam_veio(uvd, 0, 0x0049, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012f);
- ibmcam_veio(uvd, 0, 0xd055, 0x0124);
- ibmcam_veio(uvd, 0, 0x001c, 0x0127);
- ibmcam_veio(uvd, 0, 0x00cf, 0x012e);
- ibmcam_veio(uvd, 0, 0xaa28, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0032, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0x00aa, 0x0130);
- ibmcam_veio(uvd, 0, 0x82a8, 0x0124);
- ibmcam_veio(uvd, 0, 0x0036, 0x012d);
- ibmcam_veio(uvd, 0, 0x0008, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0xfffa, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x001e, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0010, 0x0127);
- ibmcam_veio(uvd, 0, 0x0013, 0x012e);
- ibmcam_veio(uvd, 0, 0x0025, 0x0130);
- ibmcam_veio(uvd, 0, 0x8a28, 0x0124);
- ibmcam_veio(uvd, 0, 0x0010, 0x012d);
- ibmcam_veio(uvd, 0, 0x0048, 0x012f);
- ibmcam_veio(uvd, 0, 0xd145, 0x0124);
- ibmcam_veio(uvd, 0, 0x0000, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00aa, 0x012d);
- ibmcam_veio(uvd, 0, 0x0038, 0x012f);
- ibmcam_veio(uvd, 0, 0xd141, 0x0124);
- ibmcam_veio(uvd, 0, 0x0004, 0x0127);
- ibmcam_veio(uvd, 0, 0xfea8, 0x0124);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- break;
- }
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-static void ibmcam_model3_setup_after_video_if(struct uvd *uvd)
-{
- int i;
- /*
- * 01.01.08 - Added for RCA video in support -LO
- * This struct is used to init the Model3 cam to use the RCA video in port
- * instead of the CCD sensor.
- */
- static const struct struct_initData initData[] = {
- {0, 0x0000, 0x010c},
- {0, 0x0006, 0x012c},
- {0, 0x0078, 0x012d},
- {0, 0x0046, 0x012f},
- {0, 0xd141, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfea8, 0x0124},
- {1, 0x0000, 0x0116},
- {0, 0x0064, 0x0116},
- {1, 0x0000, 0x0115},
- {0, 0x0003, 0x0115},
- {0, 0x0008, 0x0123},
- {0, 0x0000, 0x0117},
- {0, 0x0000, 0x0112},
- {0, 0x0080, 0x0100},
- {0, 0x0000, 0x0100},
- {1, 0x0000, 0x0116},
- {0, 0x0060, 0x0116},
- {0, 0x0002, 0x0112},
- {0, 0x0000, 0x0123},
- {0, 0x0001, 0x0117},
- {0, 0x0040, 0x0108},
- {0, 0x0019, 0x012c},
- {0, 0x0040, 0x0116},
- {0, 0x000a, 0x0115},
- {0, 0x000b, 0x0115},
- {0, 0x0078, 0x012d},
- {0, 0x0046, 0x012f},
- {0, 0xd141, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfea8, 0x0124},
- {0, 0x0064, 0x0116},
- {0, 0x0000, 0x0115},
- {0, 0x0001, 0x0115},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00aa, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00f2, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x000f, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00f8, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00fc, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00f9, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x003c, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xffff, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0027, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0019, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0021, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0006, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0045, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002a, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x000e, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002b, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00f4, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002c, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0004, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002d, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0014, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002e, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0003, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x002f, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0003, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0014, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0053, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0x0000, 0x0101},
- {0, 0x00a0, 0x0103},
- {0, 0x0078, 0x0105},
- {0, 0x0000, 0x010a},
- {0, 0x0024, 0x010b},
- {0, 0x0028, 0x0119},
- {0, 0x0088, 0x011b},
- {0, 0x0002, 0x011d},
- {0, 0x0003, 0x011e},
- {0, 0x0000, 0x0129},
- {0, 0x00fc, 0x012b},
- {0, 0x0008, 0x0102},
- {0, 0x0000, 0x0104},
- {0, 0x0008, 0x011a},
- {0, 0x0028, 0x011c},
- {0, 0x0021, 0x012a},
- {0, 0x0000, 0x0118},
- {0, 0x0000, 0x0132},
- {0, 0x0000, 0x0109},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0031, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x00dc, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0032, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0020, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0001, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0040, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0037, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0030, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0xfff9, 0x0124},
- {0, 0x0086, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0038, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0008, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0x0000, 0x0127},
- {0, 0xfff8, 0x0124},
- {0, 0xfffd, 0x0124},
- {0, 0xfffa, 0x0124},
- {0, 0x0003, 0x0106},
- {0, 0x0062, 0x0107},
- {0, 0x0003, 0x0111},
- };
-#define NUM_INIT_DATA
-
- unsigned short compression = 0; /* 0=none, 7=best frame rate */
- int f_rate; /* 0=Fastest 7=slowest */
-
- if (IBMCAM_T(uvd)->initialized)
- return;
-
- /* Internal frame rate is controlled by f_rate value */
- f_rate = 7 - framerate;
- RESTRICT_TO_RANGE(f_rate, 0, 7);
-
- ibmcam_veio(uvd, 0, 0x0000, 0x0100);
- ibmcam_veio(uvd, 1, 0x0000, 0x0116);
- ibmcam_veio(uvd, 0, 0x0060, 0x0116);
- ibmcam_veio(uvd, 0, 0x0002, 0x0112);
- ibmcam_veio(uvd, 0, 0x0000, 0x0123);
- ibmcam_veio(uvd, 0, 0x0001, 0x0117);
- ibmcam_veio(uvd, 0, 0x0040, 0x0108);
- ibmcam_veio(uvd, 0, 0x0019, 0x012c);
- ibmcam_veio(uvd, 0, 0x0060, 0x0116);
- ibmcam_veio(uvd, 0, 0x0002, 0x0115);
- ibmcam_veio(uvd, 0, 0x0003, 0x0115);
- ibmcam_veio(uvd, 1, 0x0000, 0x0115);
- ibmcam_veio(uvd, 0, 0x000b, 0x0115);
- ibmcam_model3_Packet1(uvd, 0x000a, 0x0040);
- ibmcam_model3_Packet1(uvd, 0x000b, 0x00f6);
- ibmcam_model3_Packet1(uvd, 0x000c, 0x0002);
- ibmcam_model3_Packet1(uvd, 0x000d, 0x0020);
- ibmcam_model3_Packet1(uvd, 0x000e, 0x0033);
- ibmcam_model3_Packet1(uvd, 0x000f, 0x0007);
- ibmcam_model3_Packet1(uvd, 0x0010, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0011, 0x0070);
- ibmcam_model3_Packet1(uvd, 0x0012, 0x0030);
- ibmcam_model3_Packet1(uvd, 0x0013, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0014, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x0015, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x0016, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x0017, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x0018, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x001e, 0x00c3);
- ibmcam_model3_Packet1(uvd, 0x0020, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0028, 0x0010);
- ibmcam_model3_Packet1(uvd, 0x0029, 0x0054);
- ibmcam_model3_Packet1(uvd, 0x002a, 0x0013);
- ibmcam_model3_Packet1(uvd, 0x002b, 0x0007);
- ibmcam_model3_Packet1(uvd, 0x002d, 0x0028);
- ibmcam_model3_Packet1(uvd, 0x002e, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0031, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0032, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0033, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0034, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0035, 0x0038);
- ibmcam_model3_Packet1(uvd, 0x003a, 0x0001);
- ibmcam_model3_Packet1(uvd, 0x003c, 0x001e);
- ibmcam_model3_Packet1(uvd, 0x003f, 0x000a);
- ibmcam_model3_Packet1(uvd, 0x0041, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0046, 0x003f);
- ibmcam_model3_Packet1(uvd, 0x0047, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0050, 0x0005);
- ibmcam_model3_Packet1(uvd, 0x0052, 0x001a);
- ibmcam_model3_Packet1(uvd, 0x0053, 0x0003);
- ibmcam_model3_Packet1(uvd, 0x005a, 0x006b);
- ibmcam_model3_Packet1(uvd, 0x005d, 0x001e);
- ibmcam_model3_Packet1(uvd, 0x005e, 0x0030);
- ibmcam_model3_Packet1(uvd, 0x005f, 0x0041);
- ibmcam_model3_Packet1(uvd, 0x0064, 0x0008);
- ibmcam_model3_Packet1(uvd, 0x0065, 0x0015);
- ibmcam_model3_Packet1(uvd, 0x0068, 0x000f);
- ibmcam_model3_Packet1(uvd, 0x0079, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x007a, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x007c, 0x003f);
- ibmcam_model3_Packet1(uvd, 0x0082, 0x000f);
- ibmcam_model3_Packet1(uvd, 0x0085, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x0099, 0x0000);
- ibmcam_model3_Packet1(uvd, 0x009b, 0x0023);
- ibmcam_model3_Packet1(uvd, 0x009c, 0x0022);
- ibmcam_model3_Packet1(uvd, 0x009d, 0x0096);
- ibmcam_model3_Packet1(uvd, 0x009e, 0x0096);
- ibmcam_model3_Packet1(uvd, 0x009f, 0x000a);
-
- switch (uvd->videosize) {
- case VIDEOSIZE_160x120:
- ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
- ibmcam_veio(uvd, 0, 0x0024, 0x010b); /* Differs everywhere */
- ibmcam_veio(uvd, 0, 0x00a9, 0x0119);
- ibmcam_veio(uvd, 0, 0x0016, 0x011b);
- ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
- ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
- ibmcam_veio(uvd, 0, 0x0018, 0x0102);
- ibmcam_veio(uvd, 0, 0x0004, 0x0104);
- ibmcam_veio(uvd, 0, 0x0004, 0x011a);
- ibmcam_veio(uvd, 0, 0x0028, 0x011c);
- ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
- ibmcam_veio(uvd, 0, 0x0000, 0x0118);
- ibmcam_veio(uvd, 0, 0x0000, 0x0132);
- ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
- ibmcam_veio(uvd, 0, compression, 0x0109);
- break;
- case VIDEOSIZE_320x240:
- ibmcam_veio(uvd, 0, 0x0000, 0x0101); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x00a0, 0x0103); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0078, 0x0105); /* Same on 176x144, 320x240 */
- ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
- ibmcam_veio(uvd, 0, 0x0028, 0x010b); /* Differs everywhere */
- ibmcam_veio(uvd, 0, 0x0002, 0x011d); /* Same */
- ibmcam_veio(uvd, 0, 0x0000, 0x011e);
- ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
- ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
- /* 4 commands from 160x120 skipped */
- ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
- ibmcam_veio(uvd, 0, compression, 0x0109);
- ibmcam_veio(uvd, 0, 0x00d9, 0x0119);
- ibmcam_veio(uvd, 0, 0x0006, 0x011b);
- ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0010, 0x0104);
- ibmcam_veio(uvd, 0, 0x0004, 0x011a);
- ibmcam_veio(uvd, 0, 0x003f, 0x011c);
- ibmcam_veio(uvd, 0, 0x001c, 0x0118);
- ibmcam_veio(uvd, 0, 0x0000, 0x0132);
- break;
- case VIDEOSIZE_640x480:
- ibmcam_veio(uvd, 0, 0x00f0, 0x0105);
- ibmcam_veio(uvd, 0, 0x0000, 0x010a); /* Same */
- ibmcam_veio(uvd, 0, 0x0038, 0x010b); /* Differs everywhere */
- ibmcam_veio(uvd, 0, 0x00d9, 0x0119); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0006, 0x011b); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0004, 0x011d); /* NC */
- ibmcam_veio(uvd, 0, 0x0003, 0x011e); /* Same on 176x144, 640x480 */
- ibmcam_veio(uvd, 0, 0x0000, 0x0129); /* Same */
- ibmcam_veio(uvd, 0, 0x00fc, 0x012b); /* Same */
- ibmcam_veio(uvd, 0, 0x0021, 0x0102); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0016, 0x0104); /* NC */
- ibmcam_veio(uvd, 0, 0x0004, 0x011a); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x003f, 0x011c); /* Same on 320x240, 640x480 */
- ibmcam_veio(uvd, 0, 0x0022, 0x012a); /* Same */
- ibmcam_veio(uvd, 0, 0x001c, 0x0118); /* Same on 320x240, 640x480 */
- ibmcam_model3_Packet1(uvd, 0x0021, 0x0001); /* Same */
- ibmcam_veio(uvd, 0, compression, 0x0109);
- ibmcam_veio(uvd, 0, 0x0040, 0x0101);
- ibmcam_veio(uvd, 0, 0x0040, 0x0103);
- ibmcam_veio(uvd, 0, 0x0000, 0x0132); /* Same on 320x240, 640x480 */
- break;
- }
- ibmcam_model3_Packet1(uvd, 0x007e, 0x000e); /* Hue */
- ibmcam_model3_Packet1(uvd, 0x0036, 0x0011); /* Brightness */
- ibmcam_model3_Packet1(uvd, 0x0060, 0x0002); /* Sharpness */
- ibmcam_model3_Packet1(uvd, 0x0061, 0x0004); /* Sharpness */
- ibmcam_model3_Packet1(uvd, 0x0062, 0x0005); /* Sharpness */
- ibmcam_model3_Packet1(uvd, 0x0063, 0x0014); /* Sharpness */
- ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */
- ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */
- ibmcam_model3_Packet1(uvd, 0x0067, 0x0001); /* Contrast */
- ibmcam_model3_Packet1(uvd, 0x005b, 0x000c); /* Contrast */
- ibmcam_model3_Packet1(uvd, 0x005c, 0x0016); /* Contrast */
- ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
- ibmcam_model3_Packet1(uvd, 0x002c, 0x0003); /* Was 1, broke 640x480 */
- ibmcam_model3_Packet1(uvd, 0x002f, 0x002a);
- ibmcam_model3_Packet1(uvd, 0x0030, 0x0029);
- ibmcam_model3_Packet1(uvd, 0x0037, 0x0002);
- ibmcam_model3_Packet1(uvd, 0x0038, 0x0059);
- ibmcam_model3_Packet1(uvd, 0x003d, 0x002e);
- ibmcam_model3_Packet1(uvd, 0x003e, 0x0028);
- ibmcam_model3_Packet1(uvd, 0x0078, 0x0005);
- ibmcam_model3_Packet1(uvd, 0x007b, 0x0011);
- ibmcam_model3_Packet1(uvd, 0x007d, 0x004b);
- ibmcam_model3_Packet1(uvd, 0x007f, 0x0022);
- ibmcam_model3_Packet1(uvd, 0x0080, 0x000c);
- ibmcam_model3_Packet1(uvd, 0x0081, 0x000b);
- ibmcam_model3_Packet1(uvd, 0x0083, 0x00fd);
- ibmcam_model3_Packet1(uvd, 0x0086, 0x000b);
- ibmcam_model3_Packet1(uvd, 0x0087, 0x000b);
- ibmcam_model3_Packet1(uvd, 0x007e, 0x000e);
- ibmcam_model3_Packet1(uvd, 0x0096, 0x00a0); /* Red gain */
- ibmcam_model3_Packet1(uvd, 0x0097, 0x0096); /* Blue gain */
- ibmcam_model3_Packet1(uvd, 0x0098, 0x000b);
-
- switch (uvd->videosize) {
- case VIDEOSIZE_160x120:
- ibmcam_veio(uvd, 0, 0x0002, 0x0106);
- ibmcam_veio(uvd, 0, 0x0008, 0x0107);
- ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */
- ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
- ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0040, 0x000a);
- ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
- break;
- case VIDEOSIZE_320x240:
- ibmcam_veio(uvd, 0, 0x0003, 0x0106);
- ibmcam_veio(uvd, 0, 0x0062, 0x0107);
- ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */
- ibmcam_model3_Packet1(uvd, 0x001f, 0x0000); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0039, 0x001f); /* Same */
- ibmcam_model3_Packet1(uvd, 0x003b, 0x003c); /* Same */
- ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
- ibmcam_model3_Packet1(uvd, 0x0051, 0x000b);
- break;
- case VIDEOSIZE_640x480:
- ibmcam_veio(uvd, 0, 0x0002, 0x0106); /* Adjustments */
- ibmcam_veio(uvd, 0, 0x00b4, 0x0107); /* Adjustments */
- ibmcam_veio(uvd, 0, f_rate, 0x0111); /* Frame rate */
- ibmcam_model3_Packet1(uvd, 0x001f, 0x0002); /* !Same */
- ibmcam_model3_Packet1(uvd, 0x0039, 0x003e); /* !Same */
- ibmcam_model3_Packet1(uvd, 0x0040, 0x0008);
- ibmcam_model3_Packet1(uvd, 0x0051, 0x000a);
- break;
- }
-
- /* 01.01.08 - Added for RCA video in support -LO */
- if(init_model3_input) {
- if (debug > 0)
- dev_info(&uvd->dev->dev, "Setting input to RCA.\n");
- for (i=0; i < ARRAY_SIZE(initData); i++) {
- ibmcam_veio(uvd, initData[i].req, initData[i].value, initData[i].index);
- }
- }
-
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
-}
-
-/*
- * ibmcam_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void ibmcam_video_stop(struct uvd *uvd)
-{
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- ibmcam_veio(uvd, 0, 0x00, 0x010c);
- ibmcam_veio(uvd, 0, 0x00, 0x010c);
- ibmcam_veio(uvd, 0, 0x01, 0x0114);
- ibmcam_veio(uvd, 0, 0xc0, 0x010c);
- ibmcam_veio(uvd, 0, 0x00, 0x010c);
- ibmcam_send_FF_04_02(uvd);
- ibmcam_veio(uvd, 1, 0x00, 0x0100);
- ibmcam_veio(uvd, 0, 0x81, 0x0100); /* LED Off */
- break;
- case IBMCAM_MODEL_2:
-case IBMCAM_MODEL_4:
- ibmcam_veio(uvd, 0, 0x0000, 0x010c); /* Stop the camera */
-
- ibmcam_model2_Packet1(uvd, 0x0030, 0x0004);
-
- ibmcam_veio(uvd, 0, 0x0080, 0x0100); /* LED Off */
- ibmcam_veio(uvd, 0, 0x0020, 0x0111);
- ibmcam_veio(uvd, 0, 0x00a0, 0x0111);
-
- ibmcam_model2_Packet1(uvd, 0x0030, 0x0002);
-
- ibmcam_veio(uvd, 0, 0x0020, 0x0111);
- ibmcam_veio(uvd, 0, 0x0000, 0x0112);
- break;
- case IBMCAM_MODEL_3:
-#if 1
- ibmcam_veio(uvd, 0, 0x0000, 0x010c);
-
- /* Here we are supposed to select video interface alt. setting 0 */
- ibmcam_veio(uvd, 0, 0x0006, 0x012c);
-
- ibmcam_model3_Packet1(uvd, 0x0046, 0x0000);
-
- ibmcam_veio(uvd, 1, 0x0000, 0x0116);
- ibmcam_veio(uvd, 0, 0x0064, 0x0116);
- ibmcam_veio(uvd, 1, 0x0000, 0x0115);
- ibmcam_veio(uvd, 0, 0x0003, 0x0115);
- ibmcam_veio(uvd, 0, 0x0008, 0x0123);
- ibmcam_veio(uvd, 0, 0x0000, 0x0117);
- ibmcam_veio(uvd, 0, 0x0000, 0x0112);
- ibmcam_veio(uvd, 0, 0x0080, 0x0100);
- IBMCAM_T(uvd)->initialized = 0;
-#endif
- break;
- } /* switch */
-}
-
-/*
- * ibmcam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- *
- * History:
- * 1/2/00 Created.
- */
-static void ibmcam_reinit_iso(struct uvd *uvd, int do_stop)
-{
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- if (do_stop)
- ibmcam_video_stop(uvd);
- ibmcam_veio(uvd, 0, 0x0001, 0x0114);
- ibmcam_veio(uvd, 0, 0x00c0, 0x010c);
- usb_clear_halt(uvd->dev, usb_rcvisocpipe(uvd->dev, uvd->video_endp));
- ibmcam_model1_setup_after_video_if(uvd);
- break;
- case IBMCAM_MODEL_2:
- ibmcam_model2_setup_after_video_if(uvd);
- break;
- case IBMCAM_MODEL_3:
- ibmcam_video_stop(uvd);
- ibmcam_model3_setup_after_video_if(uvd);
- break;
- case IBMCAM_MODEL_4:
- ibmcam_model4_setup_after_video_if(uvd);
- break;
- }
-}
-
-static void ibmcam_video_start(struct uvd *uvd)
-{
- ibmcam_change_lighting_conditions(uvd);
- ibmcam_set_sharpness(uvd);
- ibmcam_reinit_iso(uvd, 0);
-}
-
-/*
- * Return negative code on failure, 0 on success.
- */
-static int ibmcam_setup_on_open(struct uvd *uvd)
-{
- int setup_ok = 0; /* Success by default */
- /* Send init sequence only once, it's large! */
- if (!IBMCAM_T(uvd)->initialized) { /* FIXME rename */
- switch (IBMCAM_T(uvd)->camera_model) {
- case IBMCAM_MODEL_1:
- setup_ok = ibmcam_model1_setup(uvd);
- break;
- case IBMCAM_MODEL_2:
- setup_ok = ibmcam_model2_setup(uvd);
- break;
- case IBMCAM_MODEL_3:
- case IBMCAM_MODEL_4:
- /* We do all setup when Isoc stream is requested */
- break;
- }
- IBMCAM_T(uvd)->initialized = (setup_ok != 0);
- }
- return setup_ok;
-}
-
-static void ibmcam_configure_video(struct uvd *uvd)
-{
- if (uvd == NULL)
- return;
-
- RESTRICT_TO_RANGE(init_brightness, 0, 255);
- RESTRICT_TO_RANGE(init_contrast, 0, 255);
- RESTRICT_TO_RANGE(init_color, 0, 255);
- RESTRICT_TO_RANGE(init_hue, 0, 255);
- RESTRICT_TO_RANGE(hue_correction, 0, 255);
-
- memset(&uvd->vpic, 0, sizeof(uvd->vpic));
- memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
- uvd->vpic.colour = init_color << 8;
- uvd->vpic.hue = init_hue << 8;
- uvd->vpic.brightness = init_brightness << 8;
- uvd->vpic.contrast = init_contrast << 8;
- uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
- uvd->vpic.depth = 24;
- uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
- memset(&uvd->vcap, 0, sizeof(uvd->vcap));
- strcpy(uvd->vcap.name, "IBM USB Camera");
- uvd->vcap.type = VID_TYPE_CAPTURE;
- uvd->vcap.channels = 1;
- uvd->vcap.audios = 0;
- uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
- uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
- uvd->vcap.minwidth = min_canvasWidth;
- uvd->vcap.minheight = min_canvasHeight;
-
- memset(&uvd->vchan, 0, sizeof(uvd->vchan));
- uvd->vchan.flags = 0;
- uvd->vchan.tuners = 0;
- uvd->vchan.channel = 0;
- uvd->vchan.type = VIDEO_TYPE_CAMERA;
- strcpy(uvd->vchan.name, "Camera");
-}
-
-/*
- * ibmcam_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like IBM C-it camera.
- *
- * History:
- * 22-Jan-2000 Moved camera init code to ibmcam_open()
- * 27=Jan-2000 Changed to use static structures, added locking.
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 03-Jul-2000 Fixed endianness bug.
- * 12-Nov-2000 Reworked to comply with new probe() signature.
- * 23-Jan-2001 Added compatibility with 2.2.x kernels.
- */
-static int ibmcam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct uvd *uvd = NULL;
- int ix, i, nas, model=0, canvasX=0, canvasY=0;
- int actInterface=-1, inactInterface=-1, maxPS=0;
- __u8 ifnum = intf->altsetting->desc.bInterfaceNumber;
- unsigned char video_ep = 0;
-
- if (debug >= 1)
- dev_info(&dev->dev, "ibmcam_probe(%p,%u.)\n", intf, ifnum);
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- /* Check the version/revision */
- switch (le16_to_cpu(dev->descriptor.bcdDevice)) {
- case 0x0002:
- if (ifnum != 2)
- return -ENODEV;
- model = IBMCAM_MODEL_1;
- break;
- case 0x030A:
- if (ifnum != 0)
- return -ENODEV;
- if ((le16_to_cpu(dev->descriptor.idProduct) == NETCAM_PRODUCT_ID) ||
- (le16_to_cpu(dev->descriptor.idProduct) == VEO_800D_PRODUCT_ID))
- model = IBMCAM_MODEL_4;
- else
- model = IBMCAM_MODEL_2;
- break;
- case 0x0301:
- if (ifnum != 0)
- return -ENODEV;
- model = IBMCAM_MODEL_3;
- break;
- default:
- err("IBM camera with revision 0x%04x is not supported.",
- le16_to_cpu(dev->descriptor.bcdDevice));
- return -ENODEV;
- }
-
- /* Print detailed info on what we found so far */
- do {
- char *brand = NULL;
- switch (le16_to_cpu(dev->descriptor.idProduct)) {
- case NETCAM_PRODUCT_ID:
- brand = "IBM NetCamera";
- break;
- case VEO_800C_PRODUCT_ID:
- brand = "Veo Stingray [800C]";
- break;
- case VEO_800D_PRODUCT_ID:
- brand = "Veo Stingray [800D]";
- break;
- case IBMCAM_PRODUCT_ID:
- default:
- brand = "IBM PC Camera"; /* a.k.a. Xirlink C-It */
- break;
- }
- dev_info(&dev->dev,
- "%s USB camera found (model %d, rev. 0x%04x)\n",
- brand, model, le16_to_cpu(dev->descriptor.bcdDevice));
- } while (0);
-
- /* Validate found interface: must have one ISO endpoint */
- nas = intf->num_altsetting;
- if (debug > 0)
- dev_info(&dev->dev, "Number of alternate settings=%d.\n",
- nas);
- if (nas < 2) {
- err("Too few alternate settings for this camera!");
- return -ENODEV;
- }
- /* Validate all alternate settings */
- for (ix=0; ix < nas; ix++) {
- const struct usb_host_interface *interface;
- const struct usb_endpoint_descriptor *endpoint;
-
- interface = &intf->altsetting[ix];
- i = interface->desc.bAlternateSetting;
- if (interface->desc.bNumEndpoints != 1) {
- err("Interface %d. has %u. endpoints!",
- ifnum, (unsigned)(interface->desc.bNumEndpoints));
- return -ENODEV;
- }
- endpoint = &interface->endpoint[0].desc;
- if (video_ep == 0)
- video_ep = endpoint->bEndpointAddress;
- else if (video_ep != endpoint->bEndpointAddress) {
- err("Alternate settings have different endpoint addresses!");
- return -ENODEV;
- }
- if (!usb_endpoint_xfer_isoc(endpoint)) {
- err("Interface %d. has non-ISO endpoint!", ifnum);
- return -ENODEV;
- }
- if (usb_endpoint_dir_out(endpoint)) {
- err("Interface %d. has ISO OUT endpoint!", ifnum);
- return -ENODEV;
- }
- if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
- if (inactInterface < 0)
- inactInterface = i;
- else {
- err("More than one inactive alt. setting!");
- return -ENODEV;
- }
- } else {
- if (actInterface < 0) {
- actInterface = i;
- maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
- if (debug > 0)
- dev_info(&dev->dev,
- "Active setting=%d. "
- "maxPS=%d.\n", i, maxPS);
- } else
- err("More than one active alt. setting! Ignoring #%d.", i);
- }
- }
- if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
- err("Failed to recognize the camera!");
- return -ENODEV;
- }
-
- /* Validate options */
- switch (model) {
- case IBMCAM_MODEL_1:
- RESTRICT_TO_RANGE(lighting, 0, 2);
- RESTRICT_TO_RANGE(size, SIZE_128x96, SIZE_352x288);
- if (framerate < 0)
- framerate = 2;
- canvasX = 352;
- canvasY = 288;
- break;
- case IBMCAM_MODEL_2:
- RESTRICT_TO_RANGE(lighting, 0, 15);
- RESTRICT_TO_RANGE(size, SIZE_176x144, SIZE_352x240);
- if (framerate < 0)
- framerate = 2;
- canvasX = 352;
- canvasY = 240;
- break;
- case IBMCAM_MODEL_3:
- RESTRICT_TO_RANGE(lighting, 0, 15); /* FIXME */
- switch (size) {
- case SIZE_160x120:
- canvasX = 160;
- canvasY = 120;
- if (framerate < 0)
- framerate = 2;
- RESTRICT_TO_RANGE(framerate, 0, 5);
- break;
- default:
- dev_info(&dev->dev, "IBM camera: using 320x240\n");
- size = SIZE_320x240;
- /* No break here */
- case SIZE_320x240:
- canvasX = 320;
- canvasY = 240;
- if (framerate < 0)
- framerate = 3;
- RESTRICT_TO_RANGE(framerate, 0, 5);
- break;
- case SIZE_640x480:
- canvasX = 640;
- canvasY = 480;
- framerate = 0; /* Slowest, and maybe even that is too fast */
- break;
- }
- break;
- case IBMCAM_MODEL_4:
- RESTRICT_TO_RANGE(lighting, 0, 2);
- switch (size) {
- case SIZE_128x96:
- canvasX = 128;
- canvasY = 96;
- break;
- case SIZE_160x120:
- canvasX = 160;
- canvasY = 120;
- break;
- default:
- dev_info(&dev->dev, "IBM NetCamera: using 176x144\n");
- size = SIZE_176x144;
- /* No break here */
- case SIZE_176x144:
- canvasX = 176;
- canvasY = 144;
- break;
- case SIZE_320x240:
- canvasX = 320;
- canvasY = 240;
- break;
- case SIZE_352x288:
- canvasX = 352;
- canvasY = 288;
- break;
- }
- break;
- default:
- err("IBM camera: Model %d. not supported!", model);
- return -ENODEV;
- }
-
- uvd = usbvideo_AllocateDevice(cams);
- if (uvd != NULL) {
- /* Here uvd is a fully allocated uvd object */
- uvd->flags = flags;
- uvd->debug = debug;
- uvd->dev = dev;
- uvd->iface = ifnum;
- uvd->ifaceAltInactive = inactInterface;
- uvd->ifaceAltActive = actInterface;
- uvd->video_endp = video_ep;
- uvd->iso_packet_len = maxPS;
- uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
- uvd->defaultPalette = VIDEO_PALETTE_RGB24;
- uvd->canvas = VIDEOSIZE(canvasX, canvasY);
- uvd->videosize = ibmcam_size_to_videosize(size);
-
- /* Initialize ibmcam-specific data */
- assert(IBMCAM_T(uvd) != NULL);
- IBMCAM_T(uvd)->camera_model = model;
- IBMCAM_T(uvd)->initialized = 0;
-
- ibmcam_configure_video(uvd);
-
- i = usbvideo_RegisterVideoDevice(uvd);
- if (i != 0) {
- err("usbvideo_RegisterVideoDevice() failed.");
- uvd = NULL;
- }
- }
- usb_set_intfdata (intf, uvd);
- return 0;
-}
-
-
-static struct usb_device_id id_table[] = {
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0002, 0x0002) }, /* Model 1 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, IBMCAM_PRODUCT_ID, 0x0301, 0x0301) }, /* Model 3 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, NETCAM_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800C_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 2 */
- { USB_DEVICE_VER(IBMCAM_VENDOR_ID, VEO_800D_PRODUCT_ID, 0x030a, 0x030a) }, /* Model 4 */
- { } /* Terminating entry */
-};
-
-/*
- * ibmcam_init()
- *
- * This code is run to initialize the driver.
- *
- * History:
- * 1/27/00 Reworked to use statically allocated ibmcam structures.
- * 21/10/00 Completely redesigned to use usbvideo services.
- */
-static int __init ibmcam_init(void)
-{
- struct usbvideo_cb cbTbl;
- memset(&cbTbl, 0, sizeof(cbTbl));
- cbTbl.probe = ibmcam_probe;
- cbTbl.setupOnOpen = ibmcam_setup_on_open;
- cbTbl.videoStart = ibmcam_video_start;
- cbTbl.videoStop = ibmcam_video_stop;
- cbTbl.processData = ibmcam_ProcessIsocData;
- cbTbl.postProcess = usbvideo_DeinterlaceFrame;
- cbTbl.adjustPicture = ibmcam_adjust_picture;
- cbTbl.getFPS = ibmcam_calculate_fps;
- return usbvideo_register(
- &cams,
- MAX_IBMCAM,
- sizeof(ibmcam_t),
- "ibmcam",
- &cbTbl,
- THIS_MODULE,
- id_table);
-}
-
-static void __exit ibmcam_cleanup(void)
-{
- usbvideo_Deregister(&cams);
-}
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-module_init(ibmcam_init);
-module_exit(ibmcam_cleanup);
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
deleted file mode 100644
index 562e1d170be0..000000000000
--- a/drivers/media/video/usbvideo/konicawc.c
+++ /dev/null
@@ -1,992 +0,0 @@
-/*
- * konicawc.c - konica webcam driver
- *
- * Author: Simon Evans <spse@secret.org.uk>
- *
- * Copyright (C) 2002 Simon Evans
- *
- * Licence: GPL
- *
- * Driver for USB webcams based on Konica chipset. This
- * chipset is used in Intel YC76 camera.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/usb/input.h>
-#include <linux/gfp.h>
-
-#include "usbvideo.h"
-
-#define MAX_BRIGHTNESS 108
-#define MAX_CONTRAST 108
-#define MAX_SATURATION 108
-#define MAX_SHARPNESS 108
-#define MAX_WHITEBAL 372
-#define MAX_SPEED 6
-
-
-#define MAX_CAMERAS 1
-
-#define DRIVER_VERSION "v1.4"
-#define DRIVER_DESC "Konica Webcam driver"
-
-enum ctrl_req {
- SetWhitebal = 0x01,
- SetBrightness = 0x02,
- SetSharpness = 0x03,
- SetContrast = 0x04,
- SetSaturation = 0x05,
-};
-
-
-enum frame_sizes {
- SIZE_160X120 = 0,
- SIZE_160X136 = 1,
- SIZE_176X144 = 2,
- SIZE_320X240 = 3,
-
-};
-
-#define MAX_FRAME_SIZE SIZE_320X240
-
-static struct usbvideo *cams;
-
-#ifdef CONFIG_USB_DEBUG
-static int debug;
-#define DEBUG(n, format, arg...) \
- if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
- }
-#else
-#define DEBUG(n, arg...)
-static const int debug;
-#endif
-
-
-/* Some default values for initial camera settings,
- can be set by modprobe */
-
-static int size;
-static int speed = 6; /* Speed (fps) 0 (slowest) to 6 (fastest) */
-static int brightness = MAX_BRIGHTNESS/2;
-static int contrast = MAX_CONTRAST/2;
-static int saturation = MAX_SATURATION/2;
-static int sharpness = MAX_SHARPNESS/2;
-static int whitebal = 3*(MAX_WHITEBAL/4);
-
-static const int spd_to_iface[] = { 1, 0, 3, 2, 4, 5, 6 };
-
-/* These FPS speeds are from the windows config box. They are
- * indexed on size (0-2) and speed (0-6). Divide by 3 to get the
- * real fps.
- */
-
-static const int spd_to_fps[][7] = { { 24, 40, 48, 60, 72, 80, 100 },
- { 24, 40, 48, 60, 72, 80, 100 },
- { 18, 30, 36, 45, 54, 60, 75 },
- { 6, 10, 12, 15, 18, 21, 25 } };
-
-struct cam_size {
- u16 width;
- u16 height;
- u8 cmd;
-};
-
-static const struct cam_size camera_sizes[] = { { 160, 120, 0x7 },
- { 160, 136, 0xa },
- { 176, 144, 0x4 },
- { 320, 240, 0x5 } };
-
-struct konicawc {
- u8 brightness; /* camera uses 0 - 9, x11 for real value */
- u8 contrast; /* as above */
- u8 saturation; /* as above */
- u8 sharpness; /* as above */
- u8 white_bal; /* 0 - 33, x11 for real value */
- u8 speed; /* Stored as 0 - 6, used as index in spd_to_* (above) */
- u8 size; /* Frame Size */
- int height;
- int width;
- struct urb *sts_urb[USBVIDEO_NUMSBUF];
- u8 sts_buf[USBVIDEO_NUMSBUF][FRAMES_PER_DESC];
- struct urb *last_data_urb;
- int lastframe;
- int cur_frame_size; /* number of bytes in current frame size */
- int maxline; /* number of lines per frame */
- int yplanesz; /* Number of bytes in the Y plane */
- unsigned int buttonsts:1;
-#ifdef CONFIG_INPUT
- struct input_dev *input;
- char input_physname[64];
-#endif
-};
-
-
-#define konicawc_set_misc(uvd, req, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, req, value, index, NULL, 0)
-#define konicawc_get_misc(uvd, req, value, index, buf, sz) konicawc_ctrl_msg(uvd, USB_DIR_IN, req, value, index, buf, sz)
-#define konicawc_set_value(uvd, value, index) konicawc_ctrl_msg(uvd, USB_DIR_OUT, 2, value, index, NULL, 0)
-
-
-static int konicawc_ctrl_msg(struct uvd *uvd, u8 dir, u8 request, u16 value, u16 index, void *buf, int len)
-{
- int retval = usb_control_msg(uvd->dev,
- dir ? usb_rcvctrlpipe(uvd->dev, 0) : usb_sndctrlpipe(uvd->dev, 0),
- request, 0x40 | dir, value, index, buf, len, 1000);
- return retval < 0 ? retval : 0;
-}
-
-
-static inline void konicawc_camera_on(struct uvd *uvd)
-{
- DEBUG(0, "camera on");
- konicawc_set_misc(uvd, 0x2, 1, 0x0b);
-}
-
-
-static inline void konicawc_camera_off(struct uvd *uvd)
-{
- DEBUG(0, "camera off");
- konicawc_set_misc(uvd, 0x2, 0, 0x0b);
-}
-
-
-static void konicawc_set_camera_size(struct uvd *uvd)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- konicawc_set_misc(uvd, 0x2, camera_sizes[cam->size].cmd, 0x08);
- cam->width = camera_sizes[cam->size].width;
- cam->height = camera_sizes[cam->size].height;
- cam->yplanesz = cam->height * cam->width;
- cam->cur_frame_size = (cam->yplanesz * 3) / 2;
- cam->maxline = cam->yplanesz / 256;
- uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-}
-
-
-static int konicawc_setup_on_open(struct uvd *uvd)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
- cam->brightness * 11);
- konicawc_set_value(uvd, cam->brightness, SetBrightness);
- DEBUG(1, "setting white balance to %d (%d)", cam->white_bal,
- cam->white_bal * 11);
- konicawc_set_value(uvd, cam->white_bal, SetWhitebal);
- DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
- cam->contrast * 11);
- konicawc_set_value(uvd, cam->contrast, SetContrast);
- DEBUG(1, "setting saturation to %d (%d)", cam->saturation,
- cam->saturation * 11);
- konicawc_set_value(uvd, cam->saturation, SetSaturation);
- DEBUG(1, "setting sharpness to %d (%d)", cam->sharpness,
- cam->sharpness * 11);
- konicawc_set_value(uvd, cam->sharpness, SetSharpness);
- konicawc_set_camera_size(uvd);
- cam->lastframe = -2;
- cam->buttonsts = 0;
- return 0;
-}
-
-
-static void konicawc_adjust_picture(struct uvd *uvd)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- konicawc_camera_off(uvd);
- DEBUG(1, "new brightness: %d", uvd->vpic.brightness);
- uvd->vpic.brightness = (uvd->vpic.brightness > MAX_BRIGHTNESS) ? MAX_BRIGHTNESS : uvd->vpic.brightness;
- if(cam->brightness != uvd->vpic.brightness / 11) {
- cam->brightness = uvd->vpic.brightness / 11;
- DEBUG(1, "setting brightness to %d (%d)", cam->brightness,
- cam->brightness * 11);
- konicawc_set_value(uvd, cam->brightness, SetBrightness);
- }
-
- DEBUG(1, "new contrast: %d", uvd->vpic.contrast);
- uvd->vpic.contrast = (uvd->vpic.contrast > MAX_CONTRAST) ? MAX_CONTRAST : uvd->vpic.contrast;
- if(cam->contrast != uvd->vpic.contrast / 11) {
- cam->contrast = uvd->vpic.contrast / 11;
- DEBUG(1, "setting contrast to %d (%d)", cam->contrast,
- cam->contrast * 11);
- konicawc_set_value(uvd, cam->contrast, SetContrast);
- }
- konicawc_camera_on(uvd);
-}
-
-#ifdef CONFIG_INPUT
-
-static void konicawc_register_input(struct konicawc *cam, struct usb_device *dev)
-{
- struct input_dev *input_dev;
- int error;
-
- usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
- strlcat(cam->input_physname, "/input0", sizeof(cam->input_physname));
-
- cam->input = input_dev = input_allocate_device();
- if (!input_dev) {
- dev_warn(&dev->dev,
- "Not enough memory for camera's input device\n");
- return;
- }
-
- input_dev->name = "Konicawc snapshot button";
- input_dev->phys = cam->input_physname;
- usb_to_input_id(dev, &input_dev->id);
- input_dev->dev.parent = &dev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
-
- error = input_register_device(cam->input);
- if (error) {
- dev_warn(&dev->dev,
- "Failed to register camera's input device, err: %d\n",
- error);
- input_free_device(cam->input);
- cam->input = NULL;
- }
-}
-
-static void konicawc_unregister_input(struct konicawc *cam)
-{
- if (cam->input) {
- input_unregister_device(cam->input);
- cam->input = NULL;
- }
-}
-
-static void konicawc_report_buttonstat(struct konicawc *cam)
-{
- if (cam->input) {
- input_report_key(cam->input, KEY_CAMERA, cam->buttonsts);
- input_sync(cam->input);
- }
-}
-
-#else
-
-static inline void konicawc_register_input(struct konicawc *cam, struct usb_device *dev) { }
-static inline void konicawc_unregister_input(struct konicawc *cam) { }
-static inline void konicawc_report_buttonstat(struct konicawc *cam) { }
-
-#endif /* CONFIG_INPUT */
-
-static int konicawc_compress_iso(struct uvd *uvd, struct urb *dataurb, struct urb *stsurb)
-{
- char *cdata;
- int i, totlen = 0;
- unsigned char *status = stsurb->transfer_buffer;
- int keep = 0, discard = 0, bad = 0;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- for (i = 0; i < dataurb->number_of_packets; i++) {
- int button = cam->buttonsts;
- unsigned char sts;
- int n = dataurb->iso_frame_desc[i].actual_length;
- int st = dataurb->iso_frame_desc[i].status;
- cdata = dataurb->transfer_buffer +
- dataurb->iso_frame_desc[i].offset;
-
- /* Detect and ignore errored packets */
- if (st < 0) {
- DEBUG(1, "Data error: packet=%d. len=%d. status=%d.",
- i, n, st);
- uvd->stats.iso_err_count++;
- continue;
- }
-
- /* Detect and ignore empty packets */
- if (n <= 0) {
- uvd->stats.iso_skip_count++;
- continue;
- }
-
- /* See what the status data said about the packet */
- sts = *(status+stsurb->iso_frame_desc[i].offset);
-
- /* sts: 0x80-0xff: frame start with frame number (ie 0-7f)
- * otherwise:
- * bit 0 0: keep packet
- * 1: drop packet (padding data)
- *
- * bit 4 0 button not clicked
- * 1 button clicked
- * button is used to `take a picture' (in software)
- */
-
- if(sts < 0x80) {
- button = !!(sts & 0x40);
- sts &= ~0x40;
- }
-
- /* work out the button status, but don't do
- anything with it for now */
-
- if(button != cam->buttonsts) {
- DEBUG(2, "button: %sclicked", button ? "" : "un");
- cam->buttonsts = button;
- konicawc_report_buttonstat(cam);
- }
-
- if(sts == 0x01) { /* drop frame */
- discard++;
- continue;
- }
-
- if((sts > 0x01) && (sts < 0x80)) {
- dev_info(&uvd->dev->dev, "unknown status %2.2x\n",
- sts);
- bad++;
- continue;
- }
- if(!sts && cam->lastframe == -2) {
- DEBUG(2, "dropping frame looking for image start");
- continue;
- }
-
- keep++;
- if(sts & 0x80) { /* frame start */
- unsigned char marker[] = { 0, 0xff, 0, 0x00 };
-
- if(cam->lastframe == -2) {
- DEBUG(2, "found initial image");
- cam->lastframe = -1;
- }
-
- marker[3] = sts & 0x7F;
- RingQueue_Enqueue(&uvd->dp, marker, 4);
- totlen += 4;
- }
-
- totlen += n; /* Little local accounting */
- RingQueue_Enqueue(&uvd->dp, cdata, n);
- }
- DEBUG(8, "finished: keep = %d discard = %d bad = %d added %d bytes",
- keep, discard, bad, totlen);
- return totlen;
-}
-
-
-static void resubmit_urb(struct uvd *uvd, struct urb *urb)
-{
- int i, ret;
- for (i = 0; i < FRAMES_PER_DESC; i++) {
- urb->iso_frame_desc[i].status = 0;
- }
- urb->dev = uvd->dev;
- urb->status = 0;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- DEBUG(3, "submitting urb of length %d", urb->transfer_buffer_length);
- if(ret)
- err("usb_submit_urb error (%d)", ret);
-
-}
-
-
-static void konicawc_isoc_irq(struct urb *urb)
-{
- struct uvd *uvd = urb->context;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- /* We don't want to do anything if we are about to be removed! */
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return;
-
- if (!uvd->streaming) {
- DEBUG(1, "Not streaming, but interrupt!");
- return;
- }
-
- DEBUG(3, "got frame %d len = %d buflen =%d", urb->start_frame, urb->actual_length, urb->transfer_buffer_length);
-
- uvd->stats.urb_count++;
-
- if (urb->transfer_buffer_length > 32) {
- cam->last_data_urb = urb;
- return;
- }
- /* Copy the data received into ring queue */
- if(cam->last_data_urb) {
- int len = 0;
- if(urb->start_frame != cam->last_data_urb->start_frame)
- err("Lost sync on frames");
- else if (!urb->status && !cam->last_data_urb->status)
- len = konicawc_compress_iso(uvd, cam->last_data_urb, urb);
-
- resubmit_urb(uvd, cam->last_data_urb);
- resubmit_urb(uvd, urb);
- cam->last_data_urb = NULL;
- uvd->stats.urb_length = len;
- uvd->stats.data_count += len;
- if(len)
- RingQueue_WakeUpInterruptible(&uvd->dp);
- return;
- }
- return;
-}
-
-
-static int konicawc_start_data(struct uvd *uvd)
-{
- struct usb_device *dev = uvd->dev;
- int i, errFlag;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
- int pktsz;
- struct usb_interface *intf;
- struct usb_host_interface *interface = NULL;
-
- intf = usb_ifnum_to_if(dev, uvd->iface);
- if (intf)
- interface = usb_altnum_to_altsetting(intf,
- spd_to_iface[cam->speed]);
- if (!interface)
- return -ENXIO;
- pktsz = le16_to_cpu(interface->endpoint[1].desc.wMaxPacketSize);
- DEBUG(1, "pktsz = %d", pktsz);
- if (!CAMERA_IS_OPERATIONAL(uvd)) {
- err("Camera is not operational");
- return -EFAULT;
- }
- uvd->curframe = -1;
- konicawc_camera_on(uvd);
- /* Alternate interface 1 is is the biggest frame size */
- i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
- if (i < 0) {
- err("usb_set_interface error");
- uvd->last_error = i;
- return -EBUSY;
- }
-
- /* We double buffer the Iso lists */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- int j, k;
- struct urb *urb = uvd->sbuf[i].urb;
- urb->dev = dev;
- urb->context = uvd;
- urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
- urb->interval = 1;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = uvd->sbuf[i].data;
- urb->complete = konicawc_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
- for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length = pktsz;
- }
-
- urb = cam->sts_urb[i];
- urb->dev = dev;
- urb->context = uvd;
- urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp-1);
- urb->interval = 1;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = cam->sts_buf[i];
- urb->complete = konicawc_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = FRAMES_PER_DESC;
- for (j=0; j < FRAMES_PER_DESC; j++) {
- urb->iso_frame_desc[j].offset = j;
- urb->iso_frame_desc[j].length = 1;
- }
- }
-
- cam->last_data_urb = NULL;
-
- /* Submit all URBs */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- errFlag = usb_submit_urb(cam->sts_urb[i], GFP_KERNEL);
- if (errFlag)
- err("usb_submit_isoc(%d) ret %d", i, errFlag);
-
- errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
- if (errFlag)
- err ("usb_submit_isoc(%d) ret %d", i, errFlag);
- }
-
- uvd->streaming = 1;
- DEBUG(1, "streaming=1 video_endp=$%02x", uvd->video_endp);
- return 0;
-}
-
-
-static void konicawc_stop_data(struct uvd *uvd)
-{
- int i, j;
- struct konicawc *cam;
-
- if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
- return;
-
- konicawc_camera_off(uvd);
- uvd->streaming = 0;
- cam = (struct konicawc *)uvd->user_data;
- cam->last_data_urb = NULL;
-
- /* Unschedule all of the iso td's */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- usb_kill_urb(uvd->sbuf[i].urb);
- usb_kill_urb(cam->sts_urb[i]);
- }
-
- if (!uvd->remove_pending) {
- /* Set packet size to 0 */
- j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
- if (j < 0) {
- err("usb_set_interface() error %d.", j);
- uvd->last_error = j;
- }
- }
-}
-
-
-static void konicawc_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
- int maxline = cam->maxline;
- int yplanesz = cam->yplanesz;
-
- assert(frame != NULL);
-
- DEBUG(5, "maxline = %d yplanesz = %d", maxline, yplanesz);
- DEBUG(3, "Frame state = %d", frame->scanstate);
-
- if(frame->scanstate == ScanState_Scanning) {
- int drop = 0;
- int curframe;
- int fdrops = 0;
- DEBUG(3, "Searching for marker, queue len = %d", RingQueue_GetLength(&uvd->dp));
- while(RingQueue_GetLength(&uvd->dp) >= 4) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
- (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 3) < 0x80)) {
- curframe = RING_QUEUE_PEEK(&uvd->dp, 3);
- if(cam->lastframe >= 0) {
- fdrops = (0x80 + curframe - cam->lastframe) & 0x7F;
- fdrops--;
- if(fdrops) {
- dev_info(&uvd->dev->dev,
- "Dropped %d frames "
- "(%d -> %d)\n",
- fdrops,
- cam->lastframe,
- curframe);
- }
- }
- cam->lastframe = curframe;
- frame->curline = 0;
- frame->scanstate = ScanState_Lines;
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
- break;
- }
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- drop++;
- }
- if(drop)
- DEBUG(2, "dropped %d bytes looking for new frame", drop);
- }
-
- if(frame->scanstate == ScanState_Scanning)
- return;
-
- /* Try to move data from queue into frame buffer
- * We get data in blocks of 384 bytes made up of:
- * 256 Y, 64 U, 64 V.
- * This needs to be written out as a Y plane, a U plane and a V plane.
- */
-
- while ( frame->curline < maxline && (RingQueue_GetLength(&uvd->dp) >= 384)) {
- /* Y */
- RingQueue_Dequeue(&uvd->dp, frame->data + (frame->curline * 256), 256);
- /* U */
- RingQueue_Dequeue(&uvd->dp, frame->data + yplanesz + (frame->curline * 64), 64);
- /* V */
- RingQueue_Dequeue(&uvd->dp, frame->data + (5 * yplanesz)/4 + (frame->curline * 64), 64);
- frame->seqRead_Length += 384;
- frame->curline++;
- }
- /* See if we filled the frame */
- if (frame->curline == maxline) {
- DEBUG(5, "got whole frame");
-
- frame->frameState = FrameState_Done_Hold;
- frame->curline = 0;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- }
-}
-
-
-static int konicawc_find_fps(int size, int fps)
-{
- int i;
-
- fps *= 3;
- DEBUG(1, "konica_find_fps: size = %d fps = %d", size, fps);
- if(fps <= spd_to_fps[size][0])
- return 0;
-
- if(fps >= spd_to_fps[size][MAX_SPEED])
- return MAX_SPEED;
-
- for(i = 0; i < MAX_SPEED; i++) {
- if((fps >= spd_to_fps[size][i]) && (fps <= spd_to_fps[size][i+1])) {
- DEBUG(2, "fps %d between %d and %d", fps, i, i+1);
- if( (fps - spd_to_fps[size][i]) < (spd_to_fps[size][i+1] - fps))
- return i;
- else
- return i+1;
- }
- }
- return MAX_SPEED+1;
-}
-
-
-static int konicawc_set_video_mode(struct uvd *uvd, struct video_window *vw)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
- int newspeed = cam->speed;
- int newsize;
- int x = vw->width;
- int y = vw->height;
- int fps = vw->flags;
-
- if(x > 0 && y > 0) {
- DEBUG(2, "trying to find size %d,%d", x, y);
- for(newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
- if((camera_sizes[newsize].width == x) && (camera_sizes[newsize].height == y))
- break;
- }
- } else {
- newsize = cam->size;
- }
-
- if(newsize > MAX_FRAME_SIZE) {
- DEBUG(1, "couldn't find size %d,%d", x, y);
- return -EINVAL;
- }
-
- if(fps > 0) {
- DEBUG(1, "trying to set fps to %d", fps);
- newspeed = konicawc_find_fps(newsize, fps);
- DEBUG(1, "find_fps returned %d (%d)", newspeed, spd_to_fps[newsize][newspeed]);
- }
-
- if(newspeed > MAX_SPEED)
- return -EINVAL;
-
- DEBUG(1, "setting size to %d speed to %d", newsize, newspeed);
- if((newsize == cam->size) && (newspeed == cam->speed)) {
- DEBUG(1, "Nothing to do");
- return 0;
- }
- DEBUG(0, "setting to %dx%d @ %d fps", camera_sizes[newsize].width,
- camera_sizes[newsize].height, spd_to_fps[newsize][newspeed]/3);
-
- konicawc_stop_data(uvd);
- uvd->ifaceAltActive = spd_to_iface[newspeed];
- DEBUG(1, "new interface = %d", uvd->ifaceAltActive);
- cam->speed = newspeed;
-
- if(cam->size != newsize) {
- cam->size = newsize;
- konicawc_set_camera_size(uvd);
- }
-
- /* Flush the input queue and clear any current frame in progress */
-
- RingQueue_Flush(&uvd->dp);
- cam->lastframe = -2;
- if(uvd->curframe != -1) {
- uvd->frame[uvd->curframe].curline = 0;
- uvd->frame[uvd->curframe].seqRead_Length = 0;
- uvd->frame[uvd->curframe].seqRead_Index = 0;
- }
-
- konicawc_start_data(uvd);
- return 0;
-}
-
-
-static int konicawc_calculate_fps(struct uvd *uvd)
-{
- struct konicawc *cam = uvd->user_data;
- return spd_to_fps[cam->size][cam->speed]/3;
-}
-
-
-static void konicawc_configure_video(struct uvd *uvd)
-{
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
- u8 buf[2];
-
- memset(&uvd->vpic, 0, sizeof(uvd->vpic));
- memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
- RESTRICT_TO_RANGE(brightness, 0, MAX_BRIGHTNESS);
- RESTRICT_TO_RANGE(contrast, 0, MAX_CONTRAST);
- RESTRICT_TO_RANGE(saturation, 0, MAX_SATURATION);
- RESTRICT_TO_RANGE(sharpness, 0, MAX_SHARPNESS);
- RESTRICT_TO_RANGE(whitebal, 0, MAX_WHITEBAL);
-
- cam->brightness = brightness / 11;
- cam->contrast = contrast / 11;
- cam->saturation = saturation / 11;
- cam->sharpness = sharpness / 11;
- cam->white_bal = whitebal / 11;
-
- uvd->vpic.colour = 108;
- uvd->vpic.hue = 108;
- uvd->vpic.brightness = brightness;
- uvd->vpic.contrast = contrast;
- uvd->vpic.whiteness = whitebal;
- uvd->vpic.depth = 6;
- uvd->vpic.palette = VIDEO_PALETTE_YUV420P;
-
- memset(&uvd->vcap, 0, sizeof(uvd->vcap));
- strcpy(uvd->vcap.name, "Konica Webcam");
- uvd->vcap.type = VID_TYPE_CAPTURE;
- uvd->vcap.channels = 1;
- uvd->vcap.audios = 0;
- uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
- uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
- uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
- uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
-
- memset(&uvd->vchan, 0, sizeof(uvd->vchan));
- uvd->vchan.flags = 0 ;
- uvd->vchan.tuners = 0;
- uvd->vchan.channel = 0;
- uvd->vchan.type = VIDEO_TYPE_CAMERA;
- strcpy(uvd->vchan.name, "Camera");
-
- /* Talk to device */
- DEBUG(1, "device init");
- if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
- DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
- if(!konicawc_get_misc(uvd, 0x3, 0, 0x10, buf, 2))
- DEBUG(2, "3,10 -> %2.2x %2.2x", buf[0], buf[1]);
- if(konicawc_set_misc(uvd, 0x2, 0, 0xd))
- DEBUG(2, "2,0,d failed");
- DEBUG(1, "setting initial values");
-}
-
-static int konicawc_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct uvd *uvd = NULL;
- int ix, i, nas;
- int actInterface=-1, inactInterface=-1, maxPS=0;
- unsigned char video_ep = 0;
-
- DEBUG(1, "konicawc_probe(%p)", intf);
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- dev_info(&intf->dev, "Konica Webcam (rev. 0x%04x)\n",
- le16_to_cpu(dev->descriptor.bcdDevice));
- RESTRICT_TO_RANGE(speed, 0, MAX_SPEED);
-
- /* Validate found interface: must have one ISO endpoint */
- nas = intf->num_altsetting;
- if (nas != 8) {
- err("Incorrect number of alternate settings (%d) for this camera!", nas);
- return -ENODEV;
- }
- /* Validate all alternate settings */
- for (ix=0; ix < nas; ix++) {
- const struct usb_host_interface *interface;
- const struct usb_endpoint_descriptor *endpoint;
-
- interface = &intf->altsetting[ix];
- i = interface->desc.bAlternateSetting;
- if (interface->desc.bNumEndpoints != 2) {
- err("Interface %d. has %u. endpoints!",
- interface->desc.bInterfaceNumber,
- (unsigned)(interface->desc.bNumEndpoints));
- return -ENODEV;
- }
- endpoint = &interface->endpoint[1].desc;
- DEBUG(1, "found endpoint: addr: 0x%2.2x maxps = 0x%4.4x",
- endpoint->bEndpointAddress, le16_to_cpu(endpoint->wMaxPacketSize));
- if (video_ep == 0)
- video_ep = endpoint->bEndpointAddress;
- else if (video_ep != endpoint->bEndpointAddress) {
- err("Alternate settings have different endpoint addresses!");
- return -ENODEV;
- }
- if (!usb_endpoint_xfer_isoc(endpoint)) {
- err("Interface %d. has non-ISO endpoint!",
- interface->desc.bInterfaceNumber);
- return -ENODEV;
- }
- if (usb_endpoint_dir_out(endpoint)) {
- err("Interface %d. has ISO OUT endpoint!",
- interface->desc.bInterfaceNumber);
- return -ENODEV;
- }
- if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
- if (inactInterface < 0)
- inactInterface = i;
- else {
- err("More than one inactive alt. setting!");
- return -ENODEV;
- }
- } else {
- if (i == spd_to_iface[speed]) {
- /* This one is the requested one */
- actInterface = i;
- }
- }
- if (le16_to_cpu(endpoint->wMaxPacketSize) > maxPS)
- maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
- }
- if(actInterface == -1) {
- err("Cant find required endpoint");
- return -ENODEV;
- }
-
- DEBUG(1, "Selecting requested active setting=%d. maxPS=%d.", actInterface, maxPS);
-
- uvd = usbvideo_AllocateDevice(cams);
- if (uvd != NULL) {
- struct konicawc *cam = (struct konicawc *)(uvd->user_data);
- /* Here uvd is a fully allocated uvd object */
- for(i = 0; i < USBVIDEO_NUMSBUF; i++) {
- cam->sts_urb[i] = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if(cam->sts_urb[i] == NULL) {
- while(i--) {
- usb_free_urb(cam->sts_urb[i]);
- }
- err("can't allocate urbs");
- return -ENOMEM;
- }
- }
- cam->speed = speed;
- RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
- cam->width = camera_sizes[size].width;
- cam->height = camera_sizes[size].height;
- cam->size = size;
-
- uvd->flags = 0;
- uvd->debug = debug;
- uvd->dev = dev;
- uvd->iface = intf->altsetting->desc.bInterfaceNumber;
- uvd->ifaceAltInactive = inactInterface;
- uvd->ifaceAltActive = actInterface;
- uvd->video_endp = video_ep;
- uvd->iso_packet_len = maxPS;
- uvd->paletteBits = 1L << VIDEO_PALETTE_YUV420P;
- uvd->defaultPalette = VIDEO_PALETTE_YUV420P;
- uvd->canvas = VIDEOSIZE(320, 240);
- uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-
- /* Initialize konicawc specific data */
- konicawc_configure_video(uvd);
-
- i = usbvideo_RegisterVideoDevice(uvd);
- uvd->max_frame_size = (320 * 240 * 3)/2;
- if (i != 0) {
- err("usbvideo_RegisterVideoDevice() failed.");
- uvd = NULL;
- }
-
- konicawc_register_input(cam, dev);
- }
-
- if (uvd) {
- usb_set_intfdata (intf, uvd);
- return 0;
- }
- return -EIO;
-}
-
-
-static void konicawc_free_uvd(struct uvd *uvd)
-{
- int i;
- struct konicawc *cam = (struct konicawc *)uvd->user_data;
-
- konicawc_unregister_input(cam);
-
- for (i = 0; i < USBVIDEO_NUMSBUF; i++) {
- usb_free_urb(cam->sts_urb[i]);
- cam->sts_urb[i] = NULL;
- }
-}
-
-
-static struct usb_device_id id_table[] = {
- { USB_DEVICE(0x04c8, 0x0720) }, /* Intel YC 76 */
- { } /* Terminating entry */
-};
-
-
-static int __init konicawc_init(void)
-{
- struct usbvideo_cb cbTbl;
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
- memset(&cbTbl, 0, sizeof(cbTbl));
- cbTbl.probe = konicawc_probe;
- cbTbl.setupOnOpen = konicawc_setup_on_open;
- cbTbl.processData = konicawc_process_isoc;
- cbTbl.getFPS = konicawc_calculate_fps;
- cbTbl.setVideoMode = konicawc_set_video_mode;
- cbTbl.startDataPump = konicawc_start_data;
- cbTbl.stopDataPump = konicawc_stop_data;
- cbTbl.adjustPicture = konicawc_adjust_picture;
- cbTbl.userFree = konicawc_free_uvd;
- return usbvideo_register(
- &cams,
- MAX_CAMERAS,
- sizeof(struct konicawc),
- "konicawc",
- &cbTbl,
- THIS_MODULE,
- id_table);
-}
-
-
-static void __exit konicawc_cleanup(void)
-{
- usbvideo_Deregister(&cams);
-}
-
-
-MODULE_DEVICE_TABLE(usb, id_table);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Simon Evans <spse@secret.org.uk>");
-MODULE_DESCRIPTION(DRIVER_DESC);
-module_param(speed, int, 0);
-MODULE_PARM_DESC(speed, "Initial speed: 0 (slowest) - 6 (fastest)");
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 160x136 2: 176x144 3: 320x240");
-module_param(brightness, int, 0);
-MODULE_PARM_DESC(brightness, "Initial brightness 0 - 108");
-module_param(contrast, int, 0);
-MODULE_PARM_DESC(contrast, "Initial contrast 0 - 108");
-module_param(saturation, int, 0);
-MODULE_PARM_DESC(saturation, "Initial saturation 0 - 108");
-module_param(sharpness, int, 0);
-MODULE_PARM_DESC(sharpness, "Initial brightness 0 - 108");
-module_param(whitebal, int, 0);
-MODULE_PARM_DESC(whitebal, "Initial white balance 0 - 363");
-
-#ifdef CONFIG_USB_DEBUG
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-#endif
-
-module_init(konicawc_init);
-module_exit(konicawc_cleanup);
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
deleted file mode 100644
index fbd665fa1979..000000000000
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ /dev/null
@@ -1,1126 +0,0 @@
-/*
- * Driver for Logitech Quickcam Messenger usb video camera
- * Copyright (C) Jaya Kumar
- *
- * This work was sponsored by CIS(M) Sdn Bhd.
- * History:
- * 05/08/2006 - Jaya Kumar
- * I wrote this based on the konicawc by Simon Evans.
- * -
- * Full credit for reverse engineering and creating an initial
- * working linux driver for the VV6422 goes to the qce-ga project by
- * Tuukka Toivonen, Jochen Hoenicke, Peter McConnell,
- * Cristiano De Michele, Georg Acher, Jean-Frederic Clere as well as
- * others.
- * ---
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/usb/input.h>
-#include <linux/slab.h>
-
-#include "usbvideo.h"
-#include "quickcam_messenger.h"
-
-/*
- * Version Information
- */
-
-#ifdef CONFIG_USB_DEBUG
-static int debug;
-#define DEBUG(n, format, arg...) \
- if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
- }
-#else
-#define DEBUG(n, arg...)
-static const int debug;
-#endif
-
-#define DRIVER_VERSION "v0.01"
-#define DRIVER_DESC "Logitech Quickcam Messenger USB"
-
-#define USB_LOGITECH_VENDOR_ID 0x046D
-#define USB_QCM_PRODUCT_ID 0x08F0
-
-#define MAX_CAMERAS 1
-
-#define MAX_COLOUR 32768
-#define MAX_HUE 32768
-#define MAX_BRIGHTNESS 32768
-#define MAX_CONTRAST 32768
-#define MAX_WHITENESS 32768
-
-static int size = SIZE_320X240;
-static int colour = MAX_COLOUR;
-static int hue = MAX_HUE;
-static int brightness = MAX_BRIGHTNESS;
-static int contrast = MAX_CONTRAST;
-static int whiteness = MAX_WHITENESS;
-
-static struct usbvideo *cams;
-
-static struct usb_device_id qcm_table [] = {
- { USB_DEVICE(USB_LOGITECH_VENDOR_ID, USB_QCM_PRODUCT_ID) },
- { }
-};
-MODULE_DEVICE_TABLE(usb, qcm_table);
-
-#ifdef CONFIG_INPUT
-static void qcm_register_input(struct qcm *cam, struct usb_device *dev)
-{
- struct input_dev *input_dev;
- int error;
-
- usb_make_path(dev, cam->input_physname, sizeof(cam->input_physname));
- strlcat(cam->input_physname, "/input0", sizeof(cam->input_physname));
-
- cam->input = input_dev = input_allocate_device();
- if (!input_dev) {
- dev_warn(&dev->dev, "insufficient mem for cam input device\n");
- return;
- }
-
- input_dev->name = "QCM button";
- input_dev->phys = cam->input_physname;
- usb_to_input_id(dev, &input_dev->id);
- input_dev->dev.parent = &dev->dev;
-
- input_dev->evbit[0] = BIT_MASK(EV_KEY);
- input_dev->keybit[BIT_WORD(KEY_CAMERA)] = BIT_MASK(KEY_CAMERA);
-
- error = input_register_device(cam->input);
- if (error) {
- dev_warn(&dev->dev,
- "Failed to register camera's input device, err: %d\n",
- error);
- input_free_device(cam->input);
- cam->input = NULL;
- }
-}
-
-static void qcm_unregister_input(struct qcm *cam)
-{
- if (cam->input) {
- input_unregister_device(cam->input);
- cam->input = NULL;
- }
-}
-
-static void qcm_report_buttonstat(struct qcm *cam)
-{
- if (cam->input) {
- input_report_key(cam->input, KEY_CAMERA, cam->button_sts);
- input_sync(cam->input);
- }
-}
-
-static void qcm_int_irq(struct urb *urb)
-{
- int ret;
- struct uvd *uvd = urb->context;
- struct qcm *cam;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return;
-
- if (!uvd->streaming)
- return;
-
- uvd->stats.urb_count++;
-
- if (urb->status < 0)
- uvd->stats.iso_err_count++;
- else {
- if (urb->actual_length > 0 ) {
- cam = (struct qcm *) uvd->user_data;
- if (cam->button_sts_buf == 0x88)
- cam->button_sts = 0x0;
- else if (cam->button_sts_buf == 0x80)
- cam->button_sts = 0x1;
- qcm_report_buttonstat(cam);
- }
- }
-
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret < 0)
- err("usb_submit_urb error (%d)", ret);
-}
-
-static int qcm_setup_input_int(struct qcm *cam, struct uvd *uvd)
-{
- int errflag;
- usb_fill_int_urb(cam->button_urb, uvd->dev,
- usb_rcvintpipe(uvd->dev, uvd->video_endp + 1),
- &cam->button_sts_buf,
- 1,
- qcm_int_irq,
- uvd, 16);
-
- errflag = usb_submit_urb(cam->button_urb, GFP_KERNEL);
- if (errflag)
- err ("usb_submit_int ret %d", errflag);
- return errflag;
-}
-
-static void qcm_stop_int_data(struct qcm *cam)
-{
- usb_kill_urb(cam->button_urb);
-}
-
-static int qcm_alloc_int_urb(struct qcm *cam)
-{
- cam->button_urb = usb_alloc_urb(0, GFP_KERNEL);
-
- if (!cam->button_urb)
- return -ENOMEM;
-
- return 0;
-}
-
-static void qcm_free_int(struct qcm *cam)
-{
- usb_free_urb(cam->button_urb);
-}
-#endif /* CONFIG_INPUT */
-
-static int qcm_stv_setb(struct usb_device *dev, u16 reg, u8 val)
-{
- int ret;
-
- /* we'll wait up to 3 slices but no more */
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
- reg, 0, &val, 1, 3*HZ);
- return ret;
-}
-
-static int qcm_stv_setw(struct usb_device *dev, u16 reg, __le16 val)
-{
- int ret;
-
- /* we'll wait up to 3 slices but no more */
- ret = usb_control_msg(dev, usb_sndctrlpipe(dev, 0),
- 0x04, USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
- reg, 0, &val, 2, 3*HZ);
- return ret;
-}
-
-static int qcm_stv_getw(struct usb_device *dev, unsigned short reg,
- __le16 *val)
-{
- int ret;
-
- /* we'll wait up to 3 slices but no more */
- ret = usb_control_msg(dev, usb_rcvctrlpipe(dev, 0),
- 0x04, USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_DEVICE,
- reg, 0, val, 2, 3*HZ);
- return ret;
-}
-
-static int qcm_camera_on(struct uvd *uvd)
-{
- int ret;
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x01));
- return 0;
-}
-
-static int qcm_camera_off(struct uvd *uvd)
-{
- int ret;
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
- return 0;
-}
-
-static void qcm_hsv2rgb(u16 hue, u16 sat, u16 val, u16 *r, u16 *g, u16 *b)
-{
- unsigned int segment, valsat;
- signed int h = (signed int) hue;
- unsigned int s = (sat - 32768) * 2; /* rescale */
- unsigned int v = val;
- unsigned int p;
-
- /*
- the registers controlling gain are 8 bit of which
- we affect only the last 4 bits with our gain.
- we know that if saturation is 0, (unsaturated) then
- we're grayscale (center axis of the colour cone) so
- we set rgb=value. we use a formula obtained from
- wikipedia to map the cone to the RGB plane. it's
- as follows for the human value case of h=0..360,
- s=0..1, v=0..1
- h_i = h/60 % 6 , f = h/60 - h_i , p = v(1-s)
- q = v(1 - f*s) , t = v(1 - (1-f)s)
- h_i==0 => r=v , g=t, b=p
- h_i==1 => r=q , g=v, b=p
- h_i==2 => r=p , g=v, b=t
- h_i==3 => r=p , g=q, b=v
- h_i==4 => r=t , g=p, b=v
- h_i==5 => r=v , g=p, b=q
- the bottom side (the point) and the stuff just up
- of that is black so we simplify those two cases.
- */
- if (sat < 32768) {
- /* anything less than this is unsaturated */
- *r = val;
- *g = val;
- *b = val;
- return;
- }
- if (val <= (0xFFFF/8)) {
- /* anything less than this is black */
- *r = 0;
- *g = 0;
- *b = 0;
- return;
- }
-
- /* the rest of this code is copying tukkat's
- implementation of the hsv2rgb conversion as taken
- from qc-usb-messenger code. the 10923 is 0xFFFF/6
- to divide the cone into 6 sectors. */
-
- segment = (h + 10923) & 0xFFFF;
- segment = segment*3 >> 16; /* 0..2: 0=R, 1=G, 2=B */
- hue -= segment * 21845; /* -10923..10923 */
- h = hue;
- h *= 3;
- valsat = v*s >> 16; /* 0..65534 */
- p = v - valsat;
- if (h >= 0) {
- unsigned int t = v - (valsat * (32769 - h) >> 15);
- switch (segment) {
- case 0: /* R-> */
- *r = v;
- *g = t;
- *b = p;
- break;
- case 1: /* G-> */
- *r = p;
- *g = v;
- *b = t;
- break;
- case 2: /* B-> */
- *r = t;
- *g = p;
- *b = v;
- break;
- }
- } else {
- unsigned int q = v - (valsat * (32769 + h) >> 15);
- switch (segment) {
- case 0: /* ->R */
- *r = v;
- *g = p;
- *b = q;
- break;
- case 1: /* ->G */
- *r = q;
- *g = v;
- *b = p;
- break;
- case 2: /* ->B */
- *r = p;
- *g = q;
- *b = v;
- break;
- }
- }
-}
-
-static int qcm_sensor_set_gains(struct uvd *uvd, u16 hue,
- u16 saturation, u16 value)
-{
- int ret;
- u16 r=0,g=0,b=0;
-
- /* this code is based on qc-usb-messenger */
- qcm_hsv2rgb(hue, saturation, value, &r, &g, &b);
-
- r >>= 12;
- g >>= 12;
- b >>= 12;
-
- /* min val is 8 */
- r = max((u16) 8, r);
- g = max((u16) 8, g);
- b = max((u16) 8, b);
-
- r |= 0x30;
- g |= 0x30;
- b |= 0x30;
-
- /* set the r,g,b gain registers */
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x0509, r));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050A, g));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050B, b));
-
- /* doing as qc-usb did */
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050C, 0x2A));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x050D, 0x01));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-
- return 0;
-}
-
-static int qcm_sensor_set_exposure(struct uvd *uvd, int exposure)
-{
- int ret;
- int formedval;
-
- /* calculation was from qc-usb-messenger driver */
- formedval = ( exposure >> 12 );
-
- /* max value for formedval is 14 */
- formedval = min(formedval, 14);
-
- CHECK_RET(ret, qcm_stv_setb(uvd->dev,
- 0x143A, 0xF0 | formedval));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
- return 0;
-}
-
-static int qcm_sensor_setlevels(struct uvd *uvd, int brightness, int contrast,
- int hue, int colour)
-{
- int ret;
- /* brightness is exposure, contrast is gain, colour is saturation */
- CHECK_RET(ret,
- qcm_sensor_set_exposure(uvd, brightness));
- CHECK_RET(ret, qcm_sensor_set_gains(uvd, hue, colour, contrast));
-
- return 0;
-}
-
-static int qcm_sensor_setsize(struct uvd *uvd, u8 size)
-{
- int ret;
-
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x1505, size));
- return 0;
-}
-
-static int qcm_sensor_set_shutter(struct uvd *uvd, int whiteness)
-{
- int ret;
- /* some rescaling as done by the qc-usb-messenger code */
- if (whiteness > 0xC000)
- whiteness = 0xC000 + (whiteness & 0x3FFF)*8;
-
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143D,
- (whiteness >> 8) & 0xFF));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143E,
- (whiteness >> 16) & 0x03));
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, 0x143F, 0x01));
-
- return 0;
-}
-
-static int qcm_sensor_init(struct uvd *uvd)
-{
- struct qcm *cam = (struct qcm *) uvd->user_data;
- int ret;
- int i;
-
- for (i=0; i < ARRAY_SIZE(regval_table) ; i++) {
- CHECK_RET(ret, qcm_stv_setb(uvd->dev,
- regval_table[i].reg,
- regval_table[i].val));
- }
-
- 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, qcm_stv_setb(uvd->dev, 0x143f, 0x01));
-
- CHECK_RET(ret, qcm_stv_setb(uvd->dev, STV_ISO_ENABLE, 0x00));
-
- CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-
- CHECK_RET(ret, qcm_sensor_setlevels(uvd, uvd->vpic.brightness,
- uvd->vpic.contrast, uvd->vpic.hue, uvd->vpic.colour));
-
- CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
- CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
-
- return 0;
-}
-
-static int qcm_set_camera_size(struct uvd *uvd)
-{
- int ret;
- struct qcm *cam = (struct qcm *) uvd->user_data;
-
- CHECK_RET(ret, qcm_sensor_setsize(uvd, camera_sizes[cam->size].cmd));
- cam->width = camera_sizes[cam->size].width;
- cam->height = camera_sizes[cam->size].height;
- uvd->videosize = VIDEOSIZE(cam->width, cam->height);
-
- return 0;
-}
-
-static int qcm_setup_on_open(struct uvd *uvd)
-{
- int ret;
-
- CHECK_RET(ret, qcm_sensor_set_gains(uvd, uvd->vpic.hue,
- uvd->vpic.colour, uvd->vpic.contrast));
- CHECK_RET(ret, qcm_sensor_set_exposure(uvd, uvd->vpic.brightness));
- CHECK_RET(ret, qcm_sensor_set_shutter(uvd, uvd->vpic.whiteness));
- CHECK_RET(ret, qcm_set_camera_size(uvd));
- CHECK_RET(ret, qcm_camera_on(uvd));
- return 0;
-}
-
-static void qcm_adjust_picture(struct uvd *uvd)
-{
- int ret;
- struct qcm *cam = (struct qcm *) uvd->user_data;
-
- ret = qcm_camera_off(uvd);
- if (ret) {
- err("can't turn camera off. abandoning pic adjustment");
- return;
- }
-
- /* if there's been a change in contrast, hue, or
- colour then we need to recalculate hsv in order
- to update gains */
- if ((cam->contrast != uvd->vpic.contrast) ||
- (cam->hue != uvd->vpic.hue) ||
- (cam->colour != uvd->vpic.colour)) {
- cam->contrast = uvd->vpic.contrast;
- cam->hue = uvd->vpic.hue;
- cam->colour = uvd->vpic.colour;
- ret = qcm_sensor_set_gains(uvd, cam->hue, cam->colour,
- cam->contrast);
- if (ret) {
- err("can't set gains. abandoning pic adjustment");
- return;
- }
- }
-
- if (cam->brightness != uvd->vpic.brightness) {
- cam->brightness = uvd->vpic.brightness;
- ret = qcm_sensor_set_exposure(uvd, cam->brightness);
- if (ret) {
- err("can't set exposure. abandoning pic adjustment");
- return;
- }
- }
-
- if (cam->whiteness != uvd->vpic.whiteness) {
- cam->whiteness = uvd->vpic.whiteness;
- qcm_sensor_set_shutter(uvd, cam->whiteness);
- if (ret) {
- err("can't set shutter. abandoning pic adjustment");
- return;
- }
- }
-
- ret = qcm_camera_on(uvd);
- if (ret) {
- err("can't reenable camera. pic adjustment failed");
- return;
- }
-}
-
-static int qcm_process_frame(struct uvd *uvd, u8 *cdata, int framelen)
-{
- int datalen;
- int totaldata;
- struct framehdr {
- __be16 id;
- __be16 len;
- };
- struct framehdr *fhdr;
-
- totaldata = 0;
- while (framelen) {
- fhdr = (struct framehdr *) cdata;
- datalen = be16_to_cpu(fhdr->len);
- framelen -= 4;
- cdata += 4;
-
- if ((fhdr->id) == cpu_to_be16(0x8001)) {
- RingQueue_Enqueue(&uvd->dp, marker, 4);
- totaldata += 4;
- continue;
- }
- if ((fhdr->id & cpu_to_be16(0xFF00)) == cpu_to_be16(0x0200)) {
- RingQueue_Enqueue(&uvd->dp, cdata, datalen);
- totaldata += datalen;
- }
- framelen -= datalen;
- cdata += datalen;
- }
- return totaldata;
-}
-
-static int qcm_compress_iso(struct uvd *uvd, struct urb *dataurb)
-{
- int totlen;
- int i;
- unsigned char *cdata;
-
- totlen=0;
- for (i = 0; i < dataurb->number_of_packets; i++) {
- int n = dataurb->iso_frame_desc[i].actual_length;
- int st = dataurb->iso_frame_desc[i].status;
-
- cdata = dataurb->transfer_buffer +
- dataurb->iso_frame_desc[i].offset;
-
- if (st < 0) {
- dev_warn(&uvd->dev->dev,
- "Data error: packet=%d. len=%d. status=%d.\n",
- i, n, st);
- uvd->stats.iso_err_count++;
- continue;
- }
- if (!n)
- continue;
-
- totlen += qcm_process_frame(uvd, cdata, n);
- }
- return totlen;
-}
-
-static void resubmit_urb(struct uvd *uvd, struct urb *urb)
-{
- int ret;
-
- urb->dev = uvd->dev;
- ret = usb_submit_urb(urb, GFP_ATOMIC);
- if (ret)
- err("usb_submit_urb error (%d)", ret);
-}
-
-static void qcm_isoc_irq(struct urb *urb)
-{
- int len;
- struct uvd *uvd = urb->context;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return;
-
- if (!uvd->streaming)
- return;
-
- uvd->stats.urb_count++;
-
- if (!urb->actual_length) {
- resubmit_urb(uvd, urb);
- return;
- }
-
- len = qcm_compress_iso(uvd, urb);
- resubmit_urb(uvd, urb);
- uvd->stats.urb_length = len;
- uvd->stats.data_count += len;
- if (len)
- RingQueue_WakeUpInterruptible(&uvd->dp);
-}
-
-static int qcm_start_data(struct uvd *uvd)
-{
- struct qcm *cam = (struct qcm *) uvd->user_data;
- int i;
- int errflag;
- int pktsz;
- int err;
-
- pktsz = uvd->iso_packet_len;
- if (!CAMERA_IS_OPERATIONAL(uvd)) {
- err("Camera is not operational");
- return -EFAULT;
- }
-
- err = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltActive);
- if (err < 0) {
- err("usb_set_interface error");
- uvd->last_error = err;
- return -EBUSY;
- }
-
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- int j, k;
- struct urb *urb = uvd->sbuf[i].urb;
- urb->dev = uvd->dev;
- urb->context = uvd;
- urb->pipe = usb_rcvisocpipe(uvd->dev, uvd->video_endp);
- urb->interval = 1;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = uvd->sbuf[i].data;
- urb->complete = qcm_isoc_irq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = pktsz * FRAMES_PER_DESC;
- for (j=k=0; j < FRAMES_PER_DESC; j++, k += pktsz) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length = pktsz;
- }
- }
-
- uvd->streaming = 1;
- uvd->curframe = -1;
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- errflag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
- if (errflag)
- err ("usb_submit_isoc(%d) ret %d", i, errflag);
- }
-
- CHECK_RET(err, qcm_setup_input_int(cam, uvd));
- CHECK_RET(err, qcm_camera_on(uvd));
- return 0;
-}
-
-static void qcm_stop_data(struct uvd *uvd)
-{
- struct qcm *cam;
- int i, j;
- int ret;
-
- if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
- return;
- cam = (struct qcm *) uvd->user_data;
-
- ret = qcm_camera_off(uvd);
- if (ret)
- dev_warn(&uvd->dev->dev, "couldn't turn the cam off.\n");
-
- uvd->streaming = 0;
-
- /* Unschedule all of the iso td's */
- for (i=0; i < USBVIDEO_NUMSBUF; i++)
- usb_kill_urb(uvd->sbuf[i].urb);
-
- qcm_stop_int_data(cam);
-
- if (!uvd->remove_pending) {
- /* Set packet size to 0 */
- j = usb_set_interface(uvd->dev, uvd->iface,
- uvd->ifaceAltInactive);
- if (j < 0) {
- err("usb_set_interface() error %d.", j);
- uvd->last_error = j;
- }
- }
-}
-
-static void qcm_process_isoc(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- struct qcm *cam = (struct qcm *) uvd->user_data;
- int x;
- struct rgb *rgbL0;
- struct rgb *rgbL1;
- struct bayL0 *bayL0;
- struct bayL1 *bayL1;
- int hor,ver,hordel,verdel;
- assert(frame != NULL);
-
- switch (cam->size) {
- case SIZE_160X120:
- hor = 162; ver = 124; hordel = 1; verdel = 2;
- break;
- case SIZE_320X240:
- default:
- hor = 324; ver = 248; hordel = 2; verdel = 4;
- break;
- }
-
- if (frame->scanstate == ScanState_Scanning) {
- while (RingQueue_GetLength(&uvd->dp) >=
- 4 + (hor*verdel + hordel)) {
- if ((RING_QUEUE_PEEK(&uvd->dp, 0) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 1) == 0xff) &&
- (RING_QUEUE_PEEK(&uvd->dp, 2) == 0x00) &&
- (RING_QUEUE_PEEK(&uvd->dp, 3) == 0xff)) {
- frame->curline = 0;
- frame->scanstate = ScanState_Lines;
- frame->frameState = FrameState_Grabbing;
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 4);
- /*
- * if we're starting, we need to discard the first
- * 4 lines of y bayer data
- * and the first 2 gr elements of x bayer data
- */
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp,
- (hor*verdel + hordel));
- break;
- }
- RING_QUEUE_DEQUEUE_BYTES(&uvd->dp, 1);
- }
- }
-
- if (frame->scanstate == ScanState_Scanning)
- return;
-
- /* now we can start processing bayer data so long as we have at least
- * 2 lines worth of data. this is the simplest demosaicing method that
- * I could think of. I use each 2x2 bayer element without interpolation
- * to generate 4 rgb pixels.
- */
- while ( frame->curline < cam->height &&
- (RingQueue_GetLength(&uvd->dp) >= hor*2)) {
- /* get 2 lines of bayer for demosaicing
- * into 2 lines of RGB */
- RingQueue_Dequeue(&uvd->dp, cam->scratch, hor*2);
- bayL0 = (struct bayL0 *) cam->scratch;
- bayL1 = (struct bayL1 *) (cam->scratch + hor);
- /* frame->curline is the rgb y line */
- rgbL0 = (struct rgb *)
- ( frame->data + (cam->width*3*frame->curline));
- /* w/2 because we're already doing 2 pixels */
- rgbL1 = rgbL0 + (cam->width/2);
-
- for (x=0; x < cam->width; x+=2) {
- rgbL0->r = bayL0->r;
- rgbL0->g = bayL0->g;
- rgbL0->b = bayL1->b;
-
- rgbL0->r2 = bayL0->r;
- rgbL0->g2 = bayL1->g;
- rgbL0->b2 = bayL1->b;
-
- rgbL1->r = bayL0->r;
- rgbL1->g = bayL1->g;
- rgbL1->b = bayL1->b;
-
- rgbL1->r2 = bayL0->r;
- rgbL1->g2 = bayL1->g;
- rgbL1->b2 = bayL1->b;
-
- rgbL0++;
- rgbL1++;
-
- bayL0++;
- bayL1++;
- }
-
- frame->seqRead_Length += cam->width*3*2;
- frame->curline += 2;
- }
- /* See if we filled the frame */
- if (frame->curline == cam->height) {
- frame->frameState = FrameState_Done_Hold;
- frame->curline = 0;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- }
-}
-
-/* taken from konicawc */
-static int qcm_set_video_mode(struct uvd *uvd, struct video_window *vw)
-{
- int ret;
- int newsize;
- int oldsize;
- int x = vw->width;
- int y = vw->height;
- struct qcm *cam = (struct qcm *) uvd->user_data;
-
- if (x > 0 && y > 0) {
- DEBUG(2, "trying to find size %d,%d", x, y);
- for (newsize = 0; newsize <= MAX_FRAME_SIZE; newsize++) {
- if ((camera_sizes[newsize].width == x) &&
- (camera_sizes[newsize].height == y))
- break;
- }
- } else
- newsize = cam->size;
-
- if (newsize > MAX_FRAME_SIZE) {
- DEBUG(1, "couldn't find size %d,%d", x, y);
- return -EINVAL;
- }
-
- if (newsize == cam->size) {
- DEBUG(1, "Nothing to do");
- return 0;
- }
-
- qcm_stop_data(uvd);
-
- if (cam->size != newsize) {
- oldsize = cam->size;
- cam->size = newsize;
- ret = qcm_set_camera_size(uvd);
- if (ret) {
- err("Couldn't set camera size, err=%d",ret);
- /* restore the original size */
- cam->size = oldsize;
- return ret;
- }
- }
-
- /* Flush the input queue and clear any current frame in progress */
-
- RingQueue_Flush(&uvd->dp);
- if (uvd->curframe != -1) {
- uvd->frame[uvd->curframe].curline = 0;
- uvd->frame[uvd->curframe].seqRead_Length = 0;
- uvd->frame[uvd->curframe].seqRead_Index = 0;
- }
-
- CHECK_RET(ret, qcm_start_data(uvd));
- return 0;
-}
-
-static int qcm_configure_video(struct uvd *uvd)
-{
- int ret;
- memset(&uvd->vpic, 0, sizeof(uvd->vpic));
- memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
- uvd->vpic.colour = colour;
- uvd->vpic.hue = hue;
- uvd->vpic.brightness = brightness;
- uvd->vpic.contrast = contrast;
- uvd->vpic.whiteness = whiteness;
- uvd->vpic.depth = 24;
- uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
- memset(&uvd->vcap, 0, sizeof(uvd->vcap));
- strcpy(uvd->vcap.name, "QCM USB Camera");
- uvd->vcap.type = VID_TYPE_CAPTURE;
- uvd->vcap.channels = 1;
- uvd->vcap.audios = 0;
-
- uvd->vcap.minwidth = camera_sizes[SIZE_160X120].width;
- uvd->vcap.minheight = camera_sizes[SIZE_160X120].height;
- uvd->vcap.maxwidth = camera_sizes[SIZE_320X240].width;
- uvd->vcap.maxheight = camera_sizes[SIZE_320X240].height;
-
- memset(&uvd->vchan, 0, sizeof(uvd->vchan));
- uvd->vchan.flags = 0 ;
- uvd->vchan.tuners = 0;
- uvd->vchan.channel = 0;
- uvd->vchan.type = VIDEO_TYPE_CAMERA;
- strcpy(uvd->vchan.name, "Camera");
-
- CHECK_RET(ret, qcm_sensor_init(uvd));
- return 0;
-}
-
-static int qcm_probe(struct usb_interface *intf,
- const struct usb_device_id *devid)
-{
- int err;
- struct uvd *uvd;
- struct usb_device *dev = interface_to_usbdev(intf);
- struct qcm *cam;
- size_t buffer_size;
- unsigned char video_ep;
- struct usb_host_interface *interface;
- struct usb_endpoint_descriptor *endpoint;
- int i,j;
- unsigned int ifacenum, ifacenum_inact=0;
- __le16 sensor_id;
-
- /* we don't support multiconfig cams */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- /* first check for the video interface and not
- * the audio interface */
- interface = &intf->cur_altsetting[0];
- if ((interface->desc.bInterfaceClass != USB_CLASS_VENDOR_SPEC)
- || (interface->desc.bInterfaceSubClass !=
- USB_CLASS_VENDOR_SPEC))
- return -ENODEV;
-
- /*
- walk through each endpoint in each setting in the interface
- stop when we find the one that's an isochronous IN endpoint.
- */
- for (i=0; i < intf->num_altsetting; i++) {
- interface = &intf->cur_altsetting[i];
- ifacenum = interface->desc.bAlternateSetting;
- /* walk the end points */
- for (j=0; j < interface->desc.bNumEndpoints; j++) {
- endpoint = &interface->endpoint[j].desc;
-
- if (usb_endpoint_dir_out(endpoint))
- continue; /* not input then not good */
-
- buffer_size = le16_to_cpu(endpoint->wMaxPacketSize);
- if (!buffer_size) {
- ifacenum_inact = ifacenum;
- continue; /* 0 pkt size is not what we want */
- }
-
- if (usb_endpoint_xfer_isoc(endpoint)) {
- video_ep = endpoint->bEndpointAddress;
- /* break out of the search */
- goto good_videoep;
- }
- }
- }
- /* failed out since nothing useful was found */
- err("No suitable endpoint was found\n");
- return -ENODEV;
-
-good_videoep:
- /* disable isochronous stream before doing anything else */
- err = qcm_stv_setb(dev, STV_ISO_ENABLE, 0);
- if (err < 0) {
- err("Failed to disable sensor stream");
- return -EIO;
- }
-
- /*
- Check that this is the same unknown sensor that is known to work. This
- sensor is suspected to be the ST VV6422C001. I'll check the same value
- that the qc-usb driver checks. This value is probably not even the
- sensor ID since it matches the USB dev ID. Oh well. If it doesn't
- match, it's probably a diff sensor so exit and apologize.
- */
- err = qcm_stv_getw(dev, CMOS_SENSOR_IDREV, &sensor_id);
- if (err < 0) {
- err("Couldn't read sensor values. Err %d\n",err);
- return err;
- }
- if (sensor_id != cpu_to_le16(0x08F0)) {
- err("Sensor ID %x != %x. Unsupported. Sorry\n",
- le16_to_cpu(sensor_id), (0x08F0));
- return -ENODEV;
- }
-
- uvd = usbvideo_AllocateDevice(cams);
- if (!uvd)
- return -ENOMEM;
-
- cam = (struct qcm *) uvd->user_data;
-
- /* buf for doing demosaicing */
- cam->scratch = kmalloc(324*2, GFP_KERNEL);
- if (!cam->scratch) /* uvd freed in dereg */
- return -ENOMEM;
-
- /* yes, if we fail after here, cam->scratch gets freed
- by qcm_free_uvd */
-
- err = qcm_alloc_int_urb(cam);
- if (err < 0)
- return err;
-
- /* yes, if we fail after here, int urb gets freed
- by qcm_free_uvd */
-
- RESTRICT_TO_RANGE(size, SIZE_160X120, SIZE_320X240);
- cam->width = camera_sizes[size].width;
- cam->height = camera_sizes[size].height;
- cam->size = size;
-
- uvd->debug = debug;
- uvd->flags = 0;
- uvd->dev = dev;
- uvd->iface = intf->altsetting->desc.bInterfaceNumber;
- uvd->ifaceAltActive = ifacenum;
- uvd->ifaceAltInactive = ifacenum_inact;
- uvd->video_endp = video_ep;
- uvd->iso_packet_len = buffer_size;
- uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
- uvd->defaultPalette = VIDEO_PALETTE_RGB24;
- uvd->canvas = VIDEOSIZE(320, 240);
- uvd->videosize = VIDEOSIZE(cam->width, cam->height);
- err = qcm_configure_video(uvd);
- if (err) {
- err("failed to configure video settings");
- return err;
- }
-
- err = usbvideo_RegisterVideoDevice(uvd);
- if (err) { /* the uvd gets freed in Deregister */
- err("usbvideo_RegisterVideoDevice() failed.");
- return err;
- }
-
- uvd->max_frame_size = (320 * 240 * 3);
- qcm_register_input(cam, dev);
- usb_set_intfdata(intf, uvd);
- return 0;
-}
-
-static void qcm_free_uvd(struct uvd *uvd)
-{
- struct qcm *cam = (struct qcm *) uvd->user_data;
-
- kfree(cam->scratch);
- qcm_unregister_input(cam);
- qcm_free_int(cam);
-}
-
-static struct usbvideo_cb qcm_driver = {
- .probe = qcm_probe,
- .setupOnOpen = qcm_setup_on_open,
- .processData = qcm_process_isoc,
- .setVideoMode = qcm_set_video_mode,
- .startDataPump = qcm_start_data,
- .stopDataPump = qcm_stop_data,
- .adjustPicture = qcm_adjust_picture,
- .userFree = qcm_free_uvd
-};
-
-static int __init qcm_init(void)
-{
- printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION ":"
- DRIVER_DESC "\n");
-
- return usbvideo_register(
- &cams,
- MAX_CAMERAS,
- sizeof(struct qcm),
- "QCM",
- &qcm_driver,
- THIS_MODULE,
- qcm_table);
-}
-
-static void __exit qcm_exit(void)
-{
- usbvideo_Deregister(&cams);
-}
-
-module_param(size, int, 0);
-MODULE_PARM_DESC(size, "Initial Size 0: 160x120 1: 320x240");
-module_param(colour, int, 0);
-MODULE_PARM_DESC(colour, "Initial colour");
-module_param(hue, int, 0);
-MODULE_PARM_DESC(hue, "Initial hue");
-module_param(brightness, int, 0);
-MODULE_PARM_DESC(brightness, "Initial brightness");
-module_param(contrast, int, 0);
-MODULE_PARM_DESC(contrast, "Initial contrast");
-module_param(whiteness, int, 0);
-MODULE_PARM_DESC(whiteness, "Initial whiteness");
-
-#ifdef CONFIG_USB_DEBUG
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-#endif
-
-module_init(qcm_init);
-module_exit(qcm_exit);
-
-MODULE_LICENSE("GPL");
-MODULE_AUTHOR("Jaya Kumar");
-MODULE_DESCRIPTION("QCM USB Camera");
-MODULE_SUPPORTED_DEVICE("QCM USB Camera");
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.h b/drivers/media/video/usbvideo/quickcam_messenger.h
deleted file mode 100644
index 17ace394d981..000000000000
--- a/drivers/media/video/usbvideo/quickcam_messenger.h
+++ /dev/null
@@ -1,112 +0,0 @@
-#ifndef quickcam_messenger_h
-#define quickcam_messenger_h
-
-#ifndef CONFIG_INPUT
-/* if we're not using input we dummy out these functions */
-#define qcm_register_input(...)
-#define qcm_unregister_input(...)
-#define qcm_report_buttonstat(...)
-#define qcm_setup_input_int(...) 0
-#define qcm_stop_int_data(...)
-#define qcm_alloc_int_urb(...) 0
-#define qcm_free_int(...)
-#endif
-
-
-#define CHECK_RET(ret, expr) \
- if ((ret = expr) < 0) return ret
-
-/* Control Registers for the STVV6422 ASIC
- * - this define is taken from the qc-usb-messenger code
- */
-#define STV_ISO_ENABLE 0x1440
-#define ISOC_PACKET_SIZE 1023
-
-/* Chip identification number including revision indicator */
-#define CMOS_SENSOR_IDREV 0xE00A
-
-struct rgb {
- u8 b;
- u8 g;
- u8 r;
- u8 b2;
- u8 g2;
- u8 r2;
-};
-
-struct bayL0 {
- u8 g;
- u8 r;
-};
-
-struct bayL1 {
- u8 b;
- u8 g;
-};
-
-struct cam_size {
- u16 width;
- u16 height;
- u8 cmd;
-};
-
-static const struct cam_size camera_sizes[] = {
- { 160, 120, 0xf },
- { 320, 240, 0x2 },
-};
-
-enum frame_sizes {
- SIZE_160X120 = 0,
- SIZE_320X240 = 1,
-};
-
-#define MAX_FRAME_SIZE SIZE_320X240
-
-struct qcm {
- u16 colour;
- u16 hue;
- u16 brightness;
- u16 contrast;
- u16 whiteness;
-
- u8 size;
- int height;
- int width;
- u8 *scratch;
- struct urb *button_urb;
- u8 button_sts;
- u8 button_sts_buf;
-
-#ifdef CONFIG_INPUT
- struct input_dev *input;
- char input_physname[64];
-#endif
-};
-
-struct regval {
- u16 reg;
- u8 val;
-};
-/* this table is derived from the
-qc-usb-messenger code */
-static const struct regval regval_table[] = {
- { STV_ISO_ENABLE, 0x00 },
- { 0x1436, 0x00 }, { 0x1432, 0x03 },
- { 0x143a, 0xF9 }, { 0x0509, 0x38 },
- { 0x050a, 0x38 }, { 0x050b, 0x38 },
- { 0x050c, 0x2A }, { 0x050d, 0x01 },
- { 0x1431, 0x00 }, { 0x1433, 0x34 },
- { 0x1438, 0x18 }, { 0x1439, 0x00 },
- { 0x143b, 0x05 }, { 0x143c, 0x00 },
- { 0x143e, 0x01 }, { 0x143d, 0x00 },
- { 0x1442, 0xe2 }, { 0x1500, 0xd0 },
- { 0x1500, 0xd0 }, { 0x1500, 0x50 },
- { 0x1501, 0xaf }, { 0x1502, 0xc2 },
- { 0x1503, 0x45 }, { 0x1505, 0x02 },
- { 0x150e, 0x8e }, { 0x150f, 0x37 },
- { 0x15c0, 0x00 },
-};
-
-static const unsigned char marker[] = { 0x00, 0xff, 0x00, 0xFF };
-
-#endif /* quickcam_messenger_h */
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
deleted file mode 100644
index fbd1b6392290..000000000000
--- a/drivers/media/video/usbvideo/ultracam.c
+++ /dev/null
@@ -1,685 +0,0 @@
-/*
- * USB NB Camera driver
- *
- * HISTORY:
- * 25-Dec-2002 Dmitri Removed lighting, sharpness parameters, methods.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-#include "usbvideo.h"
-
-#define ULTRACAM_VENDOR_ID 0x0461
-#define ULTRACAM_PRODUCT_ID 0x0813
-
-#define MAX_CAMERAS 4 /* How many devices we allow to connect */
-
-/*
- * This structure lives in uvd_t->user field.
- */
-typedef struct {
- int initialized; /* Had we already sent init sequence? */
- int camera_model; /* What type of IBM camera we got? */
- int has_hdr;
-} ultracam_t;
-#define ULTRACAM_T(uvd) ((ultracam_t *)((uvd)->user_data))
-
-static struct usbvideo *cams = NULL;
-
-static int debug;
-
-static int flags; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
-
-static const int min_canvasWidth = 8;
-static const int min_canvasHeight = 4;
-
-#define FRAMERATE_MIN 0
-#define FRAMERATE_MAX 6
-static int framerate = -1;
-
-/*
- * Here we define several initialization variables. They may
- * be used to automatically set color, hue, brightness and
- * contrast to desired values. This is particularly useful in
- * case of webcams (which have no controls and no on-screen
- * output) and also when a client V4L software is used that
- * does not have some of those controls. In any case it's
- * good to have startup values as options.
- *
- * These values are all in [0..255] range. This simplifies
- * operation. Note that actual values of V4L variables may
- * be scaled up (as much as << 8). User can see that only
- * on overlay output, however, or through a V4L client.
- */
-static int init_brightness = 128;
-static int init_contrast = 192;
-static int init_color = 128;
-static int init_hue = 128;
-static int hue_correction = 128;
-
-module_param(debug, int, S_IRUGO | S_IWUSR);
-MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
-module_param(flags, int, 0);
-MODULE_PARM_DESC(flags,
- "Bitfield: 0=VIDIOCSYNC, "
- "1=B/W, "
- "2=show hints, "
- "3=show stats, "
- "4=test pattern, "
- "5=separate frames, "
- "6=clean frames");
-module_param(framerate, int, 0);
-MODULE_PARM_DESC(framerate, "Framerate setting: 0=slowest, 6=fastest (default=2)");
-
-module_param(init_brightness, int, 0);
-MODULE_PARM_DESC(init_brightness, "Brightness preconfiguration: 0-255 (default=128)");
-module_param(init_contrast, int, 0);
-MODULE_PARM_DESC(init_contrast, "Contrast preconfiguration: 0-255 (default=192)");
-module_param(init_color, int, 0);
-MODULE_PARM_DESC(init_color, "Color preconfiguration: 0-255 (default=128)");
-module_param(init_hue, int, 0);
-MODULE_PARM_DESC(init_hue, "Hue preconfiguration: 0-255 (default=128)");
-module_param(hue_correction, int, 0);
-MODULE_PARM_DESC(hue_correction, "YUV colorspace regulation: 0-255 (default=128)");
-
-/*
- * ultracam_ProcessIsocData()
- *
- * Generic routine to parse the ring queue data. It employs either
- * ultracam_find_header() or ultracam_parse_lines() to do most
- * of work.
- *
- * 02-Nov-2000 First (mostly dummy) version.
- * 06-Nov-2000 Rewrote to dump all data into frame.
- */
-static void ultracam_ProcessIsocData(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- int n;
-
- assert(uvd != NULL);
- assert(frame != NULL);
-
- /* Try to move data from queue into frame buffer */
- n = RingQueue_GetLength(&uvd->dp);
- if (n > 0) {
- int m;
- /* See how much spare we have left */
- m = uvd->max_frame_size - frame->seqRead_Length;
- if (n > m)
- n = m;
- /* Now move that much data into frame buffer */
- RingQueue_Dequeue(
- &uvd->dp,
- frame->data + frame->seqRead_Length,
- m);
- frame->seqRead_Length += m;
- }
- /* See if we filled the frame */
- if (frame->seqRead_Length >= uvd->max_frame_size) {
- frame->frameState = FrameState_Done;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- }
-}
-
-/*
- * ultracam_veio()
- *
- * History:
- * 1/27/00 Added check for dev == NULL; this happens if camera is unplugged.
- */
-static int ultracam_veio(
- struct uvd *uvd,
- unsigned char req,
- unsigned short value,
- unsigned short index,
- int is_out)
-{
- static const char proc[] = "ultracam_veio";
- unsigned char cp[8] /* = { 0xde, 0xad, 0xbe, 0xef, 0xde, 0xad, 0xbe, 0xef } */;
- int i;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return 0;
-
- if (!is_out) {
- i = usb_control_msg(
- uvd->dev,
- usb_rcvctrlpipe(uvd->dev, 0),
- req,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- index,
- cp,
- sizeof(cp),
- 1000);
-#if 1
- dev_info(&uvd->dev->dev,
- "USB => %02x%02x%02x%02x%02x%02x%02x%02x "
- "(req=$%02x val=$%04x ind=$%04x)\n",
- cp[0],cp[1],cp[2],cp[3],cp[4],cp[5],cp[6],cp[7],
- req, value, index);
-#endif
- } else {
- i = usb_control_msg(
- uvd->dev,
- usb_sndctrlpipe(uvd->dev, 0),
- req,
- USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- value,
- index,
- NULL,
- 0,
- 1000);
- }
- if (i < 0) {
- err("%s: ERROR=%d. Camera stopped; Reconnect or reload driver.",
- proc, i);
- uvd->last_error = i;
- }
- return i;
-}
-
-/*
- * ultracam_calculate_fps()
- */
-static int ultracam_calculate_fps(struct uvd *uvd)
-{
- return 3 + framerate*4 + framerate/2;
-}
-
-/*
- * ultracam_adjust_contrast()
- */
-static void ultracam_adjust_contrast(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_set_brightness()
- *
- * This procedure changes brightness of the picture.
- */
-static void ultracam_set_brightness(struct uvd *uvd)
-{
-}
-
-static void ultracam_set_hue(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_adjust_picture()
- *
- * This procedure gets called from V4L interface to update picture settings.
- * Here we change brightness and contrast.
- */
-static void ultracam_adjust_picture(struct uvd *uvd)
-{
- ultracam_adjust_contrast(uvd);
- ultracam_set_brightness(uvd);
- ultracam_set_hue(uvd);
-}
-
-/*
- * ultracam_video_stop()
- *
- * This code tells camera to stop streaming. The interface remains
- * configured and bandwidth - claimed.
- */
-static void ultracam_video_stop(struct uvd *uvd)
-{
-}
-
-/*
- * ultracam_reinit_iso()
- *
- * This procedure sends couple of commands to the camera and then
- * resets the video pipe. This sequence was observed to reinit the
- * camera or, at least, to initiate ISO data stream.
- */
-static void ultracam_reinit_iso(struct uvd *uvd, int do_stop)
-{
-}
-
-static void ultracam_video_start(struct uvd *uvd)
-{
- ultracam_reinit_iso(uvd, 0);
-}
-
-static int ultracam_resetPipe(struct uvd *uvd)
-{
- usb_clear_halt(uvd->dev, uvd->video_endp);
- return 0;
-}
-
-static int ultracam_alternateSetting(struct uvd *uvd, int setting)
-{
- static const char proc[] = "ultracam_alternateSetting";
- int i;
- i = usb_set_interface(uvd->dev, uvd->iface, setting);
- if (i < 0) {
- err("%s: usb_set_interface error", proc);
- uvd->last_error = i;
- return -EBUSY;
- }
- return 0;
-}
-
-/*
- * Return negative code on failure, 0 on success.
- */
-static int ultracam_setup_on_open(struct uvd *uvd)
-{
- int setup_ok = 0; /* Success by default */
- /* Send init sequence only once, it's large! */
- if (!ULTRACAM_T(uvd)->initialized) {
- ultracam_alternateSetting(uvd, 0x04);
- ultracam_alternateSetting(uvd, 0x00);
- ultracam_veio(uvd, 0x02, 0x0004, 0x000b, 1);
- ultracam_veio(uvd, 0x02, 0x0001, 0x0005, 1);
- ultracam_veio(uvd, 0x02, 0x8000, 0x0000, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
- ultracam_veio(uvd, 0x00, 0x00b0, 0x0001, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0002, 1);
- ultracam_veio(uvd, 0x00, 0x000c, 0x0003, 1);
- ultracam_veio(uvd, 0x00, 0x000b, 0x0004, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0005, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0006, 1);
- ultracam_veio(uvd, 0x00, 0x0079, 0x0007, 1);
- ultracam_veio(uvd, 0x00, 0x003b, 0x0008, 1);
- ultracam_veio(uvd, 0x00, 0x0002, 0x000f, 1);
- ultracam_veio(uvd, 0x00, 0x0001, 0x0010, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0011, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00bf, 1);
- ultracam_veio(uvd, 0x00, 0x0001, 0x00c0, 1);
- ultracam_veio(uvd, 0x00, 0x0010, 0x00cb, 1);
- ultracam_veio(uvd, 0x01, 0x00a4, 0x0001, 1);
- ultracam_veio(uvd, 0x01, 0x0010, 0x0002, 1);
- ultracam_veio(uvd, 0x01, 0x0066, 0x0007, 1);
- ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
- ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
- ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
- ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
- ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
- ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
- ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
- ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
- ultracam_veio(uvd, 0x01, 0x000b, 0x0011, 1);
- ultracam_veio(uvd, 0x01, 0x0001, 0x0012, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0013, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0014, 1);
- ultracam_veio(uvd, 0x01, 0x0087, 0x0051, 1);
- ultracam_veio(uvd, 0x01, 0x0040, 0x0052, 1);
- ultracam_veio(uvd, 0x01, 0x0058, 0x0053, 1);
- ultracam_veio(uvd, 0x01, 0x0040, 0x0054, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0040, 1);
- ultracam_veio(uvd, 0x01, 0x0010, 0x0041, 1);
- ultracam_veio(uvd, 0x01, 0x0020, 0x0042, 1);
- ultracam_veio(uvd, 0x01, 0x0030, 0x0043, 1);
- ultracam_veio(uvd, 0x01, 0x0040, 0x0044, 1);
- ultracam_veio(uvd, 0x01, 0x0050, 0x0045, 1);
- ultracam_veio(uvd, 0x01, 0x0060, 0x0046, 1);
- ultracam_veio(uvd, 0x01, 0x0070, 0x0047, 1);
- ultracam_veio(uvd, 0x01, 0x0080, 0x0048, 1);
- ultracam_veio(uvd, 0x01, 0x0090, 0x0049, 1);
- ultracam_veio(uvd, 0x01, 0x00a0, 0x004a, 1);
- ultracam_veio(uvd, 0x01, 0x00b0, 0x004b, 1);
- ultracam_veio(uvd, 0x01, 0x00c0, 0x004c, 1);
- ultracam_veio(uvd, 0x01, 0x00d0, 0x004d, 1);
- ultracam_veio(uvd, 0x01, 0x00e0, 0x004e, 1);
- ultracam_veio(uvd, 0x01, 0x00f0, 0x004f, 1);
- ultracam_veio(uvd, 0x01, 0x00ff, 0x0050, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0056, 1);
- ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0080, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0004, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0002, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0020, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0040, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0017, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c3, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c4, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c5, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c6, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c7, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c8, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c9, 1);
- ultracam_veio(uvd, 0x00, 0x00c0, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_veio(uvd, 0x02, 0xc040, 0x0001, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0008, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0009, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000b, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000c, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000d, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000e, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000f, 0);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0010, 0);
- ultracam_veio(uvd, 0x01, 0x000b, 0x0008, 1);
- ultracam_veio(uvd, 0x01, 0x0034, 0x0009, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x000a, 1);
- ultracam_veio(uvd, 0x01, 0x002e, 0x000b, 1);
- ultracam_veio(uvd, 0x01, 0x00d6, 0x000c, 1);
- ultracam_veio(uvd, 0x01, 0x00fc, 0x000d, 1);
- ultracam_veio(uvd, 0x01, 0x00f1, 0x000e, 1);
- ultracam_veio(uvd, 0x01, 0x00da, 0x000f, 1);
- ultracam_veio(uvd, 0x01, 0x0036, 0x0010, 1);
- ultracam_veio(uvd, 0x01, 0x0000, 0x0001, 0);
- ultracam_veio(uvd, 0x01, 0x0064, 0x0001, 1);
- ultracam_veio(uvd, 0x01, 0x0059, 0x0051, 1);
- ultracam_veio(uvd, 0x01, 0x003f, 0x0052, 1);
- ultracam_veio(uvd, 0x01, 0x0094, 0x0053, 1);
- ultracam_veio(uvd, 0x01, 0x00ff, 0x0011, 1);
- ultracam_veio(uvd, 0x01, 0x0003, 0x0012, 1);
- ultracam_veio(uvd, 0x01, 0x00f7, 0x0013, 1);
- ultracam_veio(uvd, 0x00, 0x0009, 0x0011, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0001, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x0000, 1);
- ultracam_veio(uvd, 0x00, 0x0020, 0x00c1, 1);
- ultracam_veio(uvd, 0x00, 0x0010, 0x00c2, 1);
- ultracam_veio(uvd, 0x00, 0x0000, 0x00ca, 1);
- ultracam_alternateSetting(uvd, 0x04);
- ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
- ultracam_veio(uvd, 0x02, 0x0000, 0x0001, 1);
- ultracam_veio(uvd, 0x02, 0x0000, 0x0006, 1);
- ultracam_veio(uvd, 0x02, 0x9000, 0x0007, 1);
- ultracam_veio(uvd, 0x02, 0x0042, 0x0001, 1);
- ultracam_veio(uvd, 0x02, 0x0000, 0x000b, 0);
- ultracam_resetPipe(uvd);
- ULTRACAM_T(uvd)->initialized = (setup_ok != 0);
- }
- return setup_ok;
-}
-
-static void ultracam_configure_video(struct uvd *uvd)
-{
- if (uvd == NULL)
- return;
-
- RESTRICT_TO_RANGE(init_brightness, 0, 255);
- RESTRICT_TO_RANGE(init_contrast, 0, 255);
- RESTRICT_TO_RANGE(init_color, 0, 255);
- RESTRICT_TO_RANGE(init_hue, 0, 255);
- RESTRICT_TO_RANGE(hue_correction, 0, 255);
-
- memset(&uvd->vpic, 0, sizeof(uvd->vpic));
- memset(&uvd->vpic_old, 0x55, sizeof(uvd->vpic_old));
-
- uvd->vpic.colour = init_color << 8;
- uvd->vpic.hue = init_hue << 8;
- uvd->vpic.brightness = init_brightness << 8;
- uvd->vpic.contrast = init_contrast << 8;
- uvd->vpic.whiteness = 105 << 8; /* This one isn't used */
- uvd->vpic.depth = 24;
- uvd->vpic.palette = VIDEO_PALETTE_RGB24;
-
- memset(&uvd->vcap, 0, sizeof(uvd->vcap));
- strcpy(uvd->vcap.name, "IBM Ultra Camera");
- uvd->vcap.type = VID_TYPE_CAPTURE;
- uvd->vcap.channels = 1;
- uvd->vcap.audios = 0;
- uvd->vcap.maxwidth = VIDEOSIZE_X(uvd->canvas);
- uvd->vcap.maxheight = VIDEOSIZE_Y(uvd->canvas);
- uvd->vcap.minwidth = min_canvasWidth;
- uvd->vcap.minheight = min_canvasHeight;
-
- memset(&uvd->vchan, 0, sizeof(uvd->vchan));
- uvd->vchan.flags = 0;
- uvd->vchan.tuners = 0;
- uvd->vchan.channel = 0;
- uvd->vchan.type = VIDEO_TYPE_CAMERA;
- strcpy(uvd->vchan.name, "Camera");
-}
-
-/*
- * ultracam_probe()
- *
- * This procedure queries device descriptor and accepts the interface
- * if it looks like our camera.
- *
- * History:
- * 12-Nov-2000 Reworked to comply with new probe() signature.
- * 23-Jan-2001 Added compatibility with 2.2.x kernels.
- */
-static int ultracam_probe(struct usb_interface *intf, const struct usb_device_id *devid)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- struct uvd *uvd = NULL;
- int ix, i, nas;
- int actInterface=-1, inactInterface=-1, maxPS=0;
- unsigned char video_ep = 0;
-
- if (debug >= 1)
- dev_info(&intf->dev, "ultracam_probe\n");
-
- /* We don't handle multi-config cameras */
- if (dev->descriptor.bNumConfigurations != 1)
- return -ENODEV;
-
- dev_info(&intf->dev, "IBM Ultra camera found (rev. 0x%04x)\n",
- le16_to_cpu(dev->descriptor.bcdDevice));
-
- /* Validate found interface: must have one ISO endpoint */
- nas = intf->num_altsetting;
- if (debug > 0)
- dev_info(&intf->dev, "Number of alternate settings=%d.\n",
- nas);
- if (nas < 8) {
- err("Too few alternate settings for this camera!");
- return -ENODEV;
- }
- /* Validate all alternate settings */
- for (ix=0; ix < nas; ix++) {
- const struct usb_host_interface *interface;
- const struct usb_endpoint_descriptor *endpoint;
-
- interface = &intf->altsetting[ix];
- i = interface->desc.bAlternateSetting;
- if (interface->desc.bNumEndpoints != 1) {
- err("Interface %d. has %u. endpoints!",
- interface->desc.bInterfaceNumber,
- (unsigned)(interface->desc.bNumEndpoints));
- return -ENODEV;
- }
- endpoint = &interface->endpoint[0].desc;
- if (video_ep == 0)
- video_ep = endpoint->bEndpointAddress;
- else if (video_ep != endpoint->bEndpointAddress) {
- err("Alternate settings have different endpoint addresses!");
- return -ENODEV;
- }
- if (!usb_endpoint_xfer_isoc(endpoint)) {
- err("Interface %d. has non-ISO endpoint!",
- interface->desc.bInterfaceNumber);
- return -ENODEV;
- }
- if (usb_endpoint_dir_out(endpoint)) {
- err("Interface %d. has ISO OUT endpoint!",
- interface->desc.bInterfaceNumber);
- return -ENODEV;
- }
- if (le16_to_cpu(endpoint->wMaxPacketSize) == 0) {
- if (inactInterface < 0)
- inactInterface = i;
- else {
- err("More than one inactive alt. setting!");
- return -ENODEV;
- }
- } else {
- if (actInterface < 0) {
- actInterface = i;
- maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
- if (debug > 0)
- dev_info(&intf->dev,
- "Active setting=%d. "
- "maxPS=%d.\n", i, maxPS);
- } else {
- /* Got another active alt. setting */
- if (maxPS < le16_to_cpu(endpoint->wMaxPacketSize)) {
- /* This one is better! */
- actInterface = i;
- maxPS = le16_to_cpu(endpoint->wMaxPacketSize);
- if (debug > 0) {
- dev_info(&intf->dev,
- "Even better ctive "
- "setting=%d. "
- "maxPS=%d.\n",
- i, maxPS);
- }
- }
- }
- }
- }
- if ((maxPS <= 0) || (actInterface < 0) || (inactInterface < 0)) {
- err("Failed to recognize the camera!");
- return -ENODEV;
- }
-
- uvd = usbvideo_AllocateDevice(cams);
- if (uvd != NULL) {
- /* Here uvd is a fully allocated uvd object */
- uvd->flags = flags;
- uvd->debug = debug;
- uvd->dev = dev;
- uvd->iface = intf->altsetting->desc.bInterfaceNumber;
- uvd->ifaceAltInactive = inactInterface;
- uvd->ifaceAltActive = actInterface;
- uvd->video_endp = video_ep;
- uvd->iso_packet_len = maxPS;
- uvd->paletteBits = 1L << VIDEO_PALETTE_RGB24;
- uvd->defaultPalette = VIDEO_PALETTE_RGB24;
- uvd->canvas = VIDEOSIZE(640, 480); /* FIXME */
- uvd->videosize = uvd->canvas; /* ultracam_size_to_videosize(size);*/
-
- /* Initialize ibmcam-specific data */
- assert(ULTRACAM_T(uvd) != NULL);
- ULTRACAM_T(uvd)->camera_model = 0; /* Not used yet */
- ULTRACAM_T(uvd)->initialized = 0;
-
- ultracam_configure_video(uvd);
-
- i = usbvideo_RegisterVideoDevice(uvd);
- if (i != 0) {
- err("usbvideo_RegisterVideoDevice() failed.");
- uvd = NULL;
- }
- }
-
- if (uvd) {
- usb_set_intfdata (intf, uvd);
- return 0;
- }
- return -EIO;
-}
-
-
-static struct usb_device_id id_table[] = {
- { USB_DEVICE(ULTRACAM_VENDOR_ID, ULTRACAM_PRODUCT_ID) },
- { } /* Terminating entry */
-};
-
-/*
- * ultracam_init()
- *
- * This code is run to initialize the driver.
- */
-static int __init ultracam_init(void)
-{
- struct usbvideo_cb cbTbl;
- memset(&cbTbl, 0, sizeof(cbTbl));
- cbTbl.probe = ultracam_probe;
- cbTbl.setupOnOpen = ultracam_setup_on_open;
- cbTbl.videoStart = ultracam_video_start;
- cbTbl.videoStop = ultracam_video_stop;
- cbTbl.processData = ultracam_ProcessIsocData;
- cbTbl.postProcess = usbvideo_DeinterlaceFrame;
- cbTbl.adjustPicture = ultracam_adjust_picture;
- cbTbl.getFPS = ultracam_calculate_fps;
- return usbvideo_register(
- &cams,
- MAX_CAMERAS,
- sizeof(ultracam_t),
- "ultracam",
- &cbTbl,
- THIS_MODULE,
- id_table);
-}
-
-static void __exit ultracam_cleanup(void)
-{
- usbvideo_Deregister(&cams);
-}
-
-MODULE_DEVICE_TABLE(usb, id_table);
-MODULE_LICENSE("GPL");
-
-module_init(ultracam_init);
-module_exit(ultracam_cleanup);
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
deleted file mode 100644
index 5ac37c6c4313..000000000000
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ /dev/null
@@ -1,2234 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/list.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-
-#include <asm/io.h>
-
-#include "usbvideo.h"
-
-#if defined(MAP_NR)
-#define virt_to_page(v) MAP_NR(v) /* Kernels 2.2.x */
-#endif
-
-static int video_nr = -1;
-module_param(video_nr, int, 0);
-
-/*
- * Local prototypes.
- */
-static void usbvideo_Disconnect(struct usb_interface *intf);
-static void usbvideo_CameraRelease(struct uvd *uvd);
-
-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 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 file *file);
-
-static int usbvideo_StartDataPump(struct uvd *uvd);
-static void usbvideo_StopDataPump(struct uvd *uvd);
-static int usbvideo_GetFrame(struct uvd *uvd, int frameNum);
-static int usbvideo_NewFrame(struct uvd *uvd, int framenum);
-static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
- struct usbvideo_frame *frame);
-
-/*******************************/
-/* Memory management functions */
-/*******************************/
-static void *usbvideo_rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-static void usbvideo_rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-static void RingQueue_Initialize(struct RingQueue *rq)
-{
- assert(rq != NULL);
- init_waitqueue_head(&rq->wqh);
-}
-
-static void RingQueue_Allocate(struct RingQueue *rq, int rqLen)
-{
- /* Make sure the requested size is a power of 2 and
- round up if necessary. This allows index wrapping
- using masks rather than modulo */
-
- int i = 1;
- assert(rq != NULL);
- assert(rqLen > 0);
-
- while(rqLen >> i)
- i++;
- if(rqLen != 1 << (i-1))
- rqLen = 1 << i;
-
- rq->length = rqLen;
- rq->ri = rq->wi = 0;
- rq->queue = usbvideo_rvmalloc(rq->length);
- assert(rq->queue != NULL);
-}
-
-static int RingQueue_IsAllocated(const struct RingQueue *rq)
-{
- if (rq == NULL)
- return 0;
- return (rq->queue != NULL) && (rq->length > 0);
-}
-
-static void RingQueue_Free(struct RingQueue *rq)
-{
- assert(rq != NULL);
- if (RingQueue_IsAllocated(rq)) {
- usbvideo_rvfree(rq->queue, rq->length);
- rq->queue = NULL;
- rq->length = 0;
- }
-}
-
-int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len)
-{
- int rql, toread;
-
- assert(rq != NULL);
- assert(dst != NULL);
-
- rql = RingQueue_GetLength(rq);
- if(!rql)
- return 0;
-
- /* Clip requested length to available data */
- if(len > rql)
- len = rql;
-
- toread = len;
- if(rq->ri > rq->wi) {
- /* Read data from tail */
- int read = (toread < (rq->length - rq->ri)) ? toread : rq->length - rq->ri;
- memcpy(dst, rq->queue + rq->ri, read);
- toread -= read;
- dst += read;
- rq->ri = (rq->ri + read) & (rq->length-1);
- }
- if(toread) {
- /* Read data from head */
- memcpy(dst, rq->queue + rq->ri, toread);
- rq->ri = (rq->ri + toread) & (rq->length-1);
- }
- return len;
-}
-
-EXPORT_SYMBOL(RingQueue_Dequeue);
-
-int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n)
-{
- int enqueued = 0;
-
- assert(rq != NULL);
- assert(cdata != NULL);
- assert(rq->length > 0);
- while (n > 0) {
- int m, q_avail;
-
- /* Calculate the largest chunk that fits the tail of the ring */
- q_avail = rq->length - rq->wi;
- if (q_avail <= 0) {
- rq->wi = 0;
- q_avail = rq->length;
- }
- m = n;
- assert(q_avail > 0);
- if (m > q_avail)
- m = q_avail;
-
- memcpy(rq->queue + rq->wi, cdata, m);
- RING_QUEUE_ADVANCE_INDEX(rq, wi, m);
- cdata += m;
- enqueued += m;
- n -= m;
- }
- return enqueued;
-}
-
-EXPORT_SYMBOL(RingQueue_Enqueue);
-
-static void RingQueue_InterruptibleSleepOn(struct RingQueue *rq)
-{
- assert(rq != NULL);
- interruptible_sleep_on(&rq->wqh);
-}
-
-void RingQueue_WakeUpInterruptible(struct RingQueue *rq)
-{
- assert(rq != NULL);
- if (waitqueue_active(&rq->wqh))
- wake_up_interruptible(&rq->wqh);
-}
-
-EXPORT_SYMBOL(RingQueue_WakeUpInterruptible);
-
-void RingQueue_Flush(struct RingQueue *rq)
-{
- assert(rq != NULL);
- rq->ri = 0;
- rq->wi = 0;
-}
-
-EXPORT_SYMBOL(RingQueue_Flush);
-
-
-/*
- * usbvideo_VideosizeToString()
- *
- * This procedure converts given videosize value to readable string.
- *
- * History:
- * 07-Aug-2000 Created.
- * 19-Oct-2000 Reworked for usbvideo module.
- */
-static void usbvideo_VideosizeToString(char *buf, int bufLen, videosize_t vs)
-{
- char tmp[40];
- int n;
-
- n = 1 + sprintf(tmp, "%ldx%ld", VIDEOSIZE_X(vs), VIDEOSIZE_Y(vs));
- assert(n < sizeof(tmp));
- if ((buf == NULL) || (bufLen < n))
- err("usbvideo_VideosizeToString: buffer is too small.");
- else
- memmove(buf, tmp, n);
-}
-
-/*
- * usbvideo_OverlayChar()
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayChar(struct uvd *uvd, struct usbvideo_frame *frame,
- int x, int y, int ch)
-{
- static const unsigned short digits[16] = {
- 0xF6DE, /* 0 */
- 0x2492, /* 1 */
- 0xE7CE, /* 2 */
- 0xE79E, /* 3 */
- 0xB792, /* 4 */
- 0xF39E, /* 5 */
- 0xF3DE, /* 6 */
- 0xF492, /* 7 */
- 0xF7DE, /* 8 */
- 0xF79E, /* 9 */
- 0x77DA, /* a */
- 0xD75C, /* b */
- 0xF24E, /* c */
- 0xD6DC, /* d */
- 0xF34E, /* e */
- 0xF348 /* f */
- };
- unsigned short digit;
- int ix, iy;
-
- if ((uvd == NULL) || (frame == NULL))
- return;
-
- if (ch >= '0' && ch <= '9')
- ch -= '0';
- else if (ch >= 'A' && ch <= 'F')
- ch = 10 + (ch - 'A');
- else if (ch >= 'a' && ch <= 'f')
- ch = 10 + (ch - 'a');
- else
- return;
- digit = digits[ch];
-
- for (iy=0; iy < 5; iy++) {
- for (ix=0; ix < 3; ix++) {
- if (digit & 0x8000) {
- if (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24)) {
-/* TODO */ RGB24_PUTPIXEL(frame, x+ix, y+iy, 0xFF, 0xFF, 0xFF);
- }
- }
- digit = digit << 1;
- }
- }
-}
-
-/*
- * usbvideo_OverlayString()
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayString(struct uvd *uvd, struct usbvideo_frame *frame,
- int x, int y, const char *str)
-{
- while (*str) {
- usbvideo_OverlayChar(uvd, frame, x, y, *str);
- str++;
- x += 4; /* 3 pixels character + 1 space */
- }
-}
-
-/*
- * usbvideo_OverlayStats()
- *
- * Overlays important debugging information.
- *
- * History:
- * 01-Feb-2000 Created.
- */
-static void usbvideo_OverlayStats(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- const int y_diff = 8;
- char tmp[16];
- int x = 10, y=10;
- long i, j, barLength;
- const int qi_x1 = 60, qi_y1 = 10;
- const int qi_x2 = VIDEOSIZE_X(frame->request) - 10, qi_h = 10;
-
- /* Call the user callback, see if we may proceed after that */
- if (VALID_CALLBACK(uvd, overlayHook)) {
- if (GET_CALLBACK(uvd, overlayHook)(uvd, frame) < 0)
- return;
- }
-
- /*
- * We draw a (mostly) hollow rectangle with qi_xxx coordinates.
- * Left edge symbolizes the queue index 0; right edge symbolizes
- * the full capacity of the queue.
- */
- barLength = qi_x2 - qi_x1 - 2;
- if ((barLength > 10) && (uvd->paletteBits & (1L << VIDEO_PALETTE_RGB24))) {
-/* TODO */ long u_lo, u_hi, q_used;
- long m_ri, m_wi, m_lo, m_hi;
-
- /*
- * Determine fill zones (used areas of the queue):
- * 0 xxxxxxx u_lo ...... uvd->dp.ri xxxxxxxx u_hi ..... uvd->dp.length
- *
- * if u_lo < 0 then there is no first filler.
- */
-
- q_used = RingQueue_GetLength(&uvd->dp);
- if ((uvd->dp.ri + q_used) >= uvd->dp.length) {
- u_hi = uvd->dp.length;
- u_lo = (q_used + uvd->dp.ri) & (uvd->dp.length-1);
- } else {
- u_hi = (q_used + uvd->dp.ri);
- u_lo = -1;
- }
-
- /* Convert byte indices into screen units */
- m_ri = qi_x1 + ((barLength * uvd->dp.ri) / uvd->dp.length);
- m_wi = qi_x1 + ((barLength * uvd->dp.wi) / uvd->dp.length);
- m_lo = (u_lo > 0) ? (qi_x1 + ((barLength * u_lo) / uvd->dp.length)) : -1;
- m_hi = qi_x1 + ((barLength * u_hi) / uvd->dp.length);
-
- for (j=qi_y1; j < (qi_y1 + qi_h); j++) {
- for (i=qi_x1; i < qi_x2; i++) {
- /* Draw border lines */
- if ((j == qi_y1) || (j == (qi_y1 + qi_h - 1)) ||
- (i == qi_x1) || (i == (qi_x2 - 1))) {
- RGB24_PUTPIXEL(frame, i, j, 0xFF, 0xFF, 0xFF);
- continue;
- }
- /* For all other points the Y coordinate does not matter */
- if ((i >= m_ri) && (i <= (m_ri + 3))) {
- RGB24_PUTPIXEL(frame, i, j, 0x00, 0xFF, 0x00);
- } else if ((i >= m_wi) && (i <= (m_wi + 3))) {
- RGB24_PUTPIXEL(frame, i, j, 0xFF, 0x00, 0x00);
- } else if ((i < m_lo) || ((i > m_ri) && (i < m_hi)))
- RGB24_PUTPIXEL(frame, i, j, 0x00, 0x00, 0xFF);
- }
- }
- }
-
- sprintf(tmp, "%8lx", uvd->stats.frame_num);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8lx", uvd->stats.urb_count);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8lx", uvd->stats.urb_length);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8lx", uvd->stats.data_count);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8lx", uvd->stats.header_count);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8lx", uvd->stats.iso_skip_count);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8lx", uvd->stats.iso_err_count);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8x", uvd->vpic.colour);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8x", uvd->vpic.hue);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8x", uvd->vpic.brightness >> 8);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8x", uvd->vpic.contrast >> 12);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-
- sprintf(tmp, "%8d", uvd->vpic.whiteness >> 8);
- usbvideo_OverlayString(uvd, frame, x, y, tmp);
- y += y_diff;
-}
-
-/*
- * usbvideo_ReportStatistics()
- *
- * This procedure prints packet and transfer statistics.
- *
- * History:
- * 14-Jan-2000 Corrected default multiplier.
- */
-static void usbvideo_ReportStatistics(const struct uvd *uvd)
-{
- if ((uvd != NULL) && (uvd->stats.urb_count > 0)) {
- unsigned long allPackets, badPackets, goodPackets, percent;
- allPackets = uvd->stats.urb_count * CAMERA_URB_FRAMES;
- badPackets = uvd->stats.iso_skip_count + uvd->stats.iso_err_count;
- goodPackets = allPackets - badPackets;
- /* Calculate percentage wisely, remember integer limits */
- assert(allPackets != 0);
- if (goodPackets < (((unsigned long)-1)/100))
- percent = (100 * goodPackets) / allPackets;
- else
- percent = goodPackets / (allPackets / 100);
- dev_info(&uvd->dev->dev,
- "Packet Statistics: Total=%lu. Empty=%lu. Usage=%lu%%\n",
- allPackets, badPackets, percent);
- if (uvd->iso_packet_len > 0) {
- unsigned long allBytes, xferBytes;
- char multiplier = ' ';
- allBytes = allPackets * uvd->iso_packet_len;
- xferBytes = uvd->stats.data_count;
- assert(allBytes != 0);
- if (xferBytes < (((unsigned long)-1)/100))
- percent = (100 * xferBytes) / allBytes;
- else
- percent = xferBytes / (allBytes / 100);
- /* Scale xferBytes for easy reading */
- if (xferBytes > 10*1024) {
- xferBytes /= 1024;
- multiplier = 'K';
- if (xferBytes > 10*1024) {
- xferBytes /= 1024;
- multiplier = 'M';
- if (xferBytes > 10*1024) {
- xferBytes /= 1024;
- multiplier = 'G';
- if (xferBytes > 10*1024) {
- xferBytes /= 1024;
- multiplier = 'T';
- }
- }
- }
- }
- dev_info(&uvd->dev->dev,
- "Transfer Statistics: Transferred=%lu%cB Usage=%lu%%\n",
- xferBytes, multiplier, percent);
- }
- }
-}
-
-/*
- * usbvideo_TestPattern()
- *
- * Procedure forms a test pattern (yellow grid on blue background).
- *
- * Parameters:
- * fullframe: if TRUE then entire frame is filled, otherwise the procedure
- * continues from the current scanline.
- * pmode 0: fill the frame with solid blue color (like on VCR or TV)
- * 1: Draw a colored grid
- *
- * History:
- * 01-Feb-2000 Created.
- */
-void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode)
-{
- struct usbvideo_frame *frame;
- int num_cell = 0;
- int scan_length = 0;
- static int num_pass;
-
- if (uvd == NULL) {
- err("%s: uvd == NULL", __func__);
- return;
- }
- if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
- err("%s: uvd->curframe=%d.", __func__, uvd->curframe);
- return;
- }
-
- /* Grab the current frame */
- frame = &uvd->frame[uvd->curframe];
-
- /* Optionally start at the beginning */
- if (fullframe) {
- frame->curline = 0;
- frame->seqRead_Length = 0;
- }
-#if 0
- { /* For debugging purposes only */
- char tmp[20];
- usbvideo_VideosizeToString(tmp, sizeof(tmp), frame->request);
- dev_info(&uvd->dev->dev, "testpattern: frame=%s\n", tmp);
- }
-#endif
- /* Form every scan line */
- for (; frame->curline < VIDEOSIZE_Y(frame->request); frame->curline++) {
- int i;
- unsigned char *f = frame->data +
- (VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL * frame->curline);
- for (i=0; i < VIDEOSIZE_X(frame->request); i++) {
- unsigned char cb=0x80;
- unsigned char cg = 0;
- unsigned char cr = 0;
-
- if (pmode == 1) {
- if (frame->curline % 32 == 0)
- cb = 0, cg = cr = 0xFF;
- else if (i % 32 == 0) {
- if (frame->curline % 32 == 1)
- num_cell++;
- cb = 0, cg = cr = 0xFF;
- } else {
- cb = ((num_cell*7) + num_pass) & 0xFF;
- cg = ((num_cell*5) + num_pass*2) & 0xFF;
- cr = ((num_cell*3) + num_pass*3) & 0xFF;
- }
- } else {
- /* Just the blue screen */
- }
-
- *f++ = cb;
- *f++ = cg;
- *f++ = cr;
- scan_length += 3;
- }
- }
-
- frame->frameState = FrameState_Done;
- frame->seqRead_Length += scan_length;
- ++num_pass;
-
- /* We do this unconditionally, regardless of FLAGS_OVERLAY_STATS */
- usbvideo_OverlayStats(uvd, frame);
-}
-
-EXPORT_SYMBOL(usbvideo_TestPattern);
-
-
-#ifdef DEBUG
-/*
- * usbvideo_HexDump()
- *
- * A debugging tool. Prints hex dumps.
- *
- * History:
- * 29-Jul-2000 Added printing of offsets.
- */
-void usbvideo_HexDump(const unsigned char *data, int len)
-{
- const int bytes_per_line = 32;
- char tmp[128]; /* 32*3 + 5 */
- int i, k;
-
- for (i=k=0; len > 0; i++, len--) {
- if (i > 0 && ((i % bytes_per_line) == 0)) {
- printk("%s\n", tmp);
- k=0;
- }
- if ((i % bytes_per_line) == 0)
- k += sprintf(&tmp[k], "%04x: ", i);
- k += sprintf(&tmp[k], "%02x ", data[i]);
- }
- if (k > 0)
- printk("%s\n", tmp);
-}
-
-EXPORT_SYMBOL(usbvideo_HexDump);
-
-#endif
-
-/* ******************************************************************** */
-
-/* XXX: this piece of crap really wants some error handling.. */
-static int usbvideo_ClientIncModCount(struct uvd *uvd)
-{
- if (uvd == NULL) {
- err("%s: uvd == NULL", __func__);
- return -EINVAL;
- }
- if (uvd->handle == NULL) {
- err("%s: uvd->handle == NULL", __func__);
- return -EINVAL;
- }
- if (!try_module_get(uvd->handle->md_module)) {
- err("%s: try_module_get() == 0", __func__);
- return -ENODEV;
- }
- return 0;
-}
-
-static void usbvideo_ClientDecModCount(struct uvd *uvd)
-{
- if (uvd == NULL) {
- err("%s: uvd == NULL", __func__);
- return;
- }
- if (uvd->handle == NULL) {
- err("%s: uvd->handle == NULL", __func__);
- return;
- }
- if (uvd->handle->md_module == NULL) {
- err("%s: uvd->handle->md_module == NULL", __func__);
- return;
- }
- module_put(uvd->handle->md_module);
-}
-
-int usbvideo_register(
- struct usbvideo **pCams,
- const int num_cams,
- const int num_extra,
- const char *driverName,
- const struct usbvideo_cb *cbTbl,
- struct module *md,
- const struct usb_device_id *id_table)
-{
- struct usbvideo *cams;
- int i, base_size, result;
-
- /* Check parameters for sanity */
- if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
- err("%s: Illegal call", __func__);
- return -EINVAL;
- }
-
- /* Check registration callback - must be set! */
- if (cbTbl->probe == NULL) {
- err("%s: probe() is required!", __func__);
- return -EINVAL;
- }
-
- base_size = num_cams * sizeof(struct uvd) + sizeof(struct usbvideo);
- cams = kzalloc(base_size, GFP_KERNEL);
- if (cams == NULL) {
- err("Failed to allocate %d. bytes for usbvideo struct", base_size);
- return -ENOMEM;
- }
- dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
- __func__, cams, base_size, num_cams);
-
- /* Copy callbacks, apply defaults for those that are not set */
- memmove(&cams->cb, cbTbl, sizeof(cams->cb));
- if (cams->cb.getFrame == NULL)
- cams->cb.getFrame = usbvideo_GetFrame;
- if (cams->cb.disconnect == NULL)
- cams->cb.disconnect = usbvideo_Disconnect;
- if (cams->cb.startDataPump == NULL)
- cams->cb.startDataPump = usbvideo_StartDataPump;
- if (cams->cb.stopDataPump == NULL)
- cams->cb.stopDataPump = usbvideo_StopDataPump;
-
- cams->num_cameras = num_cams;
- cams->cam = (struct uvd *) &cams[1];
- cams->md_module = md;
- mutex_init(&cams->lock); /* to 1 == available */
-
- for (i = 0; i < num_cams; i++) {
- struct uvd *up = &cams->cam[i];
-
- up->handle = cams;
-
- /* Allocate user_data separately because of kmalloc's limits */
- if (num_extra > 0) {
- up->user_size = num_cams * num_extra;
- up->user_data = kmalloc(up->user_size, GFP_KERNEL);
- if (up->user_data == NULL) {
- err("%s: Failed to allocate user_data (%d. bytes)",
- __func__, up->user_size);
- while (i) {
- up = &cams->cam[--i];
- kfree(up->user_data);
- }
- kfree(cams);
- return -ENOMEM;
- }
- dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
- __func__, i, up->user_data, up->user_size);
- }
- }
-
- /*
- * Register ourselves with USB stack.
- */
- strcpy(cams->drvName, (driverName != NULL) ? driverName : "Unknown");
- cams->usbdrv.name = cams->drvName;
- cams->usbdrv.probe = cams->cb.probe;
- cams->usbdrv.disconnect = cams->cb.disconnect;
- cams->usbdrv.id_table = id_table;
-
- /*
- * Update global handle to usbvideo. This is very important
- * because probe() can be called before usb_register() returns.
- * If the handle is not yet updated then the probe() will fail.
- */
- *pCams = cams;
- result = usb_register(&cams->usbdrv);
- if (result) {
- for (i = 0; i < num_cams; i++) {
- struct uvd *up = &cams->cam[i];
- kfree(up->user_data);
- }
- kfree(cams);
- }
-
- return result;
-}
-
-EXPORT_SYMBOL(usbvideo_register);
-
-/*
- * usbvideo_Deregister()
- *
- * Procedure frees all usbvideo and user data structures. Be warned that
- * if you had some dynamically allocated components in ->user field then
- * you should free them before calling here.
- */
-void usbvideo_Deregister(struct usbvideo **pCams)
-{
- struct usbvideo *cams;
- int i;
-
- if (pCams == NULL) {
- err("%s: pCams == NULL", __func__);
- return;
- }
- cams = *pCams;
- if (cams == NULL) {
- err("%s: cams == NULL", __func__);
- return;
- }
-
- dbg("%s: Deregistering %s driver.", __func__, cams->drvName);
- usb_deregister(&cams->usbdrv);
-
- dbg("%s: Deallocating cams=$%p (%d. cameras)", __func__, cams, cams->num_cameras);
- for (i=0; i < cams->num_cameras; i++) {
- struct uvd *up = &cams->cam[i];
- int warning = 0;
-
- if (up->user_data != NULL) {
- if (up->user_size <= 0)
- ++warning;
- } else {
- if (up->user_size > 0)
- ++warning;
- }
- if (warning) {
- err("%s: Warning: user_data=$%p user_size=%d.",
- __func__, up->user_data, up->user_size);
- } else {
- dbg("%s: Freeing %d. $%p->user_data=$%p",
- __func__, i, up, up->user_data);
- kfree(up->user_data);
- }
- }
- /* Whole array was allocated in one chunk */
- dbg("%s: Freed %d uvd structures",
- __func__, cams->num_cameras);
- kfree(cams);
- *pCams = NULL;
-}
-
-EXPORT_SYMBOL(usbvideo_Deregister);
-
-/*
- * usbvideo_Disconnect()
- *
- * This procedure stops all driver activity. Deallocation of
- * the interface-private structure (pointed by 'ptr') is done now
- * (if we don't have any open files) or later, when those files
- * are closed. After that driver should be removable.
- *
- * This code handles surprise removal. The uvd->user is a counter which
- * increments on open() and decrements on close(). If we see here that
- * this counter is not 0 then we have a client who still has us opened.
- * We set uvd->remove_pending flag as early as possible, and after that
- * all access to the camera will gracefully fail. These failures should
- * prompt client to (eventually) close the video device, and then - in
- * usbvideo_v4l_close() - we decrement uvd->uvd_used and usage counter.
- *
- * History:
- * 22-Jan-2000 Added polling of MOD_IN_USE to delay removal until all users gone.
- * 27-Jan-2000 Reworked to allow pending disconnects; see xxx_close()
- * 24-May-2000 Corrected to prevent race condition (MOD_xxx_USE_COUNT).
- * 19-Oct-2000 Moved to usbvideo module.
- */
-static void usbvideo_Disconnect(struct usb_interface *intf)
-{
- struct uvd *uvd = usb_get_intfdata (intf);
- int i;
-
- if (uvd == NULL) {
- err("%s($%p): Illegal call.", __func__, intf);
- return;
- }
-
- usb_set_intfdata (intf, NULL);
-
- usbvideo_ClientIncModCount(uvd);
- if (uvd->debug > 0)
- dev_info(&intf->dev, "%s(%p.)\n", __func__, intf);
-
- mutex_lock(&uvd->lock);
- uvd->remove_pending = 1; /* Now all ISO data will be ignored */
-
- /* At this time we ask to cancel outstanding URBs */
- GET_CALLBACK(uvd, stopDataPump)(uvd);
-
- for (i=0; i < USBVIDEO_NUMSBUF; i++)
- usb_free_urb(uvd->sbuf[i].urb);
-
- usb_put_dev(uvd->dev);
- uvd->dev = NULL; /* USB device is no more */
-
- video_unregister_device(&uvd->vdev);
- if (uvd->debug > 0)
- dev_info(&intf->dev, "%s: Video unregistered.\n", __func__);
-
- if (uvd->user)
- dev_info(&intf->dev, "%s: In use, disconnect pending.\n",
- __func__);
- else
- usbvideo_CameraRelease(uvd);
- mutex_unlock(&uvd->lock);
- dev_info(&intf->dev, "USB camera disconnected.\n");
-
- usbvideo_ClientDecModCount(uvd);
-}
-
-/*
- * usbvideo_CameraRelease()
- *
- * This code does final release of uvd. This happens
- * after the device is disconnected -and- all clients
- * closed their files.
- *
- * History:
- * 27-Jan-2000 Created.
- */
-static void usbvideo_CameraRelease(struct uvd *uvd)
-{
- if (uvd == NULL) {
- err("%s: Illegal call", __func__);
- return;
- }
-
- RingQueue_Free(&uvd->dp);
- if (VALID_CALLBACK(uvd, userFree))
- GET_CALLBACK(uvd, userFree)(uvd);
- uvd->uvd_used = 0; /* This is atomic, no need to take mutex */
-}
-
-/*
- * usbvideo_find_struct()
- *
- * This code searches the array of preallocated (static) structures
- * and returns index of the first one that isn't in use. Returns -1
- * if there are no free structures.
- *
- * History:
- * 27-Jan-2000 Created.
- */
-static int usbvideo_find_struct(struct usbvideo *cams)
-{
- int u, rv = -1;
-
- if (cams == NULL) {
- err("No usbvideo handle?");
- return -1;
- }
- mutex_lock(&cams->lock);
- for (u = 0; u < cams->num_cameras; u++) {
- struct uvd *uvd = &cams->cam[u];
- if (!uvd->uvd_used) /* This one is free */
- {
- uvd->uvd_used = 1; /* In use now */
- mutex_init(&uvd->lock); /* to 1 == available */
- uvd->dev = NULL;
- rv = u;
- break;
- }
- }
- mutex_unlock(&cams->lock);
- return rv;
-}
-
-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,
-};
-static const struct video_device usbvideo_template = {
- .fops = &usbvideo_fops,
-};
-
-struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams)
-{
- int i, devnum;
- struct uvd *uvd = NULL;
-
- if (cams == NULL) {
- err("No usbvideo handle?");
- return NULL;
- }
-
- devnum = usbvideo_find_struct(cams);
- if (devnum == -1) {
- err("IBM USB camera driver: Too many devices!");
- return NULL;
- }
- uvd = &cams->cam[devnum];
- dbg("Device entry #%d. at $%p", devnum, uvd);
-
- /* Not relying upon caller we increase module counter ourselves */
- usbvideo_ClientIncModCount(uvd);
-
- mutex_lock(&uvd->lock);
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- uvd->sbuf[i].urb = usb_alloc_urb(FRAMES_PER_DESC, GFP_KERNEL);
- if (uvd->sbuf[i].urb == NULL) {
- err("usb_alloc_urb(%d.) failed.", FRAMES_PER_DESC);
- uvd->uvd_used = 0;
- uvd = NULL;
- goto allocate_done;
- }
- }
- uvd->user=0;
- uvd->remove_pending = 0;
- uvd->last_error = 0;
- RingQueue_Initialize(&uvd->dp);
-
- /* Initialize video device structure */
- uvd->vdev = usbvideo_template;
- sprintf(uvd->vdev.name, "%.20s USB Camera", cams->drvName);
- /*
- * The client is free to overwrite those because we
- * return control to the client's probe function right now.
- */
-allocate_done:
- mutex_unlock(&uvd->lock);
- usbvideo_ClientDecModCount(uvd);
- return uvd;
-}
-
-EXPORT_SYMBOL(usbvideo_AllocateDevice);
-
-int usbvideo_RegisterVideoDevice(struct uvd *uvd)
-{
- char tmp1[20], tmp2[20]; /* Buffers for printing */
-
- if (uvd == NULL) {
- err("%s: Illegal call.", __func__);
- return -EINVAL;
- }
- if (uvd->video_endp == 0) {
- dev_info(&uvd->dev->dev,
- "%s: No video endpoint specified; data pump disabled.\n",
- __func__);
- }
- if (uvd->paletteBits == 0) {
- err("%s: No palettes specified!", __func__);
- return -EINVAL;
- }
- if (uvd->defaultPalette == 0) {
- dev_info(&uvd->dev->dev, "%s: No default palette!\n",
- __func__);
- }
-
- uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
- VIDEOSIZE_Y(uvd->canvas) * V4L_BYTES_PER_PIXEL;
- usbvideo_VideosizeToString(tmp1, sizeof(tmp1), uvd->videosize);
- usbvideo_VideosizeToString(tmp2, sizeof(tmp2), uvd->canvas);
-
- if (uvd->debug > 0) {
- dev_info(&uvd->dev->dev,
- "%s: iface=%d. endpoint=$%02x paletteBits=$%08lx\n",
- __func__, uvd->iface, uvd->video_endp,
- uvd->paletteBits);
- }
- if (uvd->dev == NULL) {
- err("%s: uvd->dev == NULL", __func__);
- return -EINVAL;
- }
- uvd->vdev.parent = &uvd->dev->dev;
- uvd->vdev.release = video_device_release_empty;
- if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) < 0) {
- err("%s: video_register_device failed", __func__);
- return -EPIPE;
- }
- if (uvd->debug > 1) {
- dev_info(&uvd->dev->dev,
- "%s: video_register_device() successful\n", __func__);
- }
-
- dev_info(&uvd->dev->dev, "%s on %s: canvas=%s videosize=%s\n",
- (uvd->handle != NULL) ? uvd->handle->drvName : "???",
- video_device_node_name(&uvd->vdev), tmp2, tmp1);
-
- usb_get_dev(uvd->dev);
- return 0;
-}
-
-EXPORT_SYMBOL(usbvideo_RegisterVideoDevice);
-
-/* ******************************************************************** */
-
-static int usbvideo_v4l_mmap(struct file *file, struct vm_area_struct *vma)
-{
- struct uvd *uvd = file->private_data;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- unsigned long page, pos;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return -EFAULT;
-
- if (size > (((USBVIDEO_NUMFRAMES * uvd->max_frame_size) + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)))
- return -EINVAL;
-
- pos = (unsigned long) uvd->fbuf;
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
-
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- return 0;
-}
-
-/*
- * usbvideo_v4l_open()
- *
- * This is part of Video 4 Linux API. The driver can be opened by one
- * client only (checks internal counter 'uvdser'). The procedure
- * then allocates buffers needed for video processing.
- *
- * History:
- * 22-Jan-2000 Rewrote, moved scratch buffer allocation here. Now the
- * camera is also initialized here (once per connect), at
- * expense of V4L client (it waits on open() call).
- * 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 file *file)
-{
- struct video_device *dev = video_devdata(file);
- struct uvd *uvd = (struct uvd *) dev;
- const int sb_size = FRAMES_PER_DESC * uvd->iso_packet_len;
- int i, errCode = 0;
-
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
-
- if (usbvideo_ClientIncModCount(uvd) < 0)
- return -ENODEV;
- mutex_lock(&uvd->lock);
-
- if (uvd->user) {
- err("%s: Someone tried to open an already opened device!", __func__);
- errCode = -EBUSY;
- } else {
- /* Clear statistics */
- memset(&uvd->stats, 0, sizeof(uvd->stats));
-
- /* Clean pointers so we know if we allocated something */
- for (i=0; i < USBVIDEO_NUMSBUF; i++)
- uvd->sbuf[i].data = NULL;
-
- /* Allocate memory for the frame buffers */
- uvd->fbuf_size = USBVIDEO_NUMFRAMES * uvd->max_frame_size;
- uvd->fbuf = usbvideo_rvmalloc(uvd->fbuf_size);
- RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
- if ((uvd->fbuf == NULL) ||
- (!RingQueue_IsAllocated(&uvd->dp))) {
- err("%s: Failed to allocate fbuf or dp", __func__);
- errCode = -ENOMEM;
- } else {
- /* Allocate all buffers */
- for (i=0; i < USBVIDEO_NUMFRAMES; i++) {
- uvd->frame[i].frameState = FrameState_Unused;
- uvd->frame[i].data = uvd->fbuf + i*(uvd->max_frame_size);
- /*
- * Set default sizes in case IOCTL (VIDIOCMCAPTURE)
- * is not used (using read() instead).
- */
- uvd->frame[i].canvas = uvd->canvas;
- uvd->frame[i].seqRead_Index = 0;
- }
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- uvd->sbuf[i].data = kmalloc(sb_size, GFP_KERNEL);
- if (uvd->sbuf[i].data == NULL) {
- errCode = -ENOMEM;
- break;
- }
- }
- }
- if (errCode != 0) {
- /* Have to free all that memory */
- if (uvd->fbuf != NULL) {
- usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
- uvd->fbuf = NULL;
- }
- RingQueue_Free(&uvd->dp);
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- kfree(uvd->sbuf[i].data);
- uvd->sbuf[i].data = NULL;
- }
- }
- }
-
- /* If so far no errors then we shall start the camera */
- if (errCode == 0) {
- /* Start data pump if we have valid endpoint */
- if (uvd->video_endp != 0)
- errCode = GET_CALLBACK(uvd, startDataPump)(uvd);
- if (errCode == 0) {
- if (VALID_CALLBACK(uvd, setupOnOpen)) {
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev,
- "%s: setupOnOpen callback\n",
- __func__);
- errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
- if (errCode < 0) {
- err("%s: setupOnOpen callback failed (%d.).",
- __func__, errCode);
- } else if (uvd->debug > 1) {
- dev_info(&uvd->dev->dev,
- "%s: setupOnOpen callback successful\n",
- __func__);
- }
- }
- if (errCode == 0) {
- uvd->settingsAdjusted = 0;
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev,
- "%s: Open succeeded.\n",
- __func__);
- uvd->user++;
- file->private_data = uvd;
- }
- }
- }
- mutex_unlock(&uvd->lock);
- if (errCode != 0)
- usbvideo_ClientDecModCount(uvd);
- if (uvd->debug > 0)
- dev_info(&uvd->dev->dev, "%s: Returning %d.\n", __func__,
- errCode);
- return errCode;
-}
-
-/*
- * usbvideo_v4l_close()
- *
- * This is part of Video 4 Linux API. The procedure
- * stops streaming and deallocates all buffers that were earlier
- * allocated in usbvideo_v4l_open().
- *
- * History:
- * 22-Jan-2000 Moved scratch buffer deallocation here.
- * 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 file *file)
-{
- struct video_device *dev = file->private_data;
- struct uvd *uvd = (struct uvd *) dev;
- int i;
-
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, dev);
-
- mutex_lock(&uvd->lock);
- GET_CALLBACK(uvd, stopDataPump)(uvd);
- usbvideo_rvfree(uvd->fbuf, uvd->fbuf_size);
- uvd->fbuf = NULL;
- RingQueue_Free(&uvd->dp);
-
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- kfree(uvd->sbuf[i].data);
- uvd->sbuf[i].data = NULL;
- }
-
-#if USBVIDEO_REPORT_STATS
- usbvideo_ReportStatistics(uvd);
-#endif
-
- uvd->user--;
- if (uvd->remove_pending) {
- if (uvd->debug > 0)
- dev_info(&uvd->dev->dev, "%s: Final disconnect.\n",
- __func__);
- usbvideo_CameraRelease(uvd);
- }
- mutex_unlock(&uvd->lock);
- usbvideo_ClientDecModCount(uvd);
-
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev, "%s: Completed.\n", __func__);
- file->private_data = NULL;
- return 0;
-}
-
-/*
- * usbvideo_v4l_ioctl()
- *
- * This is part of Video 4 Linux API. The procedure handles ioctl() calls.
- *
- * History:
- * 22-Jan-2000 Corrected VIDIOCSPICT to reject unsupported settings.
- */
-static long usbvideo_v4l_do_ioctl(struct file *file, unsigned int cmd, void *arg)
-{
- struct uvd *uvd = file->private_data;
-
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return -EIO;
-
- switch (cmd) {
- case VIDIOCGCAP:
- {
- struct video_capability *b = arg;
- *b = uvd->vcap;
- return 0;
- }
- case VIDIOCGCHAN:
- {
- struct video_channel *v = arg;
- *v = uvd->vchan;
- return 0;
- }
- case VIDIOCSCHAN:
- {
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- return 0;
- }
- case VIDIOCGPICT:
- {
- struct video_picture *pic = arg;
- *pic = uvd->vpic;
- return 0;
- }
- case VIDIOCSPICT:
- {
- struct video_picture *pic = arg;
- /*
- * Use temporary 'video_picture' structure to preserve our
- * own settings (such as color depth, palette) that we
- * aren't allowing everyone (V4L client) to change.
- */
- uvd->vpic.brightness = pic->brightness;
- uvd->vpic.hue = pic->hue;
- uvd->vpic.colour = pic->colour;
- uvd->vpic.contrast = pic->contrast;
- uvd->settingsAdjusted = 0; /* Will force new settings */
- return 0;
- }
- case VIDIOCSWIN:
- {
- struct video_window *vw = arg;
-
- if(VALID_CALLBACK(uvd, setVideoMode)) {
- return GET_CALLBACK(uvd, setVideoMode)(uvd, vw);
- }
-
- if (vw->flags)
- return -EINVAL;
- if (vw->clipcount)
- return -EINVAL;
- if (vw->width != VIDEOSIZE_X(uvd->canvas))
- return -EINVAL;
- if (vw->height != VIDEOSIZE_Y(uvd->canvas))
- return -EINVAL;
-
- return 0;
- }
- case VIDIOCGWIN:
- {
- struct video_window *vw = arg;
-
- vw->x = 0;
- vw->y = 0;
- vw->width = VIDEOSIZE_X(uvd->videosize);
- vw->height = VIDEOSIZE_Y(uvd->videosize);
- vw->chromakey = 0;
- if (VALID_CALLBACK(uvd, getFPS))
- vw->flags = GET_CALLBACK(uvd, getFPS)(uvd);
- else
- vw->flags = 10; /* FIXME: do better! */
- return 0;
- }
- case VIDIOCGMBUF:
- {
- struct video_mbuf *vm = arg;
- int i;
-
- memset(vm, 0, sizeof(*vm));
- vm->size = uvd->max_frame_size * USBVIDEO_NUMFRAMES;
- vm->frames = USBVIDEO_NUMFRAMES;
- for(i = 0; i < USBVIDEO_NUMFRAMES; i++)
- vm->offsets[i] = i * uvd->max_frame_size;
-
- return 0;
- }
- case VIDIOCMCAPTURE:
- {
- struct video_mmap *vm = arg;
-
- if (uvd->debug >= 1) {
- dev_info(&uvd->dev->dev,
- "VIDIOCMCAPTURE: frame=%d. size=%dx%d, format=%d.\n",
- vm->frame, vm->width, vm->height, vm->format);
- }
- /*
- * Check if the requested size is supported. If the requestor
- * requests too big a frame then we may be tricked into accessing
- * outside of own preallocated frame buffer (in uvd->frame).
- * This will cause oops or a security hole. Theoretically, we
- * could only clamp the size down to acceptable bounds, but then
- * we'd need to figure out how to insert our smaller buffer into
- * larger caller's buffer... this is not an easy question. So we
- * here just flatly reject too large requests, assuming that the
- * caller will resubmit with smaller size. Callers should know
- * what size we support (returned by VIDIOCGCAP). However vidcat,
- * for one, does not care and allows to ask for any size.
- */
- if ((vm->width > VIDEOSIZE_X(uvd->canvas)) ||
- (vm->height > VIDEOSIZE_Y(uvd->canvas))) {
- if (uvd->debug > 0) {
- dev_info(&uvd->dev->dev,
- "VIDIOCMCAPTURE: Size=%dx%d "
- "too large; allowed only up "
- "to %ldx%ld\n", vm->width,
- vm->height,
- VIDEOSIZE_X(uvd->canvas),
- VIDEOSIZE_Y(uvd->canvas));
- }
- return -EINVAL;
- }
- /* Check if the palette is supported */
- if (((1L << vm->format) & uvd->paletteBits) == 0) {
- if (uvd->debug > 0) {
- dev_info(&uvd->dev->dev,
- "VIDIOCMCAPTURE: format=%d. "
- "not supported "
- "(paletteBits=$%08lx)\n",
- vm->format, uvd->paletteBits);
- }
- return -EINVAL;
- }
- if ((vm->frame < 0) || (vm->frame >= USBVIDEO_NUMFRAMES)) {
- err("VIDIOCMCAPTURE: vm.frame=%d. !E [0-%d]", vm->frame, USBVIDEO_NUMFRAMES-1);
- return -EINVAL;
- }
- if (uvd->frame[vm->frame].frameState == FrameState_Grabbing) {
- /* Not an error - can happen */
- }
- uvd->frame[vm->frame].request = VIDEOSIZE(vm->width, vm->height);
- uvd->frame[vm->frame].palette = vm->format;
-
- /* Mark it as ready */
- uvd->frame[vm->frame].frameState = FrameState_Ready;
-
- return usbvideo_NewFrame(uvd, vm->frame);
- }
- case VIDIOCSYNC:
- {
- int *frameNum = arg;
- int ret;
-
- if (*frameNum < 0 || *frameNum >= USBVIDEO_NUMFRAMES)
- return -EINVAL;
-
- if (uvd->debug >= 1)
- dev_info(&uvd->dev->dev,
- "VIDIOCSYNC: syncing to frame %d.\n",
- *frameNum);
- if (uvd->flags & FLAGS_NO_DECODING)
- ret = usbvideo_GetFrame(uvd, *frameNum);
- else if (VALID_CALLBACK(uvd, getFrame)) {
- ret = GET_CALLBACK(uvd, getFrame)(uvd, *frameNum);
- if ((ret < 0) && (uvd->debug >= 1)) {
- err("VIDIOCSYNC: getFrame() returned %d.", ret);
- }
- } else {
- err("VIDIOCSYNC: getFrame is not set");
- ret = -EFAULT;
- }
-
- /*
- * The frame is in FrameState_Done_Hold state. Release it
- * right now because its data is already mapped into
- * the user space and it's up to the application to
- * make use of it until it asks for another frame.
- */
- uvd->frame[*frameNum].frameState = FrameState_Unused;
- return ret;
- }
- case VIDIOCGFBUF:
- {
- struct video_buffer *vb = arg;
-
- memset(vb, 0, sizeof(*vb));
- return 0;
- }
- case VIDIOCKEY:
- return 0;
-
- case VIDIOCCAPTURE:
- return -EINVAL;
-
- case VIDIOCSFBUF:
-
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
-
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
-
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- return -EINVAL;
-
- default:
- return -ENOIOCTLCMD;
- }
- return 0;
-}
-
-static long usbvideo_v4l_ioctl(struct file *file,
- unsigned int cmd, unsigned long arg)
-{
- return video_usercopy(file, cmd, arg, usbvideo_v4l_do_ioctl);
-}
-
-/*
- * usbvideo_v4l_read()
- *
- * This is mostly boring stuff. We simply ask for a frame and when it
- * arrives copy all the video data from it into user space. There is
- * no obvious need to override this method.
- *
- * History:
- * 20-Oct-2000 Created.
- * 01-Nov-2000 Added mutex (uvd->lock).
- */
-static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
- size_t count, loff_t *ppos)
-{
- struct uvd *uvd = file->private_data;
- int noblock = file->f_flags & O_NONBLOCK;
- int frmx = -1, i;
- struct usbvideo_frame *frame;
-
- if (!CAMERA_IS_OPERATIONAL(uvd) || (buf == NULL))
- return -EFAULT;
-
- if (uvd->debug >= 1)
- dev_info(&uvd->dev->dev,
- "%s: %Zd. bytes, noblock=%d.\n",
- __func__, count, noblock);
-
- mutex_lock(&uvd->lock);
-
- /* See if a frame is completed, then use it. */
- for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
- if ((uvd->frame[i].frameState == FrameState_Done) ||
- (uvd->frame[i].frameState == FrameState_Done_Hold) ||
- (uvd->frame[i].frameState == FrameState_Error)) {
- frmx = i;
- break;
- }
- }
-
- /* FIXME: If we don't start a frame here then who ever does? */
- if (noblock && (frmx == -1)) {
- count = -EAGAIN;
- goto read_done;
- }
-
- /*
- * If no FrameState_Done, look for a FrameState_Grabbing state.
- * See if a frame is in process (grabbing), then use it.
- * We will need to wait until it becomes cooked, of course.
- */
- if (frmx == -1) {
- for(i = 0; i < USBVIDEO_NUMFRAMES; i++) {
- if (uvd->frame[i].frameState == FrameState_Grabbing) {
- frmx = i;
- break;
- }
- }
- }
-
- /*
- * If no frame is active, start one. We don't care which one
- * it will be, so #0 is as good as any.
- * In read access mode we don't have convenience of VIDIOCMCAPTURE
- * to specify the requested palette (video format) on per-frame
- * basis. This means that we have to return data in -some- format
- * and just hope that the client knows what to do with it.
- * The default format is configured in uvd->defaultPalette field
- * as one of VIDEO_PALETTE_xxx values. We stuff it into the new
- * frame and initiate the frame filling process.
- */
- if (frmx == -1) {
- if (uvd->defaultPalette == 0) {
- err("%s: No default palette; don't know what to do!", __func__);
- count = -EFAULT;
- goto read_done;
- }
- frmx = 0;
- /*
- * We have no per-frame control over video size.
- * Therefore we only can use whatever size was
- * specified as default.
- */
- uvd->frame[frmx].request = uvd->videosize;
- uvd->frame[frmx].palette = uvd->defaultPalette;
- uvd->frame[frmx].frameState = FrameState_Ready;
- usbvideo_NewFrame(uvd, frmx);
- /* Now frame 0 is supposed to start filling... */
- }
-
- /*
- * Get a pointer to the active frame. It is either previously
- * completed frame or frame in progress but not completed yet.
- */
- frame = &uvd->frame[frmx];
-
- /*
- * Sit back & wait until the frame gets filled and postprocessed.
- * If we fail to get the picture [in time] then return the error.
- * In this call we specify that we want the frame to be waited for,
- * postprocessed and switched into FrameState_Done_Hold state. This
- * state is used to hold the frame as "fully completed" between
- * subsequent partial reads of the same frame.
- */
- if (frame->frameState != FrameState_Done_Hold) {
- long rv = -EFAULT;
- if (uvd->flags & FLAGS_NO_DECODING)
- rv = usbvideo_GetFrame(uvd, frmx);
- else if (VALID_CALLBACK(uvd, getFrame))
- rv = GET_CALLBACK(uvd, getFrame)(uvd, frmx);
- else
- err("getFrame is not set");
- if ((rv != 0) || (frame->frameState != FrameState_Done_Hold)) {
- count = rv;
- goto read_done;
- }
- }
-
- /*
- * Copy bytes to user space. We allow for partial reads, which
- * means that the user application can request read less than
- * the full frame size. It is up to the application to issue
- * subsequent calls until entire frame is read.
- *
- * First things first, make sure we don't copy more than we
- * have - even if the application wants more. That would be
- * a big security embarassment!
- */
- if ((count + frame->seqRead_Index) > frame->seqRead_Length)
- count = frame->seqRead_Length - frame->seqRead_Index;
-
- /*
- * Copy requested amount of data to user space. We start
- * copying from the position where we last left it, which
- * will be zero for a new frame (not read before).
- */
- if (copy_to_user(buf, frame->data + frame->seqRead_Index, count)) {
- count = -EFAULT;
- goto read_done;
- }
-
- /* Update last read position */
- frame->seqRead_Index += count;
- if (uvd->debug >= 1) {
- err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
- __func__, count, frame->seqRead_Index);
- }
-
- /* Finally check if the frame is done with and "release" it */
- if (frame->seqRead_Index >= frame->seqRead_Length) {
- /* All data has been read */
- frame->seqRead_Index = 0;
-
- /* Mark it as available to be used again. */
- uvd->frame[frmx].frameState = FrameState_Unused;
- if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
- err("%s: usbvideo_NewFrame failed.", __func__);
- }
- }
-read_done:
- mutex_unlock(&uvd->lock);
- return count;
-}
-
-/*
- * Make all of the blocks of data contiguous
- */
-static int usbvideo_CompressIsochronous(struct uvd *uvd, struct urb *urb)
-{
- char *cdata;
- int i, totlen = 0;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- int n = urb->iso_frame_desc[i].actual_length;
- int st = urb->iso_frame_desc[i].status;
-
- cdata = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
-
- /* Detect and ignore errored packets */
- if (st < 0) {
- if (uvd->debug >= 1)
- err("Data error: packet=%d. len=%d. status=%d.", i, n, st);
- uvd->stats.iso_err_count++;
- continue;
- }
-
- /* Detect and ignore empty packets */
- if (n <= 0) {
- uvd->stats.iso_skip_count++;
- continue;
- }
- totlen += n; /* Little local accounting */
- RingQueue_Enqueue(&uvd->dp, cdata, n);
- }
- return totlen;
-}
-
-static void usbvideo_IsocIrq(struct urb *urb)
-{
- int i, ret, len;
- struct uvd *uvd = urb->context;
-
- /* We don't want to do anything if we are about to be removed! */
- if (!CAMERA_IS_OPERATIONAL(uvd))
- return;
-#if 0
- if (urb->actual_length > 0) {
- dev_info(&uvd->dev->dev,
- "urb=$%p status=%d. errcount=%d. length=%d.\n",
- urb, urb->status, urb->error_count,
- urb->actual_length);
- } else {
- static int c = 0;
- if (c++ % 100 == 0)
- dev_info(&uvd->dev->dev, "No Isoc data\n");
- }
-#endif
-
- if (!uvd->streaming) {
- if (uvd->debug >= 1)
- dev_info(&uvd->dev->dev,
- "Not streaming, but interrupt!\n");
- return;
- }
-
- uvd->stats.urb_count++;
- if (urb->actual_length <= 0)
- goto urb_done_with;
-
- /* Copy the data received into ring queue */
- len = usbvideo_CompressIsochronous(uvd, urb);
- uvd->stats.urb_length = len;
- if (len <= 0)
- goto urb_done_with;
-
- /* Here we got some data */
- uvd->stats.data_count += len;
- RingQueue_WakeUpInterruptible(&uvd->dp);
-
-urb_done_with:
- for (i = 0; i < FRAMES_PER_DESC; i++) {
- urb->iso_frame_desc[i].status = 0;
- urb->iso_frame_desc[i].actual_length = 0;
- }
- urb->status = 0;
- urb->dev = uvd->dev;
- ret = usb_submit_urb (urb, GFP_KERNEL);
- if(ret)
- err("usb_submit_urb error (%d)", ret);
- return;
-}
-
-/*
- * usbvideo_StartDataPump()
- *
- * History:
- * 27-Jan-2000 Used ibmcam->iface, ibmcam->ifaceAltActive instead
- * of hardcoded values. Simplified by using for loop,
- * allowed any number of URBs.
- */
-static int usbvideo_StartDataPump(struct uvd *uvd)
-{
- struct usb_device *dev = uvd->dev;
- int i, errFlag;
-
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd);
-
- if (!CAMERA_IS_OPERATIONAL(uvd)) {
- err("%s: Camera is not operational", __func__);
- return -EFAULT;
- }
- uvd->curframe = -1;
-
- /* Alternate interface 1 is is the biggest frame size */
- i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
- if (i < 0) {
- err("%s: usb_set_interface error", __func__);
- uvd->last_error = i;
- return -EBUSY;
- }
- if (VALID_CALLBACK(uvd, videoStart))
- GET_CALLBACK(uvd, videoStart)(uvd);
- else
- err("%s: videoStart not set", __func__);
-
- /* We double buffer the Iso lists */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- int j, k;
- struct urb *urb = uvd->sbuf[i].urb;
- urb->dev = dev;
- urb->context = uvd;
- urb->pipe = usb_rcvisocpipe(dev, uvd->video_endp);
- urb->interval = 1;
- urb->transfer_flags = URB_ISO_ASAP;
- urb->transfer_buffer = uvd->sbuf[i].data;
- urb->complete = usbvideo_IsocIrq;
- urb->number_of_packets = FRAMES_PER_DESC;
- urb->transfer_buffer_length = uvd->iso_packet_len * FRAMES_PER_DESC;
- for (j=k=0; j < FRAMES_PER_DESC; j++, k += uvd->iso_packet_len) {
- urb->iso_frame_desc[j].offset = k;
- urb->iso_frame_desc[j].length = uvd->iso_packet_len;
- }
- }
-
- /* Submit all URBs */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
- if (errFlag)
- err("%s: usb_submit_isoc(%d) ret %d", __func__, i, errFlag);
- }
-
- uvd->streaming = 1;
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev,
- "%s: streaming=1 video_endp=$%02x\n", __func__,
- uvd->video_endp);
- return 0;
-}
-
-/*
- * usbvideo_StopDataPump()
- *
- * This procedure stops streaming and deallocates URBs. Then it
- * activates zero-bandwidth alt. setting of the video interface.
- *
- * History:
- * 22-Jan-2000 Corrected order of actions to work after surprise removal.
- * 27-Jan-2000 Used uvd->iface, uvd->ifaceAltInactive instead of hardcoded values.
- */
-static void usbvideo_StopDataPump(struct uvd *uvd)
-{
- int i, j;
-
- if ((uvd == NULL) || (!uvd->streaming) || (uvd->dev == NULL))
- return;
-
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev, "%s($%p)\n", __func__, uvd);
-
- /* Unschedule all of the iso td's */
- for (i=0; i < USBVIDEO_NUMSBUF; i++) {
- usb_kill_urb(uvd->sbuf[i].urb);
- }
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev, "%s: streaming=0\n", __func__);
- uvd->streaming = 0;
-
- if (!uvd->remove_pending) {
- /* Invoke minidriver's magic to stop the camera */
- if (VALID_CALLBACK(uvd, videoStop))
- GET_CALLBACK(uvd, videoStop)(uvd);
- else
- err("%s: videoStop not set", __func__);
-
- /* Set packet size to 0 */
- j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
- if (j < 0) {
- err("%s: usb_set_interface() error %d.", __func__, j);
- uvd->last_error = j;
- }
- }
-}
-
-/*
- * usbvideo_NewFrame()
- *
- * History:
- * 29-Mar-00 Added copying of previous frame into the current one.
- * 6-Aug-00 Added model 3 video sizes, removed redundant width, height.
- */
-static int usbvideo_NewFrame(struct uvd *uvd, int framenum)
-{
- struct usbvideo_frame *frame;
- int n;
-
- if (uvd->debug > 1)
- dev_info(&uvd->dev->dev, "usbvideo_NewFrame($%p,%d.)\n", uvd,
- framenum);
-
- /* If we're not grabbing a frame right now and the other frame is */
- /* ready to be grabbed into, then use it instead */
- if (uvd->curframe != -1)
- return 0;
-
- /* If necessary we adjust picture settings between frames */
- if (!uvd->settingsAdjusted) {
- if (VALID_CALLBACK(uvd, adjustPicture))
- GET_CALLBACK(uvd, adjustPicture)(uvd);
- uvd->settingsAdjusted = 1;
- }
-
- n = (framenum + 1) % USBVIDEO_NUMFRAMES;
- if (uvd->frame[n].frameState == FrameState_Ready)
- framenum = n;
-
- frame = &uvd->frame[framenum];
-
- frame->frameState = FrameState_Grabbing;
- frame->scanstate = ScanState_Scanning;
- frame->seqRead_Length = 0; /* Accumulated in xxx_parse_data() */
- frame->deinterlace = Deinterlace_None;
- frame->flags = 0; /* No flags yet, up to minidriver (or us) to set them */
- uvd->curframe = framenum;
-
- /*
- * Normally we would want to copy previous frame into the current one
- * before we even start filling it with data; this allows us to stop
- * filling at any moment; top portion of the frame will be new and
- * bottom portion will stay as it was in previous frame. If we don't
- * do that then missing chunks of video stream will result in flickering
- * portions of old data whatever it was before.
- *
- * If we choose not to copy previous frame (to, for example, save few
- * bus cycles - the frame can be pretty large!) then we have an option
- * to clear the frame before using. If we experience losses in this
- * mode then missing picture will be black (no flickering).
- *
- * Finally, if user chooses not to clean the current frame before
- * filling it with data then the old data will be visible if we fail
- * to refill entire frame with new data.
- */
- if (!(uvd->flags & FLAGS_SEPARATE_FRAMES)) {
- /* This copies previous frame into this one to mask losses */
- int prev = (framenum - 1 + USBVIDEO_NUMFRAMES) % USBVIDEO_NUMFRAMES;
- memmove(frame->data, uvd->frame[prev].data, uvd->max_frame_size);
- } else {
- if (uvd->flags & FLAGS_CLEAN_FRAMES) {
- /* This provides a "clean" frame but slows things down */
- memset(frame->data, 0, uvd->max_frame_size);
- }
- }
- return 0;
-}
-
-/*
- * usbvideo_CollectRawData()
- *
- * This procedure can be used instead of 'processData' callback if you
- * only want to dump the raw data from the camera into the output
- * device (frame buffer). You can look at it with V4L client, but the
- * image will be unwatchable. The main purpose of this code and of the
- * mode FLAGS_NO_DECODING is debugging and capturing of datastreams from
- * new, unknown cameras. This procedure will be automatically invoked
- * instead of the specified callback handler when uvd->flags has bit
- * FLAGS_NO_DECODING set. Therefore, any regular build of any driver
- * based on usbvideo can use this feature at any time.
- */
-static void usbvideo_CollectRawData(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- int n;
-
- assert(uvd != NULL);
- assert(frame != NULL);
-
- /* Try to move data from queue into frame buffer */
- n = RingQueue_GetLength(&uvd->dp);
- if (n > 0) {
- int m;
- /* See how much space we have left */
- m = uvd->max_frame_size - frame->seqRead_Length;
- if (n > m)
- n = m;
- /* Now move that much data into frame buffer */
- RingQueue_Dequeue(
- &uvd->dp,
- frame->data + frame->seqRead_Length,
- m);
- frame->seqRead_Length += m;
- }
- /* See if we filled the frame */
- if (frame->seqRead_Length >= uvd->max_frame_size) {
- frame->frameState = FrameState_Done;
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- }
-}
-
-static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
-{
- struct usbvideo_frame *frame = &uvd->frame[frameNum];
-
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev, "%s($%p,%d.)\n", __func__, uvd,
- frameNum);
-
- switch (frame->frameState) {
- case FrameState_Unused:
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev, "%s: FrameState_Unused\n",
- __func__);
- return -EINVAL;
- case FrameState_Ready:
- case FrameState_Grabbing:
- case FrameState_Error:
- {
- int ntries, signalPending;
- redo:
- if (!CAMERA_IS_OPERATIONAL(uvd)) {
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev,
- "%s: Camera is not operational (1)\n",
- __func__);
- return -EIO;
- }
- ntries = 0;
- do {
- RingQueue_InterruptibleSleepOn(&uvd->dp);
- signalPending = signal_pending(current);
- if (!CAMERA_IS_OPERATIONAL(uvd)) {
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev,
- "%s: Camera is not "
- "operational (2)\n", __func__);
- return -EIO;
- }
- assert(uvd->fbuf != NULL);
- if (signalPending) {
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev,
- "%s: Signal=$%08x\n", __func__,
- signalPending);
- if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
- usbvideo_TestPattern(uvd, 1, 0);
- uvd->curframe = -1;
- uvd->stats.frame_num++;
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev,
- "%s: Forced test "
- "pattern screen\n",
- __func__);
- return 0;
- } else {
- /* Standard answer: Interrupted! */
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev,
- "%s: Interrupted!\n",
- __func__);
- return -EINTR;
- }
- } else {
- /* No signals - we just got new data in dp queue */
- if (uvd->flags & FLAGS_NO_DECODING)
- usbvideo_CollectRawData(uvd, frame);
- else if (VALID_CALLBACK(uvd, processData))
- GET_CALLBACK(uvd, processData)(uvd, frame);
- else
- err("%s: processData not set", __func__);
- }
- } while (frame->frameState == FrameState_Grabbing);
- if (uvd->debug >= 2) {
- dev_info(&uvd->dev->dev,
- "%s: Grabbing done; state=%d. (%lu. bytes)\n",
- __func__, frame->frameState,
- frame->seqRead_Length);
- }
- if (frame->frameState == FrameState_Error) {
- int ret = usbvideo_NewFrame(uvd, frameNum);
- if (ret < 0) {
- err("%s: usbvideo_NewFrame() failed (%d.)", __func__, ret);
- return ret;
- }
- goto redo;
- }
- /* Note that we fall through to meet our destiny below */
- }
- case FrameState_Done:
- /*
- * Do all necessary postprocessing of data prepared in
- * "interrupt" code and the collecting code above. The
- * frame gets marked as FrameState_Done by queue parsing code.
- * This status means that we collected enough data and
- * most likely processed it as we went through. However
- * the data may need postprocessing, such as deinterlacing
- * or picture adjustments implemented in software (horror!)
- *
- * As soon as the frame becomes "final" it gets promoted to
- * FrameState_Done_Hold status where it will remain until the
- * caller consumed all the video data from the frame. Then
- * the empty shell of ex-frame is thrown out for dogs to eat.
- * But we, worried about pets, will recycle the frame!
- */
- uvd->stats.frame_num++;
- if ((uvd->flags & FLAGS_NO_DECODING) == 0) {
- if (VALID_CALLBACK(uvd, postProcess))
- GET_CALLBACK(uvd, postProcess)(uvd, frame);
- if (frame->flags & USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST)
- usbvideo_SoftwareContrastAdjustment(uvd, frame);
- }
- frame->frameState = FrameState_Done_Hold;
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev,
- "%s: Entered FrameState_Done_Hold state.\n",
- __func__);
- return 0;
-
- case FrameState_Done_Hold:
- /*
- * We stay in this state indefinitely until someone external,
- * like ioctl() or read() call finishes digesting the frame
- * data. Then it will mark the frame as FrameState_Unused and
- * it will be released back into the wild to roam freely.
- */
- if (uvd->debug >= 2)
- dev_info(&uvd->dev->dev,
- "%s: FrameState_Done_Hold state.\n",
- __func__);
- return 0;
- }
-
- /* Catch-all for other cases. We shall not be here. */
- err("%s: Invalid state %d.", __func__, frame->frameState);
- frame->frameState = FrameState_Unused;
- return 0;
-}
-
-/*
- * usbvideo_DeinterlaceFrame()
- *
- * This procedure deinterlaces the given frame. Some cameras produce
- * only half of scanlines - sometimes only even lines, sometimes only
- * odd lines. The deinterlacing method is stored in frame->deinterlace
- * variable.
- *
- * Here we scan the frame vertically and replace missing scanlines with
- * average between surrounding ones - before and after. If we have no
- * line above then we just copy next line. Similarly, if we need to
- * create a last line then preceding line is used.
- */
-void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame)
-{
- if ((uvd == NULL) || (frame == NULL))
- return;
-
- if ((frame->deinterlace == Deinterlace_FillEvenLines) ||
- (frame->deinterlace == Deinterlace_FillOddLines))
- {
- const int v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
- int i = (frame->deinterlace == Deinterlace_FillEvenLines) ? 0 : 1;
-
- for (; i < VIDEOSIZE_Y(frame->request); i += 2) {
- const unsigned char *fs1, *fs2;
- unsigned char *fd;
- int ip, in, j; /* Previous and next lines */
-
- /*
- * Need to average lines before and after 'i'.
- * If we go out of bounds seeking those lines then
- * we point back to existing line.
- */
- ip = i - 1; /* First, get rough numbers */
- in = i + 1;
-
- /* Now validate */
- if (ip < 0)
- ip = in;
- if (in >= VIDEOSIZE_Y(frame->request))
- in = ip;
-
- /* Sanity check */
- if ((ip < 0) || (in < 0) ||
- (ip >= VIDEOSIZE_Y(frame->request)) ||
- (in >= VIDEOSIZE_Y(frame->request)))
- {
- err("Error: ip=%d. in=%d. req.height=%ld.",
- ip, in, VIDEOSIZE_Y(frame->request));
- break;
- }
-
- /* Now we need to average lines 'ip' and 'in' to produce line 'i' */
- fs1 = frame->data + (v4l_linesize * ip);
- fs2 = frame->data + (v4l_linesize * in);
- fd = frame->data + (v4l_linesize * i);
-
- /* Average lines around destination */
- for (j=0; j < v4l_linesize; j++) {
- fd[j] = (unsigned char)((((unsigned) fs1[j]) +
- ((unsigned)fs2[j])) >> 1);
- }
- }
- }
-
- /* Optionally display statistics on the screen */
- if (uvd->flags & FLAGS_OVERLAY_STATS)
- usbvideo_OverlayStats(uvd, frame);
-}
-
-EXPORT_SYMBOL(usbvideo_DeinterlaceFrame);
-
-/*
- * usbvideo_SoftwareContrastAdjustment()
- *
- * This code adjusts the contrast of the frame, assuming RGB24 format.
- * As most software image processing, this job is CPU-intensive.
- * Get a camera that supports hardware adjustment!
- *
- * History:
- * 09-Feb-2001 Created.
- */
-static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
- struct usbvideo_frame *frame)
-{
- int i, j, v4l_linesize;
- signed long adj;
- const int ccm = 128; /* Color correction median - see below */
-
- if ((uvd == NULL) || (frame == NULL)) {
- err("%s: Illegal call.", __func__);
- return;
- }
- adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
- RESTRICT_TO_RANGE(adj, -ccm, ccm+1);
- if (adj == 0) {
- /* In rare case of no adjustment */
- return;
- }
- v4l_linesize = VIDEOSIZE_X(frame->request) * V4L_BYTES_PER_PIXEL;
- for (i=0; i < VIDEOSIZE_Y(frame->request); i++) {
- unsigned char *fd = frame->data + (v4l_linesize * i);
- for (j=0; j < v4l_linesize; j++) {
- signed long v = (signed long) fd[j];
- /* Magnify up to 2 times, reduce down to zero */
- v = 128 + ((ccm + adj) * (v - 128)) / ccm;
- RESTRICT_TO_RANGE(v, 0, 0xFF); /* Must flatten tails */
- fd[j] = (unsigned char) v;
- }
- }
-}
-
-MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/usbvideo/usbvideo.h b/drivers/media/video/usbvideo/usbvideo.h
deleted file mode 100644
index c66985beb8c9..000000000000
--- a/drivers/media/video/usbvideo/usbvideo.h
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2, or (at your option)
- * any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
- */
-#ifndef usbvideo_h
-#define usbvideo_h
-
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/usb.h>
-#include <linux/mutex.h>
-
-/* Most helpful debugging aid */
-#define assert(expr) ((void) ((expr) ? 0 : (err("assert failed at line %d",__LINE__))))
-
-#define USBVIDEO_REPORT_STATS 1 /* Set to 0 to block statistics on close */
-
-/* Bit flags (options) */
-#define FLAGS_RETRY_VIDIOCSYNC (1 << 0)
-#define FLAGS_MONOCHROME (1 << 1)
-#define FLAGS_DISPLAY_HINTS (1 << 2)
-#define FLAGS_OVERLAY_STATS (1 << 3)
-#define FLAGS_FORCE_TESTPATTERN (1 << 4)
-#define FLAGS_SEPARATE_FRAMES (1 << 5)
-#define FLAGS_CLEAN_FRAMES (1 << 6)
-#define FLAGS_NO_DECODING (1 << 7)
-
-/* Bit flags for frames (apply to the frame where they are specified) */
-#define USBVIDEO_FRAME_FLAG_SOFTWARE_CONTRAST (1 << 0)
-
-/* Camera capabilities (maximum) */
-#define CAMERA_URB_FRAMES 32
-#define CAMERA_MAX_ISO_PACKET 1023 /* 1022 actually sent by camera */
-#define FRAMES_PER_DESC (CAMERA_URB_FRAMES)
-#define FRAME_SIZE_PER_DESC (CAMERA_MAX_ISO_PACKET)
-
-/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
-
-#define V4L_BYTES_PER_PIXEL 3 /* Because we produce RGB24 */
-
-/*
- * Use this macro to construct constants for different video sizes.
- * We have to deal with different video sizes that have to be
- * configured in the device or compared against when we receive
- * a data. Normally one would define a bunch of VIDEOSIZE_x_by_y
- * #defines and that's the end of story. However this solution
- * does not allow to convert between real pixel sizes and the
- * constant (integer) value that may be used to tag a frame or
- * whatever. The set of macros below constructs videosize constants
- * from the pixel size and allows to reconstruct the pixel size
- * from the combined value later.
- */
-#define VIDEOSIZE(x,y) (((x) & 0xFFFFL) | (((y) & 0xFFFFL) << 16))
-#define VIDEOSIZE_X(vs) ((vs) & 0xFFFFL)
-#define VIDEOSIZE_Y(vs) (((vs) >> 16) & 0xFFFFL)
-typedef unsigned long videosize_t;
-
-/*
- * This macro checks if the camera is still operational. The 'uvd'
- * pointer must be valid, uvd->dev must be valid, we are not
- * removing the device and the device has not erred on us.
- */
-#define CAMERA_IS_OPERATIONAL(uvd) (\
- (uvd != NULL) && \
- ((uvd)->dev != NULL) && \
- ((uvd)->last_error == 0) && \
- (!(uvd)->remove_pending))
-
-/*
- * We use macros to do YUV -> RGB conversion because this is
- * very important for speed and totally unimportant for size.
- *
- * YUV -> RGB Conversion
- * ---------------------
- *
- * B = 1.164*(Y-16) + 2.018*(V-128)
- * G = 1.164*(Y-16) - 0.813*(U-128) - 0.391*(V-128)
- * R = 1.164*(Y-16) + 1.596*(U-128)
- *
- * If you fancy integer arithmetics (as you should), hear this:
- *
- * 65536*B = 76284*(Y-16) + 132252*(V-128)
- * 65536*G = 76284*(Y-16) - 53281*(U-128) - 25625*(V-128)
- * 65536*R = 76284*(Y-16) + 104595*(U-128)
- *
- * Make sure the output values are within [0..255] range.
- */
-#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
-#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
- int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
- mm_y = (my) - 16; \
- mm_u = (mu) - 128; \
- mm_v = (mv) - 128; \
- mm_yc= mm_y * 76284; \
- mm_b = (mm_yc + 132252*mm_v ) >> 16; \
- mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \
- mm_r = (mm_yc + 104595*mm_u ) >> 16; \
- mb = LIMIT_RGB(mm_b); \
- mg = LIMIT_RGB(mm_g); \
- mr = LIMIT_RGB(mm_r); \
-}
-
-#define RING_QUEUE_SIZE (128*1024) /* Must be a power of 2 */
-#define RING_QUEUE_ADVANCE_INDEX(rq,ind,n) (rq)->ind = ((rq)->ind + (n)) & ((rq)->length-1)
-#define RING_QUEUE_DEQUEUE_BYTES(rq,n) RING_QUEUE_ADVANCE_INDEX(rq,ri,n)
-#define RING_QUEUE_PEEK(rq,ofs) ((rq)->queue[((ofs) + (rq)->ri) & ((rq)->length-1)])
-
-struct RingQueue {
- unsigned char *queue; /* Data from the Isoc data pump */
- int length; /* How many bytes allocated for the queue */
- int wi; /* That's where we write */
- int ri; /* Read from here until you hit write index */
- wait_queue_head_t wqh; /* Processes waiting */
-};
-
-enum ScanState {
- ScanState_Scanning, /* Scanning for header */
- ScanState_Lines /* Parsing lines */
-};
-
-/* Completion states of the data parser */
-enum ParseState {
- scan_Continue, /* Just parse next item */
- scan_NextFrame, /* Frame done, send it to V4L */
- scan_Out, /* Not enough data for frame */
- scan_EndParse /* End parsing */
-};
-
-enum FrameState {
- FrameState_Unused, /* Unused (no MCAPTURE) */
- FrameState_Ready, /* Ready to start grabbing */
- FrameState_Grabbing, /* In the process of being grabbed into */
- FrameState_Done, /* Finished grabbing, but not been synced yet */
- FrameState_Done_Hold, /* Are syncing or reading */
- FrameState_Error, /* Something bad happened while processing */
-};
-
-/*
- * Some frames may contain only even or odd lines. This type
- * specifies what type of deinterlacing is required.
- */
-enum Deinterlace {
- Deinterlace_None=0,
- Deinterlace_FillOddLines,
- Deinterlace_FillEvenLines
-};
-
-#define USBVIDEO_NUMFRAMES 2 /* How many frames we work with */
-#define USBVIDEO_NUMSBUF 2 /* How many URBs linked in a ring */
-
-/* This structure represents one Isoc request - URB and buffer */
-struct usbvideo_sbuf {
- char *data;
- struct urb *urb;
-};
-
-struct usbvideo_frame {
- char *data; /* Frame buffer */
- unsigned long header; /* Significant bits from the header */
-
- videosize_t canvas; /* The canvas (max. image) allocated */
- videosize_t request; /* That's what the application asked for */
- unsigned short palette; /* The desired format */
-
- enum FrameState frameState;/* State of grabbing */
- enum ScanState scanstate; /* State of scanning */
- enum Deinterlace deinterlace;
- int flags; /* USBVIDEO_FRAME_FLAG_xxx bit flags */
-
- int curline; /* Line of frame we're working on */
-
- long seqRead_Length; /* Raw data length of frame */
- long seqRead_Index; /* Amount of data that has been already read */
-
- void *user; /* Additional data that user may need */
-};
-
-/* Statistics that can be overlaid on screen */
-struct usbvideo_statistics {
- unsigned long frame_num; /* Sequential number of the frame */
- unsigned long urb_count; /* How many URBs we received so far */
- unsigned long urb_length; /* Length of last URB */
- unsigned long data_count; /* How many bytes we received */
- unsigned long header_count; /* How many frame headers we found */
- unsigned long iso_skip_count; /* How many empty ISO packets received */
- unsigned long iso_err_count; /* How many bad ISO packets received */
-};
-
-struct usbvideo;
-
-struct uvd {
- struct video_device vdev; /* Must be the first field! */
- struct usb_device *dev;
- struct usbvideo *handle; /* Points back to the struct usbvideo */
- void *user_data; /* Camera-dependent data */
- int user_size; /* Size of that camera-dependent data */
- int debug; /* Debug level for usbvideo */
- unsigned char iface; /* Video interface number */
- unsigned char video_endp;
- unsigned char ifaceAltActive;
- unsigned char ifaceAltInactive; /* Alt settings */
- unsigned long flags; /* FLAGS_USBVIDEO_xxx */
- unsigned long paletteBits; /* Which palettes we accept? */
- unsigned short defaultPalette; /* What palette to use for read() */
- struct mutex lock;
- int user; /* user count for exclusive use */
-
- videosize_t videosize; /* Current setting */
- videosize_t canvas; /* This is the width,height of the V4L canvas */
- int max_frame_size; /* Bytes in one video frame */
-
- int uvd_used; /* Is this structure in use? */
- int streaming; /* Are we streaming Isochronous? */
- int grabbing; /* Are we grabbing? */
- int settingsAdjusted; /* Have we adjusted contrast etc.? */
- int last_error; /* What calamity struck us? */
-
- char *fbuf; /* Videodev buffer area */
- int fbuf_size; /* Videodev buffer size */
-
- int curframe;
- int iso_packet_len; /* Videomode-dependent, saves bus bandwidth */
-
- struct RingQueue dp; /* Isoc data pump */
- struct usbvideo_frame frame[USBVIDEO_NUMFRAMES];
- struct usbvideo_sbuf sbuf[USBVIDEO_NUMSBUF];
-
- volatile int remove_pending; /* If set then about to exit */
-
- struct video_picture vpic, vpic_old; /* Picture settings */
- struct video_capability vcap; /* Video capabilities */
- struct video_channel vchan; /* May be used for tuner support */
- struct usbvideo_statistics stats;
- char videoName[32]; /* Holds name like "video7" */
-};
-
-/*
- * usbvideo callbacks (virtual methods). They are set when usbvideo
- * services are registered. All of these default to NULL, except those
- * that default to usbvideo-provided methods.
- */
-struct usbvideo_cb {
- int (*probe)(struct usb_interface *, const struct usb_device_id *);
- void (*userFree)(struct uvd *);
- void (*disconnect)(struct usb_interface *);
- int (*setupOnOpen)(struct uvd *);
- void (*videoStart)(struct uvd *);
- void (*videoStop)(struct uvd *);
- void (*processData)(struct uvd *, struct usbvideo_frame *);
- void (*postProcess)(struct uvd *, struct usbvideo_frame *);
- void (*adjustPicture)(struct uvd *);
- int (*getFPS)(struct uvd *);
- int (*overlayHook)(struct uvd *, struct usbvideo_frame *);
- int (*getFrame)(struct uvd *, int);
- int (*startDataPump)(struct uvd *uvd);
- void (*stopDataPump)(struct uvd *uvd);
- int (*setVideoMode)(struct uvd *uvd, struct video_window *vw);
-};
-
-struct usbvideo {
- int num_cameras; /* As allocated */
- struct usb_driver usbdrv; /* Interface to the USB stack */
- char drvName[80]; /* Driver name */
- struct mutex lock; /* Mutex protecting camera structures */
- struct usbvideo_cb cb; /* Table of callbacks (virtual methods) */
- struct video_device vdt; /* Video device template */
- struct uvd *cam; /* Array of camera structures */
- struct module *md_module; /* Minidriver module */
-};
-
-
-/*
- * This macro retrieves callback address from the struct uvd object.
- * No validity checks are done here, so be sure to check the
- * callback beforehand with VALID_CALLBACK.
- */
-#define GET_CALLBACK(uvd,cbName) ((uvd)->handle->cb.cbName)
-
-/*
- * This macro returns either callback pointer or NULL. This is safe
- * macro, meaning that most of components of data structures involved
- * may be NULL - this only results in NULL being returned. You may
- * wish to use this macro to make sure that the callback is callable.
- * However keep in mind that those checks take time.
- */
-#define VALID_CALLBACK(uvd,cbName) ((((uvd) != NULL) && \
- ((uvd)->handle != NULL)) ? GET_CALLBACK(uvd,cbName) : NULL)
-
-int RingQueue_Dequeue(struct RingQueue *rq, unsigned char *dst, int len);
-int RingQueue_Enqueue(struct RingQueue *rq, const unsigned char *cdata, int n);
-void RingQueue_WakeUpInterruptible(struct RingQueue *rq);
-void RingQueue_Flush(struct RingQueue *rq);
-
-static inline int RingQueue_GetLength(const struct RingQueue *rq)
-{
- return (rq->wi - rq->ri + rq->length) & (rq->length-1);
-}
-
-static inline int RingQueue_GetFreeSpace(const struct RingQueue *rq)
-{
- return rq->length - RingQueue_GetLength(rq);
-}
-
-void usbvideo_DrawLine(
- struct usbvideo_frame *frame,
- int x1, int y1,
- int x2, int y2,
- unsigned char cr, unsigned char cg, unsigned char cb);
-void usbvideo_HexDump(const unsigned char *data, int len);
-void usbvideo_SayAndWait(const char *what);
-void usbvideo_TestPattern(struct uvd *uvd, int fullframe, int pmode);
-
-/* Memory allocation routines */
-unsigned long usbvideo_kvirt_to_pa(unsigned long adr);
-
-int usbvideo_register(
- struct usbvideo **pCams,
- const int num_cams,
- const int num_extra,
- const char *driverName,
- const struct usbvideo_cb *cbTable,
- struct module *md,
- const struct usb_device_id *id_table);
-struct uvd *usbvideo_AllocateDevice(struct usbvideo *cams);
-int usbvideo_RegisterVideoDevice(struct uvd *uvd);
-void usbvideo_Deregister(struct usbvideo **uvt);
-
-int usbvideo_v4l_initialize(struct video_device *dev);
-
-void usbvideo_DeinterlaceFrame(struct uvd *uvd, struct usbvideo_frame *frame);
-
-/*
- * This code performs bounds checking - use it when working with
- * new formats, or else you may get oopses all over the place.
- * If pixel falls out of bounds then it gets shoved back (as close
- * to place of offence as possible) and is painted bright red.
- *
- * There are two important concepts: frame width, height and
- * V4L canvas width, height. The former is the area requested by
- * the application -for this very frame-. The latter is the largest
- * possible frame that we can serve (we advertise that via V4L ioctl).
- * The frame data is expected to be formatted as lines of length
- * VIDEOSIZE_X(fr->request), total VIDEOSIZE_Y(frame->request) lines.
- */
-static inline void RGB24_PUTPIXEL(
- struct usbvideo_frame *fr,
- int ix, int iy,
- unsigned char vr,
- unsigned char vg,
- unsigned char vb)
-{
- register unsigned char *pf;
- int limiter = 0, mx, my;
- mx = ix;
- my = iy;
- if (mx < 0) {
- mx=0;
- limiter++;
- } else if (mx >= VIDEOSIZE_X((fr)->request)) {
- mx= VIDEOSIZE_X((fr)->request) - 1;
- limiter++;
- }
- if (my < 0) {
- my = 0;
- limiter++;
- } else if (my >= VIDEOSIZE_Y((fr)->request)) {
- my = VIDEOSIZE_Y((fr)->request) - 1;
- limiter++;
- }
- pf = (fr)->data + V4L_BYTES_PER_PIXEL*((iy)*VIDEOSIZE_X((fr)->request) + (ix));
- if (limiter) {
- *pf++ = 0;
- *pf++ = 0;
- *pf++ = 0xFF;
- } else {
- *pf++ = (vb);
- *pf++ = (vg);
- *pf++ = (vr);
- }
-}
-
-#endif /* usbvideo_h */
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
deleted file mode 100644
index 6030410c6677..000000000000
--- a/drivers/media/video/usbvideo/vicam.c
+++ /dev/null
@@ -1,953 +0,0 @@
-/*
- * USB ViCam WebCam driver
- * Copyright (c) 2002 Joe Burks (jburks@wavicle.org),
- * Christopher L Cheney (ccheney@cheney.cx),
- * Pavel Machek (pavel@suse.cz),
- * John Tyner (jtyner@cs.ucr.edu),
- * Monroe Williams (monroe@pobox.com)
- *
- * Supports 3COM HomeConnect PC Digital WebCam
- * Supports Compro PS39U WebCam
- *
- * 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.
- *
- * This source code is based heavily on the CPiA webcam driver which was
- * written by Peter Pregler, Scott J. Bertin and Johannes Erdfelt
- *
- * Portions of this code were also copied from usbvideo.c
- *
- * Special thanks to the whole team at Sourceforge for help making
- * this driver become a reality. Notably:
- * Andy Armstrong who reverse engineered the color encoding and
- * Pavel Machek and Chris Cheney who worked on reverse engineering the
- * camera controls and wrote the first generation driver.
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/videodev.h>
-#include <linux/usb.h>
-#include <linux/vmalloc.h>
-#include <linux/mm.h>
-#include <linux/slab.h>
-#include <linux/smp_lock.h>
-#include <linux/mutex.h>
-#include <linux/firmware.h>
-#include <linux/ihex.h>
-#include "usbvideo.h"
-
-// #define VICAM_DEBUG
-
-#ifdef VICAM_DEBUG
-#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __func__, lineno, ##args)
-#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
-#else
-#define DBG(fmn,args...) do {} while(0)
-#endif
-
-#define DRIVER_AUTHOR "Joe Burks, jburks@wavicle.org"
-#define DRIVER_DESC "ViCam WebCam Driver"
-
-/* Define these values to match your device */
-#define USB_VICAM_VENDOR_ID 0x04c1
-#define USB_VICAM_PRODUCT_ID 0x009d
-#define USB_COMPRO_VENDOR_ID 0x0602
-#define USB_COMPRO_PRODUCT_ID 0x1001
-
-#define VICAM_BYTES_PER_PIXEL 3
-#define VICAM_MAX_READ_SIZE (512*242+128)
-#define VICAM_MAX_FRAME_SIZE (VICAM_BYTES_PER_PIXEL*320*240)
-#define VICAM_FRAMES 2
-
-#define VICAM_HEADER_SIZE 64
-
-/* rvmalloc / rvfree copied from usbvideo.c
- *
- * Not sure why these are not yet non-statics which I can reference through
- * usbvideo.h the same as it is in 2.4.20. I bet this will get fixed sometime
- * in the future.
- *
-*/
-static void *rvmalloc(unsigned long size)
-{
- void *mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-static void rvfree(void *mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-struct vicam_camera {
- u16 shutter_speed; // capture shutter speed
- u16 gain; // capture gain
-
- u8 *raw_image; // raw data captured from the camera
- u8 *framebuf; // processed data in RGB24 format
- u8 *cntrlbuf; // area used to send control msgs
-
- struct video_device vdev; // v4l video device
- struct usb_device *udev; // usb device
-
- /* guard against simultaneous accesses to the camera */
- struct mutex cam_lock;
-
- int is_initialized;
- u8 open_count;
- u8 bulkEndpoint;
- int needsDummyRead;
-};
-
-static int vicam_probe( struct usb_interface *intf, const struct usb_device_id *id);
-static void vicam_disconnect(struct usb_interface *intf);
-static void read_frame(struct vicam_camera *cam, int framenum);
-static void vicam_decode_color(const u8 *, u8 *);
-
-static int __send_control_msg(struct vicam_camera *cam,
- u8 request,
- u16 value,
- u16 index,
- unsigned char *cp,
- u16 size)
-{
- int status;
-
- /* cp must be memory that has been allocated by kmalloc */
-
- status = usb_control_msg(cam->udev,
- usb_sndctrlpipe(cam->udev, 0),
- request,
- USB_DIR_OUT | USB_TYPE_VENDOR |
- USB_RECIP_DEVICE, value, index,
- cp, size, 1000);
-
- status = min(status, 0);
-
- if (status < 0) {
- printk(KERN_INFO "Failed sending control message, error %d.\n",
- status);
- }
-
- return status;
-}
-
-static int send_control_msg(struct vicam_camera *cam,
- u8 request,
- u16 value,
- u16 index,
- unsigned char *cp,
- u16 size)
-{
- int status = -ENODEV;
- mutex_lock(&cam->cam_lock);
- if (cam->udev) {
- status = __send_control_msg(cam, request, value,
- index, cp, size);
- }
- mutex_unlock(&cam->cam_lock);
- return status;
-}
-static int
-initialize_camera(struct vicam_camera *cam)
-{
- int err;
- const struct ihex_binrec *rec;
- const struct firmware *uninitialized_var(fw);
-
- err = request_ihex_firmware(&fw, "vicam/firmware.fw", &cam->udev->dev);
- if (err) {
- printk(KERN_ERR "Failed to load \"vicam/firmware.fw\": %d\n",
- err);
- return err;
- }
-
- for (rec = (void *)fw->data; rec; rec = ihex_next_binrec(rec)) {
- memcpy(cam->cntrlbuf, rec->data, be16_to_cpu(rec->len));
-
- err = send_control_msg(cam, 0xff, 0, 0,
- cam->cntrlbuf, be16_to_cpu(rec->len));
- if (err)
- break;
- }
-
- release_firmware(fw);
-
- return err;
-}
-
-static int
-set_camera_power(struct vicam_camera *cam, int state)
-{
- int status;
-
- if ((status = send_control_msg(cam, 0x50, state, 0, NULL, 0)) < 0)
- return status;
-
- if (state) {
- send_control_msg(cam, 0x55, 1, 0, NULL, 0);
- }
-
- return 0;
-}
-
-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;
- long retval = 0;
-
- if (!cam)
- return -ENODEV;
-
- switch (ioctlnr) {
- /* query capabilities */
- case VIDIOCGCAP:
- {
- struct video_capability b;
-
- DBG("VIDIOCGCAP\n");
- memset(&b, 0, sizeof(b));
- strcpy(b.name, "ViCam-based Camera");
- b.type = VID_TYPE_CAPTURE;
- b.channels = 1;
- b.audios = 0;
- b.maxwidth = 320; /* VIDEOSIZE_CIF */
- b.maxheight = 240;
- b.minwidth = 320; /* VIDEOSIZE_48_48 */
- b.minheight = 240;
-
- if (copy_to_user(user_arg, &b, sizeof(b)))
- retval = -EFAULT;
-
- break;
- }
- /* get/set video source - we are a camera and nothing else */
- case VIDIOCGCHAN:
- {
- struct video_channel v;
-
- DBG("VIDIOCGCHAN\n");
- if (copy_from_user(&v, user_arg, sizeof(v))) {
- retval = -EFAULT;
- break;
- }
- if (v.channel != 0) {
- retval = -EINVAL;
- break;
- }
-
- v.channel = 0;
- strcpy(v.name, "Camera");
- v.tuners = 0;
- v.flags = 0;
- v.type = VIDEO_TYPE_CAMERA;
- v.norm = 0;
-
- if (copy_to_user(user_arg, &v, sizeof(v)))
- retval = -EFAULT;
- break;
- }
-
- case VIDIOCSCHAN:
- {
- int v;
-
- if (copy_from_user(&v, user_arg, sizeof(v)))
- retval = -EFAULT;
- DBG("VIDIOCSCHAN %d\n", v);
-
- if (retval == 0 && v != 0)
- retval = -EINVAL;
-
- break;
- }
-
- /* image properties */
- case VIDIOCGPICT:
- {
- struct video_picture vp;
- DBG("VIDIOCGPICT\n");
- memset(&vp, 0, sizeof (struct video_picture));
- vp.brightness = cam->gain << 8;
- vp.depth = 24;
- vp.palette = VIDEO_PALETTE_RGB24;
- if (copy_to_user(user_arg, &vp, sizeof (struct video_picture)))
- retval = -EFAULT;
- break;
- }
-
- case VIDIOCSPICT:
- {
- struct video_picture vp;
-
- if (copy_from_user(&vp, user_arg, sizeof(vp))) {
- retval = -EFAULT;
- break;
- }
-
- DBG("VIDIOCSPICT depth = %d, pal = %d\n", vp.depth,
- vp.palette);
-
- cam->gain = vp.brightness >> 8;
-
- if (vp.depth != 24
- || vp.palette != VIDEO_PALETTE_RGB24)
- retval = -EINVAL;
-
- break;
- }
-
- /* get/set capture window */
- case VIDIOCGWIN:
- {
- struct video_window vw;
- vw.x = 0;
- vw.y = 0;
- vw.width = 320;
- vw.height = 240;
- vw.chromakey = 0;
- vw.flags = 0;
- vw.clips = NULL;
- vw.clipcount = 0;
-
- DBG("VIDIOCGWIN\n");
-
- if (copy_to_user(user_arg, (void *)&vw, sizeof(vw)))
- retval = -EFAULT;
-
- // I'm not sure what the deal with a capture window is, it is very poorly described
- // in the doc. So I won't support it now.
- break;
- }
-
- case VIDIOCSWIN:
- {
-
- struct video_window vw;
-
- if (copy_from_user(&vw, user_arg, sizeof(vw))) {
- retval = -EFAULT;
- break;
- }
-
- DBG("VIDIOCSWIN %d x %d\n", vw.width, vw.height);
-
- if ( vw.width != 320 || vw.height != 240 )
- retval = -EFAULT;
-
- break;
- }
-
- /* mmap interface */
- case VIDIOCGMBUF:
- {
- struct video_mbuf vm;
- int i;
-
- DBG("VIDIOCGMBUF\n");
- memset(&vm, 0, sizeof (vm));
- vm.size =
- VICAM_MAX_FRAME_SIZE * VICAM_FRAMES;
- vm.frames = VICAM_FRAMES;
- for (i = 0; i < VICAM_FRAMES; i++)
- vm.offsets[i] = VICAM_MAX_FRAME_SIZE * i;
-
- if (copy_to_user(user_arg, (void *)&vm, sizeof(vm)))
- retval = -EFAULT;
-
- break;
- }
-
- case VIDIOCMCAPTURE:
- {
- struct video_mmap vm;
- // int video_size;
-
- if (copy_from_user((void *)&vm, user_arg, sizeof(vm))) {
- retval = -EFAULT;
- break;
- }
-
- DBG("VIDIOCMCAPTURE frame=%d, height=%d, width=%d, format=%d.\n",vm.frame,vm.width,vm.height,vm.format);
-
- if ( vm.frame >= VICAM_FRAMES || vm.format != VIDEO_PALETTE_RGB24 )
- retval = -EINVAL;
-
- // in theory right here we'd start the image capturing
- // (fill in a bulk urb and submit it asynchronously)
- //
- // Instead we're going to do a total hack job for now and
- // retrieve the frame in VIDIOCSYNC
-
- break;
- }
-
- case VIDIOCSYNC:
- {
- int frame;
-
- if (copy_from_user((void *)&frame, user_arg, sizeof(int))) {
- retval = -EFAULT;
- break;
- }
- DBG("VIDIOCSYNC: %d\n", frame);
-
- read_frame(cam, frame);
- vicam_decode_color(cam->raw_image,
- cam->framebuf +
- frame * VICAM_MAX_FRAME_SIZE );
-
- break;
- }
-
- /* pointless to implement overlay with this camera */
- case VIDIOCCAPTURE:
- case VIDIOCGFBUF:
- case VIDIOCSFBUF:
- case VIDIOCKEY:
- retval = -EINVAL;
- break;
-
- /* tuner interface - we have none */
- case VIDIOCGTUNER:
- case VIDIOCSTUNER:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- retval = -EINVAL;
- break;
-
- /* audio interface - we have none */
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- retval = -EINVAL;
- break;
- default:
- retval = -ENOIOCTLCMD;
- break;
- }
-
- return retval;
-}
-
-static int
-vicam_open(struct file *file)
-{
- struct vicam_camera *cam = video_drvdata(file);
-
- DBG("open\n");
-
- if (!cam) {
- printk(KERN_ERR
- "vicam video_device improperly initialized");
- return -EINVAL;
- }
-
- /* the videodev_lock held above us protects us from
- * simultaneous opens...for now. we probably shouldn't
- * rely on this fact forever.
- */
-
- lock_kernel();
- if (cam->open_count > 0) {
- printk(KERN_INFO
- "vicam_open called on already opened camera");
- unlock_kernel();
- return -EBUSY;
- }
-
- cam->raw_image = kmalloc(VICAM_MAX_READ_SIZE, GFP_KERNEL);
- if (!cam->raw_image) {
- unlock_kernel();
- return -ENOMEM;
- }
-
- cam->framebuf = rvmalloc(VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
- if (!cam->framebuf) {
- kfree(cam->raw_image);
- unlock_kernel();
- return -ENOMEM;
- }
-
- cam->cntrlbuf = kmalloc(PAGE_SIZE, GFP_KERNEL);
- if (!cam->cntrlbuf) {
- kfree(cam->raw_image);
- rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
- unlock_kernel();
- return -ENOMEM;
- }
-
- // First upload firmware, then turn the camera on
-
- if (!cam->is_initialized) {
- initialize_camera(cam);
-
- cam->is_initialized = 1;
- }
-
- set_camera_power(cam, 1);
-
- cam->needsDummyRead = 1;
- cam->open_count++;
-
- file->private_data = cam;
- unlock_kernel();
-
- return 0;
-}
-
-static int
-vicam_close(struct file *file)
-{
- struct vicam_camera *cam = file->private_data;
- int open_count;
- struct usb_device *udev;
-
- DBG("close\n");
-
- /* it's not the end of the world if
- * we fail to turn the camera off.
- */
-
- set_camera_power(cam, 0);
-
- kfree(cam->raw_image);
- rvfree(cam->framebuf, VICAM_MAX_FRAME_SIZE * VICAM_FRAMES);
- kfree(cam->cntrlbuf);
-
- mutex_lock(&cam->cam_lock);
-
- cam->open_count--;
- open_count = cam->open_count;
- udev = cam->udev;
-
- mutex_unlock(&cam->cam_lock);
-
- if (!open_count && !udev) {
- kfree(cam);
- }
-
- return 0;
-}
-
-static void vicam_decode_color(const u8 *data, u8 *rgb)
-{
- /* vicam_decode_color - Convert from Vicam Y-Cr-Cb to RGB
- * Copyright (C) 2002 Monroe Williams (monroe@pobox.com)
- */
-
- int i, prevY, nextY;
-
- prevY = 512;
- nextY = 512;
-
- data += VICAM_HEADER_SIZE;
-
- for( i = 0; i < 240; i++, data += 512 ) {
- const int y = ( i * 242 ) / 240;
-
- int j, prevX, nextX;
- int Y, Cr, Cb;
-
- if ( y == 242 - 1 ) {
- nextY = -512;
- }
-
- prevX = 1;
- nextX = 1;
-
- for ( j = 0; j < 320; j++, rgb += 3 ) {
- const int x = ( j * 512 ) / 320;
- const u8 * const src = &data[x];
-
- if ( x == 512 - 1 ) {
- nextX = -1;
- }
-
- Cr = ( src[prevX] - src[0] ) +
- ( src[nextX] - src[0] );
- Cr /= 2;
-
- Cb = ( src[prevY] - src[prevX + prevY] ) +
- ( src[prevY] - src[nextX + prevY] ) +
- ( src[nextY] - src[prevX + nextY] ) +
- ( src[nextY] - src[nextX + nextY] );
- Cb /= 4;
-
- Y = 1160 * ( src[0] + ( Cr / 2 ) - 16 );
-
- if ( i & 1 ) {
- int Ct = Cr;
- Cr = Cb;
- Cb = Ct;
- }
-
- if ( ( x ^ i ) & 1 ) {
- Cr = -Cr;
- Cb = -Cb;
- }
-
- rgb[0] = clamp( ( ( Y + ( 2017 * Cb ) ) +
- 500 ) / 900, 0, 255 );
- rgb[1] = clamp( ( ( Y - ( 392 * Cb ) -
- ( 813 * Cr ) ) +
- 500 ) / 1000, 0, 255 );
- rgb[2] = clamp( ( ( Y + ( 1594 * Cr ) ) +
- 500 ) / 1300, 0, 255 );
-
- prevX = -1;
- }
-
- prevY = -512;
- }
-}
-
-static void
-read_frame(struct vicam_camera *cam, int framenum)
-{
- unsigned char *request = cam->cntrlbuf;
- int realShutter;
- int n;
- int actual_length;
-
- if (cam->needsDummyRead) {
- cam->needsDummyRead = 0;
- read_frame(cam, framenum);
- }
-
- memset(request, 0, 16);
- request[0] = cam->gain; // 0 = 0% gain, FF = 100% gain
-
- request[1] = 0; // 512x242 capture
-
- request[2] = 0x90; // the function of these two bytes
- request[3] = 0x07; // is not yet understood
-
- if (cam->shutter_speed > 60) {
- // Short exposure
- realShutter =
- ((-15631900 / cam->shutter_speed) + 260533) / 1000;
- request[4] = realShutter & 0xFF;
- request[5] = (realShutter >> 8) & 0xFF;
- request[6] = 0x03;
- request[7] = 0x01;
- } else {
- // Long exposure
- realShutter = 15600 / cam->shutter_speed - 1;
- request[4] = 0;
- request[5] = 0;
- request[6] = realShutter & 0xFF;
- request[7] = realShutter >> 8;
- }
-
- // Per John Markus Bjørndalen, byte at index 8 causes problems if it isn't 0
- request[8] = 0;
- // bytes 9-15 do not seem to affect exposure or image quality
-
- mutex_lock(&cam->cam_lock);
-
- if (!cam->udev) {
- goto done;
- }
-
- n = __send_control_msg(cam, 0x51, 0x80, 0, request, 16);
-
- if (n < 0) {
- printk(KERN_ERR
- " Problem sending frame capture control message");
- goto done;
- }
-
- n = usb_bulk_msg(cam->udev,
- usb_rcvbulkpipe(cam->udev, cam->bulkEndpoint),
- cam->raw_image,
- 512 * 242 + 128, &actual_length, 10000);
-
- if (n < 0) {
- printk(KERN_ERR "Problem during bulk read of frame data: %d\n",
- n);
- }
-
- done:
- mutex_unlock(&cam->cam_lock);
-}
-
-static ssize_t
-vicam_read( struct file *file, char __user *buf, size_t count, loff_t *ppos )
-{
- struct vicam_camera *cam = file->private_data;
-
- DBG("read %d bytes.\n", (int) count);
-
- if (*ppos >= VICAM_MAX_FRAME_SIZE) {
- *ppos = 0;
- return 0;
- }
-
- if (*ppos == 0) {
- read_frame(cam, 0);
- vicam_decode_color(cam->raw_image,
- cam->framebuf +
- 0 * VICAM_MAX_FRAME_SIZE);
- }
-
- count = min_t(size_t, count, VICAM_MAX_FRAME_SIZE - *ppos);
-
- if (copy_to_user(buf, &cam->framebuf[*ppos], count)) {
- count = -EFAULT;
- } else {
- *ppos += count;
- }
-
- if (count == VICAM_MAX_FRAME_SIZE) {
- *ppos = 0;
- }
-
- return count;
-}
-
-
-static int
-vicam_mmap(struct file *file, struct vm_area_struct *vma)
-{
- // TODO: allocate the raw frame buffer if necessary
- unsigned long page, pos;
- unsigned long start = vma->vm_start;
- unsigned long size = vma->vm_end-vma->vm_start;
- struct vicam_camera *cam = file->private_data;
-
- if (!cam)
- return -ENODEV;
-
- DBG("vicam_mmap: %ld\n", size);
-
- /* We let mmap allocate as much as it wants because Linux was adding 2048 bytes
- * to the size the application requested for mmap and it was screwing apps up.
- if (size > VICAM_FRAMES*VICAM_MAX_FRAME_SIZE)
- return -EINVAL;
- */
-
- pos = (unsigned long)cam->framebuf;
- while (size > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page, PAGE_SIZE, PAGE_SHARED))
- return -EAGAIN;
-
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- if (size > PAGE_SIZE)
- size -= PAGE_SIZE;
- else
- size = 0;
- }
-
- return 0;
-}
-
-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,
-};
-
-static struct video_device vicam_template = {
- .name = "ViCam-based USB Camera",
- .fops = &vicam_fops,
- .release = video_device_release_empty,
-};
-
-/* table of devices that work with this driver */
-static struct usb_device_id vicam_table[] = {
- {USB_DEVICE(USB_VICAM_VENDOR_ID, USB_VICAM_PRODUCT_ID)},
- {USB_DEVICE(USB_COMPRO_VENDOR_ID, USB_COMPRO_PRODUCT_ID)},
- {} /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE(usb, vicam_table);
-
-static struct usb_driver vicam_driver = {
- .name = "vicam",
- .probe = vicam_probe,
- .disconnect = vicam_disconnect,
- .id_table = vicam_table
-};
-
-/**
- * vicam_probe
- * @intf: the interface
- * @id: the device id
- *
- * Called by the usb core when a new device is connected that it thinks
- * this driver might be interested in.
- */
-static int
-vicam_probe( struct usb_interface *intf, const struct usb_device_id *id)
-{
- struct usb_device *dev = interface_to_usbdev(intf);
- int bulkEndpoint = 0;
- const struct usb_host_interface *interface;
- const struct usb_endpoint_descriptor *endpoint;
- struct vicam_camera *cam;
-
- printk(KERN_INFO "ViCam based webcam connected\n");
-
- interface = intf->cur_altsetting;
-
- DBG(KERN_DEBUG "Interface %d. has %u. endpoints!\n",
- interface->desc.bInterfaceNumber, (unsigned) (interface->desc.bNumEndpoints));
- endpoint = &interface->endpoint[0].desc;
-
- if (usb_endpoint_is_bulk_in(endpoint)) {
- /* we found a bulk in endpoint */
- bulkEndpoint = endpoint->bEndpointAddress;
- } else {
- printk(KERN_ERR
- "No bulk in endpoint was found ?! (this is bad)\n");
- }
-
- if ((cam =
- kzalloc(sizeof (struct vicam_camera), GFP_KERNEL)) == NULL) {
- printk(KERN_WARNING
- "could not allocate kernel memory for vicam_camera struct\n");
- return -ENOMEM;
- }
-
-
- cam->shutter_speed = 15;
-
- mutex_init(&cam->cam_lock);
-
- memcpy(&cam->vdev, &vicam_template, sizeof(vicam_template));
- video_set_drvdata(&cam->vdev, cam);
-
- cam->udev = dev;
- cam->bulkEndpoint = bulkEndpoint;
-
- if (video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1) < 0) {
- kfree(cam);
- printk(KERN_WARNING "video_register_device failed\n");
- return -EIO;
- }
-
- printk(KERN_INFO "ViCam webcam driver now controlling device %s\n",
- video_device_node_name(&cam->vdev));
-
- usb_set_intfdata (intf, cam);
-
- return 0;
-}
-
-static void
-vicam_disconnect(struct usb_interface *intf)
-{
- int open_count;
- struct vicam_camera *cam = usb_get_intfdata (intf);
- usb_set_intfdata (intf, NULL);
-
- /* we must unregister the device before taking its
- * cam_lock. This is because the video open call
- * holds the same lock as video unregister. if we
- * unregister inside of the cam_lock and open also
- * uses the cam_lock, we get deadlock.
- */
-
- video_unregister_device(&cam->vdev);
-
- /* stop the camera from being used */
-
- mutex_lock(&cam->cam_lock);
-
- /* mark the camera as gone */
-
- cam->udev = NULL;
-
- /* the only thing left to do is synchronize with
- * our close/release function on who should release
- * the camera memory. if there are any users using the
- * camera, it's their job. if there are no users,
- * it's ours.
- */
-
- open_count = cam->open_count;
-
- mutex_unlock(&cam->cam_lock);
-
- if (!open_count) {
- kfree(cam);
- }
-
- printk(KERN_DEBUG "ViCam-based WebCam disconnected\n");
-}
-
-/*
- */
-static int __init
-usb_vicam_init(void)
-{
- int retval;
- DBG(KERN_INFO "ViCam-based WebCam driver startup\n");
- retval = usb_register(&vicam_driver);
- if (retval)
- printk(KERN_WARNING "usb_register failed!\n");
- return retval;
-}
-
-static void __exit
-usb_vicam_exit(void)
-{
- DBG(KERN_INFO
- "ViCam-based WebCam driver shutdown\n");
-
- usb_deregister(&vicam_driver);
-}
-
-module_init(usb_vicam_init);
-module_exit(usb_vicam_exit);
-
-MODULE_AUTHOR(DRIVER_AUTHOR);
-MODULE_DESCRIPTION(DRIVER_DESC);
-MODULE_LICENSE("GPL");
-MODULE_FIRMWARE("vicam/firmware.fw");
diff --git a/drivers/media/video/usbvision/usbvision-cards.c b/drivers/media/video/usbvision/usbvision-cards.c
index 503b13beb922..68b998bd203f 100644
--- a/drivers/media/video/usbvision/usbvision-cards.c
+++ b/drivers/media/video/usbvision/usbvision-cards.c
@@ -32,1072 +32,1072 @@
/* Supported Devices: A table for usbvision.c*/
struct usbvision_device_data_st usbvision_device_data[] = {
[XANBOO] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 4,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Xanboo",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 4,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Xanboo",
},
[BELKIN_VIDEOBUS_II] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Belkin USB VideoBus II Adapter",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Belkin USB VideoBus II Adapter",
},
[BELKIN_VIDEOBUS] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Belkin Components USB VideoBus",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Belkin Components USB VideoBus",
},
[BELKIN_USB_VIDEOBUS_II] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Belkin USB VideoBus II",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Belkin USB VideoBus II",
},
[ECHOFX_INTERVIEW_LITE] = {
- .Interface = 0,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "echoFX InterView Lite",
+ .interface = 0,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "echoFX InterView Lite",
},
[USBGEAR_USBG_V1] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "USBGear USBG-V1 resp. HAMA USB",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "USBGear USBG-V1 resp. HAMA USB",
},
[D_LINK_V100] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 4,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "D-Link V100",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 4,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "D-Link V100",
},
[X10_USB_CAMERA] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "X10 USB Camera",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "X10 USB Camera",
},
[HPG_WINTV_LIVE_PAL_BG] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = -1,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Live (PAL B/G)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = -1,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Live (PAL B/G)",
},
[HPG_WINTV_LIVE_PRO_NTSC_MN] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Live Pro (NTSC M/N)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Live Pro (NTSC M/N)",
},
[ZORAN_PMD_NOGATECH] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 2,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 2,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Zoran Co. PMD (Nogatech) AV-grabber Manhattan",
},
[NOGATECH_USB_TV_NTSC_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = 20,
- .ModelString = "Nogatech USB-TV (NTSC) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = 20,
+ .model_string = "Nogatech USB-TV (NTSC) FM",
},
[PNY_USB_TV_NTSC_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = 20,
- .ModelString = "PNY USB-TV (NTSC) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = 20,
+ .model_string = "PNY USB-TV (NTSC) FM",
},
[PV_PLAYTV_USB_PRO_PAL_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "PixelView PlayTv-USB PRO (PAL) FM",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "PixelView PlayTv-USB PRO (PAL) FM",
},
[ZT_721] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "ZTV ZT-721 2.4GHz USB A/V Receiver",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "ZTV ZT-721 2.4GHz USB A/V Receiver",
},
[HPG_WINTV_NTSC_MN] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = 20,
- .ModelString = "Hauppauge WinTV USB (NTSC M/N)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = 20,
+ .model_string = "Hauppauge WinTV USB (NTSC M/N)",
},
[HPG_WINTV_PAL_BG] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL B/G)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL B/G)",
},
[HPG_WINTV_PAL_I] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL I)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL I)",
},
[HPG_WINTV_PAL_SECAM_L] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = 0x80,
- .Y_Offset = 0x16,
- .ModelString = "Hauppauge WinTV USB (PAL/SECAM L)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = 0x80,
+ .y_offset = 0x16,
+ .model_string = "Hauppauge WinTV USB (PAL/SECAM L)",
},
[HPG_WINTV_PAL_D_K] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL D/K)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL D/K)",
},
[HPG_WINTV_NTSC_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (NTSC FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (NTSC FM)",
},
[HPG_WINTV_PAL_BG_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL B/G FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL B/G FM)",
},
[HPG_WINTV_PAL_I_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL I FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL I FM)",
},
[HPG_WINTV_PAL_D_K_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTV USB (PAL D/K FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTV USB (PAL D/K FM)",
},
[HPG_WINTV_PRO_NTSC_MN] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_MICROTUNE_4049FM5,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_MICROTUNE_4049FM5,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N)",
},
[HPG_WINTV_PRO_NTSC_MN_V2] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_MICROTUNE_4049FM5,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V2",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_MICROTUNE_4049FM5,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N) V2",
},
[HPG_WINTV_PRO_PAL] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_FM1216ME_MK3,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L)",
},
[HPG_WINTV_PRO_NTSC_MN_V3] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N) V3",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N) V3",
},
[HPG_WINTV_PRO_PAL_BG] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL B/G)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL B/G)",
},
[HPG_WINTV_PRO_PAL_I] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL I)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL I)",
},
[HPG_WINTV_PRO_PAL_SECAM_L] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM L)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM L)",
},
[HPG_WINTV_PRO_PAL_D_K] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL D/K)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL D/K)",
},
[HPG_WINTV_PRO_PAL_SECAM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L)",
},
[HPG_WINTV_PRO_PAL_SECAM_V2] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM BGDK/I/L) V2",
},
[HPG_WINTV_PRO_PAL_BG_V2] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_ALPS_TSBE1_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL B/G) V2",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_ALPS_TSBE1_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL B/G) V2",
},
[HPG_WINTV_PRO_PAL_BG_D_K] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_ALPS_TSBE1_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL B/G,D/K)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_ALPS_TSBE1_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL B/G,D/K)",
},
[HPG_WINTV_PRO_PAL_I_D_K] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_LG_PAL_NEW_TAPC,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL I,D/K)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_LG_PAL_NEW_TAPC,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL I,D/K)",
},
[HPG_WINTV_PRO_NTSC_MN_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N FM)",
},
[HPG_WINTV_PRO_PAL_BG_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL B/G FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL B/G FM)",
},
[HPG_WINTV_PRO_PAL_I_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL I FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL I FM)",
},
[HPG_WINTV_PRO_PAL_D_K_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL D/K FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL D/K FM)",
},
[HPG_WINTV_PRO_TEMIC_PAL_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_MICROTUNE_4049FM5,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_MICROTUNE_4049FM5,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (Temic PAL/SECAM B/G/I/D/K/L FM)",
},
[HPG_WINTV_PRO_TEMIC_PAL_BG_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_MICROTUNE_4049FM5,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_MICROTUNE_4049FM5,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (Temic PAL B/G FM)",
},
[HPG_WINTV_PRO_PAL_FM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_FM1216ME_MK3,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (PAL/SECAM B/G/I/D/K/L FM)",
},
[HPG_WINTV_PRO_NTSC_MN_FM_V2] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Hauppauge WinTV USB Pro (NTSC M/N FM) V2",
},
[CAMTEL_TVB330] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = 5,
- .Y_Offset = 5,
- .ModelString = "Camtel Technology USB TV Genie Pro FM Model TVB330",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = 5,
+ .y_offset = 5,
+ .model_string = "Camtel Technology USB TV Genie Pro FM Model TVB330",
},
[DIGITAL_VIDEO_CREATOR_I] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Digital Video Creator I",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Digital Video Creator I",
},
[GLOBAL_VILLAGE_GV_007_NTSC] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 82,
- .Y_Offset = 20,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Global Village GV-007 (NTSC)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 82,
+ .y_offset = 20,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Global Village GV-007 (NTSC)",
},
[DAZZLE_DVC_50_REV_1_NTSC] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Dazzle Fusion Model DVC-50 Rev 1 (NTSC)",
},
[DAZZLE_DVC_80_REV_1_PAL] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Dazzle Fusion Model DVC-80 Rev 1 (PAL)",
},
[DAZZLE_DVC_90_REV_1_SECAM] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 0,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 0,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Dazzle Fusion Model DVC-90 Rev 1 (SECAM)",
},
[ESKAPE_LABS_MYTV2GO] = {
- .Interface = 0,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_FM1216ME_MK3,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Eskape Labs MyTV2Go",
+ .interface = 0,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Eskape Labs MyTV2Go",
},
[PINNA_PCTV_USB_PAL] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 0,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4066FY5_PAL_I,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Pinnacle Studio PCTV USB (PAL)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 0,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4066FY5_PAL_I,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Pinnacle Studio PCTV USB (PAL)",
},
[PINNA_PCTV_USB_SECAM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_SECAM,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_SECAM,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Pinnacle Studio PCTV USB (SECAM)",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_SECAM,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_SECAM,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Pinnacle Studio PCTV USB (SECAM)",
},
[PINNA_PCTV_USB_PAL_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = 128,
- .Y_Offset = 23,
- .ModelString = "Pinnacle Studio PCTV USB (PAL) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = 128,
+ .y_offset = 23,
+ .model_string = "Pinnacle Studio PCTV USB (PAL) FM",
},
[MIRO_PCTV_USB] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_PAL,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Miro PCTV USB",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_PAL,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Miro PCTV USB",
},
[PINNA_PCTV_USB_NTSC_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Pinnacle Studio PCTV USB (NTSC) FM",
},
[PINNA_PCTV_USB_NTSC_FM_V3] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V3",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Pinnacle Studio PCTV USB (NTSC) FM V3",
},
[PINNA_PCTV_USB_PAL_FM_V2] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4009FR5_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V2",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4009FR5_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio PCTV USB (PAL) FM V2",
},
[PINNA_PCTV_USB_NTSC_FM_V2] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4039FR5_NTSC,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio PCTV USB (NTSC) FM V2",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4039FR5_NTSC,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio PCTV USB (NTSC) FM V2",
},
[PINNA_PCTV_USB_PAL_FM_V3] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4009FR5_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio PCTV USB (PAL) FM V3",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4009FR5_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio PCTV USB (PAL) FM V3",
},
[PINNA_LINX_VD_IN_CAB_NTSC] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio Linx Video input cable (NTSC)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio Linx Video input cable (NTSC)",
},
[PINNA_LINX_VD_IN_CAB_PAL] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 2,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 0,
- .TunerType = 0,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle Studio Linx Video input cable (PAL)",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 2,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 0,
+ .tuner_type = 0,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle Studio Linx Video input cable (PAL)",
},
[PINNA_PCTV_BUNGEE_PAL_FM] = {
- .Interface = -1,
- .Codec = CODEC_SAA7113,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_PAL,
- .AudioChannels = 1,
- .Radio = 1,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_TEMIC_4009FR5_PAL,
- .X_Offset = 0,
- .Y_Offset = 3,
- .Dvi_yuv_override = 1,
- .Dvi_yuv = 7,
- .ModelString = "Pinnacle PCTV Bungee USB (PAL) FM",
+ .interface = -1,
+ .codec = CODEC_SAA7113,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_PAL,
+ .audio_channels = 1,
+ .radio = 1,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_TEMIC_4009FR5_PAL,
+ .x_offset = 0,
+ .y_offset = 3,
+ .dvi_yuv_override = 1,
+ .dvi_yuv = 7,
+ .model_string = "Pinnacle PCTV Bungee USB (PAL) FM",
},
[HPG_WINTV] = {
- .Interface = -1,
- .Codec = CODEC_SAA7111,
- .VideoChannels = 3,
- .VideoNorm = V4L2_STD_NTSC,
- .AudioChannels = 1,
- .Radio = 0,
- .vbi = 1,
- .Tuner = 1,
- .TunerType = TUNER_PHILIPS_NTSC_M,
- .X_Offset = -1,
- .Y_Offset = -1,
- .ModelString = "Hauppauge WinTv-USB",
+ .interface = -1,
+ .codec = CODEC_SAA7111,
+ .video_channels = 3,
+ .video_norm = V4L2_STD_NTSC,
+ .audio_channels = 1,
+ .radio = 0,
+ .vbi = 1,
+ .tuner = 1,
+ .tuner_type = TUNER_PHILIPS_NTSC_M,
+ .x_offset = -1,
+ .y_offset = -1,
+ .model_string = "Hauppauge WinTv-USB",
},
};
-const int usbvision_device_data_size=ARRAY_SIZE(usbvision_device_data);
+const int usbvision_device_data_size = ARRAY_SIZE(usbvision_device_data);
/* Supported Devices */
-struct usb_device_id usbvision_table [] = {
- { USB_DEVICE(0x0a6f, 0x0400), .driver_info=XANBOO },
- { USB_DEVICE(0x050d, 0x0106), .driver_info=BELKIN_VIDEOBUS_II },
- { USB_DEVICE(0x050d, 0x0207), .driver_info=BELKIN_VIDEOBUS },
- { USB_DEVICE(0x050d, 0x0208), .driver_info=BELKIN_USB_VIDEOBUS_II },
- { USB_DEVICE(0x0571, 0x0002), .driver_info=ECHOFX_INTERVIEW_LITE },
- { USB_DEVICE(0x0573, 0x0003), .driver_info=USBGEAR_USBG_V1 },
- { USB_DEVICE(0x0573, 0x0400), .driver_info=D_LINK_V100 },
- { USB_DEVICE(0x0573, 0x2000), .driver_info=X10_USB_CAMERA },
- { USB_DEVICE(0x0573, 0x2d00), .driver_info=HPG_WINTV_LIVE_PAL_BG },
- { USB_DEVICE(0x0573, 0x2d01), .driver_info=HPG_WINTV_LIVE_PRO_NTSC_MN },
- { USB_DEVICE(0x0573, 0x2101), .driver_info=ZORAN_PMD_NOGATECH },
- { USB_DEVICE(0x0573, 0x4100), .driver_info=NOGATECH_USB_TV_NTSC_FM },
- { USB_DEVICE(0x0573, 0x4110), .driver_info=PNY_USB_TV_NTSC_FM },
- { USB_DEVICE(0x0573, 0x4450), .driver_info=PV_PLAYTV_USB_PRO_PAL_FM },
- { USB_DEVICE(0x0573, 0x4550), .driver_info=ZT_721 },
- { USB_DEVICE(0x0573, 0x4d00), .driver_info=HPG_WINTV_NTSC_MN },
- { USB_DEVICE(0x0573, 0x4d01), .driver_info=HPG_WINTV_PAL_BG },
- { USB_DEVICE(0x0573, 0x4d02), .driver_info=HPG_WINTV_PAL_I },
- { USB_DEVICE(0x0573, 0x4d03), .driver_info=HPG_WINTV_PAL_SECAM_L },
- { USB_DEVICE(0x0573, 0x4d04), .driver_info=HPG_WINTV_PAL_D_K },
- { USB_DEVICE(0x0573, 0x4d10), .driver_info=HPG_WINTV_NTSC_FM },
- { USB_DEVICE(0x0573, 0x4d11), .driver_info=HPG_WINTV_PAL_BG_FM },
- { USB_DEVICE(0x0573, 0x4d12), .driver_info=HPG_WINTV_PAL_I_FM },
- { USB_DEVICE(0x0573, 0x4d14), .driver_info=HPG_WINTV_PAL_D_K_FM },
- { USB_DEVICE(0x0573, 0x4d2a), .driver_info=HPG_WINTV_PRO_NTSC_MN },
- { USB_DEVICE(0x0573, 0x4d2b), .driver_info=HPG_WINTV_PRO_NTSC_MN_V2 },
- { USB_DEVICE(0x0573, 0x4d2c), .driver_info=HPG_WINTV_PRO_PAL },
+struct usb_device_id usbvision_table[] = {
+ { USB_DEVICE(0x0a6f, 0x0400), .driver_info = XANBOO },
+ { USB_DEVICE(0x050d, 0x0106), .driver_info = BELKIN_VIDEOBUS_II },
+ { USB_DEVICE(0x050d, 0x0207), .driver_info = BELKIN_VIDEOBUS },
+ { USB_DEVICE(0x050d, 0x0208), .driver_info = BELKIN_USB_VIDEOBUS_II },
+ { USB_DEVICE(0x0571, 0x0002), .driver_info = ECHOFX_INTERVIEW_LITE },
+ { USB_DEVICE(0x0573, 0x0003), .driver_info = USBGEAR_USBG_V1 },
+ { USB_DEVICE(0x0573, 0x0400), .driver_info = D_LINK_V100 },
+ { USB_DEVICE(0x0573, 0x2000), .driver_info = X10_USB_CAMERA },
+ { USB_DEVICE(0x0573, 0x2d00), .driver_info = HPG_WINTV_LIVE_PAL_BG },
+ { USB_DEVICE(0x0573, 0x2d01), .driver_info = HPG_WINTV_LIVE_PRO_NTSC_MN },
+ { USB_DEVICE(0x0573, 0x2101), .driver_info = ZORAN_PMD_NOGATECH },
+ { USB_DEVICE(0x0573, 0x4100), .driver_info = NOGATECH_USB_TV_NTSC_FM },
+ { USB_DEVICE(0x0573, 0x4110), .driver_info = PNY_USB_TV_NTSC_FM },
+ { USB_DEVICE(0x0573, 0x4450), .driver_info = PV_PLAYTV_USB_PRO_PAL_FM },
+ { USB_DEVICE(0x0573, 0x4550), .driver_info = ZT_721 },
+ { USB_DEVICE(0x0573, 0x4d00), .driver_info = HPG_WINTV_NTSC_MN },
+ { USB_DEVICE(0x0573, 0x4d01), .driver_info = HPG_WINTV_PAL_BG },
+ { USB_DEVICE(0x0573, 0x4d02), .driver_info = HPG_WINTV_PAL_I },
+ { USB_DEVICE(0x0573, 0x4d03), .driver_info = HPG_WINTV_PAL_SECAM_L },
+ { USB_DEVICE(0x0573, 0x4d04), .driver_info = HPG_WINTV_PAL_D_K },
+ { USB_DEVICE(0x0573, 0x4d10), .driver_info = HPG_WINTV_NTSC_FM },
+ { USB_DEVICE(0x0573, 0x4d11), .driver_info = HPG_WINTV_PAL_BG_FM },
+ { USB_DEVICE(0x0573, 0x4d12), .driver_info = HPG_WINTV_PAL_I_FM },
+ { USB_DEVICE(0x0573, 0x4d14), .driver_info = HPG_WINTV_PAL_D_K_FM },
+ { USB_DEVICE(0x0573, 0x4d2a), .driver_info = HPG_WINTV_PRO_NTSC_MN },
+ { USB_DEVICE(0x0573, 0x4d2b), .driver_info = HPG_WINTV_PRO_NTSC_MN_V2 },
+ { USB_DEVICE(0x0573, 0x4d2c), .driver_info = HPG_WINTV_PRO_PAL },
{ USB_DEVICE(0x0573, 0x4d20), .driver_info = HPG_WINTV_PRO_NTSC_MN_V3 },
- { USB_DEVICE(0x0573, 0x4d21), .driver_info=HPG_WINTV_PRO_PAL_BG },
- { USB_DEVICE(0x0573, 0x4d22), .driver_info=HPG_WINTV_PRO_PAL_I },
- { USB_DEVICE(0x0573, 0x4d23), .driver_info=HPG_WINTV_PRO_PAL_SECAM_L },
- { USB_DEVICE(0x0573, 0x4d24), .driver_info=HPG_WINTV_PRO_PAL_D_K },
- { USB_DEVICE(0x0573, 0x4d25), .driver_info=HPG_WINTV_PRO_PAL_SECAM },
- { USB_DEVICE(0x0573, 0x4d26), .driver_info=HPG_WINTV_PRO_PAL_SECAM_V2 },
- { USB_DEVICE(0x0573, 0x4d27), .driver_info=HPG_WINTV_PRO_PAL_BG_V2 },
- { USB_DEVICE(0x0573, 0x4d28), .driver_info=HPG_WINTV_PRO_PAL_BG_D_K },
- { USB_DEVICE(0x0573, 0x4d29), .driver_info=HPG_WINTV_PRO_PAL_I_D_K },
- { USB_DEVICE(0x0573, 0x4d30), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM },
- { USB_DEVICE(0x0573, 0x4d31), .driver_info=HPG_WINTV_PRO_PAL_BG_FM },
- { USB_DEVICE(0x0573, 0x4d32), .driver_info=HPG_WINTV_PRO_PAL_I_FM },
- { USB_DEVICE(0x0573, 0x4d34), .driver_info=HPG_WINTV_PRO_PAL_D_K_FM },
- { USB_DEVICE(0x0573, 0x4d35), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_FM },
- { USB_DEVICE(0x0573, 0x4d36), .driver_info=HPG_WINTV_PRO_TEMIC_PAL_BG_FM },
- { USB_DEVICE(0x0573, 0x4d37), .driver_info=HPG_WINTV_PRO_PAL_FM },
- { USB_DEVICE(0x0573, 0x4d38), .driver_info=HPG_WINTV_PRO_NTSC_MN_FM_V2 },
- { USB_DEVICE(0x0768, 0x0006), .driver_info=CAMTEL_TVB330 },
- { USB_DEVICE(0x07d0, 0x0001), .driver_info=DIGITAL_VIDEO_CREATOR_I },
- { USB_DEVICE(0x07d0, 0x0002), .driver_info=GLOBAL_VILLAGE_GV_007_NTSC },
- { USB_DEVICE(0x07d0, 0x0003), .driver_info=DAZZLE_DVC_50_REV_1_NTSC },
- { USB_DEVICE(0x07d0, 0x0004), .driver_info=DAZZLE_DVC_80_REV_1_PAL },
- { USB_DEVICE(0x07d0, 0x0005), .driver_info=DAZZLE_DVC_90_REV_1_SECAM },
- { USB_DEVICE(0x07f8, 0x9104), .driver_info=ESKAPE_LABS_MYTV2GO },
- { USB_DEVICE(0x2304, 0x010d), .driver_info=PINNA_PCTV_USB_PAL },
- { USB_DEVICE(0x2304, 0x0109), .driver_info=PINNA_PCTV_USB_SECAM },
- { USB_DEVICE(0x2304, 0x0110), .driver_info=PINNA_PCTV_USB_PAL_FM },
- { USB_DEVICE(0x2304, 0x0111), .driver_info=MIRO_PCTV_USB },
- { USB_DEVICE(0x2304, 0x0112), .driver_info=PINNA_PCTV_USB_NTSC_FM },
+ { USB_DEVICE(0x0573, 0x4d21), .driver_info = HPG_WINTV_PRO_PAL_BG },
+ { USB_DEVICE(0x0573, 0x4d22), .driver_info = HPG_WINTV_PRO_PAL_I },
+ { USB_DEVICE(0x0573, 0x4d23), .driver_info = HPG_WINTV_PRO_PAL_SECAM_L },
+ { USB_DEVICE(0x0573, 0x4d24), .driver_info = HPG_WINTV_PRO_PAL_D_K },
+ { USB_DEVICE(0x0573, 0x4d25), .driver_info = HPG_WINTV_PRO_PAL_SECAM },
+ { USB_DEVICE(0x0573, 0x4d26), .driver_info = HPG_WINTV_PRO_PAL_SECAM_V2 },
+ { USB_DEVICE(0x0573, 0x4d27), .driver_info = HPG_WINTV_PRO_PAL_BG_V2 },
+ { USB_DEVICE(0x0573, 0x4d28), .driver_info = HPG_WINTV_PRO_PAL_BG_D_K },
+ { USB_DEVICE(0x0573, 0x4d29), .driver_info = HPG_WINTV_PRO_PAL_I_D_K },
+ { USB_DEVICE(0x0573, 0x4d30), .driver_info = HPG_WINTV_PRO_NTSC_MN_FM },
+ { USB_DEVICE(0x0573, 0x4d31), .driver_info = HPG_WINTV_PRO_PAL_BG_FM },
+ { USB_DEVICE(0x0573, 0x4d32), .driver_info = HPG_WINTV_PRO_PAL_I_FM },
+ { USB_DEVICE(0x0573, 0x4d34), .driver_info = HPG_WINTV_PRO_PAL_D_K_FM },
+ { USB_DEVICE(0x0573, 0x4d35), .driver_info = HPG_WINTV_PRO_TEMIC_PAL_FM },
+ { USB_DEVICE(0x0573, 0x4d36), .driver_info = HPG_WINTV_PRO_TEMIC_PAL_BG_FM },
+ { USB_DEVICE(0x0573, 0x4d37), .driver_info = HPG_WINTV_PRO_PAL_FM },
+ { USB_DEVICE(0x0573, 0x4d38), .driver_info = HPG_WINTV_PRO_NTSC_MN_FM_V2 },
+ { USB_DEVICE(0x0768, 0x0006), .driver_info = CAMTEL_TVB330 },
+ { USB_DEVICE(0x07d0, 0x0001), .driver_info = DIGITAL_VIDEO_CREATOR_I },
+ { USB_DEVICE(0x07d0, 0x0002), .driver_info = GLOBAL_VILLAGE_GV_007_NTSC },
+ { USB_DEVICE(0x07d0, 0x0003), .driver_info = DAZZLE_DVC_50_REV_1_NTSC },
+ { USB_DEVICE(0x07d0, 0x0004), .driver_info = DAZZLE_DVC_80_REV_1_PAL },
+ { USB_DEVICE(0x07d0, 0x0005), .driver_info = DAZZLE_DVC_90_REV_1_SECAM },
+ { USB_DEVICE(0x07f8, 0x9104), .driver_info = ESKAPE_LABS_MYTV2GO },
+ { USB_DEVICE(0x2304, 0x010d), .driver_info = PINNA_PCTV_USB_PAL },
+ { USB_DEVICE(0x2304, 0x0109), .driver_info = PINNA_PCTV_USB_SECAM },
+ { USB_DEVICE(0x2304, 0x0110), .driver_info = PINNA_PCTV_USB_PAL_FM },
+ { USB_DEVICE(0x2304, 0x0111), .driver_info = MIRO_PCTV_USB },
+ { USB_DEVICE(0x2304, 0x0112), .driver_info = PINNA_PCTV_USB_NTSC_FM },
{ USB_DEVICE(0x2304, 0x0113),
.driver_info = PINNA_PCTV_USB_NTSC_FM_V3 },
- { USB_DEVICE(0x2304, 0x0210), .driver_info=PINNA_PCTV_USB_PAL_FM_V2 },
- { USB_DEVICE(0x2304, 0x0212), .driver_info=PINNA_PCTV_USB_NTSC_FM_V2 },
- { USB_DEVICE(0x2304, 0x0214), .driver_info=PINNA_PCTV_USB_PAL_FM_V3 },
- { USB_DEVICE(0x2304, 0x0300), .driver_info=PINNA_LINX_VD_IN_CAB_NTSC },
- { USB_DEVICE(0x2304, 0x0301), .driver_info=PINNA_LINX_VD_IN_CAB_PAL },
- { USB_DEVICE(0x2304, 0x0419), .driver_info=PINNA_PCTV_BUNGEE_PAL_FM },
- { USB_DEVICE(0x2400, 0x4200), .driver_info=HPG_WINTV },
+ { USB_DEVICE(0x2304, 0x0210), .driver_info = PINNA_PCTV_USB_PAL_FM_V2 },
+ { USB_DEVICE(0x2304, 0x0212), .driver_info = PINNA_PCTV_USB_NTSC_FM_V2 },
+ { USB_DEVICE(0x2304, 0x0214), .driver_info = PINNA_PCTV_USB_PAL_FM_V3 },
+ { USB_DEVICE(0x2304, 0x0300), .driver_info = PINNA_LINX_VD_IN_CAB_NTSC },
+ { USB_DEVICE(0x2304, 0x0301), .driver_info = PINNA_LINX_VD_IN_CAB_PAL },
+ { USB_DEVICE(0x2304, 0x0419), .driver_info = PINNA_PCTV_BUNGEE_PAL_FM },
+ { USB_DEVICE(0x2400, 0x4200), .driver_info = HPG_WINTV },
{ }, /* terminate list */
};
-MODULE_DEVICE_TABLE (usb, usbvision_table);
+MODULE_DEVICE_TABLE(usb, usbvision_table);
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index b9dd74fde212..c8feb0d6fccf 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -33,7 +33,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
@@ -46,30 +46,30 @@
#include "usbvision.h"
static unsigned int core_debug;
-module_param(core_debug,int,0644);
-MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
+module_param(core_debug, int, 0644);
+MODULE_PARM_DESC(core_debug, "enable debug messages [core]");
static unsigned int force_testpattern;
-module_param(force_testpattern,int,0644);
-MODULE_PARM_DESC(force_testpattern,"enable test pattern display [core]");
+module_param(force_testpattern, int, 0644);
+MODULE_PARM_DESC(force_testpattern, "enable test pattern display [core]");
-static int adjustCompression = 1; /* Set the compression to be adaptive */
-module_param(adjustCompression, int, 0444);
-MODULE_PARM_DESC(adjustCompression, " Set the ADPCM compression for the device. Default: 1 (On)");
+static int adjust_compression = 1; /* Set the compression to be adaptive */
+module_param(adjust_compression, int, 0444);
+MODULE_PARM_DESC(adjust_compression, " Set the ADPCM compression for the device. Default: 1 (On)");
/* To help people with Black and White output with using s-video input.
* Some cables and input device are wired differently. */
-static int SwitchSVideoInput;
-module_param(SwitchSVideoInput, int, 0444);
-MODULE_PARM_DESC(SwitchSVideoInput, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)");
+static int switch_svideo_input;
+module_param(switch_svideo_input, int, 0444);
+MODULE_PARM_DESC(switch_svideo_input, " Set the S-Video input. Some cables and input device are wired differently. Default: 0 (Off)");
-static unsigned int adjust_X_Offset = -1;
-module_param(adjust_X_Offset, int, 0644);
-MODULE_PARM_DESC(adjust_X_Offset, "adjust X offset display [core]");
+static unsigned int adjust_x_offset = -1;
+module_param(adjust_x_offset, int, 0644);
+MODULE_PARM_DESC(adjust_x_offset, "adjust X offset display [core]");
-static unsigned int adjust_Y_Offset = -1;
-module_param(adjust_Y_Offset, int, 0644);
-MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
+static unsigned int adjust_y_offset = -1;
+module_param(adjust_y_offset, int, 0644);
+MODULE_PARM_DESC(adjust_y_offset, "adjust Y offset display [core]");
#define ENABLE_HEXDUMP 0 /* Enable if you need it */
@@ -82,15 +82,15 @@ MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
__func__, __LINE__ , ## args); \
}
#else
- #define PDEBUG(level, fmt, args...) do {} while(0)
+ #define PDEBUG(level, fmt, args...) do {} while (0)
#endif
-#define DBG_HEADER 1<<0
-#define DBG_IRQ 1<<1
-#define DBG_ISOC 1<<2
-#define DBG_PARSE 1<<3
-#define DBG_SCRATCH 1<<4
-#define DBG_FUNC 1<<5
+#define DBG_HEADER (1 << 0)
+#define DBG_IRQ (1 << 1)
+#define DBG_ISOC (1 << 2)
+#define DBG_PARSE (1 << 3)
+#define DBG_SCRATCH (1 << 4)
+#define DBG_FUNC (1 << 5)
static const int max_imgwidth = MAX_FRAME_WIDTH;
static const int max_imgheight = MAX_FRAME_HEIGHT;
@@ -103,14 +103,14 @@ static const int min_imgheight = MIN_FRAME_HEIGHT;
* to work with. This setting can be adjusted, but the default value
* should be OK for most desktop users.
*/
-#define DEFAULT_SCRATCH_BUF_SIZE (0x20000) // 128kB memory scratch buffer
+#define DEFAULT_SCRATCH_BUF_SIZE (0x20000) /* 128kB memory scratch buffer */
static const int scratch_buf_size = DEFAULT_SCRATCH_BUF_SIZE;
-// Function prototypes
-static int usbvision_request_intra (struct usb_usbvision *usbvision);
-static int usbvision_unrequest_intra (struct usb_usbvision *usbvision);
-static int usbvision_adjust_compression (struct usb_usbvision *usbvision);
-static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision);
+/* Function prototypes */
+static int usbvision_request_intra(struct usb_usbvision *usbvision);
+static int usbvision_unrequest_intra(struct usb_usbvision *usbvision);
+static int usbvision_adjust_compression(struct usb_usbvision *usbvision);
+static int usbvision_measure_bandwidth(struct usb_usbvision *usbvision);
/*******************************/
/* Memory management functions */
@@ -176,19 +176,19 @@ static void usbvision_hexdump(const unsigned char *data, int len)
k += sprintf(&tmp[k], "%02x ", data[i]);
}
if (k > 0)
- printk("%s\n", tmp);
+ printk(KERN_CONT "%s\n", tmp);
}
#endif
/********************************
* scratch ring buffer handling
********************************/
-static int scratch_len(struct usb_usbvision *usbvision) /*This returns the amount of data actually in the buffer */
+static int scratch_len(struct usb_usbvision *usbvision) /* This returns the amount of data actually in the buffer */
{
int len = usbvision->scratch_write_ptr - usbvision->scratch_read_ptr;
- if (len < 0) {
+
+ if (len < 0)
len += scratch_buf_size;
- }
PDEBUG(DBG_SCRATCH, "scratch_len() = %d\n", len);
return len;
@@ -199,9 +199,8 @@ static int scratch_len(struct usb_usbvision *usbvision) /*This returns the am
static int scratch_free(struct usb_usbvision *usbvision)
{
int free = usbvision->scratch_read_ptr - usbvision->scratch_write_ptr;
- if (free <= 0) {
+ if (free <= 0)
free += scratch_buf_size;
- }
if (free) {
free -= 1; /* at least one byte in the buffer must */
/* left blank, otherwise there is no chance to differ between full and empty */
@@ -221,14 +220,12 @@ static int scratch_put(struct usb_usbvision *usbvision, unsigned char *data,
if (usbvision->scratch_write_ptr + len < scratch_buf_size) {
memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len);
usbvision->scratch_write_ptr += len;
- }
- else {
+ } else {
len_part = scratch_buf_size - usbvision->scratch_write_ptr;
memcpy(usbvision->scratch + usbvision->scratch_write_ptr, data, len_part);
if (len == len_part) {
usbvision->scratch_write_ptr = 0; /* just set write_ptr to zero */
- }
- else {
+ } else {
memcpy(usbvision->scratch, data + len_part, len - len_part);
usbvision->scratch_write_ptr = len - len_part;
}
@@ -255,17 +252,16 @@ static int scratch_get_extra(struct usb_usbvision *usbvision,
unsigned char *data, int *ptr, int len)
{
int len_part;
+
if (*ptr + len < scratch_buf_size) {
memcpy(data, usbvision->scratch + *ptr, len);
*ptr += len;
- }
- else {
+ } else {
len_part = scratch_buf_size - *ptr;
memcpy(data, usbvision->scratch + *ptr, len_part);
if (len == len_part) {
*ptr = 0; /* just set the y_ptr to zero */
- }
- else {
+ } else {
memcpy(data + len_part, usbvision->scratch, len - len_part);
*ptr = len - len_part;
}
@@ -281,13 +277,13 @@ static int scratch_get_extra(struct usb_usbvision *usbvision,
static void scratch_set_extra_ptr(struct usb_usbvision *usbvision, int *ptr,
int len)
{
- *ptr = (usbvision->scratch_read_ptr + len)%scratch_buf_size;
+ *ptr = (usbvision->scratch_read_ptr + len) % scratch_buf_size;
PDEBUG(DBG_SCRATCH, "ptr=%d\n", *ptr);
}
-/*This increments the scratch extra read pointer */
+/* This increments the scratch extra read pointer */
static void scratch_inc_extra_ptr(int *ptr, int len)
{
*ptr = (*ptr + len) % scratch_buf_size;
@@ -301,17 +297,16 @@ static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data,
int len)
{
int len_part;
+
if (usbvision->scratch_read_ptr + len < scratch_buf_size) {
memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len);
usbvision->scratch_read_ptr += len;
- }
- else {
+ } else {
len_part = scratch_buf_size - usbvision->scratch_read_ptr;
memcpy(data, usbvision->scratch + usbvision->scratch_read_ptr, len_part);
if (len == len_part) {
usbvision->scratch_read_ptr = 0; /* just set the read_ptr to zero */
- }
- else {
+ } else {
memcpy(data + len_part, usbvision->scratch, len - len_part);
usbvision->scratch_read_ptr = len - len_part;
}
@@ -327,7 +322,7 @@ static int scratch_get(struct usb_usbvision *usbvision, unsigned char *data,
static int scratch_get_header(struct usb_usbvision *usbvision,
struct usbvision_frame_header *header)
{
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_SCRATCH, "from read_ptr=%d", usbvision->scratch_headermarker_read_ptr);
@@ -340,29 +335,28 @@ static int scratch_get_header(struct usb_usbvision *usbvision,
scratch_get(usbvision, (unsigned char *)header, USBVISION_HEADER_LENGTH);
if ((header->magic_1 == USBVISION_MAGIC_1)
&& (header->magic_2 == USBVISION_MAGIC_2)
- && (header->headerLength == USBVISION_HEADER_LENGTH)) {
- errCode = USBVISION_HEADER_LENGTH;
- header->frameWidth = header->frameWidthLo + (header->frameWidthHi << 8);
- header->frameHeight = header->frameHeightLo + (header->frameHeightHi << 8);
+ && (header->header_length == USBVISION_HEADER_LENGTH)) {
+ err_code = USBVISION_HEADER_LENGTH;
+ header->frame_width = header->frame_width_lo + (header->frame_width_hi << 8);
+ header->frame_height = header->frame_height_lo + (header->frame_height_hi << 8);
break;
}
}
- return errCode;
+ return err_code;
}
-/*This removes len bytes of old data from the buffer */
+/* This removes len bytes of old data from the buffer */
static void scratch_rm_old(struct usb_usbvision *usbvision, int len)
{
-
usbvision->scratch_read_ptr += len;
usbvision->scratch_read_ptr %= scratch_buf_size;
PDEBUG(DBG_SCRATCH, "read_ptr is now %d\n", usbvision->scratch_read_ptr);
}
-/*This resets the buffer - kills all data in it too */
+/* This resets the buffer - kills all data in it too */
static void scratch_reset(struct usb_usbvision *usbvision)
{
PDEBUG(DBG_SCRATCH, "\n");
@@ -371,14 +365,14 @@ static void scratch_reset(struct usb_usbvision *usbvision)
usbvision->scratch_write_ptr = 0;
usbvision->scratch_headermarker_read_ptr = 0;
usbvision->scratch_headermarker_write_ptr = 0;
- usbvision->isocstate = IsocState_NoFrame;
+ usbvision->isocstate = isoc_state_no_frame;
}
int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
{
usbvision->scratch = vmalloc_32(scratch_buf_size);
scratch_reset(usbvision);
- if(usbvision->scratch == NULL) {
+ if (usbvision->scratch == NULL) {
dev_err(&usbvision->dev->dev,
"%s: unable to allocate %d bytes for scratch\n",
__func__, scratch_buf_size);
@@ -391,7 +385,6 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision)
{
vfree(usbvision->scratch);
usbvision->scratch = NULL;
-
}
/*
@@ -420,13 +413,13 @@ static void usbvision_testpattern(struct usb_usbvision *usbvision,
printk(KERN_ERR "%s: usbvision == NULL\n", proc);
return;
}
- if (usbvision->curFrame == NULL) {
- printk(KERN_ERR "%s: usbvision->curFrame is NULL.\n", proc);
+ if (usbvision->cur_frame == NULL) {
+ printk(KERN_ERR "%s: usbvision->cur_frame is NULL.\n", proc);
return;
}
/* Grab the current frame */
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
/* Optionally start at the beginning */
if (fullframe) {
@@ -473,10 +466,9 @@ static void usbvision_testpattern(struct usb_usbvision *usbvision,
}
}
- frame->grabstate = FrameState_Done;
+ frame->grabstate = frame_state_done;
frame->scanlength += scan_length;
++num_pass;
-
}
/*
@@ -487,8 +479,9 @@ static void usbvision_testpattern(struct usb_usbvision *usbvision,
int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
{
int IFB_size = MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * 3 / 2;
- usbvision->IntraFrameBuffer = vmalloc_32(IFB_size);
- if (usbvision->IntraFrameBuffer == NULL) {
+
+ usbvision->intra_frame_buffer = vmalloc_32(IFB_size);
+ if (usbvision->intra_frame_buffer == NULL) {
dev_err(&usbvision->dev->dev,
"%s: unable to allocate %d for compr. frame buffer\n",
__func__, IFB_size);
@@ -504,8 +497,8 @@ int usbvision_decompress_alloc(struct usb_usbvision *usbvision)
*/
void usbvision_decompress_free(struct usb_usbvision *usbvision)
{
- vfree(usbvision->IntraFrameBuffer);
- usbvision->IntraFrameBuffer = NULL;
+ vfree(usbvision->intra_frame_buffer);
+ usbvision->intra_frame_buffer = NULL;
}
@@ -517,117 +510,111 @@ void usbvision_decompress_free(struct usb_usbvision *usbvision)
*
* Locate one of supported header markers in the scratch buffer.
*/
-static enum ParseState usbvision_find_header(struct usb_usbvision *usbvision)
+static enum parse_state usbvision_find_header(struct usb_usbvision *usbvision)
{
struct usbvision_frame *frame;
- int foundHeader = 0;
+ int found_header = 0;
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
- while (scratch_get_header(usbvision, &frame->isocHeader) == USBVISION_HEADER_LENGTH) {
- // found header in scratch
+ while (scratch_get_header(usbvision, &frame->isoc_header) == USBVISION_HEADER_LENGTH) {
+ /* found header in scratch */
PDEBUG(DBG_HEADER, "found header: 0x%02x%02x %d %d %d %d %#x 0x%02x %u %u",
- frame->isocHeader.magic_2,
- frame->isocHeader.magic_1,
- frame->isocHeader.headerLength,
- frame->isocHeader.frameNum,
- frame->isocHeader.framePhase,
- frame->isocHeader.frameLatency,
- frame->isocHeader.dataFormat,
- frame->isocHeader.formatParam,
- frame->isocHeader.frameWidth,
- frame->isocHeader.frameHeight);
-
- if (usbvision->requestIntra) {
- if (frame->isocHeader.formatParam & 0x80) {
- foundHeader = 1;
- usbvision->lastIsocFrameNum = -1; // do not check for lost frames this time
+ frame->isoc_header.magic_2,
+ frame->isoc_header.magic_1,
+ frame->isoc_header.header_length,
+ frame->isoc_header.frame_num,
+ frame->isoc_header.frame_phase,
+ frame->isoc_header.frame_latency,
+ frame->isoc_header.data_format,
+ frame->isoc_header.format_param,
+ frame->isoc_header.frame_width,
+ frame->isoc_header.frame_height);
+
+ if (usbvision->request_intra) {
+ if (frame->isoc_header.format_param & 0x80) {
+ found_header = 1;
+ usbvision->last_isoc_frame_num = -1; /* do not check for lost frames this time */
usbvision_unrequest_intra(usbvision);
break;
}
- }
- else {
- foundHeader = 1;
+ } else {
+ found_header = 1;
break;
}
}
- if (foundHeader) {
- frame->frmwidth = frame->isocHeader.frameWidth * usbvision->stretch_width;
- frame->frmheight = frame->isocHeader.frameHeight * usbvision->stretch_height;
- frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth)>> 3;
- }
- else { // no header found
+ if (found_header) {
+ frame->frmwidth = frame->isoc_header.frame_width * usbvision->stretch_width;
+ frame->frmheight = frame->isoc_header.frame_height * usbvision->stretch_height;
+ frame->v4l2_linesize = (frame->frmwidth * frame->v4l2_format.depth) >> 3;
+ } else { /* no header found */
PDEBUG(DBG_HEADER, "skipping scratch data, no header");
scratch_reset(usbvision);
- return ParseState_EndParse;
+ return parse_state_end_parse;
}
- // found header
- if (frame->isocHeader.dataFormat==ISOC_MODE_COMPRESS) {
- //check isocHeader.frameNum for lost frames
- if (usbvision->lastIsocFrameNum >= 0) {
- if (((usbvision->lastIsocFrameNum + 1) % 32) != frame->isocHeader.frameNum) {
- // unexpected frame drop: need to request new intra frame
- PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isocHeader.frameNum);
+ /* found header */
+ if (frame->isoc_header.data_format == ISOC_MODE_COMPRESS) {
+ /* check isoc_header.frame_num for lost frames */
+ if (usbvision->last_isoc_frame_num >= 0) {
+ if (((usbvision->last_isoc_frame_num + 1) % 32) != frame->isoc_header.frame_num) {
+ /* unexpected frame drop: need to request new intra frame */
+ PDEBUG(DBG_HEADER, "Lost frame before %d on USB", frame->isoc_header.frame_num);
usbvision_request_intra(usbvision);
- return ParseState_NextFrame;
+ return parse_state_next_frame;
}
}
- usbvision->lastIsocFrameNum = frame->isocHeader.frameNum;
+ usbvision->last_isoc_frame_num = frame->isoc_header.frame_num;
}
usbvision->header_count++;
- frame->scanstate = ScanState_Lines;
+ frame->scanstate = scan_state_lines;
frame->curline = 0;
if (force_testpattern) {
usbvision_testpattern(usbvision, 1, 1);
- return ParseState_NextFrame;
+ return parse_state_next_frame;
}
- return ParseState_Continue;
+ return parse_state_continue;
}
-static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision,
+static enum parse_state usbvision_parse_lines_422(struct usb_usbvision *usbvision,
long *pcopylen)
{
volatile struct usbvision_frame *frame;
unsigned char *f;
int len;
int i;
- unsigned char yuyv[4]={180, 128, 10, 128}; // YUV components
- unsigned char rv, gv, bv; // RGB components
+ unsigned char yuyv[4] = { 180, 128, 10, 128 }; /* YUV components */
+ unsigned char rv, gv, bv; /* RGB components */
int clipmask_index, bytes_per_pixel;
int stretch_bytes, clipmask_add;
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
f = frame->data + (frame->v4l2_linesize * frame->curline);
/* Make sure there's enough data for the entire line */
- len = (frame->isocHeader.frameWidth * 2)+5;
+ len = (frame->isoc_header.frame_width * 2) + 5;
if (scratch_len(usbvision) < len) {
PDEBUG(DBG_PARSE, "out of data in line %d, need %u.\n", frame->curline, len);
- return ParseState_Out;
+ return parse_state_out;
}
- if ((frame->curline + 1) >= frame->frmheight) {
- return ParseState_NextFrame;
- }
+ if ((frame->curline + 1) >= frame->frmheight)
+ return parse_state_next_frame;
bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
stretch_bytes = (usbvision->stretch_width - 1) * bytes_per_pixel;
clipmask_index = frame->curline * MAX_FRAME_WIDTH;
clipmask_add = usbvision->stretch_width;
- for (i = 0; i < frame->frmwidth; i+=(2 * usbvision->stretch_width)) {
-
+ for (i = 0; i < frame->frmwidth; i += (2 * usbvision->stretch_width)) {
scratch_get(usbvision, &yuyv[0], 4);
if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
- *f++ = yuyv[0]; // Y
- *f++ = yuyv[3]; // U
- }
- else {
-
+ *f++ = yuyv[0]; /* Y */
+ *f++ = yuyv[3]; /* U */
+ } else {
YUV_TO_RGB_BY_THE_BOOK(yuyv[0], yuyv[1], yuyv[3], rv, gv, bv);
switch (frame->v4l2_format.format) {
case V4L2_PIX_FMT_RGB565:
@@ -659,11 +646,9 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
f += stretch_bytes;
if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
- *f++ = yuyv[2]; // Y
- *f++ = yuyv[1]; // V
- }
- else {
-
+ *f++ = yuyv[2]; /* Y */
+ *f++ = yuyv[1]; /* V */
+ } else {
YUV_TO_RGB_BY_THE_BOOK(yuyv[2], yuyv[1], yuyv[3], rv, gv, bv);
switch (frame->v4l2_format.format) {
case V4L2_PIX_FMT_RGB565:
@@ -698,100 +683,94 @@ static enum ParseState usbvision_parse_lines_422(struct usb_usbvision *usbvision
frame->curline += usbvision->stretch_height;
*pcopylen += frame->v4l2_linesize * usbvision->stretch_height;
- if (frame->curline >= frame->frmheight) {
- return ParseState_NextFrame;
- }
- else {
- return ParseState_Continue;
- }
+ if (frame->curline >= frame->frmheight)
+ return parse_state_next_frame;
+ return parse_state_continue;
}
/* The decompression routine */
-static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *Compressed,
- unsigned char *Decompressed, int *StartPos,
- int *BlockTypeStartPos, int Len)
+static int usbvision_decompress(struct usb_usbvision *usbvision, unsigned char *compressed,
+ unsigned char *decompressed, int *start_pos,
+ int *block_typestart_pos, int len)
{
- int RestPixel, Idx, MaxPos, Pos, ExtraPos, BlockLen, BlockTypePos, BlockTypeLen;
- unsigned char BlockByte, BlockCode, BlockType, BlockTypeByte, Integrator;
-
- Integrator = 0;
- Pos = *StartPos;
- BlockTypePos = *BlockTypeStartPos;
- MaxPos = 396; //Pos + Len;
- ExtraPos = Pos;
- BlockLen = 0;
- BlockByte = 0;
- BlockCode = 0;
- BlockType = 0;
- BlockTypeByte = 0;
- BlockTypeLen = 0;
- RestPixel = Len;
-
- for (Idx = 0; Idx < Len; Idx++) {
-
- if (BlockLen == 0) {
- if (BlockTypeLen==0) {
- BlockTypeByte = Compressed[BlockTypePos];
- BlockTypePos++;
- BlockTypeLen = 4;
+ int rest_pixel, idx, max_pos, pos, extra_pos, block_len, block_type_pos, block_type_len;
+ unsigned char block_byte, block_code, block_type, block_type_byte, integrator;
+
+ integrator = 0;
+ pos = *start_pos;
+ block_type_pos = *block_typestart_pos;
+ max_pos = 396; /* pos + len; */
+ extra_pos = pos;
+ block_len = 0;
+ block_byte = 0;
+ block_code = 0;
+ block_type = 0;
+ block_type_byte = 0;
+ block_type_len = 0;
+ rest_pixel = len;
+
+ for (idx = 0; idx < len; idx++) {
+ if (block_len == 0) {
+ if (block_type_len == 0) {
+ block_type_byte = compressed[block_type_pos];
+ block_type_pos++;
+ block_type_len = 4;
}
- BlockType = (BlockTypeByte & 0xC0) >> 6;
+ block_type = (block_type_byte & 0xC0) >> 6;
- //statistic:
- usbvision->ComprBlockTypes[BlockType]++;
+ /* statistic: */
+ usbvision->compr_block_types[block_type]++;
- Pos = ExtraPos;
- if (BlockType == 0) {
- if(RestPixel >= 24) {
- Idx += 23;
- RestPixel -= 24;
- Integrator = Decompressed[Idx];
+ pos = extra_pos;
+ if (block_type == 0) {
+ if (rest_pixel >= 24) {
+ idx += 23;
+ rest_pixel -= 24;
+ integrator = decompressed[idx];
} else {
- Idx += RestPixel - 1;
- RestPixel = 0;
+ idx += rest_pixel - 1;
+ rest_pixel = 0;
}
} else {
- BlockCode = Compressed[Pos];
- Pos++;
- if (RestPixel >= 24) {
- BlockLen = 24;
- } else {
- BlockLen = RestPixel;
- }
- RestPixel -= BlockLen;
- ExtraPos = Pos + (BlockLen / 4);
+ block_code = compressed[pos];
+ pos++;
+ if (rest_pixel >= 24)
+ block_len = 24;
+ else
+ block_len = rest_pixel;
+ rest_pixel -= block_len;
+ extra_pos = pos + (block_len / 4);
}
- BlockTypeByte <<= 2;
- BlockTypeLen -= 1;
+ block_type_byte <<= 2;
+ block_type_len -= 1;
}
- if (BlockLen > 0) {
- if ((BlockLen%4) == 0) {
- BlockByte = Compressed[Pos];
- Pos++;
+ if (block_len > 0) {
+ if ((block_len % 4) == 0) {
+ block_byte = compressed[pos];
+ pos++;
}
- if (BlockType == 1) { //inter Block
- Integrator = Decompressed[Idx];
- }
- switch (BlockByte & 0xC0) {
- case 0x03<<6:
- Integrator += Compressed[ExtraPos];
- ExtraPos++;
- break;
- case 0x02<<6:
- Integrator += BlockCode;
- break;
- case 0x00:
- Integrator -= BlockCode;
- break;
+ if (block_type == 1) /* inter Block */
+ integrator = decompressed[idx];
+ switch (block_byte & 0xC0) {
+ case 0x03 << 6:
+ integrator += compressed[extra_pos];
+ extra_pos++;
+ break;
+ case 0x02 << 6:
+ integrator += block_code;
+ break;
+ case 0x00:
+ integrator -= block_code;
+ break;
}
- Decompressed[Idx] = Integrator;
- BlockByte <<= 2;
- BlockLen -= 1;
+ decompressed[idx] = integrator;
+ block_byte <<= 2;
+ block_len -= 1;
}
}
- *StartPos = ExtraPos;
- *BlockTypeStartPos = BlockTypePos;
- return Idx;
+ *start_pos = extra_pos;
+ *block_typestart_pos = block_type_pos;
+ return idx;
}
@@ -803,7 +782,7 @@ static int usbvision_decompress(struct usb_usbvision *usbvision,unsigned char *C
* number of bytes (RGB) to the *pcopylen.
*
*/
-static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
+static enum parse_state usbvision_parse_compress(struct usb_usbvision *usbvision,
long *pcopylen)
{
#define USBVISION_STRIP_MAGIC 0x5A
@@ -811,191 +790,165 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
#define USBVISION_STRIP_HEADER_LEN 3
struct usbvision_frame *frame;
- unsigned char *f,*u = NULL ,*v = NULL;
- unsigned char StripData[USBVISION_STRIP_LEN_MAX];
- unsigned char StripHeader[USBVISION_STRIP_HEADER_LEN];
- int Idx, IdxEnd, StripLen, StripPtr, StartBlockPos, BlockPos, BlockTypePos;
+ unsigned char *f, *u = NULL, *v = NULL;
+ unsigned char strip_data[USBVISION_STRIP_LEN_MAX];
+ unsigned char strip_header[USBVISION_STRIP_HEADER_LEN];
+ int idx, idx_end, strip_len, strip_ptr, startblock_pos, block_pos, block_type_pos;
int clipmask_index, bytes_per_pixel, rc;
- int imageSize;
+ int image_size;
unsigned char rv, gv, bv;
static unsigned char *Y, *U, *V;
- frame = usbvision->curFrame;
- imageSize = frame->frmwidth * frame->frmheight;
- if ( (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) ||
- (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) ) { // this is a planar format
- //... v4l2_linesize not used here.
+ frame = usbvision->cur_frame;
+ image_size = frame->frmwidth * frame->frmheight;
+ if ((frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) ||
+ (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420)) { /* this is a planar format */
+ /* ... v4l2_linesize not used here. */
f = frame->data + (frame->width * frame->curline);
} else
f = frame->data + (frame->v4l2_linesize * frame->curline);
- if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV){ //initialise u and v pointers
- // get base of u and b planes add halfoffset
-
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) { /* initialise u and v pointers */
+ /* get base of u and b planes add halfoffset */
u = frame->data
- + imageSize
- + (frame->frmwidth >>1) * frame->curline ;
- v = u + (imageSize >>1 );
-
- } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420){
-
- v = frame->data + imageSize + ((frame->curline* (frame->width))>>2) ;
- u = v + (imageSize >>2) ;
+ + image_size
+ + (frame->frmwidth >> 1) * frame->curline;
+ v = u + (image_size >> 1);
+ } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) {
+ v = frame->data + image_size + ((frame->curline * (frame->width)) >> 2);
+ u = v + (image_size >> 2);
}
- if (frame->curline == 0) {
+ if (frame->curline == 0)
usbvision_adjust_compression(usbvision);
- }
- if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN) {
- return ParseState_Out;
- }
+ if (scratch_len(usbvision) < USBVISION_STRIP_HEADER_LEN)
+ return parse_state_out;
- //get strip header without changing the scratch_read_ptr
- scratch_set_extra_ptr(usbvision, &StripPtr, 0);
- scratch_get_extra(usbvision, &StripHeader[0], &StripPtr,
+ /* get strip header without changing the scratch_read_ptr */
+ scratch_set_extra_ptr(usbvision, &strip_ptr, 0);
+ scratch_get_extra(usbvision, &strip_header[0], &strip_ptr,
USBVISION_STRIP_HEADER_LEN);
- if (StripHeader[0] != USBVISION_STRIP_MAGIC) {
- // wrong strip magic
- usbvision->stripMagicErrors++;
- return ParseState_NextFrame;
+ if (strip_header[0] != USBVISION_STRIP_MAGIC) {
+ /* wrong strip magic */
+ usbvision->strip_magic_errors++;
+ return parse_state_next_frame;
}
- if (frame->curline != (int)StripHeader[2]) {
- //line number missmatch error
- usbvision->stripLineNumberErrors++;
+ if (frame->curline != (int)strip_header[2]) {
+ /* line number mismatch error */
+ usbvision->strip_line_number_errors++;
}
- StripLen = 2 * (unsigned int)StripHeader[1];
- if (StripLen > USBVISION_STRIP_LEN_MAX) {
- // strip overrun
- // I think this never happens
+ strip_len = 2 * (unsigned int)strip_header[1];
+ if (strip_len > USBVISION_STRIP_LEN_MAX) {
+ /* strip overrun */
+ /* I think this never happens */
usbvision_request_intra(usbvision);
}
- if (scratch_len(usbvision) < StripLen) {
- //there is not enough data for the strip
- return ParseState_Out;
+ if (scratch_len(usbvision) < strip_len) {
+ /* there is not enough data for the strip */
+ return parse_state_out;
}
- if (usbvision->IntraFrameBuffer) {
- Y = usbvision->IntraFrameBuffer + frame->frmwidth * frame->curline;
- U = usbvision->IntraFrameBuffer + imageSize + (frame->frmwidth / 2) * (frame->curline / 2);
- V = usbvision->IntraFrameBuffer + imageSize / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2);
- }
- else {
- return ParseState_NextFrame;
+ if (usbvision->intra_frame_buffer) {
+ Y = usbvision->intra_frame_buffer + frame->frmwidth * frame->curline;
+ U = usbvision->intra_frame_buffer + image_size + (frame->frmwidth / 2) * (frame->curline / 2);
+ V = usbvision->intra_frame_buffer + image_size / 4 * 5 + (frame->frmwidth / 2) * (frame->curline / 2);
+ } else {
+ return parse_state_next_frame;
}
bytes_per_pixel = frame->v4l2_format.bytes_per_pixel;
clipmask_index = frame->curline * MAX_FRAME_WIDTH;
- scratch_get(usbvision, StripData, StripLen);
+ scratch_get(usbvision, strip_data, strip_len);
- IdxEnd = frame->frmwidth;
- BlockTypePos = USBVISION_STRIP_HEADER_LEN;
- StartBlockPos = BlockTypePos + (IdxEnd - 1) / 96 + (IdxEnd / 2 - 1) / 96 + 2;
- BlockPos = StartBlockPos;
+ idx_end = frame->frmwidth;
+ block_type_pos = USBVISION_STRIP_HEADER_LEN;
+ startblock_pos = block_type_pos + (idx_end - 1) / 96 + (idx_end / 2 - 1) / 96 + 2;
+ block_pos = startblock_pos;
- usbvision->BlockPos = BlockPos;
+ usbvision->block_pos = block_pos;
- if ((rc = usbvision_decompress(usbvision, StripData, Y, &BlockPos, &BlockTypePos, IdxEnd)) != IdxEnd) {
- //return ParseState_Continue;
- }
- if (StripLen > usbvision->maxStripLen) {
- usbvision->maxStripLen = StripLen;
- }
+ rc = usbvision_decompress(usbvision, strip_data, Y, &block_pos, &block_type_pos, idx_end);
+ if (strip_len > usbvision->max_strip_len)
+ usbvision->max_strip_len = strip_len;
- if (frame->curline%2) {
- if ((rc = usbvision_decompress(usbvision, StripData, V, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {
- //return ParseState_Continue;
- }
- }
- else {
- if ((rc = usbvision_decompress(usbvision, StripData, U, &BlockPos, &BlockTypePos, IdxEnd/2)) != IdxEnd/2) {
- //return ParseState_Continue;
- }
- }
+ if (frame->curline % 2)
+ rc = usbvision_decompress(usbvision, strip_data, V, &block_pos, &block_type_pos, idx_end / 2);
+ else
+ rc = usbvision_decompress(usbvision, strip_data, U, &block_pos, &block_type_pos, idx_end / 2);
- if (BlockPos > usbvision->comprBlockPos) {
- usbvision->comprBlockPos = BlockPos;
- }
- if (BlockPos > StripLen) {
- usbvision->stripLenErrors++;
- }
+ if (block_pos > usbvision->comprblock_pos)
+ usbvision->comprblock_pos = block_pos;
+ if (block_pos > strip_len)
+ usbvision->strip_len_errors++;
- for (Idx = 0; Idx < IdxEnd; Idx++) {
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
- *f++ = Y[Idx];
- *f++ = Idx & 0x01 ? U[Idx/2] : V[Idx/2];
- }
- else if(frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) {
- *f++ = Y[Idx];
- if ( Idx & 0x01)
- *u++ = U[Idx>>1] ;
+ for (idx = 0; idx < idx_end; idx++) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ *f++ = Y[idx];
+ *f++ = idx & 0x01 ? U[idx / 2] : V[idx / 2];
+ } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YUV422P) {
+ *f++ = Y[idx];
+ if (idx & 0x01)
+ *u++ = U[idx >> 1];
else
- *v++ = V[Idx>>1];
- }
- else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) {
- *f++ = Y [Idx];
- if ( !(( Idx & 0x01 ) | ( frame->curline & 0x01 )) ){
-
-/* only need do this for 1 in 4 pixels */
-/* intraframe buffer is YUV420 format */
-
- *u++ = U[Idx >>1];
- *v++ = V[Idx >>1];
+ *v++ = V[idx >> 1];
+ } else if (frame->v4l2_format.format == V4L2_PIX_FMT_YVU420) {
+ *f++ = Y[idx];
+ if (!((idx & 0x01) | (frame->curline & 0x01))) {
+ /* only need do this for 1 in 4 pixels */
+ /* intraframe buffer is YUV420 format */
+ *u++ = U[idx >> 1];
+ *v++ = V[idx >> 1];
}
-
- }
- else {
- YUV_TO_RGB_BY_THE_BOOK(Y[Idx], U[Idx/2], V[Idx/2], rv, gv, bv);
+ } else {
+ YUV_TO_RGB_BY_THE_BOOK(Y[idx], U[idx / 2], V[idx / 2], rv, gv, bv);
switch (frame->v4l2_format.format) {
- case V4L2_PIX_FMT_GREY:
- *f++ = Y[Idx];
- break;
- case V4L2_PIX_FMT_RGB555:
- *f++ = (0x1F & rv) |
- (0xE0 & (gv << 5));
- *f++ = (0x03 & (gv >> 3)) |
- (0x7C & (bv << 2));
- break;
- case V4L2_PIX_FMT_RGB565:
- *f++ = (0x1F & rv) |
- (0xE0 & (gv << 5));
- *f++ = (0x07 & (gv >> 3)) |
- (0xF8 & bv);
- break;
- case V4L2_PIX_FMT_RGB24:
- *f++ = rv;
- *f++ = gv;
- *f++ = bv;
- break;
- case V4L2_PIX_FMT_RGB32:
- *f++ = rv;
- *f++ = gv;
- *f++ = bv;
- f++;
- break;
+ case V4L2_PIX_FMT_GREY:
+ *f++ = Y[idx];
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ *f++ = (0x1F & rv) |
+ (0xE0 & (gv << 5));
+ *f++ = (0x03 & (gv >> 3)) |
+ (0x7C & (bv << 2));
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ *f++ = (0x1F & rv) |
+ (0xE0 & (gv << 5));
+ *f++ = (0x07 & (gv >> 3)) |
+ (0xF8 & bv);
+ break;
+ case V4L2_PIX_FMT_RGB24:
+ *f++ = rv;
+ *f++ = gv;
+ *f++ = bv;
+ break;
+ case V4L2_PIX_FMT_RGB32:
+ *f++ = rv;
+ *f++ = gv;
+ *f++ = bv;
+ f++;
+ break;
}
}
clipmask_index++;
}
/* Deal with non-integer no. of bytes for YUV420P */
- if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420 )
+ if (frame->v4l2_format.format != V4L2_PIX_FMT_YVU420)
*pcopylen += frame->v4l2_linesize;
else
*pcopylen += frame->curline & 0x01 ? frame->v4l2_linesize : frame->v4l2_linesize << 1;
frame->curline += 1;
- if (frame->curline >= frame->frmheight) {
- return ParseState_NextFrame;
- }
- else {
- return ParseState_Continue;
- }
+ if (frame->curline >= frame->frmheight)
+ return parse_state_next_frame;
+ return parse_state_continue;
}
@@ -1008,7 +961,7 @@ static enum ParseState usbvision_parse_compress(struct usb_usbvision *usbvision,
* number of bytes (RGB) to the *pcopylen.
*
*/
-static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision,
+static enum parse_state usbvision_parse_lines_420(struct usb_usbvision *usbvision,
long *pcopylen)
{
struct usbvision_frame *frame;
@@ -1016,11 +969,11 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
unsigned int pixel_per_line, block;
int pixel, block_split;
int y_ptr, u_ptr, v_ptr, y_odd_offset;
- const int y_block_size = 128;
- const int uv_block_size = 64;
+ const int y_block_size = 128;
+ const int uv_block_size = 64;
const int sub_block_size = 32;
- const int y_step[] = { 0, 0, 0, 2 }, y_step_size = 4;
- const int uv_step[]= { 0, 0, 0, 4 }, uv_step_size = 4;
+ const int y_step[] = { 0, 0, 0, 2 }, y_step_size = 4;
+ const int uv_step[] = { 0, 0, 0, 4 }, uv_step_size = 4;
unsigned char y[2], u, v; /* YUV components */
int y_, u_, v_, vb, uvg, ur;
int r_, g_, b_; /* RGB components */
@@ -1028,7 +981,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
int clipmask_even_index, clipmask_odd_index, bytes_per_pixel;
int clipmask_add, stretch_bytes;
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
f_even = frame->data + (frame->v4l2_linesize * frame->curline);
f_odd = f_even + frame->v4l2_linesize * usbvision->stretch_height;
@@ -1040,18 +993,17 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
clipmask_even_index = frame->curline * MAX_FRAME_WIDTH;
clipmask_odd_index = clipmask_even_index + MAX_FRAME_WIDTH;
clipmask_add = usbvision->stretch_width;
- pixel_per_line = frame->isocHeader.frameWidth;
+ pixel_per_line = frame->isoc_header.frame_width;
if (scratch_len(usbvision) < (int)pixel_per_line * 3) {
- //printk(KERN_DEBUG "out of data, need %d\n", len);
- return ParseState_Out;
+ /* printk(KERN_DEBUG "out of data, need %d\n", len); */
+ return parse_state_out;
}
- if ((frame->curline + 1) >= frame->frmheight) {
- return ParseState_NextFrame;
- }
+ if ((frame->curline + 1) >= frame->frmheight)
+ return parse_state_next_frame;
- block_split = (pixel_per_line%y_block_size) ? 1 : 0; //are some blocks splitted into different lines?
+ block_split = (pixel_per_line%y_block_size) ? 1 : 0; /* are some blocks splitted into different lines? */
y_odd_offset = (pixel_per_line / y_block_size) * (y_block_size + uv_block_size)
+ block_split * uv_block_size;
@@ -1061,31 +1013,27 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
scratch_set_extra_ptr(usbvision, &v_ptr, y_odd_offset
+ (4 - block_split) * sub_block_size);
- for (block = 0; block < (pixel_per_line / sub_block_size);
- block++) {
-
-
- for (pixel = 0; pixel < sub_block_size; pixel +=2) {
+ for (block = 0; block < (pixel_per_line / sub_block_size); block++) {
+ for (pixel = 0; pixel < sub_block_size; pixel += 2) {
scratch_get(usbvision, &y[0], 2);
scratch_get_extra(usbvision, &u, &u_ptr, 1);
scratch_get_extra(usbvision, &v, &v_ptr, 1);
- //I don't use the YUV_TO_RGB macro for better performance
+ /* I don't use the YUV_TO_RGB macro for better performance */
v_ = v - 128;
u_ = u - 128;
- vb = 132252 * v_;
- uvg= -53281 * u_ - 25625 * v_;
+ vb = 132252 * v_;
+ uvg = -53281 * u_ - 25625 * v_;
ur = 104595 * u_;
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
*f_even++ = y[0];
*f_even++ = v;
- }
- else {
+ } else {
y_ = 76284 * (y[0] - 16);
b_ = (y_ + vb) >> 16;
- g_ = (y_ + uvg)>> 16;
+ g_ = (y_ + uvg) >> 16;
r_ = (y_ + ur) >> 16;
switch (frame->v4l2_format.format) {
@@ -1121,15 +1069,14 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
clipmask_even_index += clipmask_add;
f_even += stretch_bytes;
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
*f_even++ = y[1];
*f_even++ = u;
- }
- else {
+ } else {
y_ = 76284 * (y[1] - 16);
b_ = (y_ + vb) >> 16;
- g_ = (y_ + uvg)>> 16;
+ g_ = (y_ + uvg) >> 16;
r_ = (y_ + ur) >> 16;
switch (frame->v4l2_format.format) {
@@ -1167,15 +1114,14 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
scratch_get_extra(usbvision, &y[0], &y_ptr, 2);
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
*f_odd++ = y[0];
*f_odd++ = v;
- }
- else {
+ } else {
y_ = 76284 * (y[0] - 16);
b_ = (y_ + vb) >> 16;
- g_ = (y_ + uvg)>> 16;
+ g_ = (y_ + uvg) >> 16;
r_ = (y_ + ur) >> 16;
switch (frame->v4l2_format.format) {
@@ -1211,15 +1157,14 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
clipmask_odd_index += clipmask_add;
f_odd += stretch_bytes;
- if(frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
+ if (frame->v4l2_format.format == V4L2_PIX_FMT_YUYV) {
*f_odd++ = y[1];
*f_odd++ = u;
- }
- else {
+ } else {
y_ = 76284 * (y[1] - 16);
b_ = (y_ + vb) >> 16;
- g_ = (y_ + uvg)>> 16;
+ g_ = (y_ + uvg) >> 16;
r_ = (y_ + ur) >> 16;
switch (frame->v4l2_format.format) {
@@ -1256,7 +1201,7 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
f_odd += stretch_bytes;
}
- scratch_rm_old(usbvision,y_step[block % y_step_size] * sub_block_size);
+ scratch_rm_old(usbvision, y_step[block % y_step_size] * sub_block_size);
scratch_inc_extra_ptr(&y_ptr, y_step[(block + 2 * block_split) % y_step_size]
* sub_block_size);
scratch_inc_extra_ptr(&u_ptr, uv_step[block % uv_step_size]
@@ -1272,9 +1217,8 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
*pcopylen += frame->v4l2_linesize * 2 * usbvision->stretch_height;
if (frame->curline >= frame->frmheight)
- return ParseState_NextFrame;
- else
- return ParseState_Continue;
+ return parse_state_next_frame;
+ return parse_state_continue;
}
/*
@@ -1288,53 +1232,43 @@ static enum ParseState usbvision_parse_lines_420(struct usb_usbvision *usbvision
static void usbvision_parse_data(struct usb_usbvision *usbvision)
{
struct usbvision_frame *frame;
- enum ParseState newstate;
+ enum parse_state newstate;
long copylen = 0;
unsigned long lock_flags;
- frame = usbvision->curFrame;
+ frame = usbvision->cur_frame;
PDEBUG(DBG_PARSE, "parsing len=%d\n", scratch_len(usbvision));
while (1) {
-
- newstate = ParseState_Out;
+ newstate = parse_state_out;
if (scratch_len(usbvision)) {
- if (frame->scanstate == ScanState_Scanning) {
+ if (frame->scanstate == scan_state_scanning) {
newstate = usbvision_find_header(usbvision);
- }
- else if (frame->scanstate == ScanState_Lines) {
- if (usbvision->isocMode == ISOC_MODE_YUV420) {
+ } else if (frame->scanstate == scan_state_lines) {
+ if (usbvision->isoc_mode == ISOC_MODE_YUV420)
newstate = usbvision_parse_lines_420(usbvision, &copylen);
- }
- else if (usbvision->isocMode == ISOC_MODE_YUV422) {
+ else if (usbvision->isoc_mode == ISOC_MODE_YUV422)
newstate = usbvision_parse_lines_422(usbvision, &copylen);
- }
- else if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ else if (usbvision->isoc_mode == ISOC_MODE_COMPRESS)
newstate = usbvision_parse_compress(usbvision, &copylen);
- }
-
}
}
- if (newstate == ParseState_Continue) {
+ if (newstate == parse_state_continue)
continue;
- }
- else if ((newstate == ParseState_NextFrame) || (newstate == ParseState_Out)) {
+ if ((newstate == parse_state_next_frame) || (newstate == parse_state_out))
break;
- }
- else {
- return; /* ParseState_EndParse */
- }
+ return; /* parse_state_end_parse */
}
- if (newstate == ParseState_NextFrame) {
- frame->grabstate = FrameState_Done;
+ if (newstate == parse_state_next_frame) {
+ frame->grabstate = frame_state_done;
do_gettimeofday(&(frame->timestamp));
frame->sequence = usbvision->frame_num;
spin_lock_irqsave(&usbvision->queue_lock, lock_flags);
list_move_tail(&(frame->frame), &usbvision->outqueue);
- usbvision->curFrame = NULL;
+ usbvision->cur_frame = NULL;
spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
usbvision->frame_num++;
@@ -1344,10 +1278,9 @@ static void usbvision_parse_data(struct usb_usbvision *usbvision)
PDEBUG(DBG_PARSE, "Wake up !");
wake_up_interruptible(&usbvision->wait_frame);
}
+ } else {
+ frame->grabstate = frame_state_grabbing;
}
- else
- frame->grabstate = FrameState_Grabbing;
-
/* Update the frame's uncompressed length. */
frame->scanlength += copylen;
@@ -1370,34 +1303,32 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
packet_data = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
/* Detect and ignore errored packets */
- if (packet_stat) { // packet_stat != 0 ?????????????
+ if (packet_stat) { /* packet_stat != 0 ????????????? */
PDEBUG(DBG_ISOC, "data error: [%d] len=%d, status=%X", i, packet_len, packet_stat);
- usbvision->isocErrCount++;
+ usbvision->isoc_err_count++;
continue;
}
/* Detect and ignore empty packets */
if (packet_len < 0) {
PDEBUG(DBG_ISOC, "error packet [%d]", i);
- usbvision->isocSkipCount++;
+ usbvision->isoc_skip_count++;
continue;
- }
- else if (packet_len == 0) { /* Frame end ????? */
+ } else if (packet_len == 0) { /* Frame end ????? */
PDEBUG(DBG_ISOC, "null packet [%d]", i);
- usbvision->isocstate=IsocState_NoFrame;
- usbvision->isocSkipCount++;
+ usbvision->isocstate = isoc_state_no_frame;
+ usbvision->isoc_skip_count++;
continue;
- }
- else if (packet_len > usbvision->isocPacketSize) {
- PDEBUG(DBG_ISOC, "packet[%d] > isocPacketSize", i);
- usbvision->isocSkipCount++;
+ } else if (packet_len > usbvision->isoc_packet_size) {
+ PDEBUG(DBG_ISOC, "packet[%d] > isoc_packet_size", i);
+ usbvision->isoc_skip_count++;
continue;
}
PDEBUG(DBG_ISOC, "packet ok [%d] len=%d", i, packet_len);
- if (usbvision->isocstate==IsocState_NoFrame) { //new frame begins
- usbvision->isocstate=IsocState_InFrame;
+ if (usbvision->isocstate == isoc_state_no_frame) { /* new frame begins */
+ usbvision->isocstate = isoc_state_in_frame;
scratch_mark_header(usbvision);
usbvision_measure_bandwidth(usbvision);
PDEBUG(DBG_ISOC, "packet with header");
@@ -1412,7 +1343,6 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
* your favorite evil here.
*/
if (scratch_free(usbvision) < packet_len) {
-
usbvision->scratch_ovf_count++;
PDEBUG(DBG_ISOC, "scratch buf overflow! scr_len: %d, n: %d",
scratch_len(usbvision), packet_len);
@@ -1422,12 +1352,13 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
/* Now we know that there is enough room in scratch buffer */
scratch_put(usbvision, packet_data, packet_len);
totlen += packet_len;
- usbvision->isocDataCount += packet_len;
- usbvision->isocPacketCount++;
+ usbvision->isoc_data_count += packet_len;
+ usbvision->isoc_packet_count++;
}
#if ENABLE_HEXDUMP
if (totlen > 0) {
static int foo;
+
if (foo < 1) {
printk(KERN_DEBUG "+%d.\n", usbvision->scratchlen);
usbvision_hexdump(data0, (totlen > 64) ? 64 : totlen);
@@ -1435,16 +1366,16 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
}
}
#endif
- return totlen;
+ return totlen;
}
-static void usbvision_isocIrq(struct urb *urb)
+static void usbvision_isoc_irq(struct urb *urb)
{
- int errCode = 0;
+ int err_code = 0;
int len;
struct usb_usbvision *usbvision = urb->context;
int i;
- unsigned long startTime = jiffies;
+ unsigned long start_time = jiffies;
struct usbvision_frame **f;
/* We don't want to do anything if we are about to be removed! */
@@ -1452,18 +1383,17 @@ static void usbvision_isocIrq(struct urb *urb)
return;
/* any urb with wrong status is ignored without acknowledgement */
- if (urb->status == -ENOENT) {
+ if (urb->status == -ENOENT)
return;
- }
- f = &usbvision->curFrame;
+ f = &usbvision->cur_frame;
/* Manage streaming interruption */
- if (usbvision->streaming == Stream_Interrupt) {
- usbvision->streaming = Stream_Idle;
+ if (usbvision->streaming == stream_interrupt) {
+ usbvision->streaming = stream_idle;
if ((*f)) {
- (*f)->grabstate = FrameState_Ready;
- (*f)->scanstate = ScanState_Scanning;
+ (*f)->grabstate = frame_state_ready;
+ (*f)->scanstate = scan_state_scanning;
}
PDEBUG(DBG_IRQ, "stream interrupted");
wake_up_interruptible(&usbvision->wait_stream);
@@ -1472,35 +1402,32 @@ static void usbvision_isocIrq(struct urb *urb)
/* Copy the data received into our scratch buffer */
len = usbvision_compress_isochronous(usbvision, urb);
- usbvision->isocUrbCount++;
+ usbvision->isoc_urb_count++;
usbvision->urb_length = len;
- if (usbvision->streaming == Stream_On) {
-
+ if (usbvision->streaming == stream_on) {
/* If we collected enough data let's parse! */
- if ((scratch_len(usbvision) > USBVISION_HEADER_LENGTH) &&
- (!list_empty(&(usbvision->inqueue))) ) {
+ if (scratch_len(usbvision) > USBVISION_HEADER_LENGTH &&
+ !list_empty(&(usbvision->inqueue))) {
if (!(*f)) {
(*f) = list_entry(usbvision->inqueue.next,
struct usbvision_frame,
frame);
}
usbvision_parse_data(usbvision);
- }
- else {
- /*If we don't have a frame
+ } else {
+ /* If we don't have a frame
we're current working on, complain */
PDEBUG(DBG_IRQ,
"received data, but no one needs it");
scratch_reset(usbvision);
}
- }
- else {
+ } else {
PDEBUG(DBG_IRQ, "received data, but no one needs it");
scratch_reset(usbvision);
}
- usbvision->timeInIrq += jiffies - startTime;
+ usbvision->time_in_irq += jiffies - start_time;
for (i = 0; i < USBVISION_URB_FRAMES; i++) {
urb->iso_frame_desc[i].status = 0;
@@ -1509,12 +1436,12 @@ static void usbvision_isocIrq(struct urb *urb)
urb->status = 0;
urb->dev = usbvision->dev;
- errCode = usb_submit_urb (urb, GFP_ATOMIC);
+ err_code = usb_submit_urb(urb, GFP_ATOMIC);
- if(errCode) {
+ if (err_code) {
dev_err(&usbvision->dev->dev,
"%s: usb_submit_urb failed: error %d\n",
- __func__, errCode);
+ __func__, err_code);
}
return;
@@ -1533,21 +1460,21 @@ static void usbvision_isocIrq(struct urb *urb)
int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
{
- int errCode = 0;
+ int err_code = 0;
unsigned char buffer[1];
if (!USBVISION_IS_OPERATIONAL(usbvision))
return -1;
- errCode = usb_control_msg(usbvision->dev, usb_rcvctrlpipe(usbvision->dev, 1),
+ err_code = usb_control_msg(usbvision->dev, usb_rcvctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
0, (__u16) reg, buffer, 1, HZ);
- if (errCode < 0) {
+ if (err_code < 0) {
dev_err(&usbvision->dev->dev,
- "%s: failed: error %d\n", __func__, errCode);
- return errCode;
+ "%s: failed: error %d\n", __func__, err_code);
+ return err_code;
}
return buffer[0];
}
@@ -1563,179 +1490,176 @@ int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
unsigned char value)
{
- int errCode = 0;
+ int err_code = 0;
if (!USBVISION_IS_OPERATIONAL(usbvision))
return 0;
- errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ err_code = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_OUT | USB_TYPE_VENDOR |
USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ);
- if (errCode < 0) {
+ if (err_code < 0) {
dev_err(&usbvision->dev->dev,
- "%s: failed: error %d\n", __func__, errCode);
+ "%s: failed: error %d\n", __func__, err_code);
}
- return errCode;
+ return err_code;
}
-static void usbvision_ctrlUrb_complete(struct urb *urb)
+static void usbvision_ctrl_urb_complete(struct urb *urb)
{
struct usb_usbvision *usbvision = (struct usb_usbvision *)urb->context;
PDEBUG(DBG_IRQ, "");
- usbvision->ctrlUrbBusy = 0;
- if (waitqueue_active(&usbvision->ctrlUrb_wq)) {
- wake_up_interruptible(&usbvision->ctrlUrb_wq);
- }
+ usbvision->ctrl_urb_busy = 0;
+ if (waitqueue_active(&usbvision->ctrl_urb_wq))
+ wake_up_interruptible(&usbvision->ctrl_urb_wq);
}
-static int usbvision_write_reg_irq(struct usb_usbvision *usbvision,int address,
- unsigned char *data, int len)
+static int usbvision_write_reg_irq(struct usb_usbvision *usbvision, int address,
+ unsigned char *data, int len)
{
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_IRQ, "");
- if (len > 8) {
+ if (len > 8)
return -EFAULT;
- }
- if (usbvision->ctrlUrbBusy) {
+ if (usbvision->ctrl_urb_busy)
return -EBUSY;
- }
- usbvision->ctrlUrbBusy = 1;
-
- usbvision->ctrlUrbSetup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
- usbvision->ctrlUrbSetup.bRequest = USBVISION_OP_CODE;
- usbvision->ctrlUrbSetup.wValue = 0;
- usbvision->ctrlUrbSetup.wIndex = cpu_to_le16(address);
- usbvision->ctrlUrbSetup.wLength = cpu_to_le16(len);
- usb_fill_control_urb (usbvision->ctrlUrb, usbvision->dev,
+ usbvision->ctrl_urb_busy = 1;
+
+ usbvision->ctrl_urb_setup.bRequestType = USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT;
+ usbvision->ctrl_urb_setup.bRequest = USBVISION_OP_CODE;
+ usbvision->ctrl_urb_setup.wValue = 0;
+ usbvision->ctrl_urb_setup.wIndex = cpu_to_le16(address);
+ usbvision->ctrl_urb_setup.wLength = cpu_to_le16(len);
+ usb_fill_control_urb(usbvision->ctrl_urb, usbvision->dev,
usb_sndctrlpipe(usbvision->dev, 1),
- (unsigned char *)&usbvision->ctrlUrbSetup,
- (void *)usbvision->ctrlUrbBuffer, len,
- usbvision_ctrlUrb_complete,
+ (unsigned char *)&usbvision->ctrl_urb_setup,
+ (void *)usbvision->ctrl_urb_buffer, len,
+ usbvision_ctrl_urb_complete,
(void *)usbvision);
- memcpy(usbvision->ctrlUrbBuffer, data, len);
+ memcpy(usbvision->ctrl_urb_buffer, data, len);
- errCode = usb_submit_urb(usbvision->ctrlUrb, GFP_ATOMIC);
- if (errCode < 0) {
- // error in usb_submit_urb()
- usbvision->ctrlUrbBusy = 0;
+ err_code = usb_submit_urb(usbvision->ctrl_urb, GFP_ATOMIC);
+ if (err_code < 0) {
+ /* error in usb_submit_urb() */
+ usbvision->ctrl_urb_busy = 0;
}
- PDEBUG(DBG_IRQ, "submit %d byte: error %d", len, errCode);
- return errCode;
+ PDEBUG(DBG_IRQ, "submit %d byte: error %d", len, err_code);
+ return err_code;
}
static int usbvision_init_compression(struct usb_usbvision *usbvision)
{
- int errCode = 0;
-
- usbvision->lastIsocFrameNum = -1;
- usbvision->isocDataCount = 0;
- usbvision->isocPacketCount = 0;
- usbvision->isocSkipCount = 0;
- usbvision->comprLevel = 50;
- usbvision->lastComprLevel = -1;
- usbvision->isocUrbCount = 0;
- usbvision->requestIntra = 1;
- usbvision->isocMeasureBandwidthCount = 0;
-
- return errCode;
+ int err_code = 0;
+
+ usbvision->last_isoc_frame_num = -1;
+ usbvision->isoc_data_count = 0;
+ usbvision->isoc_packet_count = 0;
+ usbvision->isoc_skip_count = 0;
+ usbvision->compr_level = 50;
+ usbvision->last_compr_level = -1;
+ usbvision->isoc_urb_count = 0;
+ usbvision->request_intra = 1;
+ usbvision->isoc_measure_bandwidth_count = 0;
+
+ return err_code;
}
/* this function measures the used bandwidth since last call
* return: 0 : no error
- * sets usedBandwidth to 1-100 : 1-100% of full bandwidth resp. to isocPacketSize
+ * sets used_bandwidth to 1-100 : 1-100% of full bandwidth resp. to isoc_packet_size
*/
-static int usbvision_measure_bandwidth (struct usb_usbvision *usbvision)
+static int usbvision_measure_bandwidth(struct usb_usbvision *usbvision)
{
- int errCode = 0;
-
- if (usbvision->isocMeasureBandwidthCount < 2) { // this gives an average bandwidth of 3 frames
- usbvision->isocMeasureBandwidthCount++;
- return errCode;
- }
- if ((usbvision->isocPacketSize > 0) && (usbvision->isocPacketCount > 0)) {
- usbvision->usedBandwidth = usbvision->isocDataCount /
- (usbvision->isocPacketCount + usbvision->isocSkipCount) *
- 100 / usbvision->isocPacketSize;
- }
- usbvision->isocMeasureBandwidthCount = 0;
- usbvision->isocDataCount = 0;
- usbvision->isocPacketCount = 0;
- usbvision->isocSkipCount = 0;
- return errCode;
+ int err_code = 0;
+
+ if (usbvision->isoc_measure_bandwidth_count < 2) { /* this gives an average bandwidth of 3 frames */
+ usbvision->isoc_measure_bandwidth_count++;
+ return err_code;
+ }
+ if ((usbvision->isoc_packet_size > 0) && (usbvision->isoc_packet_count > 0)) {
+ usbvision->used_bandwidth = usbvision->isoc_data_count /
+ (usbvision->isoc_packet_count + usbvision->isoc_skip_count) *
+ 100 / usbvision->isoc_packet_size;
+ }
+ usbvision->isoc_measure_bandwidth_count = 0;
+ usbvision->isoc_data_count = 0;
+ usbvision->isoc_packet_count = 0;
+ usbvision->isoc_skip_count = 0;
+ return err_code;
}
-static int usbvision_adjust_compression (struct usb_usbvision *usbvision)
+static int usbvision_adjust_compression(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
unsigned char buffer[6];
PDEBUG(DBG_IRQ, "");
- if ((adjustCompression) && (usbvision->usedBandwidth > 0)) {
- usbvision->comprLevel += (usbvision->usedBandwidth - 90) / 2;
- RESTRICT_TO_RANGE(usbvision->comprLevel, 0, 100);
- if (usbvision->comprLevel != usbvision->lastComprLevel) {
- int distorsion;
- if (usbvision->bridgeType == BRIDGE_NT1004 || usbvision->bridgeType == BRIDGE_NT1005) {
- buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100); // PCM Threshold 1
- buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100); // PCM Threshold 2
- distorsion = 7 + 248 * usbvision->comprLevel / 100;
- buffer[2] = (unsigned char)(distorsion & 0xFF); // Average distorsion Threshold (inter)
- buffer[3] = (unsigned char)(distorsion & 0xFF); // Average distorsion Threshold (intra)
- distorsion = 1 + 42 * usbvision->comprLevel / 100;
- buffer[4] = (unsigned char)(distorsion & 0xFF); // Maximum distorsion Threshold (inter)
- buffer[5] = (unsigned char)(distorsion & 0xFF); // Maximum distorsion Threshold (intra)
- }
- else { //BRIDGE_NT1003
- buffer[0] = (unsigned char)(4 + 16 * usbvision->comprLevel / 100); // PCM threshold 1
- buffer[1] = (unsigned char)(4 + 8 * usbvision->comprLevel / 100); // PCM threshold 2
- distorsion = 2 + 253 * usbvision->comprLevel / 100;
- buffer[2] = (unsigned char)(distorsion & 0xFF); // distorsion threshold bit0-7
- buffer[3] = 0; //(unsigned char)((distorsion >> 8) & 0x0F); // distorsion threshold bit 8-11
- distorsion = 0 + 43 * usbvision->comprLevel / 100;
- buffer[4] = (unsigned char)(distorsion & 0xFF); // maximum distorsion bit0-7
- buffer[5] = 0; //(unsigned char)((distorsion >> 8) & 0x01); // maximum distorsion bit 8
+ if ((adjust_compression) && (usbvision->used_bandwidth > 0)) {
+ usbvision->compr_level += (usbvision->used_bandwidth - 90) / 2;
+ RESTRICT_TO_RANGE(usbvision->compr_level, 0, 100);
+ if (usbvision->compr_level != usbvision->last_compr_level) {
+ int distortion;
+
+ if (usbvision->bridge_type == BRIDGE_NT1004 || usbvision->bridge_type == BRIDGE_NT1005) {
+ buffer[0] = (unsigned char)(4 + 16 * usbvision->compr_level / 100); /* PCM Threshold 1 */
+ buffer[1] = (unsigned char)(4 + 8 * usbvision->compr_level / 100); /* PCM Threshold 2 */
+ distortion = 7 + 248 * usbvision->compr_level / 100;
+ buffer[2] = (unsigned char)(distortion & 0xFF); /* Average distortion Threshold (inter) */
+ buffer[3] = (unsigned char)(distortion & 0xFF); /* Average distortion Threshold (intra) */
+ distortion = 1 + 42 * usbvision->compr_level / 100;
+ buffer[4] = (unsigned char)(distortion & 0xFF); /* Maximum distortion Threshold (inter) */
+ buffer[5] = (unsigned char)(distortion & 0xFF); /* Maximum distortion Threshold (intra) */
+ } else { /* BRIDGE_NT1003 */
+ buffer[0] = (unsigned char)(4 + 16 * usbvision->compr_level / 100); /* PCM threshold 1 */
+ buffer[1] = (unsigned char)(4 + 8 * usbvision->compr_level / 100); /* PCM threshold 2 */
+ distortion = 2 + 253 * usbvision->compr_level / 100;
+ buffer[2] = (unsigned char)(distortion & 0xFF); /* distortion threshold bit0-7 */
+ buffer[3] = 0; /* (unsigned char)((distortion >> 8) & 0x0F); distortion threshold bit 8-11 */
+ distortion = 0 + 43 * usbvision->compr_level / 100;
+ buffer[4] = (unsigned char)(distortion & 0xFF); /* maximum distortion bit0-7 */
+ buffer[5] = 0; /* (unsigned char)((distortion >> 8) & 0x01); maximum distortion bit 8 */
}
- errCode = usbvision_write_reg_irq(usbvision, USBVISION_PCM_THR1, buffer, 6);
- if (errCode == 0){
+ err_code = usbvision_write_reg_irq(usbvision, USBVISION_PCM_THR1, buffer, 6);
+ if (err_code == 0) {
PDEBUG(DBG_IRQ, "new compr params %#02x %#02x %#02x %#02x %#02x %#02x", buffer[0],
buffer[1], buffer[2], buffer[3], buffer[4], buffer[5]);
- usbvision->lastComprLevel = usbvision->comprLevel;
+ usbvision->last_compr_level = usbvision->compr_level;
}
}
}
- return errCode;
+ return err_code;
}
-static int usbvision_request_intra (struct usb_usbvision *usbvision)
+static int usbvision_request_intra(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
unsigned char buffer[1];
PDEBUG(DBG_IRQ, "");
- usbvision->requestIntra = 1;
+ usbvision->request_intra = 1;
buffer[0] = 1;
usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1);
- return errCode;
+ return err_code;
}
-static int usbvision_unrequest_intra (struct usb_usbvision *usbvision)
+static int usbvision_unrequest_intra(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
unsigned char buffer[1];
PDEBUG(DBG_IRQ, "");
- usbvision->requestIntra = 0;
+ usbvision->request_intra = 0;
buffer[0] = 0;
usbvision_write_reg_irq(usbvision, USBVISION_FORCE_INTRA, buffer, 1);
- return errCode;
+ return err_code;
}
/*******************************
@@ -1744,16 +1668,15 @@ static int usbvision_unrequest_intra (struct usb_usbvision *usbvision)
int usbvision_power_off(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_FUNC, "");
- errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
- if (errCode == 1) {
+ err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
+ if (err_code == 1)
usbvision->power = 0;
- }
- PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode!=1)?"ERROR":"power is off", errCode);
- return errCode;
+ PDEBUG(DBG_FUNC, "%s: err_code %d", (err_code != 1) ? "ERROR" : "power is off", err_code);
+ return err_code;
}
/*
@@ -1769,7 +1692,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
if (!USBVISION_IS_OPERATIONAL(usbvision))
return 0;
- PDEBUG(DBG_FUNC, "isocMode %#02x", format);
+ PDEBUG(DBG_FUNC, "isoc_mode %#02x", format);
if ((format != ISOC_MODE_YUV422)
&& (format != ISOC_MODE_YUV420)
@@ -1778,8 +1701,8 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
format);
format = ISOC_MODE_YUV420;
}
- value[0] = 0x0A; //TODO: See the effect of the filter
- value[1] = format; // Sets the VO_MODE register which follows FILT_CONT
+ value[0] = 0x0A; /* TODO: See the effect of the filter */
+ value[1] = format; /* Sets the VO_MODE register which follows FILT_CONT */
rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_OUT | USB_TYPE_VENDOR |
@@ -1790,7 +1713,7 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
printk(KERN_ERR "%s: ERROR=%d. USBVISION stopped - "
"reconnect or reload driver.\n", proc, rc);
}
- usbvision->isocMode = format;
+ usbvision->isoc_mode = format;
return rc;
}
@@ -1802,96 +1725,88 @@ static int usbvision_set_video_format(struct usb_usbvision *usbvision, int forma
int usbvision_set_output(struct usb_usbvision *usbvision, int width,
int height)
{
- int errCode = 0;
- int UsbWidth, UsbHeight;
- unsigned int frameRate=0, frameDrop=0;
+ int err_code = 0;
+ int usb_width, usb_height;
+ unsigned int frame_rate = 0, frame_drop = 0;
unsigned char value[4];
- if (!USBVISION_IS_OPERATIONAL(usbvision)) {
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
return 0;
- }
if (width > MAX_USB_WIDTH) {
- UsbWidth = width / 2;
+ usb_width = width / 2;
usbvision->stretch_width = 2;
- }
- else {
- UsbWidth = width;
+ } else {
+ usb_width = width;
usbvision->stretch_width = 1;
}
if (height > MAX_USB_HEIGHT) {
- UsbHeight = height / 2;
+ usb_height = height / 2;
usbvision->stretch_height = 2;
- }
- else {
- UsbHeight = height;
+ } else {
+ usb_height = height;
usbvision->stretch_height = 1;
}
- RESTRICT_TO_RANGE(UsbWidth, MIN_FRAME_WIDTH, MAX_USB_WIDTH);
- UsbWidth &= ~(MIN_FRAME_WIDTH-1);
- RESTRICT_TO_RANGE(UsbHeight, MIN_FRAME_HEIGHT, MAX_USB_HEIGHT);
- UsbHeight &= ~(1);
+ RESTRICT_TO_RANGE(usb_width, MIN_FRAME_WIDTH, MAX_USB_WIDTH);
+ usb_width &= ~(MIN_FRAME_WIDTH-1);
+ RESTRICT_TO_RANGE(usb_height, MIN_FRAME_HEIGHT, MAX_USB_HEIGHT);
+ usb_height &= ~(1);
PDEBUG(DBG_FUNC, "usb %dx%d; screen %dx%d; stretch %dx%d",
- UsbWidth, UsbHeight, width, height,
+ usb_width, usb_height, width, height,
usbvision->stretch_width, usbvision->stretch_height);
/* I'll not rewrite the same values */
- if ((UsbWidth != usbvision->curwidth) || (UsbHeight != usbvision->curheight)) {
- value[0] = UsbWidth & 0xff; //LSB
- value[1] = (UsbWidth >> 8) & 0x03; //MSB
- value[2] = UsbHeight & 0xff; //LSB
- value[3] = (UsbHeight >> 8) & 0x03; //MSB
+ if ((usb_width != usbvision->curwidth) || (usb_height != usbvision->curheight)) {
+ value[0] = usb_width & 0xff; /* LSB */
+ value[1] = (usb_width >> 8) & 0x03; /* MSB */
+ value[2] = usb_height & 0xff; /* LSB */
+ value[3] = (usb_height >> 8) & 0x03; /* MSB */
- errCode = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
+ err_code = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
USBVISION_OP_CODE,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_ENDPOINT,
0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ);
- if (errCode < 0) {
+ if (err_code < 0) {
dev_err(&usbvision->dev->dev,
- "%s failed: error %d\n", __func__, errCode);
- return errCode;
+ "%s failed: error %d\n", __func__, err_code);
+ return err_code;
}
- usbvision->curwidth = usbvision->stretch_width * UsbWidth;
- usbvision->curheight = usbvision->stretch_height * UsbHeight;
+ usbvision->curwidth = usbvision->stretch_width * usb_width;
+ usbvision->curheight = usbvision->stretch_height * usb_height;
}
- if (usbvision->isocMode == ISOC_MODE_YUV422) {
- frameRate = (usbvision->isocPacketSize * 1000) / (UsbWidth * UsbHeight * 2);
- }
- else if (usbvision->isocMode == ISOC_MODE_YUV420) {
- frameRate = (usbvision->isocPacketSize * 1000) / ((UsbWidth * UsbHeight * 12) / 8);
- }
- else {
- frameRate = FRAMERATE_MAX;
- }
+ if (usbvision->isoc_mode == ISOC_MODE_YUV422)
+ frame_rate = (usbvision->isoc_packet_size * 1000) / (usb_width * usb_height * 2);
+ else if (usbvision->isoc_mode == ISOC_MODE_YUV420)
+ frame_rate = (usbvision->isoc_packet_size * 1000) / ((usb_width * usb_height * 12) / 8);
+ else
+ frame_rate = FRAMERATE_MAX;
- if (usbvision->tvnormId & V4L2_STD_625_50) {
- frameDrop = frameRate * 32 / 25 - 1;
- }
- else if (usbvision->tvnormId & V4L2_STD_525_60) {
- frameDrop = frameRate * 32 / 30 - 1;
- }
+ if (usbvision->tvnorm_id & V4L2_STD_625_50)
+ frame_drop = frame_rate * 32 / 25 - 1;
+ else if (usbvision->tvnorm_id & V4L2_STD_525_60)
+ frame_drop = frame_rate * 32 / 30 - 1;
- RESTRICT_TO_RANGE(frameDrop, FRAMERATE_MIN, FRAMERATE_MAX);
+ RESTRICT_TO_RANGE(frame_drop, FRAMERATE_MIN, FRAMERATE_MAX);
- PDEBUG(DBG_FUNC, "frameRate %d fps, frameDrop %d", frameRate, frameDrop);
+ PDEBUG(DBG_FUNC, "frame_rate %d fps, frame_drop %d", frame_rate, frame_drop);
- frameDrop = FRAMERATE_MAX; // We can allow the maximum here, because dropping is controlled
+ frame_drop = FRAMERATE_MAX; /* We can allow the maximum here, because dropping is controlled */
- /* frameDrop = 7; => framePhase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
- => frameSkip = 4;
- => frameRate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
+ /* frame_drop = 7; => frame_phase = 1, 5, 9, 13, 17, 21, 25, 0, 4, 8, ...
+ => frame_skip = 4;
+ => frame_rate = (7 + 1) * 25 / 32 = 200 / 32 = 6.25;
- frameDrop = 9; => framePhase = 1, 5, 8, 11, 14, 17, 21, 24, 27, 1, 4, 8, ...
- => frameSkip = 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, ...
- => frameRate = (9 + 1) * 25 / 32 = 250 / 32 = 7.8125;
+ frame_drop = 9; => frame_phase = 1, 5, 8, 11, 14, 17, 21, 24, 27, 1, 4, 8, ...
+ => frame_skip = 4, 3, 3, 3, 3, 4, 3, 3, 3, 3, 4, ...
+ => frame_rate = (9 + 1) * 25 / 32 = 250 / 32 = 7.8125;
*/
- errCode = usbvision_write_reg(usbvision, USBVISION_FRM_RATE, frameDrop);
- return errCode;
+ err_code = usbvision_write_reg(usbvision, USBVISION_FRM_RATE, frame_drop);
+ return err_code;
}
@@ -1903,8 +1818,8 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
{
int i;
- /*needs to be page aligned cause the buffers can be mapped individually! */
- usbvision->max_frame_size = PAGE_ALIGN(usbvision->curwidth *
+ /* needs to be page aligned cause the buffers can be mapped individually! */
+ usbvision->max_frame_size = PAGE_ALIGN(usbvision->curwidth *
usbvision->curheight *
usbvision->palette.bytes_per_pixel);
@@ -1912,9 +1827,9 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
usbvision->num_frames = number_of_frames;
while (usbvision->num_frames > 0) {
usbvision->fbuf_size = usbvision->num_frames * usbvision->max_frame_size;
- if((usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size))) {
+ usbvision->fbuf = usbvision_rvmalloc(usbvision->fbuf_size);
+ if (usbvision->fbuf)
break;
- }
usbvision->num_frames--;
}
@@ -1925,7 +1840,7 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
/* Allocate all buffers */
for (i = 0; i < usbvision->num_frames; i++) {
usbvision->frame[i].index = i;
- usbvision->frame[i].grabstate = FrameState_Unused;
+ usbvision->frame[i].grabstate = frame_state_unused;
usbvision->frame[i].data = usbvision->fbuf +
i * usbvision->max_frame_size;
/*
@@ -1937,7 +1852,8 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
usbvision->frame[i].height = usbvision->curheight;
usbvision->frame[i].bytes_read = 0;
}
- PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)",usbvision->num_frames,usbvision->max_frame_size);
+ PDEBUG(DBG_FUNC, "allocated %d frames (%d bytes per frame)",
+ usbvision->num_frames, usbvision->max_frame_size);
return usbvision->num_frames;
}
@@ -1948,7 +1864,7 @@ int usbvision_frames_alloc(struct usb_usbvision *usbvision, int number_of_frames
void usbvision_frames_free(struct usb_usbvision *usbvision)
{
/* Have to free all that memory */
- PDEBUG(DBG_FUNC, "free %d frames",usbvision->num_frames);
+ PDEBUG(DBG_FUNC, "free %d frames", usbvision->num_frames);
if (usbvision->fbuf != NULL) {
usbvision_rvfree(usbvision->fbuf, usbvision->fbuf_size);
@@ -1969,7 +1885,7 @@ void usbvision_empty_framequeues(struct usb_usbvision *usbvision)
INIT_LIST_HEAD(&(usbvision->outqueue));
for (i = 0; i < USBVISION_NUMFRAMES; i++) {
- usbvision->frame[i].grabstate = FrameState_Unused;
+ usbvision->frame[i].grabstate = frame_state_unused;
usbvision->frame[i].bytes_read = 0;
}
}
@@ -1984,9 +1900,9 @@ int usbvision_stream_interrupt(struct usb_usbvision *usbvision)
/* stop reading from the device */
- usbvision->streaming = Stream_Interrupt;
+ usbvision->streaming = stream_interrupt;
ret = wait_event_timeout(usbvision->wait_stream,
- (usbvision->streaming == Stream_Idle),
+ (usbvision->streaming == stream_idle),
msecs_to_jiffies(USBVISION_NUMSBUF*USBVISION_URB_FRAMES));
return ret;
}
@@ -2002,19 +1918,19 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision)
int rc;
unsigned char value[6];
- value[0] = 0x0F; // Intra-Compression cycle
- value[1] = 0x01; // Reg.45 one line per strip
- value[2] = 0x00; // Reg.46 Force intra mode on all new frames
- value[3] = 0x00; // Reg.47 FORCE_UP <- 0 normal operation (not force)
- value[4] = 0xA2; // Reg.48 BUF_THR I'm not sure if this does something in not compressed mode.
- value[5] = 0x00; // Reg.49 DVI_YUV This has nothing to do with compression
-
- //catched values for NT1004
- // value[0] = 0xFF; // Never apply intra mode automatically
- // value[1] = 0xF1; // Use full frame height for virtual strip width; One line per strip
- // value[2] = 0x01; // Force intra mode on all new frames
- // value[3] = 0x00; // Strip size 400 Bytes; do not force up
- // value[4] = 0xA2; //
+ value[0] = 0x0F; /* Intra-Compression cycle */
+ value[1] = 0x01; /* Reg.45 one line per strip */
+ value[2] = 0x00; /* Reg.46 Force intra mode on all new frames */
+ value[3] = 0x00; /* Reg.47 FORCE_UP <- 0 normal operation (not force) */
+ value[4] = 0xA2; /* Reg.48 BUF_THR I'm not sure if this does something in not compressed mode. */
+ value[5] = 0x00; /* Reg.49 DVI_YUV This has nothing to do with compression */
+
+ /* catched values for NT1004 */
+ /* value[0] = 0xFF; Never apply intra mode automatically */
+ /* value[1] = 0xF1; Use full frame height for virtual strip width; One line per strip */
+ /* value[2] = 0x01; Force intra mode on all new frames */
+ /* value[3] = 0x00; Strip size 400 Bytes; do not force up */
+ /* value[4] = 0xA2; */
if (!USBVISION_IS_OPERATIONAL(usbvision))
return 0;
@@ -2030,21 +1946,20 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision)
return rc;
}
- if (usbvision->bridgeType == BRIDGE_NT1004) {
- value[0] = 20; // PCM Threshold 1
- value[1] = 12; // PCM Threshold 2
- value[2] = 255; // Distorsion Threshold inter
- value[3] = 255; // Distorsion Threshold intra
- value[4] = 43; // Max Distorsion inter
- value[5] = 43; // Max Distorsion intra
- }
- else {
- value[0] = 20; // PCM Threshold 1
- value[1] = 12; // PCM Threshold 2
- value[2] = 255; // Distorsion Threshold d7-d0
- value[3] = 0; // Distorsion Threshold d11-d8
- value[4] = 43; // Max Distorsion d7-d0
- value[5] = 0; // Max Distorsion d8
+ if (usbvision->bridge_type == BRIDGE_NT1004) {
+ value[0] = 20; /* PCM Threshold 1 */
+ value[1] = 12; /* PCM Threshold 2 */
+ value[2] = 255; /* Distortion Threshold inter */
+ value[3] = 255; /* Distortion Threshold intra */
+ value[4] = 43; /* Max Distortion inter */
+ value[5] = 43; /* Max Distortion intra */
+ } else {
+ value[0] = 20; /* PCM Threshold 1 */
+ value[1] = 12; /* PCM Threshold 2 */
+ value[2] = 255; /* Distortion Threshold d7-d0 */
+ value[3] = 0; /* Distortion Threshold d11-d8 */
+ value[4] = 43; /* Max Distortion d7-d0 */
+ value[5] = 0; /* Max Distortion d8 */
}
if (!USBVISION_IS_OPERATIONAL(usbvision))
@@ -2059,10 +1974,7 @@ static int usbvision_set_compress_params(struct usb_usbvision *usbvision)
if (rc < 0) {
printk(KERN_ERR "%sERROR=%d. USBVISION stopped - "
"reconnect or reload driver.\n", proc, rc);
- return rc;
}
-
-
return rc;
}
@@ -2085,9 +1997,9 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
return 0;
/* Set input format expected from decoder*/
- if (usbvision_device_data[usbvision->DevModel].Vin_Reg1_override) {
- value[0] = usbvision_device_data[usbvision->DevModel].Vin_Reg1;
- } else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
+ if (usbvision_device_data[usbvision->dev_model].vin_reg1_override) {
+ value[0] = usbvision_device_data[usbvision->dev_model].vin_reg1;
+ } else if (usbvision_device_data[usbvision->dev_model].codec == CODEC_SAA7113) {
/* SAA7113 uses 8 bit output */
value[0] = USBVISION_8_422_SYNC;
} else {
@@ -2105,53 +2017,53 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
}
- if (usbvision->tvnormId & V4L2_STD_PAL) {
+ if (usbvision->tvnorm_id & V4L2_STD_PAL) {
value[0] = 0xC0;
- value[1] = 0x02; //0x02C0 -> 704 Input video line length
+ value[1] = 0x02; /* 0x02C0 -> 704 Input video line length */
value[2] = 0x20;
- value[3] = 0x01; //0x0120 -> 288 Input video n. of lines
+ value[3] = 0x01; /* 0x0120 -> 288 Input video n. of lines */
value[4] = 0x60;
- value[5] = 0x00; //0x0060 -> 96 Input video h offset
+ value[5] = 0x00; /* 0x0060 -> 96 Input video h offset */
value[6] = 0x16;
- value[7] = 0x00; //0x0016 -> 22 Input video v offset
- } else if (usbvision->tvnormId & V4L2_STD_SECAM) {
+ value[7] = 0x00; /* 0x0016 -> 22 Input video v offset */
+ } else if (usbvision->tvnorm_id & V4L2_STD_SECAM) {
value[0] = 0xC0;
- value[1] = 0x02; //0x02C0 -> 704 Input video line length
+ value[1] = 0x02; /* 0x02C0 -> 704 Input video line length */
value[2] = 0x20;
- value[3] = 0x01; //0x0120 -> 288 Input video n. of lines
+ value[3] = 0x01; /* 0x0120 -> 288 Input video n. of lines */
value[4] = 0x01;
- value[5] = 0x00; //0x0001 -> 01 Input video h offset
+ value[5] = 0x00; /* 0x0001 -> 01 Input video h offset */
value[6] = 0x01;
- value[7] = 0x00; //0x0001 -> 01 Input video v offset
+ value[7] = 0x00; /* 0x0001 -> 01 Input video v offset */
} else { /* V4L2_STD_NTSC */
value[0] = 0xD0;
- value[1] = 0x02; //0x02D0 -> 720 Input video line length
+ value[1] = 0x02; /* 0x02D0 -> 720 Input video line length */
value[2] = 0xF0;
- value[3] = 0x00; //0x00F0 -> 240 Input video number of lines
+ value[3] = 0x00; /* 0x00F0 -> 240 Input video number of lines */
value[4] = 0x50;
- value[5] = 0x00; //0x0050 -> 80 Input video h offset
+ value[5] = 0x00; /* 0x0050 -> 80 Input video h offset */
value[6] = 0x10;
- value[7] = 0x00; //0x0010 -> 16 Input video v offset
+ value[7] = 0x00; /* 0x0010 -> 16 Input video v offset */
}
- if (usbvision_device_data[usbvision->DevModel].X_Offset >= 0) {
- value[4]=usbvision_device_data[usbvision->DevModel].X_Offset & 0xff;
- value[5]=(usbvision_device_data[usbvision->DevModel].X_Offset & 0x0300) >> 8;
+ if (usbvision_device_data[usbvision->dev_model].x_offset >= 0) {
+ value[4] = usbvision_device_data[usbvision->dev_model].x_offset & 0xff;
+ value[5] = (usbvision_device_data[usbvision->dev_model].x_offset & 0x0300) >> 8;
}
- if (adjust_X_Offset != -1) {
- value[4] = adjust_X_Offset & 0xff;
- value[5] = (adjust_X_Offset & 0x0300) >> 8;
+ if (adjust_x_offset != -1) {
+ value[4] = adjust_x_offset & 0xff;
+ value[5] = (adjust_x_offset & 0x0300) >> 8;
}
- if (usbvision_device_data[usbvision->DevModel].Y_Offset >= 0) {
- value[6]=usbvision_device_data[usbvision->DevModel].Y_Offset & 0xff;
- value[7]=(usbvision_device_data[usbvision->DevModel].Y_Offset & 0x0300) >> 8;
+ if (usbvision_device_data[usbvision->dev_model].y_offset >= 0) {
+ value[6] = usbvision_device_data[usbvision->dev_model].y_offset & 0xff;
+ value[7] = (usbvision_device_data[usbvision->dev_model].y_offset & 0x0300) >> 8;
}
- if (adjust_Y_Offset != -1) {
- value[6] = adjust_Y_Offset & 0xff;
- value[7] = (adjust_Y_Offset & 0x0300) >> 8;
+ if (adjust_y_offset != -1) {
+ value[6] = adjust_y_offset & 0xff;
+ value[7] = (adjust_y_offset & 0x0300) >> 8;
}
rc = usb_control_msg(usbvision->dev, usb_sndctrlpipe(usbvision->dev, 1),
@@ -2167,15 +2079,14 @@ int usbvision_set_input(struct usb_usbvision *usbvision)
dvi_yuv_value = 0x00; /* U comes after V, Ya comes after U/V, Yb comes after Yb */
- if(usbvision_device_data[usbvision->DevModel].Dvi_yuv_override){
- dvi_yuv_value = usbvision_device_data[usbvision->DevModel].Dvi_yuv;
- }
- else if(usbvision_device_data[usbvision->DevModel].Codec == CODEC_SAA7113) {
- /* This changes as the fine sync control changes. Further investigation necessary */
+ if (usbvision_device_data[usbvision->dev_model].dvi_yuv_override) {
+ dvi_yuv_value = usbvision_device_data[usbvision->dev_model].dvi_yuv;
+ } else if (usbvision_device_data[usbvision->dev_model].codec == CODEC_SAA7113) {
+ /* This changes as the fine sync control changes. Further investigation necessary */
dvi_yuv_value = 0x06;
}
- return (usbvision_write_reg(usbvision, USBVISION_DVI_YUV, dvi_yuv_value));
+ return usbvision_write_reg(usbvision, USBVISION_DVI_YUV, dvi_yuv_value);
}
@@ -2192,7 +2103,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
int rc;
unsigned char value[8];
- if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ if (usbvision->isoc_mode == ISOC_MODE_COMPRESS) {
value[0] = 0x42;
value[1] = 0x71;
value[2] = 0xff;
@@ -2201,11 +2112,10 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
value[5] = 0xe0;
value[6] = 0x71;
value[7] = 0xff;
- // UR: 0x0E200-0x3FFFF = 204288 Words (1 Word = 2 Byte)
- // FDL: 0x00000-0x0E099 = 57498 Words
- // VDW: 0x0E3FF-0x3FFFF
- }
- else {
+ /* UR: 0x0E200-0x3FFFF = 204288 Words (1 Word = 2 Byte) */
+ /* FDL: 0x00000-0x0E099 = 57498 Words */
+ /* VDW: 0x0E3FF-0x3FFFF */
+ } else {
value[0] = 0x42;
value[1] = 0x00;
value[2] = 0xff;
@@ -2218,14 +2128,14 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
/* These are the values of the address of the video buffer,
* they have to be loaded into the USBVISION_DRM_PRM1-8
*
- * Start address of video output buffer for read: drm_prm1-2 -> 0x00000
- * End address of video output buffer for read: drm_prm1-3 -> 0x1ffff
- * Start address of video frame delay buffer: drm_prm1-4 -> 0x20000
+ * Start address of video output buffer for read: drm_prm1-2 -> 0x00000
+ * End address of video output buffer for read: drm_prm1-3 -> 0x1ffff
+ * Start address of video frame delay buffer: drm_prm1-4 -> 0x20000
* Only used in compressed mode
- * End address of video frame delay buffer: drm_prm1-5-6 -> 0x3ffff
+ * End address of video frame delay buffer: drm_prm1-5-6 -> 0x3ffff
* Only used in compressed mode
- * Start address of video output buffer for write: drm_prm1-7 -> 0x00000
- * End address of video output buffer for write: drm_prm1-8 -> 0x1ffff
+ * Start address of video output buffer for write: drm_prm1-7 -> 0x00000
+ * End address of video output buffer for write: drm_prm1-8 -> 0x1ffff
*/
if (!USBVISION_IS_OPERATIONAL(usbvision))
@@ -2243,8 +2153,9 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
}
/* Restart the video buffer logic */
- if ((rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, USBVISION_RES_UR |
- USBVISION_RES_FDL | USBVISION_RES_VDW)) < 0)
+ rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, USBVISION_RES_UR |
+ USBVISION_RES_FDL | USBVISION_RES_VDW);
+ if (rc < 0)
return rc;
rc = usbvision_write_reg(usbvision, USBVISION_DRM_CONT, 0x00);
@@ -2261,23 +2172,22 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
int usbvision_power_on(struct usb_usbvision *usbvision)
{
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_FUNC, "");
usbvision_write_reg(usbvision, USBVISION_PWR_REG, USBVISION_SSPND_EN);
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
- USBVISION_SSPND_EN | USBVISION_RES2);
+ USBVISION_SSPND_EN | USBVISION_RES2);
usbvision_write_reg(usbvision, USBVISION_PWR_REG,
- USBVISION_SSPND_EN | USBVISION_PWR_VID);
- errCode = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
- USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
- if (errCode == 1) {
+ USBVISION_SSPND_EN | USBVISION_PWR_VID);
+ err_code = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_PWR_VID | USBVISION_RES2);
+ if (err_code == 1)
usbvision->power = 1;
- }
- PDEBUG(DBG_FUNC, "%s: errCode %d", (errCode<0)?"ERROR":"power is on", errCode);
- return errCode;
+ PDEBUG(DBG_FUNC, "%s: err_code %d", (err_code < 0) ? "ERROR" : "power is on", err_code);
+ return err_code;
}
@@ -2285,53 +2195,50 @@ int usbvision_power_on(struct usb_usbvision *usbvision)
* usbvision timer stuff
*/
-// to call usbvision_power_off from task queue
+/* to call usbvision_power_off from task queue */
static void call_usbvision_power_off(struct work_struct *work)
{
- struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, powerOffWork);
+ struct usb_usbvision *usbvision = container_of(work, struct usb_usbvision, power_off_work);
PDEBUG(DBG_FUNC, "");
- if(mutex_lock_interruptible(&usbvision->lock)) {
+ if (mutex_lock_interruptible(&usbvision->v4l2_lock))
return;
- }
-
- if(usbvision->user == 0) {
+ if (usbvision->user == 0) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
usbvision->initialized = 0;
}
- mutex_unlock(&usbvision->lock);
+ mutex_unlock(&usbvision->v4l2_lock);
}
-static void usbvision_powerOffTimer(unsigned long data)
+static void usbvision_power_off_timer(unsigned long data)
{
- struct usb_usbvision *usbvision = (void *) data;
+ struct usb_usbvision *usbvision = (void *)data;
PDEBUG(DBG_FUNC, "");
- del_timer(&usbvision->powerOffTimer);
- INIT_WORK(&usbvision->powerOffWork, call_usbvision_power_off);
- (void) schedule_work(&usbvision->powerOffWork);
+ del_timer(&usbvision->power_off_timer);
+ INIT_WORK(&usbvision->power_off_work, call_usbvision_power_off);
+ (void) schedule_work(&usbvision->power_off_work);
}
-void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision)
+void usbvision_init_power_off_timer(struct usb_usbvision *usbvision)
{
- init_timer(&usbvision->powerOffTimer);
- usbvision->powerOffTimer.data = (long) usbvision;
- usbvision->powerOffTimer.function = usbvision_powerOffTimer;
+ init_timer(&usbvision->power_off_timer);
+ usbvision->power_off_timer.data = (long)usbvision;
+ usbvision->power_off_timer.function = usbvision_power_off_timer;
}
-void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision)
+void usbvision_set_power_off_timer(struct usb_usbvision *usbvision)
{
- mod_timer(&usbvision->powerOffTimer, jiffies + USBVISION_POWEROFF_TIME);
+ mod_timer(&usbvision->power_off_timer, jiffies + USBVISION_POWEROFF_TIME);
}
-void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision)
+void usbvision_reset_power_off_timer(struct usb_usbvision *usbvision)
{
- if (timer_pending(&usbvision->powerOffTimer)) {
- del_timer(&usbvision->powerOffTimer);
- }
+ if (timer_pending(&usbvision->power_off_timer))
+ del_timer(&usbvision->power_off_timer);
}
/*
@@ -2341,14 +2248,10 @@ void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision)
*/
int usbvision_begin_streaming(struct usb_usbvision *usbvision)
{
- int errCode = 0;
-
- if (usbvision->isocMode == ISOC_MODE_COMPRESS) {
+ if (usbvision->isoc_mode == ISOC_MODE_COMPRESS)
usbvision_init_compression(usbvision);
- }
- errCode = usbvision_write_reg(usbvision, USBVISION_VIN_REG2, USBVISION_NOHVALID |
- usbvision->Vin_Reg2_Preset);
- return errCode;
+ return usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+ USBVISION_NOHVALID | usbvision->vin_reg2_preset);
}
/*
@@ -2360,25 +2263,24 @@ int usbvision_restart_isoc(struct usb_usbvision *usbvision)
{
int ret;
- if (
- (ret =
- usbvision_write_reg(usbvision, USBVISION_PWR_REG,
- USBVISION_SSPND_EN | USBVISION_PWR_VID)) < 0)
+ ret = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ USBVISION_SSPND_EN | USBVISION_PWR_VID);
+ if (ret < 0)
return ret;
- if (
- (ret =
- usbvision_write_reg(usbvision, USBVISION_PWR_REG,
+ ret = usbvision_write_reg(usbvision, USBVISION_PWR_REG,
USBVISION_SSPND_EN | USBVISION_PWR_VID |
- USBVISION_RES2)) < 0)
+ USBVISION_RES2);
+ if (ret < 0)
return ret;
- if (
- (ret =
- usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
+ ret = usbvision_write_reg(usbvision, USBVISION_VIN_REG2,
USBVISION_KEEP_BLANK | USBVISION_NOHVALID |
- usbvision->Vin_Reg2_Preset)) < 0) return ret;
+ usbvision->vin_reg2_preset);
+ if (ret < 0)
+ return ret;
/* TODO: schedule timeout */
- while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) & 0x01) != 1);
+ while ((usbvision_read_reg(usbvision, USBVISION_STATUS_REG) & 0x01) != 1)
+ ;
return 0;
}
@@ -2386,27 +2288,27 @@ int usbvision_restart_isoc(struct usb_usbvision *usbvision)
int usbvision_audio_off(struct usb_usbvision *usbvision)
{
if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, USBVISION_AUDIO_MUTE) < 0) {
- printk(KERN_ERR "usbvision_audio_off: can't wirte reg\n");
+ printk(KERN_ERR "usbvision_audio_off: can't write reg\n");
return -1;
}
- usbvision->AudioMute = 0;
- usbvision->AudioChannel = USBVISION_AUDIO_MUTE;
+ usbvision->audio_mute = 0;
+ usbvision->audio_channel = USBVISION_AUDIO_MUTE;
return 0;
}
-int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel)
+int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel)
{
- if (!usbvision->AudioMute) {
- if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, AudioChannel) < 0) {
+ if (!usbvision->audio_mute) {
+ if (usbvision_write_reg(usbvision, USBVISION_IOPIN_REG, audio_channel) < 0) {
printk(KERN_ERR "usbvision_set_audio: can't write iopin register for audio switching\n");
return -1;
}
}
- usbvision->AudioChannel = AudioChannel;
+ usbvision->audio_channel = audio_channel;
return 0;
}
-int usbvision_setup(struct usb_usbvision *usbvision,int format)
+int usbvision_setup(struct usb_usbvision *usbvision, int format)
{
usbvision_set_video_format(usbvision, format);
usbvision_set_dram_settings(usbvision);
@@ -2421,27 +2323,28 @@ int usbvision_setup(struct usb_usbvision *usbvision,int format)
int usbvision_set_alternate(struct usb_usbvision *dev)
{
- int errCode, prev_alt = dev->ifaceAlt;
+ int err_code, prev_alt = dev->iface_alt;
int i;
- dev->ifaceAlt=0;
- for(i=0;i< dev->num_alt; i++)
- if(dev->alt_max_pkt_size[i]>dev->alt_max_pkt_size[dev->ifaceAlt])
- dev->ifaceAlt=i;
-
- if (dev->ifaceAlt != prev_alt) {
- dev->isocPacketSize = dev->alt_max_pkt_size[dev->ifaceAlt];
- PDEBUG(DBG_FUNC,"setting alternate %d with wMaxPacketSize=%u", dev->ifaceAlt,dev->isocPacketSize);
- errCode = usb_set_interface(dev->dev, dev->iface, dev->ifaceAlt);
- if (errCode < 0) {
+ dev->iface_alt = 0;
+ for (i = 0; i < dev->num_alt; i++)
+ if (dev->alt_max_pkt_size[i] > dev->alt_max_pkt_size[dev->iface_alt])
+ dev->iface_alt = i;
+
+ if (dev->iface_alt != prev_alt) {
+ dev->isoc_packet_size = dev->alt_max_pkt_size[dev->iface_alt];
+ PDEBUG(DBG_FUNC, "setting alternate %d with max_packet_size=%u",
+ dev->iface_alt, dev->isoc_packet_size);
+ err_code = usb_set_interface(dev->dev, dev->iface, dev->iface_alt);
+ if (err_code < 0) {
dev_err(&dev->dev->dev,
"cannot change alternate number to %d (error=%i)\n",
- dev->ifaceAlt, errCode);
- return errCode;
+ dev->iface_alt, err_code);
+ return err_code;
}
}
- PDEBUG(DBG_ISOC, "ISO Packet Length:%d", dev->isocPacketSize);
+ PDEBUG(DBG_ISOC, "ISO Packet Length:%d", dev->isoc_packet_size);
return 0;
}
@@ -2453,27 +2356,27 @@ int usbvision_set_alternate(struct usb_usbvision *dev)
int usbvision_init_isoc(struct usb_usbvision *usbvision)
{
struct usb_device *dev = usbvision->dev;
- int bufIdx, errCode, regValue;
+ int buf_idx, err_code, reg_value;
int sb_size;
if (!USBVISION_IS_OPERATIONAL(usbvision))
return -EFAULT;
- usbvision->curFrame = NULL;
+ usbvision->cur_frame = NULL;
scratch_reset(usbvision);
/* Alternate interface 1 is is the biggest frame size */
- errCode = usbvision_set_alternate(usbvision);
- if (errCode < 0) {
- usbvision->last_error = errCode;
+ err_code = usbvision_set_alternate(usbvision);
+ if (err_code < 0) {
+ usbvision->last_error = err_code;
return -EBUSY;
}
- sb_size = USBVISION_URB_FRAMES * usbvision->isocPacketSize;
+ sb_size = USBVISION_URB_FRAMES * usbvision->isoc_packet_size;
- regValue = (16 - usbvision_read_reg(usbvision,
+ reg_value = (16 - usbvision_read_reg(usbvision,
USBVISION_ALTER_REG)) & 0x0F;
- usbvision->usb_bandwidth = regValue >> 1;
+ usbvision->usb_bandwidth = reg_value >> 1;
PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec",
usbvision->usb_bandwidth);
@@ -2481,7 +2384,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
/* We double buffer the Iso lists */
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
+ for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) {
int j, k;
struct urb *urb;
@@ -2491,8 +2394,8 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
"%s: usb_alloc_urb() failed\n", __func__);
return -ENOMEM;
}
- usbvision->sbuf[bufIdx].urb = urb;
- usbvision->sbuf[bufIdx].data =
+ usbvision->sbuf[buf_idx].urb = urb;
+ usbvision->sbuf[buf_idx].data =
usb_alloc_coherent(usbvision->dev,
sb_size,
GFP_KERNEL,
@@ -2502,31 +2405,31 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
urb->pipe = usb_rcvisocpipe(dev, usbvision->video_endp);
urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
urb->interval = 1;
- urb->transfer_buffer = usbvision->sbuf[bufIdx].data;
- urb->complete = usbvision_isocIrq;
+ urb->transfer_buffer = usbvision->sbuf[buf_idx].data;
+ urb->complete = usbvision_isoc_irq;
urb->number_of_packets = USBVISION_URB_FRAMES;
urb->transfer_buffer_length =
- usbvision->isocPacketSize * USBVISION_URB_FRAMES;
+ usbvision->isoc_packet_size * USBVISION_URB_FRAMES;
for (j = k = 0; j < USBVISION_URB_FRAMES; j++,
- k += usbvision->isocPacketSize) {
+ k += usbvision->isoc_packet_size) {
urb->iso_frame_desc[j].offset = k;
urb->iso_frame_desc[j].length =
- usbvision->isocPacketSize;
+ usbvision->isoc_packet_size;
}
}
/* Submit all URBs */
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
- errCode = usb_submit_urb(usbvision->sbuf[bufIdx].urb,
+ for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) {
+ err_code = usb_submit_urb(usbvision->sbuf[buf_idx].urb,
GFP_KERNEL);
- if (errCode) {
+ if (err_code) {
dev_err(&usbvision->dev->dev,
"%s: usb_submit_urb(%d) failed: error %d\n",
- __func__, bufIdx, errCode);
+ __func__, buf_idx, err_code);
}
}
- usbvision->streaming = Stream_Idle;
+ usbvision->streaming = stream_idle;
PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x",
__func__,
usbvision->video_endp);
@@ -2542,47 +2445,46 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
*/
void usbvision_stop_isoc(struct usb_usbvision *usbvision)
{
- int bufIdx, errCode, regValue;
- int sb_size = USBVISION_URB_FRAMES * usbvision->isocPacketSize;
+ int buf_idx, err_code, reg_value;
+ int sb_size = USBVISION_URB_FRAMES * usbvision->isoc_packet_size;
- if ((usbvision->streaming == Stream_Off) || (usbvision->dev == NULL))
+ if ((usbvision->streaming == stream_off) || (usbvision->dev == NULL))
return;
/* Unschedule all of the iso td's */
- for (bufIdx = 0; bufIdx < USBVISION_NUMSBUF; bufIdx++) {
- usb_kill_urb(usbvision->sbuf[bufIdx].urb);
- if (usbvision->sbuf[bufIdx].data){
+ for (buf_idx = 0; buf_idx < USBVISION_NUMSBUF; buf_idx++) {
+ usb_kill_urb(usbvision->sbuf[buf_idx].urb);
+ if (usbvision->sbuf[buf_idx].data) {
usb_free_coherent(usbvision->dev,
sb_size,
- usbvision->sbuf[bufIdx].data,
- usbvision->sbuf[bufIdx].urb->transfer_dma);
+ usbvision->sbuf[buf_idx].data,
+ usbvision->sbuf[buf_idx].urb->transfer_dma);
}
- usb_free_urb(usbvision->sbuf[bufIdx].urb);
- usbvision->sbuf[bufIdx].urb = NULL;
+ usb_free_urb(usbvision->sbuf[buf_idx].urb);
+ usbvision->sbuf[buf_idx].urb = NULL;
}
- PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __func__);
- usbvision->streaming = Stream_Off;
+ PDEBUG(DBG_ISOC, "%s: streaming=stream_off\n", __func__);
+ usbvision->streaming = stream_off;
if (!usbvision->remove_pending) {
-
/* Set packet size to 0 */
- usbvision->ifaceAlt=0;
- errCode = usb_set_interface(usbvision->dev, usbvision->iface,
- usbvision->ifaceAlt);
- if (errCode < 0) {
+ usbvision->iface_alt = 0;
+ err_code = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->iface_alt);
+ if (err_code < 0) {
dev_err(&usbvision->dev->dev,
"%s: usb_set_interface() failed: error %d\n",
- __func__, errCode);
- usbvision->last_error = errCode;
+ __func__, err_code);
+ usbvision->last_error = err_code;
}
- regValue = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
- usbvision->isocPacketSize =
- (regValue == 0) ? 0 : (regValue * 64) - 1;
+ reg_value = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
+ usbvision->isoc_packet_size =
+ (reg_value == 0) ? 0 : (reg_value * 64) - 1;
PDEBUG(DBG_ISOC, "ISO Packet Length:%d",
- usbvision->isocPacketSize);
+ usbvision->isoc_packet_size);
- usbvision->usb_bandwidth = regValue >> 1;
+ usbvision->usb_bandwidth = reg_value >> 1;
PDEBUG(DBG_ISOC, "USB Bandwidth Usage: %dMbit/Sec",
usbvision->usb_bandwidth);
}
@@ -2592,39 +2494,38 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel)
{
/* inputs #0 and #3 are constant for every SAA711x. */
/* inputs #1 and #2 are variable for SAA7111 and SAA7113 */
- int mode[4]= {SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3};
- int audio[]= {1, 0, 0, 0};
- //channel 0 is TV with audiochannel 1 (tuner mono)
- //channel 1 is Composite with audio channel 0 (line in)
- //channel 2 is S-Video with audio channel 0 (line in)
- //channel 3 is additional video inputs to the device with audio channel 0 (line in)
+ int mode[4] = { SAA7115_COMPOSITE0, 0, 0, SAA7115_COMPOSITE3 };
+ int audio[] = { 1, 0, 0, 0 };
+ /* channel 0 is TV with audiochannel 1 (tuner mono) */
+ /* channel 1 is Composite with audio channel 0 (line in) */
+ /* channel 2 is S-Video with audio channel 0 (line in) */
+ /* channel 3 is additional video inputs to the device with audio channel 0 (line in) */
RESTRICT_TO_RANGE(channel, 0, usbvision->video_inputs);
usbvision->ctl_input = channel;
- // set the new channel
- // Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video
- // Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red
-
- switch (usbvision_device_data[usbvision->DevModel].Codec) {
- case CODEC_SAA7113:
- mode[1] = SAA7115_COMPOSITE2;
- if (SwitchSVideoInput) {
- /* To handle problems with S-Video Input for
- * some devices. Use SwitchSVideoInput
- * parameter when loading the module.*/
- mode[2] = SAA7115_COMPOSITE1;
- }
- else {
- mode[2] = SAA7115_SVIDEO1;
- }
- break;
- case CODEC_SAA7111:
- default:
- /* modes for saa7111 */
- mode[1] = SAA7115_COMPOSITE1;
+ /* set the new channel */
+ /* Regular USB TV Tuners -> channel: 0 = Television, 1 = Composite, 2 = S-Video */
+ /* Four video input devices -> channel: 0 = Chan White, 1 = Chan Green, 2 = Chan Yellow, 3 = Chan Red */
+
+ switch (usbvision_device_data[usbvision->dev_model].codec) {
+ case CODEC_SAA7113:
+ mode[1] = SAA7115_COMPOSITE2;
+ if (switch_svideo_input) {
+ /* To handle problems with S-Video Input for
+ * some devices. Use switch_svideo_input
+ * parameter when loading the module.*/
+ mode[2] = SAA7115_COMPOSITE1;
+ } else {
mode[2] = SAA7115_SVIDEO1;
- break;
+ }
+ break;
+ case CODEC_SAA7111:
+ default:
+ /* modes for saa7111 */
+ mode[1] = SAA7115_COMPOSITE1;
+ mode[2] = SAA7115_SVIDEO1;
+ break;
}
call_all(usbvision, video, s_routing, mode[channel], 0, 0);
usbvision_set_audio(usbvision, audio[channel]);
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index 42ba28785750..05b1344181cd 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -28,18 +28,18 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/init.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
#include <linux/ioport.h>
#include <linux/errno.h>
#include <linux/usb.h>
#include <linux/i2c.h>
#include "usbvision.h"
-#define DBG_I2C 1<<0
+#define DBG_I2C (1 << 0)
static int i2c_debug;
-module_param (i2c_debug, int, 0644); // debug_i2c_usb mode of the device driver
+module_param(i2c_debug, int, 0644); /* debug_i2c_usb mode of the device driver */
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
#define PDEBUG(level, fmt, args...) { \
@@ -72,8 +72,8 @@ static inline int try_write_address(struct i2c_adapter *i2c_adap,
udelay(10);
}
if (i) {
- PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr);
- PDEBUG(DBG_I2C,"Maybe there's no device at this address");
+ PDEBUG(DBG_I2C, "Needed %d retries for address %#2x", i, addr);
+ PDEBUG(DBG_I2C, "Maybe there's no device at this address");
}
return ret;
}
@@ -96,8 +96,8 @@ static inline int try_read_address(struct i2c_adapter *i2c_adap,
udelay(10);
}
if (i) {
- PDEBUG(DBG_I2C,"Needed %d retries for address %#2x", i, addr);
- PDEBUG(DBG_I2C,"Maybe there's no device at this address");
+ PDEBUG(DBG_I2C, "Needed %d retries for address %#2x", i, addr);
+ PDEBUG(DBG_I2C, "Maybe there's no device at this address");
}
return ret;
}
@@ -143,9 +143,8 @@ static inline int usb_find_address(struct i2c_adapter *i2c_adap,
else
ret = try_write_address(i2c_adap, addr, retries);
- if (ret != 1) {
+ if (ret != 1)
return -EREMOTEIO;
- }
}
return 0;
}
@@ -164,22 +163,20 @@ usbvision_i2c_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
pmsg = &msgs[i];
ret = usb_find_address(i2c_adap, pmsg, i2c_adap->retries, &addr);
if (ret != 0) {
- PDEBUG(DBG_I2C,"got NAK from device, message #%d", i);
+ PDEBUG(DBG_I2C, "got NAK from device, message #%d", i);
return (ret < 0) ? ret : -EREMOTEIO;
}
if (pmsg->flags & I2C_M_RD) {
/* read bytes into buffer */
ret = (usbvision_i2c_read(usbvision, addr, pmsg->buf, pmsg->len));
- if (ret < pmsg->len) {
+ if (ret < pmsg->len)
return (ret < 0) ? ret : -EREMOTEIO;
- }
} else {
/* write bytes from buffer */
ret = (usbvision_i2c_write(usbvision, addr, pmsg->buf, pmsg->len));
- if (ret < pmsg->len) {
+ if (ret < pmsg->len)
return (ret < 0) ? ret : -EREMOTEIO;
- }
}
}
return num;
@@ -211,12 +208,15 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
0x42 >> 1, 0x40 >> 1, /* SAA7114, SAA7115 and SAA7118 */
I2C_CLIENT_END };
+ if (usbvision->registered_i2c)
+ return 0;
+
memcpy(&usbvision->i2c_adap, &i2c_adap_template,
sizeof(struct i2c_adapter));
sprintf(usbvision->i2c_adap.name, "%s-%d-%s", i2c_adap_template.name,
usbvision->dev->bus->busnum, usbvision->dev->devpath);
- PDEBUG(DBG_I2C,"Adaptername: %s", usbvision->i2c_adap.name);
+ PDEBUG(DBG_I2C, "Adaptername: %s", usbvision->i2c_adap.name);
usbvision->i2c_adap.dev.parent = &usbvision->dev->dev;
i2c_set_adapdata(&usbvision->i2c_adap, &usbvision->v4l2_dev);
@@ -241,33 +241,35 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
PDEBUG(DBG_I2C, "i2c bus for %s registered", usbvision->i2c_adap.name);
/* Request the load of the i2c modules we need */
- switch (usbvision_device_data[usbvision->DevModel].Codec) {
+ switch (usbvision_device_data[usbvision->dev_model].codec) {
case CODEC_SAA7113:
case CODEC_SAA7111:
/* Without this delay the detection of the saa711x is
hit-and-miss. */
mdelay(10);
v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, "saa7115",
+ &usbvision->i2c_adap,
"saa7115_auto", 0, saa711x_addrs);
break;
}
- if (usbvision_device_data[usbvision->DevModel].Tuner == 1) {
+ if (usbvision_device_data[usbvision->dev_model].tuner == 1) {
struct v4l2_subdev *sd;
enum v4l2_i2c_tuner_type type;
struct tuner_setup tun_setup;
sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, "tuner",
+ &usbvision->i2c_adap,
"tuner", 0, v4l2_i2c_tuner_addrs(ADDRS_DEMOD));
/* depending on whether we found a demod or not, select
the tuner type. */
type = sd ? ADDRS_TV_WITH_DEMOD : ADDRS_TV;
sd = v4l2_i2c_new_subdev(&usbvision->v4l2_dev,
- &usbvision->i2c_adap, "tuner",
+ &usbvision->i2c_adap,
"tuner", 0, v4l2_i2c_tuner_addrs(type));
+ if (sd == NULL)
+ return -ENODEV;
if (usbvision->tuner_type != -1) {
tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
tun_setup.type = usbvision->tuner_type;
@@ -275,16 +277,20 @@ int usbvision_i2c_register(struct usb_usbvision *usbvision)
call_all(usbvision, tuner, s_type_addr, &tun_setup);
}
}
+ usbvision->registered_i2c = 1;
return 0;
}
int usbvision_i2c_unregister(struct usb_usbvision *usbvision)
{
+ if (!usbvision->registered_i2c)
+ return 0;
i2c_del_adapter(&(usbvision->i2c_adap));
+ usbvision->registered_i2c = 0;
- PDEBUG(DBG_I2C,"i2c bus for %s unregistered", usbvision->i2c_adap.name);
+ PDEBUG(DBG_I2C, "i2c bus for %s unregistered", usbvision->i2c_adap.name);
return 0;
}
@@ -346,9 +352,9 @@ usbvision_i2c_read_max4(struct usb_usbvision *usbvision, unsigned char addr,
if (i2c_debug & DBG_I2C) {
int idx;
- for (idx = 0; idx < len; idx++) {
- PDEBUG(DBG_I2C,"read %x from address %x", (unsigned char)buf[idx], addr);
- }
+
+ for (idx = 0; idx < len; idx++)
+ PDEBUG(DBG_I2C, "read %x from address %x", (unsigned char)buf[idx], addr);
}
return len;
}
@@ -407,9 +413,9 @@ static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision,
if (i2c_debug & DBG_I2C) {
int idx;
- for (idx = 0; idx < len; idx++) {
- PDEBUG(DBG_I2C,"wrote %x at address %x", (unsigned char)buf[idx], addr);
- }
+
+ for (idx = 0; idx < len; idx++)
+ PDEBUG(DBG_I2C, "wrote %x at address %x", (unsigned char)buf[idx], addr);
}
return len;
}
@@ -417,18 +423,18 @@ static int usbvision_i2c_write_max4(struct usb_usbvision *usbvision,
static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
short len)
{
- char *bufPtr = buf;
+ char *buf_ptr = buf;
int retval;
int wrcount = 0;
int count;
- int maxLen = 4;
+ int max_len = 4;
while (len > 0) {
- count = (len > maxLen) ? maxLen : len;
- retval = usbvision_i2c_write_max4(usbvision, addr, bufPtr, count);
+ count = (len > max_len) ? max_len : len;
+ retval = usbvision_i2c_write_max4(usbvision, addr, buf_ptr, count);
if (retval > 0) {
len -= count;
- bufPtr += count;
+ buf_ptr += count;
wrcount += count;
} else
return (retval < 0) ? retval : -EFAULT;
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index 6248a639ba2d..6083137f0bf8 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -50,14 +50,13 @@
#include <linux/list.h>
#include <linux/timer.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/mm.h>
#include <linux/highmem.h>
#include <linux/vmalloc.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/spinlock.h>
-#include <asm/io.h>
+#include <linux/io.h>
#include <linux/videodev2.h>
#include <linux/i2c.h>
@@ -71,8 +70,8 @@
#include "usbvision.h"
#include "usbvision-cards.h"
-#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>,\
- Dwaine Garden <DwaineGarden@rogers.com>"
+#define DRIVER_AUTHOR "Joerg Heckenbach <joerg@heckenbach-aw.de>, \
+Dwaine Garden <DwaineGarden@rogers.com>"
#define DRIVER_NAME "usbvision"
#define DRIVER_ALIAS "USBVision"
#define DRIVER_DESC "USBVision USB Video Device Driver for Linux"
@@ -83,9 +82,9 @@
#define USBVISION_DRIVER_VERSION KERNEL_VERSION(USBVISION_DRIVER_VERSION_MAJOR,\
USBVISION_DRIVER_VERSION_MINOR,\
USBVISION_DRIVER_VERSION_PATCHLEVEL)
-#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR)\
- "." __stringify(USBVISION_DRIVER_VERSION_MINOR)\
- "." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
+#define USBVISION_VERSION_STRING __stringify(USBVISION_DRIVER_VERSION_MAJOR) \
+"." __stringify(USBVISION_DRIVER_VERSION_MINOR) \
+"." __stringify(USBVISION_DRIVER_VERSION_PATCHLEVEL)
#define ENABLE_HEXDUMP 0 /* Enable if you need it */
@@ -97,16 +96,16 @@ USBVISION_DRIVER_VERSION_PATCHLEVEL)
__func__, __LINE__ , ## args); \
}
#else
- #define PDEBUG(level, fmt, args...) do {} while(0)
+ #define PDEBUG(level, fmt, args...) do {} while (0)
#endif
-#define DBG_IO 1<<1
-#define DBG_PROBE 1<<2
-#define DBG_MMAP 1<<3
+#define DBG_IO (1 << 1)
+#define DBG_PROBE (1 << 2)
+#define DBG_MMAP (1 << 3)
-//String operations
-#define rmspace(str) while(*str==' ') str++;
-#define goto2next(str) while(*str!=' ') str++; while(*str==' ') str++;
+/* String operations */
+#define rmspace(str) while (*str == ' ') str++;
+#define goto2next(str) while (*str != ' ') str++; while (*str == ' ') str++;
/* sequential number of usbvision device */
@@ -119,7 +118,7 @@ static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 4, 32, V4L2_PIX_FMT_RGB32 , "RGB32" },
{ 1, 2, 16, V4L2_PIX_FMT_RGB555 , "RGB555" },
{ 1, 2, 16, V4L2_PIX_FMT_YUYV , "YUV422" },
- { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, // 1.5 !
+ { 1, 2, 12, V4L2_PIX_FMT_YVU420 , "YUV420P" }, /* 1.5 ! */
{ 1, 2, 16, V4L2_PIX_FMT_YUV422P , "YUV422P" }
};
@@ -128,11 +127,11 @@ static void usbvision_release(struct usb_usbvision *usbvision);
/* Default initialization of device driver parameters */
/* Set the default format for ISOC endpoint */
-static int isocMode = ISOC_MODE_COMPRESS;
+static int isoc_mode = ISOC_MODE_COMPRESS;
/* Set the default Debug Mode of the device driver */
static int video_debug;
/* Set the default device to power on at startup */
-static int PowerOnAtOpen = 1;
+static int power_on_at_open = 1;
/* Sequential Number of Video Device */
static int video_nr = -1;
/* Sequential Number of Radio Device */
@@ -141,20 +140,20 @@ static int radio_nr = -1;
/* Grab parameters for the device driver */
/* Showing parameters under SYSFS */
-module_param(isocMode, int, 0444);
+module_param(isoc_mode, int, 0444);
module_param(video_debug, int, 0444);
-module_param(PowerOnAtOpen, int, 0444);
+module_param(power_on_at_open, int, 0444);
module_param(video_nr, int, 0444);
module_param(radio_nr, int, 0444);
-MODULE_PARM_DESC(isocMode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
+MODULE_PARM_DESC(isoc_mode, " Set the default format for ISOC endpoint. Default: 0x60 (Compression On)");
MODULE_PARM_DESC(video_debug, " Set the default Debug Mode of the device driver. Default: 0 (Off)");
-MODULE_PARM_DESC(PowerOnAtOpen, " Set the default device to power on when device is opened. Default: 1 (On)");
+MODULE_PARM_DESC(power_on_at_open, " Set the default device to power on when device is opened. Default: 1 (On)");
MODULE_PARM_DESC(video_nr, "Set video device number (/dev/videoX). Default: -1 (autodetect)");
MODULE_PARM_DESC(radio_nr, "Set radio device number (/dev/radioX). Default: -1 (autodetect)");
-// Misc stuff
+/* Misc stuff */
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
MODULE_LICENSE(DRIVER_LICENSE);
@@ -193,7 +192,7 @@ static ssize_t show_model(struct device *cd,
container_of(cd, struct video_device, dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
- usbvision_device_data[usbvision->DevModel].ModelString);
+ usbvision_device_data[usbvision->dev_model].model_string);
}
static DEVICE_ATTR(model, S_IRUGO, show_model, NULL);
@@ -206,7 +205,7 @@ static ssize_t show_hue(struct device *cd,
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_HUE;
ctrl.value = 0;
- if(usbvision->user)
+ if (usbvision->user)
call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
@@ -221,7 +220,7 @@ static ssize_t show_contrast(struct device *cd,
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_CONTRAST;
ctrl.value = 0;
- if(usbvision->user)
+ if (usbvision->user)
call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
@@ -236,7 +235,7 @@ static ssize_t show_brightness(struct device *cd,
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_BRIGHTNESS;
ctrl.value = 0;
- if(usbvision->user)
+ if (usbvision->user)
call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
@@ -251,7 +250,7 @@ static ssize_t show_saturation(struct device *cd,
struct v4l2_control ctrl;
ctrl.id = V4L2_CID_SATURATION;
ctrl.value = 0;
- if(usbvision->user)
+ if (usbvision->user)
call_all(usbvision, core, g_ctrl, &ctrl);
return sprintf(buf, "%d\n", ctrl.value);
}
@@ -264,7 +263,7 @@ static ssize_t show_streaming(struct device *cd,
container_of(cd, struct video_device, dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
- YES_NO(usbvision->streaming==Stream_On?1:0));
+ YES_NO(usbvision->streaming == stream_on ? 1 : 0));
}
static DEVICE_ATTR(streaming, S_IRUGO, show_streaming, NULL);
@@ -275,7 +274,7 @@ static ssize_t show_compression(struct device *cd,
container_of(cd, struct video_device, dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
return sprintf(buf, "%s\n",
- YES_NO(usbvision->isocMode==ISOC_MODE_COMPRESS));
+ YES_NO(usbvision->isoc_mode == ISOC_MODE_COMPRESS));
}
static DEVICE_ATTR(compression, S_IRUGO, show_compression, NULL);
@@ -285,42 +284,43 @@ static ssize_t show_device_bridge(struct device *cd,
struct video_device *vdev =
container_of(cd, struct video_device, dev);
struct usb_usbvision *usbvision = video_get_drvdata(vdev);
- return sprintf(buf, "%d\n", usbvision->bridgeType);
+ return sprintf(buf, "%d\n", usbvision->bridge_type);
}
static DEVICE_ATTR(bridge, S_IRUGO, show_device_bridge, NULL);
static void usbvision_create_sysfs(struct video_device *vdev)
{
int res;
+
if (!vdev)
return;
do {
res = device_create_file(&vdev->dev, &dev_attr_version);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_model);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_hue);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_contrast);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_brightness);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_saturation);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_streaming);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_compression);
- if (res<0)
+ if (res < 0)
break;
res = device_create_file(&vdev->dev, &dev_attr_bridge);
- if (res>=0)
+ if (res >= 0)
return;
} while (0);
@@ -353,24 +353,23 @@ static void usbvision_remove_sysfs(struct video_device *vdev)
static int usbvision_v4l2_open(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_IO, "open");
- lock_kernel();
- usbvision_reset_powerOffTimer(usbvision);
+ usbvision_reset_power_off_timer(usbvision);
if (usbvision->user)
- errCode = -EBUSY;
+ err_code = -EBUSY;
else {
/* Allocate memory for the scratch ring buffer */
- errCode = usbvision_scratch_alloc(usbvision);
- if (isocMode==ISOC_MODE_COMPRESS) {
+ err_code = usbvision_scratch_alloc(usbvision);
+ if (isoc_mode == ISOC_MODE_COMPRESS) {
/* Allocate intermediate decompression buffers
only if needed */
- errCode = usbvision_decompress_alloc(usbvision);
+ err_code = usbvision_decompress_alloc(usbvision);
}
- if (errCode) {
+ if (err_code) {
/* Deallocate all buffers if trouble */
usbvision_scratch_free(usbvision);
usbvision_decompress_free(usbvision);
@@ -378,8 +377,7 @@ static int usbvision_v4l2_open(struct file *file)
}
/* If so far no errors then we shall start the camera */
- if (!errCode) {
- mutex_lock(&usbvision->lock);
+ if (!err_code) {
if (usbvision->power == 0) {
usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
@@ -388,35 +386,33 @@ static int usbvision_v4l2_open(struct file *file)
/* Send init sequence only once, it's large! */
if (!usbvision->initialized) {
int setup_ok = 0;
- setup_ok = usbvision_setup(usbvision,isocMode);
+ setup_ok = usbvision_setup(usbvision, isoc_mode);
if (setup_ok)
usbvision->initialized = 1;
else
- errCode = -EBUSY;
+ err_code = -EBUSY;
}
- if (!errCode) {
+ if (!err_code) {
usbvision_begin_streaming(usbvision);
- errCode = usbvision_init_isoc(usbvision);
+ err_code = usbvision_init_isoc(usbvision);
/* device must be initialized before isoc transfer */
- usbvision_muxsel(usbvision,0);
+ usbvision_muxsel(usbvision, 0);
usbvision->user++;
} else {
- if (PowerOnAtOpen) {
+ if (power_on_at_open) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
usbvision->initialized = 0;
}
}
- mutex_unlock(&usbvision->lock);
}
/* prepare queues */
usbvision_empty_framequeues(usbvision);
PDEBUG(DBG_IO, "success");
- unlock_kernel();
- return errCode;
+ return err_code;
}
/*
@@ -432,7 +428,6 @@ static int usbvision_v4l2_close(struct file *file)
struct usb_usbvision *usbvision = video_drvdata(file);
PDEBUG(DBG_IO, "close");
- mutex_lock(&usbvision->lock);
usbvision_audio_off(usbvision);
usbvision_restart_isoc(usbvision);
@@ -445,15 +440,13 @@ static int usbvision_v4l2_close(struct file *file)
usbvision->user--;
- if (PowerOnAtOpen) {
+ if (power_on_at_open) {
/* power off in a little while
to avoid off/on every close/open short sequences */
- usbvision_set_powerOffTimer(usbvision);
+ usbvision_set_power_off_timer(usbvision);
usbvision->initialized = 0;
}
- mutex_unlock(&usbvision->lock);
-
if (usbvision->remove_pending) {
printk(KERN_INFO "%s: Final disconnect\n", __func__);
usbvision_release(usbvision);
@@ -471,55 +464,55 @@ static int usbvision_v4l2_close(struct file *file)
*
*/
#ifdef CONFIG_VIDEO_ADV_DEBUG
-static int vidioc_g_register (struct file *file, void *priv,
+static int vidioc_g_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode;
+ int err_code;
if (!v4l2_chip_match_host(&reg->match))
return -EINVAL;
/* NT100x has a 8-bit register space */
- errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
- if (errCode < 0) {
+ err_code = usbvision_read_reg(usbvision, reg->reg&0xff);
+ if (err_code < 0) {
dev_err(&usbvision->vdev->dev,
"%s: VIDIOC_DBG_G_REGISTER failed: error %d\n",
- __func__, errCode);
- return errCode;
+ __func__, err_code);
+ return err_code;
}
- reg->val = errCode;
+ reg->val = err_code;
reg->size = 1;
return 0;
}
-static int vidioc_s_register (struct file *file, void *priv,
+static int vidioc_s_register(struct file *file, void *priv,
struct v4l2_dbg_register *reg)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode;
+ int err_code;
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);
- if (errCode < 0) {
+ err_code = usbvision_write_reg(usbvision, reg->reg & 0xff, reg->val);
+ if (err_code < 0) {
dev_err(&usbvision->vdev->dev,
"%s: VIDIOC_DBG_S_REGISTER failed: error %d\n",
- __func__, errCode);
- return errCode;
+ __func__, err_code);
+ return err_code;
}
return 0;
}
#endif
-static int vidioc_querycap (struct file *file, void *priv,
+static int vidioc_querycap(struct file *file, void *priv,
struct v4l2_capability *vc)
{
struct usb_usbvision *usbvision = video_drvdata(file);
strlcpy(vc->driver, "USBVision", sizeof(vc->driver));
strlcpy(vc->card,
- usbvision_device_data[usbvision->DevModel].ModelString,
+ usbvision_device_data[usbvision->dev_model].model_string,
sizeof(vc->card));
usb_make_path(usbvision->dev, vc->bus_info, sizeof(vc->bus_info));
vc->version = USBVISION_DRIVER_VERSION;
@@ -531,7 +524,7 @@ static int vidioc_querycap (struct file *file, void *priv,
return 0;
}
-static int vidioc_enum_input (struct file *file, void *priv,
+static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *vi)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -539,16 +532,16 @@ static int vidioc_enum_input (struct file *file, void *priv,
if (vi->index >= usbvision->video_inputs)
return -EINVAL;
- if (usbvision->have_tuner) {
+ if (usbvision->have_tuner)
chan = vi->index;
- } else {
- chan = vi->index + 1; /*skip Television string*/
- }
+ else
+ chan = vi->index + 1; /* skip Television string*/
+
/* Determine the requested input characteristics
specific for each usbvision card model */
- switch(chan) {
+ switch (chan) {
case 0:
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4) {
strcpy(vi->name, "White Video Input");
} else {
strcpy(vi->name, "Television");
@@ -560,20 +553,18 @@ static int vidioc_enum_input (struct file *file, void *priv,
break;
case 1:
vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
strcpy(vi->name, "Green Video Input");
- } else {
+ else
strcpy(vi->name, "Composite Video Input");
- }
vi->std = V4L2_STD_PAL;
break;
case 2:
vi->type = V4L2_INPUT_TYPE_CAMERA;
- if (usbvision_device_data[usbvision->DevModel].VideoChannels == 4) {
+ if (usbvision_device_data[usbvision->dev_model].video_channels == 4)
strcpy(vi->name, "Yellow Video Input");
- } else {
+ else
strcpy(vi->name, "S-Video Input");
- }
vi->std = V4L2_STD_PAL;
break;
case 3:
@@ -585,7 +576,7 @@ static int vidioc_enum_input (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
+static int vidioc_g_input(struct file *file, void *priv, unsigned int *input)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -593,46 +584,42 @@ static int vidioc_g_input (struct file *file, void *priv, unsigned int *input)
return 0;
}
-static int vidioc_s_input (struct file *file, void *priv, unsigned int input)
+static int vidioc_s_input(struct file *file, void *priv, unsigned int input)
{
struct usb_usbvision *usbvision = video_drvdata(file);
if (input >= usbvision->video_inputs)
return -EINVAL;
- mutex_lock(&usbvision->lock);
usbvision_muxsel(usbvision, input);
usbvision_set_input(usbvision);
usbvision_set_output(usbvision,
usbvision->curwidth,
usbvision->curheight);
- mutex_unlock(&usbvision->lock);
return 0;
}
-static int vidioc_s_std (struct file *file, void *priv, v4l2_std_id *id)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *id)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- usbvision->tvnormId=*id;
+ usbvision->tvnorm_id = *id;
- mutex_lock(&usbvision->lock);
- call_all(usbvision, core, s_std, usbvision->tvnormId);
- mutex_unlock(&usbvision->lock);
+ call_all(usbvision, core, s_std, usbvision->tvnorm_id);
/* propagate the change to the decoder */
usbvision_muxsel(usbvision, usbvision->ctl_input);
return 0;
}
-static int vidioc_g_tuner (struct file *file, void *priv,
+static int vidioc_g_tuner(struct file *file, void *priv,
struct v4l2_tuner *vt)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- if (!usbvision->have_tuner || vt->index) // Only tuner 0
+ if (!usbvision->have_tuner || vt->index) /* Only tuner 0 */
return -EINVAL;
- if(usbvision->radio) {
+ if (usbvision->radio) {
strcpy(vt->name, "Radio");
vt->type = V4L2_TUNER_RADIO;
} else {
@@ -644,12 +631,12 @@ static int vidioc_g_tuner (struct file *file, void *priv,
return 0;
}
-static int vidioc_s_tuner (struct file *file, void *priv,
+static int vidioc_s_tuner(struct file *file, void *priv,
struct v4l2_tuner *vt)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- // Only no or one tuner for now
+ /* Only no or one tuner for now */
if (!usbvision->have_tuner || vt->index)
return -EINVAL;
/* let clients handle this */
@@ -658,28 +645,27 @@ static int vidioc_s_tuner (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_frequency (struct file *file, void *priv,
+static int vidioc_g_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- freq->tuner = 0; // Only one tuner
- if(usbvision->radio) {
+ freq->tuner = 0; /* Only one tuner */
+ if (usbvision->radio)
freq->type = V4L2_TUNER_RADIO;
- } else {
+ else
freq->type = V4L2_TUNER_ANALOG_TV;
- }
freq->frequency = usbvision->freq;
return 0;
}
-static int vidioc_s_frequency (struct file *file, void *priv,
+static int vidioc_s_frequency(struct file *file, void *priv,
struct v4l2_frequency *freq)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- // Only no or one tuner for now
+ /* Only no or one tuner for now */
if (!usbvision->have_tuner || freq->tuner)
return -EINVAL;
@@ -689,30 +675,27 @@ static int vidioc_s_frequency (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_audio (struct file *file, void *priv, struct v4l2_audio *a)
+static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- if(usbvision->radio) {
- strcpy(a->name,"Radio");
- } else {
+ if (usbvision->radio)
+ strcpy(a->name, "Radio");
+ else
strcpy(a->name, "TV");
- }
return 0;
}
-static int vidioc_s_audio (struct file *file, void *fh,
+static int vidioc_s_audio(struct file *file, void *fh,
struct v4l2_audio *a)
{
- if(a->index) {
+ if (a->index)
return -EINVAL;
- }
-
return 0;
}
-static int vidioc_queryctrl (struct file *file, void *priv,
+static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -725,52 +708,53 @@ static int vidioc_queryctrl (struct file *file, void *priv,
return 0;
}
-static int vidioc_g_ctrl (struct file *file, void *priv,
+static int vidioc_g_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- call_all(usbvision, core, g_ctrl, ctrl);
+ call_all(usbvision, core, g_ctrl, ctrl);
return 0;
}
-static int vidioc_s_ctrl (struct file *file, void *priv,
+static int vidioc_s_ctrl(struct file *file, void *priv,
struct v4l2_control *ctrl)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- call_all(usbvision, core, s_ctrl, ctrl);
+ call_all(usbvision, core, s_ctrl, ctrl);
return 0;
}
-static int vidioc_reqbufs (struct file *file,
+static int vidioc_reqbufs(struct file *file,
void *priv, struct v4l2_requestbuffers *vr)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int ret;
- RESTRICT_TO_RANGE(vr->count,1,USBVISION_NUMFRAMES);
+ RESTRICT_TO_RANGE(vr->count, 1, USBVISION_NUMFRAMES);
/* Check input validity:
the user must do a VIDEO CAPTURE and MMAP method. */
if (vr->memory != V4L2_MEMORY_MMAP)
return -EINVAL;
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
+ if (usbvision->streaming == stream_on) {
+ ret = usbvision_stream_interrupt(usbvision);
+ if (ret)
return ret;
}
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
- vr->count = usbvision_frames_alloc(usbvision,vr->count);
+ vr->count = usbvision_frames_alloc(usbvision, vr->count);
- usbvision->curFrame = NULL;
+ usbvision->cur_frame = NULL;
return 0;
}
-static int vidioc_querybuf (struct file *file,
+static int vidioc_querybuf(struct file *file,
void *priv, struct v4l2_buffer *vb)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -778,52 +762,49 @@ static int vidioc_querybuf (struct file *file,
/* FIXME : must control
that buffers are mapped (VIDIOC_REQBUFS has been called) */
- if(vb->index>=usbvision->num_frames) {
+ if (vb->index >= usbvision->num_frames)
return -EINVAL;
- }
/* Updating the corresponding frame state */
vb->flags = 0;
frame = &usbvision->frame[vb->index];
- if(frame->grabstate >= FrameState_Ready)
+ if (frame->grabstate >= frame_state_ready)
vb->flags |= V4L2_BUF_FLAG_QUEUED;
- if(frame->grabstate >= FrameState_Done)
+ if (frame->grabstate >= frame_state_done)
vb->flags |= V4L2_BUF_FLAG_DONE;
- if(frame->grabstate == FrameState_Unused)
+ if (frame->grabstate == frame_state_unused)
vb->flags |= V4L2_BUF_FLAG_MAPPED;
vb->memory = V4L2_MEMORY_MMAP;
- vb->m.offset = vb->index*PAGE_ALIGN(usbvision->max_frame_size);
+ vb->m.offset = vb->index * PAGE_ALIGN(usbvision->max_frame_size);
vb->memory = V4L2_MEMORY_MMAP;
vb->field = V4L2_FIELD_NONE;
- vb->length = usbvision->curwidth*
- usbvision->curheight*
+ vb->length = usbvision->curwidth *
+ usbvision->curheight *
usbvision->palette.bytes_per_pixel;
vb->timestamp = usbvision->frame[vb->index].timestamp;
vb->sequence = usbvision->frame[vb->index].sequence;
return 0;
}
-static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
{
struct usb_usbvision *usbvision = video_drvdata(file);
struct usbvision_frame *frame;
unsigned long lock_flags;
/* FIXME : works only on VIDEO_CAPTURE MODE, MMAP. */
- if(vb->index>=usbvision->num_frames) {
+ if (vb->index >= usbvision->num_frames)
return -EINVAL;
- }
frame = &usbvision->frame[vb->index];
- if (frame->grabstate != FrameState_Unused) {
+ if (frame->grabstate != frame_state_unused)
return -EAGAIN;
- }
/* Mark it as ready and enqueue frame */
- frame->grabstate = FrameState_Ready;
- frame->scanstate = ScanState_Scanning;
+ frame->grabstate = frame_state_ready;
+ frame->scanstate = scan_state_scanning;
frame->scanlength = 0; /* Accumulated in usbvision_parse_data() */
vb->flags &= ~V4L2_BUF_FLAG_DONE;
@@ -838,7 +819,7 @@ static int vidioc_qbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
return 0;
}
-static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
+static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *vb)
{
struct usb_usbvision *usbvision = video_drvdata(file);
int ret;
@@ -846,7 +827,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
unsigned long lock_flags;
if (list_empty(&(usbvision->outqueue))) {
- if (usbvision->streaming == Stream_Idle)
+ if (usbvision->streaming == stream_idle)
return -EINVAL;
ret = wait_event_interruptible
(usbvision->wait_frame,
@@ -861,7 +842,7 @@ static int vidioc_dqbuf (struct file *file, void *priv, struct v4l2_buffer *vb)
list_del(usbvision->outqueue.next);
spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
- f->grabstate = FrameState_Unused;
+ f->grabstate = frame_state_unused;
vb->memory = V4L2_MEMORY_MMAP;
vb->flags = V4L2_BUF_FLAG_MAPPED |
@@ -880,7 +861,7 @@ static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- usbvision->streaming = Stream_On;
+ usbvision->streaming = stream_on;
call_all(usbvision, video, s_stream, 1);
return 0;
@@ -894,7 +875,7 @@ static int vidioc_streamoff(struct file *file,
if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
- if(usbvision->streaming == Stream_On) {
+ if (usbvision->streaming == stream_on) {
usbvision_stream_interrupt(usbvision);
/* Stop all video streamings */
call_all(usbvision, video, s_stream, 0);
@@ -904,18 +885,17 @@ static int vidioc_streamoff(struct file *file,
return 0;
}
-static int vidioc_enum_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_enum_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_fmtdesc *vfd)
{
- if(vfd->index>=USBVISION_SUPPORTED_PALETTES-1) {
+ if (vfd->index >= USBVISION_SUPPORTED_PALETTES - 1)
return -EINVAL;
- }
- strcpy(vfd->description,usbvision_v4l2_format[vfd->index].desc);
+ strcpy(vfd->description, usbvision_v4l2_format[vfd->index].desc);
vfd->pixelformat = usbvision_v4l2_format[vfd->index].format;
return 0;
}
-static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_g_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *vf)
{
struct usb_usbvision *usbvision = video_drvdata(file);
@@ -923,32 +903,31 @@ static int vidioc_g_fmt_vid_cap (struct file *file, void *priv,
vf->fmt.pix.height = usbvision->curheight;
vf->fmt.pix.pixelformat = usbvision->palette.format;
vf->fmt.pix.bytesperline =
- usbvision->curwidth*usbvision->palette.bytes_per_pixel;
- vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline*usbvision->curheight;
+ usbvision->curwidth * usbvision->palette.bytes_per_pixel;
+ vf->fmt.pix.sizeimage = vf->fmt.pix.bytesperline * usbvision->curheight;
vf->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
vf->fmt.pix.field = V4L2_FIELD_NONE; /* Always progressive image */
return 0;
}
-static int vidioc_try_fmt_vid_cap (struct file *file, void *priv,
+static int vidioc_try_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *vf)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int formatIdx;
+ int format_idx;
/* Find requested format in available ones */
- for(formatIdx=0;formatIdx<USBVISION_SUPPORTED_PALETTES;formatIdx++) {
- if(vf->fmt.pix.pixelformat ==
- usbvision_v4l2_format[formatIdx].format) {
- usbvision->palette = usbvision_v4l2_format[formatIdx];
+ for (format_idx = 0; format_idx < USBVISION_SUPPORTED_PALETTES; format_idx++) {
+ if (vf->fmt.pix.pixelformat ==
+ usbvision_v4l2_format[format_idx].format) {
+ usbvision->palette = usbvision_v4l2_format[format_idx];
break;
}
}
/* robustness */
- if(formatIdx == USBVISION_SUPPORTED_PALETTES) {
+ if (format_idx == USBVISION_SUPPORTED_PALETTES)
return -EINVAL;
- }
RESTRICT_TO_RANGE(vf->fmt.pix.width, MIN_FRAME_WIDTH, MAX_FRAME_WIDTH);
RESTRICT_TO_RANGE(vf->fmt.pix.height, MIN_FRAME_HEIGHT, MAX_FRAME_HEIGHT);
@@ -965,24 +944,23 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct usb_usbvision *usbvision = video_drvdata(file);
int ret;
- if( 0 != (ret=vidioc_try_fmt_vid_cap (file, priv, vf)) ) {
+ ret = vidioc_try_fmt_vid_cap(file, priv, vf);
+ if (ret)
return ret;
- }
/* stop io in case it is already in progress */
- if(usbvision->streaming == Stream_On) {
- if ((ret = usbvision_stream_interrupt(usbvision)))
+ if (usbvision->streaming == stream_on) {
+ ret = usbvision_stream_interrupt(usbvision);
+ if (ret)
return ret;
}
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
- usbvision->curFrame = NULL;
+ usbvision->cur_frame = NULL;
/* by now we are committed to the new data... */
- mutex_lock(&usbvision->lock);
usbvision_set_output(usbvision, vf->fmt.pix.width, vf->fmt.pix.height);
- mutex_unlock(&usbvision->lock);
return 0;
}
@@ -993,8 +971,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
struct usb_usbvision *usbvision = video_drvdata(file);
int noblock = file->f_flags & O_NONBLOCK;
unsigned long lock_flags;
-
- int ret,i;
+ int ret, i;
struct usbvision_frame *frame;
PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__,
@@ -1006,28 +983,28 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
/* This entry point is compatible with the mmap routines
so that a user can do either VIDIOC_QBUF/VIDIOC_DQBUF
to get frames or call read on the device. */
- if(!usbvision->num_frames) {
+ if (!usbvision->num_frames) {
/* First, allocate some frames to work with
if this has not been done with VIDIOC_REQBUF */
usbvision_frames_free(usbvision);
usbvision_empty_framequeues(usbvision);
- usbvision_frames_alloc(usbvision,USBVISION_NUMFRAMES);
+ usbvision_frames_alloc(usbvision, USBVISION_NUMFRAMES);
}
- if(usbvision->streaming != Stream_On) {
+ if (usbvision->streaming != stream_on) {
/* no stream is running, make it running ! */
- usbvision->streaming = Stream_On;
+ usbvision->streaming = stream_on;
call_all(usbvision, video, s_stream, 1);
}
/* Then, enqueue as many frames as possible
(like a user of VIDIOC_QBUF would do) */
- for(i=0;i<usbvision->num_frames;i++) {
+ for (i = 0; i < usbvision->num_frames; i++) {
frame = &usbvision->frame[i];
- if(frame->grabstate == FrameState_Unused) {
+ if (frame->grabstate == frame_state_unused) {
/* Mark it as ready and enqueue frame */
- frame->grabstate = FrameState_Ready;
- frame->scanstate = ScanState_Scanning;
+ frame->grabstate = frame_state_ready;
+ frame->scanstate = scan_state_scanning;
/* Accumulated in usbvision_parse_data() */
frame->scanlength = 0;
@@ -1043,7 +1020,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
/* Then try to steal a frame (like a VIDIOC_DQBUF would do) */
if (list_empty(&(usbvision->outqueue))) {
- if(noblock)
+ if (noblock)
return -EAGAIN;
ret = wait_event_interruptible
@@ -1060,7 +1037,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
spin_unlock_irqrestore(&usbvision->queue_lock, lock_flags);
/* An error returns an empty frame */
- if (frame->grabstate == FrameState_Error) {
+ if (frame->grabstate == frame_state_error) {
frame->bytes_read = 0;
return 0;
}
@@ -1073,9 +1050,8 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
if ((count + frame->bytes_read) > (unsigned long)frame->scanlength)
count = frame->scanlength - frame->bytes_read;
- if (copy_to_user(buf, frame->data + frame->bytes_read, count)) {
+ if (copy_to_user(buf, frame->data + frame->bytes_read, count))
return -EFAULT;
- }
frame->bytes_read += count;
PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
@@ -1083,12 +1059,12 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
(unsigned long)count, frame->bytes_read);
/* For now, forget the frame if it has not been read in one shot. */
-/* if (frame->bytes_read >= frame->scanlength) {// All data has been read */
+/* if (frame->bytes_read >= frame->scanlength) {*/ /* All data has been read */
frame->bytes_read = 0;
/* Mark it as available to be used again. */
- frame->grabstate = FrameState_Unused;
-/* } */
+ frame->grabstate = frame_state_unused;
+/* } */
return count;
}
@@ -1103,16 +1079,11 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
PDEBUG(DBG_MMAP, "mmap");
- mutex_lock(&usbvision->lock);
-
- if (!USBVISION_IS_OPERATIONAL(usbvision)) {
- mutex_unlock(&usbvision->lock);
+ if (!USBVISION_IS_OPERATIONAL(usbvision))
return -EFAULT;
- }
if (!(vma->vm_flags & VM_WRITE) ||
size != PAGE_ALIGN(usbvision->max_frame_size)) {
- mutex_unlock(&usbvision->lock);
return -EINVAL;
}
@@ -1124,7 +1095,6 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
if (i == usbvision->num_frames) {
PDEBUG(DBG_MMAP,
"mmap: user supplied mapping address is out of range");
- mutex_unlock(&usbvision->lock);
return -EINVAL;
}
@@ -1134,10 +1104,8 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
pos = usbvision->frame[i].data;
while (size > 0) {
-
if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
PDEBUG(DBG_MMAP, "mmap: vm_insert_page failed");
- mutex_unlock(&usbvision->lock);
return -EAGAIN;
}
start += PAGE_SIZE;
@@ -1145,7 +1113,6 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
size -= PAGE_SIZE;
}
- mutex_unlock(&usbvision->lock);
return 0;
}
@@ -1157,21 +1124,18 @@ static int usbvision_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
static int usbvision_radio_open(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_IO, "%s:", __func__);
- mutex_lock(&usbvision->lock);
-
if (usbvision->user) {
dev_err(&usbvision->rdev->dev,
"%s: Someone tried to open an already opened USBVision Radio!\n",
__func__);
- errCode = -EBUSY;
- }
- else {
- if(PowerOnAtOpen) {
- usbvision_reset_powerOffTimer(usbvision);
+ err_code = -EBUSY;
+ } else {
+ if (power_on_at_open) {
+ usbvision_reset_power_off_timer(usbvision);
if (usbvision->power == 0) {
usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
@@ -1179,80 +1143,73 @@ static int usbvision_radio_open(struct file *file)
}
/* Alternate interface 1 is is the biggest frame size */
- errCode = usbvision_set_alternate(usbvision);
- if (errCode < 0) {
- usbvision->last_error = errCode;
- errCode = -EBUSY;
+ err_code = usbvision_set_alternate(usbvision);
+ if (err_code < 0) {
+ usbvision->last_error = err_code;
+ err_code = -EBUSY;
goto out;
}
- // If so far no errors then we shall start the radio
+ /* If so far no errors then we shall start the radio */
usbvision->radio = 1;
call_all(usbvision, tuner, s_radio);
usbvision_set_audio(usbvision, USBVISION_AUDIO_RADIO);
usbvision->user++;
}
- if (errCode) {
- if (PowerOnAtOpen) {
+ if (err_code) {
+ if (power_on_at_open) {
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
usbvision->initialized = 0;
}
}
out:
- mutex_unlock(&usbvision->lock);
- return errCode;
+ return err_code;
}
static int usbvision_radio_close(struct file *file)
{
struct usb_usbvision *usbvision = video_drvdata(file);
- int errCode = 0;
+ int err_code = 0;
PDEBUG(DBG_IO, "");
- mutex_lock(&usbvision->lock);
-
/* Set packet size to 0 */
- usbvision->ifaceAlt=0;
- errCode = usb_set_interface(usbvision->dev, usbvision->iface,
- usbvision->ifaceAlt);
+ usbvision->iface_alt = 0;
+ err_code = usb_set_interface(usbvision->dev, usbvision->iface,
+ usbvision->iface_alt);
usbvision_audio_off(usbvision);
- usbvision->radio=0;
+ usbvision->radio = 0;
usbvision->user--;
- if (PowerOnAtOpen) {
- usbvision_set_powerOffTimer(usbvision);
+ if (power_on_at_open) {
+ usbvision_set_power_off_timer(usbvision);
usbvision->initialized = 0;
}
- mutex_unlock(&usbvision->lock);
-
if (usbvision->remove_pending) {
printk(KERN_INFO "%s: Final disconnect\n", __func__);
usbvision_release(usbvision);
}
PDEBUG(DBG_IO, "success");
- return errCode;
+ return err_code;
}
-//
-// Video registration stuff
-//
+/* Video registration stuff */
-// Video template
+/* Video template */
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,
-/* .poll = video_poll, */
+ .unlocked_ioctl = video_ioctl2,
+/* .poll = video_poll, */
};
static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
@@ -1276,9 +1233,6 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
.vidioc_s_ctrl = vidioc_s_ctrl,
.vidioc_streamon = vidioc_streamon,
.vidioc_streamoff = vidioc_streamoff,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-/* .vidiocgmbuf = vidiocgmbuf, */
-#endif
.vidioc_g_tuner = vidioc_g_tuner,
.vidioc_s_tuner = vidioc_s_tuner,
.vidioc_g_frequency = vidioc_g_frequency,
@@ -1291,20 +1245,20 @@ static const struct v4l2_ioctl_ops usbvision_ioctl_ops = {
static struct video_device usbvision_video_template = {
.fops = &usbvision_fops,
- .ioctl_ops = &usbvision_ioctl_ops,
+ .ioctl_ops = &usbvision_ioctl_ops,
.name = "usbvision-video",
.release = video_device_release,
- .tvnorms = USBVISION_NORMS,
- .current_norm = V4L2_STD_PAL
+ .tvnorms = USBVISION_NORMS,
+ .current_norm = V4L2_STD_PAL
};
-// Radio template
+/* Radio template */
static const struct v4l2_file_operations usbvision_radio_fops = {
.owner = THIS_MODULE,
.open = usbvision_radio_open,
.release = usbvision_radio_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
};
static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = {
@@ -1325,9 +1279,9 @@ static const struct v4l2_ioctl_ops usbvision_radio_ioctl_ops = {
static struct video_device usbvision_radio_template = {
.fops = &usbvision_radio_fops,
- .name = "usbvision-radio",
+ .name = "usbvision-radio",
.release = video_device_release,
- .ioctl_ops = &usbvision_radio_ioctl_ops,
+ .ioctl_ops = &usbvision_radio_ioctl_ops,
.tvnorms = USBVISION_NORMS,
.current_norm = V4L2_STD_PAL
@@ -1348,80 +1302,70 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
}
vdev = video_device_alloc();
- if (NULL == vdev) {
+ if (NULL == vdev)
return NULL;
- }
*vdev = *vdev_template;
+ vdev->lock = &usbvision->v4l2_lock;
vdev->v4l2_dev = &usbvision->v4l2_dev;
snprintf(vdev->name, sizeof(vdev->name), "%s", name);
video_set_drvdata(vdev, usbvision);
return vdev;
}
-// unregister video4linux devices
+/* unregister video4linux devices */
static void usbvision_unregister_video(struct usb_usbvision *usbvision)
{
- // Radio Device:
+ /* Radio Device: */
if (usbvision->rdev) {
PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
video_device_node_name(usbvision->rdev));
- if (video_is_registered(usbvision->rdev)) {
+ if (video_is_registered(usbvision->rdev))
video_unregister_device(usbvision->rdev);
- } else {
+ else
video_device_release(usbvision->rdev);
- }
usbvision->rdev = NULL;
}
- // Video Device:
+ /* Video Device: */
if (usbvision->vdev) {
PDEBUG(DBG_PROBE, "unregister %s [v4l2]",
video_device_node_name(usbvision->vdev));
- if (video_is_registered(usbvision->vdev)) {
+ if (video_is_registered(usbvision->vdev))
video_unregister_device(usbvision->vdev);
- } else {
+ else
video_device_release(usbvision->vdev);
- }
usbvision->vdev = NULL;
}
}
-// register video4linux devices
+/* register video4linux devices */
static int __devinit usbvision_register_video(struct usb_usbvision *usbvision)
{
- // Video Device:
+ /* Video Device: */
usbvision->vdev = usbvision_vdev_init(usbvision,
&usbvision_video_template,
"USBVision Video");
- if (usbvision->vdev == NULL) {
+ if (usbvision->vdev == NULL)
goto err_exit;
- }
- if (video_register_device(usbvision->vdev,
- VFL_TYPE_GRABBER,
- video_nr)<0) {
+ if (video_register_device(usbvision->vdev, VFL_TYPE_GRABBER, video_nr) < 0)
goto err_exit;
- }
printk(KERN_INFO "USBVision[%d]: registered USBVision Video device %s [v4l2]\n",
usbvision->nr, video_device_node_name(usbvision->vdev));
- // Radio Device:
- if (usbvision_device_data[usbvision->DevModel].Radio) {
- // usbvision has radio
+ /* Radio Device: */
+ if (usbvision_device_data[usbvision->dev_model].radio) {
+ /* usbvision has radio */
usbvision->rdev = usbvision_vdev_init(usbvision,
&usbvision_radio_template,
"USBVision Radio");
- if (usbvision->rdev == NULL) {
+ if (usbvision->rdev == NULL)
goto err_exit;
- }
- if (video_register_device(usbvision->rdev,
- VFL_TYPE_RADIO,
- radio_nr)<0) {
+ if (video_register_device(usbvision->rdev, VFL_TYPE_RADIO, radio_nr) < 0)
goto err_exit;
- }
printk(KERN_INFO "USBVision[%d]: registered USBVision Radio device %s [v4l2]\n",
usbvision->nr, video_device_node_name(usbvision->rdev));
}
- // all done
+ /* all done */
return 0;
err_exit:
@@ -1454,15 +1398,15 @@ static struct usb_usbvision *usbvision_alloc(struct usb_device *dev,
if (v4l2_device_register(&intf->dev, &usbvision->v4l2_dev))
goto err_free;
- mutex_init(&usbvision->lock); /* available */
+ mutex_init(&usbvision->v4l2_lock);
- // prepare control urb for control messages during interrupts
- usbvision->ctrlUrb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
- if (usbvision->ctrlUrb == NULL)
+ /* prepare control urb for control messages during interrupts */
+ usbvision->ctrl_urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
+ if (usbvision->ctrl_urb == NULL)
goto err_unreg;
- init_waitqueue_head(&usbvision->ctrlUrb_wq);
+ init_waitqueue_head(&usbvision->ctrl_urb_wq);
- usbvision_init_powerOffTimer(usbvision);
+ usbvision_init_power_off_timer(usbvision);
return usbvision;
@@ -1484,20 +1428,14 @@ static void usbvision_release(struct usb_usbvision *usbvision)
{
PDEBUG(DBG_PROBE, "");
- mutex_lock(&usbvision->lock);
-
- usbvision_reset_powerOffTimer(usbvision);
+ usbvision_reset_power_off_timer(usbvision);
usbvision->initialized = 0;
- mutex_unlock(&usbvision->lock);
-
usbvision_remove_sysfs(usbvision->vdev);
usbvision_unregister_video(usbvision);
- if (usbvision->ctrlUrb) {
- usb_free_urb(usbvision->ctrlUrb);
- }
+ usb_free_urb(usbvision->ctrl_urb);
v4l2_device_unregister(&usbvision->v4l2_dev);
kfree(usbvision);
@@ -1515,25 +1453,25 @@ static void usbvision_configure_video(struct usb_usbvision *usbvision)
if (usbvision == NULL)
return;
- model = usbvision->DevModel;
- usbvision->palette = usbvision_v4l2_format[2]; // V4L2_PIX_FMT_RGB24;
+ model = usbvision->dev_model;
+ usbvision->palette = usbvision_v4l2_format[2]; /* V4L2_PIX_FMT_RGB24; */
- if (usbvision_device_data[usbvision->DevModel].Vin_Reg2_override) {
- usbvision->Vin_Reg2_Preset =
- usbvision_device_data[usbvision->DevModel].Vin_Reg2;
+ if (usbvision_device_data[usbvision->dev_model].vin_reg2_override) {
+ usbvision->vin_reg2_preset =
+ usbvision_device_data[usbvision->dev_model].vin_reg2;
} else {
- usbvision->Vin_Reg2_Preset = 0;
+ usbvision->vin_reg2_preset = 0;
}
- usbvision->tvnormId = usbvision_device_data[model].VideoNorm;
+ usbvision->tvnorm_id = usbvision_device_data[model].video_norm;
- usbvision->video_inputs = usbvision_device_data[model].VideoChannels;
+ usbvision->video_inputs = usbvision_device_data[model].video_channels;
usbvision->ctl_input = 0;
/* This should be here to make i2c clients to be able to register */
/* first switch off audio */
usbvision_audio_off(usbvision);
- if (!PowerOnAtOpen) {
+ if (!power_on_at_open) {
/* and then power up the noisy tuner */
usbvision_power_on(usbvision);
usbvision_i2c_register(usbvision);
@@ -1556,25 +1494,24 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
const struct usb_host_interface *interface;
struct usb_usbvision *usbvision = NULL;
const struct usb_endpoint_descriptor *endpoint;
- int model,i;
+ int model, i;
PDEBUG(DBG_PROBE, "VID=%#04x, PID=%#04x, ifnum=%u",
dev->descriptor.idVendor,
dev->descriptor.idProduct, ifnum);
model = devid->driver_info;
- if ( (model<0) || (model>=usbvision_device_data_size) ) {
- PDEBUG(DBG_PROBE, "model out of bounds %d",model);
+ if (model < 0 || model >= usbvision_device_data_size) {
+ PDEBUG(DBG_PROBE, "model out of bounds %d", model);
return -ENODEV;
}
printk(KERN_INFO "%s: %s found\n", __func__,
- usbvision_device_data[model].ModelString);
+ usbvision_device_data[model].model_string);
- if (usbvision_device_data[model].Interface >= 0) {
- interface = &dev->actconfig->interface[usbvision_device_data[model].Interface]->altsetting[0];
- } else {
+ if (usbvision_device_data[model].interface >= 0)
+ interface = &dev->actconfig->interface[usbvision_device_data[model].interface]->altsetting[0];
+ else
interface = &dev->actconfig->interface[ifnum]->altsetting[0];
- }
endpoint = &interface->endpoint[1].desc;
if (!usb_endpoint_xfer_isoc(endpoint)) {
dev_err(&intf->dev, "%s: interface %d. has non-ISO endpoint!\n",
@@ -1595,59 +1532,52 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
return -ENOMEM;
}
- if (dev->descriptor.bNumConfigurations > 1) {
- usbvision->bridgeType = BRIDGE_NT1004;
- } else if (model == DAZZLE_DVC_90_REV_1_SECAM) {
- usbvision->bridgeType = BRIDGE_NT1005;
- } else {
- usbvision->bridgeType = BRIDGE_NT1003;
- }
- PDEBUG(DBG_PROBE, "bridgeType %d", usbvision->bridgeType);
-
- mutex_lock(&usbvision->lock);
+ if (dev->descriptor.bNumConfigurations > 1)
+ usbvision->bridge_type = BRIDGE_NT1004;
+ else if (model == DAZZLE_DVC_90_REV_1_SECAM)
+ usbvision->bridge_type = BRIDGE_NT1005;
+ else
+ usbvision->bridge_type = BRIDGE_NT1003;
+ PDEBUG(DBG_PROBE, "bridge_type %d", usbvision->bridge_type);
/* compute alternate max packet sizes */
uif = dev->actconfig->interface[0];
- usbvision->num_alt=uif->num_altsetting;
- PDEBUG(DBG_PROBE, "Alternate settings: %i",usbvision->num_alt);
- usbvision->alt_max_pkt_size = kmalloc(32*
- usbvision->num_alt,GFP_KERNEL);
+ usbvision->num_alt = uif->num_altsetting;
+ PDEBUG(DBG_PROBE, "Alternate settings: %i", usbvision->num_alt);
+ usbvision->alt_max_pkt_size = kmalloc(32 * usbvision->num_alt, GFP_KERNEL);
if (usbvision->alt_max_pkt_size == NULL) {
dev_err(&intf->dev, "usbvision: out of memory!\n");
- mutex_unlock(&usbvision->lock);
return -ENOMEM;
}
- for (i = 0; i < usbvision->num_alt ; i++) {
+ for (i = 0; i < usbvision->num_alt; i++) {
u16 tmp = le16_to_cpu(uif->altsetting[i].endpoint[1].desc.
wMaxPacketSize);
usbvision->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i",i,
+ PDEBUG(DBG_PROBE, "Alternate setting %i, max size= %i", i,
usbvision->alt_max_pkt_size[i]);
}
usbvision->nr = usbvision_nr++;
- usbvision->have_tuner = usbvision_device_data[model].Tuner;
- if (usbvision->have_tuner) {
- usbvision->tuner_type = usbvision_device_data[model].TunerType;
- }
+ usbvision->have_tuner = usbvision_device_data[model].tuner;
+ if (usbvision->have_tuner)
+ usbvision->tuner_type = usbvision_device_data[model].tuner_type;
- usbvision->DevModel = model;
+ usbvision->dev_model = model;
usbvision->remove_pending = 0;
usbvision->iface = ifnum;
- usbvision->ifaceAlt = 0;
+ usbvision->iface_alt = 0;
usbvision->video_endp = endpoint->bEndpointAddress;
- usbvision->isocPacketSize = 0;
+ usbvision->isoc_packet_size = 0;
usbvision->usb_bandwidth = 0;
usbvision->user = 0;
- usbvision->streaming = Stream_Off;
- usbvision_register_video(usbvision);
+ usbvision->streaming = stream_off;
usbvision_configure_video(usbvision);
- mutex_unlock(&usbvision->lock);
+ usbvision_register_video(usbvision);
usbvision_create_sysfs(usbvision->vdev);
@@ -1671,14 +1601,13 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
PDEBUG(DBG_PROBE, "");
if (usbvision == NULL) {
- dev_err(&usbvision->dev->dev,
- "%s: usb_get_intfdata() failed\n", __func__);
+ pr_err("%s: usb_get_intfdata() failed\n", __func__);
return;
}
- mutex_lock(&usbvision->lock);
+ mutex_lock(&usbvision->v4l2_lock);
- // At this time we ask to cancel outstanding URBs
+ /* At this time we ask to cancel outstanding URBs */
usbvision_stop_isoc(usbvision);
v4l2_device_disconnect(&usbvision->v4l2_dev);
@@ -1687,12 +1616,12 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
usbvision_i2c_unregister(usbvision);
usbvision_power_off(usbvision);
}
- usbvision->remove_pending = 1; // Now all ISO data will be ignored
+ usbvision->remove_pending = 1; /* Now all ISO data will be ignored */
usb_put_dev(usbvision->dev);
- usbvision->dev = NULL; // USB device is no more
+ usbvision->dev = NULL; /* USB device is no more */
- mutex_unlock(&usbvision->lock);
+ mutex_unlock(&usbvision->v4l2_lock);
if (usbvision->user) {
printk(KERN_INFO "%s: In use, disconnect pending\n",
@@ -1721,7 +1650,7 @@ static struct usb_driver usbvision_driver = {
*/
static int __init usbvision_init(void)
{
- int errCode;
+ int err_code;
PDEBUG(DBG_PROBE, "");
@@ -1730,27 +1659,27 @@ static int __init usbvision_init(void)
PDEBUG(DBG_MMAP, "MMAP debugging is enabled [video]");
/* disable planar mode support unless compression enabled */
- if (isocMode != ISOC_MODE_COMPRESS ) {
- // FIXME : not the right way to set supported flag
- usbvision_v4l2_format[6].supported = 0; // V4L2_PIX_FMT_YVU420
- usbvision_v4l2_format[7].supported = 0; // V4L2_PIX_FMT_YUV422P
+ if (isoc_mode != ISOC_MODE_COMPRESS) {
+ /* FIXME : not the right way to set supported flag */
+ usbvision_v4l2_format[6].supported = 0; /* V4L2_PIX_FMT_YVU420 */
+ usbvision_v4l2_format[7].supported = 0; /* V4L2_PIX_FMT_YUV422P */
}
- errCode = usb_register(&usbvision_driver);
+ err_code = usb_register(&usbvision_driver);
- if (errCode == 0) {
+ if (err_code == 0) {
printk(KERN_INFO DRIVER_DESC " : " USBVISION_VERSION_STRING "\n");
PDEBUG(DBG_PROBE, "success");
}
- return errCode;
+ return err_code;
}
static void __exit usbvision_exit(void)
{
- PDEBUG(DBG_PROBE, "");
+ PDEBUG(DBG_PROBE, "");
- usb_deregister(&usbvision_driver);
- PDEBUG(DBG_PROBE, "success");
+ usb_deregister(&usbvision_driver);
+ PDEBUG(DBG_PROBE, "success");
}
module_init(usbvision_init);
diff --git a/drivers/media/video/usbvision/usbvision.h b/drivers/media/video/usbvision/usbvision.h
index d1b3cc0cd87f..8074787fd1ac 100644
--- a/drivers/media/video/usbvision/usbvision.h
+++ b/drivers/media/video/usbvision/usbvision.h
@@ -132,15 +132,15 @@
#define MAX_BYTES_PER_PIXEL 4
#define MIN_FRAME_WIDTH 64
-#define MAX_USB_WIDTH 320 //384
-#define MAX_FRAME_WIDTH 320 //384 /*streching sometimes causes crashes*/
+#define MAX_USB_WIDTH 320 /* 384 */
+#define MAX_FRAME_WIDTH 320 /* 384 */ /* streching sometimes causes crashes*/
#define MIN_FRAME_HEIGHT 48
-#define MAX_USB_HEIGHT 240 //288
-#define MAX_FRAME_HEIGHT 240 //288 /*Streching sometimes causes crashes*/
+#define MAX_USB_HEIGHT 240 /* 288 */
+#define MAX_FRAME_HEIGHT 240 /* 288 */ /* Streching sometimes causes crashes*/
-#define MAX_FRAME_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL)
-#define USBVISION_CLIPMASK_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) //bytesize of clipmask
+#define MAX_FRAME_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT * MAX_BYTES_PER_PIXEL)
+#define USBVISION_CLIPMASK_SIZE (MAX_FRAME_WIDTH * MAX_FRAME_HEIGHT / 8) /* bytesize of clipmask */
#define USBVISION_URB_FRAMES 32
@@ -148,7 +148,7 @@
#define USBVISION_NUMFRAMES 3 /* Maximum number of frames an application can get */
#define USBVISION_NUMSBUF 2 /* Dimensioning the USB S buffering */
-#define USBVISION_POWEROFF_TIME 3 * (HZ) // 3 seconds
+#define USBVISION_POWEROFF_TIME (3 * HZ) /* 3 seconds */
#define FRAMERATE_MIN 0
@@ -161,7 +161,8 @@ enum {
};
/* This macro restricts an int variable to an inclusive range */
-#define RESTRICT_TO_RANGE(v,mi,ma) { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
+#define RESTRICT_TO_RANGE(v, mi, ma) \
+ { if ((v) < (mi)) (v) = (mi); else if ((v) > (ma)) (v) = (ma); }
/*
* We use macros to do YUV -> RGB conversion because this is
@@ -183,18 +184,18 @@ enum {
* Make sure the output values are within [0..255] range.
*/
#define LIMIT_RGB(x) (((x) < 0) ? 0 : (((x) > 255) ? 255 : (x)))
-#define YUV_TO_RGB_BY_THE_BOOK(my,mu,mv,mr,mg,mb) { \
- int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
- mm_y = (my) - 16; \
- mm_u = (mu) - 128; \
- mm_v = (mv) - 128; \
- mm_yc= mm_y * 76284; \
- mm_b = (mm_yc + 132252*mm_v ) >> 16; \
- mm_g = (mm_yc - 53281*mm_u - 25625*mm_v ) >> 16; \
- mm_r = (mm_yc + 104595*mm_u ) >> 16; \
- mb = LIMIT_RGB(mm_b); \
- mg = LIMIT_RGB(mm_g); \
- mr = LIMIT_RGB(mm_r); \
+#define YUV_TO_RGB_BY_THE_BOOK(my, mu, mv, mr, mg, mb) { \
+ int mm_y, mm_yc, mm_u, mm_v, mm_r, mm_g, mm_b; \
+ mm_y = (my) - 16; \
+ mm_u = (mu) - 128; \
+ mm_v = (mv) - 128; \
+ mm_yc = mm_y * 76284; \
+ mm_b = (mm_yc + 132252 * mm_v) >> 16; \
+ mm_g = (mm_yc - 53281 * mm_u - 25625 * mm_v) >> 16; \
+ mm_r = (mm_yc + 104595 * mm_u) >> 16; \
+ mb = LIMIT_RGB(mm_b); \
+ mg = LIMIT_RGB(mm_g); \
+ mr = LIMIT_RGB(mm_r); \
}
/* Debugging aid */
@@ -202,7 +203,7 @@ enum {
wait_queue_head_t wq; \
init_waitqueue_head(&wq); \
printk(KERN_INFO "Say: %s\n", what); \
- interruptible_sleep_on_timeout (&wq, HZ*3); \
+ interruptible_sleep_on_timeout(&wq, HZ * 3); \
}
/*
@@ -223,39 +224,39 @@ enum {
/* ----------------------------------------------------------------- */
/* usbvision video structures */
/* ----------------------------------------------------------------- */
-enum ScanState {
- ScanState_Scanning, /* Scanning for header */
- ScanState_Lines /* Parsing lines */
+enum scan_state {
+ scan_state_scanning, /* Scanning for header */
+ scan_state_lines /* Parsing lines */
};
/* Completion states of the data parser */
-enum ParseState {
- ParseState_Continue, /* Just parse next item */
- ParseState_NextFrame, /* Frame done, send it to V4L */
- ParseState_Out, /* Not enough data for frame */
- ParseState_EndParse /* End parsing */
+enum parse_state {
+ parse_state_continue, /* Just parse next item */
+ parse_state_next_frame, /* Frame done, send it to V4L */
+ parse_state_out, /* Not enough data for frame */
+ parse_state_end_parse /* End parsing */
};
-enum FrameState {
- FrameState_Unused, /* Unused (no MCAPTURE) */
- FrameState_Ready, /* Ready to start grabbing */
- FrameState_Grabbing, /* In the process of being grabbed into */
- FrameState_Done, /* Finished grabbing, but not been synced yet */
- FrameState_DoneHold, /* Are syncing or reading */
- FrameState_Error, /* Something bad happened while processing */
+enum frame_state {
+ frame_state_unused, /* Unused (no MCAPTURE) */
+ frame_state_ready, /* Ready to start grabbing */
+ frame_state_grabbing, /* In the process of being grabbed into */
+ frame_state_done, /* Finished grabbing, but not been synced yet */
+ frame_state_done_hold, /* Are syncing or reading */
+ frame_state_error, /* Something bad happened while processing */
};
/* stream states */
-enum StreamState {
- Stream_Off, /* Driver streaming is completely OFF */
- Stream_Idle, /* Driver streaming is ready to be put ON by the application */
- Stream_Interrupt, /* Driver streaming must be interrupted */
- Stream_On, /* Driver streaming is put ON by the application */
+enum stream_state {
+ stream_off, /* Driver streaming is completely OFF */
+ stream_idle, /* Driver streaming is ready to be put ON by the application */
+ stream_interrupt, /* Driver streaming must be interrupted */
+ stream_on, /* Driver streaming is put ON by the application */
};
-enum IsocState {
- IsocState_InFrame, /* Isoc packet is member of frame */
- IsocState_NoFrame, /* Isoc packet is not member of any frame */
+enum isoc_state {
+ isoc_state_in_frame, /* Isoc packet is member of frame */
+ isoc_state_no_frame, /* Isoc packet is not member of any frame */
};
struct usb_device;
@@ -265,8 +266,8 @@ struct usbvision_sbuf {
struct urb *urb;
};
-#define USBVISION_MAGIC_1 0x55
-#define USBVISION_MAGIC_2 0xAA
+#define USBVISION_MAGIC_1 0x55
+#define USBVISION_MAGIC_2 0xAA
#define USBVISION_HEADER_LENGTH 0x0c
#define USBVISION_SAA7111_ADDR 0x48
#define USBVISION_SAA7113_ADDR 0x4a
@@ -286,23 +287,23 @@ struct usbvision_v4l2_format_st {
struct usbvision_frame_header {
unsigned char magic_1; /* 0 magic */
unsigned char magic_2; /* 1 magic */
- unsigned char headerLength; /* 2 */
- unsigned char frameNum; /* 3 */
- unsigned char framePhase; /* 4 */
- unsigned char frameLatency; /* 5 */
- unsigned char dataFormat; /* 6 */
- unsigned char formatParam; /* 7 */
- unsigned char frameWidthLo; /* 8 */
- unsigned char frameWidthHi; /* 9 */
- unsigned char frameHeightLo; /* 10 */
- unsigned char frameHeightHi; /* 11 */
- __u16 frameWidth; /* 8 - 9 after endian correction*/
- __u16 frameHeight; /* 10 - 11 after endian correction*/
+ unsigned char header_length; /* 2 */
+ unsigned char frame_num; /* 3 */
+ unsigned char frame_phase; /* 4 */
+ unsigned char frame_latency; /* 5 */
+ unsigned char data_format; /* 6 */
+ unsigned char format_param; /* 7 */
+ unsigned char frame_width_lo; /* 8 */
+ unsigned char frame_width_hi; /* 9 */
+ unsigned char frame_height_lo; /* 10 */
+ unsigned char frame_height_hi; /* 11 */
+ __u16 frame_width; /* 8 - 9 after endian correction*/
+ __u16 frame_height; /* 10 - 11 after endian correction*/
};
struct usbvision_frame {
char *data; /* Frame buffer */
- struct usbvision_frame_header isocHeader; /* Header from stream */
+ struct usbvision_frame_header isoc_header; /* Header from stream */
int width; /* Width application is expecting */
int height; /* Height */
@@ -322,7 +323,7 @@ struct usbvision_frame {
struct usbvision_v4l2_format_st v4l2_format; /* format the user needs*/
int v4l2_linesize; /* bytes for one videoline*/
struct timeval timestamp;
- int sequence; // How many video frames we send to user
+ int sequence; /* How many video frames we send to user */
};
#define CODEC_SAA7113 7113
@@ -332,24 +333,24 @@ struct usbvision_frame {
#define BRIDGE_NT1005 1005
struct usbvision_device_data_st {
- __u64 VideoNorm;
- const char *ModelString;
- int Interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */
- __u16 Codec;
- unsigned VideoChannels:3;
- unsigned AudioChannels:2;
- unsigned Radio:1;
+ __u64 video_norm;
+ const char *model_string;
+ int interface; /* to handle special interface number like BELKIN and Hauppauge WinTV-USB II */
+ __u16 codec;
+ unsigned video_channels:3;
+ unsigned audio_channels:2;
+ unsigned radio:1;
unsigned vbi:1;
- unsigned Tuner:1;
- unsigned Vin_Reg1_override:1; /* Override default value with */
- unsigned Vin_Reg2_override:1; /* Vin_Reg1, Vin_Reg2, etc. */
- unsigned Dvi_yuv_override:1;
- __u8 Vin_Reg1;
- __u8 Vin_Reg2;
- __u8 Dvi_yuv;
- __u8 TunerType;
- __s16 X_Offset;
- __s16 Y_Offset;
+ unsigned tuner:1;
+ unsigned vin_reg1_override:1; /* Override default value with */
+ unsigned vin_reg2_override:1; /* vin_reg1, vin_reg2, etc. */
+ unsigned dvi_yuv_override:1;
+ __u8 vin_reg1;
+ __u8 vin_reg2;
+ __u8 dvi_yuv;
+ __u8 tuner_type;
+ __s16 x_offset;
+ __s16 y_offset;
};
/* Declared on usbvision-cards.c */
@@ -358,49 +359,50 @@ extern struct usb_device_id usbvision_table[];
struct usb_usbvision {
struct v4l2_device v4l2_dev;
- struct video_device *vdev; /* Video Device */
- struct video_device *rdev; /* Radio Device */
+ struct video_device *vdev; /* Video Device */
+ struct video_device *rdev; /* Radio Device */
/* i2c Declaration Section*/
struct i2c_adapter i2c_adap;
+ int registered_i2c;
- struct urb *ctrlUrb;
- unsigned char ctrlUrbBuffer[8];
- int ctrlUrbBusy;
- struct usb_ctrlrequest ctrlUrbSetup;
- wait_queue_head_t ctrlUrb_wq; // Processes waiting
+ struct urb *ctrl_urb;
+ unsigned char ctrl_urb_buffer[8];
+ int ctrl_urb_busy;
+ struct usb_ctrlrequest ctrl_urb_setup;
+ wait_queue_head_t ctrl_urb_wq; /* Processes waiting */
/* configuration part */
int have_tuner;
int tuner_type;
- int bridgeType; // NT1003, NT1004, NT1005
+ int bridge_type; /* NT1003, NT1004, NT1005 */
int radio;
- int video_inputs; // # of inputs
+ int video_inputs; /* # of inputs */
unsigned long freq;
- int AudioMute;
- int AudioChannel;
- int isocMode; // format of video data for the usb isoc-transfer
- unsigned int nr; // Number of the device
+ int audio_mute;
+ int audio_channel;
+ int isoc_mode; /* format of video data for the usb isoc-transfer */
+ unsigned int nr; /* Number of the device */
/* Device structure */
struct usb_device *dev;
/* usb transfer */
int num_alt; /* Number of alternative settings */
- unsigned int *alt_max_pkt_size; /* array of wMaxPacketSize */
+ unsigned int *alt_max_pkt_size; /* array of max_packet_size */
unsigned char iface; /* Video interface number */
- unsigned char ifaceAlt; /* Alt settings */
- unsigned char Vin_Reg2_Preset;
- struct mutex lock;
- struct timer_list powerOffTimer;
- struct work_struct powerOffWork;
+ unsigned char iface_alt; /* Alt settings */
+ unsigned char vin_reg2_preset;
+ struct mutex v4l2_lock;
+ struct timer_list power_off_timer;
+ struct work_struct power_off_work;
int power; /* is the device powered on? */
int user; /* user count for exclusive use */
int initialized; /* Had we already sent init sequence? */
- int DevModel; /* What type of USBVISION device we got? */
- enum StreamState streaming; /* Are we streaming Isochronous? */
+ int dev_model; /* What type of USBVISION device we got? */
+ enum stream_state streaming; /* Are we streaming Isochronous? */
int last_error; /* What calamity struck us? */
int curwidth; /* width of the frame the device is currently set to*/
- int curheight; /* height of the frame the device is currently set to*/
+ int curheight; /* height of the frame the device is currently set to*/
int stretch_width; /* stretch-factor for frame width (from usb to screen)*/
int stretch_height; /* stretch-factor for frame height (from usb to screen)*/
char *fbuf; /* Videodev buffer area for mmap*/
@@ -410,10 +412,10 @@ struct usb_usbvision {
struct list_head inqueue, outqueue; /* queued frame list and ready to dequeue frame list */
wait_queue_head_t wait_frame; /* Processes waiting */
wait_queue_head_t wait_stream; /* Processes waiting */
- struct usbvision_frame *curFrame; // pointer to current frame, set by usbvision_find_header
- struct usbvision_frame frame[USBVISION_NUMFRAMES]; // frame buffer
- int num_frames; // number of frames allocated
- struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; // S buffering
+ struct usbvision_frame *cur_frame; /* pointer to current frame, set by usbvision_find_header */
+ struct usbvision_frame frame[USBVISION_NUMFRAMES]; /* frame buffer */
+ int num_frames; /* number of frames allocated */
+ struct usbvision_sbuf sbuf[USBVISION_NUMSBUF]; /* S buffering */
volatile int remove_pending; /* If set then about to exit */
/* Scratch space from the Isochronous Pipe.*/
@@ -423,43 +425,43 @@ struct usb_usbvision {
int scratch_headermarker[USBVISION_NUM_HEADERMARKER];
int scratch_headermarker_read_ptr;
int scratch_headermarker_write_ptr;
- enum IsocState isocstate;
+ enum isoc_state isocstate;
struct usbvision_v4l2_format_st palette;
struct v4l2_capability vcap; /* Video capabilities */
unsigned int ctl_input; /* selected input */
- v4l2_std_id tvnormId; /* selected tv norm */
+ v4l2_std_id tvnorm_id; /* selected tv norm */
unsigned char video_endp; /* 0x82 for USBVISION devices based */
- // Decompression stuff:
- unsigned char *IntraFrameBuffer; /* Buffer for reference frame */
- int BlockPos; //for test only
- int requestIntra; // 0 = normal; 1 = intra frame is requested;
- int lastIsocFrameNum; // check for lost isoc frames
- int isocPacketSize; // need to calculate usedBandwidth
- int usedBandwidth; // used bandwidth 0-100%, need to set comprLevel
- int comprLevel; // How strong (100) or weak (0) is compression
- int lastComprLevel; // How strong (100) or weak (0) was compression
+ /* Decompression stuff: */
+ unsigned char *intra_frame_buffer; /* Buffer for reference frame */
+ int block_pos; /* for test only */
+ int request_intra; /* 0 = normal; 1 = intra frame is requested; */
+ int last_isoc_frame_num; /* check for lost isoc frames */
+ int isoc_packet_size; /* need to calculate used_bandwidth */
+ int used_bandwidth; /* used bandwidth 0-100%, need to set compr_level */
+ int compr_level; /* How strong (100) or weak (0) is compression */
+ int last_compr_level; /* How strong (100) or weak (0) was compression */
int usb_bandwidth; /* Mbit/s */
/* Statistics that can be overlayed on the screen */
- unsigned long isocUrbCount; // How many URBs we received so far
+ unsigned long isoc_urb_count; /* How many URBs we received so far */
unsigned long urb_length; /* Length of last URB */
- unsigned long isocDataCount; /* How many bytes we received */
+ unsigned long isoc_data_count; /* How many bytes we received */
unsigned long header_count; /* How many frame headers we found */
unsigned long scratch_ovf_count; /* How many times we overflowed scratch */
- unsigned long isocSkipCount; /* How many empty ISO packets received */
- unsigned long isocErrCount; /* How many bad ISO packets received */
- unsigned long isocPacketCount; // How many packets we totally got
- unsigned long timeInIrq; // How long do we need for interrupt
- int isocMeasureBandwidthCount;
- int frame_num; // How many video frames we send to user
- int maxStripLen; // How big is the biggest strip
- int comprBlockPos;
- int stripLenErrors; // How many times was BlockPos greater than StripLen
- int stripMagicErrors;
- int stripLineNumberErrors;
- int ComprBlockTypes[4];
+ unsigned long isoc_skip_count; /* How many empty ISO packets received */
+ unsigned long isoc_err_count; /* How many bad ISO packets received */
+ unsigned long isoc_packet_count; /* How many packets we totally got */
+ unsigned long time_in_irq; /* How long do we need for interrupt */
+ int isoc_measure_bandwidth_count;
+ int frame_num; /* How many video frames we send to user */
+ int max_strip_len; /* How big is the biggest strip */
+ int comprblock_pos;
+ int strip_len_errors; /* How many times was block_pos greater than strip_len */
+ int strip_magic_errors;
+ int strip_line_number_errors;
+ int compr_block_types[4];
};
static inline struct usb_usbvision *to_usbvision(struct v4l2_device *v4l2_dev)
@@ -493,13 +495,13 @@ void usbvision_scratch_free(struct usb_usbvision *usbvision);
int usbvision_decompress_alloc(struct usb_usbvision *usbvision);
void usbvision_decompress_free(struct usb_usbvision *usbvision);
-int usbvision_setup(struct usb_usbvision *usbvision,int format);
+int usbvision_setup(struct usb_usbvision *usbvision, int format);
int usbvision_init_isoc(struct usb_usbvision *usbvision);
int usbvision_restart_isoc(struct usb_usbvision *usbvision);
void usbvision_stop_isoc(struct usb_usbvision *usbvision);
int usbvision_set_alternate(struct usb_usbvision *dev);
-int usbvision_set_audio(struct usb_usbvision *usbvision, int AudioChannel);
+int usbvision_set_audio(struct usb_usbvision *usbvision, int audio_channel);
int usbvision_audio_off(struct usb_usbvision *usbvision);
int usbvision_begin_streaming(struct usb_usbvision *usbvision);
@@ -510,9 +512,9 @@ int usbvision_muxsel(struct usb_usbvision *usbvision, int channel);
int usbvision_set_input(struct usb_usbvision *usbvision);
int usbvision_set_output(struct usb_usbvision *usbvision, int width, int height);
-void usbvision_init_powerOffTimer(struct usb_usbvision *usbvision);
-void usbvision_set_powerOffTimer(struct usb_usbvision *usbvision);
-void usbvision_reset_powerOffTimer(struct usb_usbvision *usbvision);
+void usbvision_init_power_off_timer(struct usb_usbvision *usbvision);
+void usbvision_set_power_off_timer(struct usb_usbvision *usbvision);
+void usbvision_reset_power_off_timer(struct usb_usbvision *usbvision);
int usbvision_power_off(struct usb_usbvision *usbvision);
int usbvision_power_on(struct usb_usbvision *usbvision);
diff --git a/drivers/media/video/uvc/uvc_ctrl.c b/drivers/media/video/uvc/uvc_ctrl.c
index aa0720af07a0..59f8a9ad3796 100644
--- a/drivers/media/video/uvc/uvc_ctrl.c
+++ b/drivers/media/video/uvc/uvc_ctrl.c
@@ -1,8 +1,8 @@
/*
* uvc_ctrl.c -- USB Video Class driver - Controls
*
- * Copyright (C) 2005-2009
- * Laurent Pinchart (laurent.pinchart@skynet.be)
+ * Copyright (C) 2005-2010
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -122,8 +122,8 @@ static struct uvc_control_info uvc_ctrls[] = {
.selector = UVC_PU_POWER_LINE_FREQUENCY_CONTROL,
.index = 10,
.size = 1,
- .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_RANGE
- | UVC_CONTROL_RESTORE,
+ .flags = UVC_CONTROL_SET_CUR | UVC_CONTROL_GET_CUR
+ | UVC_CONTROL_GET_DEF | UVC_CONTROL_RESTORE,
},
{
.entity = UVC_GUID_UVC_PROCESSING,
@@ -606,6 +606,26 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
.set = uvc_ctrl_set_zoom,
},
{
+ .id = V4L2_CID_PAN_ABSOLUTE,
+ .name = "Pan (Absolute)",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
+ .size = 32,
+ .offset = 0,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
+ .id = V4L2_CID_TILT_ABSOLUTE,
+ .name = "Tilt (Absolute)",
+ .entity = UVC_GUID_UVC_CAMERA,
+ .selector = UVC_CT_PANTILT_ABSOLUTE_CONTROL,
+ .size = 32,
+ .offset = 32,
+ .v4l2_type = V4L2_CTRL_TYPE_INTEGER,
+ .data_type = UVC_CTRL_DATA_TYPE_UNSIGNED,
+ },
+ {
.id = V4L2_CID_PRIVACY,
.name = "Privacy",
.entity = UVC_GUID_UVC_CAMERA,
@@ -623,7 +643,7 @@ static struct uvc_control_mapping uvc_ctrl_mappings[] = {
static inline __u8 *uvc_ctrl_data(struct uvc_control *ctrl, int id)
{
- return ctrl->data + id * ctrl->info->size;
+ return ctrl->uvc_data + id * ctrl->info.size;
}
static inline int uvc_test_bit(const __u8 *data, int bit)
@@ -678,6 +698,14 @@ static void uvc_set_le_value(struct uvc_control_mapping *mapping,
int offset = mapping->offset;
__u8 mask;
+ /* According to the v4l2 spec, writing any value to a button control
+ * should result in the action belonging to the button control being
+ * triggered. UVC devices however want to see a 1 written -> override
+ * value.
+ */
+ if (mapping->v4l2_type == V4L2_CTRL_TYPE_BUTTON)
+ value = -1;
+
data += offset / 8;
offset &= 7;
@@ -699,7 +727,8 @@ static const __u8 uvc_camera_guid[16] = UVC_GUID_UVC_CAMERA;
static const __u8 uvc_media_transport_input_guid[16] =
UVC_GUID_UVC_MEDIA_TRANSPORT_INPUT;
-static int uvc_entity_match_guid(struct uvc_entity *entity, __u8 guid[16])
+static int uvc_entity_match_guid(const struct uvc_entity *entity,
+ const __u8 guid[16])
{
switch (UVC_ENTITY_TYPE(entity)) {
case UVC_ITT_CAMERA:
@@ -737,10 +766,10 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
- if (ctrl->info == NULL)
+ if (!ctrl->initialized)
continue;
- list_for_each_entry(map, &ctrl->info->mappings, list) {
+ list_for_each_entry(map, &ctrl->info.mappings, list) {
if ((map->id == v4l2_id) && !next) {
*control = ctrl;
*mapping = map;
@@ -756,7 +785,7 @@ static void __uvc_find_control(struct uvc_entity *entity, __u32 v4l2_id,
}
}
-struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
+static struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
__u32 v4l2_id, struct uvc_control_mapping **mapping)
{
struct uvc_control *ctrl = NULL;
@@ -787,36 +816,36 @@ static int uvc_ctrl_populate_cache(struct uvc_video_chain *chain,
{
int ret;
- if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+ if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_DEF, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
+ chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF),
- ctrl->info->size);
+ ctrl->info.size);
if (ret < 0)
return ret;
}
- if (ctrl->info->flags & UVC_CONTROL_GET_MIN) {
+ if (ctrl->info.flags & UVC_CONTROL_GET_MIN) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_MIN, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
+ chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN),
- ctrl->info->size);
+ ctrl->info.size);
if (ret < 0)
return ret;
}
- if (ctrl->info->flags & UVC_CONTROL_GET_MAX) {
+ if (ctrl->info.flags & UVC_CONTROL_GET_MAX) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_MAX, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
+ chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX),
- ctrl->info->size);
+ ctrl->info.size);
if (ret < 0)
return ret;
}
- if (ctrl->info->flags & UVC_CONTROL_GET_RES) {
+ if (ctrl->info.flags & UVC_CONTROL_GET_RES) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_RES, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
+ chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES),
- ctrl->info->size);
+ ctrl->info.size);
if (ret < 0)
return ret;
}
@@ -834,9 +863,15 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
unsigned int i;
int ret;
+ ret = mutex_lock_interruptible(&chain->ctrl_mutex);
+ if (ret < 0)
+ return -ERESTARTSYS;
+
ctrl = uvc_find_control(chain, v4l2_ctrl->id, &mapping);
- if (ctrl == NULL)
- return -EINVAL;
+ if (ctrl == NULL) {
+ ret = -EINVAL;
+ goto done;
+ }
memset(v4l2_ctrl, 0, sizeof *v4l2_ctrl);
v4l2_ctrl->id = mapping->id;
@@ -844,18 +879,18 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
strlcpy(v4l2_ctrl->name, mapping->name, sizeof v4l2_ctrl->name);
v4l2_ctrl->flags = 0;
- if (!(ctrl->info->flags & UVC_CONTROL_GET_CUR))
+ if (!(ctrl->info.flags & UVC_CONTROL_GET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- if (!(ctrl->info->flags & UVC_CONTROL_SET_CUR))
+ if (!(ctrl->info.flags & UVC_CONTROL_SET_CUR))
v4l2_ctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
if (!ctrl->cached) {
ret = uvc_ctrl_populate_cache(chain, ctrl);
if (ret < 0)
- return ret;
+ goto done;
}
- if (ctrl->info->flags & UVC_CONTROL_GET_DEF) {
+ if (ctrl->info.flags & UVC_CONTROL_GET_DEF) {
v4l2_ctrl->default_value = mapping->get(mapping, UVC_GET_DEF,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_DEF));
}
@@ -874,37 +909,85 @@ int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
}
}
- return 0;
+ goto done;
case V4L2_CTRL_TYPE_BOOLEAN:
v4l2_ctrl->minimum = 0;
v4l2_ctrl->maximum = 1;
v4l2_ctrl->step = 1;
- return 0;
+ goto done;
case V4L2_CTRL_TYPE_BUTTON:
v4l2_ctrl->minimum = 0;
v4l2_ctrl->maximum = 0;
v4l2_ctrl->step = 0;
- return 0;
+ goto done;
default:
break;
}
- if (ctrl->info->flags & UVC_CONTROL_GET_MIN)
+ if (ctrl->info.flags & UVC_CONTROL_GET_MIN)
v4l2_ctrl->minimum = mapping->get(mapping, UVC_GET_MIN,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MIN));
- if (ctrl->info->flags & UVC_CONTROL_GET_MAX)
+ if (ctrl->info.flags & UVC_CONTROL_GET_MAX)
v4l2_ctrl->maximum = mapping->get(mapping, UVC_GET_MAX,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_MAX));
- if (ctrl->info->flags & UVC_CONTROL_GET_RES)
+ if (ctrl->info.flags & UVC_CONTROL_GET_RES)
v4l2_ctrl->step = mapping->get(mapping, UVC_GET_RES,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_RES));
- return 0;
+done:
+ mutex_unlock(&chain->ctrl_mutex);
+ return ret;
+}
+
+/*
+ * Mapping V4L2 controls to UVC controls can be straighforward if done well.
+ * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
+ * must be grouped (for instance the Red Balance, Blue Balance and Do White
+ * Balance V4L2 controls use the White Balance Component UVC control) or
+ * otherwise translated. The approach we take here is to use a translation
+ * table for the controls that can be mapped directly, and handle the others
+ * manually.
+ */
+int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
+ struct v4l2_querymenu *query_menu)
+{
+ struct uvc_menu_info *menu_info;
+ struct uvc_control_mapping *mapping;
+ struct uvc_control *ctrl;
+ u32 index = query_menu->index;
+ u32 id = query_menu->id;
+ int ret;
+
+ memset(query_menu, 0, sizeof(*query_menu));
+ query_menu->id = id;
+ query_menu->index = index;
+
+ ret = mutex_lock_interruptible(&chain->ctrl_mutex);
+ if (ret < 0)
+ return -ERESTARTSYS;
+
+ ctrl = uvc_find_control(chain, query_menu->id, &mapping);
+ if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if (query_menu->index >= mapping->menu_count) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ menu_info = &mapping->menu_info[query_menu->index];
+ strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
+
+done:
+ mutex_unlock(&chain->ctrl_mutex);
+ return ret;
}
@@ -949,14 +1032,14 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
- if (ctrl->info == NULL)
+ if (!ctrl->initialized)
continue;
/* Reset the loaded flag for auto-update controls that were
* marked as loaded in uvc_ctrl_get/uvc_ctrl_set to prevent
* uvc_ctrl_get from using the cached value.
*/
- if (ctrl->info->flags & UVC_CONTROL_AUTO_UPDATE)
+ if (ctrl->info.flags & UVC_CONTROL_AUTO_UPDATE)
ctrl->loaded = 0;
if (!ctrl->dirty)
@@ -964,16 +1047,16 @@ static int uvc_ctrl_commit_entity(struct uvc_device *dev,
if (!rollback)
ret = uvc_query_ctrl(dev, UVC_SET_CUR, ctrl->entity->id,
- dev->intfnum, ctrl->info->selector,
+ dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info->size);
+ ctrl->info.size);
else
ret = 0;
if (rollback || ret < 0)
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
- ctrl->info->size);
+ ctrl->info.size);
ctrl->dirty = 0;
@@ -1011,14 +1094,14 @@ int uvc_ctrl_get(struct uvc_video_chain *chain,
int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0)
+ if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0)
return -EINVAL;
if (!ctrl->loaded) {
ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR, ctrl->entity->id,
- chain->dev->intfnum, ctrl->info->selector,
+ chain->dev->intfnum, ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info->size);
+ ctrl->info.size);
if (ret < 0)
return ret;
@@ -1053,7 +1136,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
int ret;
ctrl = uvc_find_control(chain, xctrl->id, &mapping);
- if (ctrl == NULL || (ctrl->info->flags & UVC_CONTROL_SET_CUR) == 0)
+ if (ctrl == NULL || (ctrl->info.flags & UVC_CONTROL_SET_CUR) == 0)
return -EINVAL;
/* Clamp out of range values. */
@@ -1099,16 +1182,16 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
* needs to be loaded from the device to perform the read-modify-write
* operation.
*/
- if (!ctrl->loaded && (ctrl->info->size * 8) != mapping->size) {
- if ((ctrl->info->flags & UVC_CONTROL_GET_CUR) == 0) {
+ if (!ctrl->loaded && (ctrl->info.size * 8) != mapping->size) {
+ if ((ctrl->info.flags & UVC_CONTROL_GET_CUR) == 0) {
memset(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- 0, ctrl->info->size);
+ 0, ctrl->info.size);
} else {
ret = uvc_query_ctrl(chain->dev, UVC_GET_CUR,
ctrl->entity->id, chain->dev->intfnum,
- ctrl->info->selector,
+ ctrl->info.selector,
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info->size);
+ ctrl->info.size);
if (ret < 0)
return ret;
}
@@ -1120,7 +1203,7 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
if (!ctrl->dirty) {
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- ctrl->info->size);
+ ctrl->info.size);
}
mapping->set(mapping, value,
@@ -1135,12 +1218,138 @@ int uvc_ctrl_set(struct uvc_video_chain *chain,
* Dynamic controls
*/
+static void uvc_ctrl_fixup_xu_info(struct uvc_device *dev,
+ const struct uvc_control *ctrl, struct uvc_control_info *info)
+{
+ struct uvc_ctrl_fixup {
+ struct usb_device_id id;
+ u8 entity;
+ u8 selector;
+ u8 flags;
+ };
+
+ static const struct uvc_ctrl_fixup fixups[] = {
+ { { USB_DEVICE(0x046d, 0x08c2) }, 9, 1,
+ UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+ UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
+ UVC_CONTROL_AUTO_UPDATE },
+ { { USB_DEVICE(0x046d, 0x08cc) }, 9, 1,
+ UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+ UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
+ UVC_CONTROL_AUTO_UPDATE },
+ { { USB_DEVICE(0x046d, 0x0994) }, 9, 1,
+ UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
+ UVC_CONTROL_GET_DEF | UVC_CONTROL_SET_CUR |
+ UVC_CONTROL_AUTO_UPDATE },
+ };
+
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(fixups); ++i) {
+ if (!usb_match_one_id(dev->intf, &fixups[i].id))
+ continue;
+
+ if (fixups[i].entity == ctrl->entity->id &&
+ fixups[i].selector == info->selector) {
+ info->flags = fixups[i].flags;
+ return;
+ }
+ }
+}
+
+/*
+ * Query control information (size and flags) for XU controls.
+ */
+static int uvc_ctrl_fill_xu_info(struct uvc_device *dev,
+ const struct uvc_control *ctrl, struct uvc_control_info *info)
+{
+ u8 *data;
+ int ret;
+
+ data = kmalloc(2, GFP_KERNEL);
+ if (data == NULL)
+ return -ENOMEM;
+
+ memcpy(info->entity, ctrl->entity->extension.guidExtensionCode,
+ sizeof(info->entity));
+ info->index = ctrl->index;
+ info->selector = ctrl->index + 1;
+
+ /* Query and verify the control length (GET_LEN) */
+ ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id, dev->intfnum,
+ info->selector, data, 2);
+ if (ret < 0) {
+ uvc_trace(UVC_TRACE_CONTROL,
+ "GET_LEN failed on control %pUl/%u (%d).\n",
+ info->entity, info->selector, ret);
+ goto done;
+ }
+
+ info->size = le16_to_cpup((__le16 *)data);
+
+ /* Query the control information (GET_INFO) */
+ ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id, dev->intfnum,
+ info->selector, data, 1);
+ if (ret < 0) {
+ uvc_trace(UVC_TRACE_CONTROL,
+ "GET_INFO failed on control %pUl/%u (%d).\n",
+ info->entity, info->selector, ret);
+ goto done;
+ }
+
+ info->flags = UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX
+ | UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF
+ | (data[0] & UVC_CONTROL_CAP_GET ? UVC_CONTROL_GET_CUR : 0)
+ | (data[0] & UVC_CONTROL_CAP_SET ? UVC_CONTROL_SET_CUR : 0)
+ | (data[0] & UVC_CONTROL_CAP_AUTOUPDATE ?
+ UVC_CONTROL_AUTO_UPDATE : 0);
+
+ uvc_ctrl_fixup_xu_info(dev, ctrl, info);
+
+ uvc_trace(UVC_TRACE_CONTROL, "XU control %pUl/%u queried: len %u, "
+ "flags { get %u set %u auto %u }.\n",
+ info->entity, info->selector, info->size,
+ (info->flags & UVC_CONTROL_GET_CUR) ? 1 : 0,
+ (info->flags & UVC_CONTROL_SET_CUR) ? 1 : 0,
+ (info->flags & UVC_CONTROL_AUTO_UPDATE) ? 1 : 0);
+
+done:
+ kfree(data);
+ return ret;
+}
+
+static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
+ const struct uvc_control_info *info);
+
+static int uvc_ctrl_init_xu_ctrl(struct uvc_device *dev,
+ struct uvc_control *ctrl)
+{
+ struct uvc_control_info info;
+ int ret;
+
+ if (ctrl->initialized)
+ return 0;
+
+ ret = uvc_ctrl_fill_xu_info(dev, ctrl, &info);
+ if (ret < 0)
+ return ret;
+
+ ret = uvc_ctrl_add_info(dev, ctrl, &info);
+ if (ret < 0)
+ uvc_trace(UVC_TRACE_CONTROL, "Failed to initialize control "
+ "%pUl/%u on device %s entity %u\n", info.entity,
+ info.selector, dev->udev->devpath, ctrl->entity->id);
+
+ return ret;
+}
+
int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
struct uvc_xu_control *xctrl, int set)
{
struct uvc_entity *entity;
struct uvc_control *ctrl = NULL;
unsigned int i, found = 0;
+ int restore = 0;
__u8 *data;
int ret;
@@ -1157,13 +1366,10 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
return -EINVAL;
}
- /* Find the control. */
+ /* Find the control and perform delayed initialization if needed. */
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
- if (ctrl->info == NULL)
- continue;
-
- if (ctrl->info->selector == xctrl->selector) {
+ if (ctrl->index == xctrl->selector - 1) {
found = 1;
break;
}
@@ -1175,40 +1381,48 @@ int uvc_xu_ctrl_query(struct uvc_video_chain *chain,
return -EINVAL;
}
- /* Validate control data size. */
- if (ctrl->info->size != xctrl->size)
- return -EINVAL;
-
- if ((set && !(ctrl->info->flags & UVC_CONTROL_SET_CUR)) ||
- (!set && !(ctrl->info->flags & UVC_CONTROL_GET_CUR)))
- return -EINVAL;
-
if (mutex_lock_interruptible(&chain->ctrl_mutex))
return -ERESTARTSYS;
+ ret = uvc_ctrl_init_xu_ctrl(chain->dev, ctrl);
+ if (ret < 0) {
+ ret = -ENOENT;
+ goto done;
+ }
+
+ /* Validate control data size. */
+ if (ctrl->info.size != xctrl->size) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((set && !(ctrl->info.flags & UVC_CONTROL_SET_CUR)) ||
+ (!set && !(ctrl->info.flags & UVC_CONTROL_GET_CUR))) {
+ ret = -EINVAL;
+ goto done;
+ }
+
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
- xctrl->size);
+ ctrl->info.size);
data = uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT);
+ restore = set;
if (set && copy_from_user(data, xctrl->data, xctrl->size)) {
ret = -EFAULT;
- goto out;
+ goto done;
}
ret = uvc_query_ctrl(chain->dev, set ? UVC_SET_CUR : UVC_GET_CUR,
xctrl->unit, chain->dev->intfnum, xctrl->selector,
data, xctrl->size);
if (ret < 0)
- goto out;
+ goto done;
- if (!set && copy_to_user(xctrl->data, data, xctrl->size)) {
+ if (!set && copy_to_user(xctrl->data, data, xctrl->size))
ret = -EFAULT;
- goto out;
- }
-
-out:
- if (ret)
+done:
+ if (ret && restore)
memcpy(uvc_ctrl_data(ctrl, UVC_CTRL_DATA_CURRENT),
uvc_ctrl_data(ctrl, UVC_CTRL_DATA_BACKUP),
xctrl->size);
@@ -1243,13 +1457,13 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
for (i = 0; i < entity->ncontrols; ++i) {
ctrl = &entity->controls[i];
- if (ctrl->info == NULL || !ctrl->modified ||
- (ctrl->info->flags & UVC_CONTROL_RESTORE) == 0)
+ if (!ctrl->initialized || !ctrl->modified ||
+ (ctrl->info.flags & UVC_CONTROL_RESTORE) == 0)
continue;
printk(KERN_INFO "restoring control %pUl/%u/%u\n",
- ctrl->info->entity, ctrl->info->index,
- ctrl->info->selector);
+ ctrl->info.entity, ctrl->info.index,
+ ctrl->info.selector);
ctrl->dirty = 1;
}
@@ -1265,186 +1479,150 @@ int uvc_ctrl_resume_device(struct uvc_device *dev)
* Control and mapping handling
*/
-static void uvc_ctrl_add_ctrl(struct uvc_device *dev,
- struct uvc_control_info *info)
+/*
+ * Add control information to a given control.
+ */
+static int uvc_ctrl_add_info(struct uvc_device *dev, struct uvc_control *ctrl,
+ const struct uvc_control_info *info)
{
- struct uvc_entity *entity;
- struct uvc_control *ctrl = NULL;
- int ret, found = 0;
- unsigned int i;
-
- list_for_each_entry(entity, &dev->entities, list) {
- if (!uvc_entity_match_guid(entity, info->entity))
- continue;
+ int ret = 0;
- for (i = 0; i < entity->ncontrols; ++i) {
- ctrl = &entity->controls[i];
- if (ctrl->index == info->index) {
- found = 1;
- break;
- }
- }
+ memcpy(&ctrl->info, info, sizeof(*info));
+ INIT_LIST_HEAD(&ctrl->info.mappings);
- if (found)
- break;
+ /* Allocate an array to save control values (cur, def, max, etc.) */
+ ctrl->uvc_data = kzalloc(ctrl->info.size * UVC_CTRL_DATA_LAST + 1,
+ GFP_KERNEL);
+ if (ctrl->uvc_data == NULL) {
+ ret = -ENOMEM;
+ goto done;
}
- if (!found)
- return;
-
- if (UVC_ENTITY_TYPE(entity) == UVC_VC_EXTENSION_UNIT) {
- /* Check if the device control information and length match
- * the user supplied information.
- */
- __u32 flags;
- __le16 size;
- __u8 inf;
-
- ret = uvc_query_ctrl(dev, UVC_GET_LEN, ctrl->entity->id,
- dev->intfnum, info->selector, (__u8 *)&size, 2);
- if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL,
- "GET_LEN failed on control %pUl/%u (%d).\n",
- info->entity, info->selector, ret);
- return;
- }
-
- if (info->size != le16_to_cpu(size)) {
- uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u size "
- "doesn't match user supplied value.\n",
- info->entity, info->selector);
- return;
- }
-
- ret = uvc_query_ctrl(dev, UVC_GET_INFO, ctrl->entity->id,
- dev->intfnum, info->selector, &inf, 1);
- if (ret < 0) {
- uvc_trace(UVC_TRACE_CONTROL,
- "GET_INFO failed on control %pUl/%u (%d).\n",
- info->entity, info->selector, ret);
- return;
- }
+ ctrl->initialized = 1;
- flags = info->flags;
- if (((flags & UVC_CONTROL_GET_CUR) && !(inf & (1 << 0))) ||
- ((flags & UVC_CONTROL_SET_CUR) && !(inf & (1 << 1)))) {
- uvc_trace(UVC_TRACE_CONTROL, "Control %pUl/%u flags "
- "don't match supported operations.\n",
- info->entity, info->selector);
- return;
- }
- }
-
- ctrl->info = info;
- ctrl->data = kmalloc(ctrl->info->size * UVC_CTRL_DATA_LAST, GFP_KERNEL);
uvc_trace(UVC_TRACE_CONTROL, "Added control %pUl/%u to device %s "
- "entity %u\n", ctrl->info->entity, ctrl->info->selector,
- dev->udev->devpath, entity->id);
+ "entity %u\n", ctrl->info.entity, ctrl->info.selector,
+ dev->udev->devpath, ctrl->entity->id);
+
+done:
+ if (ret < 0)
+ kfree(ctrl->uvc_data);
+ return ret;
}
/*
- * Add an item to the UVC control information list, and instantiate a control
- * structure for each device that supports the control.
+ * Add a control mapping to a given control.
*/
-int uvc_ctrl_add_info(struct uvc_control_info *info)
+static int __uvc_ctrl_add_mapping(struct uvc_device *dev,
+ struct uvc_control *ctrl, const struct uvc_control_mapping *mapping)
{
- struct uvc_control_info *ctrl;
- struct uvc_device *dev;
- int ret = 0;
-
- /* Find matching controls by walking the devices, entities and
- * controls list.
- */
- mutex_lock(&uvc_driver.ctrl_mutex);
+ struct uvc_control_mapping *map;
+ unsigned int size;
- /* First check if the list contains a control matching the new one.
- * Bail out if it does.
+ /* Most mappings come from static kernel data and need to be duplicated.
+ * Mappings that come from userspace will be unnecessarily duplicated,
+ * this could be optimized.
*/
- list_for_each_entry(ctrl, &uvc_driver.controls, list) {
- if (memcmp(ctrl->entity, info->entity, 16))
- continue;
-
- if (ctrl->selector == info->selector) {
- uvc_trace(UVC_TRACE_CONTROL,
- "Control %pUl/%u is already defined.\n",
- info->entity, info->selector);
- ret = -EEXIST;
- goto end;
- }
- if (ctrl->index == info->index) {
- uvc_trace(UVC_TRACE_CONTROL,
- "Control %pUl/%u would overwrite index %d.\n",
- info->entity, info->selector, info->index);
- ret = -EEXIST;
- goto end;
- }
+ map = kmemdup(mapping, sizeof(*mapping), GFP_KERNEL);
+ if (map == NULL)
+ return -ENOMEM;
+
+ size = sizeof(*mapping->menu_info) * mapping->menu_count;
+ map->menu_info = kmemdup(mapping->menu_info, size, GFP_KERNEL);
+ if (map->menu_info == NULL) {
+ kfree(map);
+ return -ENOMEM;
}
- list_for_each_entry(dev, &uvc_driver.devices, list)
- uvc_ctrl_add_ctrl(dev, info);
+ if (map->get == NULL)
+ map->get = uvc_get_le_value;
+ if (map->set == NULL)
+ map->set = uvc_set_le_value;
- INIT_LIST_HEAD(&info->mappings);
- list_add_tail(&info->list, &uvc_driver.controls);
-end:
- mutex_unlock(&uvc_driver.ctrl_mutex);
- return ret;
+ map->ctrl = &ctrl->info;
+ list_add_tail(&map->list, &ctrl->info.mappings);
+ uvc_trace(UVC_TRACE_CONTROL,
+ "Adding mapping '%s' to control %pUl/%u.\n",
+ map->name, ctrl->info.entity, ctrl->info.selector);
+
+ return 0;
}
-int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping)
+int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
+ const struct uvc_control_mapping *mapping)
{
- struct uvc_control_info *info;
+ struct uvc_device *dev = chain->dev;
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;
+ struct uvc_entity *entity;
+ struct uvc_control *ctrl;
+ int found = 0;
+ int ret;
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,
+ uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', control "
+ "id 0x%08x is invalid.\n", mapping->name,
mapping->id);
return -EINVAL;
}
- mutex_lock(&uvc_driver.ctrl_mutex);
- list_for_each_entry(info, &uvc_driver.controls, list) {
- if (memcmp(info->entity, mapping->entity, 16) ||
- info->selector != mapping->selector)
- continue;
+ /* Search for the matching (GUID/CS) control in the given device */
+ list_for_each_entry(entity, &dev->entities, list) {
+ unsigned int i;
- if (info->size * 8 < mapping->size + mapping->offset) {
- uvc_trace(UVC_TRACE_CONTROL,
- "Mapping '%s' would overflow control %pUl/%u\n",
- mapping->name, info->entity, info->selector);
- ret = -EOVERFLOW;
- goto end;
- }
+ if (UVC_ENTITY_TYPE(entity) != UVC_VC_EXTENSION_UNIT ||
+ !uvc_entity_match_guid(entity, mapping->entity))
+ continue;
- /* Check if the list contains a mapping matching the new one.
- * Bail out if it does.
- */
- list_for_each_entry(map, &info->mappings, list) {
- if (map->id == mapping->id) {
- uvc_trace(UVC_TRACE_CONTROL, "Mapping '%s' is "
- "already defined.\n", mapping->name);
- ret = -EEXIST;
- goto end;
+ for (i = 0; i < entity->ncontrols; ++i) {
+ ctrl = &entity->controls[i];
+ if (ctrl->index == mapping->selector - 1) {
+ found = 1;
+ break;
}
}
- mapping->ctrl = info;
- list_add_tail(&mapping->list, &info->mappings);
- uvc_trace(UVC_TRACE_CONTROL,
- "Adding mapping %s to control %pUl/%u.\n",
- mapping->name, info->entity, info->selector);
+ if (found)
+ break;
+ }
+ if (!found)
+ return -ENOENT;
- ret = 0;
- break;
+ if (mutex_lock_interruptible(&chain->ctrl_mutex))
+ return -ERESTARTSYS;
+
+ /* Perform delayed initialization of XU controls */
+ ret = uvc_ctrl_init_xu_ctrl(dev, ctrl);
+ if (ret < 0) {
+ ret = -ENOENT;
+ goto done;
}
-end:
- mutex_unlock(&uvc_driver.ctrl_mutex);
+
+ list_for_each_entry(map, &ctrl->info.mappings, list) {
+ if (mapping->id == map->id) {
+ uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', "
+ "control id 0x%08x already exists.\n",
+ mapping->name, mapping->id);
+ ret = -EEXIST;
+ goto done;
+ }
+ }
+
+ /* Prevent excess memory consumption */
+ if (atomic_inc_return(&dev->nmappings) > UVC_MAX_CONTROL_MAPPINGS) {
+ atomic_dec(&dev->nmappings);
+ uvc_trace(UVC_TRACE_CONTROL, "Can't add mapping '%s', maximum "
+ "mappings count (%u) exceeded.\n", mapping->name,
+ UVC_MAX_CONTROL_MAPPINGS);
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ ret = __uvc_ctrl_add_mapping(dev, ctrl, mapping);
+ if (ret < 0)
+ atomic_dec(&dev->nmappings);
+
+done:
+ mutex_unlock(&chain->ctrl_mutex);
return ret;
}
@@ -1453,29 +1631,49 @@ end:
* are currently the ones that crash the camera or unconditionally return an
* error when queried.
*/
-static void
-uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
+static void uvc_ctrl_prune_entity(struct uvc_device *dev,
+ struct uvc_entity *entity)
{
- static const struct {
+ struct uvc_ctrl_blacklist {
struct usb_device_id id;
u8 index;
- } blacklist[] = {
+ };
+
+ static const struct uvc_ctrl_blacklist processing_blacklist[] = {
{ { USB_DEVICE(0x13d3, 0x509b) }, 9 }, /* Gain */
{ { USB_DEVICE(0x1c4f, 0x3000) }, 6 }, /* WB Temperature */
{ { USB_DEVICE(0x5986, 0x0241) }, 2 }, /* Hue */
};
+ static const struct uvc_ctrl_blacklist camera_blacklist[] = {
+ { { USB_DEVICE(0x06f8, 0x3005) }, 9 }, /* Zoom, Absolute */
+ };
- u8 *controls;
+ const struct uvc_ctrl_blacklist *blacklist;
unsigned int size;
+ unsigned int count;
unsigned int i;
+ u8 *controls;
- if (UVC_ENTITY_TYPE(entity) != UVC_VC_PROCESSING_UNIT)
- return;
+ switch (UVC_ENTITY_TYPE(entity)) {
+ case UVC_VC_PROCESSING_UNIT:
+ blacklist = processing_blacklist;
+ count = ARRAY_SIZE(processing_blacklist);
+ controls = entity->processing.bmControls;
+ size = entity->processing.bControlSize;
+ break;
+
+ case UVC_ITT_CAMERA:
+ blacklist = camera_blacklist;
+ count = ARRAY_SIZE(camera_blacklist);
+ controls = entity->camera.bmControls;
+ size = entity->camera.bControlSize;
+ break;
- controls = entity->processing.bmControls;
- size = entity->processing.bControlSize;
+ default:
+ return;
+ }
- for (i = 0; i < ARRAY_SIZE(blacklist); ++i) {
+ for (i = 0; i < count; ++i) {
if (!usb_match_one_id(dev->intf, &blacklist[i].id))
continue;
@@ -1491,17 +1689,54 @@ uvc_ctrl_prune_entity(struct uvc_device *dev, struct uvc_entity *entity)
}
/*
+ * Add control information and hardcoded stock control mappings to the given
+ * device.
+ */
+static void uvc_ctrl_init_ctrl(struct uvc_device *dev, struct uvc_control *ctrl)
+{
+ const struct uvc_control_info *info = uvc_ctrls;
+ const struct uvc_control_info *iend = info + ARRAY_SIZE(uvc_ctrls);
+ const struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
+ const struct uvc_control_mapping *mend =
+ mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+
+ /* XU controls initialization requires querying the device for control
+ * information. As some buggy UVC devices will crash when queried
+ * repeatedly in a tight loop, delay XU controls initialization until
+ * first use.
+ */
+ if (UVC_ENTITY_TYPE(ctrl->entity) == UVC_VC_EXTENSION_UNIT)
+ return;
+
+ for (; info < iend; ++info) {
+ if (uvc_entity_match_guid(ctrl->entity, info->entity) &&
+ ctrl->index == info->index) {
+ uvc_ctrl_add_info(dev, ctrl, info);
+ break;
+ }
+ }
+
+ if (!ctrl->initialized)
+ return;
+
+ for (; mapping < mend; ++mapping) {
+ if (uvc_entity_match_guid(ctrl->entity, mapping->entity) &&
+ ctrl->info.selector == mapping->selector)
+ __uvc_ctrl_add_mapping(dev, ctrl, mapping);
+ }
+}
+
+/*
* Initialize device controls.
*/
int uvc_ctrl_init_device(struct uvc_device *dev)
{
- struct uvc_control_info *info;
- struct uvc_control *ctrl;
struct uvc_entity *entity;
unsigned int i;
/* Walk the entities list and instantiate controls */
list_for_each_entry(entity, &dev->entities, list) {
+ struct uvc_control *ctrl;
unsigned int bControlSize = 0, ncontrols = 0;
__u8 *bmControls = NULL;
@@ -1516,20 +1751,22 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
bControlSize = entity->camera.bControlSize;
}
+ /* Remove bogus/blacklisted controls */
uvc_ctrl_prune_entity(dev, entity);
+ /* Count supported controls and allocate the controls array */
for (i = 0; i < bControlSize; ++i)
ncontrols += hweight8(bmControls[i]);
-
if (ncontrols == 0)
continue;
- entity->controls = kzalloc(ncontrols*sizeof *ctrl, GFP_KERNEL);
+ entity->controls = kzalloc(ncontrols * sizeof(*ctrl),
+ GFP_KERNEL);
if (entity->controls == NULL)
return -ENOMEM;
-
entity->ncontrols = ncontrols;
+ /* Initialize all supported controls */
ctrl = entity->controls;
for (i = 0; i < bControlSize * 8; ++i) {
if (uvc_test_bit(bmControls, i) == 0)
@@ -1537,59 +1774,47 @@ int uvc_ctrl_init_device(struct uvc_device *dev)
ctrl->entity = entity;
ctrl->index = i;
+
+ uvc_ctrl_init_ctrl(dev, ctrl);
ctrl++;
}
}
- /* Walk the controls info list and associate them with the device
- * controls, then add the device to the global device list. This has
- * to be done while holding the controls lock, to make sure
- * uvc_ctrl_add_info() will not get called in-between.
- */
- mutex_lock(&uvc_driver.ctrl_mutex);
- list_for_each_entry(info, &uvc_driver.controls, list)
- uvc_ctrl_add_ctrl(dev, info);
-
- list_add_tail(&dev->list, &uvc_driver.devices);
- mutex_unlock(&uvc_driver.ctrl_mutex);
-
return 0;
}
/*
* Cleanup device controls.
*/
+static void uvc_ctrl_cleanup_mappings(struct uvc_device *dev,
+ struct uvc_control *ctrl)
+{
+ struct uvc_control_mapping *mapping, *nm;
+
+ list_for_each_entry_safe(mapping, nm, &ctrl->info.mappings, list) {
+ list_del(&mapping->list);
+ kfree(mapping->menu_info);
+ kfree(mapping);
+ }
+}
+
void uvc_ctrl_cleanup_device(struct uvc_device *dev)
{
struct uvc_entity *entity;
unsigned int i;
- /* Remove the device from the global devices list */
- mutex_lock(&uvc_driver.ctrl_mutex);
- if (dev->list.next != NULL)
- list_del(&dev->list);
- mutex_unlock(&uvc_driver.ctrl_mutex);
-
+ /* Free controls and control mappings for all entities. */
list_for_each_entry(entity, &dev->entities, list) {
- for (i = 0; i < entity->ncontrols; ++i)
- kfree(entity->controls[i].data);
-
- kfree(entity->controls);
- }
-}
+ for (i = 0; i < entity->ncontrols; ++i) {
+ struct uvc_control *ctrl = &entity->controls[i];
-void uvc_ctrl_init(void)
-{
- struct uvc_control_info *ctrl = uvc_ctrls;
- struct uvc_control_info *cend = ctrl + ARRAY_SIZE(uvc_ctrls);
- struct uvc_control_mapping *mapping = uvc_ctrl_mappings;
- struct uvc_control_mapping *mend =
- mapping + ARRAY_SIZE(uvc_ctrl_mappings);
+ if (!ctrl->initialized)
+ continue;
- for (; ctrl < cend; ++ctrl)
- uvc_ctrl_add_info(ctrl);
+ uvc_ctrl_cleanup_mappings(dev, ctrl);
+ kfree(ctrl->uvc_data);
+ }
- for (; mapping < mend; ++mapping)
- uvc_ctrl_add_mapping(mapping);
+ kfree(entity->controls);
+ }
}
-
diff --git a/drivers/media/video/uvc/uvc_driver.c b/drivers/media/video/uvc/uvc_driver.c
index 838b56f097cf..a1e9dfb52f69 100644
--- a/drivers/media/video/uvc/uvc_driver.c
+++ b/drivers/media/video/uvc/uvc_driver.c
@@ -1,8 +1,8 @@
/*
* uvc_driver.c -- USB Video Class driver
*
- * Copyright (C) 2005-2009
- * Laurent Pinchart (laurent.pinchart@skynet.be)
+ * Copyright (C) 2005-2010
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -38,11 +38,9 @@
#include "uvcvideo.h"
-#define DRIVER_AUTHOR "Laurent Pinchart <laurent.pinchart@skynet.be>"
+#define DRIVER_AUTHOR "Laurent Pinchart " \
+ "<laurent.pinchart@ideasonboard.com>"
#define DRIVER_DESC "USB Video Class driver"
-#ifndef DRIVER_VERSION
-#define DRIVER_VERSION "v0.1.0"
-#endif
unsigned int uvc_clock_param = CLOCK_MONOTONIC;
unsigned int uvc_no_drop_param;
@@ -486,6 +484,12 @@ static int uvc_parse_format(struct uvc_device *dev,
max(frame->dwFrameInterval[0],
frame->dwDefaultFrameInterval));
+ if (dev->quirks & UVC_QUIRK_RESTRICT_FRAME_RATE) {
+ frame->bFrameIntervalType = 1;
+ frame->dwFrameInterval[0] =
+ frame->dwDefaultFrameInterval;
+ }
+
uvc_trace(UVC_TRACE_DESCR, "- %ux%u (%u.%u fps)\n",
frame->wWidth, frame->wHeight,
10000000/frame->dwDefaultFrameInterval,
@@ -637,14 +641,13 @@ static int uvc_parse_streaming(struct uvc_device *dev,
}
streaming->header.bControlSize = n;
- streaming->header.bmaControls = kmalloc(p*n, GFP_KERNEL);
+ streaming->header.bmaControls = kmemdup(&buffer[size], 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];
@@ -1757,6 +1760,7 @@ static int uvc_probe(struct usb_interface *intf,
INIT_LIST_HEAD(&dev->streams);
atomic_set(&dev->nstreams, 0);
atomic_set(&dev->users, 0);
+ atomic_set(&dev->nmappings, 0);
dev->udev = usb_get_dev(udev);
dev->intf = usb_get_intf(intf);
@@ -1815,6 +1819,7 @@ static int uvc_probe(struct usb_interface *intf,
}
uvc_trace(UVC_TRACE_PROBE, "UVC device initialized.\n");
+ usb_enable_autosuspend(udev);
return 0;
error:
@@ -2027,6 +2032,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceClass = USB_CLASS_VENDOR_SPEC,
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0 },
+ /* Chicony CNF7129 (Asus EEE 100HE) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x04f2,
+ .idProduct = 0xb071,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_RESTRICT_FRAME_RATE },
/* Alcor Micro AU3820 (Future Boy PC USB Webcam) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2092,6 +2106,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_MINMAX
| UVC_QUIRK_PROBE_DEF },
+ /* IMC Networks (Medion Akoya) */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x13d3,
+ .idProduct = 0x5103,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
/* Syntek (HP Spartan) */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2146,6 +2169,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_STREAM_NO_FID },
+ /* Miricle 307K */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x17dc,
+ .idProduct = 0x0202,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_STREAM_NO_FID },
/* Lenovo Thinkpad SL400/SL500 */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2174,6 +2206,15 @@ static struct usb_device_id uvc_ids[] = {
.bInterfaceSubClass = 1,
.bInterfaceProtocol = 0,
.driver_info = UVC_QUIRK_PROBE_EXTRAFIELDS },
+ /* Manta MM-353 Plako */
+ { .match_flags = USB_DEVICE_ID_MATCH_DEVICE
+ | USB_DEVICE_ID_MATCH_INT_INFO,
+ .idVendor = 0x18ec,
+ .idProduct = 0x3188,
+ .bInterfaceClass = USB_CLASS_VIDEO,
+ .bInterfaceSubClass = 1,
+ .bInterfaceProtocol = 0,
+ .driver_info = UVC_QUIRK_PROBE_MINMAX },
/* FSC WebCam V30S */
{ .match_flags = USB_DEVICE_ID_MATCH_DEVICE
| USB_DEVICE_ID_MATCH_INT_INFO,
@@ -2246,12 +2287,6 @@ static int __init uvc_init(void)
{
int result;
- INIT_LIST_HEAD(&uvc_driver.devices);
- INIT_LIST_HEAD(&uvc_driver.controls);
- mutex_init(&uvc_driver.ctrl_mutex);
-
- uvc_ctrl_init();
-
result = usb_register(&uvc_driver.driver);
if (result == 0)
printk(KERN_INFO DRIVER_DESC " (" DRIVER_VERSION ")\n");
diff --git a/drivers/media/video/uvc/uvc_isight.c b/drivers/media/video/uvc/uvc_isight.c
index a9285b570dbe..74bbe8f18f3e 100644
--- a/drivers/media/video/uvc/uvc_isight.c
+++ b/drivers/media/video/uvc/uvc_isight.c
@@ -4,7 +4,7 @@
* Copyright (C) 2006-2007
* Ivan N. Zlatev <contact@i-nz.net>
* Copyright (C) 2008-2009
- * Laurent Pinchart <laurent.pinchart@skynet.be>
+ * Laurent Pinchart <laurent.pinchart@ideasonboard.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
diff --git a/drivers/media/video/uvc/uvc_queue.c b/drivers/media/video/uvc/uvc_queue.c
index 133c78d113ac..f14581bd707f 100644
--- a/drivers/media/video/uvc/uvc_queue.c
+++ b/drivers/media/video/uvc/uvc_queue.c
@@ -1,8 +1,8 @@
/*
* uvc_queue.c -- USB Video Class driver - Buffers management
*
- * Copyright (C) 2005-2009
- * Laurent Pinchart (laurent.pinchart@skynet.be)
+ * Copyright (C) 2005-2010
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -78,16 +78,51 @@
*
*/
-void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type)
+void uvc_queue_init(struct uvc_video_queue *queue, enum v4l2_buf_type type,
+ int drop_corrupted)
{
mutex_init(&queue->mutex);
spin_lock_init(&queue->irqlock);
INIT_LIST_HEAD(&queue->mainqueue);
INIT_LIST_HEAD(&queue->irqqueue);
+ queue->flags = drop_corrupted ? UVC_QUEUE_DROP_CORRUPTED : 0;
queue->type = type;
}
/*
+ * Free the video buffers.
+ *
+ * This function must be called with the queue lock held.
+ */
+static int __uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ unsigned int i;
+
+ for (i = 0; i < queue->count; ++i) {
+ if (queue->buffer[i].vma_use_count != 0)
+ return -EBUSY;
+ }
+
+ if (queue->count) {
+ vfree(queue->mem);
+ queue->count = 0;
+ }
+
+ return 0;
+}
+
+int uvc_free_buffers(struct uvc_video_queue *queue)
+{
+ int ret;
+
+ mutex_lock(&queue->mutex);
+ ret = __uvc_free_buffers(queue);
+ mutex_unlock(&queue->mutex);
+
+ return ret;
+}
+
+/*
* Allocate the video buffers.
*
* Pages are reserved to make sure they will not be swapped, as they will be
@@ -108,7 +143,7 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
mutex_lock(&queue->mutex);
- if ((ret = uvc_free_buffers(queue)) < 0)
+ if ((ret = __uvc_free_buffers(queue)) < 0)
goto done;
/* Bail out if no buffers should be allocated. */
@@ -133,7 +168,6 @@ int uvc_alloc_buffers(struct uvc_video_queue *queue, unsigned int nbuffers,
queue->buffer[i].buf.m.offset = i * bufsize;
queue->buffer[i].buf.length = buflength;
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;
queue->buffer[i].buf.flags = 0;
@@ -151,28 +185,6 @@ done:
}
/*
- * Free the video buffers.
- *
- * This function must be called with the queue lock held.
- */
-int uvc_free_buffers(struct uvc_video_queue *queue)
-{
- unsigned int i;
-
- for (i = 0; i < queue->count; ++i) {
- if (queue->buffer[i].vma_use_count != 0)
- return -EBUSY;
- }
-
- if (queue->count) {
- vfree(queue->mem);
- queue->count = 0;
- }
-
- return 0;
-}
-
-/*
* Check if buffers have been allocated.
*/
int uvc_queue_allocated(struct uvc_video_queue *queue)
@@ -368,6 +380,82 @@ done:
}
/*
+ * VMA operations.
+ */
+static void uvc_vm_open(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count++;
+}
+
+static void uvc_vm_close(struct vm_area_struct *vma)
+{
+ struct uvc_buffer *buffer = vma->vm_private_data;
+ buffer->vma_use_count--;
+}
+
+static const struct vm_operations_struct uvc_vm_ops = {
+ .open = uvc_vm_open,
+ .close = uvc_vm_close,
+};
+
+/*
+ * Memory-map a video buffer.
+ *
+ * This function implements video buffers memory mapping and is intended to be
+ * used by the device mmap handler.
+ */
+int uvc_queue_mmap(struct uvc_video_queue *queue, struct vm_area_struct *vma)
+{
+ struct uvc_buffer *uninitialized_var(buffer);
+ struct page *page;
+ unsigned long addr, start, size;
+ unsigned int i;
+ int ret = 0;
+
+ start = vma->vm_start;
+ size = vma->vm_end - vma->vm_start;
+
+ mutex_lock(&queue->mutex);
+
+ for (i = 0; i < queue->count; ++i) {
+ buffer = &queue->buffer[i];
+ if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
+ break;
+ }
+
+ if (i == queue->count || size != queue->buf_size) {
+ ret = -EINVAL;
+ goto done;
+ }
+
+ /*
+ * VM_IO marks the area as being an mmaped region for I/O to a
+ * device. It also prevents the region from being core dumped.
+ */
+ vma->vm_flags |= VM_IO;
+
+ addr = (unsigned long)queue->mem + buffer->buf.m.offset;
+ while (size > 0) {
+ page = vmalloc_to_page((void *)addr);
+ if ((ret = vm_insert_page(vma, start, page)) < 0)
+ goto done;
+
+ start += PAGE_SIZE;
+ addr += PAGE_SIZE;
+ size -= PAGE_SIZE;
+ }
+
+ vma->vm_ops = &uvc_vm_ops;
+ vma->vm_private_data = buffer;
+ uvc_vm_open(vma);
+
+done:
+ mutex_unlock(&queue->mutex);
+ return ret;
+}
+
+/*
* Poll the video queue.
*
* This function implements video queue polling and is intended to be used by
@@ -408,8 +496,7 @@ done:
* state can be properly initialized before buffers are accessed from the
* interrupt handler.
*
- * Enabling the video queue initializes parameters (such as sequence number,
- * sync pattern, ...). If the queue is already enabled, return -EBUSY.
+ * Enabling the video queue returns -EBUSY if the queue is already enabled.
*
* Disabling the video queue cancels the queue and removes all buffers from
* the main queue.
@@ -428,15 +515,16 @@ int uvc_queue_enable(struct uvc_video_queue *queue, int enable)
ret = -EBUSY;
goto done;
}
- queue->sequence = 0;
queue->flags |= UVC_QUEUE_STREAMING;
queue->buf_used = 0;
} else {
uvc_queue_cancel(queue, 0);
INIT_LIST_HEAD(&queue->mainqueue);
- for (i = 0; i < queue->count; ++i)
+ for (i = 0; i < queue->count; ++i) {
+ queue->buffer[i].error = 0;
queue->buffer[i].state = UVC_BUF_STATE_IDLE;
+ }
queue->flags &= ~UVC_QUEUE_STREAMING;
}
@@ -488,8 +576,8 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *nextbuf;
unsigned long flags;
- if ((queue->flags & UVC_QUEUE_DROP_INCOMPLETE) &&
- buf->buf.length != buf->buf.bytesused) {
+ if ((queue->flags & UVC_QUEUE_DROP_CORRUPTED) && buf->error) {
+ buf->error = 0;
buf->state = UVC_BUF_STATE_QUEUED;
buf->buf.bytesused = 0;
return buf;
@@ -497,6 +585,7 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
spin_lock_irqsave(&queue->irqlock, flags);
list_del(&buf->queue);
+ buf->error = 0;
buf->state = UVC_BUF_STATE_DONE;
if (!list_empty(&queue->irqqueue))
nextbuf = list_first_entry(&queue->irqqueue, struct uvc_buffer,
@@ -505,8 +594,6 @@ struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
nextbuf = NULL;
spin_unlock_irqrestore(&queue->irqlock, flags);
- buf->buf.sequence = queue->sequence++;
-
wake_up(&buf->wait);
return nextbuf;
}
diff --git a/drivers/media/video/uvc/uvc_status.c b/drivers/media/video/uvc/uvc_status.c
index 85019bdacdf7..b7492775e6ae 100644
--- a/drivers/media/video/uvc/uvc_status.c
+++ b/drivers/media/video/uvc/uvc_status.c
@@ -1,8 +1,8 @@
/*
* uvc_status.c -- USB Video Class driver - Status endpoint
*
- * Copyright (C) 2007-2009
- * Laurent Pinchart (laurent.pinchart@skynet.be)
+ * Copyright (C) 2005-2009
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.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
diff --git a/drivers/media/video/uvc/uvc_v4l2.c b/drivers/media/video/uvc/uvc_v4l2.c
index 7c9ab2933496..9005a8d9d5f8 100644
--- a/drivers/media/video/uvc/uvc_v4l2.c
+++ b/drivers/media/video/uvc/uvc_v4l2.c
@@ -1,8 +1,8 @@
/*
* uvc_v4l2.c -- USB Video Class driver - V4L2 API
*
- * Copyright (C) 2005-2009
- * Laurent Pinchart (laurent.pinchart@skynet.be)
+ * Copyright (C) 2005-2010
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -29,43 +29,77 @@
#include "uvcvideo.h"
/* ------------------------------------------------------------------------
- * V4L2 interface
- */
-
-/*
- * Mapping V4L2 controls to UVC controls can be straighforward if done well.
- * Most of the UVC controls exist in V4L2, and can be mapped directly. Some
- * must be grouped (for instance the Red Balance, Blue Balance and Do White
- * Balance V4L2 controls use the White Balance Component UVC control) or
- * otherwise translated. The approach we take here is to use a translation
- * table for the controls that can be mapped directly, and handle the others
- * manually.
+ * UVC ioctls
*/
-static int uvc_v4l2_query_menu(struct uvc_video_chain *chain,
- struct v4l2_querymenu *query_menu)
+static int uvc_ioctl_ctrl_map(struct uvc_video_chain *chain,
+ struct uvc_xu_control_mapping *xmap, int old)
{
- struct uvc_menu_info *menu_info;
- struct uvc_control_mapping *mapping;
- struct uvc_control *ctrl;
- u32 index = query_menu->index;
- u32 id = query_menu->id;
-
- ctrl = uvc_find_control(chain, query_menu->id, &mapping);
- if (ctrl == NULL || mapping->v4l2_type != V4L2_CTRL_TYPE_MENU)
- return -EINVAL;
+ struct uvc_control_mapping *map;
+ unsigned int size;
+ int ret;
- if (query_menu->index >= mapping->menu_count)
- return -EINVAL;
+ map = kzalloc(sizeof *map, GFP_KERNEL);
+ if (map == NULL)
+ return -ENOMEM;
- memset(query_menu, 0, sizeof(*query_menu));
- query_menu->id = id;
- query_menu->index = index;
+ map->id = xmap->id;
+ memcpy(map->name, xmap->name, sizeof map->name);
+ memcpy(map->entity, xmap->entity, sizeof map->entity);
+ map->selector = xmap->selector;
+ map->size = xmap->size;
+ map->offset = xmap->offset;
+ map->v4l2_type = xmap->v4l2_type;
+ map->data_type = xmap->data_type;
+
+ switch (xmap->v4l2_type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ case V4L2_CTRL_TYPE_BUTTON:
+ break;
- menu_info = &mapping->menu_info[query_menu->index];
- strlcpy(query_menu->name, menu_info->name, sizeof query_menu->name);
- return 0;
+ case V4L2_CTRL_TYPE_MENU:
+ if (old) {
+ uvc_trace(UVC_TRACE_CONTROL, "V4L2_CTRL_TYPE_MENU not "
+ "supported for UVCIOC_CTRL_MAP_OLD.\n");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ size = xmap->menu_count * sizeof(*map->menu_info);
+ map->menu_info = kmalloc(size, GFP_KERNEL);
+ if (map->menu_info == NULL) {
+ ret = -ENOMEM;
+ goto done;
+ }
+
+ if (copy_from_user(map->menu_info, xmap->menu_info, size)) {
+ ret = -EFAULT;
+ goto done;
+ }
+
+ map->menu_count = xmap->menu_count;
+ break;
+
+ default:
+ uvc_trace(UVC_TRACE_CONTROL, "Unsupported V4L2 control type "
+ "%u.\n", xmap->v4l2_type);
+ ret = -EINVAL;
+ goto done;
+ }
+
+ ret = uvc_ctrl_add_mapping(chain, map);
+
+done:
+ kfree(map->menu_info);
+ kfree(map);
+
+ return ret;
}
+/* ------------------------------------------------------------------------
+ * V4L2 interface
+ */
+
/*
* Find the frame interval closest to the requested frame interval for the
* given frame format and size. This should be done by the device as part of
@@ -192,12 +226,14 @@ static int uvc_v4l2_try_format(struct uvc_streaming *stream,
* developers test their webcams with the Linux driver as well as with
* the Windows driver).
*/
+ mutex_lock(&stream->mutex);
if (stream->dev->quirks & UVC_QUIRK_PROBE_EXTRAFIELDS)
probe->dwMaxVideoFrameSize =
stream->ctrl.dwMaxVideoFrameSize;
/* Probe the device. */
ret = uvc_probe_video(stream, probe);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
goto done;
@@ -221,14 +257,21 @@ done:
static int uvc_v4l2_get_format(struct uvc_streaming *stream,
struct v4l2_format *fmt)
{
- struct uvc_format *format = stream->cur_format;
- struct uvc_frame *frame = stream->cur_frame;
+ struct uvc_format *format;
+ struct uvc_frame *frame;
+ int ret = 0;
if (fmt->type != stream->type)
return -EINVAL;
- if (format == NULL || frame == NULL)
- return -EINVAL;
+ mutex_lock(&stream->mutex);
+ format = stream->cur_format;
+ frame = stream->cur_frame;
+
+ if (format == NULL || frame == NULL) {
+ ret = -EINVAL;
+ goto done;
+ }
fmt->fmt.pix.pixelformat = format->fcc;
fmt->fmt.pix.width = frame->wWidth;
@@ -239,7 +282,9 @@ static int uvc_v4l2_get_format(struct uvc_streaming *stream,
fmt->fmt.pix.colorspace = format->colorspace;
fmt->fmt.pix.priv = 0;
- return 0;
+done:
+ mutex_unlock(&stream->mutex);
+ return ret;
}
static int uvc_v4l2_set_format(struct uvc_streaming *stream,
@@ -253,18 +298,24 @@ static int uvc_v4l2_set_format(struct uvc_streaming *stream,
if (fmt->type != stream->type)
return -EINVAL;
- if (uvc_queue_allocated(&stream->queue))
- return -EBUSY;
-
ret = uvc_v4l2_try_format(stream, fmt, &probe, &format, &frame);
if (ret < 0)
return ret;
+ mutex_lock(&stream->mutex);
+
+ if (uvc_queue_allocated(&stream->queue)) {
+ ret = -EBUSY;
+ goto done;
+ }
+
memcpy(&stream->ctrl, &probe, sizeof probe);
stream->cur_format = format;
stream->cur_frame = frame;
- return 0;
+done:
+ mutex_unlock(&stream->mutex);
+ return ret;
}
static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
@@ -275,7 +326,10 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
if (parm->type != stream->type)
return -EINVAL;
+ mutex_lock(&stream->mutex);
numerator = stream->ctrl.dwFrameInterval;
+ mutex_unlock(&stream->mutex);
+
denominator = 10000000;
uvc_simplify_fraction(&numerator, &denominator, 8, 333);
@@ -302,7 +356,6 @@ static int uvc_v4l2_get_streamparm(struct uvc_streaming *stream,
static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
struct v4l2_streamparm *parm)
{
- struct uvc_frame *frame = stream->cur_frame;
struct uvc_streaming_control probe;
struct v4l2_fract timeperframe;
uint32_t interval;
@@ -311,28 +364,36 @@ static int uvc_v4l2_set_streamparm(struct uvc_streaming *stream,
if (parm->type != stream->type)
return -EINVAL;
- if (uvc_queue_streaming(&stream->queue))
- return -EBUSY;
-
if (parm->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
timeperframe = parm->parm.capture.timeperframe;
else
timeperframe = parm->parm.output.timeperframe;
- memcpy(&probe, &stream->ctrl, sizeof probe);
interval = uvc_fraction_to_interval(timeperframe.numerator,
timeperframe.denominator);
-
uvc_trace(UVC_TRACE_FORMAT, "Setting frame interval to %u/%u (%u).\n",
timeperframe.numerator, timeperframe.denominator, interval);
- probe.dwFrameInterval = uvc_try_frame_interval(frame, interval);
+
+ mutex_lock(&stream->mutex);
+
+ if (uvc_queue_streaming(&stream->queue)) {
+ mutex_unlock(&stream->mutex);
+ return -EBUSY;
+ }
+
+ memcpy(&probe, &stream->ctrl, sizeof probe);
+ probe.dwFrameInterval =
+ uvc_try_frame_interval(stream->cur_frame, interval);
/* Probe the device with the new settings. */
ret = uvc_probe_video(stream, &probe);
- if (ret < 0)
+ if (ret < 0) {
+ mutex_unlock(&stream->mutex);
return ret;
+ }
memcpy(&stream->ctrl, &probe, sizeof probe);
+ mutex_unlock(&stream->mutex);
/* Return the actual frame period. */
timeperframe.numerator = probe.dwFrameInterval;
@@ -451,7 +512,7 @@ static int uvc_v4l2_open(struct file *file)
static int uvc_v4l2_release(struct file *file)
{
- struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_release\n");
@@ -460,11 +521,9 @@ static int uvc_v4l2_release(struct file *file)
if (uvc_has_privileges(handle)) {
uvc_video_enable(stream, 0);
- mutex_lock(&stream->queue.mutex);
if (uvc_free_buffers(&stream->queue) < 0)
uvc_printk(KERN_ERR, "uvc_v4l2_release: Unable to "
"free buffers.\n");
- mutex_unlock(&stream->queue.mutex);
}
/* Release the file handle. */
@@ -482,7 +541,7 @@ static int uvc_v4l2_release(struct file *file)
static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
{
struct video_device *vdev = video_devdata(file);
- struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_fh *handle = file->private_data;
struct uvc_video_chain *chain = handle->chain;
struct uvc_streaming *stream = handle->stream;
long ret = 0;
@@ -556,7 +615,7 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
}
case VIDIOC_QUERYMENU:
- return uvc_v4l2_query_menu(chain, arg);
+ return uvc_query_v4l2_menu(chain, arg);
case VIDIOC_G_EXT_CTRLS:
{
@@ -837,15 +896,17 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_CROPCAP:
{
struct v4l2_cropcap *ccap = arg;
- struct uvc_frame *frame = stream->cur_frame;
if (ccap->type != stream->type)
return -EINVAL;
ccap->bounds.left = 0;
ccap->bounds.top = 0;
- ccap->bounds.width = frame->wWidth;
- ccap->bounds.height = frame->wHeight;
+
+ mutex_lock(&stream->mutex);
+ ccap->bounds.width = stream->cur_frame->wWidth;
+ ccap->bounds.height = stream->cur_frame->wHeight;
+ mutex_unlock(&stream->mutex);
ccap->defrect = ccap->bounds;
@@ -862,8 +923,6 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
case VIDIOC_REQBUFS:
{
struct v4l2_requestbuffers *rb = arg;
- unsigned int bufsize =
- stream->ctrl.dwMaxVideoFrameSize;
if (rb->type != stream->type ||
rb->memory != V4L2_MEMORY_MMAP)
@@ -872,7 +931,10 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if ((ret = uvc_acquire_privileges(handle)) < 0)
return ret;
- ret = uvc_alloc_buffers(&stream->queue, rb->count, bufsize);
+ mutex_lock(&stream->mutex);
+ ret = uvc_alloc_buffers(&stream->queue, rb->count,
+ stream->ctrl.dwMaxVideoFrameSize);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
@@ -920,7 +982,9 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
if (!uvc_has_privileges(handle))
return -EBUSY;
+ mutex_lock(&stream->mutex);
ret = uvc_video_enable(stream, 1);
+ mutex_unlock(&stream->mutex);
if (ret < 0)
return ret;
break;
@@ -956,58 +1020,13 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
/* Dynamic controls. */
case UVCIOC_CTRL_ADD:
- {
- struct uvc_xu_control_info *xinfo = arg;
- struct uvc_control_info *info;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- info = kzalloc(sizeof *info, GFP_KERNEL);
- if (info == NULL)
- return -ENOMEM;
-
- memcpy(info->entity, xinfo->entity, sizeof info->entity);
- info->index = xinfo->index;
- info->selector = xinfo->selector;
- info->size = xinfo->size;
- info->flags = xinfo->flags;
-
- info->flags |= UVC_CONTROL_GET_MIN | UVC_CONTROL_GET_MAX |
- UVC_CONTROL_GET_RES | UVC_CONTROL_GET_DEF;
-
- ret = uvc_ctrl_add_info(info);
- if (ret < 0)
- kfree(info);
- break;
- }
+ /* Legacy ioctl, kept for API compatibility reasons */
+ return -EEXIST;
+ case UVCIOC_CTRL_MAP_OLD:
case UVCIOC_CTRL_MAP:
- {
- struct uvc_xu_control_mapping *xmap = arg;
- struct uvc_control_mapping *map;
-
- if (!capable(CAP_SYS_ADMIN))
- return -EPERM;
-
- map = kzalloc(sizeof *map, GFP_KERNEL);
- if (map == NULL)
- return -ENOMEM;
-
- map->id = xmap->id;
- memcpy(map->name, xmap->name, sizeof map->name);
- memcpy(map->entity, xmap->entity, sizeof map->entity);
- map->selector = xmap->selector;
- map->size = xmap->size;
- map->offset = xmap->offset;
- map->v4l2_type = xmap->v4l2_type;
- map->data_type = xmap->data_type;
-
- ret = uvc_ctrl_add_mapping(map);
- if (ret < 0)
- kfree(map);
- break;
- }
+ return uvc_ioctl_ctrl_map(chain, arg,
+ cmd == UVCIOC_CTRL_MAP_OLD);
case UVCIOC_CTRL_GET:
return uvc_xu_ctrl_query(chain, arg, 0);
@@ -1016,11 +1035,8 @@ static long uvc_v4l2_do_ioctl(struct file *file, unsigned int cmd, void *arg)
return uvc_xu_ctrl_query(chain, arg, 1);
default:
- if ((ret = v4l_compat_translate_ioctl(file, cmd, arg,
- uvc_v4l2_do_ioctl)) == -ENOIOCTLCMD)
- uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n",
- cmd);
- return ret;
+ uvc_trace(UVC_TRACE_IOCTL, "Unknown ioctl 0x%08x\n", cmd);
+ return -EINVAL;
}
return ret;
@@ -1045,84 +1061,19 @@ static ssize_t uvc_v4l2_read(struct file *file, char __user *data,
return -EINVAL;
}
-/*
- * VMA operations.
- */
-static void uvc_vm_open(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count++;
-}
-
-static void uvc_vm_close(struct vm_area_struct *vma)
-{
- struct uvc_buffer *buffer = vma->vm_private_data;
- buffer->vma_use_count--;
-}
-
-static const struct vm_operations_struct uvc_vm_ops = {
- .open = uvc_vm_open,
- .close = uvc_vm_close,
-};
-
static int uvc_v4l2_mmap(struct file *file, struct vm_area_struct *vma)
{
- struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
- struct uvc_video_queue *queue = &stream->queue;
- struct uvc_buffer *uninitialized_var(buffer);
- struct page *page;
- unsigned long addr, start, size;
- unsigned int i;
- int ret = 0;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_mmap\n");
- start = vma->vm_start;
- size = vma->vm_end - vma->vm_start;
-
- mutex_lock(&queue->mutex);
-
- for (i = 0; i < queue->count; ++i) {
- buffer = &queue->buffer[i];
- if ((buffer->buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
-
- if (i == queue->count || size != queue->buf_size) {
- ret = -EINVAL;
- goto done;
- }
-
- /*
- * VM_IO marks the area as being an mmaped region for I/O to a
- * device. It also prevents the region from being core dumped.
- */
- vma->vm_flags |= VM_IO;
-
- addr = (unsigned long)queue->mem + buffer->buf.m.offset;
- while (size > 0) {
- page = vmalloc_to_page((void *)addr);
- if ((ret = vm_insert_page(vma, start, page)) < 0)
- goto done;
-
- start += PAGE_SIZE;
- addr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &uvc_vm_ops;
- vma->vm_private_data = buffer;
- uvc_vm_open(vma);
-
-done:
- mutex_unlock(&queue->mutex);
- return ret;
+ return uvc_queue_mmap(&stream->queue, vma);
}
static unsigned int uvc_v4l2_poll(struct file *file, poll_table *wait)
{
- struct uvc_fh *handle = (struct uvc_fh *)file->private_data;
+ struct uvc_fh *handle = file->private_data;
struct uvc_streaming *stream = handle->stream;
uvc_trace(UVC_TRACE_CALLS, "uvc_v4l2_poll\n");
@@ -1134,7 +1085,7 @@ const struct v4l2_file_operations uvc_fops = {
.owner = THIS_MODULE,
.open = uvc_v4l2_open,
.release = uvc_v4l2_release,
- .ioctl = uvc_v4l2_ioctl,
+ .unlocked_ioctl = uvc_v4l2_ioctl,
.read = uvc_v4l2_read,
.mmap = uvc_v4l2_mmap,
.poll = uvc_v4l2_poll,
diff --git a/drivers/media/video/uvc/uvc_video.c b/drivers/media/video/uvc/uvc_video.c
index 53f3ef4635eb..5673d673504b 100644
--- a/drivers/media/video/uvc/uvc_video.c
+++ b/drivers/media/video/uvc/uvc_video.c
@@ -1,8 +1,8 @@
/*
* uvc_video.c -- USB Video Class driver - Video handling
*
- * Copyright (C) 2005-2009
- * Laurent Pinchart (laurent.pinchart@skynet.be)
+ * Copyright (C) 2005-2010
+ * Laurent Pinchart (laurent.pinchart@ideasonboard.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
@@ -45,6 +45,30 @@ static int __uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
unit << 8 | intfnum, data, size, timeout);
}
+static const char *uvc_query_name(__u8 query)
+{
+ switch (query) {
+ case UVC_SET_CUR:
+ return "SET_CUR";
+ case UVC_GET_CUR:
+ return "GET_CUR";
+ case UVC_GET_MIN:
+ return "GET_MIN";
+ case UVC_GET_MAX:
+ return "GET_MAX";
+ case UVC_GET_RES:
+ return "GET_RES";
+ case UVC_GET_LEN:
+ return "GET_LEN";
+ case UVC_GET_INFO:
+ return "GET_INFO";
+ case UVC_GET_DEF:
+ return "GET_DEF";
+ default:
+ return "<invalid>";
+ }
+}
+
int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
__u8 intfnum, __u8 cs, void *data, __u16 size)
{
@@ -53,9 +77,9 @@ int uvc_query_ctrl(struct uvc_device *dev, __u8 query, __u8 unit,
ret = __uvc_query_ctrl(dev, query, unit, intfnum, cs, data, size,
UVC_CTRL_CONTROL_TIMEOUT);
if (ret != size) {
- uvc_printk(KERN_ERR, "Failed to query (%u) UVC control %u "
- "(unit %u) : %d (exp. %u).\n", query, cs, unit, ret,
- size);
+ uvc_printk(KERN_ERR, "Failed to query (%s) UVC control %u on "
+ "unit %u: %d (exp. %u).\n", uvc_query_name(query), cs,
+ unit, ret, size);
return -EIO;
}
@@ -114,6 +138,15 @@ static void uvc_fixup_video_ctrl(struct uvc_streaming *stream,
bandwidth /= 8;
bandwidth += 12;
+ /* The bandwidth estimate is too low for many cameras. Don't use
+ * maximum packet sizes lower than 1024 bytes to try and work
+ * around the problem. According to measurements done on two
+ * different camera models, the value is high enough to get most
+ * resolutions working while not preventing two simultaneous
+ * VGA streams at 15 fps.
+ */
+ bandwidth = max_t(u32, bandwidth, 1024);
+
ctrl->dwMaxPayloadTransferSize = bandwidth;
}
}
@@ -260,8 +293,6 @@ int uvc_probe_video(struct uvc_streaming *stream,
unsigned int i;
int ret;
- mutex_lock(&stream->mutex);
-
/* Perform probing. The device should adjust the requested values
* according to its capabilities. However, some devices, namely the
* first generation UVC Logitech webcams, don't implement the Video
@@ -313,7 +344,6 @@ int uvc_probe_video(struct uvc_streaming *stream,
}
done:
- mutex_unlock(&stream->mutex);
return ret;
}
@@ -394,6 +424,12 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
fid = data[1] & UVC_STREAM_FID;
+ /* Increase the sequence number regardless of any buffer states, so
+ * that discontinuous sequence numbers always indicate lost frames.
+ */
+ if (stream->last_fid != fid)
+ stream->sequence++;
+
/* Store the payload FID bit and return immediately when the buffer is
* NULL.
*/
@@ -427,6 +463,7 @@ static int uvc_video_decode_start(struct uvc_streaming *stream,
else
ktime_get_real_ts(&ts);
+ buf->buf.sequence = stream->sequence;
buf->buf.timestamp.tv_sec = ts.tv_sec;
buf->buf.timestamp.tv_usec = ts.tv_nsec / NSEC_PER_USEC;
@@ -555,6 +592,9 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
if (urb->iso_frame_desc[i].status < 0) {
uvc_trace(UVC_TRACE_FRAME, "USB isochronous frame "
"lost (%d).\n", urb->iso_frame_desc[i].status);
+ /* Mark the buffer as faulty. */
+ if (buf != NULL)
+ buf->error = 1;
continue;
}
@@ -579,8 +619,14 @@ static void uvc_video_decode_isoc(struct urb *urb, struct uvc_streaming *stream,
uvc_video_decode_end(stream, buf, mem,
urb->iso_frame_desc[i].actual_length);
- if (buf->state == UVC_BUF_STATE_READY)
+ if (buf->state == UVC_BUF_STATE_READY) {
+ if (buf->buf.length != buf->buf.bytesused &&
+ !(stream->cur_format->flags &
+ UVC_FMT_FLAG_COMPRESSED))
+ buf->error = 1;
+
buf = uvc_queue_next_buffer(&stream->queue, buf);
+ }
}
}
@@ -679,6 +725,7 @@ static void uvc_video_encode_bulk(struct urb *urb, struct uvc_streaming *stream,
if (buf->buf.bytesused == stream->queue.buf_used) {
stream->queue.buf_used = 0;
buf->state = UVC_BUF_STATE_READY;
+ buf->buf.sequence = ++stream->sequence;
uvc_queue_next_buffer(&stream->queue, buf);
stream->last_fid ^= UVC_STREAM_FID;
}
@@ -937,6 +984,7 @@ static int uvc_init_video(struct uvc_streaming *stream, gfp_t gfp_flags)
unsigned int i;
int ret;
+ stream->sequence = -1;
stream->last_fid = -1;
stream->bulk.header_size = 0;
stream->bulk.skip_payload = 0;
@@ -1104,7 +1152,7 @@ int uvc_video_init(struct uvc_streaming *stream)
atomic_set(&stream->active, 0);
/* Initialize the video buffers queue. */
- uvc_queue_init(&stream->queue, stream->type);
+ uvc_queue_init(&stream->queue, stream->type, !uvc_no_drop_param);
/* Alternate setting 0 should be the default, yet the XBox Live Vision
* Cam (and possibly other devices) crash or otherwise misbehave if
@@ -1197,12 +1245,6 @@ int uvc_video_enable(struct uvc_streaming *stream, int enable)
return 0;
}
- if ((stream->cur_format->flags & UVC_FMT_FLAG_COMPRESSED) ||
- uvc_no_drop_param)
- stream->queue.flags &= ~UVC_QUEUE_DROP_INCOMPLETE;
- else
- stream->queue.flags |= UVC_QUEUE_DROP_INCOMPLETE;
-
ret = uvc_queue_enable(&stream->queue, 1);
if (ret < 0)
return ret;
diff --git a/drivers/media/video/uvc/uvcvideo.h b/drivers/media/video/uvc/uvcvideo.h
index d1f88406a5e7..45f01e7e13d2 100644
--- a/drivers/media/video/uvc/uvcvideo.h
+++ b/drivers/media/video/uvc/uvcvideo.h
@@ -40,6 +40,15 @@ struct uvc_xu_control_info {
__u32 flags;
};
+struct uvc_menu_info {
+ __u32 value;
+ __u8 name[32];
+};
+
+struct uvc_xu_control_mapping_old {
+ __u8 reserved[64];
+};
+
struct uvc_xu_control_mapping {
__u32 id;
__u8 name[32];
@@ -50,6 +59,11 @@ struct uvc_xu_control_mapping {
__u8 offset;
enum v4l2_ctrl_type v4l2_type;
__u32 data_type;
+
+ struct uvc_menu_info __user *menu_info;
+ __u32 menu_count;
+
+ __u32 reserved[4];
};
struct uvc_xu_control {
@@ -60,6 +74,7 @@ struct uvc_xu_control {
};
#define UVCIOC_CTRL_ADD _IOW('U', 1, struct uvc_xu_control_info)
+#define UVCIOC_CTRL_MAP_OLD _IOWR('U', 2, struct uvc_xu_control_mapping_old)
#define UVCIOC_CTRL_MAP _IOWR('U', 2, struct uvc_xu_control_mapping)
#define UVCIOC_CTRL_GET _IOWR('U', 3, struct uvc_xu_control)
#define UVCIOC_CTRL_SET _IOW('U', 4, struct uvc_xu_control)
@@ -142,7 +157,8 @@ struct uvc_xu_control {
* Driver specific constants.
*/
-#define DRIVER_VERSION_NUMBER KERNEL_VERSION(0, 1, 0)
+#define DRIVER_VERSION_NUMBER KERNEL_VERSION(1, 0, 0)
+#define DRIVER_VERSION "v1.0.0"
/* Number of isochronous URBs. */
#define UVC_URBS 5
@@ -156,6 +172,9 @@ struct uvc_xu_control {
#define UVC_CTRL_CONTROL_TIMEOUT 300
#define UVC_CTRL_STREAMING_TIMEOUT 5000
+/* Maximum allowed number of control mappings per device */
+#define UVC_MAX_CONTROL_MAPPINGS 1024
+
/* Devices quirks */
#define UVC_QUIRK_STATUS_INTERVAL 0x00000001
#define UVC_QUIRK_PROBE_MINMAX 0x00000002
@@ -165,6 +184,7 @@ struct uvc_xu_control {
#define UVC_QUIRK_IGNORE_SELECTOR_UNIT 0x00000020
#define UVC_QUIRK_FIX_BANDWIDTH 0x00000080
#define UVC_QUIRK_PROBE_DEF 0x00000100
+#define UVC_QUIRK_RESTRICT_FRAME_RATE 0x00000200
/* Format flags */
#define UVC_FMT_FLAG_COMPRESSED 0x00000001
@@ -179,36 +199,11 @@ struct uvc_device;
/* TODO: Put the most frequently accessed fields at the beginning of
* structures to maximize cache efficiency.
*/
-struct uvc_streaming_control {
- __u16 bmHint;
- __u8 bFormatIndex;
- __u8 bFrameIndex;
- __u32 dwFrameInterval;
- __u16 wKeyFrameRate;
- __u16 wPFrameRate;
- __u16 wCompQuality;
- __u16 wCompWindowSize;
- __u16 wDelay;
- __u32 dwMaxVideoFrameSize;
- __u32 dwMaxPayloadTransferSize;
- __u32 dwClockFrequency;
- __u8 bmFramingInfo;
- __u8 bPreferedVersion;
- __u8 bMinVersion;
- __u8 bMaxVersion;
-};
-
-struct uvc_menu_info {
- __u32 value;
- __u8 name[32];
-};
-
struct uvc_control_info {
- struct list_head list;
struct list_head mappings;
__u8 entity[16];
- __u8 index;
+ __u8 index; /* Bit index in bmControls */
__u8 selector;
__u16 size;
@@ -241,16 +236,17 @@ struct uvc_control_mapping {
struct uvc_control {
struct uvc_entity *entity;
- struct uvc_control_info *info;
+ struct uvc_control_info info;
__u8 index; /* Used to match the uvc_control entry with a
uvc_control_info. */
- __u8 dirty : 1,
- loaded : 1,
- modified : 1,
- cached : 1;
+ __u8 dirty:1,
+ loaded:1,
+ modified:1,
+ cached:1,
+ initialized:1;
- __u8 *data;
+ __u8 *uvc_data;
};
struct uvc_format_desc {
@@ -385,18 +381,18 @@ struct uvc_buffer {
struct list_head queue;
wait_queue_head_t wait;
enum uvc_buffer_state state;
+ unsigned int error;
};
#define UVC_QUEUE_STREAMING (1 << 0)
#define UVC_QUEUE_DISCONNECTED (1 << 1)
-#define UVC_QUEUE_DROP_INCOMPLETE (1 << 2)
+#define UVC_QUEUE_DROP_CORRUPTED (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;
@@ -417,7 +413,7 @@ struct uvc_video_chain {
struct uvc_entity *processing; /* Processing unit */
struct uvc_entity *selector; /* Selector unit */
- struct mutex ctrl_mutex;
+ struct mutex ctrl_mutex; /* Protects ctrl.info */
};
struct uvc_streaming {
@@ -440,7 +436,9 @@ struct uvc_streaming {
struct uvc_streaming_control ctrl;
struct uvc_format *cur_format;
struct uvc_frame *cur_frame;
-
+ /* Protect access to ctrl, cur_format, cur_frame and hardware video
+ * probe control.
+ */
struct mutex mutex;
unsigned int frozen : 1;
@@ -462,6 +460,7 @@ struct uvc_streaming {
dma_addr_t urb_dma[UVC_URBS];
unsigned int urb_size;
+ __u32 sequence;
__u8 last_fid;
};
@@ -478,8 +477,8 @@ struct uvc_device {
char name[32];
enum uvc_device_state state;
- struct list_head list;
atomic_t users;
+ atomic_t nmappings;
/* Video control interface */
__u16 uvc_version;
@@ -513,11 +512,6 @@ struct uvc_fh {
struct uvc_driver {
struct usb_driver driver;
-
- struct list_head devices; /* struct uvc_device list */
- struct list_head controls; /* struct uvc_control_info list */
- struct mutex ctrl_mutex; /* protects controls and devices
- lists */
};
/* ------------------------------------------------------------------------
@@ -568,7 +562,7 @@ extern struct uvc_driver uvc_driver;
/* Video buffers queue management. */
extern void uvc_queue_init(struct uvc_video_queue *queue,
- enum v4l2_buf_type type);
+ enum v4l2_buf_type type, int drop_corrupted);
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);
@@ -582,6 +576,8 @@ extern int uvc_queue_enable(struct uvc_video_queue *queue, int enable);
extern void uvc_queue_cancel(struct uvc_video_queue *queue, int disconnect);
extern struct uvc_buffer *uvc_queue_next_buffer(struct uvc_video_queue *queue,
struct uvc_buffer *buf);
+extern int uvc_queue_mmap(struct uvc_video_queue *queue,
+ struct vm_area_struct *vma);
extern unsigned int uvc_queue_poll(struct uvc_video_queue *queue,
struct file *file, poll_table *wait);
extern int uvc_queue_allocated(struct uvc_video_queue *queue);
@@ -614,17 +610,16 @@ extern int uvc_status_suspend(struct uvc_device *dev);
extern int uvc_status_resume(struct uvc_device *dev);
/* Controls */
-extern struct uvc_control *uvc_find_control(struct uvc_video_chain *chain,
- __u32 v4l2_id, struct uvc_control_mapping **mapping);
extern int uvc_query_v4l2_ctrl(struct uvc_video_chain *chain,
struct v4l2_queryctrl *v4l2_ctrl);
+extern int uvc_query_v4l2_menu(struct uvc_video_chain *chain,
+ struct v4l2_querymenu *query_menu);
-extern int uvc_ctrl_add_info(struct uvc_control_info *info);
-extern int uvc_ctrl_add_mapping(struct uvc_control_mapping *mapping);
+extern int uvc_ctrl_add_mapping(struct uvc_video_chain *chain,
+ const struct uvc_control_mapping *mapping);
extern int uvc_ctrl_init_device(struct uvc_device *dev);
extern void uvc_ctrl_cleanup_device(struct uvc_device *dev);
extern int uvc_ctrl_resume_device(struct uvc_device *dev);
-extern void uvc_ctrl_init(void);
extern int uvc_ctrl_begin(struct uvc_video_chain *chain);
extern int __uvc_ctrl_commit(struct uvc_video_chain *chain, int rollback);
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
deleted file mode 100644
index 0c2105ca611e..000000000000
--- a/drivers/media/video/v4l1-compat.c
+++ /dev/null
@@ -1,1270 +0,0 @@
-/*
- *
- * Video for Linux Two
- * Backward Compatibility Layer
- *
- * Support subroutines for providing V4L2 drivers with backward
- * compatibility with applications using the old API.
- *
- * 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.
- *
- * Author: Bill Dirks <bill@thedirks.org>
- * et al.
- *
- */
-
-
-#include <linux/init.h>
-#include <linux/module.h>
-#include <linux/types.h>
-#include <linux/kernel.h>
-#include <linux/sched.h>
-#include <linux/mm.h>
-#include <linux/fs.h>
-#include <linux/file.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/videodev.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-
-#include <asm/uaccess.h>
-#include <asm/system.h>
-#include <asm/pgtable.h>
-
-static unsigned int debug;
-module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "enable debug messages");
-MODULE_AUTHOR("Bill Dirks");
-MODULE_DESCRIPTION("v4l(1) compatibility layer for v4l2 drivers.");
-MODULE_LICENSE("GPL");
-
-#define dprintk(fmt, arg...) \
- do { \
- if (debug) \
- printk(KERN_DEBUG "v4l1-compat: " fmt , ## arg);\
- } while (0)
-
-/*
- * I O C T L T R A N S L A T I O N
- *
- * From here on down is the code for translating the numerous
- * ioctl commands from the old API to the new API.
- */
-
-static int
-get_v4l_control(struct file *file,
- int cid,
- v4l2_kioctl drv)
-{
- struct v4l2_queryctrl qctrl2;
- struct v4l2_control ctrl2;
- int err;
-
- qctrl2.id = cid;
- err = drv(file, VIDIOC_QUERYCTRL, &qctrl2);
- if (err < 0)
- dprintk("VIDIOC_QUERYCTRL: %d\n", err);
- if (err == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) {
- ctrl2.id = qctrl2.id;
- err = drv(file, VIDIOC_G_CTRL, &ctrl2);
- if (err < 0) {
- dprintk("VIDIOC_G_CTRL: %d\n", err);
- return 0;
- }
- return DIV_ROUND_CLOSEST((ctrl2.value-qctrl2.minimum) * 65535,
- qctrl2.maximum - qctrl2.minimum);
- }
- return 0;
-}
-
-static int
-set_v4l_control(struct file *file,
- int cid,
- int value,
- v4l2_kioctl drv)
-{
- struct v4l2_queryctrl qctrl2;
- struct v4l2_control ctrl2;
- int err;
-
- qctrl2.id = cid;
- err = drv(file, VIDIOC_QUERYCTRL, &qctrl2);
- if (err < 0)
- dprintk("VIDIOC_QUERYCTRL: %d\n", err);
- if (err == 0 &&
- !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED) &&
- !(qctrl2.flags & V4L2_CTRL_FLAG_GRABBED)) {
- if (value < 0)
- value = 0;
- if (value > 65535)
- value = 65535;
- if (value && qctrl2.type == V4L2_CTRL_TYPE_BOOLEAN)
- value = 65535;
- ctrl2.id = qctrl2.id;
- ctrl2.value =
- (value * (qctrl2.maximum - qctrl2.minimum)
- + 32767)
- / 65535;
- ctrl2.value += qctrl2.minimum;
- err = drv(file, VIDIOC_S_CTRL, &ctrl2);
- if (err < 0)
- dprintk("VIDIOC_S_CTRL: %d\n", err);
- }
- return 0;
-}
-
-/* ----------------------------------------------------------------- */
-
-static const unsigned int palette2pixelformat[] = {
- [VIDEO_PALETTE_GREY] = V4L2_PIX_FMT_GREY,
- [VIDEO_PALETTE_RGB555] = V4L2_PIX_FMT_RGB555,
- [VIDEO_PALETTE_RGB565] = V4L2_PIX_FMT_RGB565,
- [VIDEO_PALETTE_RGB24] = V4L2_PIX_FMT_BGR24,
- [VIDEO_PALETTE_RGB32] = V4L2_PIX_FMT_BGR32,
- /* yuv packed pixel */
- [VIDEO_PALETTE_YUYV] = V4L2_PIX_FMT_YUYV,
- [VIDEO_PALETTE_YUV422] = V4L2_PIX_FMT_YUYV,
- [VIDEO_PALETTE_UYVY] = V4L2_PIX_FMT_UYVY,
- /* yuv planar */
- [VIDEO_PALETTE_YUV410P] = V4L2_PIX_FMT_YUV410,
- [VIDEO_PALETTE_YUV420] = V4L2_PIX_FMT_YUV420,
- [VIDEO_PALETTE_YUV420P] = V4L2_PIX_FMT_YUV420,
- [VIDEO_PALETTE_YUV411P] = V4L2_PIX_FMT_YUV411P,
- [VIDEO_PALETTE_YUV422P] = V4L2_PIX_FMT_YUV422P,
-};
-
-static unsigned int __pure
-palette_to_pixelformat(unsigned int palette)
-{
- if (palette < ARRAY_SIZE(palette2pixelformat))
- return palette2pixelformat[palette];
- else
- return 0;
-}
-
-static unsigned int __attribute_const__
-pixelformat_to_palette(unsigned int pixelformat)
-{
- int palette = 0;
- switch (pixelformat) {
- case V4L2_PIX_FMT_GREY:
- palette = VIDEO_PALETTE_GREY;
- break;
- case V4L2_PIX_FMT_RGB555:
- palette = VIDEO_PALETTE_RGB555;
- break;
- case V4L2_PIX_FMT_RGB565:
- palette = VIDEO_PALETTE_RGB565;
- break;
- case V4L2_PIX_FMT_BGR24:
- palette = VIDEO_PALETTE_RGB24;
- break;
- case V4L2_PIX_FMT_BGR32:
- palette = VIDEO_PALETTE_RGB32;
- break;
- /* yuv packed pixel */
- case V4L2_PIX_FMT_YUYV:
- palette = VIDEO_PALETTE_YUYV;
- break;
- case V4L2_PIX_FMT_UYVY:
- palette = VIDEO_PALETTE_UYVY;
- break;
- /* yuv planar */
- case V4L2_PIX_FMT_YUV410:
- palette = VIDEO_PALETTE_YUV420;
- break;
- case V4L2_PIX_FMT_YUV420:
- palette = VIDEO_PALETTE_YUV420;
- break;
- case V4L2_PIX_FMT_YUV411P:
- palette = VIDEO_PALETTE_YUV411P;
- break;
- case V4L2_PIX_FMT_YUV422P:
- palette = VIDEO_PALETTE_YUV422P;
- break;
- }
- return palette;
-}
-
-/* ----------------------------------------------------------------- */
-
-static int poll_one(struct file *file, struct poll_wqueues *pwq)
-{
- int retval = 1;
- poll_table *table;
-
- poll_initwait(pwq);
- table = &pwq->pt;
- for (;;) {
- int mask;
- mask = file->f_op->poll(file, table);
- if (mask & POLLIN)
- break;
- table = NULL;
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
- poll_schedule(pwq, TASK_INTERRUPTIBLE);
- }
- poll_freewait(pwq);
- return retval;
-}
-
-static int count_inputs(
- struct file *file,
- v4l2_kioctl drv)
-{
- struct v4l2_input input2;
- int i;
-
- for (i = 0;; i++) {
- memset(&input2, 0, sizeof(input2));
- input2.index = i;
- if (0 != drv(file, VIDIOC_ENUMINPUT, &input2))
- break;
- }
- return i;
-}
-
-static int check_size(
- struct file *file,
- v4l2_kioctl drv,
- int *maxw,
- int *maxh)
-{
- struct v4l2_fmtdesc desc2;
- struct v4l2_format fmt2;
-
- memset(&desc2, 0, sizeof(desc2));
- memset(&fmt2, 0, sizeof(fmt2));
-
- desc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (0 != drv(file, VIDIOC_ENUM_FMT, &desc2))
- goto done;
-
- fmt2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- fmt2.fmt.pix.width = 10000;
- fmt2.fmt.pix.height = 10000;
- fmt2.fmt.pix.pixelformat = desc2.pixelformat;
- if (0 != drv(file, VIDIOC_TRY_FMT, &fmt2))
- goto done;
-
- *maxw = fmt2.fmt.pix.width;
- *maxh = fmt2.fmt.pix.height;
-
-done:
- return 0;
-}
-
-/* ----------------------------------------------------------------- */
-
-static noinline long v4l1_compat_get_capabilities(
- struct video_capability *cap,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_framebuffer fbuf;
- struct v4l2_capability *cap2;
-
- cap2 = kzalloc(sizeof(*cap2), GFP_KERNEL);
- if (!cap2) {
- err = -ENOMEM;
- return err;
- }
- memset(cap, 0, sizeof(*cap));
- memset(&fbuf, 0, sizeof(fbuf));
-
- err = drv(file, VIDIOC_QUERYCAP, cap2);
- if (err < 0) {
- 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: %ld\n", err);
- memset(&fbuf, 0, sizeof(fbuf));
- }
- err = 0;
- }
-
- memcpy(cap->name, cap2->card,
- min(sizeof(cap->name), sizeof(cap2->card)));
- cap->name[sizeof(cap->name) - 1] = 0;
- if (cap2->capabilities & V4L2_CAP_VIDEO_CAPTURE)
- cap->type |= VID_TYPE_CAPTURE;
- if (cap2->capabilities & V4L2_CAP_TUNER)
- cap->type |= VID_TYPE_TUNER;
- if (cap2->capabilities & V4L2_CAP_VBI_CAPTURE)
- cap->type |= VID_TYPE_TELETEXT;
- if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY)
- cap->type |= VID_TYPE_OVERLAY;
- if (fbuf.capability & V4L2_FBUF_CAP_LIST_CLIPPING)
- cap->type |= VID_TYPE_CLIPPING;
-
- cap->channels = count_inputs(file, drv);
- check_size(file, drv,
- &cap->maxwidth, &cap->maxheight);
- cap->audios = 0; /* FIXME */
- cap->minwidth = 48; /* FIXME */
- cap->minheight = 32; /* FIXME */
-
-done:
- kfree(cap2);
- return err;
-}
-
-static noinline long v4l1_compat_get_frame_buffer(
- struct video_buffer *buffer,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_framebuffer fbuf;
-
- memset(buffer, 0, sizeof(*buffer));
- memset(&fbuf, 0, sizeof(fbuf));
-
- err = drv(file, VIDIOC_G_FBUF, &fbuf);
- if (err < 0) {
- dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %ld\n", err);
- goto done;
- }
- buffer->base = fbuf.base;
- buffer->height = fbuf.fmt.height;
- buffer->width = fbuf.fmt.width;
-
- switch (fbuf.fmt.pixelformat) {
- case V4L2_PIX_FMT_RGB332:
- buffer->depth = 8;
- break;
- case V4L2_PIX_FMT_RGB555:
- buffer->depth = 15;
- break;
- case V4L2_PIX_FMT_RGB565:
- buffer->depth = 16;
- break;
- case V4L2_PIX_FMT_BGR24:
- buffer->depth = 24;
- break;
- case V4L2_PIX_FMT_BGR32:
- buffer->depth = 32;
- break;
- default:
- buffer->depth = 0;
- }
- if (fbuf.fmt.bytesperline) {
- buffer->bytesperline = fbuf.fmt.bytesperline;
- if (!buffer->depth && buffer->width)
- buffer->depth = ((fbuf.fmt.bytesperline<<3)
- + (buffer->width-1))
- / buffer->width;
- } else {
- buffer->bytesperline =
- (buffer->width * buffer->depth + 7) & 7;
- buffer->bytesperline >>= 3;
- }
-done:
- return err;
-}
-
-static noinline long v4l1_compat_set_frame_buffer(
- struct video_buffer *buffer,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_framebuffer fbuf;
-
- memset(&fbuf, 0, sizeof(fbuf));
- fbuf.base = buffer->base;
- fbuf.fmt.height = buffer->height;
- fbuf.fmt.width = buffer->width;
- switch (buffer->depth) {
- case 8:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB332;
- break;
- case 15:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB555;
- break;
- case 16:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
- break;
- case 24:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR24;
- break;
- case 32:
- fbuf.fmt.pixelformat = V4L2_PIX_FMT_BGR32;
- break;
- }
- fbuf.fmt.bytesperline = buffer->bytesperline;
- err = drv(file, VIDIOC_S_FBUF, &fbuf);
- if (err < 0)
- dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %ld\n", err);
- return err;
-}
-
-static noinline long v4l1_compat_get_win_cap_dimensions(
- struct video_window *win,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
- memset(win, 0, sizeof(*win));
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
- err = drv(file, VIDIOC_G_FMT, fmt);
- if (err < 0)
- 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;
- win->width = fmt->fmt.win.w.width;
- win->height = fmt->fmt.win.w.height;
- win->chromakey = fmt->fmt.win.chromakey;
- win->clips = NULL;
- win->clipcount = 0;
- goto done;
- }
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_G_FMT, fmt);
- if (err < 0) {
- dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %ld\n", err);
- goto done;
- }
- win->x = 0;
- win->y = 0;
- win->width = fmt->fmt.pix.width;
- win->height = fmt->fmt.pix.height;
- win->chromakey = 0;
- win->clips = NULL;
- win->clipcount = 0;
-done:
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_set_win_cap_dimensions(
- struct video_window *win,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err, err1, err2;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- drv(file, VIDIOC_STREAMOFF, &fmt->type);
- err1 = drv(file, VIDIOC_G_FMT, fmt);
- if (err1 < 0)
- dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %ld\n", err1);
- if (err1 == 0) {
- fmt->fmt.pix.width = win->width;
- fmt->fmt.pix.height = win->height;
- fmt->fmt.pix.field = V4L2_FIELD_ANY;
- fmt->fmt.pix.bytesperline = 0;
- err = drv(file, VIDIOC_S_FMT, fmt);
- if (err < 0)
- dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %ld\n",
- err);
- win->width = fmt->fmt.pix.width;
- win->height = fmt->fmt.pix.height;
- }
-
- memset(fmt, 0, sizeof(*fmt));
- fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
- fmt->fmt.win.w.left = win->x;
- fmt->fmt.win.w.top = win->y;
- fmt->fmt.win.w.width = win->width;
- fmt->fmt.win.w.height = win->height;
- fmt->fmt.win.chromakey = win->chromakey;
- fmt->fmt.win.clips = (void __user *)win->clips;
- fmt->fmt.win.clipcount = win->clipcount;
- err2 = drv(file, VIDIOC_S_FMT, fmt);
- if (err2 < 0)
- dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %ld\n", err2);
-
- if (err1 != 0 && err2 != 0)
- err = err1;
- else
- err = 0;
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_turn_preview_on_off(
- int *on,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- if (0 == *on) {
- /* dirty hack time. But v4l1 has no STREAMOFF
- * equivalent in the API, and this one at
- * least comes close ... */
- drv(file, VIDIOC_STREAMOFF, &captype);
- }
- err = drv(file, VIDIOC_OVERLAY, on);
- if (err < 0)
- dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %ld\n", err);
- return err;
-}
-
-static noinline long v4l1_compat_get_input_info(
- struct video_channel *chan,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_input input2;
- v4l2_std_id sid;
-
- memset(&input2, 0, sizeof(input2));
- input2.index = chan->channel;
- err = drv(file, VIDIOC_ENUMINPUT, &input2);
- if (err < 0) {
- dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: "
- "channel=%d err=%ld\n", chan->channel, err);
- goto done;
- }
- chan->channel = input2.index;
- memcpy(chan->name, input2.name,
- min(sizeof(chan->name), sizeof(input2.name)));
- chan->name[sizeof(chan->name) - 1] = 0;
- chan->tuners = (input2.type == V4L2_INPUT_TYPE_TUNER) ? 1 : 0;
- chan->flags = (chan->tuners) ? VIDEO_VC_TUNER : 0;
- switch (input2.type) {
- case V4L2_INPUT_TYPE_TUNER:
- chan->type = VIDEO_TYPE_TV;
- break;
- default:
- case V4L2_INPUT_TYPE_CAMERA:
- chan->type = VIDEO_TYPE_CAMERA;
- break;
- }
- chan->norm = 0;
- /* Note: G_STD might not be present for radio receivers,
- * so we should ignore any errors. */
- if (drv(file, VIDIOC_G_STD, &sid) == 0) {
- if (sid & V4L2_STD_PAL)
- chan->norm = VIDEO_MODE_PAL;
- if (sid & V4L2_STD_NTSC)
- chan->norm = VIDEO_MODE_NTSC;
- if (sid & V4L2_STD_SECAM)
- chan->norm = VIDEO_MODE_SECAM;
- if (sid == V4L2_STD_ALL)
- chan->norm = VIDEO_MODE_AUTO;
- }
-done:
- return err;
-}
-
-static noinline long v4l1_compat_set_input(
- struct video_channel *chan,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- v4l2_std_id sid = 0;
-
- err = drv(file, VIDIOC_S_INPUT, &chan->channel);
- if (err < 0)
- dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %ld\n", err);
- switch (chan->norm) {
- case VIDEO_MODE_PAL:
- sid = V4L2_STD_PAL;
- break;
- case VIDEO_MODE_NTSC:
- sid = V4L2_STD_NTSC;
- break;
- case VIDEO_MODE_SECAM:
- sid = V4L2_STD_SECAM;
- break;
- case VIDEO_MODE_AUTO:
- sid = V4L2_STD_ALL;
- break;
- }
- if (0 != sid) {
- err = drv(file, VIDIOC_S_STD, &sid);
- if (err < 0)
- dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %ld\n", err);
- }
- return err;
-}
-
-static noinline long v4l1_compat_get_picture(
- struct video_picture *pict,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
-
- pict->brightness = get_v4l_control(file,
- V4L2_CID_BRIGHTNESS, drv);
- pict->hue = get_v4l_control(file,
- V4L2_CID_HUE, drv);
- pict->contrast = get_v4l_control(file,
- V4L2_CID_CONTRAST, drv);
- pict->colour = get_v4l_control(file,
- V4L2_CID_SATURATION, drv);
- pict->whiteness = get_v4l_control(file,
- V4L2_CID_WHITENESS, drv);
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_G_FMT, fmt);
- if (err < 0) {
- dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %ld\n", err);
- goto done;
- }
-
- pict->depth = ((fmt->fmt.pix.bytesperline << 3)
- + (fmt->fmt.pix.width - 1))
- / fmt->fmt.pix.width;
- pict->palette = pixelformat_to_palette(
- fmt->fmt.pix.pixelformat);
-done:
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_set_picture(
- struct video_picture *pict,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_framebuffer fbuf;
- int mem_err = 0, ovl_err = 0;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
- memset(&fbuf, 0, sizeof(fbuf));
-
- set_v4l_control(file,
- V4L2_CID_BRIGHTNESS, pict->brightness, drv);
- set_v4l_control(file,
- V4L2_CID_HUE, pict->hue, drv);
- set_v4l_control(file,
- V4L2_CID_CONTRAST, pict->contrast, drv);
- set_v4l_control(file,
- V4L2_CID_SATURATION, pict->colour, drv);
- set_v4l_control(file,
- V4L2_CID_WHITENESS, pict->whiteness, drv);
- /*
- * V4L1 uses this ioctl to set both memory capture and overlay
- * pixel format, while V4L2 has two different ioctls for this.
- * Some cards may not support one or the other, and may support
- * different pixel formats for memory vs overlay.
- */
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_G_FMT, fmt);
- /* If VIDIOC_G_FMT failed, then the driver likely doesn't
- support memory capture. Trying to set the memory capture
- parameters would be pointless. */
- if (err < 0) {
- 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)) {
- fmt->fmt.pix.pixelformat = palette_to_pixelformat(
- pict->palette);
- mem_err = drv(file, VIDIOC_S_FMT, fmt);
- if (mem_err < 0)
- dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n",
- mem_err);
- }
-
- err = drv(file, VIDIOC_G_FBUF, &fbuf);
- /* If VIDIOC_G_FBUF failed, then the driver likely doesn't
- support overlay. Trying to set the overlay parameters
- would be quite pointless. */
- if (err < 0) {
- 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)) {
- fbuf.fmt.pixelformat = palette_to_pixelformat(
- pict->palette);
- ovl_err = drv(file, VIDIOC_S_FBUF, &fbuf);
- if (ovl_err < 0)
- dprintk("VIDIOCSPICT / VIDIOC_S_FBUF: %d\n",
- ovl_err);
- }
- if (ovl_err < 0 && mem_err < 0) {
- /* ioctl failed, couldn't set either parameter */
- if (mem_err != -1000)
- err = mem_err;
- else if (ovl_err == -EPERM)
- err = 0;
- else
- err = ovl_err;
- } else
- err = 0;
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_get_tuner(
- struct video_tuner *tun,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- int i;
- struct v4l2_tuner tun2;
- struct v4l2_standard std2;
- v4l2_std_id sid;
-
- memset(&tun2, 0, sizeof(tun2));
- err = drv(file, VIDIOC_G_TUNER, &tun2);
- if (err < 0) {
- dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %ld\n", err);
- goto done;
- }
- memcpy(tun->name, tun2.name,
- min(sizeof(tun->name), sizeof(tun2.name)));
- tun->name[sizeof(tun->name) - 1] = 0;
- tun->rangelow = tun2.rangelow;
- tun->rangehigh = tun2.rangehigh;
- tun->flags = 0;
- tun->mode = VIDEO_MODE_AUTO;
-
- for (i = 0; i < 64; i++) {
- memset(&std2, 0, sizeof(std2));
- std2.index = i;
- if (0 != drv(file, VIDIOC_ENUMSTD, &std2))
- break;
- if (std2.id & V4L2_STD_PAL)
- tun->flags |= VIDEO_TUNER_PAL;
- if (std2.id & V4L2_STD_NTSC)
- tun->flags |= VIDEO_TUNER_NTSC;
- if (std2.id & V4L2_STD_SECAM)
- tun->flags |= VIDEO_TUNER_SECAM;
- }
-
- /* Note: G_STD might not be present for radio receivers,
- * so we should ignore any errors. */
- if (drv(file, VIDIOC_G_STD, &sid) == 0) {
- if (sid & V4L2_STD_PAL)
- tun->mode = VIDEO_MODE_PAL;
- if (sid & V4L2_STD_NTSC)
- tun->mode = VIDEO_MODE_NTSC;
- if (sid & V4L2_STD_SECAM)
- tun->mode = VIDEO_MODE_SECAM;
- }
-
- if (tun2.capability & V4L2_TUNER_CAP_LOW)
- tun->flags |= VIDEO_TUNER_LOW;
- if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
- tun->flags |= VIDEO_TUNER_STEREO_ON;
- tun->signal = tun2.signal;
-done:
- return err;
-}
-
-static noinline long v4l1_compat_select_tuner(
- struct video_tuner *tun,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_tuner t;/*84 bytes on x86_64*/
- memset(&t, 0, sizeof(t));
-
- t.index = tun->tuner;
-
- err = drv(file, VIDIOC_S_TUNER, &t);
- if (err < 0)
- dprintk("VIDIOCSTUNER / VIDIOC_S_TUNER: %ld\n", err);
- return err;
-}
-
-static noinline long v4l1_compat_get_frequency(
- unsigned long *freq,
- struct file *file,
- v4l2_kioctl drv)
-{
- 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: %ld\n", err);
- if (0 == err)
- *freq = freq2.frequency;
- return err;
-}
-
-static noinline long v4l1_compat_set_frequency(
- unsigned long *freq,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_frequency freq2;
- memset(&freq2, 0, sizeof(freq2));
-
- drv(file, VIDIOC_G_FREQUENCY, &freq2);
- freq2.frequency = *freq;
- err = drv(file, VIDIOC_S_FREQUENCY, &freq2);
- if (err < 0)
- dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %ld\n", err);
- return err;
-}
-
-static noinline long v4l1_compat_get_audio(
- struct video_audio *aud,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- int i;
- struct v4l2_queryctrl qctrl2;
- struct v4l2_audio aud2;
- struct v4l2_tuner tun2;
- memset(&aud2, 0, sizeof(aud2));
-
- err = drv(file, VIDIOC_G_AUDIO, &aud2);
- if (err < 0) {
- dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %ld\n", err);
- goto done;
- }
- memcpy(aud->name, aud2.name,
- min(sizeof(aud->name), sizeof(aud2.name)));
- aud->name[sizeof(aud->name) - 1] = 0;
- aud->audio = aud2.index;
- aud->flags = 0;
- i = get_v4l_control(file, V4L2_CID_AUDIO_VOLUME, drv);
- if (i >= 0) {
- aud->volume = i;
- aud->flags |= VIDEO_AUDIO_VOLUME;
- }
- i = get_v4l_control(file, V4L2_CID_AUDIO_BASS, drv);
- if (i >= 0) {
- aud->bass = i;
- aud->flags |= VIDEO_AUDIO_BASS;
- }
- i = get_v4l_control(file, V4L2_CID_AUDIO_TREBLE, drv);
- if (i >= 0) {
- aud->treble = i;
- aud->flags |= VIDEO_AUDIO_TREBLE;
- }
- i = get_v4l_control(file, V4L2_CID_AUDIO_BALANCE, drv);
- if (i >= 0) {
- aud->balance = i;
- aud->flags |= VIDEO_AUDIO_BALANCE;
- }
- i = get_v4l_control(file, V4L2_CID_AUDIO_MUTE, drv);
- if (i >= 0) {
- if (i)
- aud->flags |= VIDEO_AUDIO_MUTE;
- aud->flags |= VIDEO_AUDIO_MUTABLE;
- }
- aud->step = 1;
- qctrl2.id = V4L2_CID_AUDIO_VOLUME;
- if (drv(file, VIDIOC_QUERYCTRL, &qctrl2) == 0 &&
- !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
- aud->step = qctrl2.step;
- aud->mode = 0;
-
- memset(&tun2, 0, sizeof(tun2));
- err = drv(file, VIDIOC_G_TUNER, &tun2);
- if (err < 0) {
- dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %ld\n", err);
- err = 0;
- goto done;
- }
-
- if (tun2.rxsubchans & V4L2_TUNER_SUB_LANG2)
- aud->mode = VIDEO_SOUND_LANG1 | VIDEO_SOUND_LANG2;
- else if (tun2.rxsubchans & V4L2_TUNER_SUB_STEREO)
- aud->mode = VIDEO_SOUND_STEREO;
- else if (tun2.rxsubchans & V4L2_TUNER_SUB_MONO)
- aud->mode = VIDEO_SOUND_MONO;
-done:
- return err;
-}
-
-static noinline long v4l1_compat_set_audio(
- struct video_audio *aud,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_audio aud2;
- struct v4l2_tuner tun2;
-
- memset(&aud2, 0, sizeof(aud2));
- memset(&tun2, 0, sizeof(tun2));
-
- aud2.index = aud->audio;
- err = drv(file, VIDIOC_S_AUDIO, &aud2);
- if (err < 0) {
- dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %ld\n", err);
- goto done;
- }
-
- set_v4l_control(file, V4L2_CID_AUDIO_VOLUME,
- aud->volume, drv);
- set_v4l_control(file, V4L2_CID_AUDIO_BASS,
- aud->bass, drv);
- set_v4l_control(file, V4L2_CID_AUDIO_TREBLE,
- aud->treble, drv);
- set_v4l_control(file, V4L2_CID_AUDIO_BALANCE,
- aud->balance, drv);
- set_v4l_control(file, V4L2_CID_AUDIO_MUTE,
- !!(aud->flags & VIDEO_AUDIO_MUTE), drv);
-
- err = drv(file, VIDIOC_G_TUNER, &tun2);
- if (err < 0)
- dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %ld\n", err);
- if (err == 0) {
- switch (aud->mode) {
- default:
- case VIDEO_SOUND_MONO:
- case VIDEO_SOUND_LANG1:
- tun2.audmode = V4L2_TUNER_MODE_MONO;
- break;
- case VIDEO_SOUND_STEREO:
- tun2.audmode = V4L2_TUNER_MODE_STEREO;
- break;
- case VIDEO_SOUND_LANG2:
- tun2.audmode = V4L2_TUNER_MODE_LANG2;
- break;
- }
- err = drv(file, VIDIOC_S_TUNER, &tun2);
- if (err < 0)
- dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %ld\n", err);
- }
- err = 0;
-done:
- return err;
-}
-
-static noinline long v4l1_compat_capture_frame(
- struct video_mmap *mm,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- struct v4l2_buffer buf;
- struct v4l2_format *fmt;
-
- fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
- if (!fmt) {
- err = -ENOMEM;
- return err;
- }
- memset(&buf, 0, sizeof(buf));
-
- fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_G_FMT, fmt);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %ld\n", err);
- goto done;
- }
- if (mm->width != fmt->fmt.pix.width ||
- mm->height != fmt->fmt.pix.height ||
- palette_to_pixelformat(mm->format) !=
- fmt->fmt.pix.pixelformat) {
- /* New capture format... */
- fmt->fmt.pix.width = mm->width;
- fmt->fmt.pix.height = mm->height;
- fmt->fmt.pix.pixelformat =
- palette_to_pixelformat(mm->format);
- fmt->fmt.pix.field = V4L2_FIELD_ANY;
- fmt->fmt.pix.bytesperline = 0;
- err = drv(file, VIDIOC_S_FMT, fmt);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %ld\n", err);
- goto done;
- }
- }
- buf.index = mm->frame;
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_QUERYBUF, &buf);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %ld\n", err);
- goto done;
- }
- err = drv(file, VIDIOC_QBUF, &buf);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %ld\n", err);
- goto done;
- }
- err = drv(file, VIDIOC_STREAMON, &captype);
- if (err < 0)
- dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %ld\n", err);
-done:
- kfree(fmt);
- return err;
-}
-
-static noinline long v4l1_compat_sync(
- int *i,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- struct v4l2_buffer buf;
- struct poll_wqueues *pwq;
-
- memset(&buf, 0, sizeof(buf));
- buf.index = *i;
- buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(file, VIDIOC_QUERYBUF, &buf);
- if (err < 0) {
- /* No such buffer */
- dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %ld\n", err);
- goto done;
- }
- if (!(buf.flags & V4L2_BUF_FLAG_MAPPED)) {
- /* Buffer is not mapped */
- err = -EINVAL;
- goto done;
- }
-
- /* make sure capture actually runs so we don't block forever */
- err = drv(file, VIDIOC_STREAMON, &captype);
- if (err < 0) {
- dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %ld\n", err);
- goto done;
- }
-
- pwq = kmalloc(sizeof(*pwq), GFP_KERNEL);
- /* Loop as long as the buffer is queued, but not done */
- while ((buf.flags & (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
- == V4L2_BUF_FLAG_QUEUED) {
- err = poll_one(file, pwq);
- if (err < 0 || /* error or sleep was interrupted */
- err == 0) /* timeout? Shouldn't occur. */
- break;
- err = drv(file, VIDIOC_QUERYBUF, &buf);
- if (err < 0)
- dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %ld\n", err);
- }
- kfree(pwq);
- if (!(buf.flags & V4L2_BUF_FLAG_DONE)) /* not done */
- goto done;
- do {
- err = drv(file, VIDIOC_DQBUF, &buf);
- if (err < 0)
- dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %ld\n", err);
- } while (err == 0 && buf.index != *i);
-done:
- return err;
-}
-
-static noinline long v4l1_compat_get_vbi_format(
- struct vbi_format *fmt,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_format *fmt2;
-
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- return err;
- }
- fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
-
- err = drv(file, VIDIOC_G_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %ld\n", err);
- goto done;
- }
- if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
- err = -EINVAL;
- goto done;
- }
- memset(fmt, 0, sizeof(*fmt));
- fmt->samples_per_line = fmt2->fmt.vbi.samples_per_line;
- fmt->sampling_rate = fmt2->fmt.vbi.sampling_rate;
- fmt->sample_format = VIDEO_PALETTE_RAW;
- fmt->start[0] = fmt2->fmt.vbi.start[0];
- fmt->count[0] = fmt2->fmt.vbi.count[0];
- fmt->start[1] = fmt2->fmt.vbi.start[1];
- fmt->count[1] = fmt2->fmt.vbi.count[1];
- fmt->flags = fmt2->fmt.vbi.flags & 0x03;
-done:
- kfree(fmt2);
- return err;
-}
-
-static noinline long v4l1_compat_set_vbi_format(
- struct vbi_format *fmt,
- struct file *file,
- v4l2_kioctl drv)
-{
- long err;
- struct v4l2_format *fmt2 = NULL;
-
- if (VIDEO_PALETTE_RAW != fmt->sample_format) {
- err = -EINVAL;
- return err;
- }
-
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- return err;
- }
- fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- fmt2->fmt.vbi.samples_per_line = fmt->samples_per_line;
- fmt2->fmt.vbi.sampling_rate = fmt->sampling_rate;
- fmt2->fmt.vbi.sample_format = V4L2_PIX_FMT_GREY;
- fmt2->fmt.vbi.start[0] = fmt->start[0];
- fmt2->fmt.vbi.count[0] = fmt->count[0];
- fmt2->fmt.vbi.start[1] = fmt->start[1];
- fmt2->fmt.vbi.count[1] = fmt->count[1];
- fmt2->fmt.vbi.flags = fmt->flags;
- err = drv(file, VIDIOC_TRY_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %ld\n", err);
- goto done;
- }
-
- if (fmt2->fmt.vbi.samples_per_line != fmt->samples_per_line ||
- fmt2->fmt.vbi.sampling_rate != fmt->sampling_rate ||
- fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY ||
- fmt2->fmt.vbi.start[0] != fmt->start[0] ||
- fmt2->fmt.vbi.count[0] != fmt->count[0] ||
- fmt2->fmt.vbi.start[1] != fmt->start[1] ||
- fmt2->fmt.vbi.count[1] != fmt->count[1] ||
- fmt2->fmt.vbi.flags != fmt->flags) {
- err = -EINVAL;
- goto done;
- }
- err = drv(file, VIDIOC_S_FMT, fmt2);
- if (err < 0)
- dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %ld\n", err);
-done:
- kfree(fmt2);
- return err;
-}
-
-/*
- * This function is exported.
- */
-long
-v4l_compat_translate_ioctl(struct file *file,
- int cmd,
- void *arg,
- v4l2_kioctl drv)
-{
- long err;
-
- switch (cmd) {
- case VIDIOCGCAP: /* capability */
- err = v4l1_compat_get_capabilities(arg, file, drv);
- break;
- case VIDIOCGFBUF: /* get frame buffer */
- err = v4l1_compat_get_frame_buffer(arg, file, drv);
- break;
- case VIDIOCSFBUF: /* set frame buffer */
- err = v4l1_compat_set_frame_buffer(arg, file, drv);
- break;
- case VIDIOCGWIN: /* get window or capture dimensions */
- err = v4l1_compat_get_win_cap_dimensions(arg, file, drv);
- break;
- case VIDIOCSWIN: /* set window and/or capture dimensions */
- err = v4l1_compat_set_win_cap_dimensions(arg, file, drv);
- break;
- case VIDIOCCAPTURE: /* turn on/off preview */
- err = v4l1_compat_turn_preview_on_off(arg, file, drv);
- break;
- case VIDIOCGCHAN: /* get input information */
- err = v4l1_compat_get_input_info(arg, file, drv);
- break;
- case VIDIOCSCHAN: /* set input */
- err = v4l1_compat_set_input(arg, file, drv);
- break;
- case VIDIOCGPICT: /* get tone controls & partial capture format */
- err = v4l1_compat_get_picture(arg, file, drv);
- break;
- case VIDIOCSPICT: /* set tone controls & partial capture format */
- err = v4l1_compat_set_picture(arg, file, drv);
- break;
- case VIDIOCGTUNER: /* get tuner information */
- err = v4l1_compat_get_tuner(arg, file, drv);
- break;
- case VIDIOCSTUNER: /* select a tuner input */
- err = v4l1_compat_select_tuner(arg, file, drv);
- break;
- case VIDIOCGFREQ: /* get frequency */
- err = v4l1_compat_get_frequency(arg, file, drv);
- break;
- case VIDIOCSFREQ: /* set frequency */
- err = v4l1_compat_set_frequency(arg, file, drv);
- break;
- case VIDIOCGAUDIO: /* get audio properties/controls */
- err = v4l1_compat_get_audio(arg, file, drv);
- break;
- case VIDIOCSAUDIO: /* set audio controls */
- err = v4l1_compat_set_audio(arg, file, drv);
- break;
- case VIDIOCMCAPTURE: /* capture a frame */
- err = v4l1_compat_capture_frame(arg, file, drv);
- break;
- case VIDIOCSYNC: /* wait for a frame */
- err = v4l1_compat_sync(arg, file, drv);
- break;
- case VIDIOCGVBIFMT: /* query VBI data capture format */
- err = v4l1_compat_get_vbi_format(arg, file, drv);
- break;
- case VIDIOCSVBIFMT:
- err = v4l1_compat_set_vbi_format(arg, file, drv);
- break;
- default:
- err = -ENOIOCTLCMD;
- break;
- }
-
- return err;
-}
-EXPORT_SYMBOL(v4l_compat_translate_ioctl);
-
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/v4l2-common.c b/drivers/media/video/v4l2-common.c
index 4e53b0b3339c..810eef43c216 100644
--- a/drivers/media/video/v4l2-common.c
+++ b/drivers/media/video/v4l2-common.c
@@ -62,6 +62,7 @@
#define __OLD_VIDIOC_ /* To allow fixing old calls*/
#include <media/v4l2-common.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-chip-ident.h>
#include <linux/videodev2.h>
@@ -149,7 +150,7 @@ EXPORT_SYMBOL(v4l2_prio_check);
struct v4l2_queryctrl and the available menu items. Note that
menu_items may be NULL, in that case it is ignored. */
int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
- const char **menu_items)
+ const char * const *menu_items)
{
if (qctrl->flags & V4L2_CTRL_FLAG_DISABLED)
return -EINVAL;
@@ -172,487 +173,17 @@ int v4l2_ctrl_check(struct v4l2_ext_control *ctrl, struct v4l2_queryctrl *qctrl,
}
EXPORT_SYMBOL(v4l2_ctrl_check);
-/* Returns NULL or a character pointer array containing the menu for
- the given control ID. The pointer array ends with a NULL pointer.
- An empty string signifies a menu entry that is invalid. This allows
- drivers to disable certain options if it is not supported. */
-const char **v4l2_ctrl_get_menu(u32 id)
-{
- static const char *mpeg_audio_sampling_freq[] = {
- "44.1 kHz",
- "48 kHz",
- "32 kHz",
- NULL
- };
- static const char *mpeg_audio_encoding[] = {
- "MPEG-1/2 Layer I",
- "MPEG-1/2 Layer II",
- "MPEG-1/2 Layer III",
- "MPEG-2/4 AAC",
- "AC-3",
- NULL
- };
- static const char *mpeg_audio_l1_bitrate[] = {
- "32 kbps",
- "64 kbps",
- "96 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "288 kbps",
- "320 kbps",
- "352 kbps",
- "384 kbps",
- "416 kbps",
- "448 kbps",
- NULL
- };
- static const char *mpeg_audio_l2_bitrate[] = {
- "32 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- "384 kbps",
- NULL
- };
- static const char *mpeg_audio_l3_bitrate[] = {
- "32 kbps",
- "40 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- NULL
- };
- static const char *mpeg_audio_ac3_bitrate[] = {
- "32 kbps",
- "40 kbps",
- "48 kbps",
- "56 kbps",
- "64 kbps",
- "80 kbps",
- "96 kbps",
- "112 kbps",
- "128 kbps",
- "160 kbps",
- "192 kbps",
- "224 kbps",
- "256 kbps",
- "320 kbps",
- "384 kbps",
- "448 kbps",
- "512 kbps",
- "576 kbps",
- "640 kbps",
- NULL
- };
- static const char *mpeg_audio_mode[] = {
- "Stereo",
- "Joint Stereo",
- "Dual",
- "Mono",
- NULL
- };
- static const char *mpeg_audio_mode_extension[] = {
- "Bound 4",
- "Bound 8",
- "Bound 12",
- "Bound 16",
- NULL
- };
- static const char *mpeg_audio_emphasis[] = {
- "No Emphasis",
- "50/15 us",
- "CCITT J17",
- NULL
- };
- static const char *mpeg_audio_crc[] = {
- "No CRC",
- "16-bit CRC",
- NULL
- };
- static const char *mpeg_video_encoding[] = {
- "MPEG-1",
- "MPEG-2",
- "MPEG-4 AVC",
- NULL
- };
- static const char *mpeg_video_aspect[] = {
- "1x1",
- "4x3",
- "16x9",
- "2.21x1",
- NULL
- };
- static const char *mpeg_video_bitrate_mode[] = {
- "Variable Bitrate",
- "Constant Bitrate",
- NULL
- };
- static const char *mpeg_stream_type[] = {
- "MPEG-2 Program Stream",
- "MPEG-2 Transport Stream",
- "MPEG-1 System Stream",
- "MPEG-2 DVD-compatible Stream",
- "MPEG-1 VCD-compatible Stream",
- "MPEG-2 SVCD-compatible Stream",
- NULL
- };
- static const char *mpeg_stream_vbi_fmt[] = {
- "No VBI",
- "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
- };
- static const char *colorfx[] = {
- "None",
- "Black & White",
- "Sepia",
- "Negative",
- "Emboss",
- "Sketch",
- "Sky blue",
- "Grass green",
- "Skin whiten",
- "Vivid",
- NULL
- };
- static const char *tune_preemphasis[] = {
- "No preemphasis",
- "50 useconds",
- "75 useconds",
- NULL,
- };
-
- switch (id) {
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
- return mpeg_audio_sampling_freq;
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- return mpeg_audio_encoding;
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
- return mpeg_audio_l1_bitrate;
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- return mpeg_audio_l2_bitrate;
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
- return mpeg_audio_l3_bitrate;
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- return mpeg_audio_ac3_bitrate;
- case V4L2_CID_MPEG_AUDIO_MODE:
- return mpeg_audio_mode;
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- return mpeg_audio_mode_extension;
- case V4L2_CID_MPEG_AUDIO_EMPHASIS:
- return mpeg_audio_emphasis;
- case V4L2_CID_MPEG_AUDIO_CRC:
- return mpeg_audio_crc;
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- return mpeg_video_encoding;
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- return mpeg_video_aspect;
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- return mpeg_video_bitrate_mode;
- case V4L2_CID_MPEG_STREAM_TYPE:
- 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;
- case V4L2_CID_COLORFX:
- return colorfx;
- case V4L2_CID_TUNE_PREEMPHASIS:
- return tune_preemphasis;
- default:
- return NULL;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_menu);
-
-/* Return the control name. */
-const char *v4l2_ctrl_get_name(u32 id)
-{
- switch (id) {
- /* USER controls */
- case V4L2_CID_USER_CLASS: return "User Controls";
- 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_AUDIO_VOLUME: return "Volume";
- 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_MUTE: return "Mute";
- case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
- 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_CHROMA_GAIN: return "Chroma Gain";
- case V4L2_CID_COLOR_KILLER: return "Color Killer";
- case V4L2_CID_COLORFX: return "Color Effects";
- case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic";
- case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter";
- case V4L2_CID_ROTATE: return "Rotate";
- case V4L2_CID_BG_COLOR: return "Background Color";
-
- /* MPEG controls */
- case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
- case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
- case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
- case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
- case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
- case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
- case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
- case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
- case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
- case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
- case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
- case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
- case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
- case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
- case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
- case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
- case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
- case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
- case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
- case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
- case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
- case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
- case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
- case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
- case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
- case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio 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_IRIS_ABSOLUTE: return "Iris, Absolute";
- case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";
- 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";
-
- /* FM Radio Modulator control */
- case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
- case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
- case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
- case V4L2_CID_RDS_TX_PTY: return "RDS Program Type";
- case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name";
- case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text";
- case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
- case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
- case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
- case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
- case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
- case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
- case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
- case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
- case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
- case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
- case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
- case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings";
- case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
-
- default:
- return NULL;
- }
-}
-EXPORT_SYMBOL(v4l2_ctrl_get_name);
-
/* Fill in a struct v4l2_queryctrl */
int v4l2_ctrl_query_fill(struct v4l2_queryctrl *qctrl, s32 min, s32 max, s32 step, s32 def)
{
- const char *name = v4l2_ctrl_get_name(qctrl->id);
+ const char *name;
+
+ v4l2_ctrl_fill(qctrl->id, &name, &qctrl->type,
+ &min, &max, &step, &def, &qctrl->flags);
- qctrl->flags = 0;
if (name == NULL)
return -EINVAL;
- 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_CHROMA_AGC:
- case V4L2_CID_COLOR_KILLER:
- 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_FOCUS_AUTO:
- case V4L2_CID_PRIVACY:
- case V4L2_CID_AUDIO_LIMITER_ENABLED:
- case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
- case V4L2_CID_PILOT_TONE_ENABLED:
- qctrl->type = V4L2_CTRL_TYPE_BOOLEAN;
- min = 0;
- max = step = 1;
- break;
- case V4L2_CID_PAN_RESET:
- case V4L2_CID_TILT_RESET:
- qctrl->type = V4L2_CTRL_TYPE_BUTTON;
- qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- min = max = step = def = 0;
- 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:
- case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
- case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
- case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
- case V4L2_CID_MPEG_AUDIO_MODE:
- case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
- case V4L2_CID_MPEG_AUDIO_EMPHASIS:
- case V4L2_CID_MPEG_AUDIO_CRC:
- case V4L2_CID_MPEG_VIDEO_ENCODING:
- case V4L2_CID_MPEG_VIDEO_ASPECT:
- 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:
- case V4L2_CID_COLORFX:
- case V4L2_CID_TUNE_PREEMPHASIS:
- qctrl->type = V4L2_CTRL_TYPE_MENU;
- step = 1;
- break;
- case V4L2_CID_RDS_TX_PS_NAME:
- case V4L2_CID_RDS_TX_RADIO_TEXT:
- qctrl->type = V4L2_CTRL_TYPE_STRING;
- break;
- case V4L2_CID_USER_CLASS:
- case V4L2_CID_CAMERA_CLASS:
- case V4L2_CID_MPEG_CLASS:
- case V4L2_CID_FM_TX_CLASS:
- qctrl->type = V4L2_CTRL_TYPE_CTRL_CLASS;
- qctrl->flags |= V4L2_CTRL_FLAG_READ_ONLY;
- min = max = step = def = 0;
- break;
- case V4L2_CID_BG_COLOR:
- qctrl->type = V4L2_CTRL_TYPE_INTEGER;
- step = 1;
- min = 0;
- /* Max is calculated as RGB888 that is 2^24 */
- max = 0xFFFFFF;
- break;
- default:
- qctrl->type = V4L2_CTRL_TYPE_INTEGER;
- break;
- }
- switch (qctrl->id) {
- case V4L2_CID_MPEG_AUDIO_ENCODING:
- case V4L2_CID_MPEG_AUDIO_MODE:
- case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
- case V4L2_CID_MPEG_VIDEO_B_FRAMES:
- case V4L2_CID_MPEG_STREAM_TYPE:
- qctrl->flags |= V4L2_CTRL_FLAG_UPDATE;
- break;
- case V4L2_CID_AUDIO_VOLUME:
- case V4L2_CID_AUDIO_BALANCE:
- case V4L2_CID_AUDIO_BASS:
- case V4L2_CID_AUDIO_TREBLE:
- case V4L2_CID_BRIGHTNESS:
- case V4L2_CID_CONTRAST:
- case V4L2_CID_SATURATION:
- case V4L2_CID_HUE:
- case V4L2_CID_RED_BALANCE:
- case V4L2_CID_BLUE_BALANCE:
- case V4L2_CID_GAMMA:
- case V4L2_CID_SHARPNESS:
- case V4L2_CID_CHROMA_GAIN:
- case V4L2_CID_RDS_TX_DEVIATION:
- case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
- case V4L2_CID_AUDIO_LIMITER_DEVIATION:
- case V4L2_CID_AUDIO_COMPRESSION_GAIN:
- case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
- case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
- case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
- case V4L2_CID_PILOT_TONE_DEVIATION:
- case V4L2_CID_PILOT_TONE_FREQUENCY:
- case V4L2_CID_TUNE_POWER_LEVEL:
- case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
- qctrl->flags |= V4L2_CTRL_FLAG_SLIDER;
- break;
- case V4L2_CID_PAN_RELATIVE:
- case V4L2_CID_TILT_RELATIVE:
- case V4L2_CID_FOCUS_RELATIVE:
- case V4L2_CID_IRIS_RELATIVE:
- case V4L2_CID_ZOOM_RELATIVE:
- qctrl->flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
- break;
- }
qctrl->minimum = min;
qctrl->maximum = max;
qctrl->step = step;
@@ -668,7 +199,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_fill);
If menu_items is NULL, then the menu items are retrieved using
v4l2_ctrl_get_menu. */
int v4l2_ctrl_query_menu(struct v4l2_querymenu *qmenu, struct v4l2_queryctrl *qctrl,
- const char **menu_items)
+ const char * const *menu_items)
{
int i;
@@ -691,7 +222,7 @@ EXPORT_SYMBOL(v4l2_ctrl_query_menu);
Use this if there are 'holes' in the list of valid menu items. */
int v4l2_ctrl_query_menu_valid_items(struct v4l2_querymenu *qmenu, const u32 *ids)
{
- const char **menu_items = v4l2_ctrl_get_menu(qmenu->id);
+ const char * const *menu_items = v4l2_ctrl_get_menu(qmenu->id);
qmenu->reserved = 0;
if (menu_items == NULL || ids == NULL)
@@ -837,20 +368,20 @@ EXPORT_SYMBOL_GPL(v4l2_i2c_subdev_init);
/* Load an i2c sub-device. */
struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter, const char *module_name,
- struct i2c_board_info *info, const unsigned short *probe_addrs)
+ struct i2c_adapter *adapter, struct i2c_board_info *info,
+ const unsigned short *probe_addrs)
{
struct v4l2_subdev *sd = NULL;
struct i2c_client *client;
BUG_ON(!v4l2_dev);
- if (module_name)
- request_module(module_name);
+ request_module(I2C_MODULE_PREFIX "%s", info->type);
/* Create the i2c client */
if (info->addr == 0 && probe_addrs)
- client = i2c_new_probed_device(adapter, info, probe_addrs);
+ client = i2c_new_probed_device(adapter, info, probe_addrs,
+ NULL);
else
client = i2c_new_device(adapter, info);
@@ -876,18 +407,6 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_board(struct v4l2_device *v4l2_dev,
/* Decrease the module use count to match the first try_module_get. */
module_put(client->driver->driver.owner);
- if (sd) {
- /* We return errors from v4l2_subdev_call only if we have the
- callback as the .s_config is not mandatory */
- int err = v4l2_subdev_call(sd, core, s_config,
- info->irq, info->platform_data);
-
- if (err && err != -ENOIOCTLCMD) {
- v4l2_device_unregister_subdev(sd);
- sd = NULL;
- }
- }
-
error:
/* If we have a client but no subdev, then something went wrong and
we must unregister the client. */
@@ -897,10 +416,8 @@ error:
}
EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_board);
-struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
- struct i2c_adapter *adapter,
- const char *module_name, const char *client_type,
- int irq, void *platform_data,
+struct v4l2_subdev *v4l2_i2c_new_subdev(struct v4l2_device *v4l2_dev,
+ struct i2c_adapter *adapter, const char *client_type,
u8 addr, const unsigned short *probe_addrs)
{
struct i2c_board_info info;
@@ -910,13 +427,10 @@ struct v4l2_subdev *v4l2_i2c_new_subdev_cfg(struct v4l2_device *v4l2_dev,
memset(&info, 0, sizeof(info));
strlcpy(info.type, client_type, sizeof(info.type));
info.addr = addr;
- info.irq = irq;
- info.platform_data = platform_data;
- return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, module_name,
- &info, probe_addrs);
+ return v4l2_i2c_new_subdev_board(v4l2_dev, adapter, &info, probe_addrs);
}
-EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev_cfg);
+EXPORT_SYMBOL_GPL(v4l2_i2c_new_subdev);
/* Return i2c client address of v4l2_subdev. */
unsigned short v4l2_i2c_subdev_addr(struct v4l2_subdev *sd)
@@ -1144,3 +658,28 @@ int v4l_fill_dv_preset_info(u32 preset, struct v4l2_dv_enum_preset *info)
return 0;
}
EXPORT_SYMBOL_GPL(v4l_fill_dv_preset_info);
+
+const struct v4l2_frmsize_discrete *v4l2_find_nearest_format(
+ const struct v4l2_discrete_probe *probe,
+ s32 width, s32 height)
+{
+ int i;
+ u32 error, min_error = UINT_MAX;
+ const struct v4l2_frmsize_discrete *size, *best = NULL;
+
+ if (!probe)
+ return best;
+
+ for (i = 0, size = probe->sizes; i < probe->num_sizes; i++, size++) {
+ error = abs(size->width - width) + abs(size->height - height);
+ if (error < min_error) {
+ min_error = error;
+ best = size;
+ }
+ if (!error)
+ break;
+ }
+
+ return best;
+}
+EXPORT_SYMBOL_GPL(v4l2_find_nearest_format);
diff --git a/drivers/media/video/v4l2-compat-ioctl32.c b/drivers/media/video/v4l2-compat-ioctl32.c
index 9004a5fe7643..dc82eb83c1d4 100644
--- a/drivers/media/video/v4l2-compat-ioctl32.c
+++ b/drivers/media/video/v4l2-compat-ioctl32.c
@@ -5,7 +5,7 @@
* Copyright (C) 1997-2000 Jakub Jelinek (jakub@redhat.com)
* Copyright (C) 1998 Eddie C. Dost (ecd@skynet.be)
* Copyright (C) 2001,2002 Andi Kleen, SuSE Labs
- * Copyright (C) 2003 Pavel Machek (pavel@suse.cz)
+ * Copyright (C) 2003 Pavel Machek (pavel@ucw.cz)
* Copyright (C) 2005 Philippe De Muyter (phdm@macqel.be)
* Copyright (C) 2008 Hans Verkuil <hverkuil@xs4all.nl>
*
@@ -15,224 +15,18 @@
#include <linux/compat.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls*/
-#include <linux/videodev.h>
#include <linux/videodev2.h>
#include <linux/module.h>
-#include <linux/smp_lock.h>
#include <media/v4l2-ioctl.h>
#ifdef CONFIG_COMPAT
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-struct video_tuner32 {
- compat_int_t tuner;
- char name[32];
- compat_ulong_t rangelow, rangehigh;
- u32 flags; /* It is really u32 in videodev.h */
- u16 mode, signal;
-};
-
-static int get_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_tuner32)) ||
- get_user(kp->tuner, &up->tuner) ||
- copy_from_user(kp->name, up->name, 32) ||
- get_user(kp->rangelow, &up->rangelow) ||
- get_user(kp->rangehigh, &up->rangehigh) ||
- get_user(kp->flags, &up->flags) ||
- get_user(kp->mode, &up->mode) ||
- get_user(kp->signal, &up->signal))
- return -EFAULT;
- return 0;
-}
-
-static int put_video_tuner32(struct video_tuner *kp, struct video_tuner32 __user *up)
-{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_tuner32)) ||
- put_user(kp->tuner, &up->tuner) ||
- copy_to_user(up->name, kp->name, 32) ||
- put_user(kp->rangelow, &up->rangelow) ||
- put_user(kp->rangehigh, &up->rangehigh) ||
- put_user(kp->flags, &up->flags) ||
- put_user(kp->mode, &up->mode) ||
- put_user(kp->signal, &up->signal))
- return -EFAULT;
- return 0;
-}
-
-struct video_buffer32 {
- compat_caddr_t base;
- compat_int_t height, width, depth, bytesperline;
-};
-
-static int get_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
- u32 tmp;
-
- if (!access_ok(VERIFY_READ, up, sizeof(struct video_buffer32)) ||
- get_user(tmp, &up->base) ||
- get_user(kp->height, &up->height) ||
- get_user(kp->width, &up->width) ||
- get_user(kp->depth, &up->depth) ||
- get_user(kp->bytesperline, &up->bytesperline))
- return -EFAULT;
-
- /* This is actually a physical address stored
- * as a void pointer.
- */
- kp->base = (void *)(unsigned long) tmp;
-
- return 0;
-}
-
-static int put_video_buffer32(struct video_buffer *kp, struct video_buffer32 __user *up)
-{
- u32 tmp = (u32)((unsigned long)kp->base);
-
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_buffer32)) ||
- put_user(tmp, &up->base) ||
- put_user(kp->height, &up->height) ||
- put_user(kp->width, &up->width) ||
- put_user(kp->depth, &up->depth) ||
- put_user(kp->bytesperline, &up->bytesperline))
- return -EFAULT;
- return 0;
-}
-
-struct video_clip32 {
- s32 x, y, width, height; /* It's really s32 in videodev.h */
- compat_caddr_t next;
-};
-
-struct video_window32 {
- u32 x, y, width, height, chromakey, flags;
- compat_caddr_t clips;
- compat_int_t clipcount;
-};
-
-static int get_video_window32(struct video_window *kp, struct video_window32 __user *up)
-{
- struct video_clip __user *uclips;
- struct video_clip __user *kclips;
- compat_caddr_t p;
- int nclips;
-
- 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;
- }
-
- /* 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;
-}
-
-/* You get back everything except the clips... */
-static int put_video_window32(struct video_window *kp, struct video_window32 __user *up)
-{
- if (!access_ok(VERIFY_WRITE, up, sizeof(struct video_window32)) ||
- put_user(kp->x, &up->x) ||
- put_user(kp->y, &up->y) ||
- put_user(kp->width, &up->width) ||
- put_user(kp->height, &up->height) ||
- put_user(kp->chromakey, &up->chromakey) ||
- put_user(kp->flags, &up->flags) ||
- put_user(kp->clipcount, &up->clipcount))
- 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();
- ret = file->f_op->ioctl(file->f_path.dentry->d_inode, file, cmd, arg);
- unlock_kernel();
- }
return ret;
}
@@ -371,8 +165,6 @@ static int get_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
if (copy_from_user(kp, up, sizeof(kp->fmt.raw_data)))
return -EFAULT;
return 0;
- case 0:
- return -EINVAL;
default:
printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
kp->type);
@@ -402,8 +194,6 @@ static int put_v4l2_format32(struct v4l2_format *kp, struct v4l2_format32 __user
if (copy_to_user(up, kp, sizeof(up->fmt.raw_data)))
return -EFAULT;
return 0;
- case 0:
- return -EINVAL;
default:
printk(KERN_INFO "compat_ioctl32: unexpected VIDIOC_FMT type %d\n",
kp->type);
@@ -740,13 +530,6 @@ static int put_v4l2_ext_controls32(struct v4l2_ext_controls *kp, struct v4l2_ext
static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
union {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- struct video_tuner vt;
- struct video_buffer vb;
- struct video_window vw;
- struct video_code vc;
- struct video_audio va;
-#endif
struct v4l2_format v2f;
struct v4l2_buffer v2b;
struct v4l2_framebuffer v2fb;
@@ -762,17 +545,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
/* First, convert the command. */
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- 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;
@@ -799,43 +571,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
}
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case VIDIOCSTUNER:
- case VIDIOCGTUNER:
- err = get_video_tuner32(&karg.vt, up);
- compatible_arg = 0;
- break;
-
- case VIDIOCSFBUF:
- err = get_video_buffer32(&karg.vb, up);
- compatible_arg = 0;
- break;
-
- 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;
-
- case VIDIOCSFREQ:
- err = get_user(karg.vx, (u32 __user *)up);
- compatible_arg = 0;
- break;
-
- case VIDIOCCAPTURE:
- case VIDIOCSYNC:
- case VIDIOCSWRITEMODE:
-#endif
case VIDIOC_OVERLAY:
case VIDIOC_STREAMON:
case VIDIOC_STREAMOFF:
@@ -918,23 +653,6 @@ static long do_video_ioctl(struct file *file, unsigned int cmd, unsigned long ar
return err;
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;
-
- case VIDIOCGFREQ:
- err = put_user(((u32)karg.vx), (u32 __user *)up);
- break;
-#endif
case VIDIOC_S_INPUT:
case VIDIOC_S_OUTPUT:
case VIDIOC_G_INPUT:
@@ -973,41 +691,10 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
{
long ret = -ENOIOCTLCMD;
- if (!file->f_op->ioctl && !file->f_op->unlocked_ioctl)
+ if (!file->f_op->unlocked_ioctl)
return ret;
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- 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:
@@ -1092,19 +779,6 @@ long v4l2_compat_ioctl32(struct file *file, unsigned int cmd, unsigned long arg)
ret = do_video_ioctl(file, cmd, arg);
break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /* BTTV specific... */
- case _IOW('v', BASE_VIDIOCPRIVATE+0, char [256]):
- case _IOR('v', BASE_VIDIOCPRIVATE+1, char [256]):
- case _IOR('v' , BASE_VIDIOCPRIVATE+2, unsigned int):
- case _IOW('v' , BASE_VIDIOCPRIVATE+3, char [16]): /* struct bttv_pll_info */
- case _IOR('v' , BASE_VIDIOCPRIVATE+4, int):
- case _IOR('v' , BASE_VIDIOCPRIVATE+5, int):
- case _IOR('v' , BASE_VIDIOCPRIVATE+6, int):
- case _IOR('v' , BASE_VIDIOCPRIVATE+7, int):
- ret = native_ioctl(file, cmd, (unsigned long)compat_ptr(arg));
- break;
-#endif
default:
printk(KERN_WARNING "compat_ioctl32: "
"unknown ioctl '%c', dir=%d, #%d (0x%08x)\n",
diff --git a/drivers/media/video/v4l2-ctrls.c b/drivers/media/video/v4l2-ctrls.c
new file mode 100644
index 000000000000..ef66d2af0c57
--- /dev/null
+++ b/drivers/media/video/v4l2-ctrls.c
@@ -0,0 +1,1873 @@
+/*
+ V4L2 controls framework implementation.
+
+ Copyright (C) 2010 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/ctype.h>
+#include <linux/slab.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-dev.h>
+
+/* Internal temporary helper struct, one for each v4l2_ext_control */
+struct ctrl_helper {
+ /* The control corresponding to the v4l2_ext_control ID field. */
+ struct v4l2_ctrl *ctrl;
+ /* Used internally to mark whether this control was already
+ processed. */
+ bool handled;
+};
+
+/* Returns NULL or a character pointer array containing the menu for
+ the given control ID. The pointer array ends with a NULL pointer.
+ An empty string signifies a menu entry that is invalid. This allows
+ drivers to disable certain options if it is not supported. */
+const char * const *v4l2_ctrl_get_menu(u32 id)
+{
+ static const char * const mpeg_audio_sampling_freq[] = {
+ "44.1 kHz",
+ "48 kHz",
+ "32 kHz",
+ NULL
+ };
+ static const char * const mpeg_audio_encoding[] = {
+ "MPEG-1/2 Layer I",
+ "MPEG-1/2 Layer II",
+ "MPEG-1/2 Layer III",
+ "MPEG-2/4 AAC",
+ "AC-3",
+ NULL
+ };
+ static const char * const mpeg_audio_l1_bitrate[] = {
+ "32 kbps",
+ "64 kbps",
+ "96 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "288 kbps",
+ "320 kbps",
+ "352 kbps",
+ "384 kbps",
+ "416 kbps",
+ "448 kbps",
+ NULL
+ };
+ static const char * const mpeg_audio_l2_bitrate[] = {
+ "32 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ NULL
+ };
+ static const char * const mpeg_audio_l3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ NULL
+ };
+ static const char * const mpeg_audio_ac3_bitrate[] = {
+ "32 kbps",
+ "40 kbps",
+ "48 kbps",
+ "56 kbps",
+ "64 kbps",
+ "80 kbps",
+ "96 kbps",
+ "112 kbps",
+ "128 kbps",
+ "160 kbps",
+ "192 kbps",
+ "224 kbps",
+ "256 kbps",
+ "320 kbps",
+ "384 kbps",
+ "448 kbps",
+ "512 kbps",
+ "576 kbps",
+ "640 kbps",
+ NULL
+ };
+ static const char * const mpeg_audio_mode[] = {
+ "Stereo",
+ "Joint Stereo",
+ "Dual",
+ "Mono",
+ NULL
+ };
+ static const char * const mpeg_audio_mode_extension[] = {
+ "Bound 4",
+ "Bound 8",
+ "Bound 12",
+ "Bound 16",
+ NULL
+ };
+ static const char * const mpeg_audio_emphasis[] = {
+ "No Emphasis",
+ "50/15 us",
+ "CCITT J17",
+ NULL
+ };
+ static const char * const mpeg_audio_crc[] = {
+ "No CRC",
+ "16-bit CRC",
+ NULL
+ };
+ static const char * const mpeg_video_encoding[] = {
+ "MPEG-1",
+ "MPEG-2",
+ "MPEG-4 AVC",
+ NULL
+ };
+ static const char * const mpeg_video_aspect[] = {
+ "1x1",
+ "4x3",
+ "16x9",
+ "2.21x1",
+ NULL
+ };
+ static const char * const mpeg_video_bitrate_mode[] = {
+ "Variable Bitrate",
+ "Constant Bitrate",
+ NULL
+ };
+ static const char * const mpeg_stream_type[] = {
+ "MPEG-2 Program Stream",
+ "MPEG-2 Transport Stream",
+ "MPEG-1 System Stream",
+ "MPEG-2 DVD-compatible Stream",
+ "MPEG-1 VCD-compatible Stream",
+ "MPEG-2 SVCD-compatible Stream",
+ NULL
+ };
+ static const char * const mpeg_stream_vbi_fmt[] = {
+ "No VBI",
+ "Private packet, IVTV format",
+ NULL
+ };
+ static const char * const camera_power_line_frequency[] = {
+ "Disabled",
+ "50 Hz",
+ "60 Hz",
+ NULL
+ };
+ static const char * const camera_exposure_auto[] = {
+ "Auto Mode",
+ "Manual Mode",
+ "Shutter Priority Mode",
+ "Aperture Priority Mode",
+ NULL
+ };
+ static const char * const colorfx[] = {
+ "None",
+ "Black & White",
+ "Sepia",
+ "Negative",
+ "Emboss",
+ "Sketch",
+ "Sky blue",
+ "Grass green",
+ "Skin whiten",
+ "Vivid",
+ NULL
+ };
+ static const char * const tune_preemphasis[] = {
+ "No preemphasis",
+ "50 useconds",
+ "75 useconds",
+ NULL,
+ };
+
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ:
+ return mpeg_audio_sampling_freq;
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ return mpeg_audio_encoding;
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE:
+ return mpeg_audio_l1_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ return mpeg_audio_l2_bitrate;
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ return mpeg_audio_l3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ return mpeg_audio_ac3_bitrate;
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ return mpeg_audio_mode;
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ return mpeg_audio_mode_extension;
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ return mpeg_audio_emphasis;
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ return mpeg_audio_crc;
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ return mpeg_video_encoding;
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ return mpeg_video_aspect;
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ return mpeg_video_bitrate_mode;
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ 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;
+ case V4L2_CID_COLORFX:
+ return colorfx;
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ return tune_preemphasis;
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_menu);
+
+/* Return the control name. */
+const char *v4l2_ctrl_get_name(u32 id)
+{
+ switch (id) {
+ /* USER controls */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
+ case V4L2_CID_USER_CLASS: return "User Controls";
+ 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_AUDIO_VOLUME: return "Volume";
+ 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_MUTE: return "Mute";
+ case V4L2_CID_AUDIO_LOUDNESS: return "Loudness";
+ 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";
+ case V4L2_CID_COLORFX: return "Color Effects";
+ case V4L2_CID_AUTOBRIGHTNESS: return "Brightness, Automatic";
+ case V4L2_CID_BAND_STOP_FILTER: return "Band-Stop Filter";
+ case V4L2_CID_ROTATE: return "Rotate";
+ case V4L2_CID_BG_COLOR: return "Background Color";
+ case V4L2_CID_CHROMA_GAIN: return "Chroma Gain";
+ case V4L2_CID_ILLUMINATORS_1: return "Illuminator 1";
+ case V4L2_CID_ILLUMINATORS_2: return "Illuminator 2";
+
+ /* MPEG controls */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
+ case V4L2_CID_MPEG_CLASS: return "MPEG Encoder Controls";
+ case V4L2_CID_MPEG_STREAM_TYPE: return "Stream Type";
+ case V4L2_CID_MPEG_STREAM_PID_PMT: return "Stream PMT Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_AUDIO: return "Stream Audio Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_VIDEO: return "Stream Video Program ID";
+ case V4L2_CID_MPEG_STREAM_PID_PCR: return "Stream PCR Program ID";
+ case V4L2_CID_MPEG_STREAM_PES_ID_AUDIO: return "Stream PES Audio 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";
+ case V4L2_CID_MPEG_AUDIO_SAMPLING_FREQ: return "Audio Sampling Frequency";
+ case V4L2_CID_MPEG_AUDIO_ENCODING: return "Audio Encoding";
+ case V4L2_CID_MPEG_AUDIO_L1_BITRATE: return "Audio Layer I Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE: return "Audio Layer II Bitrate";
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE: return "Audio Layer III Bitrate";
+ case V4L2_CID_MPEG_AUDIO_MODE: return "Audio Stereo Mode";
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION: return "Audio Stereo Mode Extension";
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS: return "Audio Emphasis";
+ case V4L2_CID_MPEG_AUDIO_CRC: return "Audio CRC";
+ case V4L2_CID_MPEG_AUDIO_MUTE: return "Audio Mute";
+ case V4L2_CID_MPEG_AUDIO_AAC_BITRATE: return "Audio AAC Bitrate";
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE: return "Audio AC-3 Bitrate";
+ case V4L2_CID_MPEG_VIDEO_ENCODING: return "Video Encoding";
+ case V4L2_CID_MPEG_VIDEO_ASPECT: return "Video Aspect";
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES: return "Video B Frames";
+ case V4L2_CID_MPEG_VIDEO_GOP_SIZE: return "Video GOP Size";
+ case V4L2_CID_MPEG_VIDEO_GOP_CLOSURE: return "Video GOP Closure";
+ case V4L2_CID_MPEG_VIDEO_PULLDOWN: return "Video Pulldown";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE: return "Video Bitrate Mode";
+ case V4L2_CID_MPEG_VIDEO_BITRATE: return "Video Bitrate";
+ case V4L2_CID_MPEG_VIDEO_BITRATE_PEAK: return "Video Peak Bitrate";
+ case V4L2_CID_MPEG_VIDEO_TEMPORAL_DECIMATION: return "Video Temporal Decimation";
+ case V4L2_CID_MPEG_VIDEO_MUTE: return "Video Mute";
+ case V4L2_CID_MPEG_VIDEO_MUTE_YUV: return "Video Mute YUV";
+
+ /* CAMERA controls */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
+ 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";
+ case V4L2_CID_IRIS_ABSOLUTE: return "Iris, Absolute";
+ case V4L2_CID_IRIS_RELATIVE: return "Iris, Relative";
+
+ /* FM Radio Modulator control */
+ /* Keep the order of the 'case's the same as in videodev2.h! */
+ case V4L2_CID_FM_TX_CLASS: return "FM Radio Modulator Controls";
+ case V4L2_CID_RDS_TX_DEVIATION: return "RDS Signal Deviation";
+ case V4L2_CID_RDS_TX_PI: return "RDS Program ID";
+ case V4L2_CID_RDS_TX_PTY: return "RDS Program Type";
+ case V4L2_CID_RDS_TX_PS_NAME: return "RDS PS Name";
+ case V4L2_CID_RDS_TX_RADIO_TEXT: return "RDS Radio Text";
+ case V4L2_CID_AUDIO_LIMITER_ENABLED: return "Audio Limiter Feature Enabled";
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME: return "Audio Limiter Release Time";
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION: return "Audio Limiter Deviation";
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED: return "Audio Compression Feature Enabled";
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN: return "Audio Compression Gain";
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD: return "Audio Compression Threshold";
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME: return "Audio Compression Attack Time";
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME: return "Audio Compression Release Time";
+ case V4L2_CID_PILOT_TONE_ENABLED: return "Pilot Tone Feature Enabled";
+ case V4L2_CID_PILOT_TONE_DEVIATION: return "Pilot Tone Deviation";
+ case V4L2_CID_PILOT_TONE_FREQUENCY: return "Pilot Tone Frequency";
+ case V4L2_CID_TUNE_PREEMPHASIS: return "Pre-emphasis settings";
+ case V4L2_CID_TUNE_POWER_LEVEL: return "Tune Power Level";
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR: return "Tune Antenna Capacitor";
+
+ default:
+ return NULL;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_get_name);
+
+void v4l2_ctrl_fill(u32 id, const char **name, enum v4l2_ctrl_type *type,
+ s32 *min, s32 *max, s32 *step, s32 *def, u32 *flags)
+{
+ *name = v4l2_ctrl_get_name(id);
+ *flags = 0;
+
+ switch (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_CHROMA_AGC:
+ case V4L2_CID_COLOR_KILLER:
+ 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_FOCUS_AUTO:
+ case V4L2_CID_PRIVACY:
+ case V4L2_CID_AUDIO_LIMITER_ENABLED:
+ case V4L2_CID_AUDIO_COMPRESSION_ENABLED:
+ case V4L2_CID_PILOT_TONE_ENABLED:
+ case V4L2_CID_ILLUMINATORS_1:
+ case V4L2_CID_ILLUMINATORS_2:
+ *type = V4L2_CTRL_TYPE_BOOLEAN;
+ *min = 0;
+ *max = *step = 1;
+ break;
+ case V4L2_CID_PAN_RESET:
+ case V4L2_CID_TILT_RESET:
+ *type = V4L2_CTRL_TYPE_BUTTON;
+ *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ *min = *max = *step = *def = 0;
+ 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:
+ case V4L2_CID_MPEG_AUDIO_L2_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_L3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_AC3_BITRATE:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_AUDIO_MODE_EXTENSION:
+ case V4L2_CID_MPEG_AUDIO_EMPHASIS:
+ case V4L2_CID_MPEG_AUDIO_CRC:
+ case V4L2_CID_MPEG_VIDEO_ENCODING:
+ case V4L2_CID_MPEG_VIDEO_ASPECT:
+ 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:
+ case V4L2_CID_COLORFX:
+ case V4L2_CID_TUNE_PREEMPHASIS:
+ *type = V4L2_CTRL_TYPE_MENU;
+ break;
+ case V4L2_CID_RDS_TX_PS_NAME:
+ case V4L2_CID_RDS_TX_RADIO_TEXT:
+ *type = V4L2_CTRL_TYPE_STRING;
+ break;
+ case V4L2_CID_USER_CLASS:
+ case V4L2_CID_CAMERA_CLASS:
+ case V4L2_CID_MPEG_CLASS:
+ case V4L2_CID_FM_TX_CLASS:
+ *type = V4L2_CTRL_TYPE_CTRL_CLASS;
+ /* You can neither read not write these */
+ *flags |= V4L2_CTRL_FLAG_READ_ONLY | V4L2_CTRL_FLAG_WRITE_ONLY;
+ *min = *max = *step = *def = 0;
+ break;
+ case V4L2_CID_BG_COLOR:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ *step = 1;
+ *min = 0;
+ /* Max is calculated as RGB888 that is 2^24 */
+ *max = 0xFFFFFF;
+ break;
+ default:
+ *type = V4L2_CTRL_TYPE_INTEGER;
+ break;
+ }
+ switch (id) {
+ case V4L2_CID_MPEG_AUDIO_ENCODING:
+ case V4L2_CID_MPEG_AUDIO_MODE:
+ case V4L2_CID_MPEG_VIDEO_BITRATE_MODE:
+ case V4L2_CID_MPEG_VIDEO_B_FRAMES:
+ case V4L2_CID_MPEG_STREAM_TYPE:
+ *flags |= V4L2_CTRL_FLAG_UPDATE;
+ break;
+ case V4L2_CID_AUDIO_VOLUME:
+ case V4L2_CID_AUDIO_BALANCE:
+ case V4L2_CID_AUDIO_BASS:
+ case V4L2_CID_AUDIO_TREBLE:
+ case V4L2_CID_BRIGHTNESS:
+ case V4L2_CID_CONTRAST:
+ case V4L2_CID_SATURATION:
+ case V4L2_CID_HUE:
+ case V4L2_CID_RED_BALANCE:
+ case V4L2_CID_BLUE_BALANCE:
+ case V4L2_CID_GAMMA:
+ case V4L2_CID_SHARPNESS:
+ case V4L2_CID_CHROMA_GAIN:
+ case V4L2_CID_RDS_TX_DEVIATION:
+ case V4L2_CID_AUDIO_LIMITER_RELEASE_TIME:
+ case V4L2_CID_AUDIO_LIMITER_DEVIATION:
+ case V4L2_CID_AUDIO_COMPRESSION_GAIN:
+ case V4L2_CID_AUDIO_COMPRESSION_THRESHOLD:
+ case V4L2_CID_AUDIO_COMPRESSION_ATTACK_TIME:
+ case V4L2_CID_AUDIO_COMPRESSION_RELEASE_TIME:
+ case V4L2_CID_PILOT_TONE_DEVIATION:
+ case V4L2_CID_PILOT_TONE_FREQUENCY:
+ case V4L2_CID_TUNE_POWER_LEVEL:
+ case V4L2_CID_TUNE_ANTENNA_CAPACITOR:
+ *flags |= V4L2_CTRL_FLAG_SLIDER;
+ break;
+ case V4L2_CID_PAN_RELATIVE:
+ case V4L2_CID_TILT_RELATIVE:
+ case V4L2_CID_FOCUS_RELATIVE:
+ case V4L2_CID_IRIS_RELATIVE:
+ case V4L2_CID_ZOOM_RELATIVE:
+ *flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ break;
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_fill);
+
+/* Helper function to determine whether the control type is compatible with
+ VIDIOC_G/S_CTRL. */
+static bool type_is_int(const struct v4l2_ctrl *ctrl)
+{
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER64:
+ case V4L2_CTRL_TYPE_STRING:
+ /* Nope, these need v4l2_ext_control */
+ return false;
+ default:
+ return true;
+ }
+}
+
+/* Helper function: copy the current control value back to the caller */
+static int cur_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl)
+{
+ u32 len;
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ len = strlen(ctrl->cur.string);
+ if (c->size < len + 1) {
+ c->size = len + 1;
+ return -ENOSPC;
+ }
+ return copy_to_user(c->string, ctrl->cur.string,
+ len + 1) ? -EFAULT : 0;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ c->value64 = ctrl->cur.val64;
+ break;
+ default:
+ c->value = ctrl->cur.val;
+ break;
+ }
+ return 0;
+}
+
+/* Helper function: copy the caller-provider value as the new control value */
+static int user_to_new(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl)
+{
+ int ret;
+ u32 size;
+
+ ctrl->is_new = 1;
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER64:
+ ctrl->val64 = c->value64;
+ break;
+ case V4L2_CTRL_TYPE_STRING:
+ size = c->size;
+ if (size == 0)
+ return -ERANGE;
+ if (size > ctrl->maximum + 1)
+ size = ctrl->maximum + 1;
+ ret = copy_from_user(ctrl->string, c->string, size);
+ if (!ret) {
+ char last = ctrl->string[size - 1];
+
+ ctrl->string[size - 1] = 0;
+ /* If the string was longer than ctrl->maximum,
+ then return an error. */
+ if (strlen(ctrl->string) == ctrl->maximum && last)
+ return -ERANGE;
+ }
+ return ret ? -EFAULT : 0;
+ default:
+ ctrl->val = c->value;
+ break;
+ }
+ return 0;
+}
+
+/* Helper function: copy the new control value back to the caller */
+static int new_to_user(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl)
+{
+ u32 len;
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ len = strlen(ctrl->string);
+ if (c->size < len + 1) {
+ c->size = ctrl->maximum + 1;
+ return -ENOSPC;
+ }
+ return copy_to_user(c->string, ctrl->string,
+ len + 1) ? -EFAULT : 0;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ c->value64 = ctrl->val64;
+ break;
+ default:
+ c->value = ctrl->val;
+ break;
+ }
+ return 0;
+}
+
+/* Copy the new value to the current value. */
+static void new_to_cur(struct v4l2_ctrl *ctrl)
+{
+ if (ctrl == NULL)
+ return;
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ /* strings are always 0-terminated */
+ strcpy(ctrl->cur.string, ctrl->string);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ ctrl->cur.val64 = ctrl->val64;
+ break;
+ default:
+ ctrl->cur.val = ctrl->val;
+ break;
+ }
+}
+
+/* Copy the current value to the new value */
+static void cur_to_new(struct v4l2_ctrl *ctrl)
+{
+ if (ctrl == NULL)
+ return;
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_STRING:
+ /* strings are always 0-terminated */
+ strcpy(ctrl->string, ctrl->cur.string);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ ctrl->val64 = ctrl->cur.val64;
+ break;
+ default:
+ ctrl->val = ctrl->cur.val;
+ break;
+ }
+}
+
+/* Return non-zero if one or more of the controls in the cluster has a new
+ value that differs from the current value. */
+static int cluster_changed(struct v4l2_ctrl *master)
+{
+ int diff = 0;
+ int i;
+
+ for (i = 0; !diff && i < master->ncontrols; i++) {
+ struct v4l2_ctrl *ctrl = master->cluster[i];
+
+ if (ctrl == NULL)
+ continue;
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_BUTTON:
+ /* Button controls are always 'different' */
+ return 1;
+ case V4L2_CTRL_TYPE_STRING:
+ /* strings are always 0-terminated */
+ diff = strcmp(ctrl->string, ctrl->cur.string);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ diff = ctrl->val64 != ctrl->cur.val64;
+ break;
+ default:
+ diff = ctrl->val != ctrl->cur.val;
+ break;
+ }
+ }
+ return diff;
+}
+
+/* Validate a new control */
+static int validate_new(struct v4l2_ctrl *ctrl)
+{
+ s32 val = ctrl->val;
+ char *s = ctrl->string;
+ u32 offset;
+ size_t len;
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ /* Round towards the closest legal value */
+ val += ctrl->step / 2;
+ if (val < ctrl->minimum)
+ val = ctrl->minimum;
+ if (val > ctrl->maximum)
+ val = ctrl->maximum;
+ offset = val - ctrl->minimum;
+ offset = ctrl->step * (offset / ctrl->step);
+ val = ctrl->minimum + offset;
+ ctrl->val = val;
+ return 0;
+
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ ctrl->val = !!ctrl->val;
+ return 0;
+
+ case V4L2_CTRL_TYPE_MENU:
+ if (val < ctrl->minimum || val > ctrl->maximum)
+ return -ERANGE;
+ if (ctrl->qmenu[val][0] == '\0' ||
+ (ctrl->menu_skip_mask & (1 << val)))
+ return -EINVAL;
+ return 0;
+
+ case V4L2_CTRL_TYPE_BUTTON:
+ case V4L2_CTRL_TYPE_CTRL_CLASS:
+ ctrl->val64 = 0;
+ return 0;
+
+ case V4L2_CTRL_TYPE_INTEGER64:
+ return 0;
+
+ case V4L2_CTRL_TYPE_STRING:
+ len = strlen(s);
+ if (len < ctrl->minimum)
+ return -ERANGE;
+ if ((len - ctrl->minimum) % ctrl->step)
+ return -ERANGE;
+ return 0;
+
+ default:
+ return -EINVAL;
+ }
+}
+
+static inline u32 node2id(struct list_head *node)
+{
+ return list_entry(node, struct v4l2_ctrl_ref, node)->ctrl->id;
+}
+
+/* Set the handler's error code if it wasn't set earlier already */
+static inline int handler_set_err(struct v4l2_ctrl_handler *hdl, int err)
+{
+ if (hdl->error == 0)
+ hdl->error = err;
+ return err;
+}
+
+/* Initialize the handler */
+int v4l2_ctrl_handler_init(struct v4l2_ctrl_handler *hdl,
+ unsigned nr_of_controls_hint)
+{
+ mutex_init(&hdl->lock);
+ INIT_LIST_HEAD(&hdl->ctrls);
+ INIT_LIST_HEAD(&hdl->ctrl_refs);
+ hdl->nr_of_buckets = 1 + nr_of_controls_hint / 8;
+ hdl->buckets = kzalloc(sizeof(hdl->buckets[0]) * hdl->nr_of_buckets,
+ GFP_KERNEL);
+ hdl->error = hdl->buckets ? 0 : -ENOMEM;
+ return hdl->error;
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_init);
+
+/* Free all controls and control refs */
+void v4l2_ctrl_handler_free(struct v4l2_ctrl_handler *hdl)
+{
+ struct v4l2_ctrl_ref *ref, *next_ref;
+ struct v4l2_ctrl *ctrl, *next_ctrl;
+
+ if (hdl == NULL || hdl->buckets == NULL)
+ return;
+
+ mutex_lock(&hdl->lock);
+ /* Free all nodes */
+ list_for_each_entry_safe(ref, next_ref, &hdl->ctrl_refs, node) {
+ list_del(&ref->node);
+ kfree(ref);
+ }
+ /* Free all controls owned by the handler */
+ list_for_each_entry_safe(ctrl, next_ctrl, &hdl->ctrls, node) {
+ list_del(&ctrl->node);
+ kfree(ctrl);
+ }
+ kfree(hdl->buckets);
+ hdl->buckets = NULL;
+ hdl->cached = NULL;
+ hdl->error = 0;
+ mutex_unlock(&hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_free);
+
+/* For backwards compatibility: V4L2_CID_PRIVATE_BASE should no longer
+ be used except in G_CTRL, S_CTRL, QUERYCTRL and QUERYMENU when dealing
+ with applications that do not use the NEXT_CTRL flag.
+
+ We just find the n-th private user control. It's O(N), but that should not
+ be an issue in this particular case. */
+static struct v4l2_ctrl_ref *find_private_ref(
+ struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref;
+
+ id -= V4L2_CID_PRIVATE_BASE;
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ /* Search for private user controls that are compatible with
+ VIDIOC_G/S_CTRL. */
+ if (V4L2_CTRL_ID2CLASS(ref->ctrl->id) == V4L2_CTRL_CLASS_USER &&
+ V4L2_CTRL_DRIVER_PRIV(ref->ctrl->id)) {
+ if (!type_is_int(ref->ctrl))
+ continue;
+ if (id == 0)
+ return ref;
+ id--;
+ }
+ }
+ return NULL;
+}
+
+/* Find a control with the given ID. */
+static struct v4l2_ctrl_ref *find_ref(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref;
+ int bucket;
+
+ id &= V4L2_CTRL_ID_MASK;
+
+ /* Old-style private controls need special handling */
+ if (id >= V4L2_CID_PRIVATE_BASE)
+ return find_private_ref(hdl, id);
+ bucket = id % hdl->nr_of_buckets;
+
+ /* Simple optimization: cache the last control found */
+ if (hdl->cached && hdl->cached->ctrl->id == id)
+ return hdl->cached;
+
+ /* Not in cache, search the hash */
+ ref = hdl->buckets ? hdl->buckets[bucket] : NULL;
+ while (ref && ref->ctrl->id != id)
+ ref = ref->next;
+
+ if (ref)
+ hdl->cached = ref; /* cache it! */
+ return ref;
+}
+
+/* Find a control with the given ID. Take the handler's lock first. */
+static struct v4l2_ctrl_ref *find_ref_lock(
+ struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref = NULL;
+
+ if (hdl) {
+ mutex_lock(&hdl->lock);
+ ref = find_ref(hdl, id);
+ mutex_unlock(&hdl->lock);
+ }
+ return ref;
+}
+
+/* Find a control with the given ID. */
+struct v4l2_ctrl *v4l2_ctrl_find(struct v4l2_ctrl_handler *hdl, u32 id)
+{
+ struct v4l2_ctrl_ref *ref = find_ref_lock(hdl, id);
+
+ return ref ? ref->ctrl : NULL;
+}
+EXPORT_SYMBOL(v4l2_ctrl_find);
+
+/* Allocate a new v4l2_ctrl_ref and hook it into the handler. */
+static int handler_new_ref(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl *ctrl)
+{
+ struct v4l2_ctrl_ref *ref;
+ struct v4l2_ctrl_ref *new_ref;
+ u32 id = ctrl->id;
+ u32 class_ctrl = V4L2_CTRL_ID2CLASS(id) | 1;
+ int bucket = id % hdl->nr_of_buckets; /* which bucket to use */
+
+ /* Automatically add the control class if it is not yet present. */
+ if (id != class_ctrl && find_ref_lock(hdl, class_ctrl) == NULL)
+ if (!v4l2_ctrl_new_std(hdl, NULL, class_ctrl, 0, 0, 0, 0))
+ return hdl->error;
+
+ if (hdl->error)
+ return hdl->error;
+
+ new_ref = kzalloc(sizeof(*new_ref), GFP_KERNEL);
+ if (!new_ref)
+ return handler_set_err(hdl, -ENOMEM);
+ new_ref->ctrl = ctrl;
+ if (ctrl->handler == hdl) {
+ /* By default each control starts in a cluster of its own.
+ new_ref->ctrl is basically a cluster array with one
+ element, so that's perfect to use as the cluster pointer.
+ But only do this for the handler that owns the control. */
+ ctrl->cluster = &new_ref->ctrl;
+ ctrl->ncontrols = 1;
+ }
+
+ INIT_LIST_HEAD(&new_ref->node);
+
+ mutex_lock(&hdl->lock);
+
+ /* Add immediately at the end of the list if the list is empty, or if
+ the last element in the list has a lower ID.
+ This ensures that when elements are added in ascending order the
+ insertion is an O(1) operation. */
+ if (list_empty(&hdl->ctrl_refs) || id > node2id(hdl->ctrl_refs.prev)) {
+ list_add_tail(&new_ref->node, &hdl->ctrl_refs);
+ goto insert_in_hash;
+ }
+
+ /* Find insert position in sorted list */
+ list_for_each_entry(ref, &hdl->ctrl_refs, node) {
+ if (ref->ctrl->id < id)
+ continue;
+ /* Don't add duplicates */
+ if (ref->ctrl->id == id) {
+ kfree(new_ref);
+ goto unlock;
+ }
+ list_add(&new_ref->node, ref->node.prev);
+ break;
+ }
+
+insert_in_hash:
+ /* Insert the control node in the hash */
+ new_ref->next = hdl->buckets[bucket];
+ hdl->buckets[bucket] = new_ref;
+
+unlock:
+ mutex_unlock(&hdl->lock);
+ return 0;
+}
+
+/* Add a new control */
+static struct v4l2_ctrl *v4l2_ctrl_new(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, const char *name, enum v4l2_ctrl_type type,
+ s32 min, s32 max, u32 step, s32 def,
+ u32 flags, const char * const *qmenu, void *priv)
+{
+ struct v4l2_ctrl *ctrl;
+ unsigned sz_extra = 0;
+
+ if (hdl->error)
+ return NULL;
+
+ /* Sanity checks */
+ if (id == 0 || name == NULL || id >= V4L2_CID_PRIVATE_BASE ||
+ max < min ||
+ (type == V4L2_CTRL_TYPE_INTEGER && step == 0) ||
+ (type == V4L2_CTRL_TYPE_MENU && qmenu == NULL) ||
+ (type == V4L2_CTRL_TYPE_STRING && max == 0)) {
+ handler_set_err(hdl, -ERANGE);
+ return NULL;
+ }
+ if ((type == V4L2_CTRL_TYPE_INTEGER ||
+ type == V4L2_CTRL_TYPE_MENU ||
+ type == V4L2_CTRL_TYPE_BOOLEAN) &&
+ (def < min || def > max)) {
+ handler_set_err(hdl, -ERANGE);
+ return NULL;
+ }
+
+ if (type == V4L2_CTRL_TYPE_BUTTON)
+ flags |= V4L2_CTRL_FLAG_WRITE_ONLY;
+ else if (type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ flags |= V4L2_CTRL_FLAG_READ_ONLY;
+ else if (type == V4L2_CTRL_TYPE_STRING)
+ sz_extra += 2 * (max + 1);
+
+ ctrl = kzalloc(sizeof(*ctrl) + sz_extra, GFP_KERNEL);
+ if (ctrl == NULL) {
+ handler_set_err(hdl, -ENOMEM);
+ return NULL;
+ }
+
+ INIT_LIST_HEAD(&ctrl->node);
+ ctrl->handler = hdl;
+ ctrl->ops = ops;
+ ctrl->id = id;
+ ctrl->name = name;
+ ctrl->type = type;
+ ctrl->flags = flags;
+ ctrl->minimum = min;
+ ctrl->maximum = max;
+ ctrl->step = step;
+ ctrl->qmenu = qmenu;
+ ctrl->priv = priv;
+ ctrl->cur.val = ctrl->val = ctrl->default_value = def;
+
+ if (ctrl->type == V4L2_CTRL_TYPE_STRING) {
+ ctrl->cur.string = (char *)&ctrl[1] + sz_extra - (max + 1);
+ ctrl->string = (char *)&ctrl[1] + sz_extra - 2 * (max + 1);
+ if (ctrl->minimum)
+ memset(ctrl->cur.string, ' ', ctrl->minimum);
+ }
+ if (handler_new_ref(hdl, ctrl)) {
+ kfree(ctrl);
+ return NULL;
+ }
+ mutex_lock(&hdl->lock);
+ list_add_tail(&ctrl->node, &hdl->ctrls);
+ mutex_unlock(&hdl->lock);
+ return ctrl;
+}
+
+struct v4l2_ctrl *v4l2_ctrl_new_custom(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_config *cfg, void *priv)
+{
+ bool is_menu;
+ struct v4l2_ctrl *ctrl;
+ const char *name = cfg->name;
+ const char * const *qmenu = cfg->qmenu;
+ enum v4l2_ctrl_type type = cfg->type;
+ u32 flags = cfg->flags;
+ s32 min = cfg->min;
+ s32 max = cfg->max;
+ u32 step = cfg->step;
+ s32 def = cfg->def;
+
+ if (name == NULL)
+ v4l2_ctrl_fill(cfg->id, &name, &type, &min, &max, &step,
+ &def, &flags);
+
+ is_menu = (cfg->type == V4L2_CTRL_TYPE_MENU);
+ if (is_menu)
+ WARN_ON(step);
+ else
+ WARN_ON(cfg->menu_skip_mask);
+ if (is_menu && qmenu == NULL)
+ qmenu = v4l2_ctrl_get_menu(cfg->id);
+
+ ctrl = v4l2_ctrl_new(hdl, cfg->ops, cfg->id, name,
+ type, min, max,
+ is_menu ? cfg->menu_skip_mask : step,
+ def, flags, qmenu, priv);
+ if (ctrl) {
+ ctrl->is_private = cfg->is_private;
+ ctrl->is_volatile = cfg->is_volatile;
+ }
+ return ctrl;
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_custom);
+
+/* Helper function for standard non-menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 min, s32 max, u32 step, s32 def)
+{
+ const char *name;
+ enum v4l2_ctrl_type type;
+ u32 flags;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type == V4L2_CTRL_TYPE_MENU) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, id, name, type,
+ min, max, step, def, flags, NULL, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std);
+
+/* Helper function for standard menu controls */
+struct v4l2_ctrl *v4l2_ctrl_new_std_menu(struct v4l2_ctrl_handler *hdl,
+ const struct v4l2_ctrl_ops *ops,
+ u32 id, s32 max, s32 mask, s32 def)
+{
+ const char * const *qmenu = v4l2_ctrl_get_menu(id);
+ const char *name;
+ enum v4l2_ctrl_type type;
+ s32 min;
+ s32 step;
+ u32 flags;
+
+ v4l2_ctrl_fill(id, &name, &type, &min, &max, &step, &def, &flags);
+ if (type != V4L2_CTRL_TYPE_MENU) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ return v4l2_ctrl_new(hdl, ops, id, name, type,
+ 0, max, mask, def, flags, qmenu, NULL);
+}
+EXPORT_SYMBOL(v4l2_ctrl_new_std_menu);
+
+/* Add a control from another handler to this handler */
+struct v4l2_ctrl *v4l2_ctrl_add_ctrl(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl *ctrl)
+{
+ if (hdl == NULL || hdl->error)
+ return NULL;
+ if (ctrl == NULL) {
+ handler_set_err(hdl, -EINVAL);
+ return NULL;
+ }
+ if (ctrl->handler == hdl)
+ return ctrl;
+ return handler_new_ref(hdl, ctrl) ? NULL : ctrl;
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_ctrl);
+
+/* Add the controls from another handler to our own. */
+int v4l2_ctrl_add_handler(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ctrl_handler *add)
+{
+ struct v4l2_ctrl *ctrl;
+ int ret = 0;
+
+ /* Do nothing if either handler is NULL or if they are the same */
+ if (!hdl || !add || hdl == add)
+ return 0;
+ if (hdl->error)
+ return hdl->error;
+ mutex_lock(&add->lock);
+ list_for_each_entry(ctrl, &add->ctrls, node) {
+ /* Skip handler-private controls. */
+ if (ctrl->is_private)
+ continue;
+ ret = handler_new_ref(hdl, ctrl);
+ if (ret)
+ break;
+ }
+ mutex_unlock(&add->lock);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_add_handler);
+
+/* Cluster controls */
+void v4l2_ctrl_cluster(unsigned ncontrols, struct v4l2_ctrl **controls)
+{
+ int i;
+
+ /* The first control is the master control and it must not be NULL */
+ BUG_ON(controls[0] == NULL);
+
+ for (i = 0; i < ncontrols; i++) {
+ if (controls[i]) {
+ controls[i]->cluster = controls;
+ controls[i]->ncontrols = ncontrols;
+ }
+ }
+}
+EXPORT_SYMBOL(v4l2_ctrl_cluster);
+
+/* Activate/deactivate a control. */
+void v4l2_ctrl_activate(struct v4l2_ctrl *ctrl, bool active)
+{
+ if (ctrl == NULL)
+ return;
+
+ if (!active)
+ /* set V4L2_CTRL_FLAG_INACTIVE */
+ set_bit(4, &ctrl->flags);
+ else
+ /* clear V4L2_CTRL_FLAG_INACTIVE */
+ clear_bit(4, &ctrl->flags);
+}
+EXPORT_SYMBOL(v4l2_ctrl_activate);
+
+/* Grab/ungrab a control.
+ Typically used when streaming starts and you want to grab controls,
+ preventing the user from changing them.
+
+ Just call this and the framework will block any attempts to change
+ these controls. */
+void v4l2_ctrl_grab(struct v4l2_ctrl *ctrl, bool grabbed)
+{
+ if (ctrl == NULL)
+ return;
+
+ if (grabbed)
+ /* set V4L2_CTRL_FLAG_GRABBED */
+ set_bit(1, &ctrl->flags);
+ else
+ /* clear V4L2_CTRL_FLAG_GRABBED */
+ clear_bit(1, &ctrl->flags);
+}
+EXPORT_SYMBOL(v4l2_ctrl_grab);
+
+/* Log the control name and value */
+static void log_ctrl(const struct v4l2_ctrl *ctrl,
+ const char *prefix, const char *colon)
+{
+ int fl_inact = ctrl->flags & V4L2_CTRL_FLAG_INACTIVE;
+ int fl_grabbed = ctrl->flags & V4L2_CTRL_FLAG_GRABBED;
+
+ if (ctrl->flags & (V4L2_CTRL_FLAG_DISABLED | V4L2_CTRL_FLAG_WRITE_ONLY))
+ return;
+ if (ctrl->type == V4L2_CTRL_TYPE_CTRL_CLASS)
+ return;
+
+ printk(KERN_INFO "%s%s%s: ", prefix, colon, ctrl->name);
+
+ switch (ctrl->type) {
+ case V4L2_CTRL_TYPE_INTEGER:
+ printk(KERN_CONT "%d", ctrl->cur.val);
+ break;
+ case V4L2_CTRL_TYPE_BOOLEAN:
+ printk(KERN_CONT "%s", ctrl->cur.val ? "true" : "false");
+ break;
+ case V4L2_CTRL_TYPE_MENU:
+ printk(KERN_CONT "%s", ctrl->qmenu[ctrl->cur.val]);
+ break;
+ case V4L2_CTRL_TYPE_INTEGER64:
+ printk(KERN_CONT "%lld", ctrl->cur.val64);
+ break;
+ case V4L2_CTRL_TYPE_STRING:
+ printk(KERN_CONT "%s", ctrl->cur.string);
+ break;
+ default:
+ printk(KERN_CONT "unknown type %d", ctrl->type);
+ break;
+ }
+ if (fl_inact && fl_grabbed)
+ printk(KERN_CONT " (inactive, grabbed)\n");
+ else if (fl_inact)
+ printk(KERN_CONT " (inactive)\n");
+ else if (fl_grabbed)
+ printk(KERN_CONT " (grabbed)\n");
+ else
+ printk(KERN_CONT "\n");
+}
+
+/* Log all controls owned by the handler */
+void v4l2_ctrl_handler_log_status(struct v4l2_ctrl_handler *hdl,
+ const char *prefix)
+{
+ struct v4l2_ctrl *ctrl;
+ const char *colon = "";
+ int len;
+
+ if (hdl == NULL)
+ return;
+ if (prefix == NULL)
+ prefix = "";
+ len = strlen(prefix);
+ if (len && prefix[len - 1] != ' ')
+ colon = ": ";
+ mutex_lock(&hdl->lock);
+ list_for_each_entry(ctrl, &hdl->ctrls, node)
+ if (!(ctrl->flags & V4L2_CTRL_FLAG_DISABLED))
+ log_ctrl(ctrl, prefix, colon);
+ mutex_unlock(&hdl->lock);
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_log_status);
+
+/* Call s_ctrl for all controls owned by the handler */
+int v4l2_ctrl_handler_setup(struct v4l2_ctrl_handler *hdl)
+{
+ struct v4l2_ctrl *ctrl;
+ int ret = 0;
+
+ if (hdl == NULL)
+ return 0;
+ mutex_lock(&hdl->lock);
+ list_for_each_entry(ctrl, &hdl->ctrls, node)
+ ctrl->done = false;
+
+ list_for_each_entry(ctrl, &hdl->ctrls, node) {
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int i;
+
+ /* Skip if this control was already handled by a cluster. */
+ if (ctrl->done)
+ continue;
+
+ for (i = 0; i < master->ncontrols; i++) {
+ if (master->cluster[i]) {
+ cur_to_new(master->cluster[i]);
+ master->cluster[i]->is_new = 1;
+ }
+ }
+
+ /* Skip button controls and read-only controls. */
+ if (ctrl->type == V4L2_CTRL_TYPE_BUTTON ||
+ (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY))
+ continue;
+ ret = master->ops->s_ctrl(master);
+ if (ret)
+ break;
+ for (i = 0; i < master->ncontrols; i++)
+ if (master->cluster[i])
+ master->cluster[i]->done = true;
+ }
+ mutex_unlock(&hdl->lock);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_ctrl_handler_setup);
+
+/* Implement VIDIOC_QUERYCTRL */
+int v4l2_queryctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_queryctrl *qc)
+{
+ u32 id = qc->id & V4L2_CTRL_ID_MASK;
+ struct v4l2_ctrl_ref *ref;
+ struct v4l2_ctrl *ctrl;
+
+ if (hdl == NULL)
+ return -EINVAL;
+
+ mutex_lock(&hdl->lock);
+
+ /* Try to find it */
+ ref = find_ref(hdl, id);
+
+ if ((qc->id & V4L2_CTRL_FLAG_NEXT_CTRL) && !list_empty(&hdl->ctrl_refs)) {
+ /* Find the next control with ID > qc->id */
+
+ /* Did we reach the end of the control list? */
+ if (id >= node2id(hdl->ctrl_refs.prev)) {
+ ref = NULL; /* Yes, so there is no next control */
+ } else if (ref) {
+ /* We found a control with the given ID, so just get
+ the next one in the list. */
+ ref = list_entry(ref->node.next, typeof(*ref), node);
+ } else {
+ /* No control with the given ID exists, so start
+ searching for the next largest ID. We know there
+ is one, otherwise the first 'if' above would have
+ been true. */
+ list_for_each_entry(ref, &hdl->ctrl_refs, node)
+ if (id < ref->ctrl->id)
+ break;
+ }
+ }
+ mutex_unlock(&hdl->lock);
+ if (!ref)
+ return -EINVAL;
+
+ ctrl = ref->ctrl;
+ memset(qc, 0, sizeof(*qc));
+ if (id >= V4L2_CID_PRIVATE_BASE)
+ qc->id = id;
+ else
+ qc->id = ctrl->id;
+ strlcpy(qc->name, ctrl->name, sizeof(qc->name));
+ qc->minimum = ctrl->minimum;
+ qc->maximum = ctrl->maximum;
+ qc->default_value = ctrl->default_value;
+ if (ctrl->type == V4L2_CTRL_TYPE_MENU)
+ qc->step = 1;
+ else
+ qc->step = ctrl->step;
+ qc->flags = ctrl->flags;
+ qc->type = ctrl->type;
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_queryctrl);
+
+int v4l2_subdev_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
+{
+ return v4l2_queryctrl(sd->ctrl_handler, qc);
+}
+EXPORT_SYMBOL(v4l2_subdev_queryctrl);
+
+/* Implement VIDIOC_QUERYMENU */
+int v4l2_querymenu(struct v4l2_ctrl_handler *hdl, struct v4l2_querymenu *qm)
+{
+ struct v4l2_ctrl *ctrl;
+ u32 i = qm->index;
+
+ ctrl = v4l2_ctrl_find(hdl, qm->id);
+ if (!ctrl)
+ return -EINVAL;
+
+ qm->reserved = 0;
+ /* Sanity checks */
+ if (ctrl->qmenu == NULL ||
+ i < ctrl->minimum || i > ctrl->maximum)
+ return -EINVAL;
+ /* Use mask to see if this menu item should be skipped */
+ if (ctrl->menu_skip_mask & (1 << i))
+ return -EINVAL;
+ /* Empty menu items should also be skipped */
+ if (ctrl->qmenu[i] == NULL || ctrl->qmenu[i][0] == '\0')
+ return -EINVAL;
+ strlcpy(qm->name, ctrl->qmenu[i], sizeof(qm->name));
+ return 0;
+}
+EXPORT_SYMBOL(v4l2_querymenu);
+
+int v4l2_subdev_querymenu(struct v4l2_subdev *sd, struct v4l2_querymenu *qm)
+{
+ return v4l2_querymenu(sd->ctrl_handler, qm);
+}
+EXPORT_SYMBOL(v4l2_subdev_querymenu);
+
+
+
+/* Some general notes on the atomic requirements of VIDIOC_G/TRY/S_EXT_CTRLS:
+
+ It is not a fully atomic operation, just best-effort only. After all, if
+ multiple controls have to be set through multiple i2c writes (for example)
+ then some initial writes may succeed while others fail. Thus leaving the
+ system in an inconsistent state. The question is how much effort you are
+ willing to spend on trying to make something atomic that really isn't.
+
+ From the point of view of an application the main requirement is that
+ when you call VIDIOC_S_EXT_CTRLS and some values are invalid then an
+ error should be returned without actually affecting any controls.
+
+ If all the values are correct, then it is acceptable to just give up
+ in case of low-level errors.
+
+ It is important though that the application can tell when only a partial
+ configuration was done. The way we do that is through the error_idx field
+ of struct v4l2_ext_controls: if that is equal to the count field then no
+ controls were affected. Otherwise all controls before that index were
+ successful in performing their 'get' or 'set' operation, the control at
+ the given index failed, and you don't know what happened with the controls
+ after the failed one. Since if they were part of a control cluster they
+ could have been successfully processed (if a cluster member was encountered
+ at index < error_idx), they could have failed (if a cluster member was at
+ error_idx), or they may not have been processed yet (if the first cluster
+ member appeared after error_idx).
+
+ It is all fairly theoretical, though. In practice all you can do is to
+ bail out. If error_idx == count, then it is an application bug. If
+ error_idx < count then it is only an application bug if the error code was
+ EBUSY. That usually means that something started streaming just when you
+ tried to set the controls. In all other cases it is a driver/hardware
+ problem and all you can do is to retry or bail out.
+
+ Note that these rules do not apply to VIDIOC_TRY_EXT_CTRLS: since that
+ never modifies controls the error_idx is just set to whatever control
+ has an invalid value.
+ */
+
+/* Prepare for the extended g/s/try functions.
+ Find the controls in the control array and do some basic checks. */
+static int prepare_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct ctrl_helper *helpers,
+ bool try)
+{
+ u32 i;
+
+ for (i = 0; i < cs->count; i++) {
+ struct v4l2_ext_control *c = &cs->controls[i];
+ struct v4l2_ctrl *ctrl;
+ u32 id = c->id & V4L2_CTRL_ID_MASK;
+
+ if (try)
+ cs->error_idx = i;
+
+ if (cs->ctrl_class && V4L2_CTRL_ID2CLASS(id) != cs->ctrl_class)
+ return -EINVAL;
+
+ /* Old-style private controls are not allowed for
+ extended controls */
+ if (id >= V4L2_CID_PRIVATE_BASE)
+ return -EINVAL;
+ ctrl = v4l2_ctrl_find(hdl, id);
+ if (ctrl == NULL)
+ return -EINVAL;
+ if (ctrl->flags & V4L2_CTRL_FLAG_DISABLED)
+ return -EINVAL;
+
+ helpers[i].ctrl = ctrl;
+ helpers[i].handled = false;
+ }
+ return 0;
+}
+
+typedef int (*cluster_func)(struct v4l2_ext_control *c,
+ struct v4l2_ctrl *ctrl);
+
+/* Walk over all controls in v4l2_ext_controls belonging to the same cluster
+ and call the provided function. */
+static int cluster_walk(unsigned from,
+ struct v4l2_ext_controls *cs,
+ struct ctrl_helper *helpers,
+ cluster_func f)
+{
+ struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster;
+ int ret = 0;
+ int i;
+
+ /* Find any controls from the same cluster and call the function */
+ for (i = from; !ret && i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+
+ if (!helpers[i].handled && ctrl->cluster == cluster)
+ ret = f(&cs->controls[i], ctrl);
+ }
+ return ret;
+}
+
+static void cluster_done(unsigned from,
+ struct v4l2_ext_controls *cs,
+ struct ctrl_helper *helpers)
+{
+ struct v4l2_ctrl **cluster = helpers[from].ctrl->cluster;
+ int i;
+
+ /* Find any controls from the same cluster and mark them as handled */
+ for (i = from; i < cs->count; i++)
+ if (helpers[i].ctrl->cluster == cluster)
+ helpers[i].handled = true;
+}
+
+/* Handles the corner case where cs->count == 0. It checks whether the
+ specified control class exists. If that class ID is 0, then it checks
+ whether there are any controls at all. */
+static int class_check(struct v4l2_ctrl_handler *hdl, u32 ctrl_class)
+{
+ if (ctrl_class == 0)
+ return list_empty(&hdl->ctrl_refs) ? -EINVAL : 0;
+ return find_ref_lock(hdl, ctrl_class | 1) ? 0 : -EINVAL;
+}
+
+
+
+/* Get extended controls. Allocates the helpers array if needed. */
+int v4l2_g_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+{
+ struct ctrl_helper helper[4];
+ struct ctrl_helper *helpers = helper;
+ int ret;
+ int i;
+
+ cs->error_idx = cs->count;
+ cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+
+ if (hdl == NULL)
+ return -EINVAL;
+
+ if (cs->count == 0)
+ return class_check(hdl, cs->ctrl_class);
+
+ if (cs->count > ARRAY_SIZE(helper)) {
+ helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+ if (helpers == NULL)
+ return -ENOMEM;
+ }
+
+ ret = prepare_ext_ctrls(hdl, cs, helpers, false);
+
+ for (i = 0; !ret && i < cs->count; i++)
+ if (helpers[i].ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+ ret = -EACCES;
+
+ for (i = 0; !ret && i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+
+ if (helpers[i].handled)
+ continue;
+
+ cs->error_idx = i;
+
+ v4l2_ctrl_lock(master);
+ /* g_volatile_ctrl will update the current control values */
+ if (ctrl->is_volatile && master->ops->g_volatile_ctrl)
+ ret = master->ops->g_volatile_ctrl(master);
+ /* If OK, then copy the current control values to the caller */
+ if (!ret)
+ ret = cluster_walk(i, cs, helpers, cur_to_user);
+ v4l2_ctrl_unlock(master);
+ cluster_done(i, cs, helpers);
+ }
+
+ if (cs->count > ARRAY_SIZE(helper))
+ kfree(helpers);
+ return ret;
+}
+EXPORT_SYMBOL(v4l2_g_ext_ctrls);
+
+int v4l2_subdev_g_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
+{
+ return v4l2_g_ext_ctrls(sd->ctrl_handler, cs);
+}
+EXPORT_SYMBOL(v4l2_subdev_g_ext_ctrls);
+
+/* Helper function to get a single control */
+static int get_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
+{
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int ret = 0;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_WRITE_ONLY)
+ return -EACCES;
+
+ v4l2_ctrl_lock(master);
+ /* g_volatile_ctrl will update the current control values */
+ if (ctrl->is_volatile && master->ops->g_volatile_ctrl)
+ ret = master->ops->g_volatile_ctrl(master);
+ *val = ctrl->cur.val;
+ v4l2_ctrl_unlock(master);
+ return ret;
+}
+
+int v4l2_g_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+
+ if (ctrl == NULL || !type_is_int(ctrl))
+ return -EINVAL;
+ return get_ctrl(ctrl, &control->value);
+}
+EXPORT_SYMBOL(v4l2_g_ctrl);
+
+int v4l2_subdev_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control)
+{
+ return v4l2_g_ctrl(sd->ctrl_handler, control);
+}
+EXPORT_SYMBOL(v4l2_subdev_g_ctrl);
+
+s32 v4l2_ctrl_g_ctrl(struct v4l2_ctrl *ctrl)
+{
+ s32 val = 0;
+
+ /* It's a driver bug if this happens. */
+ WARN_ON(!type_is_int(ctrl));
+ get_ctrl(ctrl, &val);
+ return val;
+}
+EXPORT_SYMBOL(v4l2_ctrl_g_ctrl);
+
+
+/* Core function that calls try/s_ctrl and ensures that the new value is
+ copied to the current value on a set.
+ Must be called with ctrl->handler->lock held. */
+static int try_or_set_control_cluster(struct v4l2_ctrl *master, bool set)
+{
+ bool try = !set;
+ int ret = 0;
+ int i;
+
+ /* Go through the cluster and either validate the new value or
+ (if no new value was set), copy the current value to the new
+ value, ensuring a consistent view for the control ops when
+ called. */
+ for (i = 0; !ret && i < master->ncontrols; i++) {
+ struct v4l2_ctrl *ctrl = master->cluster[i];
+
+ if (ctrl == NULL)
+ continue;
+
+ if (ctrl->is_new) {
+ /* Double check this: it may have changed since the
+ last check in try_or_set_ext_ctrls(). */
+ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+ return -EBUSY;
+
+ /* Validate if required */
+ if (!set)
+ ret = validate_new(ctrl);
+ continue;
+ }
+ /* No new value was set, so copy the current and force
+ a call to try_ctrl later, since the values for the cluster
+ may now have changed and the end result might be invalid. */
+ try = true;
+ cur_to_new(ctrl);
+ }
+
+ /* For larger clusters you have to call try_ctrl again to
+ verify that the controls are still valid after the
+ 'cur_to_new' above. */
+ if (!ret && master->ops->try_ctrl && try)
+ ret = master->ops->try_ctrl(master);
+
+ /* Don't set if there is no change */
+ if (!ret && set && cluster_changed(master)) {
+ ret = master->ops->s_ctrl(master);
+ /* If OK, then make the new values permanent. */
+ if (!ret)
+ for (i = 0; i < master->ncontrols; i++)
+ new_to_cur(master->cluster[i]);
+ }
+ return ret;
+}
+
+/* Try or set controls. */
+static int try_or_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ struct ctrl_helper *helpers,
+ bool set)
+{
+ unsigned i, j;
+ int ret = 0;
+
+ cs->error_idx = cs->count;
+ for (i = 0; i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+
+ if (!set)
+ cs->error_idx = i;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+ return -EACCES;
+ /* This test is also done in try_set_control_cluster() which
+ is called in atomic context, so that has the final say,
+ but it makes sense to do an up-front check as well. Once
+ an error occurs in try_set_control_cluster() some other
+ controls may have been set already and we want to do a
+ best-effort to avoid that. */
+ if (set && (ctrl->flags & V4L2_CTRL_FLAG_GRABBED))
+ return -EBUSY;
+ }
+
+ for (i = 0; !ret && i < cs->count; i++) {
+ struct v4l2_ctrl *ctrl = helpers[i].ctrl;
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+
+ cs->error_idx = i;
+
+ if (helpers[i].handled)
+ continue;
+
+ v4l2_ctrl_lock(ctrl);
+
+ /* Reset the 'is_new' flags of the cluster */
+ for (j = 0; j < master->ncontrols; j++)
+ if (master->cluster[j])
+ master->cluster[j]->is_new = 0;
+
+ /* Copy the new caller-supplied control values.
+ user_to_new() sets 'is_new' to 1. */
+ ret = cluster_walk(i, cs, helpers, user_to_new);
+
+ if (!ret)
+ ret = try_or_set_control_cluster(master, set);
+
+ /* Copy the new values back to userspace. */
+ if (!ret)
+ ret = cluster_walk(i, cs, helpers, new_to_user);
+
+ v4l2_ctrl_unlock(ctrl);
+ cluster_done(i, cs, helpers);
+ }
+ return ret;
+}
+
+/* Try or try-and-set controls */
+static int try_set_ext_ctrls(struct v4l2_ctrl_handler *hdl,
+ struct v4l2_ext_controls *cs,
+ bool set)
+{
+ struct ctrl_helper helper[4];
+ struct ctrl_helper *helpers = helper;
+ int ret;
+ int i;
+
+ cs->error_idx = cs->count;
+ cs->ctrl_class = V4L2_CTRL_ID2CLASS(cs->ctrl_class);
+
+ if (hdl == NULL)
+ return -EINVAL;
+
+ if (cs->count == 0)
+ return class_check(hdl, cs->ctrl_class);
+
+ if (cs->count > ARRAY_SIZE(helper)) {
+ helpers = kmalloc(sizeof(helper[0]) * cs->count, GFP_KERNEL);
+ if (!helpers)
+ return -ENOMEM;
+ }
+ ret = prepare_ext_ctrls(hdl, cs, helpers, !set);
+ if (ret)
+ goto free;
+
+ /* First 'try' all controls and abort on error */
+ ret = try_or_set_ext_ctrls(hdl, cs, helpers, false);
+ /* If this is a 'set' operation and the initial 'try' failed,
+ then set error_idx to count to tell the application that no
+ controls changed value yet. */
+ if (set)
+ cs->error_idx = cs->count;
+ if (!ret && set) {
+ /* Reset 'handled' state */
+ for (i = 0; i < cs->count; i++)
+ helpers[i].handled = false;
+ ret = try_or_set_ext_ctrls(hdl, cs, helpers, true);
+ }
+
+free:
+ if (cs->count > ARRAY_SIZE(helper))
+ kfree(helpers);
+ return ret;
+}
+
+int v4l2_try_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(hdl, cs, false);
+}
+EXPORT_SYMBOL(v4l2_try_ext_ctrls);
+
+int v4l2_s_ext_ctrls(struct v4l2_ctrl_handler *hdl, struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(hdl, cs, true);
+}
+EXPORT_SYMBOL(v4l2_s_ext_ctrls);
+
+int v4l2_subdev_try_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(sd->ctrl_handler, cs, false);
+}
+EXPORT_SYMBOL(v4l2_subdev_try_ext_ctrls);
+
+int v4l2_subdev_s_ext_ctrls(struct v4l2_subdev *sd, struct v4l2_ext_controls *cs)
+{
+ return try_set_ext_ctrls(sd->ctrl_handler, cs, true);
+}
+EXPORT_SYMBOL(v4l2_subdev_s_ext_ctrls);
+
+/* Helper function for VIDIOC_S_CTRL compatibility */
+static int set_ctrl(struct v4l2_ctrl *ctrl, s32 *val)
+{
+ struct v4l2_ctrl *master = ctrl->cluster[0];
+ int ret;
+ int i;
+
+ if (ctrl->flags & V4L2_CTRL_FLAG_READ_ONLY)
+ return -EACCES;
+
+ v4l2_ctrl_lock(ctrl);
+
+ /* Reset the 'is_new' flags of the cluster */
+ for (i = 0; i < master->ncontrols; i++)
+ if (master->cluster[i])
+ master->cluster[i]->is_new = 0;
+
+ ctrl->val = *val;
+ ctrl->is_new = 1;
+ ret = try_or_set_control_cluster(master, false);
+ if (!ret)
+ ret = try_or_set_control_cluster(master, true);
+ *val = ctrl->cur.val;
+ v4l2_ctrl_unlock(ctrl);
+ return ret;
+}
+
+int v4l2_s_ctrl(struct v4l2_ctrl_handler *hdl, struct v4l2_control *control)
+{
+ struct v4l2_ctrl *ctrl = v4l2_ctrl_find(hdl, control->id);
+
+ if (ctrl == NULL || !type_is_int(ctrl))
+ return -EINVAL;
+
+ return set_ctrl(ctrl, &control->value);
+}
+EXPORT_SYMBOL(v4l2_s_ctrl);
+
+int v4l2_subdev_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *control)
+{
+ return v4l2_s_ctrl(sd->ctrl_handler, control);
+}
+EXPORT_SYMBOL(v4l2_subdev_s_ctrl);
+
+int v4l2_ctrl_s_ctrl(struct v4l2_ctrl *ctrl, s32 val)
+{
+ /* It's a driver bug if this happens. */
+ WARN_ON(!type_is_int(ctrl));
+ return set_ctrl(ctrl, &val);
+}
+EXPORT_SYMBOL(v4l2_ctrl_s_ctrl);
diff --git a/drivers/media/video/v4l2-dev.c b/drivers/media/video/v4l2-dev.c
index 0ca7ec9ca902..341764a3a990 100644
--- a/drivers/media/video/v4l2-dev.c
+++ b/drivers/media/video/v4l2-dev.c
@@ -80,7 +80,7 @@ static inline unsigned long *devnode_bits(int vfl_type)
/* Any types not assigned to fixed minor ranges must be mapped to
one single bitmap for the purposes of finding a free node number
since all those unassigned types use the same minor range. */
- int idx = (vfl_type > VFL_TYPE_VTX) ? VFL_TYPE_MAX - 1 : vfl_type;
+ int idx = (vfl_type > VFL_TYPE_RADIO) ? VFL_TYPE_MAX - 1 : vfl_type;
return devnode_nums[idx];
}
@@ -186,83 +186,117 @@ static ssize_t v4l2_read(struct file *filp, char __user *buf,
size_t sz, loff_t *off)
{
struct video_device *vdev = video_devdata(filp);
+ int ret = -ENODEV;
if (!vdev->fops->read)
return -EINVAL;
- if (!video_is_registered(vdev))
- return -EIO;
- return vdev->fops->read(filp, buf, sz, off);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->read(filp, buf, sz, off);
+ if (vdev->lock)
+ mutex_unlock(vdev->lock);
+ return ret;
}
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);
+ int ret = -ENODEV;
if (!vdev->fops->write)
return -EINVAL;
- if (!video_is_registered(vdev))
- return -EIO;
- return vdev->fops->write(filp, buf, sz, off);
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->write(filp, buf, sz, off);
+ if (vdev->lock)
+ mutex_unlock(vdev->lock);
+ return ret;
}
static unsigned int v4l2_poll(struct file *filp, struct poll_table_struct *poll)
{
struct video_device *vdev = video_devdata(filp);
+ int ret = POLLERR | POLLHUP;
- if (!vdev->fops->poll || !video_is_registered(vdev))
+ if (!vdev->fops->poll)
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);
+ if (vdev->lock)
+ mutex_lock(vdev->lock);
+ if (video_is_registered(vdev))
+ ret = vdev->fops->poll(filp, poll);
+ if (vdev->lock)
+ mutex_unlock(vdev->lock);
+ return ret;
}
-#ifdef CONFIG_MMU
-#define v4l2_get_unmapped_area NULL
-#else
-static unsigned long v4l2_get_unmapped_area(struct file *filp,
- unsigned long addr, unsigned long len, unsigned long pgoff,
- unsigned long flags)
+static long v4l2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
{
struct video_device *vdev = video_devdata(filp);
+ int ret = -ENODEV;
+
+ if (vdev->fops->unlocked_ioctl) {
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->unlocked_ioctl(filp, cmd, arg);
+ if (vdev->lock)
+ mutex_unlock(vdev->lock);
+ } else if (vdev->fops->ioctl) {
+ /* This code path is a replacement for the BKL. It is a major
+ * hack but it will have to do for those drivers that are not
+ * yet converted to use unlocked_ioctl.
+ *
+ * There are two options: if the driver implements struct
+ * v4l2_device, then the lock defined there is used to
+ * serialize the ioctls. Otherwise the v4l2 core lock defined
+ * below is used. This lock is really bad since it serializes
+ * completely independent devices.
+ *
+ * Both variants suffer from the same problem: if the driver
+ * sleeps, then it blocks all ioctls since the lock is still
+ * held. This is very common for VIDIOC_DQBUF since that
+ * normally waits for a frame to arrive. As a result any other
+ * ioctl calls will proceed very, very slowly since each call
+ * will have to wait for the VIDIOC_QBUF to finish. Things that
+ * should take 0.01s may now take 10-20 seconds.
+ *
+ * The workaround is to *not* take the lock for VIDIOC_DQBUF.
+ * This actually works OK for videobuf-based drivers, since
+ * videobuf will take its own internal lock.
+ */
+ static DEFINE_MUTEX(v4l2_ioctl_mutex);
+ struct mutex *m = vdev->v4l2_dev ?
+ &vdev->v4l2_dev->ioctl_lock : &v4l2_ioctl_mutex;
+
+ if (cmd != VIDIOC_DQBUF && mutex_lock_interruptible(m))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->ioctl(filp, cmd, arg);
+ if (cmd != VIDIOC_DQBUF)
+ mutex_unlock(m);
+ } else
+ ret = -ENOTTY;
- if (!vdev->fops->get_unmapped_area)
- return -ENOSYS;
- if (!video_is_registered(vdev))
- return -ENODEV;
- return vdev->fops->get_unmapped_area(filp, addr, len, pgoff, flags);
+ return ret;
}
-#endif
static int v4l2_mmap(struct file *filp, struct vm_area_struct *vm)
{
struct video_device *vdev = video_devdata(filp);
+ int ret = -ENODEV;
- if (!vdev->fops->mmap || !video_is_registered(vdev))
- return -ENODEV;
- return vdev->fops->mmap(filp, vm);
+ if (!vdev->fops->mmap)
+ return ret;
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock))
+ return -ERESTARTSYS;
+ if (video_is_registered(vdev))
+ ret = vdev->fops->mmap(filp, vm);
+ if (vdev->lock)
+ mutex_unlock(vdev->lock);
+ return ret;
}
/* Override for the open function */
@@ -274,8 +308,7 @@ static int v4l2_open(struct inode *inode, struct file *filp)
/* 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. */
+ /* return ENODEV if the video device has already been removed. */
if (vdev == NULL || !video_is_registered(vdev)) {
mutex_unlock(&videodev_lock);
return -ENODEV;
@@ -283,9 +316,20 @@ static int v4l2_open(struct inode *inode, struct file *filp)
/* and increase the device refcount */
video_get(vdev);
mutex_unlock(&videodev_lock);
- if (vdev->fops->open)
- ret = vdev->fops->open(filp);
+ if (vdev->fops->open) {
+ if (vdev->lock && mutex_lock_interruptible(vdev->lock)) {
+ ret = -ERESTARTSYS;
+ goto err;
+ }
+ if (video_is_registered(vdev))
+ ret = vdev->fops->open(filp);
+ else
+ ret = -ENODEV;
+ if (vdev->lock)
+ mutex_unlock(vdev->lock);
+ }
+err:
/* decrease the refcount in case of an error */
if (ret)
video_put(vdev);
@@ -298,8 +342,13 @@ static int v4l2_release(struct inode *inode, struct file *filp)
struct video_device *vdev = video_devdata(filp);
int ret = 0;
- if (vdev->fops->release)
+ if (vdev->fops->release) {
+ if (vdev->lock)
+ mutex_lock(vdev->lock);
vdev->fops->release(filp);
+ if (vdev->lock)
+ mutex_unlock(vdev->lock);
+ }
/* decrease the refcount unconditionally since the release()
return value is ignored. */
@@ -307,30 +356,13 @@ static int v4l2_release(struct inode *inode, struct file *filp)
return ret;
}
-static const struct file_operations v4l2_unlocked_fops = {
- .owner = THIS_MODULE,
- .read = v4l2_read,
- .write = v4l2_write,
- .open = v4l2_open,
- .get_unmapped_area = v4l2_get_unmapped_area,
- .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,
- .get_unmapped_area = v4l2_get_unmapped_area,
.mmap = v4l2_mmap,
- .ioctl = v4l2_ioctl,
+ .unlocked_ioctl = v4l2_ioctl,
#ifdef CONFIG_COMPAT
.compat_ioctl = v4l2_compat_ioctl32,
#endif
@@ -387,6 +419,10 @@ static int get_index(struct video_device *vdev)
* The registration code assigns minor numbers and device node numbers
* based on the requested type and registers the new device node with
* the kernel.
+ *
+ * This function assumes that struct video_device was zeroed when it
+ * was allocated and does not contain any stale date.
+ *
* An error is returned if no free minor or device node number could be
* found, or if the registration of the device node failed.
*
@@ -396,8 +432,6 @@ static int get_index(struct video_device *vdev)
*
* %VFL_TYPE_GRABBER - A frame grabber
*
- * %VFL_TYPE_VTX - A teletext device
- *
* %VFL_TYPE_VBI - Vertical blank data (undecoded)
*
* %VFL_TYPE_RADIO - A radio card
@@ -410,7 +444,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
int minor_offset = 0;
int minor_cnt = VIDEO_NUM_DEVICES;
const char *name_base;
- void *priv = video_get_drvdata(vdev);
/* A minor value of -1 marks this video device as never
having been registered */
@@ -430,9 +463,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
case VFL_TYPE_GRABBER:
name_base = "video";
break;
- case VFL_TYPE_VTX:
- name_base = "vtx";
- break;
case VFL_TYPE_VBI:
name_base = "vbi";
break;
@@ -447,8 +477,12 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
vdev->vfl_type = type;
vdev->cdev = NULL;
- if (vdev->v4l2_dev && vdev->v4l2_dev->dev)
- vdev->parent = vdev->v4l2_dev->dev;
+ if (vdev->v4l2_dev) {
+ if (vdev->v4l2_dev->dev)
+ vdev->parent = vdev->v4l2_dev->dev;
+ if (vdev->ctrl_handler == NULL)
+ vdev->ctrl_handler = vdev->v4l2_dev->ctrl_handler;
+ }
/* Part 2: find a free minor, device node number and device index. */
#ifdef CONFIG_VIDEO_FIXED_MINOR_RANGES
@@ -466,10 +500,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
minor_offset = 64;
minor_cnt = 64;
break;
- case VFL_TYPE_VTX:
- minor_offset = 192;
- minor_cnt = 32;
- break;
case VFL_TYPE_VBI:
minor_offset = 224;
minor_cnt = 32;
@@ -521,10 +551,7 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
ret = -ENOMEM;
goto cleanup;
}
- if (vdev->fops->unlocked_ioctl)
- vdev->cdev->ops = &v4l2_unlocked_fops;
- else
- vdev->cdev->ops = &v4l2_fops;
+ vdev->cdev->ops = &v4l2_fops;
vdev->cdev->owner = vdev->fops->owner;
ret = cdev_add(vdev->cdev, MKDEV(VIDEO_MAJOR, vdev->minor), 1);
if (ret < 0) {
@@ -535,10 +562,6 @@ static int __video_register_device(struct video_device *vdev, int type, int nr,
}
/* 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(vdev, priv);
vdev->dev.class = &video_class;
vdev->dev.devt = MKDEV(VIDEO_MAJOR, vdev->minor);
if (vdev->parent)
@@ -600,7 +623,12 @@ void video_unregister_device(struct video_device *vdev)
if (!vdev || !video_is_registered(vdev))
return;
+ mutex_lock(&videodev_lock);
+ /* This must be in a critical section to prevent a race with v4l2_open.
+ * Once this bit has been cleared video_get may never be called again.
+ */
clear_bit(V4L2_FL_REGISTERED, &vdev->flags);
+ mutex_unlock(&videodev_lock);
device_unregister(&vdev->dev);
}
EXPORT_SYMBOL(video_unregister_device);
diff --git a/drivers/media/video/v4l2-device.c b/drivers/media/video/v4l2-device.c
index 5a7dc4afe92a..ce64fe16bc60 100644
--- a/drivers/media/video/v4l2-device.c
+++ b/drivers/media/video/v4l2-device.c
@@ -26,6 +26,7 @@
#endif
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
+#include <media/v4l2-ctrls.h>
int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
{
@@ -34,6 +35,7 @@ int v4l2_device_register(struct device *dev, struct v4l2_device *v4l2_dev)
INIT_LIST_HEAD(&v4l2_dev->subdevs);
spin_lock_init(&v4l2_dev->lock);
+ mutex_init(&v4l2_dev->ioctl_lock);
v4l2_dev->dev = dev;
if (dev == NULL) {
/* If dev == NULL, then name must be filled in by the caller */
@@ -98,6 +100,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
is a platform bus, then it is never deleted. */
if (client)
i2c_unregister_device(client);
+ continue;
}
#endif
#if defined(CONFIG_SPI)
@@ -106,6 +109,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
if (spi)
spi_unregister_device(spi);
+ continue;
}
#endif
}
@@ -115,6 +119,8 @@ EXPORT_SYMBOL_GPL(v4l2_device_unregister);
int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
struct v4l2_subdev *sd)
{
+ int err;
+
/* Check for valid input */
if (v4l2_dev == NULL || sd == NULL || !sd->name[0])
return -EINVAL;
@@ -123,6 +129,18 @@ int v4l2_device_register_subdev(struct v4l2_device *v4l2_dev,
if (!try_module_get(sd->owner))
return -ENODEV;
sd->v4l2_dev = v4l2_dev;
+ if (sd->internal_ops && sd->internal_ops->registered) {
+ err = sd->internal_ops->registered(sd);
+ if (err)
+ return err;
+ }
+ /* This just returns 0 if either of the two args is NULL */
+ err = v4l2_ctrl_add_handler(v4l2_dev->ctrl_handler, sd->ctrl_handler);
+ if (err) {
+ if (sd->internal_ops && sd->internal_ops->unregistered)
+ sd->internal_ops->unregistered(sd);
+ return err;
+ }
spin_lock(&v4l2_dev->lock);
list_add_tail(&sd->list, &v4l2_dev->subdevs);
spin_unlock(&v4l2_dev->lock);
@@ -138,6 +156,8 @@ void v4l2_device_unregister_subdev(struct v4l2_subdev *sd)
spin_lock(&sd->v4l2_dev->lock);
list_del(&sd->list);
spin_unlock(&sd->v4l2_dev->lock);
+ if (sd->internal_ops && sd->internal_ops->unregistered)
+ sd->internal_ops->unregistered(sd);
sd->v4l2_dev = NULL;
module_put(sd->owner);
}
diff --git a/drivers/media/video/v4l2-event.c b/drivers/media/video/v4l2-event.c
index de74ce07b5e2..69fd343d4774 100644
--- a/drivers/media/video/v4l2-event.c
+++ b/drivers/media/video/v4l2-event.c
@@ -134,15 +134,22 @@ int v4l2_event_dequeue(struct v4l2_fh *fh, struct v4l2_event *event,
if (nonblocking)
return __v4l2_event_dequeue(fh, event);
+ /* Release the vdev lock while waiting */
+ if (fh->vdev->lock)
+ mutex_unlock(fh->vdev->lock);
+
do {
ret = wait_event_interruptible(events->wait,
events->navailable != 0);
if (ret < 0)
- return ret;
+ break;
ret = __v4l2_event_dequeue(fh, event);
} while (ret == -ENOENT);
+ if (fh->vdev->lock)
+ mutex_lock(fh->vdev->lock);
+
return ret;
}
EXPORT_SYMBOL_GPL(v4l2_event_dequeue);
diff --git a/drivers/media/video/v4l2-ioctl.c b/drivers/media/video/v4l2-ioctl.c
index 0eeceae50329..f51327ef6757 100644
--- a/drivers/media/video/v4l2-ioctl.c
+++ b/drivers/media/video/v4l2-ioctl.c
@@ -18,14 +18,11 @@
#include <linux/kernel.h>
#define __OLD_VIDIOC_ /* To allow fixing old calls */
-#include <linux/videodev.h>
#include <linux/videodev2.h>
-#ifdef CONFIG_VIDEO_V4L1
-#include <linux/videodev.h>
-#endif
#include <media/v4l2-common.h>
#include <media/v4l2-ioctl.h>
+#include <media/v4l2-ctrls.h>
#include <media/v4l2-fh.h>
#include <media/v4l2-event.h>
#include <media/v4l2-chip-ident.h>
@@ -182,42 +179,6 @@ static const char *v4l2_memory_names[] = {
/* ------------------------------------------------------------------ */
/* debug help functions */
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static const char *v4l1_ioctls[] = {
- [_IOC_NR(VIDIOCGCAP)] = "VIDIOCGCAP",
- [_IOC_NR(VIDIOCGCHAN)] = "VIDIOCGCHAN",
- [_IOC_NR(VIDIOCSCHAN)] = "VIDIOCSCHAN",
- [_IOC_NR(VIDIOCGTUNER)] = "VIDIOCGTUNER",
- [_IOC_NR(VIDIOCSTUNER)] = "VIDIOCSTUNER",
- [_IOC_NR(VIDIOCGPICT)] = "VIDIOCGPICT",
- [_IOC_NR(VIDIOCSPICT)] = "VIDIOCSPICT",
- [_IOC_NR(VIDIOCCAPTURE)] = "VIDIOCCAPTURE",
- [_IOC_NR(VIDIOCGWIN)] = "VIDIOCGWIN",
- [_IOC_NR(VIDIOCSWIN)] = "VIDIOCSWIN",
- [_IOC_NR(VIDIOCGFBUF)] = "VIDIOCGFBUF",
- [_IOC_NR(VIDIOCSFBUF)] = "VIDIOCSFBUF",
- [_IOC_NR(VIDIOCKEY)] = "VIDIOCKEY",
- [_IOC_NR(VIDIOCGFREQ)] = "VIDIOCGFREQ",
- [_IOC_NR(VIDIOCSFREQ)] = "VIDIOCSFREQ",
- [_IOC_NR(VIDIOCGAUDIO)] = "VIDIOCGAUDIO",
- [_IOC_NR(VIDIOCSAUDIO)] = "VIDIOCSAUDIO",
- [_IOC_NR(VIDIOCSYNC)] = "VIDIOCSYNC",
- [_IOC_NR(VIDIOCMCAPTURE)] = "VIDIOCMCAPTURE",
- [_IOC_NR(VIDIOCGMBUF)] = "VIDIOCGMBUF",
- [_IOC_NR(VIDIOCGUNIT)] = "VIDIOCGUNIT",
- [_IOC_NR(VIDIOCGCAPTURE)] = "VIDIOCGCAPTURE",
- [_IOC_NR(VIDIOCSCAPTURE)] = "VIDIOCSCAPTURE",
- [_IOC_NR(VIDIOCSPLAYMODE)] = "VIDIOCSPLAYMODE",
- [_IOC_NR(VIDIOCSWRITEMODE)] = "VIDIOCSWRITEMODE",
- [_IOC_NR(VIDIOCGPLAYINFO)] = "VIDIOCGPLAYINFO",
- [_IOC_NR(VIDIOCSMICROCODE)] = "VIDIOCSMICROCODE",
- [_IOC_NR(VIDIOCGVBIFMT)] = "VIDIOCGVBIFMT",
- [_IOC_NR(VIDIOCSVBIFMT)] = "VIDIOCSVBIFMT"
-};
-#define V4L1_IOCTLS ARRAY_SIZE(v4l1_ioctls)
-#endif
-
static const char *v4l2_ioctls[] = {
[_IOC_NR(VIDIOC_QUERYCAP)] = "VIDIOC_QUERYCAP",
[_IOC_NR(VIDIOC_RESERVED)] = "VIDIOC_RESERVED",
@@ -309,15 +270,6 @@ void v4l_printk_ioctl(unsigned int cmd)
case 'd':
type = "v4l2_int";
break;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- case 'v':
- if (_IOC_NR(cmd) >= V4L1_IOCTLS) {
- type = "v4l1";
- break;
- }
- printk("%s", v4l1_ioctls[_IOC_NR(cmd)]);
- return;
-#endif
case 'V':
if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
type = "v4l2";
@@ -621,20 +573,6 @@ static long __video_do_ioctl(struct file *file,
return -EINVAL;
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /********************************************************
- All other V4L1 calls are handled by v4l1_compat module.
- Those calls will be translated into V4L2 calls, and
- __video_do_ioctl will be called again, with one or more
- V4L2 ioctls.
- ********************************************************/
- if (_IOC_TYPE(cmd) == 'v' && cmd != VIDIOCGMBUF &&
- _IOC_NR(cmd) < BASE_VIDIOCPRIVATE) {
- return v4l_compat_translate_ioctl(file, cmd, arg,
- __video_do_ioctl);
- }
-#endif
-
if ((vfd->debug & V4L2_DEBUG_IOCTL) &&
!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
v4l_print_ioctl(vfd->name, cmd);
@@ -643,29 +581,6 @@ static long __video_do_ioctl(struct file *file,
switch (cmd) {
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- /***********************************************************
- Handles calls to the obsoleted V4L1 API
- Due to the nature of VIDIOCGMBUF, each driver that supports
- V4L1 should implement its own handler for this ioctl.
- ***********************************************************/
-
- /* --- streaming capture ------------------------------------- */
- case VIDIOCGMBUF:
- {
- struct video_mbuf *p = arg;
-
- if (!ops->vidiocgmbuf)
- break;
- ret = ops->vidiocgmbuf(file, fh, p);
- if (!ret)
- dbgarg(cmd, "size=%d, frames=%d, offsets=0x%08lx\n",
- p->size, p->frames,
- (unsigned long)p->offsets);
- break;
- }
-#endif
-
/* --- capabilities ------------------------------------------ */
case VIDIOC_QUERYCAP:
{
@@ -1259,9 +1174,12 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_queryctrl *p = arg;
- if (!ops->vidioc_queryctrl)
+ if (vfd->ctrl_handler)
+ ret = v4l2_queryctrl(vfd->ctrl_handler, p);
+ else if (ops->vidioc_queryctrl)
+ ret = ops->vidioc_queryctrl(file, fh, p);
+ else
break;
- ret = ops->vidioc_queryctrl(file, fh, p);
if (!ret)
dbgarg(cmd, "id=0x%x, type=%d, name=%s, min/max=%d/%d, "
"step=%d, default=%d, flags=0x%08x\n",
@@ -1276,7 +1194,9 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_control *p = arg;
- if (ops->vidioc_g_ctrl)
+ if (vfd->ctrl_handler)
+ ret = v4l2_g_ctrl(vfd->ctrl_handler, p);
+ else if (ops->vidioc_g_ctrl)
ret = ops->vidioc_g_ctrl(file, fh, p);
else if (ops->vidioc_g_ext_ctrls) {
struct v4l2_ext_controls ctrls;
@@ -1306,11 +1226,16 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_ext_controls ctrls;
struct v4l2_ext_control ctrl;
- if (!ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
+ if (!vfd->ctrl_handler &&
+ !ops->vidioc_s_ctrl && !ops->vidioc_s_ext_ctrls)
break;
dbgarg(cmd, "id=0x%x, value=%d\n", p->id, p->value);
+ if (vfd->ctrl_handler) {
+ ret = v4l2_s_ctrl(vfd->ctrl_handler, p);
+ break;
+ }
if (ops->vidioc_s_ctrl) {
ret = ops->vidioc_s_ctrl(file, fh, p);
break;
@@ -1332,10 +1257,12 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_ext_controls *p = arg;
p->error_idx = p->count;
- if (!ops->vidioc_g_ext_ctrls)
- break;
- if (check_ext_ctrls(p, 0))
+ if (vfd->ctrl_handler)
+ ret = v4l2_g_ext_ctrls(vfd->ctrl_handler, p);
+ else if (ops->vidioc_g_ext_ctrls && check_ext_ctrls(p, 0))
ret = ops->vidioc_g_ext_ctrls(file, fh, p);
+ else
+ break;
v4l_print_ext_ctrls(cmd, vfd, p, !ret);
break;
}
@@ -1344,10 +1271,12 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_ext_controls *p = arg;
p->error_idx = p->count;
- if (!ops->vidioc_s_ext_ctrls)
+ if (!vfd->ctrl_handler && !ops->vidioc_s_ext_ctrls)
break;
v4l_print_ext_ctrls(cmd, vfd, p, 1);
- if (check_ext_ctrls(p, 0))
+ if (vfd->ctrl_handler)
+ ret = v4l2_s_ext_ctrls(vfd->ctrl_handler, p);
+ else if (check_ext_ctrls(p, 0))
ret = ops->vidioc_s_ext_ctrls(file, fh, p);
break;
}
@@ -1356,10 +1285,12 @@ static long __video_do_ioctl(struct file *file,
struct v4l2_ext_controls *p = arg;
p->error_idx = p->count;
- if (!ops->vidioc_try_ext_ctrls)
+ if (!vfd->ctrl_handler && !ops->vidioc_try_ext_ctrls)
break;
v4l_print_ext_ctrls(cmd, vfd, p, 1);
- if (check_ext_ctrls(p, 0))
+ if (vfd->ctrl_handler)
+ ret = v4l2_try_ext_ctrls(vfd->ctrl_handler, p);
+ else if (check_ext_ctrls(p, 0))
ret = ops->vidioc_try_ext_ctrls(file, fh, p);
break;
}
@@ -1367,9 +1298,12 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_querymenu *p = arg;
- if (!ops->vidioc_querymenu)
+ if (vfd->ctrl_handler)
+ ret = v4l2_querymenu(vfd->ctrl_handler, p);
+ else if (ops->vidioc_querymenu)
+ ret = ops->vidioc_querymenu(file, fh, p);
+ else
break;
- ret = ops->vidioc_querymenu(file, fh, p);
if (!ret)
dbgarg(cmd, "id=0x%x, index=%d, name=%s\n",
p->id, p->index, p->name);
@@ -1725,20 +1659,24 @@ static long __video_do_ioctl(struct file *file,
{
struct v4l2_dbg_register *p = arg;
- if (!capable(CAP_SYS_ADMIN))
- ret = -EPERM;
- else if (ops->vidioc_g_register)
- ret = ops->vidioc_g_register(file, fh, p);
+ if (ops->vidioc_g_register) {
+ if (!capable(CAP_SYS_ADMIN))
+ ret = -EPERM;
+ else
+ ret = ops->vidioc_g_register(file, fh, p);
+ }
break;
}
case VIDIOC_DBG_S_REGISTER:
{
struct v4l2_dbg_register *p = arg;
- if (!capable(CAP_SYS_ADMIN))
- ret = -EPERM;
- else if (ops->vidioc_s_register)
- ret = ops->vidioc_s_register(file, fh, p);
+ if (ops->vidioc_s_register) {
+ if (!capable(CAP_SYS_ADMIN))
+ ret = -EPERM;
+ else
+ ret = ops->vidioc_s_register(file, fh, p);
+ }
break;
}
#endif
diff --git a/drivers/media/video/v4l2-mem2mem.c b/drivers/media/video/v4l2-mem2mem.c
index f45f9405ea39..ac832a28e18e 100644
--- a/drivers/media/video/v4l2-mem2mem.c
+++ b/drivers/media/video/v4l2-mem2mem.c
@@ -421,8 +421,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
src_q = v4l2_m2m_get_src_vq(m2m_ctx);
dst_q = v4l2_m2m_get_dst_vq(m2m_ctx);
- mutex_lock(&src_q->vb_lock);
- mutex_lock(&dst_q->vb_lock);
+ videobuf_queue_lock(src_q);
+ videobuf_queue_lock(dst_q);
if (src_q->streaming && !list_empty(&src_q->stream))
src_vb = list_first_entry(&src_q->stream,
@@ -450,8 +450,8 @@ unsigned int v4l2_m2m_poll(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
}
end:
- mutex_unlock(&dst_q->vb_lock);
- mutex_unlock(&src_q->vb_lock);
+ videobuf_queue_unlock(dst_q);
+ videobuf_queue_unlock(src_q);
return rc;
}
EXPORT_SYMBOL_GPL(v4l2_m2m_poll);
diff --git a/drivers/media/video/via-camera.c b/drivers/media/video/via-camera.c
new file mode 100644
index 000000000000..2f973cd56408
--- /dev/null
+++ b/drivers/media/video/via-camera.c
@@ -0,0 +1,1459 @@
+/*
+ * Driver for the VIA Chrome integrated camera controller.
+ *
+ * Copyright 2009,2010 Jonathan Corbet <corbet@lwn.net>
+ * Distributable under the terms of the GNU General Public License, version 2
+ *
+ * This work was supported by the One Laptop Per Child project
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/gpio.h>
+#include <linux/interrupt.h>
+#include <linux/platform_device.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-ioctl.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/videobuf-dma-sg.h>
+#include <linux/delay.h>
+#include <linux/dma-mapping.h>
+#include <linux/pm_qos_params.h>
+#include <linux/via-core.h>
+#include <linux/via-gpio.h>
+#include <linux/via_i2c.h>
+
+#include "via-camera.h"
+
+MODULE_AUTHOR("Jonathan Corbet <corbet@lwn.net>");
+MODULE_DESCRIPTION("VIA framebuffer-based camera controller driver");
+MODULE_LICENSE("GPL");
+
+static int flip_image;
+module_param(flip_image, bool, 0444);
+MODULE_PARM_DESC(flip_image,
+ "If set, the sensor will be instructed to flip the image "
+ "vertically.");
+
+#ifdef CONFIG_OLPC_XO_1_5
+static int override_serial;
+module_param(override_serial, bool, 0444);
+MODULE_PARM_DESC(override_serial,
+ "The camera driver will normally refuse to load if "
+ "the XO 1.5 serial port is enabled. Set this option "
+ "to force the issue.");
+#endif
+
+/*
+ * Basic window sizes.
+ */
+#define VGA_WIDTH 640
+#define VGA_HEIGHT 480
+#define QCIF_WIDTH 176
+#define QCIF_HEIGHT 144
+
+/*
+ * The structure describing our camera.
+ */
+enum viacam_opstate { S_IDLE = 0, S_RUNNING = 1 };
+
+struct via_camera {
+ struct v4l2_device v4l2_dev;
+ struct video_device vdev;
+ struct v4l2_subdev *sensor;
+ struct platform_device *platdev;
+ struct viafb_dev *viadev;
+ struct mutex lock;
+ enum viacam_opstate opstate;
+ unsigned long flags;
+ struct pm_qos_request_list qos_request;
+ /*
+ * GPIO info for power/reset management
+ */
+ int power_gpio;
+ int reset_gpio;
+ /*
+ * I/O memory stuff.
+ */
+ void __iomem *mmio; /* Where the registers live */
+ void __iomem *fbmem; /* Frame buffer memory */
+ u32 fb_offset; /* Reserved memory offset (FB) */
+ /*
+ * Capture buffers and related. The controller supports
+ * up to three, so that's what we have here. These buffers
+ * live in frame buffer memory, so we don't call them "DMA".
+ */
+ unsigned int cb_offsets[3]; /* offsets into fb mem */
+ u8 *cb_addrs[3]; /* Kernel-space addresses */
+ int n_cap_bufs; /* How many are we using? */
+ int next_buf;
+ struct videobuf_queue vb_queue;
+ struct list_head buffer_queue; /* prot. by reg_lock */
+ /*
+ * User tracking.
+ */
+ int users;
+ struct file *owner;
+ /*
+ * Video format information. sensor_format is kept in a form
+ * that we can use to pass to the sensor. We always run the
+ * sensor in VGA resolution, though, and let the controller
+ * downscale things if need be. So we keep the "real*
+ * dimensions separately.
+ */
+ struct v4l2_pix_format sensor_format;
+ struct v4l2_pix_format user_format;
+ enum v4l2_mbus_pixelcode mbus_code;
+};
+
+/*
+ * Yes, this is a hack, but there's only going to be one of these
+ * on any system we know of.
+ */
+static struct via_camera *via_cam_info;
+
+/*
+ * Flag values, manipulated with bitops
+ */
+#define CF_DMA_ACTIVE 0 /* A frame is incoming */
+#define CF_CONFIG_NEEDED 1 /* Must configure hardware */
+
+
+/*
+ * Nasty ugly v4l2 boilerplate.
+ */
+#define sensor_call(cam, optype, func, args...) \
+ v4l2_subdev_call(cam->sensor, optype, func, ##args)
+
+/*
+ * Debugging and related.
+ */
+#define cam_err(cam, fmt, arg...) \
+ dev_err(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_warn(cam, fmt, arg...) \
+ dev_warn(&(cam)->platdev->dev, fmt, ##arg);
+#define cam_dbg(cam, fmt, arg...) \
+ dev_dbg(&(cam)->platdev->dev, fmt, ##arg);
+
+/*
+ * Format handling. This is ripped almost directly from Hans's changes
+ * to cafe_ccic.c. It's a little unfortunate; until this change, we
+ * didn't need to know anything about the format except its byte depth;
+ * now this information must be managed at this level too.
+ */
+static struct via_format {
+ __u8 *desc;
+ __u32 pixelformat;
+ int bpp; /* Bytes per pixel */
+ enum v4l2_mbus_pixelcode mbus_code;
+} via_formats[] = {
+ {
+ .desc = "YUYV 4:2:2",
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .mbus_code = V4L2_MBUS_FMT_YUYV8_2X8,
+ .bpp = 2,
+ },
+ {
+ .desc = "RGB 565",
+ .pixelformat = V4L2_PIX_FMT_RGB565,
+ .mbus_code = V4L2_MBUS_FMT_RGB565_2X8_LE,
+ .bpp = 2,
+ },
+ /* RGB444 and Bayer should be doable, but have never been
+ tested with this driver. */
+};
+#define N_VIA_FMTS ARRAY_SIZE(via_formats)
+
+static struct via_format *via_find_format(u32 pixelformat)
+{
+ unsigned i;
+
+ for (i = 0; i < N_VIA_FMTS; i++)
+ if (via_formats[i].pixelformat == pixelformat)
+ return via_formats + i;
+ /* Not found? Then return the first format. */
+ return via_formats;
+}
+
+
+/*--------------------------------------------------------------------------*/
+/*
+ * Sensor power/reset management. This piece is OLPC-specific for
+ * sure; other configurations will have things connected differently.
+ */
+static int via_sensor_power_setup(struct via_camera *cam)
+{
+ int ret;
+
+ cam->power_gpio = viafb_gpio_lookup("VGPIO3");
+ cam->reset_gpio = viafb_gpio_lookup("VGPIO2");
+ if (cam->power_gpio < 0 || cam->reset_gpio < 0) {
+ dev_err(&cam->platdev->dev, "Unable to find GPIO lines\n");
+ return -EINVAL;
+ }
+ ret = gpio_request(cam->power_gpio, "viafb-camera");
+ if (ret) {
+ dev_err(&cam->platdev->dev, "Unable to request power GPIO\n");
+ return ret;
+ }
+ ret = gpio_request(cam->reset_gpio, "viafb-camera");
+ if (ret) {
+ dev_err(&cam->platdev->dev, "Unable to request reset GPIO\n");
+ gpio_free(cam->power_gpio);
+ return ret;
+ }
+ gpio_direction_output(cam->power_gpio, 0);
+ gpio_direction_output(cam->reset_gpio, 0);
+ return 0;
+}
+
+/*
+ * Power up the sensor and perform the reset dance.
+ */
+static void via_sensor_power_up(struct via_camera *cam)
+{
+ gpio_set_value(cam->power_gpio, 1);
+ gpio_set_value(cam->reset_gpio, 0);
+ msleep(20); /* Probably excessive */
+ gpio_set_value(cam->reset_gpio, 1);
+ msleep(20);
+}
+
+static void via_sensor_power_down(struct via_camera *cam)
+{
+ gpio_set_value(cam->power_gpio, 0);
+ gpio_set_value(cam->reset_gpio, 0);
+}
+
+
+static void via_sensor_power_release(struct via_camera *cam)
+{
+ via_sensor_power_down(cam);
+ gpio_free(cam->power_gpio);
+ gpio_free(cam->reset_gpio);
+}
+
+/* --------------------------------------------------------------------------*/
+/* Sensor ops */
+
+/*
+ * Manage the ov7670 "flip" bit, which needs special help.
+ */
+static int viacam_set_flip(struct via_camera *cam)
+{
+ struct v4l2_control ctrl;
+
+ memset(&ctrl, 0, sizeof(ctrl));
+ ctrl.id = V4L2_CID_VFLIP;
+ ctrl.value = flip_image;
+ return sensor_call(cam, core, s_ctrl, &ctrl);
+}
+
+/*
+ * Configure the sensor. It's up to the caller to ensure
+ * that the camera is in the correct operating state.
+ */
+static int viacam_configure_sensor(struct via_camera *cam)
+{
+ struct v4l2_mbus_framefmt mbus_fmt;
+ int ret;
+
+ v4l2_fill_mbus_format(&mbus_fmt, &cam->sensor_format, cam->mbus_code);
+ ret = sensor_call(cam, core, init, 0);
+ if (ret == 0)
+ ret = sensor_call(cam, video, s_mbus_fmt, &mbus_fmt);
+ /*
+ * OV7670 does weird things if flip is set *before* format...
+ */
+ if (ret == 0)
+ ret = viacam_set_flip(cam);
+ return ret;
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/*
+ * Some simple register accessors; they assume that the lock is held.
+ *
+ * Should we want to support the second capture engine, we could
+ * hide the register difference by adding 0x1000 to registers in the
+ * 0x300-350 range.
+ */
+static inline void viacam_write_reg(struct via_camera *cam,
+ int reg, int value)
+{
+ iowrite32(value, cam->mmio + reg);
+}
+
+static inline int viacam_read_reg(struct via_camera *cam, int reg)
+{
+ return ioread32(cam->mmio + reg);
+}
+
+static inline void viacam_write_reg_mask(struct via_camera *cam,
+ int reg, int value, int mask)
+{
+ int tmp = viacam_read_reg(cam, reg);
+
+ tmp = (tmp & ~mask) | (value & mask);
+ viacam_write_reg(cam, reg, tmp);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Interrupt management and handling */
+
+static irqreturn_t viacam_quick_irq(int irq, void *data)
+{
+ struct via_camera *cam = data;
+ irqreturn_t ret = IRQ_NONE;
+ int icv;
+
+ /*
+ * All we do here is to clear the interrupts and tell
+ * the handler thread to wake up.
+ */
+ spin_lock(&cam->viadev->reg_lock);
+ icv = viacam_read_reg(cam, VCR_INTCTRL);
+ if (icv & VCR_IC_EAV) {
+ icv |= VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL;
+ viacam_write_reg(cam, VCR_INTCTRL, icv);
+ ret = IRQ_WAKE_THREAD;
+ }
+ spin_unlock(&cam->viadev->reg_lock);
+ return ret;
+}
+
+/*
+ * Find the next videobuf buffer which has somebody waiting on it.
+ */
+static struct videobuf_buffer *viacam_next_buffer(struct via_camera *cam)
+{
+ unsigned long flags;
+ struct videobuf_buffer *buf = NULL;
+
+ spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+ if (cam->opstate != S_RUNNING)
+ goto out;
+ if (list_empty(&cam->buffer_queue))
+ goto out;
+ buf = list_entry(cam->buffer_queue.next, struct videobuf_buffer, queue);
+ if (!waitqueue_active(&buf->done)) {/* Nobody waiting */
+ buf = NULL;
+ goto out;
+ }
+ list_del(&buf->queue);
+ buf->state = VIDEOBUF_ACTIVE;
+out:
+ spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+ return buf;
+}
+
+/*
+ * The threaded IRQ handler.
+ */
+static irqreturn_t viacam_irq(int irq, void *data)
+{
+ int bufn;
+ struct videobuf_buffer *vb;
+ struct via_camera *cam = data;
+ struct videobuf_dmabuf *vdma;
+
+ /*
+ * If there is no place to put the data frame, don't bother
+ * with anything else.
+ */
+ vb = viacam_next_buffer(cam);
+ if (vb == NULL)
+ goto done;
+ /*
+ * Figure out which buffer we just completed.
+ */
+ bufn = (viacam_read_reg(cam, VCR_INTCTRL) & VCR_IC_ACTBUF) >> 3;
+ bufn -= 1;
+ if (bufn < 0)
+ bufn = cam->n_cap_bufs - 1;
+ /*
+ * Copy over the data and let any waiters know.
+ */
+ vdma = videobuf_to_dma(vb);
+ viafb_dma_copy_out_sg(cam->cb_offsets[bufn], vdma->sglist, vdma->sglen);
+ vb->state = VIDEOBUF_DONE;
+ vb->size = cam->user_format.sizeimage;
+ wake_up(&vb->done);
+done:
+ return IRQ_HANDLED;
+}
+
+
+/*
+ * These functions must mess around with the general interrupt
+ * control register, which is relevant to much more than just the
+ * camera. Nothing else uses interrupts, though, as of this writing.
+ * Should that situation change, we'll have to improve support at
+ * the via-core level.
+ */
+static void viacam_int_enable(struct via_camera *cam)
+{
+ viacam_write_reg(cam, VCR_INTCTRL,
+ VCR_IC_INTEN|VCR_IC_EAV|VCR_IC_EVBI|VCR_IC_FFULL);
+ viafb_irq_enable(VDE_I_C0AVEN);
+}
+
+static void viacam_int_disable(struct via_camera *cam)
+{
+ viafb_irq_disable(VDE_I_C0AVEN);
+ viacam_write_reg(cam, VCR_INTCTRL, 0);
+}
+
+
+
+/* --------------------------------------------------------------------------*/
+/* Controller operations */
+
+/*
+ * Set up our capture buffers in framebuffer memory.
+ */
+static int viacam_ctlr_cbufs(struct via_camera *cam)
+{
+ int nbuf = cam->viadev->camera_fbmem_size/cam->sensor_format.sizeimage;
+ int i;
+ unsigned int offset;
+
+ /*
+ * See how many buffers we can work with.
+ */
+ if (nbuf >= 3) {
+ cam->n_cap_bufs = 3;
+ viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_3BUFS,
+ VCR_CI_3BUFS);
+ } else if (nbuf == 2) {
+ cam->n_cap_bufs = 2;
+ viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_3BUFS);
+ } else {
+ cam_warn(cam, "Insufficient frame buffer memory\n");
+ return -ENOMEM;
+ }
+ /*
+ * Set them up.
+ */
+ offset = cam->fb_offset;
+ for (i = 0; i < cam->n_cap_bufs; i++) {
+ cam->cb_offsets[i] = offset;
+ cam->cb_addrs[i] = cam->fbmem + offset;
+ viacam_write_reg(cam, VCR_VBUF1 + i*4, offset & VCR_VBUF_MASK);
+ offset += cam->sensor_format.sizeimage;
+ }
+ return 0;
+}
+
+/*
+ * Set the scaling register for downscaling the image.
+ *
+ * This register works like this... Vertical scaling is enabled
+ * by bit 26; if that bit is set, downscaling is controlled by the
+ * value in bits 16:25. Those bits are divided by 1024 to get
+ * the scaling factor; setting just bit 25 thus cuts the height
+ * in half.
+ *
+ * Horizontal scaling works about the same, but it's enabled by
+ * bit 11, with bits 0:10 giving the numerator of a fraction
+ * (over 2048) for the scaling value.
+ *
+ * This function is naive in that, if the user departs from
+ * the 3x4 VGA scaling factor, the image will distort. We
+ * could work around that if it really seemed important.
+ */
+static void viacam_set_scale(struct via_camera *cam)
+{
+ unsigned int avscale;
+ int sf;
+
+ if (cam->user_format.width == VGA_WIDTH)
+ avscale = 0;
+ else {
+ sf = (cam->user_format.width*2048)/VGA_WIDTH;
+ avscale = VCR_AVS_HEN | sf;
+ }
+ if (cam->user_format.height < VGA_HEIGHT) {
+ sf = (1024*cam->user_format.height)/VGA_HEIGHT;
+ avscale |= VCR_AVS_VEN | (sf << 16);
+ }
+ viacam_write_reg(cam, VCR_AVSCALE, avscale);
+}
+
+
+/*
+ * Configure image-related information into the capture engine.
+ */
+static void viacam_ctlr_image(struct via_camera *cam)
+{
+ int cicreg;
+
+ /*
+ * Disable clock before messing with stuff - from the via
+ * sample driver.
+ */
+ viacam_write_reg(cam, VCR_CAPINTC, ~(VCR_CI_ENABLE|VCR_CI_CLKEN));
+ /*
+ * Set up the controller for VGA resolution, modulo magic
+ * offsets from the via sample driver.
+ */
+ viacam_write_reg(cam, VCR_HORRANGE, 0x06200120);
+ viacam_write_reg(cam, VCR_VERTRANGE, 0x01de0000);
+ viacam_set_scale(cam);
+ /*
+ * Image size info.
+ */
+ viacam_write_reg(cam, VCR_MAXDATA,
+ (cam->sensor_format.height << 16) |
+ (cam->sensor_format.bytesperline >> 3));
+ viacam_write_reg(cam, VCR_MAXVBI, 0);
+ viacam_write_reg(cam, VCR_VSTRIDE,
+ cam->user_format.bytesperline & VCR_VS_STRIDE);
+ /*
+ * Set up the capture interface control register,
+ * everything but the "go" bit.
+ *
+ * The FIFO threshold is a bit of a magic number; 8 is what
+ * VIA's sample code uses.
+ */
+ cicreg = VCR_CI_CLKEN |
+ 0x08000000 | /* FIFO threshold */
+ VCR_CI_FLDINV | /* OLPC-specific? */
+ VCR_CI_VREFINV | /* OLPC-specific? */
+ VCR_CI_DIBOTH | /* Capture both fields */
+ VCR_CI_CCIR601_8;
+ if (cam->n_cap_bufs == 3)
+ cicreg |= VCR_CI_3BUFS;
+ /*
+ * YUV formats need different byte swapping than RGB.
+ */
+ if (cam->user_format.pixelformat == V4L2_PIX_FMT_YUYV)
+ cicreg |= VCR_CI_YUYV;
+ else
+ cicreg |= VCR_CI_UYVY;
+ viacam_write_reg(cam, VCR_CAPINTC, cicreg);
+}
+
+
+static int viacam_config_controller(struct via_camera *cam)
+{
+ int ret;
+ unsigned long flags;
+
+ spin_lock_irqsave(&cam->viadev->reg_lock, flags);
+ ret = viacam_ctlr_cbufs(cam);
+ if (!ret)
+ viacam_ctlr_image(cam);
+ spin_unlock_irqrestore(&cam->viadev->reg_lock, flags);
+ clear_bit(CF_CONFIG_NEEDED, &cam->flags);
+ return ret;
+}
+
+/*
+ * Make it start grabbing data.
+ */
+static void viacam_start_engine(struct via_camera *cam)
+{
+ spin_lock_irq(&cam->viadev->reg_lock);
+ cam->next_buf = 0;
+ viacam_write_reg_mask(cam, VCR_CAPINTC, VCR_CI_ENABLE, VCR_CI_ENABLE);
+ viacam_int_enable(cam);
+ (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+ cam->opstate = S_RUNNING;
+ spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+static void viacam_stop_engine(struct via_camera *cam)
+{
+ spin_lock_irq(&cam->viadev->reg_lock);
+ viacam_int_disable(cam);
+ viacam_write_reg_mask(cam, VCR_CAPINTC, 0, VCR_CI_ENABLE);
+ (void) viacam_read_reg(cam, VCR_CAPINTC); /* Force post */
+ cam->opstate = S_IDLE;
+ spin_unlock_irq(&cam->viadev->reg_lock);
+}
+
+
+/* --------------------------------------------------------------------------*/
+/* Videobuf callback ops */
+
+/*
+ * buffer_setup. The purpose of this one would appear to be to tell
+ * videobuf how big a single image is. It's also evidently up to us
+ * to put some sort of limit on the maximum number of buffers allowed.
+ */
+static int viacam_vb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct via_camera *cam = q->priv_data;
+
+ *size = cam->user_format.sizeimage;
+ if (*count == 0 || *count > 6) /* Arbitrary number */
+ *count = 6;
+ return 0;
+}
+
+/*
+ * Prepare a buffer.
+ */
+static int viacam_vb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct via_camera *cam = q->priv_data;
+
+ vb->size = cam->user_format.sizeimage;
+ vb->width = cam->user_format.width; /* bytesperline???? */
+ vb->height = cam->user_format.height;
+ vb->field = field;
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ int ret = videobuf_iolock(q, vb, NULL);
+ if (ret)
+ return ret;
+ }
+ vb->state = VIDEOBUF_PREPARED;
+ return 0;
+}
+
+/*
+ * We've got a buffer to put data into.
+ *
+ * FIXME: check for a running engine and valid buffers?
+ */
+static void viacam_vb_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct via_camera *cam = q->priv_data;
+
+ /*
+ * Note that videobuf holds the lock when it calls
+ * us, so we need not (indeed, cannot) take it here.
+ */
+ vb->state = VIDEOBUF_QUEUED;
+ list_add_tail(&vb->queue, &cam->buffer_queue);
+}
+
+/*
+ * Free a buffer.
+ */
+static void viacam_vb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct via_camera *cam = q->priv_data;
+
+ videobuf_dma_unmap(&cam->platdev->dev, videobuf_to_dma(vb));
+ videobuf_dma_free(videobuf_to_dma(vb));
+ vb->state = VIDEOBUF_NEEDS_INIT;
+}
+
+static const struct videobuf_queue_ops viacam_vb_ops = {
+ .buf_setup = viacam_vb_buf_setup,
+ .buf_prepare = viacam_vb_buf_prepare,
+ .buf_queue = viacam_vb_buf_queue,
+ .buf_release = viacam_vb_buf_release,
+};
+
+/* --------------------------------------------------------------------------*/
+/* File operations */
+
+static int viacam_open(struct file *filp)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ filp->private_data = cam;
+ /*
+ * Note the new user. If this is the first one, we'll also
+ * need to power up the sensor.
+ */
+ mutex_lock(&cam->lock);
+ if (cam->users == 0) {
+ int ret = viafb_request_dma();
+
+ if (ret) {
+ mutex_unlock(&cam->lock);
+ return ret;
+ }
+ via_sensor_power_up(cam);
+ set_bit(CF_CONFIG_NEEDED, &cam->flags);
+ /*
+ * Hook into videobuf. Evidently this cannot fail.
+ */
+ videobuf_queue_sg_init(&cam->vb_queue, &viacam_vb_ops,
+ &cam->platdev->dev, &cam->viadev->reg_lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ sizeof(struct videobuf_buffer), cam, NULL);
+ }
+ (cam->users)++;
+ mutex_unlock(&cam->lock);
+ return 0;
+}
+
+static int viacam_release(struct file *filp)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ mutex_lock(&cam->lock);
+ (cam->users)--;
+ /*
+ * If the "owner" is closing, shut down any ongoing
+ * operations.
+ */
+ if (filp == cam->owner) {
+ videobuf_stop(&cam->vb_queue);
+ /*
+ * We don't hold the spinlock here, but, if release()
+ * is being called by the owner, nobody else will
+ * be changing the state. And an extra stop would
+ * not hurt anyway.
+ */
+ if (cam->opstate != S_IDLE)
+ viacam_stop_engine(cam);
+ cam->owner = NULL;
+ }
+ /*
+ * Last one out needs to turn out the lights.
+ */
+ if (cam->users == 0) {
+ videobuf_mmap_free(&cam->vb_queue);
+ via_sensor_power_down(cam);
+ viafb_release_dma();
+ }
+ mutex_unlock(&cam->lock);
+ return 0;
+}
+
+/*
+ * Read a frame from the device.
+ */
+static ssize_t viacam_read(struct file *filp, char __user *buffer,
+ size_t len, loff_t *pos)
+{
+ struct via_camera *cam = video_drvdata(filp);
+ int ret;
+
+ mutex_lock(&cam->lock);
+ /*
+ * Enforce the V4l2 "only one owner gets to read data" rule.
+ */
+ if (cam->owner && cam->owner != filp) {
+ ret = -EBUSY;
+ goto out_unlock;
+ }
+ cam->owner = filp;
+ /*
+ * Do we need to configure the hardware?
+ */
+ if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+ ret = viacam_configure_sensor(cam);
+ if (!ret)
+ ret = viacam_config_controller(cam);
+ if (ret)
+ goto out_unlock;
+ }
+ /*
+ * Fire up the capture engine, then have videobuf do
+ * the heavy lifting. Someday it would be good to avoid
+ * stopping and restarting the engine each time.
+ */
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ viacam_start_engine(cam);
+ ret = videobuf_read_stream(&cam->vb_queue, buffer, len, pos, 0,
+ filp->f_flags & O_NONBLOCK);
+ viacam_stop_engine(cam);
+ /* videobuf_stop() ?? */
+
+out_unlock:
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static unsigned int viacam_poll(struct file *filp, struct poll_table_struct *pt)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ return videobuf_poll_stream(filp, &cam->vb_queue, pt);
+}
+
+
+static int viacam_mmap(struct file *filp, struct vm_area_struct *vma)
+{
+ struct via_camera *cam = video_drvdata(filp);
+
+ return videobuf_mmap_mapper(&cam->vb_queue, vma);
+}
+
+
+
+static const struct v4l2_file_operations viacam_fops = {
+ .owner = THIS_MODULE,
+ .open = viacam_open,
+ .release = viacam_release,
+ .read = viacam_read,
+ .poll = viacam_poll,
+ .mmap = viacam_mmap,
+ .unlocked_ioctl = video_ioctl2,
+};
+
+/*----------------------------------------------------------------------------*/
+/*
+ * The long list of v4l2 ioctl ops
+ */
+
+static int viacam_g_chip_ident(struct file *file, void *priv,
+ struct v4l2_dbg_chip_ident *ident)
+{
+ struct via_camera *cam = priv;
+
+ ident->ident = V4L2_IDENT_NONE;
+ ident->revision = 0;
+ if (v4l2_chip_match_host(&ident->match)) {
+ ident->ident = V4L2_IDENT_VIA_VX855;
+ return 0;
+ }
+ return sensor_call(cam, core, g_chip_ident, ident);
+}
+
+/*
+ * Control ops are passed through to the sensor.
+ */
+static int viacam_queryctrl(struct file *filp, void *priv,
+ struct v4l2_queryctrl *qc)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, queryctrl, qc);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static int viacam_g_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, g_ctrl, ctrl);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static int viacam_s_ctrl(struct file *filp, void *priv,
+ struct v4l2_control *ctrl)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, core, s_ctrl, ctrl);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+/*
+ * Only one input.
+ */
+static int viacam_enum_input(struct file *filp, void *priv,
+ struct v4l2_input *input)
+{
+ if (input->index != 0)
+ return -EINVAL;
+
+ input->type = V4L2_INPUT_TYPE_CAMERA;
+ input->std = V4L2_STD_ALL; /* Not sure what should go here */
+ strcpy(input->name, "Camera");
+ return 0;
+}
+
+static int viacam_g_input(struct file *filp, void *priv, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int viacam_s_input(struct file *filp, void *priv, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+ return 0;
+}
+
+static int viacam_s_std(struct file *filp, void *priv, v4l2_std_id *std)
+{
+ return 0;
+}
+
+/*
+ * Video format stuff. Here is our default format until
+ * user space messes with things.
+ */
+static const struct v4l2_pix_format viacam_def_pix_format = {
+ .width = VGA_WIDTH,
+ .height = VGA_HEIGHT,
+ .pixelformat = V4L2_PIX_FMT_YUYV,
+ .field = V4L2_FIELD_NONE,
+ .bytesperline = VGA_WIDTH * 2,
+ .sizeimage = VGA_WIDTH * VGA_HEIGHT * 2,
+};
+
+static const enum v4l2_mbus_pixelcode via_def_mbus_code = V4L2_MBUS_FMT_YUYV8_2X8;
+
+static int viacam_enum_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_fmtdesc *fmt)
+{
+ if (fmt->index >= N_VIA_FMTS)
+ return -EINVAL;
+ strlcpy(fmt->description, via_formats[fmt->index].desc,
+ sizeof(fmt->description));
+ fmt->pixelformat = via_formats[fmt->index].pixelformat;
+ return 0;
+}
+
+/*
+ * Figure out proper image dimensions, but always force the
+ * sensor to VGA.
+ */
+static void viacam_fmt_pre(struct v4l2_pix_format *userfmt,
+ struct v4l2_pix_format *sensorfmt)
+{
+ *sensorfmt = *userfmt;
+ if (userfmt->width < QCIF_WIDTH || userfmt->height < QCIF_HEIGHT) {
+ userfmt->width = QCIF_WIDTH;
+ userfmt->height = QCIF_HEIGHT;
+ }
+ if (userfmt->width > VGA_WIDTH || userfmt->height > VGA_HEIGHT) {
+ userfmt->width = VGA_WIDTH;
+ userfmt->height = VGA_HEIGHT;
+ }
+ sensorfmt->width = VGA_WIDTH;
+ sensorfmt->height = VGA_HEIGHT;
+}
+
+static void viacam_fmt_post(struct v4l2_pix_format *userfmt,
+ struct v4l2_pix_format *sensorfmt)
+{
+ struct via_format *f = via_find_format(userfmt->pixelformat);
+
+ sensorfmt->bytesperline = sensorfmt->width * f->bpp;
+ sensorfmt->sizeimage = sensorfmt->height * sensorfmt->bytesperline;
+ userfmt->pixelformat = sensorfmt->pixelformat;
+ userfmt->field = sensorfmt->field;
+ userfmt->bytesperline = 2 * userfmt->width;
+ userfmt->sizeimage = userfmt->bytesperline * userfmt->height;
+}
+
+
+/*
+ * The real work of figuring out a workable format.
+ */
+static int viacam_do_try_fmt(struct via_camera *cam,
+ struct v4l2_pix_format *upix, struct v4l2_pix_format *spix)
+{
+ int ret;
+ struct v4l2_mbus_framefmt mbus_fmt;
+ struct via_format *f = via_find_format(upix->pixelformat);
+
+ upix->pixelformat = f->pixelformat;
+ viacam_fmt_pre(upix, spix);
+ v4l2_fill_mbus_format(&mbus_fmt, upix, f->mbus_code);
+ ret = sensor_call(cam, video, try_mbus_fmt, &mbus_fmt);
+ v4l2_fill_pix_format(spix, &mbus_fmt);
+ viacam_fmt_post(upix, spix);
+ return ret;
+}
+
+
+
+static int viacam_try_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+ struct v4l2_format sfmt;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+static int viacam_g_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+
+ mutex_lock(&cam->lock);
+ fmt->fmt.pix = cam->user_format;
+ mutex_unlock(&cam->lock);
+ return 0;
+}
+
+static int viacam_s_fmt_vid_cap(struct file *filp, void *priv,
+ struct v4l2_format *fmt)
+{
+ struct via_camera *cam = priv;
+ int ret;
+ struct v4l2_format sfmt;
+ struct via_format *f = via_find_format(fmt->fmt.pix.pixelformat);
+
+ /*
+ * Camera must be idle or we can't mess with the
+ * video setup.
+ */
+ mutex_lock(&cam->lock);
+ if (cam->opstate != S_IDLE) {
+ ret = -EBUSY;
+ goto out;
+ }
+ /*
+ * Let the sensor code look over and tweak the
+ * requested formatting.
+ */
+ ret = viacam_do_try_fmt(cam, &fmt->fmt.pix, &sfmt.fmt.pix);
+ if (ret)
+ goto out;
+ /*
+ * OK, let's commit to the new format.
+ */
+ cam->user_format = fmt->fmt.pix;
+ cam->sensor_format = sfmt.fmt.pix;
+ cam->mbus_code = f->mbus_code;
+ ret = viacam_configure_sensor(cam);
+ if (!ret)
+ ret = viacam_config_controller(cam);
+out:
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+static int viacam_querycap(struct file *filp, void *priv,
+ struct v4l2_capability *cap)
+{
+ strcpy(cap->driver, "via-camera");
+ strcpy(cap->card, "via-camera");
+ cap->version = 1;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE | V4L2_CAP_STREAMING;
+ return 0;
+}
+
+/*
+ * Streaming operations - pure videobuf stuff.
+ */
+static int viacam_reqbufs(struct file *filp, void *priv,
+ struct v4l2_requestbuffers *rb)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_reqbufs(&cam->vb_queue, rb);
+}
+
+static int viacam_querybuf(struct file *filp, void *priv,
+ struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_querybuf(&cam->vb_queue, buf);
+}
+
+static int viacam_qbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_qbuf(&cam->vb_queue, buf);
+}
+
+static int viacam_dqbuf(struct file *filp, void *priv, struct v4l2_buffer *buf)
+{
+ struct via_camera *cam = priv;
+
+ return videobuf_dqbuf(&cam->vb_queue, buf, filp->f_flags & O_NONBLOCK);
+}
+
+static int viacam_streamon(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+ struct via_camera *cam = priv;
+ int ret = 0;
+
+ if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ mutex_lock(&cam->lock);
+ if (cam->opstate != S_IDLE) {
+ ret = -EBUSY;
+ goto out;
+ }
+ /*
+ * Enforce the V4l2 "only one owner gets to read data" rule.
+ */
+ if (cam->owner && cam->owner != filp) {
+ ret = -EBUSY;
+ goto out;
+ }
+ cam->owner = filp;
+ /*
+ * Configure things if need be.
+ */
+ if (test_bit(CF_CONFIG_NEEDED, &cam->flags)) {
+ ret = viacam_configure_sensor(cam);
+ if (ret)
+ goto out;
+ ret = viacam_config_controller(cam);
+ if (ret)
+ goto out;
+ }
+ /*
+ * If the CPU goes into C3, the DMA transfer gets corrupted and
+ * users start filing unsightly bug reports. Put in a "latency"
+ * requirement which will keep the CPU out of the deeper sleep
+ * states.
+ */
+ pm_qos_add_request(&cam->qos_request, PM_QOS_CPU_DMA_LATENCY, 50);
+ /*
+ * Fire things up.
+ */
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ ret = videobuf_streamon(&cam->vb_queue);
+ if (!ret)
+ viacam_start_engine(cam);
+out:
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+static int viacam_streamoff(struct file *filp, void *priv, enum v4l2_buf_type t)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ if (t != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ mutex_lock(&cam->lock);
+ if (cam->opstate != S_RUNNING) {
+ ret = -EINVAL;
+ goto out;
+ }
+ pm_qos_remove_request(&cam->qos_request);
+ viacam_stop_engine(cam);
+ /*
+ * Videobuf will recycle all of the outstanding buffers, but
+ * we should be sure we don't retain any references to
+ * any of them.
+ */
+ ret = videobuf_streamoff(&cam->vb_queue);
+ INIT_LIST_HEAD(&cam->buffer_queue);
+out:
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+/* G/S_PARM */
+
+static int viacam_g_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, g_parm, parm);
+ mutex_unlock(&cam->lock);
+ parm->parm.capture.readbuffers = cam->n_cap_bufs;
+ return ret;
+}
+
+static int viacam_s_parm(struct file *filp, void *priv,
+ struct v4l2_streamparm *parm)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, s_parm, parm);
+ mutex_unlock(&cam->lock);
+ parm->parm.capture.readbuffers = cam->n_cap_bufs;
+ return ret;
+}
+
+static int viacam_enum_framesizes(struct file *filp, void *priv,
+ struct v4l2_frmsizeenum *sizes)
+{
+ if (sizes->index != 0)
+ return -EINVAL;
+ sizes->type = V4L2_FRMSIZE_TYPE_CONTINUOUS;
+ sizes->stepwise.min_width = QCIF_WIDTH;
+ sizes->stepwise.min_height = QCIF_HEIGHT;
+ sizes->stepwise.max_width = VGA_WIDTH;
+ sizes->stepwise.max_height = VGA_HEIGHT;
+ sizes->stepwise.step_width = sizes->stepwise.step_height = 1;
+ return 0;
+}
+
+static int viacam_enum_frameintervals(struct file *filp, void *priv,
+ struct v4l2_frmivalenum *interval)
+{
+ struct via_camera *cam = priv;
+ int ret;
+
+ mutex_lock(&cam->lock);
+ ret = sensor_call(cam, video, enum_frameintervals, interval);
+ mutex_unlock(&cam->lock);
+ return ret;
+}
+
+
+
+static const struct v4l2_ioctl_ops viacam_ioctl_ops = {
+ .vidioc_g_chip_ident = viacam_g_chip_ident,
+ .vidioc_queryctrl = viacam_queryctrl,
+ .vidioc_g_ctrl = viacam_g_ctrl,
+ .vidioc_s_ctrl = viacam_s_ctrl,
+ .vidioc_enum_input = viacam_enum_input,
+ .vidioc_g_input = viacam_g_input,
+ .vidioc_s_input = viacam_s_input,
+ .vidioc_s_std = viacam_s_std,
+ .vidioc_enum_fmt_vid_cap = viacam_enum_fmt_vid_cap,
+ .vidioc_try_fmt_vid_cap = viacam_try_fmt_vid_cap,
+ .vidioc_g_fmt_vid_cap = viacam_g_fmt_vid_cap,
+ .vidioc_s_fmt_vid_cap = viacam_s_fmt_vid_cap,
+ .vidioc_querycap = viacam_querycap,
+ .vidioc_reqbufs = viacam_reqbufs,
+ .vidioc_querybuf = viacam_querybuf,
+ .vidioc_qbuf = viacam_qbuf,
+ .vidioc_dqbuf = viacam_dqbuf,
+ .vidioc_streamon = viacam_streamon,
+ .vidioc_streamoff = viacam_streamoff,
+ .vidioc_g_parm = viacam_g_parm,
+ .vidioc_s_parm = viacam_s_parm,
+ .vidioc_enum_framesizes = viacam_enum_framesizes,
+ .vidioc_enum_frameintervals = viacam_enum_frameintervals,
+};
+
+/*----------------------------------------------------------------------------*/
+
+/*
+ * Power management.
+ */
+
+/*
+ * Setup stuff.
+ */
+
+static struct video_device viacam_v4l_template = {
+ .name = "via-camera",
+ .minor = -1,
+ .tvnorms = V4L2_STD_NTSC_M,
+ .current_norm = V4L2_STD_NTSC_M,
+ .fops = &viacam_fops,
+ .ioctl_ops = &viacam_ioctl_ops,
+ .release = video_device_release_empty, /* Check this */
+};
+
+
+static __devinit int viacam_probe(struct platform_device *pdev)
+{
+ int ret;
+ struct i2c_adapter *sensor_adapter;
+ struct viafb_dev *viadev = pdev->dev.platform_data;
+
+ /*
+ * Note that there are actually two capture channels on
+ * the device. We only deal with one for now. That
+ * is encoded here; nothing else assumes it's dealing with
+ * a unique capture device.
+ */
+ struct via_camera *cam;
+
+ /*
+ * Ensure that frame buffer memory has been set aside for
+ * this purpose. As an arbitrary limit, refuse to work
+ * with less than two frames of VGA 16-bit data.
+ *
+ * If we ever support the second port, we'll need to set
+ * aside more memory.
+ */
+ if (viadev->camera_fbmem_size < (VGA_HEIGHT*VGA_WIDTH*4)) {
+ printk(KERN_ERR "viacam: insufficient FB memory reserved\n");
+ return -ENOMEM;
+ }
+ if (viadev->engine_mmio == NULL) {
+ printk(KERN_ERR "viacam: No I/O memory, so no pictures\n");
+ return -ENOMEM;
+ }
+ /*
+ * Basic structure initialization.
+ */
+ cam = kzalloc (sizeof(struct via_camera), GFP_KERNEL);
+ if (cam == NULL)
+ return -ENOMEM;
+ via_cam_info = cam;
+ cam->platdev = pdev;
+ cam->viadev = viadev;
+ cam->users = 0;
+ cam->owner = NULL;
+ cam->opstate = S_IDLE;
+ cam->user_format = cam->sensor_format = viacam_def_pix_format;
+ mutex_init(&cam->lock);
+ INIT_LIST_HEAD(&cam->buffer_queue);
+ cam->mmio = viadev->engine_mmio;
+ cam->fbmem = viadev->fbmem;
+ cam->fb_offset = viadev->camera_fbmem_offset;
+ cam->flags = 1 << CF_CONFIG_NEEDED;
+ cam->mbus_code = via_def_mbus_code;
+ /*
+ * Tell V4L that we exist.
+ */
+ ret = v4l2_device_register(&pdev->dev, &cam->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Unable to register v4l2 device\n");
+ return ret;
+ }
+ /*
+ * Convince the system that we can do DMA.
+ */
+ pdev->dev.dma_mask = &viadev->pdev->dma_mask;
+ dma_set_mask(&pdev->dev, 0xffffffff);
+ /*
+ * Fire up the capture port. The write to 0x78 looks purely
+ * OLPCish; any system will need to tweak 0x1e.
+ */
+ via_write_reg_mask(VIASR, 0x78, 0, 0x80);
+ via_write_reg_mask(VIASR, 0x1e, 0xc0, 0xc0);
+ /*
+ * Get the sensor powered up.
+ */
+ ret = via_sensor_power_setup(cam);
+ if (ret)
+ goto out_unregister;
+ via_sensor_power_up(cam);
+
+ /*
+ * See if we can't find it on the bus. The VIA_PORT_31 assumption
+ * is OLPC-specific. 0x42 assumption is ov7670-specific.
+ */
+ sensor_adapter = viafb_find_i2c_adapter(VIA_PORT_31);
+ cam->sensor = v4l2_i2c_new_subdev(&cam->v4l2_dev, sensor_adapter,
+ "ov7670", 0x42 >> 1, NULL);
+ if (cam->sensor == NULL) {
+ dev_err(&pdev->dev, "Unable to find the sensor!\n");
+ ret = -ENODEV;
+ goto out_power_down;
+ }
+ /*
+ * Get the IRQ.
+ */
+ viacam_int_disable(cam);
+ ret = request_threaded_irq(viadev->pdev->irq, viacam_quick_irq,
+ viacam_irq, IRQF_SHARED, "via-camera", cam);
+ if (ret)
+ goto out_power_down;
+ /*
+ * Tell V4l2 that we exist.
+ */
+ cam->vdev = viacam_v4l_template;
+ cam->vdev.v4l2_dev = &cam->v4l2_dev;
+ ret = video_register_device(&cam->vdev, VFL_TYPE_GRABBER, -1);
+ if (ret)
+ goto out_irq;
+ video_set_drvdata(&cam->vdev, cam);
+
+ /* Power the sensor down until somebody opens the device */
+ via_sensor_power_down(cam);
+ return 0;
+
+out_irq:
+ free_irq(viadev->pdev->irq, cam);
+out_power_down:
+ via_sensor_power_release(cam);
+out_unregister:
+ v4l2_device_unregister(&cam->v4l2_dev);
+ return ret;
+}
+
+static __devexit int viacam_remove(struct platform_device *pdev)
+{
+ struct via_camera *cam = via_cam_info;
+ struct viafb_dev *viadev = pdev->dev.platform_data;
+
+ video_unregister_device(&cam->vdev);
+ v4l2_device_unregister(&cam->v4l2_dev);
+ free_irq(viadev->pdev->irq, cam);
+ via_sensor_power_release(cam);
+ via_cam_info = NULL;
+ return 0;
+}
+
+
+static struct platform_driver viacam_driver = {
+ .driver = {
+ .name = "viafb-camera",
+ },
+ .probe = viacam_probe,
+ .remove = viacam_remove,
+};
+
+
+#ifdef CONFIG_OLPC_XO_1_5
+/*
+ * The OLPC folks put the serial port on the same pin as
+ * the camera. They also get grumpy if we break the
+ * serial port and keep them from using it. So we have
+ * to check the serial enable bit and not step on it.
+ */
+#define VIACAM_SERIAL_DEVFN 0x88
+#define VIACAM_SERIAL_CREG 0x46
+#define VIACAM_SERIAL_BIT 0x40
+
+static __devinit int viacam_check_serial_port(void)
+{
+ struct pci_bus *pbus = pci_find_bus(0, 0);
+ u8 cbyte;
+
+ pci_bus_read_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+ VIACAM_SERIAL_CREG, &cbyte);
+ if ((cbyte & VIACAM_SERIAL_BIT) == 0)
+ return 0; /* Not enabled */
+ if (override_serial == 0) {
+ printk(KERN_NOTICE "Via camera: serial port is enabled, " \
+ "refusing to load.\n");
+ printk(KERN_NOTICE "Specify override_serial=1 to force " \
+ "module loading.\n");
+ return -EBUSY;
+ }
+ printk(KERN_NOTICE "Via camera: overriding serial port\n");
+ pci_bus_write_config_byte(pbus, VIACAM_SERIAL_DEVFN,
+ VIACAM_SERIAL_CREG, cbyte & ~VIACAM_SERIAL_BIT);
+ return 0;
+}
+#endif
+
+
+
+
+static int viacam_init(void)
+{
+#ifdef CONFIG_OLPC_XO_1_5
+ if (viacam_check_serial_port())
+ return -EBUSY;
+#endif
+ return platform_driver_register(&viacam_driver);
+}
+module_init(viacam_init);
+
+static void viacam_exit(void)
+{
+ platform_driver_unregister(&viacam_driver);
+}
+module_exit(viacam_exit);
diff --git a/drivers/media/video/via-camera.h b/drivers/media/video/via-camera.h
new file mode 100644
index 000000000000..b12a4b3d616f
--- /dev/null
+++ b/drivers/media/video/via-camera.h
@@ -0,0 +1,93 @@
+/*
+ * VIA Camera register definitions.
+ */
+#define VCR_INTCTRL 0x300 /* Capture interrupt control */
+#define VCR_IC_EAV 0x0001 /* End of active video status */
+#define VCR_IC_EVBI 0x0002 /* End of VBI status */
+#define VCR_IC_FBOTFLD 0x0004 /* "flipping" Bottom field is active */
+#define VCR_IC_ACTBUF 0x0018 /* Active video buffer */
+#define VCR_IC_VSYNC 0x0020 /* 0 = VB, 1 = active video */
+#define VCR_IC_BOTFLD 0x0040 /* Bottom field is active */
+#define VCR_IC_FFULL 0x0080 /* FIFO full */
+#define VCR_IC_INTEN 0x0100 /* End of active video int. enable */
+#define VCR_IC_VBIINT 0x0200 /* End of VBI int enable */
+#define VCR_IC_VBIBUF 0x0400 /* Current VBI buffer */
+
+#define VCR_TSC 0x308 /* Transport stream control */
+#define VCR_TSC_ENABLE 0x000001 /* Transport stream input enable */
+#define VCR_TSC_DROPERR 0x000002 /* Drop error packets */
+#define VCR_TSC_METHOD 0x00000c /* DMA method (non-functional) */
+#define VCR_TSC_COUNT 0x07fff0 /* KByte or packet count */
+#define VCR_TSC_CBMODE 0x080000 /* Change buffer by byte count */
+#define VCR_TSC_PSSIG 0x100000 /* Packet starting signal disable */
+#define VCR_TSC_BE 0x200000 /* MSB first (serial mode) */
+#define VCR_TSC_SERIAL 0x400000 /* Serial input (0 = parallel) */
+
+#define VCR_CAPINTC 0x310 /* Capture interface control */
+#define VCR_CI_ENABLE 0x00000001 /* Capture enable */
+#define VCR_CI_BSS 0x00000002 /* WTF "bit stream selection" */
+#define VCR_CI_3BUFS 0x00000004 /* 1 = 3 buffers, 0 = 2 buffers */
+#define VCR_CI_VIPEN 0x00000008 /* VIP enable */
+#define VCR_CI_CCIR601_8 0 /* CCIR601 input stream, 8 bit */
+#define VCR_CI_CCIR656_8 0x00000010 /* ... CCIR656, 8 bit */
+#define VCR_CI_CCIR601_16 0x00000020 /* ... CCIR601, 16 bit */
+#define VCR_CI_CCIR656_16 0x00000030 /* ... CCIR656, 16 bit */
+#define VCR_CI_HDMODE 0x00000040 /* CCIR656-16 hdr decode mode; 1=16b */
+#define VCR_CI_BSWAP 0x00000080 /* Swap bytes (16-bit) */
+#define VCR_CI_YUYV 0 /* Byte order 0123 */
+#define VCR_CI_UYVY 0x00000100 /* Byte order 1032 */
+#define VCR_CI_YVYU 0x00000200 /* Byte order 0321 */
+#define VCR_CI_VYUY 0x00000300 /* Byte order 3012 */
+#define VCR_CI_VIPTYPE 0x00000400 /* VIP type */
+#define VCR_CI_IFSEN 0x00000800 /* Input field signal enable */
+#define VCR_CI_DIODD 0 /* De-interlace odd, 30fps */
+#define VCR_CI_DIEVEN 0x00001000 /* ...even field, 30fps */
+#define VCR_CI_DIBOTH 0x00002000 /* ...both fields, 60fps */
+#define VCR_CI_DIBOTH30 0x00003000 /* ...both fields, 30fps interlace */
+#define VCR_CI_CONVTYPE 0x00004000 /* 4:2:2 to 4:4:4; 1 = interpolate */
+#define VCR_CI_CFC 0x00008000 /* Capture flipping control */
+#define VCR_CI_FILTER 0x00070000 /* Horiz filter mode select
+ 000 = none
+ 001 = 2 tap
+ 010 = 3 tap
+ 011 = 4 tap
+ 100 = 5 tap */
+#define VCR_CI_CLKINV 0x00080000 /* Input CLK inverted */
+#define VCR_CI_VREFINV 0x00100000 /* VREF inverted */
+#define VCR_CI_HREFINV 0x00200000 /* HREF inverted */
+#define VCR_CI_FLDINV 0x00400000 /* Field inverted */
+#define VCR_CI_CLKPIN 0x00800000 /* Capture clock pin */
+#define VCR_CI_THRESH 0x0f000000 /* Capture fifo threshold */
+#define VCR_CI_HRLE 0x10000000 /* Positive edge of HREF */
+#define VCR_CI_VRLE 0x20000000 /* Positive edge of VREF */
+#define VCR_CI_OFLDINV 0x40000000 /* Field output inverted */
+#define VCR_CI_CLKEN 0x80000000 /* Capture clock enable */
+
+#define VCR_HORRANGE 0x314 /* Active video horizontal range */
+#define VCR_VERTRANGE 0x318 /* Active video vertical range */
+#define VCR_AVSCALE 0x31c /* Active video scaling control */
+#define VCR_AVS_HEN 0x00000800 /* Horizontal scale enable */
+#define VCR_AVS_VEN 0x04000000 /* Vertical enable */
+#define VCR_VBIHOR 0x320 /* VBI Data horizontal range */
+#define VCR_VBIVERT 0x324 /* VBI data vertical range */
+#define VCR_VBIBUF1 0x328 /* First VBI buffer */
+#define VCR_VBISTRIDE 0x32c /* VBI stride */
+#define VCR_ANCDATACNT 0x330 /* Ancillary data count setting */
+#define VCR_MAXDATA 0x334 /* Active data count of active video */
+#define VCR_MAXVBI 0x338 /* Maximum data count of VBI */
+#define VCR_CAPDATA 0x33c /* Capture data count */
+#define VCR_VBUF1 0x340 /* First video buffer */
+#define VCR_VBUF2 0x344 /* Second video buffer */
+#define VCR_VBUF3 0x348 /* Third video buffer */
+#define VCR_VBUF_MASK 0x1ffffff0 /* Bits 28:4 */
+#define VCR_VBIBUF2 0x34c /* Second VBI buffer */
+#define VCR_VSTRIDE 0x350 /* Stride of video + coring control */
+#define VCR_VS_STRIDE_SHIFT 4
+#define VCR_VS_STRIDE 0x00001ff0 /* Stride (8-byte units) */
+#define VCR_VS_CCD 0x007f0000 /* Coring compare data */
+#define VCR_VS_COREEN 0x00800000 /* Coring enable */
+#define VCR_TS0ERR 0x354 /* TS buffer 0 error indicator */
+#define VCR_TS1ERR 0x358 /* TS buffer 0 error indicator */
+#define VCR_TS2ERR 0x35c /* TS buffer 0 error indicator */
+
+/* Add 0x1000 for the second capture engine registers */
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index 7d3378437ded..de4fa4eb8844 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -52,18 +52,18 @@ MODULE_LICENSE("GPL");
#define CALL(q, f, arg...) \
((q->int_ops->f) ? q->int_ops->f(arg) : 0)
-struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q)
+struct videobuf_buffer *videobuf_alloc_vb(struct videobuf_queue *q)
{
struct videobuf_buffer *vb;
BUG_ON(q->msize < sizeof(*vb));
- if (!q->int_ops || !q->int_ops->alloc) {
+ if (!q->int_ops || !q->int_ops->alloc_vb) {
printk(KERN_ERR "No specific ops defined!\n");
BUG();
}
- vb = q->int_ops->alloc(q->msize);
+ vb = q->int_ops->alloc_vb(q->msize);
if (NULL != vb) {
init_waitqueue_head(&vb->done);
vb->magic = MAGIC_BUFFER;
@@ -71,27 +71,48 @@ struct videobuf_buffer *videobuf_alloc(struct videobuf_queue *q)
return vb;
}
-EXPORT_SYMBOL_GPL(videobuf_alloc);
+EXPORT_SYMBOL_GPL(videobuf_alloc_vb);
-#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
- vb->state != VIDEOBUF_QUEUED)
-int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
+static int is_state_active_or_queued(struct videobuf_queue *q, struct videobuf_buffer *vb)
{
+ unsigned long flags;
+ bool rc;
+
+ spin_lock_irqsave(q->irqlock, flags);
+ rc = vb->state != VIDEOBUF_ACTIVE && vb->state != VIDEOBUF_QUEUED;
+ spin_unlock_irqrestore(q->irqlock, flags);
+ return rc;
+};
+
+int videobuf_waiton(struct videobuf_queue *q, struct videobuf_buffer *vb,
+ int non_blocking, int intr)
+{
+ bool is_ext_locked;
+ int ret = 0;
+
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
if (non_blocking) {
- if (WAITON_CONDITION)
+ if (is_state_active_or_queued(q, vb))
return 0;
- else
- return -EAGAIN;
+ return -EAGAIN;
}
+ is_ext_locked = q->ext_lock && mutex_is_locked(q->ext_lock);
+
+ /* Release vdev lock to prevent this wait from blocking outside access to
+ the device. */
+ if (is_ext_locked)
+ mutex_unlock(q->ext_lock);
if (intr)
- return wait_event_interruptible(vb->done, WAITON_CONDITION);
+ ret = wait_event_interruptible(vb->done, is_state_active_or_queued(q, vb));
else
- wait_event(vb->done, WAITON_CONDITION);
+ wait_event(vb->done, is_state_active_or_queued(q, vb));
+ /* Relock */
+ if (is_ext_locked)
+ mutex_lock(q->ext_lock);
- return 0;
+ return ret;
}
EXPORT_SYMBOL_GPL(videobuf_waiton);
@@ -125,11 +146,13 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
enum v4l2_field field,
unsigned int msize,
void *priv,
- struct videobuf_qtype_ops *int_ops)
+ struct videobuf_qtype_ops *int_ops,
+ struct mutex *ext_lock)
{
BUG_ON(!q);
memset(q, 0, sizeof(*q));
q->irqlock = irqlock;
+ q->ext_lock = ext_lock;
q->dev = dev;
q->type = type;
q->field = field;
@@ -195,6 +218,45 @@ int videobuf_queue_is_busy(struct videobuf_queue *q)
}
EXPORT_SYMBOL_GPL(videobuf_queue_is_busy);
+/**
+ * __videobuf_free() - free all the buffers and their control structures
+ *
+ * This function can only be called if streaming/reading is off, i.e. no buffers
+ * are under control of the driver.
+ */
+/* Locking: Caller holds q->vb_lock */
+static int __videobuf_free(struct videobuf_queue *q)
+{
+ int i;
+
+ dprintk(1, "%s\n", __func__);
+ if (!q)
+ return 0;
+
+ if (q->streaming || q->reading) {
+ dprintk(1, "Cannot free buffers when streaming or reading\n");
+ return -EBUSY;
+ }
+
+ MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++)
+ if (q->bufs[i] && q->bufs[i]->map) {
+ dprintk(1, "Cannot free mmapped buffers\n");
+ return -EBUSY;
+ }
+
+ for (i = 0; i < VIDEO_MAX_FRAME; i++) {
+ if (NULL == q->bufs[i])
+ continue;
+ q->ops->buf_release(q, q->bufs[i]);
+ kfree(q->bufs[i]);
+ q->bufs[i] = NULL;
+ }
+
+ return 0;
+}
+
/* Locking: Caller holds q->vb_lock */
void videobuf_queue_cancel(struct videobuf_queue *q)
{
@@ -308,37 +370,12 @@ static void videobuf_status(struct videobuf_queue *q, struct v4l2_buffer *b,
b->sequence = vb->field_count >> 1;
}
-/* Locking: Caller holds q->vb_lock */
-static int __videobuf_mmap_free(struct videobuf_queue *q)
-{
- int i;
-
- if (!q)
- return 0;
-
- MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
-
- for (i = 0; i < VIDEO_MAX_FRAME; i++)
- if (q->bufs[i] && q->bufs[i]->map)
- return -EBUSY;
-
- for (i = 0; i < VIDEO_MAX_FRAME; i++) {
- if (NULL == q->bufs[i])
- continue;
- q->ops->buf_release(q, q->bufs[i]);
- kfree(q->bufs[i]);
- q->bufs[i] = NULL;
- }
-
- return 0;
-}
-
int videobuf_mmap_free(struct videobuf_queue *q)
{
int ret;
- mutex_lock(&q->vb_lock);
- ret = __videobuf_mmap_free(q);
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_lock(q);
+ ret = __videobuf_free(q);
+ videobuf_queue_unlock(q);
return ret;
}
EXPORT_SYMBOL_GPL(videobuf_mmap_free);
@@ -353,13 +390,13 @@ int __videobuf_mmap_setup(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- err = __videobuf_mmap_free(q);
+ err = __videobuf_free(q);
if (0 != err)
return err;
/* Allocate and initialize buffers */
for (i = 0; i < bcount; i++) {
- q->bufs[i] = videobuf_alloc(q);
+ q->bufs[i] = videobuf_alloc_vb(q);
if (NULL == q->bufs[i])
break;
@@ -393,9 +430,9 @@ int videobuf_mmap_setup(struct videobuf_queue *q,
enum v4l2_memory memory)
{
int ret;
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
ret = __videobuf_mmap_setup(q, bcount, bsize, memory);
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return ret;
}
EXPORT_SYMBOL_GPL(videobuf_mmap_setup);
@@ -418,7 +455,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
return -EINVAL;
}
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
if (req->type != q->type) {
dprintk(1, "reqbufs: queue type invalid\n");
retval = -EINVAL;
@@ -455,7 +492,7 @@ int videobuf_reqbufs(struct videobuf_queue *q,
retval = 0;
done:
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return retval;
}
EXPORT_SYMBOL_GPL(videobuf_reqbufs);
@@ -464,7 +501,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
{
int ret = -EINVAL;
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
if (unlikely(b->type != q->type)) {
dprintk(1, "querybuf: Wrong type.\n");
goto done;
@@ -482,7 +519,7 @@ int videobuf_querybuf(struct videobuf_queue *q, struct v4l2_buffer *b)
ret = 0;
done:
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return ret;
}
EXPORT_SYMBOL_GPL(videobuf_querybuf);
@@ -499,7 +536,7 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
if (b->memory == V4L2_MEMORY_MMAP)
down_read(&current->mm->mmap_sem);
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
retval = -EBUSY;
if (q->reading) {
dprintk(1, "qbuf: Reading running...\n");
@@ -591,7 +628,7 @@ int videobuf_qbuf(struct videobuf_queue *q, struct v4l2_buffer *b)
wake_up_interruptible_sync(&q->wait);
done:
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
if (b->memory == V4L2_MEMORY_MMAP)
up_read(&current->mm->mmap_sem);
@@ -621,14 +658,14 @@ checks:
dprintk(2, "next_buffer: waiting on buffer\n");
/* Drop lock to avoid deadlock with qbuf */
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
/* Checking list_empty and streaming is safe without
* locks because we goto checks to validate while
* holding locks before proceeding */
retval = wait_event_interruptible(q->wait,
!list_empty(&q->stream) || !q->streaming);
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
if (retval)
goto done;
@@ -655,7 +692,7 @@ static int stream_next_buffer(struct videobuf_queue *q,
goto done;
buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
- retval = videobuf_waiton(buf, nonblocking, 1);
+ retval = videobuf_waiton(q, buf, nonblocking, 1);
if (retval < 0)
goto done;
@@ -673,7 +710,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
memset(b, 0, sizeof(*b));
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
retval = stream_next_buffer(q, &buf, nonblocking);
if (retval < 0) {
@@ -699,7 +736,7 @@ int videobuf_dqbuf(struct videobuf_queue *q,
buf->state = VIDEOBUF_IDLE;
b->flags &= ~V4L2_BUF_FLAG_DONE;
done:
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return retval;
}
EXPORT_SYMBOL_GPL(videobuf_dqbuf);
@@ -710,7 +747,7 @@ int videobuf_streamon(struct videobuf_queue *q)
unsigned long flags = 0;
int retval;
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
retval = -EBUSY;
if (q->reading)
goto done;
@@ -726,7 +763,7 @@ int videobuf_streamon(struct videobuf_queue *q)
wake_up_interruptible_sync(&q->wait);
done:
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return retval;
}
EXPORT_SYMBOL_GPL(videobuf_streamon);
@@ -746,9 +783,9 @@ int videobuf_streamoff(struct videobuf_queue *q)
{
int retval;
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
retval = __videobuf_streamoff(q);
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return retval;
}
@@ -766,7 +803,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
/* setup stuff */
- q->read_buf = videobuf_alloc(q);
+ q->read_buf = videobuf_alloc_vb(q);
if (NULL == q->read_buf)
return -ENOMEM;
@@ -783,7 +820,7 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, q->read_buf);
spin_unlock_irqrestore(q->irqlock, flags);
- retval = videobuf_waiton(q->read_buf, 0, 0);
+ retval = videobuf_waiton(q, q->read_buf, 0, 0);
if (0 == retval) {
CALL(q, sync, q, q->read_buf);
if (VIDEOBUF_ERROR == q->read_buf->state)
@@ -854,7 +891,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
q->ops->buf_setup(q, &nbufs, &size);
@@ -871,7 +908,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
if (NULL == q->read_buf) {
/* need to capture a new frame */
retval = -ENOMEM;
- q->read_buf = videobuf_alloc(q);
+ q->read_buf = videobuf_alloc_vb(q);
dprintk(1, "video alloc=0x%p\n", q->read_buf);
if (NULL == q->read_buf)
@@ -895,7 +932,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
/* wait until capture is done */
- retval = videobuf_waiton(q->read_buf, nonblocking, 1);
+ retval = videobuf_waiton(q, q->read_buf, nonblocking, 1);
if (0 != retval)
goto done;
@@ -924,7 +961,7 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
}
done:
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return retval;
}
EXPORT_SYMBOL_GPL(videobuf_read_one);
@@ -970,7 +1007,7 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
int i;
videobuf_queue_cancel(q);
- __videobuf_mmap_free(q);
+ __videobuf_free(q);
INIT_LIST_HEAD(&q->stream);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
@@ -985,9 +1022,9 @@ int videobuf_read_start(struct videobuf_queue *q)
{
int rc;
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
rc = __videobuf_read_start(q);
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return rc;
}
@@ -995,15 +1032,15 @@ EXPORT_SYMBOL_GPL(videobuf_read_start);
void videobuf_read_stop(struct videobuf_queue *q)
{
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
__videobuf_read_stop(q);
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
}
EXPORT_SYMBOL_GPL(videobuf_read_stop);
void videobuf_stop(struct videobuf_queue *q)
{
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
if (q->streaming)
__videobuf_streamoff(q);
@@ -1011,7 +1048,7 @@ void videobuf_stop(struct videobuf_queue *q)
if (q->reading)
__videobuf_read_stop(q);
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
}
EXPORT_SYMBOL_GPL(videobuf_stop);
@@ -1025,7 +1062,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
dprintk(2, "%s\n", __func__);
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
retval = -EBUSY;
if (q->streaming)
goto done;
@@ -1045,7 +1082,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
list_del(&q->read_buf->stream);
q->read_off = 0;
}
- rc = videobuf_waiton(q->read_buf, nonblocking, 1);
+ rc = videobuf_waiton(q, q->read_buf, nonblocking, 1);
if (rc < 0) {
if (0 == retval)
retval = rc;
@@ -1083,7 +1120,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
}
done:
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return retval;
}
EXPORT_SYMBOL_GPL(videobuf_read_stream);
@@ -1095,7 +1132,7 @@ unsigned int videobuf_poll_stream(struct file *file,
struct videobuf_buffer *buf = NULL;
unsigned int rc = 0;
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
if (q->streaming) {
if (!list_empty(&q->stream))
buf = list_entry(q->stream.next,
@@ -1133,7 +1170,7 @@ unsigned int videobuf_poll_stream(struct file *file,
}
}
}
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return rc;
}
EXPORT_SYMBOL_GPL(videobuf_poll_stream);
@@ -1150,7 +1187,7 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma)
return -EINVAL;
}
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
struct videobuf_buffer *buf = q->bufs[i];
@@ -1160,38 +1197,8 @@ int videobuf_mmap_mapper(struct videobuf_queue *q, struct vm_area_struct *vma)
break;
}
}
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
return rc;
}
EXPORT_SYMBOL_GPL(videobuf_mmap_mapper);
-
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-int videobuf_cgmbuf(struct videobuf_queue *q,
- struct video_mbuf *mbuf, int count)
-{
- struct v4l2_requestbuffers req;
- int rc, i;
-
- MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
-
- memset(&req, 0, sizeof(req));
- req.type = q->type;
- req.count = count;
- req.memory = V4L2_MEMORY_MMAP;
- rc = videobuf_reqbufs(q, &req);
- if (rc < 0)
- return rc;
-
- mbuf->frames = req.count;
- mbuf->size = 0;
- for (i = 0; i < mbuf->frames; i++) {
- mbuf->offsets[i] = q->bufs[i]->boff;
- mbuf->size += PAGE_ALIGN(q->bufs[i]->bsize);
- }
-
- return 0;
-}
-EXPORT_SYMBOL_GPL(videobuf_cgmbuf);
-#endif
-
diff --git a/drivers/media/video/videobuf-dma-contig.c b/drivers/media/video/videobuf-dma-contig.c
index 74730c624cfc..c9691115f2d2 100644
--- a/drivers/media/video/videobuf-dma-contig.c
+++ b/drivers/media/video/videobuf-dma-contig.c
@@ -28,7 +28,6 @@ struct videobuf_dma_contig_memory {
void *vaddr;
dma_addr_t dma_handle;
unsigned long size;
- int is_userptr;
};
#define MAGIC_DC_MEM 0x0733ac61
@@ -63,7 +62,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
struct videobuf_dma_contig_memory *mem;
dev_dbg(q->dev, "munmap %p q=%p\n", map, q);
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
/* We need first to cancel streams, before unmapping */
if (q->streaming)
@@ -103,7 +102,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
kfree(map);
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
}
}
@@ -120,7 +119,6 @@ static const struct vm_operations_struct videobuf_vm_ops = {
*/
static void videobuf_dma_contig_user_put(struct videobuf_dma_contig_memory *mem)
{
- mem->is_userptr = 0;
mem->dma_handle = 0;
mem->size = 0;
}
@@ -147,7 +145,6 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
offset = vb->baddr & ~PAGE_MASK;
mem->size = PAGE_ALIGN(vb->size + offset);
- mem->is_userptr = 0;
ret = -EINVAL;
down_read(&mm->mmap_sem);
@@ -181,16 +178,13 @@ static int videobuf_dma_contig_user_get(struct videobuf_dma_contig_memory *mem,
pages_done++;
}
- if (!ret)
- mem->is_userptr = 1;
-
out_up:
up_read(&current->mm->mmap_sem);
return ret;
}
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
{
struct videobuf_dma_contig_memory *mem;
struct videobuf_buffer *vb;
@@ -280,8 +274,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
return -ENOMEM;
buf->map = map;
- map->start = vma->vm_start;
- map->end = vma->vm_end;
map->q = q;
buf->baddr = vma->vm_start;
@@ -338,7 +330,7 @@ error:
static struct videobuf_qtype_ops qops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc = __videobuf_alloc,
+ .alloc_vb = __videobuf_alloc_vb,
.iolock = __videobuf_iolock,
.mmap_mapper = __videobuf_mmap_mapper,
.vaddr = __videobuf_to_vaddr,
@@ -351,10 +343,11 @@ void videobuf_queue_dma_contig_init(struct videobuf_queue *q,
enum v4l2_buf_type type,
enum v4l2_field field,
unsigned int msize,
- void *priv)
+ void *priv,
+ struct mutex *ext_lock)
{
videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
- priv, &qops);
+ priv, &qops, ext_lock);
}
EXPORT_SYMBOL_GPL(videobuf_queue_dma_contig_init);
@@ -395,8 +388,10 @@ void videobuf_dma_contig_free(struct videobuf_queue *q,
}
/* read() method */
- dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
- mem->vaddr = NULL;
+ if (mem->vaddr) {
+ dma_free_coherent(q->dev, mem->size, mem->vaddr, mem->dma_handle);
+ mem->vaddr = NULL;
+ }
}
EXPORT_SYMBOL_GPL(videobuf_dma_contig_free);
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 8359e6badd36..ddb8f4b46c03 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -57,16 +57,21 @@ MODULE_LICENSE("GPL");
/* --------------------------------------------------------------------- */
-struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt, int nr_pages)
+/*
+ * Return a scatterlist for some page-aligned vmalloc()'ed memory
+ * block (NULL on errors). Memory for the scatterlist is allocated
+ * using kmalloc. The caller must free the memory.
+ */
+static struct scatterlist *videobuf_vmalloc_to_sg(unsigned char *virt,
+ int nr_pages)
{
struct scatterlist *sglist;
struct page *pg;
int i;
- sglist = vmalloc(nr_pages * sizeof(*sglist));
+ sglist = vzalloc(nr_pages * sizeof(*sglist));
if (NULL == sglist)
return NULL;
- memset(sglist, 0, nr_pages * sizeof(*sglist));
sg_init_table(sglist, nr_pages);
for (i = 0; i < nr_pages; i++, virt += PAGE_SIZE) {
pg = vmalloc_to_page(virt);
@@ -81,10 +86,14 @@ err:
vfree(sglist);
return NULL;
}
-EXPORT_SYMBOL_GPL(videobuf_vmalloc_to_sg);
-struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
- int offset)
+/*
+ * Return a scatterlist for a an array of userpages (NULL on errors).
+ * Memory for the scatterlist is allocated using kmalloc. The caller
+ * must free the memory.
+ */
+static struct scatterlist *videobuf_pages_to_sg(struct page **pages,
+ int nr_pages, int offset, size_t size)
{
struct scatterlist *sglist;
int i;
@@ -100,12 +109,14 @@ struct scatterlist *videobuf_pages_to_sg(struct page **pages, int nr_pages,
/* DMA to highmem pages might not work */
goto highmem;
sg_set_page(&sglist[0], pages[0], PAGE_SIZE - offset, offset);
+ size -= PAGE_SIZE - offset;
for (i = 1; i < nr_pages; i++) {
if (NULL == pages[i])
goto nopage;
if (PageHighMem(pages[i]))
goto highmem;
- sg_set_page(&sglist[i], pages[i], PAGE_SIZE, 0);
+ sg_set_page(&sglist[i], pages[i], min_t(size_t, PAGE_SIZE, size), 0);
+ size -= min_t(size_t, PAGE_SIZE, size);
}
return sglist;
@@ -160,7 +171,8 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
first = (data & PAGE_MASK) >> PAGE_SHIFT;
last = ((data+size-1) & PAGE_MASK) >> PAGE_SHIFT;
- dma->offset = data & ~PAGE_MASK;
+ dma->offset = data & ~PAGE_MASK;
+ dma->size = size;
dma->nr_pages = last-first+1;
dma->pages = kmalloc(dma->nr_pages * sizeof(struct page *), GFP_KERNEL);
if (NULL == dma->pages)
@@ -201,17 +213,17 @@ int videobuf_dma_init_kernel(struct videobuf_dmabuf *dma, int direction,
dprintk(1, "init kernel [%d pages]\n", nr_pages);
dma->direction = direction;
- dma->vmalloc = vmalloc_32(nr_pages << PAGE_SHIFT);
- if (NULL == dma->vmalloc) {
+ dma->vaddr = vmalloc_32(nr_pages << PAGE_SHIFT);
+ if (NULL == dma->vaddr) {
dprintk(1, "vmalloc_32(%d pages) failed\n", nr_pages);
return -ENOMEM;
}
dprintk(1, "vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)dma->vmalloc,
+ (unsigned long)dma->vaddr,
nr_pages << PAGE_SHIFT);
- memset(dma->vmalloc, 0, nr_pages << PAGE_SHIFT);
+ memset(dma->vaddr, 0, nr_pages << PAGE_SHIFT);
dma->nr_pages = nr_pages;
return 0;
@@ -235,17 +247,17 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
}
EXPORT_SYMBOL_GPL(videobuf_dma_init_overlay);
-int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
{
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
BUG_ON(0 == dma->nr_pages);
if (dma->pages) {
dma->sglist = videobuf_pages_to_sg(dma->pages, dma->nr_pages,
- dma->offset);
+ dma->offset, dma->size);
}
- if (dma->vmalloc) {
- dma->sglist = videobuf_vmalloc_to_sg(dma->vmalloc,
+ if (dma->vaddr) {
+ dma->sglist = videobuf_vmalloc_to_sg(dma->vaddr,
dma->nr_pages);
}
if (dma->bus_addr) {
@@ -263,7 +275,7 @@ int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
return -ENOMEM;
}
if (!dma->bus_addr) {
- dma->sglen = dma_map_sg(q->dev, dma->sglist,
+ dma->sglen = dma_map_sg(dev, dma->sglist,
dma->nr_pages, dma->direction);
if (0 == dma->sglen) {
printk(KERN_WARNING
@@ -279,14 +291,14 @@ int videobuf_dma_map(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
}
EXPORT_SYMBOL_GPL(videobuf_dma_map);
-int videobuf_dma_unmap(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
+int videobuf_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
{
MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
if (!dma->sglen)
return 0;
- dma_unmap_sg(q->dev, dma->sglist, dma->sglen, dma->direction);
+ dma_unmap_sg(dev, dma->sglist, dma->sglen, dma->direction);
vfree(dma->sglist);
dma->sglist = NULL;
@@ -309,8 +321,8 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
dma->pages = NULL;
}
- vfree(dma->vmalloc);
- dma->vmalloc = NULL;
+ vfree(dma->vaddr);
+ dma->vaddr = NULL;
if (dma->bus_addr)
dma->bus_addr = 0;
@@ -322,28 +334,6 @@ EXPORT_SYMBOL_GPL(videobuf_dma_free);
/* --------------------------------------------------------------------- */
-int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
-{
- struct videobuf_queue q;
-
- q.dev = dev;
-
- return videobuf_dma_map(&q, dma);
-}
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);
-
-int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
-{
- struct videobuf_queue q;
-
- q.dev = dev;
-
- return videobuf_dma_unmap(&q, dma);
-}
-EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);
-
-/* --------------------------------------------------------------------- */
-
static void videobuf_vm_open(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
@@ -367,7 +357,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
map->count--;
if (0 == map->count) {
dprintk(1, "munmap %p q=%p\n", map, q);
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -383,7 +373,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
q->bufs[i]->baddr = 0;
q->ops->buf_release(q, q->bufs[i]);
}
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
kfree(map);
}
return;
@@ -428,7 +418,7 @@ static const struct vm_operations_struct videobuf_vm_ops = {
struct videobuf_dma_sg_memory
*/
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
{
struct videobuf_dma_sg_memory *mem;
struct videobuf_buffer *vb;
@@ -456,7 +446,7 @@ static void *__videobuf_to_vaddr(struct videobuf_buffer *buf)
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
- return mem->dma.vmalloc;
+ return mem->dma.vaddr;
}
static int __videobuf_iolock(struct videobuf_queue *q,
@@ -520,7 +510,7 @@ static int __videobuf_iolock(struct videobuf_queue *q,
default:
BUG();
}
- err = videobuf_dma_map(q, &mem->dma);
+ err = videobuf_dma_map(q->dev, &mem->dma);
if (0 != err)
return err;
@@ -553,14 +543,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
retval = -EINVAL;
- /* This function maintains backwards compatibility with V4L1 and will
- * map more than one buffer if the vma length is equal to the combined
- * size of multiple buffers than it will map them together. See
- * VIDIOCGMBUF in the v4l spec
- *
- * TODO: Allow drivers to specify if they support this mode
- */
-
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
@@ -580,29 +562,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
}
last = first;
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- if (size != (vma->vm_end - vma->vm_start)) {
- /* look for last buffer to map */
- for (last = first + 1; last < VIDEO_MAX_FRAME; last++) {
- if (NULL == q->bufs[last])
- continue;
- if (V4L2_MEMORY_MMAP != q->bufs[last]->memory)
- continue;
- if (q->bufs[last]->map) {
- retval = -EBUSY;
- goto done;
- }
- size += PAGE_ALIGN(q->bufs[last]->bsize);
- if (size == (vma->vm_end - vma->vm_start))
- break;
- }
- if (VIDEO_MAX_FRAME == last) {
- dprintk(1, "mmap app bug: size invalid [size=0x%lx]\n",
- (vma->vm_end - vma->vm_start));
- goto done;
- }
- }
-#endif
/* create mapping + update buffer list */
retval = -ENOMEM;
@@ -620,8 +579,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
}
map->count = 1;
- map->start = vma->vm_start;
- map->end = vma->vm_end;
map->q = q;
vma->vm_ops = &videobuf_vm_ops;
vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
@@ -638,7 +595,7 @@ done:
static struct videobuf_qtype_ops sg_ops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc = __videobuf_alloc,
+ .alloc_vb = __videobuf_alloc_vb,
.iolock = __videobuf_iolock,
.sync = __videobuf_sync,
.mmap_mapper = __videobuf_mmap_mapper,
@@ -654,7 +611,7 @@ void *videobuf_sg_alloc(size_t size)
q.msize = size;
- return videobuf_alloc(&q);
+ return videobuf_alloc_vb(&q);
}
EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
@@ -665,10 +622,11 @@ void videobuf_queue_sg_init(struct videobuf_queue *q,
enum v4l2_buf_type type,
enum v4l2_field field,
unsigned int msize,
- void *priv)
+ void *priv,
+ struct mutex *ext_lock)
{
videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
- priv, &sg_ops);
+ priv, &sg_ops, ext_lock);
}
EXPORT_SYMBOL_GPL(videobuf_queue_sg_init);
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index 3f76398968b8..3de7c7e4402d 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -57,7 +57,7 @@ static int videobuf_dvb_thread(void *data)
buf = list_entry(dvb->dvbq.stream.next,
struct videobuf_buffer, stream);
list_del(&buf->stream);
- err = videobuf_waiton(buf,0,1);
+ err = videobuf_waiton(&dvb->dvbq, buf, 0, 1);
/* no more feeds left or stop_feed() asked us to quit */
if (0 == dvb->nfeeds)
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 583728f4c221..df142580e44c 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -75,7 +75,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
struct videobuf_vmalloc_memory *mem;
dprintk(1, "munmap %p q=%p\n", map, q);
- mutex_lock(&q->vb_lock);
+ videobuf_queue_lock(q);
/* We need first to cancel streams, before unmapping */
if (q->streaming)
@@ -102,10 +102,10 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
called with IRQ's disabled
*/
dprintk(1, "%s: buf[%d] freeing (%p)\n",
- __func__, i, mem->vmalloc);
+ __func__, i, mem->vaddr);
- vfree(mem->vmalloc);
- mem->vmalloc = NULL;
+ vfree(mem->vaddr);
+ mem->vaddr = NULL;
}
q->bufs[i]->map = NULL;
@@ -114,7 +114,7 @@ static void videobuf_vm_close(struct vm_area_struct *vma)
kfree(map);
- mutex_unlock(&q->vb_lock);
+ videobuf_queue_unlock(q);
}
return;
@@ -135,7 +135,7 @@ static const struct vm_operations_struct videobuf_vm_ops = {
struct videobuf_dma_sg_memory
*/
-static struct videobuf_buffer *__videobuf_alloc(size_t size)
+static struct videobuf_buffer *__videobuf_alloc_vb(size_t size)
{
struct videobuf_vmalloc_memory *mem;
struct videobuf_buffer *vb;
@@ -170,7 +170,7 @@ static int __videobuf_iolock(struct videobuf_queue *q,
dprintk(1, "%s memory method MMAP\n", __func__);
/* All handling should be done by __videobuf_mmap_mapper() */
- if (!mem->vmalloc) {
+ if (!mem->vaddr) {
printk(KERN_ERR "memory is not alloced/mmapped.\n");
return -EINVAL;
}
@@ -189,13 +189,13 @@ static int __videobuf_iolock(struct videobuf_queue *q,
* read() method.
*/
- mem->vmalloc = vmalloc_user(pages);
- if (!mem->vmalloc) {
+ mem->vaddr = vmalloc_user(pages);
+ if (!mem->vaddr) {
printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
return -ENOMEM;
}
dprintk(1, "vmalloc is at addr %p (%d pages)\n",
- mem->vmalloc, pages);
+ mem->vaddr, pages);
#if 0
int rc;
@@ -245,8 +245,6 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
return -ENOMEM;
buf->map = map;
- map->start = vma->vm_start;
- map->end = vma->vm_end;
map->q = q;
buf->baddr = vma->vm_start;
@@ -256,18 +254,18 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
- mem->vmalloc = vmalloc_user(pages);
- if (!mem->vmalloc) {
+ mem->vaddr = vmalloc_user(pages);
+ if (!mem->vaddr) {
printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
goto error;
}
- dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vmalloc, pages);
+ dprintk(1, "vmalloc is at addr %p (%d pages)\n", mem->vaddr, pages);
/* Try to remap memory */
- retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
+ retval = remap_vmalloc_range(vma, mem->vaddr, 0);
if (retval < 0) {
printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
- vfree(mem->vmalloc);
+ vfree(mem->vaddr);
goto error;
}
@@ -293,7 +291,7 @@ error:
static struct videobuf_qtype_ops qops = {
.magic = MAGIC_QTYPE_OPS,
- .alloc = __videobuf_alloc,
+ .alloc_vb = __videobuf_alloc_vb,
.iolock = __videobuf_iolock,
.mmap_mapper = __videobuf_mmap_mapper,
.vaddr = videobuf_to_vmalloc,
@@ -306,10 +304,11 @@ void videobuf_queue_vmalloc_init(struct videobuf_queue *q,
enum v4l2_buf_type type,
enum v4l2_field field,
unsigned int msize,
- void *priv)
+ void *priv,
+ struct mutex *ext_lock)
{
videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
- priv, &qops);
+ priv, &qops, ext_lock);
}
EXPORT_SYMBOL_GPL(videobuf_queue_vmalloc_init);
@@ -319,7 +318,7 @@ void *videobuf_to_vmalloc(struct videobuf_buffer *buf)
BUG_ON(!mem);
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
- return mem->vmalloc;
+ return mem->vaddr;
}
EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
@@ -341,8 +340,8 @@ void videobuf_vmalloc_free(struct videobuf_buffer *buf)
MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
- vfree(mem->vmalloc);
- mem->vmalloc = NULL;
+ vfree(mem->vaddr);
+ mem->vaddr = NULL;
return;
}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 3eb15f72ac09..d63e9d978493 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -2954,9 +2954,6 @@ static int vino_enum_input(struct file *file, void *__fh,
if (input == VINO_INPUT_NONE)
return -EINVAL;
- memset(i, 0, sizeof(struct v4l2_input));
-
- i->index = index;
i->type = V4L2_INPUT_TYPE_CAMERA;
i->std = vino_inputs[input].std;
strcpy(i->name, vino_inputs[input].name);
@@ -4334,10 +4331,10 @@ static int __init vino_module_init(void)
vino_drvdata->decoder =
v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- "saa7191", "saa7191", 0, I2C_ADDRS(0x45));
+ "saa7191", 0, I2C_ADDRS(0x45));
vino_drvdata->camera =
v4l2_i2c_new_subdev(&vino_drvdata->v4l2_dev, &vino_i2c_adapter,
- "indycam", "indycam", 0, I2C_ADDRS(0x2b));
+ "indycam", 0, I2C_ADDRS(0x2b));
dprintk("init complete!\n");
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index e17b6fee046b..c49c39386bd0 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -820,14 +820,11 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_dev *dev = video_drvdata(file);
- struct videobuf_queue *q = &dev->vb_vidq;
int ret = vidioc_try_fmt_vid_cap(file, priv, f);
if (ret < 0)
return ret;
- mutex_lock(&q->vb_lock);
-
if (vivi_is_generating(dev)) {
dprintk(dev, 1, "%s device busy\n", __func__);
ret = -EBUSY;
@@ -840,7 +837,6 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
dev->vb_vidq.field = f->fmt.pix.field;
ret = 0;
out:
- mutex_unlock(&q->vb_lock);
return ret;
}
@@ -874,15 +870,6 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
file->f_flags & O_NONBLOCK);
}
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
-{
- struct vivi_dev *dev = video_drvdata(file);
-
- return videobuf_cgmbuf(&dev->vb_vidq, mbuf, 8);
-}
-#endif
-
static int vidioc_streamon(struct file *file, void *priv, enum v4l2_buf_type i)
{
struct vivi_dev *dev = video_drvdata(file);
@@ -1086,7 +1073,7 @@ static const struct v4l2_file_operations vivi_fops = {
.release = vivi_close,
.read = vivi_read,
.poll = vivi_poll,
- .ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .unlocked_ioctl = video_ioctl2, /* V4L2 ioctl handler */
.mmap = vivi_mmap,
};
@@ -1109,9 +1096,6 @@ static const struct v4l2_ioctl_ops vivi_ioctl_ops = {
.vidioc_queryctrl = vidioc_queryctrl,
.vidioc_g_ctrl = vidioc_g_ctrl,
.vidioc_s_ctrl = vidioc_s_ctrl,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidiocgmbuf = vidiocgmbuf,
-#endif
};
static struct video_device vivi_template = {
@@ -1173,19 +1157,19 @@ static int __init vivi_create_instance(int inst)
dev->saturation = 127;
dev->hue = 0;
+ /* initialize locks */
+ spin_lock_init(&dev->slock);
+ mutex_init(&dev->mutex);
+
videobuf_queue_vmalloc_init(&dev->vb_vidq, &vivi_video_qops,
NULL, &dev->slock, V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
- sizeof(struct vivi_buffer), dev);
+ sizeof(struct vivi_buffer), dev, &dev->mutex);
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
init_waitqueue_head(&dev->vidq.wq);
- /* initialize locks */
- spin_lock_init(&dev->slock);
- mutex_init(&dev->mutex);
-
ret = -ENOMEM;
vfd = video_device_alloc();
if (!vfd)
@@ -1194,6 +1178,7 @@ static int __init vivi_create_instance(int inst)
*vfd = vivi_template;
vfd->debug = debug;
vfd->v4l2_dev = &dev->v4l2_dev;
+ vfd->lock = &dev->mutex;
ret = video_register_device(vfd, VFL_TYPE_GRABBER, video_nr);
if (ret < 0)
diff --git a/drivers/media/video/vp27smpx.c b/drivers/media/video/vp27smpx.c
index ca8303bd2401..c15efb6e7771 100644
--- a/drivers/media/video/vp27smpx.c
+++ b/drivers/media/video/vp27smpx.c
@@ -27,11 +27,9 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("vp27smpx driver");
MODULE_AUTHOR("Hans Verkuil");
@@ -200,9 +198,25 @@ static const struct i2c_device_id vp27smpx_id[] = {
};
MODULE_DEVICE_TABLE(i2c, vp27smpx_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "vp27smpx",
- .probe = vp27smpx_probe,
- .remove = vp27smpx_remove,
- .id_table = vp27smpx_id,
+static struct i2c_driver vp27smpx_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "vp27smpx",
+ },
+ .probe = vp27smpx_probe,
+ .remove = vp27smpx_remove,
+ .id_table = vp27smpx_id,
};
+
+static __init int init_vp27smpx(void)
+{
+ return i2c_add_driver(&vp27smpx_driver);
+}
+
+static __exit void exit_vp27smpx(void)
+{
+ i2c_del_driver(&vp27smpx_driver);
+}
+
+module_init(init_vp27smpx);
+module_exit(exit_vp27smpx);
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index 77ebcea7c3da..91a01b3cdf8c 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -28,7 +28,6 @@
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
MODULE_DESCRIPTION("vpx3220a/vpx3216b/vpx3214c video decoder driver");
MODULE_AUTHOR("Laurent Pinchart");
@@ -614,9 +613,25 @@ static const struct i2c_device_id vpx3220_id[] = {
};
MODULE_DEVICE_TABLE(i2c, vpx3220_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "vpx3220",
- .probe = vpx3220_probe,
- .remove = vpx3220_remove,
- .id_table = vpx3220_id,
+static struct i2c_driver vpx3220_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "vpx3220",
+ },
+ .probe = vpx3220_probe,
+ .remove = vpx3220_remove,
+ .id_table = vpx3220_id,
};
+
+static __init int init_vpx3220(void)
+{
+ return i2c_add_driver(&vpx3220_driver);
+}
+
+static __exit void exit_vpx3220(void)
+{
+ i2c_del_driver(&vpx3220_driver);
+}
+
+module_init(init_vpx3220);
+module_exit(exit_vpx3220);
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 635420d8d84a..fa35639d0c15 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -815,7 +815,7 @@ out:
static const struct v4l2_file_operations w9966_fops = {
.owner = THIS_MODULE,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = video_ioctl2,
.read = w9966_v4l_read,
};
@@ -937,6 +937,7 @@ static void w9966_term(struct w9966 *cam)
parport_unregister_device(cam->pdev);
w9966_set_state(cam, W9966_STATE_PDEV, 0);
}
+ memset(cam, 0, sizeof(*cam));
}
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
deleted file mode 100644
index d807eea91757..000000000000
--- a/drivers/media/video/w9968cf.c
+++ /dev/null
@@ -1,3620 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. *
- * *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * - Memory management code from bttv driver by Ralph Metzler, *
- * Marcus Metzler and Gerd Knorr. *
- * - I2C interface to kernel, high-level image sensor control routines and *
- * some symbolic names from OV511 driver by Mark W. McClelland. *
- * - Low-level I2C fast write function by Piotr Czerczak. *
- * - Low-level I2C read function by Frederic Jouault. *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/kernel.h>
-#include <linux/kmod.h>
-#include <linux/init.h>
-#include <linux/fs.h>
-#include <linux/vmalloc.h>
-#include <linux/slab.h>
-#include <linux/mm.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/sched.h>
-#include <linux/ioctl.h>
-#include <linux/delay.h>
-#include <linux/stddef.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-#include <linux/page-flags.h>
-#include <linux/videodev.h>
-#include <media/v4l2-ioctl.h>
-
-#include "w9968cf.h"
-#include "w9968cf_decoder.h"
-
-static struct w9968cf_vpp_t* w9968cf_vpp;
-static DECLARE_WAIT_QUEUE_HEAD(w9968cf_vppmod_wait);
-
-static LIST_HEAD(w9968cf_dev_list); /* head of V4L registered cameras list */
-static DEFINE_MUTEX(w9968cf_devlist_mutex); /* semaphore for list traversal */
-
-static DECLARE_RWSEM(w9968cf_disconnect); /* prevent races with open() */
-
-
-/****************************************************************************
- * Module macros and parameters *
- ****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, winbond_id_table);
-
-MODULE_AUTHOR(W9968CF_MODULE_AUTHOR" "W9968CF_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(W9968CF_MODULE_NAME);
-MODULE_VERSION(W9968CF_MODULE_VERSION);
-MODULE_LICENSE(W9968CF_MODULE_LICENSE);
-MODULE_SUPPORTED_DEVICE("Video");
-
-static unsigned short simcams = W9968CF_SIMCAMS;
-static short video_nr[]={[0 ... W9968CF_MAX_DEVICES-1] = -1}; /*-1=first free*/
-static unsigned int packet_size[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_PACKET_SIZE};
-static unsigned short max_buffers[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_BUFFERS};
-static int double_buffer[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_DOUBLE_BUFFER};
-static int clamping[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLAMPING};
-static unsigned short filter_type[]= {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_FILTER_TYPE};
-static int largeview[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_LARGEVIEW};
-static unsigned short decompression[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_DECOMPRESSION};
-static int upscaling[]= {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_UPSCALING};
-static unsigned short force_palette[] = {[0 ... W9968CF_MAX_DEVICES-1] = 0};
-static int force_rgb[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_FORCE_RGB};
-static int autobright[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOBRIGHT};
-static int autoexp[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_AUTOEXP};
-static unsigned short lightfreq[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_LIGHTFREQ};
-static int bandingfilter[] = {[0 ... W9968CF_MAX_DEVICES-1]=
- W9968CF_BANDINGFILTER};
-static short clockdiv[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_CLOCKDIV};
-static int backlight[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_BACKLIGHT};
-static int mirror[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_MIRROR};
-static int monochrome[] = {[0 ... W9968CF_MAX_DEVICES-1]=W9968CF_MONOCHROME};
-static unsigned int brightness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_BRIGHTNESS};
-static unsigned int hue[] = {[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_HUE};
-static unsigned int colour[]={[0 ... W9968CF_MAX_DEVICES-1] = W9968CF_COLOUR};
-static unsigned int contrast[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_CONTRAST};
-static unsigned int whiteness[] = {[0 ... W9968CF_MAX_DEVICES-1] =
- W9968CF_WHITENESS};
-#ifdef W9968CF_DEBUG
-static unsigned short debug = W9968CF_DEBUG_LEVEL;
-static int specific_debug = W9968CF_SPECIFIC_DEBUG;
-#endif
-
-static unsigned int param_nv[24]; /* number of values per parameter */
-
-module_param(simcams, ushort, 0644);
-module_param_array(video_nr, short, &param_nv[0], 0444);
-module_param_array(packet_size, uint, &param_nv[1], 0444);
-module_param_array(max_buffers, ushort, &param_nv[2], 0444);
-module_param_array(double_buffer, bool, &param_nv[3], 0444);
-module_param_array(clamping, bool, &param_nv[4], 0444);
-module_param_array(filter_type, ushort, &param_nv[5], 0444);
-module_param_array(largeview, bool, &param_nv[6], 0444);
-module_param_array(decompression, ushort, &param_nv[7], 0444);
-module_param_array(upscaling, bool, &param_nv[8], 0444);
-module_param_array(force_palette, ushort, &param_nv[9], 0444);
-module_param_array(force_rgb, ushort, &param_nv[10], 0444);
-module_param_array(autobright, bool, &param_nv[11], 0444);
-module_param_array(autoexp, bool, &param_nv[12], 0444);
-module_param_array(lightfreq, ushort, &param_nv[13], 0444);
-module_param_array(bandingfilter, bool, &param_nv[14], 0444);
-module_param_array(clockdiv, short, &param_nv[15], 0444);
-module_param_array(backlight, bool, &param_nv[16], 0444);
-module_param_array(mirror, bool, &param_nv[17], 0444);
-module_param_array(monochrome, bool, &param_nv[18], 0444);
-module_param_array(brightness, uint, &param_nv[19], 0444);
-module_param_array(hue, uint, &param_nv[20], 0444);
-module_param_array(colour, uint, &param_nv[21], 0444);
-module_param_array(contrast, uint, &param_nv[22], 0444);
-module_param_array(whiteness, uint, &param_nv[23], 0444);
-#ifdef W9968CF_DEBUG
-module_param(debug, ushort, 0644);
-module_param(specific_debug, bool, 0644);
-#endif
-
-MODULE_PARM_DESC(simcams,
- "\n<n> Number of cameras allowed to stream simultaneously."
- "\nn may vary from 0 to "
- __MODULE_STRING(W9968CF_MAX_DEVICES)"."
- "\nDefault value is "__MODULE_STRING(W9968CF_SIMCAMS)"."
- "\n");
-MODULE_PARM_DESC(video_nr,
- "\n<-1|n[,...]> Specify V4L minor mode number."
- "\n -1 = use next available (default)"
- "\n n = use minor number n (integer >= 0)"
- "\nYou can specify up to "__MODULE_STRING(W9968CF_MAX_DEVICES)
- " cameras this way."
- "\nFor example:"
- "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
- "\nthe second camera and use auto for the first"
- "\none and for every other camera."
- "\n");
-MODULE_PARM_DESC(packet_size,
- "\n<n[,...]> Specify the maximum data payload"
- "\nsize in bytes for alternate settings, for each device."
- "\nn is scaled between 63 and 1023 "
- "(default is "__MODULE_STRING(W9968CF_PACKET_SIZE)")."
- "\n");
-MODULE_PARM_DESC(max_buffers,
- "\n<n[,...]> For advanced users."
- "\nSpecify the maximum number of video frame buffers"
- "\nto allocate for each device, from 2 to "
- __MODULE_STRING(W9968CF_MAX_BUFFERS)
- ". (default is "__MODULE_STRING(W9968CF_BUFFERS)")."
- "\n");
-MODULE_PARM_DESC(double_buffer,
- "\n<0|1[,...]> "
- "Hardware double buffering: 0 disabled, 1 enabled."
- "\nIt should be enabled if you want smooth video output: if"
- "\nyou obtain out of sync. video, disable it, or try to"
- "\ndecrease the 'clockdiv' module parameter value."
- "\nDefault value is "__MODULE_STRING(W9968CF_DOUBLE_BUFFER)
- " for every device."
- "\n");
-MODULE_PARM_DESC(clamping,
- "\n<0|1[,...]> Video data clamping: 0 disabled, 1 enabled."
- "\nDefault value is "__MODULE_STRING(W9968CF_CLAMPING)
- " for every device."
- "\n");
-MODULE_PARM_DESC(filter_type,
- "\n<0|1|2[,...]> Video filter type."
- "\n0 none, 1 (1-2-1) 3-tap filter, "
- "2 (2-3-6-3-2) 5-tap filter."
- "\nDefault value is "__MODULE_STRING(W9968CF_FILTER_TYPE)
- " for every device."
- "\nThe filter is used to reduce noise and aliasing artifacts"
- "\nproduced by the CCD or CMOS image sensor, and the scaling"
- " process."
- "\n");
-MODULE_PARM_DESC(largeview,
- "\n<0|1[,...]> Large view: 0 disabled, 1 enabled."
- "\nDefault value is "__MODULE_STRING(W9968CF_LARGEVIEW)
- " for every device."
- "\n");
-MODULE_PARM_DESC(upscaling,
- "\n<0|1[,...]> Software scaling (for non-compressed video):"
- "\n0 disabled, 1 enabled."
- "\nDisable it if you have a slow CPU or you don't have"
- " enough memory."
- "\nDefault value is "__MODULE_STRING(W9968CF_UPSCALING)
- " for every device."
- "\nIf 'w9968cf-vpp' is not present, this parameter is"
- " set to 0."
- "\n");
-MODULE_PARM_DESC(decompression,
- "\n<0|1|2[,...]> Software video decompression:"
- "\n- 0 disables decompression (doesn't allow formats needing"
- " decompression)"
- "\n- 1 forces decompression (allows formats needing"
- " decompression only);"
- "\n- 2 allows any permitted formats."
- "\nFormats supporting compressed video are YUV422P and"
- " YUV420P/YUV420 "
- "\nin any resolutions where both width and height are "
- "a multiple of 16."
- "\nDefault value is "__MODULE_STRING(W9968CF_DECOMPRESSION)
- " for every device."
- "\nIf 'w9968cf-vpp' is not present, forcing decompression is "
- "\nnot allowed; in this case this parameter is set to 2."
- "\n");
-MODULE_PARM_DESC(force_palette,
- "\n<0"
- "|" __MODULE_STRING(VIDEO_PALETTE_UYVY)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUV420)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUV422P)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUV420P)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUYV)
- "|" __MODULE_STRING(VIDEO_PALETTE_YUV422)
- "|" __MODULE_STRING(VIDEO_PALETTE_GREY)
- "|" __MODULE_STRING(VIDEO_PALETTE_RGB555)
- "|" __MODULE_STRING(VIDEO_PALETTE_RGB565)
- "|" __MODULE_STRING(VIDEO_PALETTE_RGB24)
- "|" __MODULE_STRING(VIDEO_PALETTE_RGB32)
- "[,...]>"
- " Force picture palette."
- "\nIn order:"
- "\n- 0 allows any of the following formats:"
- "\n- UYVY 16 bpp - Original video, compression disabled"
- "\n- YUV420 12 bpp - Original video, compression enabled"
- "\n- YUV422P 16 bpp - Original video, compression enabled"
- "\n- YUV420P 12 bpp - Original video, compression enabled"
- "\n- YUVY 16 bpp - Software conversion from UYVY"
- "\n- YUV422 16 bpp - Software conversion from UYVY"
- "\n- GREY 8 bpp - Software conversion from UYVY"
- "\n- RGB555 16 bpp - Software conversion from UYVY"
- "\n- RGB565 16 bpp - Software conversion from UYVY"
- "\n- RGB24 24 bpp - Software conversion from UYVY"
- "\n- RGB32 32 bpp - Software conversion from UYVY"
- "\nWhen not 0, this parameter will override 'decompression'."
- "\nDefault value is 0 for every device."
- "\nInitial palette is "
- __MODULE_STRING(W9968CF_PALETTE_DECOMP_ON)"."
- "\nIf 'w9968cf-vpp' is not present, this parameter is"
- " set to 9 (UYVY)."
- "\n");
-MODULE_PARM_DESC(force_rgb,
- "\n<0|1[,...]> Read RGB video data instead of BGR:"
- "\n 1 = use RGB component ordering."
- "\n 0 = use BGR component ordering."
- "\nThis parameter has effect when using RGBX palettes only."
- "\nDefault value is "__MODULE_STRING(W9968CF_FORCE_RGB)
- " for every device."
- "\n");
-MODULE_PARM_DESC(autobright,
- "\n<0|1[,...]> Image sensor automatically changes brightness:"
- "\n 0 = no, 1 = yes"
- "\nDefault value is "__MODULE_STRING(W9968CF_AUTOBRIGHT)
- " for every device."
- "\n");
-MODULE_PARM_DESC(autoexp,
- "\n<0|1[,...]> Image sensor automatically changes exposure:"
- "\n 0 = no, 1 = yes"
- "\nDefault value is "__MODULE_STRING(W9968CF_AUTOEXP)
- " for every device."
- "\n");
-MODULE_PARM_DESC(lightfreq,
- "\n<50|60[,...]> Light frequency in Hz:"
- "\n 50 for European and Asian lighting,"
- " 60 for American lighting."
- "\nDefault value is "__MODULE_STRING(W9968CF_LIGHTFREQ)
- " for every device."
- "\n");
-MODULE_PARM_DESC(bandingfilter,
- "\n<0|1[,...]> Banding filter to reduce effects of"
- " fluorescent lighting:"
- "\n 0 disabled, 1 enabled."
- "\nThis filter tries to reduce the pattern of horizontal"
- "\nlight/dark bands caused by some (usually fluorescent)"
- " lighting."
- "\nDefault value is "__MODULE_STRING(W9968CF_BANDINGFILTER)
- " for every device."
- "\n");
-MODULE_PARM_DESC(clockdiv,
- "\n<-1|n[,...]> "
- "Force pixel clock divisor to a specific value (for experts):"
- "\n n may vary from 0 to 127."
- "\n -1 for automatic value."
- "\nSee also the 'double_buffer' module parameter."
- "\nDefault value is "__MODULE_STRING(W9968CF_CLOCKDIV)
- " for every device."
- "\n");
-MODULE_PARM_DESC(backlight,
- "\n<0|1[,...]> Objects are lit from behind:"
- "\n 0 = no, 1 = yes"
- "\nDefault value is "__MODULE_STRING(W9968CF_BACKLIGHT)
- " for every device."
- "\n");
-MODULE_PARM_DESC(mirror,
- "\n<0|1[,...]> Reverse image horizontally:"
- "\n 0 = no, 1 = yes"
- "\nDefault value is "__MODULE_STRING(W9968CF_MIRROR)
- " for every device."
- "\n");
-MODULE_PARM_DESC(monochrome,
- "\n<0|1[,...]> Use image sensor as monochrome sensor:"
- "\n 0 = no, 1 = yes"
- "\nNot all the sensors support monochrome color."
- "\nDefault value is "__MODULE_STRING(W9968CF_MONOCHROME)
- " for every device."
- "\n");
-MODULE_PARM_DESC(brightness,
- "\n<n[,...]> Set picture brightness (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_BRIGHTNESS)
- " for every device."
- "\nThis parameter has no effect if 'autobright' is enabled."
- "\n");
-MODULE_PARM_DESC(hue,
- "\n<n[,...]> Set picture hue (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_HUE)
- " for every device."
- "\n");
-MODULE_PARM_DESC(colour,
- "\n<n[,...]> Set picture saturation (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_COLOUR)
- " for every device."
- "\n");
-MODULE_PARM_DESC(contrast,
- "\n<n[,...]> Set picture contrast (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_CONTRAST)
- " for every device."
- "\n");
-MODULE_PARM_DESC(whiteness,
- "\n<n[,...]> Set picture whiteness (0-65535)."
- "\nDefault value is "__MODULE_STRING(W9968CF_WHITENESS)
- " for every device."
- "\n");
-#ifdef W9968CF_DEBUG
-MODULE_PARM_DESC(debug,
- "\n<n> Debugging information level, from 0 to 6:"
- "\n0 = none (use carefully)"
- "\n1 = critical errors"
- "\n2 = significant informations"
- "\n3 = configuration or general messages"
- "\n4 = warnings"
- "\n5 = called functions"
- "\n6 = function internals"
- "\nLevel 5 and 6 are useful for testing only, when only "
- "one device is used."
- "\nDefault value is "__MODULE_STRING(W9968CF_DEBUG_LEVEL)"."
- "\n");
-MODULE_PARM_DESC(specific_debug,
- "\n<0|1> Enable or disable specific debugging messages:"
- "\n0 = print messages concerning every level"
- " <= 'debug' level."
- "\n1 = print messages concerning the level"
- " indicated by 'debug'."
- "\nDefault value is "
- __MODULE_STRING(W9968CF_SPECIFIC_DEBUG)"."
- "\n");
-#endif /* W9968CF_DEBUG */
-
-
-
-/****************************************************************************
- * Some prototypes *
- ****************************************************************************/
-
-/* Video4linux interface */
-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 */
-static int w9968cf_start_transfer(struct w9968cf_device*);
-static int w9968cf_stop_transfer(struct w9968cf_device*);
-static int w9968cf_write_reg(struct w9968cf_device*, u16 value, u16 index);
-static int w9968cf_read_reg(struct w9968cf_device*, u16 index);
-static int w9968cf_write_fsb(struct w9968cf_device*, u16* data);
-static int w9968cf_write_sb(struct w9968cf_device*, u16 value);
-static int w9968cf_read_sb(struct w9968cf_device*);
-static int w9968cf_upload_quantizationtables(struct w9968cf_device*);
-static void w9968cf_urb_complete(struct urb *urb);
-
-/* Low-level I2C (SMBus) I/O */
-static int w9968cf_smbus_start(struct w9968cf_device*);
-static int w9968cf_smbus_stop(struct w9968cf_device*);
-static int w9968cf_smbus_write_byte(struct w9968cf_device*, u8 v);
-static int w9968cf_smbus_read_byte(struct w9968cf_device*, u8* v);
-static int w9968cf_smbus_write_ack(struct w9968cf_device*);
-static int w9968cf_smbus_read_ack(struct w9968cf_device*);
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device*);
-static int w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
- u16 address, u8* value);
-static int w9968cf_i2c_adap_read_byte_data(struct w9968cf_device*, u16 address,
- u8 subaddress, u8* value);
-static int w9968cf_i2c_adap_write_byte(struct w9968cf_device*,
- u16 address, u8 subaddress);
-static int w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device*,
- u16 address, u8 subaddress,
- u8 value);
-
-/* I2C interface to kernel */
-static int w9968cf_i2c_init(struct w9968cf_device*);
-static int w9968cf_i2c_smbus_xfer(struct i2c_adapter*, u16 addr,
- unsigned short flags, char read_write,
- u8 command, int size, union i2c_smbus_data*);
-static u32 w9968cf_i2c_func(struct i2c_adapter*);
-
-/* Memory management */
-static void* rvmalloc(unsigned long size);
-static void rvfree(void *mem, unsigned long size);
-static void w9968cf_deallocate_memory(struct w9968cf_device*);
-static int w9968cf_allocate_memory(struct w9968cf_device*);
-
-/* High-level image sensor control functions */
-static int w9968cf_sensor_set_control(struct w9968cf_device*,int cid,int val);
-static int w9968cf_sensor_get_control(struct w9968cf_device*,int cid,int *val);
-static int w9968cf_sensor_cmd(struct w9968cf_device*,
- unsigned int cmd, void *arg);
-static int w9968cf_sensor_init(struct w9968cf_device*);
-static int w9968cf_sensor_update_settings(struct w9968cf_device*);
-static int w9968cf_sensor_get_picture(struct w9968cf_device*);
-static int w9968cf_sensor_update_picture(struct w9968cf_device*,
- struct video_picture pict);
-
-/* Other helper functions */
-static void w9968cf_configure_camera(struct w9968cf_device*,struct usb_device*,
- enum w9968cf_model_id,
- const unsigned short dev_nr);
-static void w9968cf_adjust_configuration(struct w9968cf_device*);
-static int w9968cf_turn_on_led(struct w9968cf_device*);
-static int w9968cf_init_chip(struct w9968cf_device*);
-static inline u16 w9968cf_valid_palette(u16 palette);
-static inline u16 w9968cf_valid_depth(u16 palette);
-static inline u8 w9968cf_need_decompression(u16 palette);
-static int w9968cf_set_picture(struct w9968cf_device*, struct video_picture);
-static int w9968cf_set_window(struct w9968cf_device*, struct video_window);
-static int w9968cf_postprocess_frame(struct w9968cf_device*,
- struct w9968cf_frame_t*);
-static int w9968cf_adjust_window_size(struct w9968cf_device*, u32 *w, u32 *h);
-static void w9968cf_init_framelist(struct w9968cf_device*);
-static void w9968cf_push_frame(struct w9968cf_device*, u8 f_num);
-static void w9968cf_pop_frame(struct w9968cf_device*,struct w9968cf_frame_t**);
-static void w9968cf_release_resources(struct w9968cf_device*);
-
-
-
-/****************************************************************************
- * Symbolic names *
- ****************************************************************************/
-
-/* Used to represent a list of values and their respective symbolic names */
-struct w9968cf_symbolic_list {
- const int num;
- const char *name;
-};
-
-/*--------------------------------------------------------------------------
- Returns the name of the matching element in the symbolic_list array. The
- end of the list must be marked with an element that has a NULL name.
- --------------------------------------------------------------------------*/
-static inline const char *
-symbolic(struct w9968cf_symbolic_list list[], const int num)
-{
- int i;
-
- for (i = 0; list[i].name != NULL; i++)
- if (list[i].num == num)
- return (list[i].name);
-
- return "Unknown";
-}
-
-static struct w9968cf_symbolic_list camlist[] = {
- { W9968CF_MOD_GENERIC, "W996[87]CF JPEG USB Dual Mode Camera" },
- { W9968CF_MOD_CLVBWGP, "Creative Labs Video Blaster WebCam Go Plus" },
-
- /* Other cameras (having the same descriptors as Generic W996[87]CF) */
- { W9968CF_MOD_ADPVDMA, "Aroma Digi Pen VGA Dual Mode ADG-5000" },
- { W9986CF_MOD_AAU, "AVerMedia AVerTV USB" },
- { W9968CF_MOD_CLVBWG, "Creative Labs Video Blaster WebCam Go" },
- { W9968CF_MOD_LL, "Lebon LDC-035A" },
- { W9968CF_MOD_EEEMC, "Ezonics EZ-802 EZMega Cam" },
- { W9968CF_MOD_OOE, "OmniVision OV8610-EDE" },
- { W9968CF_MOD_ODPVDMPC, "OPCOM Digi Pen VGA Dual Mode Pen Camera" },
- { W9968CF_MOD_PDPII, "Pretec Digi Pen-II" },
- { W9968CF_MOD_PDP480, "Pretec DigiPen-480" },
-
- { -1, NULL }
-};
-
-static struct w9968cf_symbolic_list senlist[] = {
- { CC_OV76BE, "OV76BE" },
- { CC_OV7610, "OV7610" },
- { CC_OV7620, "OV7620" },
- { CC_OV7620AE, "OV7620AE" },
- { CC_OV6620, "OV6620" },
- { CC_OV6630, "OV6630" },
- { CC_OV6630AE, "OV6630AE" },
- { CC_OV6630AF, "OV6630AF" },
- { -1, NULL }
-};
-
-/* Video4Linux1 palettes */
-static struct w9968cf_symbolic_list v4l1_plist[] = {
- { VIDEO_PALETTE_GREY, "GREY" },
- { VIDEO_PALETTE_HI240, "HI240" },
- { VIDEO_PALETTE_RGB565, "RGB565" },
- { VIDEO_PALETTE_RGB24, "RGB24" },
- { VIDEO_PALETTE_RGB32, "RGB32" },
- { VIDEO_PALETTE_RGB555, "RGB555" },
- { VIDEO_PALETTE_YUV422, "YUV422" },
- { VIDEO_PALETTE_YUYV, "YUYV" },
- { VIDEO_PALETTE_UYVY, "UYVY" },
- { VIDEO_PALETTE_YUV420, "YUV420" },
- { VIDEO_PALETTE_YUV411, "YUV411" },
- { VIDEO_PALETTE_RAW, "RAW" },
- { VIDEO_PALETTE_YUV422P, "YUV422P" },
- { VIDEO_PALETTE_YUV411P, "YUV411P" },
- { VIDEO_PALETTE_YUV420P, "YUV420P" },
- { VIDEO_PALETTE_YUV410P, "YUV410P" },
- { -1, NULL }
-};
-
-/* Decoder error codes: */
-static struct w9968cf_symbolic_list decoder_errlist[] = {
- { W9968CF_DEC_ERR_CORRUPTED_DATA, "Corrupted data" },
- { W9968CF_DEC_ERR_BUF_OVERFLOW, "Buffer overflow" },
- { W9968CF_DEC_ERR_NO_SOI, "SOI marker not found" },
- { W9968CF_DEC_ERR_NO_SOF0, "SOF0 marker not found" },
- { W9968CF_DEC_ERR_NO_SOS, "SOS marker not found" },
- { W9968CF_DEC_ERR_NO_EOI, "EOI marker not found" },
- { -1, NULL }
-};
-
-/* URB error codes: */
-static struct w9968cf_symbolic_list urb_errlist[] = {
- { -ENOMEM, "No memory for allocation of internal structures" },
- { -ENOSPC, "The host controller's bandwidth is already consumed" },
- { -ENOENT, "URB was canceled by unlink_urb" },
- { -EXDEV, "ISO transfer only partially completed" },
- { -EAGAIN, "Too match scheduled for the future" },
- { -ENXIO, "URB already queued" },
- { -EFBIG, "Too much ISO frames requested" },
- { -ENOSR, "Buffer error (overrun)" },
- { -EPIPE, "Specified endpoint is stalled (device not responding)"},
- { -EOVERFLOW, "Babble (too much data)" },
- { -EPROTO, "Bit-stuff error (bad cable?)" },
- { -EILSEQ, "CRC/Timeout" },
- { -ETIME, "Device does not respond to token" },
- { -ETIMEDOUT, "Device does not respond to command" },
- { -1, NULL }
-};
-
-/****************************************************************************
- * Memory management functions *
- ****************************************************************************/
-static void* rvmalloc(unsigned long size)
-{
- void* mem;
- unsigned long adr;
-
- size = PAGE_ALIGN(size);
- mem = vmalloc_32(size);
- if (!mem)
- return NULL;
-
- memset(mem, 0, size); /* Clear the ram out, no junk to the user */
- adr = (unsigned long) mem;
- while (size > 0) {
- SetPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- return mem;
-}
-
-
-static void rvfree(void* mem, unsigned long size)
-{
- unsigned long adr;
-
- if (!mem)
- return;
-
- adr = (unsigned long) mem;
- while ((long) size > 0) {
- ClearPageReserved(vmalloc_to_page((void *)adr));
- adr += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
- vfree(mem);
-}
-
-
-/*--------------------------------------------------------------------------
- Deallocate previously allocated memory.
- --------------------------------------------------------------------------*/
-static void w9968cf_deallocate_memory(struct w9968cf_device* cam)
-{
- u8 i;
-
- /* Free the isochronous transfer buffers */
- for (i = 0; i < W9968CF_URBS; i++) {
- kfree(cam->transfer_buffer[i]);
- cam->transfer_buffer[i] = NULL;
- }
-
- /* Free temporary frame buffer */
- if (cam->frame_tmp.buffer) {
- rvfree(cam->frame_tmp.buffer, cam->frame_tmp.size);
- cam->frame_tmp.buffer = NULL;
- }
-
- /* Free helper buffer */
- if (cam->frame_vpp.buffer) {
- rvfree(cam->frame_vpp.buffer, cam->frame_vpp.size);
- cam->frame_vpp.buffer = NULL;
- }
-
- /* Free video frame buffers */
- if (cam->frame[0].buffer) {
- rvfree(cam->frame[0].buffer, cam->nbuffers*cam->frame[0].size);
- cam->frame[0].buffer = NULL;
- }
-
- cam->nbuffers = 0;
-
- DBG(5, "Memory successfully deallocated")
-}
-
-
-/*--------------------------------------------------------------------------
- Allocate memory buffers for USB transfers and video frames.
- This function is called by open() only.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_allocate_memory(struct w9968cf_device* cam)
-{
- const u16 p_size = wMaxPacketSize[cam->altsetting-1];
- void* buff = NULL;
- unsigned long hw_bufsize, vpp_bufsize;
- u8 i, bpp;
-
- /* NOTE: Deallocation is done elsewhere in case of error */
-
- /* Calculate the max amount of raw data per frame from the device */
- hw_bufsize = cam->maxwidth*cam->maxheight*2;
-
- /* Calculate the max buf. size needed for post-processing routines */
- bpp = (w9968cf_vpp) ? 4 : 2;
- if (cam->upscaling)
- vpp_bufsize = max(W9968CF_MAX_WIDTH*W9968CF_MAX_HEIGHT*bpp,
- cam->maxwidth*cam->maxheight*bpp);
- else
- vpp_bufsize = cam->maxwidth*cam->maxheight*bpp;
-
- /* Allocate memory for the isochronous transfer buffers */
- for (i = 0; i < W9968CF_URBS; i++) {
- if (!(cam->transfer_buffer[i] =
- kzalloc(W9968CF_ISO_PACKETS*p_size, GFP_KERNEL))) {
- DBG(1, "Couldn't allocate memory for the isochronous "
- "transfer buffers (%u bytes)",
- p_size * W9968CF_ISO_PACKETS)
- return -ENOMEM;
- }
- }
-
- /* Allocate memory for the temporary frame buffer */
- if (!(cam->frame_tmp.buffer = rvmalloc(hw_bufsize))) {
- DBG(1, "Couldn't allocate memory for the temporary "
- "video frame buffer (%lu bytes)", hw_bufsize)
- return -ENOMEM;
- }
- cam->frame_tmp.size = hw_bufsize;
- cam->frame_tmp.number = -1;
-
- /* Allocate memory for the helper buffer */
- if (w9968cf_vpp) {
- if (!(cam->frame_vpp.buffer = rvmalloc(vpp_bufsize))) {
- DBG(1, "Couldn't allocate memory for the helper buffer"
- " (%lu bytes)", vpp_bufsize)
- return -ENOMEM;
- }
- cam->frame_vpp.size = vpp_bufsize;
- } else
- cam->frame_vpp.buffer = NULL;
-
- /* Allocate memory for video frame buffers */
- cam->nbuffers = cam->max_buffers;
- while (cam->nbuffers >= 2) {
- if ((buff = rvmalloc(cam->nbuffers * vpp_bufsize)))
- break;
- else
- cam->nbuffers--;
- }
-
- if (!buff) {
- DBG(1, "Couldn't allocate memory for the video frame buffers")
- cam->nbuffers = 0;
- return -ENOMEM;
- }
-
- if (cam->nbuffers != cam->max_buffers)
- DBG(2, "Couldn't allocate memory for %u video frame buffers. "
- "Only memory for %u buffers has been allocated",
- cam->max_buffers, cam->nbuffers)
-
- for (i = 0; i < cam->nbuffers; i++) {
- cam->frame[i].buffer = buff + i*vpp_bufsize;
- cam->frame[i].size = vpp_bufsize;
- cam->frame[i].number = i;
- /* Circular list */
- if (i != cam->nbuffers-1)
- cam->frame[i].next = &cam->frame[i+1];
- else
- cam->frame[i].next = &cam->frame[0];
- cam->frame[i].status = F_UNUSED;
- }
-
- DBG(5, "Memory successfully allocated")
- return 0;
-}
-
-
-
-/****************************************************************************
- * USB-specific functions *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
- This is an handler function which is called after the URBs are completed.
- It collects multiple data packets coming from the camera by putting them
- into frame buffers: one or more zero data length data packets are used to
- mark the end of a video frame; the first non-zero data packet is the start
- of the next video frame; if an error is encountered in a packet, the entire
- video frame is discarded and grabbed again.
- If there are no requested frames in the FIFO list, packets are collected into
- a temporary buffer.
- --------------------------------------------------------------------------*/
-static void w9968cf_urb_complete(struct urb *urb)
-{
- struct w9968cf_device* cam = (struct w9968cf_device*)urb->context;
- struct w9968cf_frame_t** f;
- unsigned int len, status;
- void* pos;
- u8 i;
- int err = 0;
-
- if ((!cam->streaming) || cam->disconnected) {
- DBG(4, "Got interrupt, but not streaming")
- return;
- }
-
- /* "(*f)" will be used instead of "cam->frame_current" */
- f = &cam->frame_current;
-
- /* If a frame has been requested and we are grabbing into
- the temporary frame, we'll switch to that requested frame */
- if ((*f) == &cam->frame_tmp && *cam->requested_frame) {
- if (cam->frame_tmp.status == F_GRABBING) {
- w9968cf_pop_frame(cam, &cam->frame_current);
- (*f)->status = F_GRABBING;
- (*f)->length = cam->frame_tmp.length;
- memcpy((*f)->buffer, cam->frame_tmp.buffer,
- (*f)->length);
- DBG(6, "Switched from temp. frame to frame #%d",
- (*f)->number)
- }
- }
-
- for (i = 0; i < urb->number_of_packets; i++) {
- len = urb->iso_frame_desc[i].actual_length;
- status = urb->iso_frame_desc[i].status;
- pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
- if (status && len != 0) {
- DBG(4, "URB failed, error in data packet "
- "(error #%u, %s)",
- status, symbolic(urb_errlist, status))
- (*f)->status = F_ERROR;
- continue;
- }
-
- if (len) { /* start of frame */
-
- if ((*f)->status == F_UNUSED) {
- (*f)->status = F_GRABBING;
- (*f)->length = 0;
- }
-
- /* Buffer overflows shouldn't happen, however...*/
- if ((*f)->length + len > (*f)->size) {
- DBG(4, "Buffer overflow: bad data packets")
- (*f)->status = F_ERROR;
- }
-
- if ((*f)->status == F_GRABBING) {
- memcpy((*f)->buffer + (*f)->length, pos, len);
- (*f)->length += len;
- }
-
- } else if ((*f)->status == F_GRABBING) { /* end of frame */
-
- DBG(6, "Frame #%d successfully grabbed", (*f)->number)
-
- if (cam->vpp_flag & VPP_DECOMPRESSION) {
- err = w9968cf_vpp->check_headers((*f)->buffer,
- (*f)->length);
- if (err) {
- DBG(4, "Skip corrupted frame: %s",
- symbolic(decoder_errlist, err))
- (*f)->status = F_UNUSED;
- continue; /* grab this frame again */
- }
- }
-
- (*f)->status = F_READY;
- (*f)->queued = 0;
-
- /* Take a pointer to the new frame from the FIFO list.
- If the list is empty,we'll use the temporary frame*/
- if (*cam->requested_frame)
- w9968cf_pop_frame(cam, &cam->frame_current);
- else {
- cam->frame_current = &cam->frame_tmp;
- (*f)->status = F_UNUSED;
- }
-
- } else if ((*f)->status == F_ERROR)
- (*f)->status = F_UNUSED; /* grab it again */
-
- PDBGG("Frame length %lu | pack.#%u | pack.len. %u | state %d",
- (unsigned long)(*f)->length, i, len, (*f)->status)
-
- } /* end for */
-
- /* Resubmit this URB */
- urb->dev = cam->usbdev;
- urb->status = 0;
- spin_lock(&cam->urb_lock);
- if (cam->streaming)
- if ((err = usb_submit_urb(urb, GFP_ATOMIC))) {
- cam->misconfigured = 1;
- DBG(1, "Couldn't resubmit the URB: error %d, %s",
- err, symbolic(urb_errlist, err))
- }
- spin_unlock(&cam->urb_lock);
-
- /* Wake up the user process */
- wake_up_interruptible(&cam->wait_queue);
-}
-
-
-/*---------------------------------------------------------------------------
- Setup the URB structures for the isochronous transfer.
- Submit the URBs so that the data transfer begins.
- Return 0 on success, a negative number otherwise.
- ---------------------------------------------------------------------------*/
-static int w9968cf_start_transfer(struct w9968cf_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- struct urb* urb;
- const u16 p_size = wMaxPacketSize[cam->altsetting-1];
- u16 w, h, d;
- int vidcapt;
- u32 t_size;
- int err = 0;
- s8 i, j;
-
- for (i = 0; i < W9968CF_URBS; i++) {
- urb = usb_alloc_urb(W9968CF_ISO_PACKETS, GFP_KERNEL);
- if (!urb) {
- for (j = 0; j < i; j++)
- usb_free_urb(cam->urb[j]);
- DBG(1, "Couldn't allocate the URB structures")
- return -ENOMEM;
- }
-
- cam->urb[i] = urb;
- urb->dev = udev;
- urb->context = (void*)cam;
- urb->pipe = usb_rcvisocpipe(udev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->number_of_packets = W9968CF_ISO_PACKETS;
- urb->complete = w9968cf_urb_complete;
- urb->transfer_buffer = cam->transfer_buffer[i];
- urb->transfer_buffer_length = p_size*W9968CF_ISO_PACKETS;
- urb->interval = 1;
- for (j = 0; j < W9968CF_ISO_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = p_size*j;
- urb->iso_frame_desc[j].length = p_size;
- }
- }
-
- /* Transfer size per frame, in WORD ! */
- d = cam->hw_depth;
- w = cam->hw_width;
- h = cam->hw_height;
-
- t_size = (w*h*d)/16;
-
- err = w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
- err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
-
- /* Transfer size */
- err += w9968cf_write_reg(cam, t_size & 0xffff, 0x3d); /* low bits */
- err += w9968cf_write_reg(cam, t_size >> 16, 0x3e); /* high bits */
-
- if (cam->vpp_flag & VPP_DECOMPRESSION)
- err += w9968cf_upload_quantizationtables(cam);
-
- vidcapt = w9968cf_read_reg(cam, 0x16); /* read picture settings */
- err += w9968cf_write_reg(cam, vidcapt|0x8000, 0x16); /* capt. enable */
-
- err += usb_set_interface(udev, 0, cam->altsetting);
- err += w9968cf_write_reg(cam, 0x8a05, 0x3c); /* USB FIFO enable */
-
- if (err || (vidcapt < 0)) {
- for (i = 0; i < W9968CF_URBS; i++)
- usb_free_urb(cam->urb[i]);
- DBG(1, "Couldn't tell the camera to start the data transfer")
- return err;
- }
-
- w9968cf_init_framelist(cam);
-
- /* Begin to grab into the temporary buffer */
- cam->frame_tmp.status = F_UNUSED;
- cam->frame_tmp.queued = 0;
- cam->frame_current = &cam->frame_tmp;
-
- if (!(cam->vpp_flag & VPP_DECOMPRESSION))
- DBG(5, "Isochronous transfer size: %lu bytes/frame",
- (unsigned long)t_size*2)
-
- DBG(5, "Starting the isochronous transfer...")
-
- cam->streaming = 1;
-
- /* Submit the URBs */
- for (i = 0; i < W9968CF_URBS; i++) {
- err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
- if (err) {
- cam->streaming = 0;
- for (j = i-1; j >= 0; j--) {
- usb_kill_urb(cam->urb[j]);
- usb_free_urb(cam->urb[j]);
- }
- DBG(1, "Couldn't send a transfer request to the "
- "USB core (error #%d, %s)", err,
- symbolic(urb_errlist, err))
- return err;
- }
- }
-
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Stop the isochronous transfer and set alternate setting to 0 (0Mb/s).
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_stop_transfer(struct w9968cf_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- unsigned long lock_flags;
- int err = 0;
- s8 i;
-
- if (!cam->streaming)
- return 0;
-
- /* This avoids race conditions with usb_submit_urb()
- in the URB completition handler */
- spin_lock_irqsave(&cam->urb_lock, lock_flags);
- cam->streaming = 0;
- spin_unlock_irqrestore(&cam->urb_lock, lock_flags);
-
- for (i = W9968CF_URBS-1; i >= 0; i--)
- if (cam->urb[i]) {
- usb_kill_urb(cam->urb[i]);
- usb_free_urb(cam->urb[i]);
- cam->urb[i] = NULL;
- }
-
- if (cam->disconnected)
- goto exit;
-
- err = w9968cf_write_reg(cam, 0x0a05, 0x3c); /* stop USB transfer */
- err += usb_set_interface(udev, 0, 0); /* 0 Mb/s */
- err += w9968cf_write_reg(cam, 0x0000, 0x39); /* disable JPEG encoder */
- err += w9968cf_write_reg(cam, 0x0000, 0x16); /* stop video capture */
-
- if (err) {
- DBG(2, "Failed to tell the camera to stop the isochronous "
- "transfer. However this is not a critical error.")
- return -EIO;
- }
-
-exit:
- DBG(5, "Isochronous transfer stopped")
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Write a W9968CF register.
- Return 0 on success, -1 otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_write_reg(struct w9968cf_device* cam, u16 value, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- int res;
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
- USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
- value, index, NULL, 0, W9968CF_USB_CTRL_TIMEOUT);
-
- if (res < 0)
- DBG(4, "Failed to write a register "
- "(value 0x%04X, index 0x%02X, error #%d, %s)",
- value, index, res, symbolic(urb_errlist, res))
-
- return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
- Read a W9968CF register.
- Return the register value on success, -1 otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_read_reg(struct w9968cf_device* cam, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- u16* buff = cam->control_buffer;
- int res;
-
- res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 1,
- USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
- 0, index, buff, 2, W9968CF_USB_CTRL_TIMEOUT);
-
- if (res < 0)
- DBG(4, "Failed to read a register "
- "(index 0x%02X, error #%d, %s)",
- index, res, symbolic(urb_errlist, res))
-
- return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-/*--------------------------------------------------------------------------
- Write 64-bit data to the fast serial bus registers.
- Return 0 on success, -1 otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_write_fsb(struct w9968cf_device* cam, u16* data)
-{
- struct usb_device* udev = cam->usbdev;
- u16 value;
- int res;
-
- value = *data++;
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0,
- USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
- value, 0x06, data, 6, W9968CF_USB_CTRL_TIMEOUT);
-
- if (res < 0)
- DBG(4, "Failed to write the FSB registers "
- "(error #%d, %s)", res, symbolic(urb_errlist, res))
-
- return (res >= 0) ? 0 : -1;
-}
-
-
-/*--------------------------------------------------------------------------
- Write data to the serial bus control register.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_write_sb(struct w9968cf_device* cam, u16 value)
-{
- int err = 0;
-
- err = w9968cf_write_reg(cam, value, 0x01);
- udelay(W9968CF_I2C_BUS_DELAY);
-
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Read data from the serial bus control register.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_read_sb(struct w9968cf_device* cam)
-{
- int v = 0;
-
- v = w9968cf_read_reg(cam, 0x01);
- udelay(W9968CF_I2C_BUS_DELAY);
-
- return v;
-}
-
-
-/*--------------------------------------------------------------------------
- Upload quantization tables for the JPEG compression.
- This function is called by w9968cf_start_transfer().
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_upload_quantizationtables(struct w9968cf_device* cam)
-{
- u16 a, b;
- int err = 0, i, j;
-
- err += w9968cf_write_reg(cam, 0x0010, 0x39); /* JPEG clock enable */
-
- for (i = 0, j = 0; i < 32; i++, j += 2) {
- a = Y_QUANTABLE[j] | ((unsigned)(Y_QUANTABLE[j+1]) << 8);
- b = UV_QUANTABLE[j] | ((unsigned)(UV_QUANTABLE[j+1]) << 8);
- err += w9968cf_write_reg(cam, a, 0x40+i);
- err += w9968cf_write_reg(cam, b, 0x60+i);
- }
- err += w9968cf_write_reg(cam, 0x0012, 0x39); /* JPEG encoder enable */
-
- return err;
-}
-
-
-
-/****************************************************************************
- * Low-level I2C I/O functions. *
- * The adapter supports the following I2C transfer functions: *
- * i2c_adap_fastwrite_byte_data() (at 400 kHz bit frequency only) *
- * i2c_adap_read_byte_data() *
- * i2c_adap_read_byte() *
- ****************************************************************************/
-
-static int w9968cf_smbus_start(struct w9968cf_device* cam)
-{
- int err = 0;
-
- err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
- return err;
-}
-
-
-static int w9968cf_smbus_stop(struct w9968cf_device* cam)
-{
- int err = 0;
-
- err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
-
- return err;
-}
-
-
-static int w9968cf_smbus_write_byte(struct w9968cf_device* cam, u8 v)
-{
- u8 bit;
- int err = 0, sda;
-
- for (bit = 0 ; bit < 8 ; bit++) {
- sda = (v & 0x80) ? 2 : 0;
- v <<= 1;
- /* SDE=1, SDA=sda, SCL=0 */
- err += w9968cf_write_sb(cam, 0x10 | sda);
- /* SDE=1, SDA=sda, SCL=1 */
- err += w9968cf_write_sb(cam, 0x11 | sda);
- /* SDE=1, SDA=sda, SCL=0 */
- err += w9968cf_write_sb(cam, 0x10 | sda);
- }
-
- return err;
-}
-
-
-static int w9968cf_smbus_read_byte(struct w9968cf_device* cam, u8* v)
-{
- u8 bit;
- int err = 0;
-
- *v = 0;
- for (bit = 0 ; bit < 8 ; bit++) {
- *v <<= 1;
- err += w9968cf_write_sb(cam, 0x0013);
- *v |= (w9968cf_read_sb(cam) & 0x0008) ? 1 : 0;
- err += w9968cf_write_sb(cam, 0x0012);
- }
-
- return err;
-}
-
-
-static int w9968cf_smbus_write_ack(struct w9968cf_device* cam)
-{
- int err = 0;
-
- err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
- err += w9968cf_write_sb(cam, 0x0011); /* SDE=1, SDA=0, SCL=1 */
- err += w9968cf_write_sb(cam, 0x0010); /* SDE=1, SDA=0, SCL=0 */
-
- return err;
-}
-
-
-static int w9968cf_smbus_read_ack(struct w9968cf_device* cam)
-{
- int err = 0, sda;
-
- err += w9968cf_write_sb(cam, 0x0013); /* SDE=1, SDA=1, SCL=1 */
- sda = (w9968cf_read_sb(cam) & 0x08) ? 1 : 0; /* sda = SDA */
- err += w9968cf_write_sb(cam, 0x0012); /* SDE=1, SDA=1, SCL=0 */
- if (sda < 0)
- err += sda;
- if (sda == 1) {
- DBG(6, "Couldn't receive the ACK")
- err += -1;
- }
-
- return err;
-}
-
-
-/* This seems to refresh the communication through the serial bus */
-static int w9968cf_smbus_refresh_bus(struct w9968cf_device* cam)
-{
- int err = 0, j;
-
- for (j = 1; j <= 10; j++) {
- err = w9968cf_write_reg(cam, 0x0020, 0x01);
- err += w9968cf_write_reg(cam, 0x0000, 0x01);
- if (err)
- break;
- }
-
- return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] Value [A] P */
-static int
-w9968cf_i2c_adap_fastwrite_byte_data(struct w9968cf_device* cam,
- u16 address, u8 subaddress,u8 value)
-{
- u16* data = cam->data_buffer;
- int err = 0;
-
- err += w9968cf_smbus_refresh_bus(cam);
-
- /* Enable SBUS outputs */
- err += w9968cf_write_sb(cam, 0x0020);
-
- data[0] = 0x082f | ((address & 0x80) ? 0x1500 : 0x0);
- data[0] |= (address & 0x40) ? 0x4000 : 0x0;
- data[1] = 0x2082 | ((address & 0x40) ? 0x0005 : 0x0);
- data[1] |= (address & 0x20) ? 0x0150 : 0x0;
- data[1] |= (address & 0x10) ? 0x5400 : 0x0;
- data[2] = 0x8208 | ((address & 0x08) ? 0x0015 : 0x0);
- data[2] |= (address & 0x04) ? 0x0540 : 0x0;
- data[2] |= (address & 0x02) ? 0x5000 : 0x0;
- data[3] = 0x1d20 | ((address & 0x02) ? 0x0001 : 0x0);
- data[3] |= (address & 0x01) ? 0x0054 : 0x0;
-
- err += w9968cf_write_fsb(cam, data);
-
- data[0] = 0x8208 | ((subaddress & 0x80) ? 0x0015 : 0x0);
- data[0] |= (subaddress & 0x40) ? 0x0540 : 0x0;
- data[0] |= (subaddress & 0x20) ? 0x5000 : 0x0;
- data[1] = 0x0820 | ((subaddress & 0x20) ? 0x0001 : 0x0);
- data[1] |= (subaddress & 0x10) ? 0x0054 : 0x0;
- data[1] |= (subaddress & 0x08) ? 0x1500 : 0x0;
- data[1] |= (subaddress & 0x04) ? 0x4000 : 0x0;
- data[2] = 0x2082 | ((subaddress & 0x04) ? 0x0005 : 0x0);
- data[2] |= (subaddress & 0x02) ? 0x0150 : 0x0;
- data[2] |= (subaddress & 0x01) ? 0x5400 : 0x0;
- data[3] = 0x001d;
-
- err += w9968cf_write_fsb(cam, data);
-
- data[0] = 0x8208 | ((value & 0x80) ? 0x0015 : 0x0);
- data[0] |= (value & 0x40) ? 0x0540 : 0x0;
- data[0] |= (value & 0x20) ? 0x5000 : 0x0;
- data[1] = 0x0820 | ((value & 0x20) ? 0x0001 : 0x0);
- data[1] |= (value & 0x10) ? 0x0054 : 0x0;
- data[1] |= (value & 0x08) ? 0x1500 : 0x0;
- data[1] |= (value & 0x04) ? 0x4000 : 0x0;
- data[2] = 0x2082 | ((value & 0x04) ? 0x0005 : 0x0);
- data[2] |= (value & 0x02) ? 0x0150 : 0x0;
- data[2] |= (value & 0x01) ? 0x5400 : 0x0;
- data[3] = 0xfe1d;
-
- err += w9968cf_write_fsb(cam, data);
-
- /* Disable SBUS outputs */
- err += w9968cf_write_sb(cam, 0x0000);
-
- if (!err)
- DBG(5, "I2C write byte data done, addr.0x%04X, subaddr.0x%02X "
- "value 0x%02X", address, subaddress, value)
- else
- DBG(5, "I2C write byte data failed, addr.0x%04X, "
- "subaddr.0x%02X, value 0x%02X",
- address, subaddress, value)
-
- return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Subaddr [A] P S Addr+1 Rd [A] [Value] NA P */
-static int
-w9968cf_i2c_adap_read_byte_data(struct w9968cf_device* cam,
- u16 address, u8 subaddress,
- u8* value)
-{
- int err = 0;
-
- /* Serial data enable */
- err += w9968cf_write_sb(cam, 0x0013); /* don't change ! */
-
- err += w9968cf_smbus_start(cam);
- err += w9968cf_smbus_write_byte(cam, address);
- err += w9968cf_smbus_read_ack(cam);
- err += w9968cf_smbus_write_byte(cam, subaddress);
- err += w9968cf_smbus_read_ack(cam);
- err += w9968cf_smbus_stop(cam);
- err += w9968cf_smbus_start(cam);
- err += w9968cf_smbus_write_byte(cam, address + 1);
- err += w9968cf_smbus_read_ack(cam);
- err += w9968cf_smbus_read_byte(cam, value);
- err += w9968cf_smbus_write_ack(cam);
- err += w9968cf_smbus_stop(cam);
-
- /* Serial data disable */
- err += w9968cf_write_sb(cam, 0x0000);
-
- if (!err)
- DBG(5, "I2C read byte data done, addr.0x%04X, "
- "subaddr.0x%02X, value 0x%02X",
- address, subaddress, *value)
- else
- DBG(5, "I2C read byte data failed, addr.0x%04X, "
- "subaddr.0x%02X, wrong value 0x%02X",
- address, subaddress, *value)
-
- return err;
-}
-
-
-/* SMBus protocol: S Addr+1 Rd [A] [Value] NA P */
-static int
-w9968cf_i2c_adap_read_byte(struct w9968cf_device* cam,
- u16 address, u8* value)
-{
- int err = 0;
-
- /* Serial data enable */
- err += w9968cf_write_sb(cam, 0x0013);
-
- err += w9968cf_smbus_start(cam);
- err += w9968cf_smbus_write_byte(cam, address + 1);
- err += w9968cf_smbus_read_ack(cam);
- err += w9968cf_smbus_read_byte(cam, value);
- err += w9968cf_smbus_write_ack(cam);
- err += w9968cf_smbus_stop(cam);
-
- /* Serial data disable */
- err += w9968cf_write_sb(cam, 0x0000);
-
- if (!err)
- DBG(5, "I2C read byte done, addr.0x%04X, "
- "value 0x%02X", address, *value)
- else
- DBG(5, "I2C read byte failed, addr.0x%04X, "
- "wrong value 0x%02X", address, *value)
-
- return err;
-}
-
-
-/* SMBus protocol: S Addr Wr [A] Value [A] P */
-static int
-w9968cf_i2c_adap_write_byte(struct w9968cf_device* cam,
- u16 address, u8 value)
-{
- DBG(4, "i2c_write_byte() is an unsupported transfer mode")
- return -EINVAL;
-}
-
-
-
-/****************************************************************************
- * I2C interface to kernel *
- ****************************************************************************/
-
-static int
-w9968cf_i2c_smbus_xfer(struct i2c_adapter *adapter, u16 addr,
- unsigned short flags, char read_write, u8 command,
- int size, union i2c_smbus_data *data)
-{
- struct v4l2_device *v4l2_dev = i2c_get_adapdata(adapter);
- struct w9968cf_device *cam = to_cam(v4l2_dev);
- u8 i;
- int err = 0;
-
- if (size == I2C_SMBUS_BYTE) {
- /* Why addr <<= 1? See OVXXX0_SID defines in ovcamchip.h */
- addr <<= 1;
-
- if (read_write == I2C_SMBUS_WRITE)
- err = w9968cf_i2c_adap_write_byte(cam, addr, command);
- else if (read_write == I2C_SMBUS_READ)
- for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
- err = w9968cf_i2c_adap_read_byte(cam, addr,
- &data->byte);
- if (err) {
- if (w9968cf_smbus_refresh_bus(cam)) {
- err = -EIO;
- break;
- }
- } else
- break;
- }
- } else if (size == I2C_SMBUS_BYTE_DATA) {
- addr <<= 1;
-
- if (read_write == I2C_SMBUS_WRITE)
- err = w9968cf_i2c_adap_fastwrite_byte_data(cam, addr,
- command, data->byte);
- else if (read_write == I2C_SMBUS_READ) {
- for (i = 1; i <= W9968CF_I2C_RW_RETRIES; i++) {
- err = w9968cf_i2c_adap_read_byte_data(cam,addr,
- command, &data->byte);
- if (err) {
- if (w9968cf_smbus_refresh_bus(cam)) {
- err = -EIO;
- break;
- }
- } else
- break;
- }
-
- } else
- return -EINVAL;
-
- } else {
- DBG(4, "Unsupported I2C transfer mode (%d)", size)
- return -EINVAL;
- }
- return err;
-}
-
-
-static u32 w9968cf_i2c_func(struct i2c_adapter* adap)
-{
- return I2C_FUNC_SMBUS_READ_BYTE |
- I2C_FUNC_SMBUS_READ_BYTE_DATA |
- I2C_FUNC_SMBUS_WRITE_BYTE_DATA;
-}
-
-
-static int w9968cf_i2c_init(struct w9968cf_device* cam)
-{
- int err = 0;
-
- static struct i2c_algorithm algo = {
- .smbus_xfer = w9968cf_i2c_smbus_xfer,
- .functionality = w9968cf_i2c_func,
- };
-
- static struct i2c_adapter adap = {
- .owner = THIS_MODULE,
- .algo = &algo,
- };
-
- memcpy(&cam->i2c_adapter, &adap, sizeof(struct i2c_adapter));
- strcpy(cam->i2c_adapter.name, "w9968cf");
- cam->i2c_adapter.dev.parent = &cam->usbdev->dev;
- i2c_set_adapdata(&cam->i2c_adapter, &cam->v4l2_dev);
-
- DBG(6, "Registering I2C adapter with kernel...")
-
- err = i2c_add_adapter(&cam->i2c_adapter);
- if (err)
- DBG(1, "Failed to register the I2C adapter")
- else
- DBG(5, "I2C adapter registered")
-
- return err;
-}
-
-
-
-/****************************************************************************
- * Helper functions *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
- Turn on the LED on some webcams. A beep should be heard too.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_turn_on_led(struct w9968cf_device* cam)
-{
- int err = 0;
-
- err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power-down */
- err += w9968cf_write_reg(cam, 0xbf17, 0x00); /* reset everything */
- err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* normal operation */
- err += w9968cf_write_reg(cam, 0x0010, 0x01); /* serial bus, SDS high */
- err += w9968cf_write_reg(cam, 0x0000, 0x01); /* serial bus, SDS low */
- err += w9968cf_write_reg(cam, 0x0010, 0x01); /* ..high 'beep-beep' */
-
- if (err)
- DBG(2, "Couldn't turn on the LED")
-
- DBG(5, "LED turned on")
-
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Write some registers for the device initialization.
- This function is called once on open().
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_init_chip(struct w9968cf_device* cam)
-{
- unsigned long hw_bufsize = cam->maxwidth*cam->maxheight*2,
- y0 = 0x0000,
- u0 = y0 + hw_bufsize/2,
- v0 = u0 + hw_bufsize/4,
- y1 = v0 + hw_bufsize/4,
- u1 = y1 + hw_bufsize/2,
- v1 = u1 + hw_bufsize/4;
- int err = 0;
-
- err += w9968cf_write_reg(cam, 0xff00, 0x00); /* power off */
- err += w9968cf_write_reg(cam, 0xbf10, 0x00); /* power on */
-
- err += w9968cf_write_reg(cam, 0x405d, 0x03); /* DRAM timings */
- err += w9968cf_write_reg(cam, 0x0030, 0x04); /* SDRAM timings */
-
- err += w9968cf_write_reg(cam, y0 & 0xffff, 0x20); /* Y buf.0, low */
- err += w9968cf_write_reg(cam, y0 >> 16, 0x21); /* Y buf.0, high */
- err += w9968cf_write_reg(cam, u0 & 0xffff, 0x24); /* U buf.0, low */
- err += w9968cf_write_reg(cam, u0 >> 16, 0x25); /* U buf.0, high */
- err += w9968cf_write_reg(cam, v0 & 0xffff, 0x28); /* V buf.0, low */
- err += w9968cf_write_reg(cam, v0 >> 16, 0x29); /* V buf.0, high */
-
- err += w9968cf_write_reg(cam, y1 & 0xffff, 0x22); /* Y buf.1, low */
- err += w9968cf_write_reg(cam, y1 >> 16, 0x23); /* Y buf.1, high */
- err += w9968cf_write_reg(cam, u1 & 0xffff, 0x26); /* U buf.1, low */
- err += w9968cf_write_reg(cam, u1 >> 16, 0x27); /* U buf.1, high */
- err += w9968cf_write_reg(cam, v1 & 0xffff, 0x2a); /* V buf.1, low */
- err += w9968cf_write_reg(cam, v1 >> 16, 0x2b); /* V buf.1, high */
-
- err += w9968cf_write_reg(cam, y1 & 0xffff, 0x32); /* JPEG buf 0 low */
- err += w9968cf_write_reg(cam, y1 >> 16, 0x33); /* JPEG buf 0 high */
-
- err += w9968cf_write_reg(cam, y1 & 0xffff, 0x34); /* JPEG buf 1 low */
- err += w9968cf_write_reg(cam, y1 >> 16, 0x35); /* JPEG bug 1 high */
-
- err += w9968cf_write_reg(cam, 0x0000, 0x36);/* JPEG restart interval */
- err += w9968cf_write_reg(cam, 0x0804, 0x37);/*JPEG VLE FIFO threshold*/
- err += w9968cf_write_reg(cam, 0x0000, 0x38);/* disable hw up-scaling */
- err += w9968cf_write_reg(cam, 0x0000, 0x3f); /* JPEG/MCTL test data */
-
- err += w9968cf_set_picture(cam, cam->picture); /* this before */
- err += w9968cf_set_window(cam, cam->window);
-
- if (err)
- DBG(1, "Chip initialization failed")
- else
- DBG(5, "Chip successfully initialized")
-
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Return non-zero if the palette is supported, 0 otherwise.
- --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_palette(u16 palette)
-{
- u8 i = 0;
- while (w9968cf_formatlist[i].palette != 0) {
- if (palette == w9968cf_formatlist[i].palette)
- return palette;
- i++;
- }
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Return the depth corresponding to the given palette.
- Palette _must_ be supported !
- --------------------------------------------------------------------------*/
-static inline u16 w9968cf_valid_depth(u16 palette)
-{
- u8 i=0;
- while (w9968cf_formatlist[i].palette != palette)
- i++;
-
- return w9968cf_formatlist[i].depth;
-}
-
-
-/*--------------------------------------------------------------------------
- Return non-zero if the format requires decompression, 0 otherwise.
- --------------------------------------------------------------------------*/
-static inline u8 w9968cf_need_decompression(u16 palette)
-{
- u8 i = 0;
- while (w9968cf_formatlist[i].palette != 0) {
- if (palette == w9968cf_formatlist[i].palette)
- return w9968cf_formatlist[i].compression;
- i++;
- }
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Change the picture settings of the camera.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_set_picture(struct w9968cf_device* cam, struct video_picture pict)
-{
- u16 fmt, hw_depth, hw_palette, reg_v = 0x0000;
- int err = 0;
-
- /* Make sure we are using a valid depth */
- pict.depth = w9968cf_valid_depth(pict.palette);
-
- fmt = pict.palette;
-
- hw_depth = pict.depth; /* depth used by the winbond chip */
- hw_palette = pict.palette; /* palette used by the winbond chip */
-
- /* VS & HS polarities */
- reg_v = (cam->vs_polarity << 12) | (cam->hs_polarity << 11);
-
- switch (fmt)
- {
- case VIDEO_PALETTE_UYVY:
- reg_v |= 0x0000;
- cam->vpp_flag = VPP_NONE;
- break;
- case VIDEO_PALETTE_YUV422P:
- reg_v |= 0x0002;
- cam->vpp_flag = VPP_DECOMPRESSION;
- break;
- case VIDEO_PALETTE_YUV420:
- case VIDEO_PALETTE_YUV420P:
- reg_v |= 0x0003;
- cam->vpp_flag = VPP_DECOMPRESSION;
- break;
- case VIDEO_PALETTE_YUYV:
- case VIDEO_PALETTE_YUV422:
- reg_v |= 0x0000;
- cam->vpp_flag = VPP_SWAP_YUV_BYTES;
- hw_palette = VIDEO_PALETTE_UYVY;
- break;
- /* Original video is used instead of RGBX palettes.
- Software conversion later. */
- case VIDEO_PALETTE_GREY:
- case VIDEO_PALETTE_RGB555:
- case VIDEO_PALETTE_RGB565:
- case VIDEO_PALETTE_RGB24:
- case VIDEO_PALETTE_RGB32:
- reg_v |= 0x0000; /* UYVY 16 bit is used */
- hw_depth = 16;
- hw_palette = VIDEO_PALETTE_UYVY;
- cam->vpp_flag = VPP_UYVY_TO_RGBX;
- break;
- }
-
- /* NOTE: due to memory issues, it is better to disable the hardware
- double buffering during compression */
- if (cam->double_buffer && !(cam->vpp_flag & VPP_DECOMPRESSION))
- reg_v |= 0x0080;
-
- if (cam->clamping)
- reg_v |= 0x0020;
-
- if (cam->filter_type == 1)
- reg_v |= 0x0008;
- else if (cam->filter_type == 2)
- reg_v |= 0x000c;
-
- if ((err = w9968cf_write_reg(cam, reg_v, 0x16)))
- goto error;
-
- if ((err = w9968cf_sensor_update_picture(cam, pict)))
- goto error;
-
- /* If all went well, update the device data structure */
- memcpy(&cam->picture, &pict, sizeof(pict));
- cam->hw_depth = hw_depth;
- cam->hw_palette = hw_palette;
-
- /* Settings changed, so we clear the frame buffers */
- memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
- DBG(4, "Palette is %s, depth is %u bpp",
- symbolic(v4l1_plist, pict.palette), pict.depth)
-
- return 0;
-
-error:
- DBG(1, "Failed to change picture settings")
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Change the capture area size of the camera.
- This function _must_ be called _after_ w9968cf_set_picture().
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_set_window(struct w9968cf_device* cam, struct video_window win)
-{
- u16 x, y, w, h, scx, scy, cw, ch, ax, ay;
- unsigned long fw, fh;
- struct ovcamchip_window s_win;
- int err = 0;
-
- /* Work around to avoid FP arithmetics */
- #define SC(x) ((x) << 10)
- #define UNSC(x) ((x) >> 10)
-
- /* Make sure we are using a supported resolution */
- if ((err = w9968cf_adjust_window_size(cam, &win.width, &win.height)))
- goto error;
-
- /* Scaling factors */
- fw = SC(win.width) / cam->maxwidth;
- fh = SC(win.height) / cam->maxheight;
-
- /* Set up the width and height values used by the chip */
- if ((win.width > cam->maxwidth) || (win.height > cam->maxheight)) {
- cam->vpp_flag |= VPP_UPSCALE;
- /* Calculate largest w,h mantaining the same w/h ratio */
- w = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
- h = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
- if (w < cam->minwidth) /* just in case */
- w = cam->minwidth;
- if (h < cam->minheight) /* just in case */
- h = cam->minheight;
- } else {
- cam->vpp_flag &= ~VPP_UPSCALE;
- w = win.width;
- h = win.height;
- }
-
- /* x,y offsets of the cropped area */
- scx = cam->start_cropx;
- scy = cam->start_cropy;
-
- /* Calculate cropped area manteining the right w/h ratio */
- if (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE)) {
- cw = (fw >= fh) ? cam->maxwidth : SC(win.width)/fh;
- ch = (fw >= fh) ? SC(win.height)/fw : cam->maxheight;
- } else {
- cw = w;
- ch = h;
- }
-
- /* Setup the window of the sensor */
- s_win.format = VIDEO_PALETTE_UYVY;
- s_win.width = cam->maxwidth;
- s_win.height = cam->maxheight;
- s_win.quarter = 0; /* full progressive video */
-
- /* Center it */
- s_win.x = (s_win.width - cw) / 2;
- s_win.y = (s_win.height - ch) / 2;
-
- /* Clock divisor */
- if (cam->clockdiv >= 0)
- s_win.clockdiv = cam->clockdiv; /* manual override */
- else
- switch (cam->sensor) {
- case CC_OV6620:
- s_win.clockdiv = 0;
- break;
- case CC_OV6630:
- s_win.clockdiv = 0;
- break;
- case CC_OV76BE:
- case CC_OV7610:
- case CC_OV7620:
- s_win.clockdiv = 0;
- break;
- default:
- s_win.clockdiv = W9968CF_DEF_CLOCKDIVISOR;
- }
-
- /* We have to scale win.x and win.y offsets */
- if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
- || (cam->vpp_flag & VPP_UPSCALE) ) {
- ax = SC(win.x)/fw;
- ay = SC(win.y)/fh;
- } else {
- ax = win.x;
- ay = win.y;
- }
-
- if ((ax + cw) > cam->maxwidth)
- ax = cam->maxwidth - cw;
-
- if ((ay + ch) > cam->maxheight)
- ay = cam->maxheight - ch;
-
- /* Adjust win.x, win.y */
- if ( (cam->largeview && !(cam->vpp_flag & VPP_UPSCALE))
- || (cam->vpp_flag & VPP_UPSCALE) ) {
- win.x = UNSC(ax*fw);
- win.y = UNSC(ay*fh);
- } else {
- win.x = ax;
- win.y = ay;
- }
-
- /* Offsets used by the chip */
- x = ax + s_win.x;
- y = ay + s_win.y;
-
- /* Go ! */
- if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_MODE, &s_win)))
- goto error;
-
- err += w9968cf_write_reg(cam, scx + x, 0x10);
- err += w9968cf_write_reg(cam, scy + y, 0x11);
- err += w9968cf_write_reg(cam, scx + x + cw, 0x12);
- err += w9968cf_write_reg(cam, scy + y + ch, 0x13);
- err += w9968cf_write_reg(cam, w, 0x14);
- err += w9968cf_write_reg(cam, h, 0x15);
-
- /* JPEG width & height */
- err += w9968cf_write_reg(cam, w, 0x30);
- err += w9968cf_write_reg(cam, h, 0x31);
-
- /* Y & UV frame buffer strides (in WORD) */
- if (cam->vpp_flag & VPP_DECOMPRESSION) {
- err += w9968cf_write_reg(cam, w/2, 0x2c);
- err += w9968cf_write_reg(cam, w/4, 0x2d);
- } else
- err += w9968cf_write_reg(cam, w, 0x2c);
-
- if (err)
- goto error;
-
- /* If all went well, update the device data structure */
- memcpy(&cam->window, &win, sizeof(win));
- cam->hw_width = w;
- cam->hw_height = h;
-
- /* Settings changed, so we clear the frame buffers */
- memset(cam->frame[0].buffer, 0, cam->nbuffers*cam->frame[0].size);
-
- DBG(4, "The capture area is %dx%d, Offset (x,y)=(%u,%u)",
- win.width, win.height, win.x, win.y)
-
- PDBGG("x=%u ,y=%u, w=%u, h=%u, ax=%u, ay=%u, s_win.x=%u, s_win.y=%u, "
- "cw=%u, ch=%u, win.x=%u, win.y=%u, win.width=%u, win.height=%u",
- x, y, w, h, ax, ay, s_win.x, s_win.y, cw, ch, win.x, win.y,
- win.width, win.height)
-
- return 0;
-
-error:
- DBG(1, "Failed to change the capture area size")
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Adjust the asked values for window width and height.
- Return 0 on success, -1 otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_adjust_window_size(struct w9968cf_device *cam, u32 *width, u32 *height)
-{
- unsigned int maxw, maxh, align;
-
- maxw = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
- w9968cf_vpp ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
- : cam->maxwidth;
- maxh = cam->upscaling && !(cam->vpp_flag & VPP_DECOMPRESSION) &&
- w9968cf_vpp ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
- : cam->maxheight;
- align = (cam->vpp_flag & VPP_DECOMPRESSION) ? 4 : 0;
-
- v4l_bound_align_image(width, cam->minwidth, maxw, align,
- height, cam->minheight, maxh, align, 0);
-
- PDBGG("Window size adjusted w=%u, h=%u ", *width, *height)
-
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Initialize the FIFO list of requested frames.
- --------------------------------------------------------------------------*/
-static void w9968cf_init_framelist(struct w9968cf_device* cam)
-{
- u8 i;
-
- for (i = 0; i < cam->nbuffers; i++) {
- cam->requested_frame[i] = NULL;
- cam->frame[i].queued = 0;
- cam->frame[i].status = F_UNUSED;
- }
-}
-
-
-/*--------------------------------------------------------------------------
- Add a frame in the FIFO list of requested frames.
- This function is called in process context.
- --------------------------------------------------------------------------*/
-static void w9968cf_push_frame(struct w9968cf_device* cam, u8 f_num)
-{
- u8 f;
- unsigned long lock_flags;
-
- spin_lock_irqsave(&cam->flist_lock, lock_flags);
-
- for (f=0; cam->requested_frame[f] != NULL; f++);
- cam->requested_frame[f] = &cam->frame[f_num];
- cam->frame[f_num].queued = 1;
- cam->frame[f_num].status = F_UNUSED; /* clear the status */
-
- spin_unlock_irqrestore(&cam->flist_lock, lock_flags);
-
- DBG(6, "Frame #%u pushed into the FIFO list. Position %u", f_num, f)
-}
-
-
-/*--------------------------------------------------------------------------
- Read, store and remove the first pointer in the FIFO list of requested
- frames. This function is called in interrupt context.
- --------------------------------------------------------------------------*/
-static void
-w9968cf_pop_frame(struct w9968cf_device* cam, struct w9968cf_frame_t** framep)
-{
- u8 i;
-
- spin_lock(&cam->flist_lock);
-
- *framep = cam->requested_frame[0];
-
- /* Shift the list of pointers */
- for (i = 0; i < cam->nbuffers-1; i++)
- cam->requested_frame[i] = cam->requested_frame[i+1];
- cam->requested_frame[i] = NULL;
-
- spin_unlock(&cam->flist_lock);
-
- DBG(6,"Popped frame #%d from the list", (*framep)->number)
-}
-
-
-/*--------------------------------------------------------------------------
- High-level video post-processing routine on grabbed frames.
- Return 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_postprocess_frame(struct w9968cf_device* cam,
- struct w9968cf_frame_t* fr)
-{
- void *pIn = fr->buffer, *pOut = cam->frame_vpp.buffer, *tmp;
- u16 w = cam->window.width,
- h = cam->window.height,
- d = cam->picture.depth,
- fmt = cam->picture.palette,
- rgb = cam->force_rgb,
- hw_w = cam->hw_width,
- hw_h = cam->hw_height,
- hw_d = cam->hw_depth;
- int err = 0;
-
- #define _PSWAP(pIn, pOut) {tmp = (pIn); (pIn) = (pOut); (pOut) = tmp;}
-
- if (cam->vpp_flag & VPP_DECOMPRESSION) {
- memcpy(pOut, pIn, fr->length);
- _PSWAP(pIn, pOut)
- err = w9968cf_vpp->decode(pIn, fr->length, hw_w, hw_h, pOut);
- PDBGG("Compressed frame length: %lu",(unsigned long)fr->length)
- fr->length = (hw_w*hw_h*hw_d)/8;
- _PSWAP(pIn, pOut)
- if (err) {
- DBG(4, "An error occurred while decoding the frame: "
- "%s", symbolic(decoder_errlist, err))
- return err;
- } else
- DBG(6, "Frame decoded")
- }
-
- if (cam->vpp_flag & VPP_SWAP_YUV_BYTES) {
- w9968cf_vpp->swap_yuvbytes(pIn, fr->length);
- DBG(6, "Original UYVY component ordering changed")
- }
-
- if (cam->vpp_flag & VPP_UPSCALE) {
- w9968cf_vpp->scale_up(pIn, pOut, hw_w, hw_h, hw_d, w, h);
- fr->length = (w*h*hw_d)/8;
- _PSWAP(pIn, pOut)
- DBG(6, "Vertical up-scaling done: %u,%u,%ubpp->%u,%u",
- hw_w, hw_h, hw_d, w, h)
- }
-
- if (cam->vpp_flag & VPP_UYVY_TO_RGBX) {
- w9968cf_vpp->uyvy_to_rgbx(pIn, fr->length, pOut, fmt, rgb);
- fr->length = (w*h*d)/8;
- _PSWAP(pIn, pOut)
- DBG(6, "UYVY-16bit to %s conversion done",
- symbolic(v4l1_plist, fmt))
- }
-
- if (pOut == fr->buffer)
- memcpy(fr->buffer, cam->frame_vpp.buffer, fr->length);
-
- return 0;
-}
-
-
-
-/****************************************************************************
- * Image sensor control routines *
- ****************************************************************************/
-
-static int
-w9968cf_sensor_set_control(struct w9968cf_device* cam, int cid, int val)
-{
- struct ovcamchip_control ctl;
- int err;
-
- ctl.id = cid;
- ctl.value = val;
-
- err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_S_CTRL, &ctl);
-
- return err;
-}
-
-
-static int
-w9968cf_sensor_get_control(struct w9968cf_device* cam, int cid, int* val)
-{
- struct ovcamchip_control ctl;
- int err;
-
- ctl.id = cid;
-
- err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_G_CTRL, &ctl);
- if (!err)
- *val = ctl.value;
-
- return err;
-}
-
-
-static int
-w9968cf_sensor_cmd(struct w9968cf_device* cam, unsigned int cmd, void* arg)
-{
- int rc;
-
- rc = v4l2_subdev_call(cam->sensor_sd, core, ioctl, cmd, arg);
- /* The I2C driver returns -EPERM on non-supported controls */
- return (rc < 0 && rc != -EPERM) ? rc : 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Update some settings of the image sensor.
- Returns: 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_sensor_update_settings(struct w9968cf_device* cam)
-{
- int err = 0;
-
- /* Auto brightness */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOBRIGHT,
- cam->auto_brt);
- if (err)
- return err;
-
- /* Auto exposure */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_AUTOEXP,
- cam->auto_exp);
- if (err)
- return err;
-
- /* Banding filter */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BANDFILT,
- cam->bandfilt);
- if (err)
- return err;
-
- /* Light frequency */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_FREQ,
- cam->lightfreq);
- if (err)
- return err;
-
- /* Back light */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BACKLIGHT,
- cam->backlight);
- if (err)
- return err;
-
- /* Mirror */
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_MIRROR,
- cam->mirror);
- if (err)
- return err;
-
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Get some current picture settings from the image sensor and update the
- internal 'picture' structure of the camera.
- Returns: 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_sensor_get_picture(struct w9968cf_device* cam)
-{
- int err, v;
-
- err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_CONT, &v);
- if (err)
- return err;
- cam->picture.contrast = v;
-
- err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_BRIGHT, &v);
- if (err)
- return err;
- cam->picture.brightness = v;
-
- err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_SAT, &v);
- if (err)
- return err;
- cam->picture.colour = v;
-
- err = w9968cf_sensor_get_control(cam, OVCAMCHIP_CID_HUE, &v);
- if (err)
- return err;
- cam->picture.hue = v;
-
- DBG(5, "Got picture settings from the image sensor")
-
- PDBGG("Brightness, contrast, hue, colour, whiteness are "
- "%u,%u,%u,%u,%u", cam->picture.brightness,cam->picture.contrast,
- cam->picture.hue, cam->picture.colour, cam->picture.whiteness)
-
- return 0;
-}
-
-
-/*--------------------------------------------------------------------------
- Update picture settings of the image sensor.
- Returns: 0 on success, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int
-w9968cf_sensor_update_picture(struct w9968cf_device* cam,
- struct video_picture pict)
-{
- int err = 0;
-
- if ((!cam->sensor_initialized)
- || pict.contrast != cam->picture.contrast) {
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_CONT,
- pict.contrast);
- if (err)
- goto fail;
- DBG(4, "Contrast changed from %u to %u",
- cam->picture.contrast, pict.contrast)
- cam->picture.contrast = pict.contrast;
- }
-
- if (((!cam->sensor_initialized) ||
- pict.brightness != cam->picture.brightness) && (!cam->auto_brt)) {
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_BRIGHT,
- pict.brightness);
- if (err)
- goto fail;
- DBG(4, "Brightness changed from %u to %u",
- cam->picture.brightness, pict.brightness)
- cam->picture.brightness = pict.brightness;
- }
-
- if ((!cam->sensor_initialized) || pict.colour != cam->picture.colour) {
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_SAT,
- pict.colour);
- if (err)
- goto fail;
- DBG(4, "Colour changed from %u to %u",
- cam->picture.colour, pict.colour)
- cam->picture.colour = pict.colour;
- }
-
- if ((!cam->sensor_initialized) || pict.hue != cam->picture.hue) {
- err = w9968cf_sensor_set_control(cam, OVCAMCHIP_CID_HUE,
- pict.hue);
- if (err)
- goto fail;
- DBG(4, "Hue changed from %u to %u",
- cam->picture.hue, pict.hue)
- cam->picture.hue = pict.hue;
- }
-
- return 0;
-
-fail:
- DBG(4, "Failed to change sensor picture setting")
- return err;
-}
-
-
-
-/****************************************************************************
- * Camera configuration *
- ****************************************************************************/
-
-/*--------------------------------------------------------------------------
- This function is called when a supported image sensor is detected.
- Return 0 if the initialization succeeds, a negative number otherwise.
- --------------------------------------------------------------------------*/
-static int w9968cf_sensor_init(struct w9968cf_device* cam)
-{
- int err = 0;
-
- if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_INITIALIZE,
- &cam->monochrome)))
- goto error;
-
- if ((err = w9968cf_sensor_cmd(cam, OVCAMCHIP_CMD_Q_SUBTYPE,
- &cam->sensor)))
- goto error;
-
- /* NOTE: Make sure width and height are a multiple of 16 */
- switch (v4l2_i2c_subdev_addr(cam->sensor_sd)) {
- case OV6xx0_SID:
- cam->maxwidth = 352;
- cam->maxheight = 288;
- cam->minwidth = 64;
- cam->minheight = 48;
- break;
- case OV7xx0_SID:
- cam->maxwidth = 640;
- cam->maxheight = 480;
- cam->minwidth = 64;
- cam->minheight = 48;
- break;
- default:
- DBG(1, "Not supported image sensor detected for %s",
- symbolic(camlist, cam->id))
- return -EINVAL;
- }
-
- /* These values depend on the ones in the ovxxx0.c sources */
- switch (cam->sensor) {
- case CC_OV7620:
- cam->start_cropx = 287;
- cam->start_cropy = 35;
- /* Seems to work around a bug in the image sensor */
- cam->vs_polarity = 1;
- cam->hs_polarity = 1;
- break;
- default:
- cam->start_cropx = 320;
- cam->start_cropy = 35;
- cam->vs_polarity = 1;
- cam->hs_polarity = 0;
- }
-
- if ((err = w9968cf_sensor_update_settings(cam)))
- goto error;
-
- if ((err = w9968cf_sensor_update_picture(cam, cam->picture)))
- goto error;
-
- cam->sensor_initialized = 1;
-
- DBG(2, "%s image sensor initialized", symbolic(senlist, cam->sensor))
- return 0;
-
-error:
- cam->sensor_initialized = 0;
- cam->sensor = CC_UNKNOWN;
- DBG(1, "Image sensor initialization failed for %s (%s). "
- "Try to detach and attach this device again",
- symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev))
- return err;
-}
-
-
-/*--------------------------------------------------------------------------
- Fill some basic fields in the main device data structure.
- This function is called once on w9968cf_usb_probe() for each recognized
- camera.
- --------------------------------------------------------------------------*/
-static void
-w9968cf_configure_camera(struct w9968cf_device* cam,
- struct usb_device* udev,
- enum w9968cf_model_id mod_id,
- const unsigned short dev_nr)
-{
- mutex_init(&cam->fileop_mutex);
- init_waitqueue_head(&cam->open);
- spin_lock_init(&cam->urb_lock);
- spin_lock_init(&cam->flist_lock);
-
- cam->users = 0;
- cam->disconnected = 0;
- cam->id = mod_id;
- cam->sensor = CC_UNKNOWN;
- cam->sensor_initialized = 0;
-
- /* Calculate the alternate setting number (from 1 to 16)
- according to the 'packet_size' module parameter */
- if (packet_size[dev_nr] < W9968CF_MIN_PACKET_SIZE)
- packet_size[dev_nr] = W9968CF_MIN_PACKET_SIZE;
- for (cam->altsetting = 1;
- packet_size[dev_nr] < wMaxPacketSize[cam->altsetting-1];
- cam->altsetting++);
-
- cam->max_buffers = (max_buffers[dev_nr] < 2 ||
- max_buffers[dev_nr] > W9968CF_MAX_BUFFERS)
- ? W9968CF_BUFFERS : (u8)max_buffers[dev_nr];
-
- cam->double_buffer = (double_buffer[dev_nr] == 0 ||
- double_buffer[dev_nr] == 1)
- ? (u8)double_buffer[dev_nr]:W9968CF_DOUBLE_BUFFER;
-
- cam->clamping = (clamping[dev_nr] == 0 || clamping[dev_nr] == 1)
- ? (u8)clamping[dev_nr] : W9968CF_CLAMPING;
-
- cam->filter_type = (filter_type[dev_nr] == 0 ||
- filter_type[dev_nr] == 1 ||
- filter_type[dev_nr] == 2)
- ? (u8)filter_type[dev_nr] : W9968CF_FILTER_TYPE;
-
- cam->capture = 1;
-
- cam->largeview = (largeview[dev_nr] == 0 || largeview[dev_nr] == 1)
- ? (u8)largeview[dev_nr] : W9968CF_LARGEVIEW;
-
- cam->decompression = (decompression[dev_nr] == 0 ||
- decompression[dev_nr] == 1 ||
- decompression[dev_nr] == 2)
- ? (u8)decompression[dev_nr]:W9968CF_DECOMPRESSION;
-
- cam->upscaling = (upscaling[dev_nr] == 0 ||
- upscaling[dev_nr] == 1)
- ? (u8)upscaling[dev_nr] : W9968CF_UPSCALING;
-
- cam->auto_brt = (autobright[dev_nr] == 0 || autobright[dev_nr] == 1)
- ? (u8)autobright[dev_nr] : W9968CF_AUTOBRIGHT;
-
- cam->auto_exp = (autoexp[dev_nr] == 0 || autoexp[dev_nr] == 1)
- ? (u8)autoexp[dev_nr] : W9968CF_AUTOEXP;
-
- cam->lightfreq = (lightfreq[dev_nr] == 50 || lightfreq[dev_nr] == 60)
- ? (u8)lightfreq[dev_nr] : W9968CF_LIGHTFREQ;
-
- cam->bandfilt = (bandingfilter[dev_nr] == 0 ||
- bandingfilter[dev_nr] == 1)
- ? (u8)bandingfilter[dev_nr] : W9968CF_BANDINGFILTER;
-
- cam->backlight = (backlight[dev_nr] == 0 || backlight[dev_nr] == 1)
- ? (u8)backlight[dev_nr] : W9968CF_BACKLIGHT;
-
- cam->clockdiv = (clockdiv[dev_nr] == -1 || clockdiv[dev_nr] >= 0)
- ? (s8)clockdiv[dev_nr] : W9968CF_CLOCKDIV;
-
- cam->mirror = (mirror[dev_nr] == 0 || mirror[dev_nr] == 1)
- ? (u8)mirror[dev_nr] : W9968CF_MIRROR;
-
- cam->monochrome = (monochrome[dev_nr] == 0 || monochrome[dev_nr] == 1)
- ? monochrome[dev_nr] : W9968CF_MONOCHROME;
-
- cam->picture.brightness = (u16)brightness[dev_nr];
- cam->picture.hue = (u16)hue[dev_nr];
- cam->picture.colour = (u16)colour[dev_nr];
- cam->picture.contrast = (u16)contrast[dev_nr];
- cam->picture.whiteness = (u16)whiteness[dev_nr];
- if (w9968cf_valid_palette((u16)force_palette[dev_nr])) {
- cam->picture.palette = (u16)force_palette[dev_nr];
- cam->force_palette = 1;
- } else {
- cam->force_palette = 0;
- if (cam->decompression == 0)
- cam->picture.palette = W9968CF_PALETTE_DECOMP_OFF;
- else if (cam->decompression == 1)
- cam->picture.palette = W9968CF_PALETTE_DECOMP_FORCE;
- else
- cam->picture.palette = W9968CF_PALETTE_DECOMP_ON;
- }
- cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
-
- cam->force_rgb = (force_rgb[dev_nr] == 0 || force_rgb[dev_nr] == 1)
- ? (u8)force_rgb[dev_nr] : W9968CF_FORCE_RGB;
-
- cam->window.x = 0;
- cam->window.y = 0;
- cam->window.width = W9968CF_WIDTH;
- cam->window.height = W9968CF_HEIGHT;
- cam->window.chromakey = 0;
- cam->window.clipcount = 0;
- cam->window.flags = 0;
-
- DBG(3, "%s configured with settings #%u:",
- symbolic(camlist, cam->id), dev_nr)
-
- DBG(3, "- Data packet size for USB isochrnous transfer: %u bytes",
- wMaxPacketSize[cam->altsetting-1])
-
- DBG(3, "- Number of requested video frame buffers: %u",
- cam->max_buffers)
-
- if (cam->double_buffer)
- DBG(3, "- Hardware double buffering enabled")
- else
- DBG(3, "- Hardware double buffering disabled")
-
- if (cam->filter_type == 0)
- DBG(3, "- Video filtering disabled")
- else if (cam->filter_type == 1)
- DBG(3, "- Video filtering enabled: type 1-2-1")
- else if (cam->filter_type == 2)
- DBG(3, "- Video filtering enabled: type 2-3-6-3-2")
-
- if (cam->clamping)
- DBG(3, "- Video data clamping (CCIR-601 format) enabled")
- else
- DBG(3, "- Video data clamping (CCIR-601 format) disabled")
-
- if (cam->largeview)
- DBG(3, "- Large view enabled")
- else
- DBG(3, "- Large view disabled")
-
- if ((cam->decompression) == 0 && (!cam->force_palette))
- DBG(3, "- Decompression disabled")
- else if ((cam->decompression) == 1 && (!cam->force_palette))
- DBG(3, "- Decompression forced")
- else if ((cam->decompression) == 2 && (!cam->force_palette))
- DBG(3, "- Decompression allowed")
-
- if (cam->upscaling)
- DBG(3, "- Software image scaling enabled")
- else
- DBG(3, "- Software image scaling disabled")
-
- if (cam->force_palette)
- DBG(3, "- Image palette forced to %s",
- symbolic(v4l1_plist, cam->picture.palette))
-
- if (cam->force_rgb)
- DBG(3, "- RGB component ordering will be used instead of BGR")
-
- if (cam->auto_brt)
- DBG(3, "- Auto brightness enabled")
- else
- DBG(3, "- Auto brightness disabled")
-
- if (cam->auto_exp)
- DBG(3, "- Auto exposure enabled")
- else
- DBG(3, "- Auto exposure disabled")
-
- if (cam->backlight)
- DBG(3, "- Backlight exposure algorithm enabled")
- else
- DBG(3, "- Backlight exposure algorithm disabled")
-
- if (cam->mirror)
- DBG(3, "- Mirror enabled")
- else
- DBG(3, "- Mirror disabled")
-
- if (cam->bandfilt)
- DBG(3, "- Banding filter enabled")
- else
- DBG(3, "- Banding filter disabled")
-
- DBG(3, "- Power lighting frequency: %u", cam->lightfreq)
-
- if (cam->clockdiv == -1)
- DBG(3, "- Automatic clock divisor enabled")
- else
- DBG(3, "- Clock divisor: %d", cam->clockdiv)
-
- if (cam->monochrome)
- DBG(3, "- Image sensor used as monochrome")
- else
- DBG(3, "- Image sensor not used as monochrome")
-}
-
-
-/*--------------------------------------------------------------------------
- If the video post-processing module is not loaded, some parameters
- must be overridden.
- --------------------------------------------------------------------------*/
-static void w9968cf_adjust_configuration(struct w9968cf_device* cam)
-{
- if (!w9968cf_vpp) {
- if (cam->decompression == 1) {
- cam->decompression = 2;
- DBG(2, "Video post-processing module not found: "
- "'decompression' parameter forced to 2")
- }
- if (cam->upscaling) {
- cam->upscaling = 0;
- DBG(2, "Video post-processing module not found: "
- "'upscaling' parameter forced to 0")
- }
- if (cam->picture.palette != VIDEO_PALETTE_UYVY) {
- cam->force_palette = 0;
- DBG(2, "Video post-processing module not found: "
- "'force_palette' parameter forced to 0")
- }
- cam->picture.palette = VIDEO_PALETTE_UYVY;
- cam->picture.depth = w9968cf_valid_depth(cam->picture.palette);
- }
-}
-
-
-/*--------------------------------------------------------------------------
- Release the resources used by the driver.
- This function is called on disconnect
- (or on close if deallocation has been deferred)
- --------------------------------------------------------------------------*/
-static void w9968cf_release_resources(struct w9968cf_device* cam)
-{
- mutex_lock(&w9968cf_devlist_mutex);
-
- DBG(2, "V4L device deregistered: %s",
- video_device_node_name(cam->v4ldev))
-
- video_unregister_device(cam->v4ldev);
- list_del(&cam->v4llist);
- i2c_del_adapter(&cam->i2c_adapter);
- w9968cf_deallocate_memory(cam);
- kfree(cam->control_buffer);
- kfree(cam->data_buffer);
- v4l2_device_unregister(&cam->v4l2_dev);
-
- mutex_unlock(&w9968cf_devlist_mutex);
-}
-
-
-
-/****************************************************************************
- * Video4Linux interface *
- ****************************************************************************/
-
-static int w9968cf_open(struct file *filp)
-{
- struct w9968cf_device* cam;
- int err;
-
- /* This the only safe way to prevent race conditions with disconnect */
- if (!down_read_trylock(&w9968cf_disconnect))
- return -EAGAIN;
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- mutex_lock(&cam->dev_mutex);
-
- if (cam->sensor == CC_UNKNOWN) {
- DBG(2, "No supported image sensor has been detected by the "
- "'ovcamchip' module for the %s (%s). Make sure "
- "it is loaded *before* (re)connecting the camera.",
- symbolic(camlist, cam->id),
- video_device_node_name(cam->v4ldev))
- mutex_unlock(&cam->dev_mutex);
- up_read(&w9968cf_disconnect);
- return -ENODEV;
- }
-
- if (cam->users) {
- DBG(2, "%s (%s) has been already occupied by '%s'",
- symbolic(camlist, cam->id),
- video_device_node_name(cam->v4ldev), cam->command)
- if ((filp->f_flags & O_NONBLOCK)||(filp->f_flags & O_NDELAY)) {
- mutex_unlock(&cam->dev_mutex);
- up_read(&w9968cf_disconnect);
- return -EWOULDBLOCK;
- }
- mutex_unlock(&cam->dev_mutex);
- err = wait_event_interruptible_exclusive(cam->open,
- cam->disconnected ||
- !cam->users);
- if (err) {
- up_read(&w9968cf_disconnect);
- return err;
- }
- if (cam->disconnected) {
- up_read(&w9968cf_disconnect);
- return -ENODEV;
- }
- mutex_lock(&cam->dev_mutex);
- }
-
- DBG(5, "Opening '%s', %s ...",
- symbolic(camlist, cam->id), video_device_node_name(cam->v4ldev))
-
- cam->streaming = 0;
- cam->misconfigured = 0;
-
- w9968cf_adjust_configuration(cam);
-
- if ((err = w9968cf_allocate_memory(cam)))
- goto deallocate_memory;
-
- if ((err = w9968cf_init_chip(cam)))
- goto deallocate_memory;
-
- if ((err = w9968cf_start_transfer(cam)))
- goto deallocate_memory;
-
- filp->private_data = cam;
-
- cam->users++;
- strcpy(cam->command, current->comm);
-
- init_waitqueue_head(&cam->wait_queue);
-
- DBG(5, "Video device is open")
-
- mutex_unlock(&cam->dev_mutex);
- up_read(&w9968cf_disconnect);
-
- return 0;
-
-deallocate_memory:
- w9968cf_deallocate_memory(cam);
- DBG(2, "Failed to open the video device")
- mutex_unlock(&cam->dev_mutex);
- up_read(&w9968cf_disconnect);
- return err;
-}
-
-
-static int w9968cf_release(struct file *filp)
-{
- struct w9968cf_device* cam;
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- mutex_lock(&cam->dev_mutex); /* prevent disconnect() to be called */
-
- w9968cf_stop_transfer(cam);
-
- if (cam->disconnected) {
- w9968cf_release_resources(cam);
- mutex_unlock(&cam->dev_mutex);
- kfree(cam);
- return 0;
- }
-
- cam->users--;
- w9968cf_deallocate_memory(cam);
- wake_up_interruptible_nr(&cam->open, 1);
-
- DBG(5, "Video device closed")
- mutex_unlock(&cam->dev_mutex);
- return 0;
-}
-
-
-static ssize_t
-w9968cf_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
- struct w9968cf_device* cam;
- struct w9968cf_frame_t* fr;
- int err = 0;
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- if (filp->f_flags & O_NONBLOCK)
- return -EWOULDBLOCK;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->disconnected) {
- DBG(2, "Device not present")
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->misconfigured) {
- DBG(2, "The camera is misconfigured. Close and open it again.")
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (!cam->frame[0].queued)
- w9968cf_push_frame(cam, 0);
-
- if (!cam->frame[1].queued)
- w9968cf_push_frame(cam, 1);
-
- err = wait_event_interruptible(cam->wait_queue,
- cam->frame[0].status == F_READY ||
- cam->frame[1].status == F_READY ||
- cam->disconnected);
- if (err) {
- mutex_unlock(&cam->fileop_mutex);
- return err;
- }
- if (cam->disconnected) {
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- fr = (cam->frame[0].status == F_READY) ? &cam->frame[0]:&cam->frame[1];
-
- if (w9968cf_vpp)
- w9968cf_postprocess_frame(cam, fr);
-
- if (count > fr->length)
- count = fr->length;
-
- if (copy_to_user(buf, fr->buffer, count)) {
- fr->status = F_UNUSED;
- mutex_unlock(&cam->fileop_mutex);
- return -EFAULT;
- }
- *f_pos += count;
-
- fr->status = F_UNUSED;
-
- DBG(5, "%zu bytes read", count)
-
- mutex_unlock(&cam->fileop_mutex);
- return count;
-}
-
-
-static int w9968cf_mmap(struct file* filp, struct vm_area_struct *vma)
-{
- struct w9968cf_device* cam = (struct w9968cf_device*)
- video_get_drvdata(video_devdata(filp));
- unsigned long vsize = vma->vm_end - vma->vm_start,
- psize = cam->nbuffers * cam->frame[0].size,
- start = vma->vm_start,
- pos = (unsigned long)cam->frame[0].buffer,
- page;
-
- if (cam->disconnected) {
- DBG(2, "Device not present")
- return -ENODEV;
- }
-
- if (cam->misconfigured) {
- DBG(2, "The camera is misconfigured. Close and open it again")
- return -EIO;
- }
-
- PDBGG("mmapping %lu bytes...", vsize)
-
- if (vsize > psize - (vma->vm_pgoff << PAGE_SHIFT))
- return -EINVAL;
-
- while (vsize > 0) {
- page = vmalloc_to_pfn((void *)pos);
- if (remap_pfn_range(vma, start, page + vma->vm_pgoff,
- PAGE_SIZE, vma->vm_page_prot))
- return -EAGAIN;
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- vsize -= PAGE_SIZE;
- }
-
- DBG(5, "mmap method successfully called")
- return 0;
-}
-
-
-static long
-w9968cf_ioctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct w9968cf_device* cam;
- long err;
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->disconnected) {
- DBG(2, "Device not present")
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->misconfigured) {
- DBG(2, "The camera is misconfigured. Close and open it again.")
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- err = w9968cf_v4l_ioctl(filp, cmd, (void __user *)arg);
-
- mutex_unlock(&cam->fileop_mutex);
- return err;
-}
-
-
-static long w9968cf_v4l_ioctl(struct file *filp,
- unsigned int cmd, void __user *arg)
-{
- struct w9968cf_device* cam;
- const char* v4l1_ioctls[] = {
- "?", "CGAP", "GCHAN", "SCHAN", "GTUNER", "STUNER",
- "GPICT", "SPICT", "CCAPTURE", "GWIN", "SWIN", "GFBUF",
- "SFBUF", "KEY", "GFREQ", "SFREQ", "GAUDIO", "SAUDIO",
- "SYNC", "MCAPTURE", "GMBUF", "GUNIT", "GCAPTURE", "SCAPTURE",
- "SPLAYMODE", "SWRITEMODE", "GPLAYINFO", "SMICROCODE",
- "GVBIFMT", "SVBIFMT"
- };
-
- #define V4L1_IOCTL(cmd) \
- ((_IOC_NR((cmd)) < ARRAY_SIZE(v4l1_ioctls)) ? \
- v4l1_ioctls[_IOC_NR((cmd))] : "?")
-
- cam = (struct w9968cf_device*)video_get_drvdata(video_devdata(filp));
-
- switch (cmd) {
-
- case VIDIOCGCAP: /* get video capability */
- {
- struct video_capability cap = {
- .type = VID_TYPE_CAPTURE | VID_TYPE_SCALES,
- .channels = 1,
- .audios = 0,
- .minwidth = cam->minwidth,
- .minheight = cam->minheight,
- };
- sprintf(cap.name, "W996[87]CF USB Camera");
- cap.maxwidth = (cam->upscaling && w9968cf_vpp)
- ? max((u16)W9968CF_MAX_WIDTH, cam->maxwidth)
- : cam->maxwidth;
- cap.maxheight = (cam->upscaling && w9968cf_vpp)
- ? max((u16)W9968CF_MAX_HEIGHT, cam->maxheight)
- : cam->maxheight;
-
- if (copy_to_user(arg, &cap, sizeof(cap)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGCAP successfully called")
- return 0;
- }
-
- case VIDIOCGCHAN: /* get video channel informations */
- {
- struct video_channel chan;
- if (copy_from_user(&chan, arg, sizeof(chan)))
- return -EFAULT;
-
- if (chan.channel != 0)
- return -EINVAL;
-
- strcpy(chan.name, "Camera");
- chan.tuners = 0;
- chan.flags = 0;
- chan.type = VIDEO_TYPE_CAMERA;
- chan.norm = VIDEO_MODE_AUTO;
-
- if (copy_to_user(arg, &chan, sizeof(chan)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGCHAN successfully called")
- return 0;
- }
-
- case VIDIOCSCHAN: /* set active channel */
- {
- struct video_channel chan;
-
- if (copy_from_user(&chan, arg, sizeof(chan)))
- return -EFAULT;
-
- if (chan.channel != 0)
- return -EINVAL;
-
- DBG(5, "VIDIOCSCHAN successfully called")
- return 0;
- }
-
- case VIDIOCGPICT: /* get image properties of the picture */
- {
- if (w9968cf_sensor_get_picture(cam))
- return -EIO;
-
- if (copy_to_user(arg, &cam->picture, sizeof(cam->picture)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGPICT successfully called")
- return 0;
- }
-
- case VIDIOCSPICT: /* change picture settings */
- {
- struct video_picture pict;
- int err = 0;
-
- if (copy_from_user(&pict, arg, sizeof(pict)))
- return -EFAULT;
-
- if ( (cam->force_palette || !w9968cf_vpp)
- && pict.palette != cam->picture.palette ) {
- DBG(4, "Palette %s rejected: only %s is allowed",
- symbolic(v4l1_plist, pict.palette),
- symbolic(v4l1_plist, cam->picture.palette))
- return -EINVAL;
- }
-
- if (!w9968cf_valid_palette(pict.palette)) {
- DBG(4, "Palette %s not supported. VIDIOCSPICT failed",
- symbolic(v4l1_plist, pict.palette))
- return -EINVAL;
- }
-
- if (!cam->force_palette) {
- if (cam->decompression == 0) {
- if (w9968cf_need_decompression(pict.palette)) {
- DBG(4, "Decompression disabled: palette %s is not "
- "allowed. VIDIOCSPICT failed",
- symbolic(v4l1_plist, pict.palette))
- return -EINVAL;
- }
- } else if (cam->decompression == 1) {
- if (!w9968cf_need_decompression(pict.palette)) {
- DBG(4, "Decompression forced: palette %s is not "
- "allowed. VIDIOCSPICT failed",
- symbolic(v4l1_plist, pict.palette))
- return -EINVAL;
- }
- }
- }
-
- if (pict.depth != w9968cf_valid_depth(pict.palette)) {
- DBG(4, "Requested depth %u bpp is not valid for %s "
- "palette: ignored and changed to %u bpp",
- pict.depth, symbolic(v4l1_plist, pict.palette),
- w9968cf_valid_depth(pict.palette))
- pict.depth = w9968cf_valid_depth(pict.palette);
- }
-
- if (pict.palette != cam->picture.palette) {
- if(*cam->requested_frame
- || cam->frame_current->queued) {
- err = wait_event_interruptible
- ( cam->wait_queue,
- cam->disconnected ||
- (!*cam->requested_frame &&
- !cam->frame_current->queued) );
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- }
-
- if (w9968cf_stop_transfer(cam))
- goto ioctl_fail;
-
- if (w9968cf_set_picture(cam, pict))
- goto ioctl_fail;
-
- if (w9968cf_start_transfer(cam))
- goto ioctl_fail;
-
- } else if (w9968cf_sensor_update_picture(cam, pict))
- return -EIO;
-
-
- DBG(5, "VIDIOCSPICT successfully called")
- return 0;
- }
-
- case VIDIOCSWIN: /* set capture area */
- {
- struct video_window win;
- int err = 0;
-
- if (copy_from_user(&win, arg, sizeof(win)))
- return -EFAULT;
-
- DBG(6, "VIDIOCSWIN called: clipcount=%d, flags=%u, "
- "x=%u, y=%u, %ux%u", win.clipcount, win.flags,
- win.x, win.y, win.width, win.height)
-
- if (win.clipcount != 0 || win.flags != 0)
- return -EINVAL;
-
- if ((err = w9968cf_adjust_window_size(cam, &win.width,
- &win.height))) {
- DBG(4, "Resolution not supported (%ux%u). "
- "VIDIOCSWIN failed", win.width, win.height)
- return err;
- }
-
- if (win.x != cam->window.x ||
- win.y != cam->window.y ||
- win.width != cam->window.width ||
- win.height != cam->window.height) {
- if(*cam->requested_frame
- || cam->frame_current->queued) {
- err = wait_event_interruptible
- ( cam->wait_queue,
- cam->disconnected ||
- (!*cam->requested_frame &&
- !cam->frame_current->queued) );
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- }
-
- if (w9968cf_stop_transfer(cam))
- goto ioctl_fail;
-
- /* This _must_ be called before set_window() */
- if (w9968cf_set_picture(cam, cam->picture))
- goto ioctl_fail;
-
- if (w9968cf_set_window(cam, win))
- goto ioctl_fail;
-
- if (w9968cf_start_transfer(cam))
- goto ioctl_fail;
- }
-
- DBG(5, "VIDIOCSWIN successfully called. ")
- return 0;
- }
-
- case VIDIOCGWIN: /* get current window properties */
- {
- if (copy_to_user(arg,&cam->window,sizeof(struct video_window)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGWIN successfully called")
- return 0;
- }
-
- case VIDIOCGMBUF: /* request for memory (mapped) buffer */
- {
- struct video_mbuf mbuf;
- u8 i;
-
- mbuf.size = cam->nbuffers * cam->frame[0].size;
- mbuf.frames = cam->nbuffers;
- for (i = 0; i < cam->nbuffers; i++)
- mbuf.offsets[i] = (unsigned long)cam->frame[i].buffer -
- (unsigned long)cam->frame[0].buffer;
-
- if (copy_to_user(arg, &mbuf, sizeof(mbuf)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGMBUF successfully called")
- return 0;
- }
-
- case VIDIOCMCAPTURE: /* start the capture to a frame */
- {
- struct video_mmap mmap;
- struct w9968cf_frame_t* fr;
- u32 w, h;
- int err = 0;
-
- if (copy_from_user(&mmap, arg, sizeof(mmap)))
- return -EFAULT;
-
- DBG(6, "VIDIOCMCAPTURE called: frame #%u, format=%s, %dx%d",
- mmap.frame, symbolic(v4l1_plist, mmap.format),
- mmap.width, mmap.height)
-
- if (mmap.frame >= cam->nbuffers) {
- DBG(4, "Invalid frame number (%u). "
- "VIDIOCMCAPTURE failed", mmap.frame)
- return -EINVAL;
- }
-
- if (mmap.format!=cam->picture.palette &&
- (cam->force_palette || !w9968cf_vpp)) {
- DBG(4, "Palette %s rejected: only %s is allowed",
- symbolic(v4l1_plist, mmap.format),
- symbolic(v4l1_plist, cam->picture.palette))
- return -EINVAL;
- }
-
- if (!w9968cf_valid_palette(mmap.format)) {
- DBG(4, "Palette %s not supported. "
- "VIDIOCMCAPTURE failed",
- symbolic(v4l1_plist, mmap.format))
- return -EINVAL;
- }
-
- if (!cam->force_palette) {
- if (cam->decompression == 0) {
- if (w9968cf_need_decompression(mmap.format)) {
- DBG(4, "Decompression disabled: palette %s is not "
- "allowed. VIDIOCSPICT failed",
- symbolic(v4l1_plist, mmap.format))
- return -EINVAL;
- }
- } else if (cam->decompression == 1) {
- if (!w9968cf_need_decompression(mmap.format)) {
- DBG(4, "Decompression forced: palette %s is not "
- "allowed. VIDIOCSPICT failed",
- symbolic(v4l1_plist, mmap.format))
- return -EINVAL;
- }
- }
- }
-
- w = mmap.width; h = mmap.height;
- err = w9968cf_adjust_window_size(cam, &w, &h);
- mmap.width = w; mmap.height = h;
- if (err) {
- DBG(4, "Resolution not supported (%dx%d). "
- "VIDIOCMCAPTURE failed",
- mmap.width, mmap.height)
- return err;
- }
-
- fr = &cam->frame[mmap.frame];
-
- if (mmap.width != cam->window.width ||
- mmap.height != cam->window.height ||
- mmap.format != cam->picture.palette) {
-
- struct video_window win;
- struct video_picture pict;
-
- if(*cam->requested_frame
- || cam->frame_current->queued) {
- DBG(6, "VIDIOCMCAPTURE. Change settings for "
- "frame #%u: %dx%d, format %s. Wait...",
- mmap.frame, mmap.width, mmap.height,
- symbolic(v4l1_plist, mmap.format))
- err = wait_event_interruptible
- ( cam->wait_queue,
- cam->disconnected ||
- (!*cam->requested_frame &&
- !cam->frame_current->queued) );
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- }
-
- memcpy(&win, &cam->window, sizeof(win));
- memcpy(&pict, &cam->picture, sizeof(pict));
- win.width = mmap.width;
- win.height = mmap.height;
- pict.palette = mmap.format;
-
- if (w9968cf_stop_transfer(cam))
- goto ioctl_fail;
-
- /* This before set_window */
- if (w9968cf_set_picture(cam, pict))
- goto ioctl_fail;
-
- if (w9968cf_set_window(cam, win))
- goto ioctl_fail;
-
- if (w9968cf_start_transfer(cam))
- goto ioctl_fail;
-
- } else if (fr->queued) {
-
- DBG(6, "Wait until frame #%u is free", mmap.frame)
-
- err = wait_event_interruptible(cam->wait_queue,
- cam->disconnected ||
- (!fr->queued));
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- }
-
- w9968cf_push_frame(cam, mmap.frame);
- DBG(5, "VIDIOCMCAPTURE(%u): successfully called", mmap.frame)
- return 0;
- }
-
- case VIDIOCSYNC: /* wait until the capture of a frame is finished */
- {
- unsigned int f_num;
- struct w9968cf_frame_t* fr;
- int err = 0;
-
- if (copy_from_user(&f_num, arg, sizeof(f_num)))
- return -EFAULT;
-
- if (f_num >= cam->nbuffers) {
- DBG(4, "Invalid frame number (%u). "
- "VIDIOCMCAPTURE failed", f_num)
- return -EINVAL;
- }
-
- DBG(6, "VIDIOCSYNC called for frame #%u", f_num)
-
- fr = &cam->frame[f_num];
-
- switch (fr->status) {
- case F_UNUSED:
- if (!fr->queued) {
- DBG(4, "VIDIOSYNC: Frame #%u not requested!",
- f_num)
- return -EFAULT;
- }
- case F_ERROR:
- case F_GRABBING:
- err = wait_event_interruptible(cam->wait_queue,
- (fr->status == F_READY)
- || cam->disconnected);
- if (err)
- return err;
- if (cam->disconnected)
- return -ENODEV;
- break;
- case F_READY:
- break;
- }
-
- if (w9968cf_vpp)
- w9968cf_postprocess_frame(cam, fr);
-
- fr->status = F_UNUSED;
-
- DBG(5, "VIDIOCSYNC(%u) successfully called", f_num)
- return 0;
- }
-
- case VIDIOCGUNIT:/* report the unit numbers of the associated devices*/
- {
- struct video_unit unit = {
- .video = cam->v4ldev->minor,
- .vbi = VIDEO_NO_UNIT,
- .radio = VIDEO_NO_UNIT,
- .audio = VIDEO_NO_UNIT,
- .teletext = VIDEO_NO_UNIT,
- };
-
- if (copy_to_user(arg, &unit, sizeof(unit)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGUNIT successfully called")
- return 0;
- }
-
- case VIDIOCKEY:
- return 0;
-
- case VIDIOCGFBUF:
- {
- if (clear_user(arg, sizeof(struct video_buffer)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGFBUF successfully called")
- return 0;
- }
-
- case VIDIOCGTUNER:
- {
- struct video_tuner tuner;
- if (copy_from_user(&tuner, arg, sizeof(tuner)))
- return -EFAULT;
-
- if (tuner.tuner != 0)
- return -EINVAL;
-
- strcpy(tuner.name, "no_tuner");
- tuner.rangelow = 0;
- tuner.rangehigh = 0;
- tuner.flags = VIDEO_TUNER_NORM;
- tuner.mode = VIDEO_MODE_AUTO;
- tuner.signal = 0xffff;
-
- if (copy_to_user(arg, &tuner, sizeof(tuner)))
- return -EFAULT;
-
- DBG(5, "VIDIOCGTUNER successfully called")
- return 0;
- }
-
- case VIDIOCSTUNER:
- {
- struct video_tuner tuner;
- if (copy_from_user(&tuner, arg, sizeof(tuner)))
- return -EFAULT;
-
- if (tuner.tuner != 0)
- return -EINVAL;
-
- if (tuner.mode != VIDEO_MODE_AUTO)
- return -EINVAL;
-
- DBG(5, "VIDIOCSTUNER successfully called")
- return 0;
- }
-
- case VIDIOCSFBUF:
- case VIDIOCCAPTURE:
- case VIDIOCGFREQ:
- case VIDIOCSFREQ:
- case VIDIOCGAUDIO:
- case VIDIOCSAUDIO:
- case VIDIOCSPLAYMODE:
- case VIDIOCSWRITEMODE:
- case VIDIOCGPLAYINFO:
- case VIDIOCSMICROCODE:
- case VIDIOCGVBIFMT:
- case VIDIOCSVBIFMT:
- DBG(4, "Unsupported V4L1 IOCtl: VIDIOC%s "
- "(type 0x%01X, "
- "n. 0x%01X, "
- "dir. 0x%01X, "
- "size 0x%02X)",
- V4L1_IOCTL(cmd),
- _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
- return -EINVAL;
-
- default:
- DBG(4, "Invalid V4L1 IOCtl: VIDIOC%s "
- "type 0x%01X, "
- "n. 0x%01X, "
- "dir. 0x%01X, "
- "size 0x%02X",
- V4L1_IOCTL(cmd),
- _IOC_TYPE(cmd),_IOC_NR(cmd),_IOC_DIR(cmd),_IOC_SIZE(cmd))
-
- return -ENOIOCTLCMD;
-
- } /* end of switch */
-
-ioctl_fail:
- cam->misconfigured = 1;
- DBG(1, "VIDIOC%s failed because of hardware problems. "
- "To use the camera, close and open it again.", V4L1_IOCTL(cmd))
- return -EFAULT;
-}
-
-
-static const struct v4l2_file_operations w9968cf_fops = {
- .owner = THIS_MODULE,
- .open = w9968cf_open,
- .release = w9968cf_release,
- .read = w9968cf_read,
- .ioctl = w9968cf_ioctl,
- .mmap = w9968cf_mmap,
-};
-
-
-
-/****************************************************************************
- * USB probe and V4L registration, disconnect and id_table[] definition *
- ****************************************************************************/
-
-static int
-w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct w9968cf_device* cam;
- int err = 0;
- enum w9968cf_model_id mod_id;
- struct list_head* ptr;
- u8 sc = 0; /* number of simultaneous cameras */
- static unsigned short dev_nr; /* 0 - we are handling device number n */
- static unsigned short addrs[] = {
- OV7xx0_SID,
- OV6xx0_SID,
- I2C_CLIENT_END
- };
-
- if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor &&
- le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
- mod_id = W9968CF_MOD_CLVBWGP; /* see camlist[] table */
- else if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[1].idVendor &&
- le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[1].idProduct)
- mod_id = W9968CF_MOD_GENERIC; /* see camlist[] table */
- else
- return -ENODEV;
-
- cam = (struct w9968cf_device*)
- kzalloc(sizeof(struct w9968cf_device), GFP_KERNEL);
- if (!cam)
- return -ENOMEM;
-
- err = v4l2_device_register(&intf->dev, &cam->v4l2_dev);
- if (err)
- goto fail0;
-
- mutex_init(&cam->dev_mutex);
- mutex_lock(&cam->dev_mutex);
-
- cam->usbdev = udev;
-
- DBG(2, "%s detected", symbolic(camlist, mod_id))
-
- if (simcams > W9968CF_MAX_DEVICES)
- simcams = W9968CF_SIMCAMS;
-
- /* How many cameras are connected ? */
- mutex_lock(&w9968cf_devlist_mutex);
- list_for_each(ptr, &w9968cf_dev_list)
- sc++;
- mutex_unlock(&w9968cf_devlist_mutex);
-
- if (sc >= simcams) {
- DBG(2, "Device rejected: too many connected cameras "
- "(max. %u)", simcams)
- err = -EPERM;
- goto fail;
- }
-
-
- /* Allocate 2 bytes of memory for camera control USB transfers */
- if (!(cam->control_buffer = kzalloc(2, GFP_KERNEL))) {
- DBG(1,"Couldn't allocate memory for camera control transfers")
- err = -ENOMEM;
- goto fail;
- }
-
- /* Allocate 8 bytes of memory for USB data transfers to the FSB */
- if (!(cam->data_buffer = kzalloc(8, GFP_KERNEL))) {
- DBG(1, "Couldn't allocate memory for data "
- "transfers to the FSB")
- err = -ENOMEM;
- goto fail;
- }
-
- /* Register the V4L device */
- cam->v4ldev = video_device_alloc();
- if (!cam->v4ldev) {
- DBG(1, "Could not allocate memory for a V4L structure")
- err = -ENOMEM;
- goto fail;
- }
-
- strcpy(cam->v4ldev->name, symbolic(camlist, mod_id));
- cam->v4ldev->fops = &w9968cf_fops;
- cam->v4ldev->release = video_device_release;
- video_set_drvdata(cam->v4ldev, cam);
- cam->v4ldev->v4l2_dev = &cam->v4l2_dev;
-
- err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
- video_nr[dev_nr]);
- if (err) {
- DBG(1, "V4L device registration failed")
- if (err == -ENFILE && video_nr[dev_nr] == -1)
- DBG(2, "Couldn't find a free /dev/videoX node")
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
- goto fail;
- }
-
- DBG(2, "V4L device registered as %s",
- video_device_node_name(cam->v4ldev))
-
- /* Set some basic constants */
- w9968cf_configure_camera(cam, udev, mod_id, dev_nr);
-
- /* Add a new entry into the list of V4L registered devices */
- mutex_lock(&w9968cf_devlist_mutex);
- list_add(&cam->v4llist, &w9968cf_dev_list);
- mutex_unlock(&w9968cf_devlist_mutex);
- dev_nr = (dev_nr < W9968CF_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
- w9968cf_turn_on_led(cam);
-
- w9968cf_i2c_init(cam);
- cam->sensor_sd = v4l2_i2c_new_subdev(&cam->v4l2_dev,
- &cam->i2c_adapter,
- "ovcamchip", "ovcamchip", 0, addrs);
-
- usb_set_intfdata(intf, cam);
- mutex_unlock(&cam->dev_mutex);
-
- err = w9968cf_sensor_init(cam);
- return 0;
-
-fail: /* Free unused memory */
- kfree(cam->control_buffer);
- kfree(cam->data_buffer);
- if (cam->v4ldev)
- video_device_release(cam->v4ldev);
- mutex_unlock(&cam->dev_mutex);
- v4l2_device_unregister(&cam->v4l2_dev);
-fail0:
- kfree(cam);
- return err;
-}
-
-
-static void w9968cf_usb_disconnect(struct usb_interface* intf)
-{
- struct w9968cf_device* cam =
- (struct w9968cf_device*)usb_get_intfdata(intf);
-
- if (cam) {
- down_write(&w9968cf_disconnect);
- /* Prevent concurrent accesses to data */
- mutex_lock(&cam->dev_mutex);
-
- cam->disconnected = 1;
-
- DBG(2, "Disconnecting %s...", symbolic(camlist, cam->id));
-
- v4l2_device_disconnect(&cam->v4l2_dev);
-
- wake_up_interruptible_all(&cam->open);
-
- if (cam->users) {
- DBG(2, "The device is open (%s)! "
- "Process name: %s. Deregistration and memory "
- "deallocation are deferred on close.",
- video_device_node_name(cam->v4ldev), cam->command)
- cam->misconfigured = 1;
- w9968cf_stop_transfer(cam);
- wake_up_interruptible(&cam->wait_queue);
- } else
- w9968cf_release_resources(cam);
-
- mutex_unlock(&cam->dev_mutex);
- up_write(&w9968cf_disconnect);
-
- if (!cam->users) {
- kfree(cam);
- }
- }
-}
-
-
-static struct usb_driver w9968cf_usb_driver = {
- .name = "w9968cf",
- .id_table = winbond_id_table,
- .probe = w9968cf_usb_probe,
- .disconnect = w9968cf_usb_disconnect,
-};
-
-
-
-/****************************************************************************
- * Module init, exit and intermodule communication *
- ****************************************************************************/
-
-static int __init w9968cf_module_init(void)
-{
- int err;
-
- KDBG(2, W9968CF_MODULE_NAME" "W9968CF_MODULE_VERSION)
- KDBG(3, W9968CF_MODULE_AUTHOR)
-
- if ((err = usb_register(&w9968cf_usb_driver)))
- return err;
-
- return 0;
-}
-
-
-static void __exit w9968cf_module_exit(void)
-{
- /* w9968cf_usb_disconnect() will be called */
- usb_deregister(&w9968cf_usb_driver);
-
- KDBG(2, W9968CF_MODULE_NAME" deregistered")
-}
-
-
-module_init(w9968cf_module_init);
-module_exit(w9968cf_module_exit);
-
diff --git a/drivers/media/video/w9968cf.h b/drivers/media/video/w9968cf.h
deleted file mode 100644
index 73ad864b4842..000000000000
--- a/drivers/media/video/w9968cf.h
+++ /dev/null
@@ -1,333 +0,0 @@
-/***************************************************************************
- * Video4Linux driver for W996[87]CF JPEG USB Dual Mode Camera Chip. *
- * *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _W9968CF_H_
-#define _W9968CF_H_
-
-#include <linux/videodev2.h>
-#include <linux/usb.h>
-#include <linux/i2c.h>
-#include <linux/device.h>
-#include <linux/spinlock.h>
-#include <linux/list.h>
-#include <linux/wait.h>
-#include <linux/param.h>
-#include <linux/types.h>
-#include <linux/rwsem.h>
-#include <linux/mutex.h>
-
-#include <media/v4l2-device.h>
-#include <media/ovcamchip.h>
-
-#include "w9968cf_vpp.h"
-
-
-/****************************************************************************
- * Default values *
- ****************************************************************************/
-
-#define W9968CF_VPPMOD_LOAD 1 /* automatic 'w9968cf-vpp' module loading */
-
-/* Comment/uncomment the following line to enable/disable debugging messages */
-#define W9968CF_DEBUG
-
-/* These have effect only if W9968CF_DEBUG is defined */
-#define W9968CF_DEBUG_LEVEL 2 /* from 0 to 6. 0 for no debug informations */
-#define W9968CF_SPECIFIC_DEBUG 0 /* 0 or 1 */
-
-#define W9968CF_MAX_DEVICES 32
-#define W9968CF_SIMCAMS W9968CF_MAX_DEVICES /* simultaneous cameras */
-
-#define W9968CF_MAX_BUFFERS 32
-#define W9968CF_BUFFERS 2 /* n. of frame buffers from 2 to MAX_BUFFERS */
-
-/* Maximum data payload sizes in bytes for alternate settings */
-static const u16 wMaxPacketSize[] = {1023, 959, 895, 831, 767, 703, 639, 575,
- 511, 447, 383, 319, 255, 191, 127, 63};
-#define W9968CF_PACKET_SIZE 1023 /* according to wMaxPacketSizes[] */
-#define W9968CF_MIN_PACKET_SIZE 63 /* minimum value */
-#define W9968CF_ISO_PACKETS 5 /* n.of packets for isochronous transfers */
-#define W9968CF_USB_CTRL_TIMEOUT 1000 /* timeout (ms) for usb control commands */
-#define W9968CF_URBS 2 /* n. of scheduled URBs for ISO transfer */
-
-#define W9968CF_I2C_BUS_DELAY 4 /* delay in us for I2C bit r/w operations */
-#define W9968CF_I2C_RW_RETRIES 15 /* number of max I2C r/w retries */
-
-/* Available video formats */
-struct w9968cf_format {
- const u16 palette;
- const u16 depth;
- const u8 compression;
-};
-
-static const struct w9968cf_format w9968cf_formatlist[] = {
- { VIDEO_PALETTE_UYVY, 16, 0 }, /* original video */
- { VIDEO_PALETTE_YUV422P, 16, 1 }, /* with JPEG compression */
- { VIDEO_PALETTE_YUV420P, 12, 1 }, /* with JPEG compression */
- { VIDEO_PALETTE_YUV420, 12, 1 }, /* same as YUV420P */
- { VIDEO_PALETTE_YUYV, 16, 0 }, /* software conversion */
- { VIDEO_PALETTE_YUV422, 16, 0 }, /* software conversion */
- { VIDEO_PALETTE_GREY, 8, 0 }, /* software conversion */
- { VIDEO_PALETTE_RGB555, 16, 0 }, /* software conversion */
- { VIDEO_PALETTE_RGB565, 16, 0 }, /* software conversion */
- { VIDEO_PALETTE_RGB24, 24, 0 }, /* software conversion */
- { VIDEO_PALETTE_RGB32, 32, 0 }, /* software conversion */
- { 0, 0, 0 } /* 0 is a terminating entry */
-};
-
-#define W9968CF_DECOMPRESSION 2 /* decomp:0=disable,1=force,2=any formats */
-#define W9968CF_PALETTE_DECOMP_OFF VIDEO_PALETTE_UYVY /* when decomp=0 */
-#define W9968CF_PALETTE_DECOMP_FORCE VIDEO_PALETTE_YUV420P /* when decomp=1 */
-#define W9968CF_PALETTE_DECOMP_ON VIDEO_PALETTE_UYVY /* when decomp=2 */
-
-#define W9968CF_FORCE_RGB 0 /* read RGB instead of BGR, yes=1/no=0 */
-
-#define W9968CF_MAX_WIDTH 800 /* Has effect if up-scaling is on */
-#define W9968CF_MAX_HEIGHT 600 /* Has effect if up-scaling is on */
-#define W9968CF_WIDTH 320 /* from 128 to 352, multiple of 16 */
-#define W9968CF_HEIGHT 240 /* from 96 to 288, multiple of 16 */
-
-#define W9968CF_CLAMPING 0 /* 0 disable, 1 enable video data clamping */
-#define W9968CF_FILTER_TYPE 0 /* 0 disable 1 (1-2-1), 2 (2-3-6-3-2) */
-#define W9968CF_DOUBLE_BUFFER 1 /* 0 disable, 1 enable double buffer */
-#define W9968CF_LARGEVIEW 1 /* 0 disable, 1 enable */
-#define W9968CF_UPSCALING 0 /* 0 disable, 1 enable */
-
-#define W9968CF_MONOCHROME 0 /* 0 not monochrome, 1 monochrome sensor */
-#define W9968CF_BRIGHTNESS 31000 /* from 0 to 65535 */
-#define W9968CF_HUE 32768 /* from 0 to 65535 */
-#define W9968CF_COLOUR 32768 /* from 0 to 65535 */
-#define W9968CF_CONTRAST 50000 /* from 0 to 65535 */
-#define W9968CF_WHITENESS 32768 /* from 0 to 65535 */
-
-#define W9968CF_AUTOBRIGHT 0 /* 0 disable, 1 enable automatic brightness */
-#define W9968CF_AUTOEXP 1 /* 0 disable, 1 enable automatic exposure */
-#define W9968CF_LIGHTFREQ 50 /* light frequency. 50Hz (Europe) or 60Hz */
-#define W9968CF_BANDINGFILTER 0 /* 0 disable, 1 enable banding filter */
-#define W9968CF_BACKLIGHT 0 /* 0 or 1, 1=object is lit from behind */
-#define W9968CF_MIRROR 0 /* 0 or 1 [don't] reverse image horizontally*/
-
-#define W9968CF_CLOCKDIV -1 /* -1 = automatic clock divisor */
-#define W9968CF_DEF_CLOCKDIVISOR 0 /* default sensor clock divisor value */
-
-
-/****************************************************************************
- * Globals *
- ****************************************************************************/
-
-#define W9968CF_MODULE_NAME "V4L driver for W996[87]CF JPEG USB " \
- "Dual Mode Camera Chip"
-#define W9968CF_MODULE_VERSION "1:1.34-basic"
-#define W9968CF_MODULE_AUTHOR "(C) 2002-2004 Luca Risolia"
-#define W9968CF_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
-#define W9968CF_MODULE_LICENSE "GPL"
-
-static const struct usb_device_id winbond_id_table[] = {
- {
- /* Creative Labs Video Blaster WebCam Go Plus */
- USB_DEVICE(0x041e, 0x4003),
- .driver_info = (unsigned long)"w9968cf",
- },
- {
- /* Generic W996[87]CF JPEG USB Dual Mode Camera */
- USB_DEVICE(0x1046, 0x9967),
- .driver_info = (unsigned long)"w9968cf",
- },
- { } /* terminating entry */
-};
-
-/* W996[87]CF camera models, internal ids: */
-enum w9968cf_model_id {
- W9968CF_MOD_GENERIC = 1, /* Generic W996[87]CF based device */
- W9968CF_MOD_CLVBWGP = 11,/*Creative Labs Video Blaster WebCam Go Plus*/
- W9968CF_MOD_ADPVDMA = 21, /* Aroma Digi Pen VGA Dual Mode ADG-5000 */
- W9986CF_MOD_AAU = 31, /* AVerMedia AVerTV USB */
- W9968CF_MOD_CLVBWG = 34, /* Creative Labs Video Blaster WebCam Go */
- W9968CF_MOD_LL = 37, /* Lebon LDC-035A */
- W9968CF_MOD_EEEMC = 40, /* Ezonics EZ-802 EZMega Cam */
- W9968CF_MOD_OOE = 42, /* OmniVision OV8610-EDE */
- W9968CF_MOD_ODPVDMPC = 43,/* OPCOM Digi Pen VGA Dual Mode Pen Camera */
- W9968CF_MOD_PDPII = 46, /* Pretec Digi Pen-II */
- W9968CF_MOD_PDP480 = 49, /* Pretec DigiPen-480 */
-};
-
-enum w9968cf_frame_status {
- F_READY, /* finished grabbing & ready to be read/synced */
- F_GRABBING, /* in the process of being grabbed into */
- F_ERROR, /* something bad happened while processing */
- F_UNUSED /* unused (no VIDIOCMCAPTURE) */
-};
-
-struct w9968cf_frame_t {
- void* buffer;
- unsigned long size;
- u32 length;
- int number;
- enum w9968cf_frame_status status;
- struct w9968cf_frame_t* next;
- u8 queued;
-};
-
-enum w9968cf_vpp_flag {
- VPP_NONE = 0x00,
- VPP_UPSCALE = 0x01,
- VPP_SWAP_YUV_BYTES = 0x02,
- VPP_DECOMPRESSION = 0x04,
- VPP_UYVY_TO_RGBX = 0x08,
-};
-
-/* Main device driver structure */
-struct w9968cf_device {
- enum w9968cf_model_id id; /* private device identifier */
-
- struct v4l2_device v4l2_dev;
- struct video_device* v4ldev; /* -> V4L structure */
- struct list_head v4llist; /* entry of the list of V4L cameras */
-
- struct usb_device* usbdev; /* -> main USB structure */
- struct urb* urb[W9968CF_URBS]; /* -> USB request block structs */
- void* transfer_buffer[W9968CF_URBS]; /* -> ISO transfer buffers */
- u16* control_buffer; /* -> buffer for control req.*/
- u16* data_buffer; /* -> data to send to the FSB */
-
- struct w9968cf_frame_t frame[W9968CF_MAX_BUFFERS];
- struct w9968cf_frame_t frame_tmp; /* temporary frame */
- struct w9968cf_frame_t frame_vpp; /* helper frame.*/
- struct w9968cf_frame_t* frame_current; /* -> frame being grabbed */
- struct w9968cf_frame_t* requested_frame[W9968CF_MAX_BUFFERS];
-
- u8 max_buffers, /* number of requested buffers */
- force_palette, /* yes=1/no=0 */
- force_rgb, /* read RGB instead of BGR, yes=1, no=0 */
- double_buffer, /* hardware double buffering yes=1/no=0 */
- clamping, /* video data clamping yes=1/no=0 */
- filter_type, /* 0=disabled, 1=3 tap, 2=5 tap filter */
- capture, /* 0=disabled, 1=enabled */
- largeview, /* 0=disabled, 1=enabled */
- decompression, /* 0=disabled, 1=forced, 2=allowed */
- upscaling; /* software image scaling, 0=enabled, 1=disabled */
-
- struct video_picture picture; /* current picture settings */
- struct video_window window; /* current window settings */
-
- u16 hw_depth, /* depth (used by the chip) */
- hw_palette, /* palette (used by the chip) */
- hw_width, /* width (used by the chip) */
- hw_height, /* height (used by the chip) */
- hs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
- vs_polarity, /* 0=negative sync pulse, 1=positive sync pulse */
- start_cropx, /* pixels from HS inactive edge to 1st cropped pixel*/
- start_cropy; /* pixels from VS inactive edge to 1st cropped pixel*/
-
- enum w9968cf_vpp_flag vpp_flag; /* post-processing routines in use */
-
- u8 nbuffers, /* number of allocated frame buffers */
- altsetting, /* camera alternate setting */
- disconnected, /* flag: yes=1, no=0 */
- misconfigured, /* flag: yes=1, no=0 */
- users, /* flag: number of users holding the device */
- streaming; /* flag: yes=1, no=0 */
-
- u8 sensor_initialized; /* flag: yes=1, no=0 */
-
- /* Determined by the image sensor type: */
- int sensor, /* type of image sensor chip (CC_*) */
- monochrome; /* image sensor is (probably) monochrome */
- u16 maxwidth, /* maximum width supported by the image sensor */
- maxheight, /* maximum height supported by the image sensor */
- minwidth, /* minimum width supported by the image sensor */
- minheight; /* minimum height supported by the image sensor */
- u8 auto_brt, /* auto brightness enabled flag */
- auto_exp, /* auto exposure enabled flag */
- backlight, /* backlight exposure algorithm flag */
- mirror, /* image is reversed horizontally */
- lightfreq, /* power (lighting) frequency */
- bandfilt; /* banding filter enabled flag */
- s8 clockdiv; /* clock divisor */
-
- /* I2C interface to kernel */
- struct i2c_adapter i2c_adapter;
- struct v4l2_subdev *sensor_sd;
-
- /* Locks */
- struct mutex dev_mutex, /* for probe, disconnect,open and close */
- fileop_mutex; /* for read and ioctl */
- spinlock_t urb_lock, /* for submit_urb() and unlink_urb() */
- flist_lock; /* for requested frame list accesses */
- wait_queue_head_t open, wait_queue;
-
- char command[16]; /* name of the program holding the device */
-};
-
-static inline struct w9968cf_device *to_cam(struct v4l2_device *v4l2_dev)
-{
- return container_of(v4l2_dev, struct w9968cf_device, v4l2_dev);
-}
-
-
-/****************************************************************************
- * Macros for debugging *
- ****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef W9968CF_DEBUG
-/* For device specific debugging messages */
-# define DBG(level, fmt, args...) \
-{ \
- if ( ((specific_debug) && (debug == (level))) || \
- ((!specific_debug) && (debug >= (level))) ) { \
- if ((level) == 1) \
- v4l2_err(&cam->v4l2_dev, fmt "\n", ## args); \
- else if ((level) == 2 || (level) == 3) \
- v4l2_info(&cam->v4l2_dev, fmt "\n", ## args); \
- else if ((level) == 4) \
- v4l2_warn(&cam->v4l2_dev, fmt "\n", ## args); \
- else if ((level) >= 5) \
- v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", \
- __func__, __LINE__ , ## args); \
- } \
-}
-/* For generic kernel (not device specific) messages */
-# define KDBG(level, fmt, args...) \
-{ \
- if ( ((specific_debug) && (debug == (level))) || \
- ((!specific_debug) && (debug >= (level))) ) { \
- if ((level) >= 1 && (level) <= 4) \
- pr_info("w9968cf: " fmt "\n", ## args); \
- else if ((level) >= 5) \
- pr_debug("w9968cf: [%s:%d] " fmt "\n", __func__, \
- __LINE__ , ## args); \
- } \
-}
-#else
- /* Not debugging: nothing */
-# define DBG(level, fmt, args...) do {;} while(0);
-# define KDBG(level, fmt, args...) do {;} while(0);
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...) \
-v4l2_info(&cam->v4l2_dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
-
-#endif /* _W9968CF_H_ */
diff --git a/drivers/media/video/w9968cf_decoder.h b/drivers/media/video/w9968cf_decoder.h
deleted file mode 100644
index 59decbfc540a..000000000000
--- a/drivers/media/video/w9968cf_decoder.h
+++ /dev/null
@@ -1,86 +0,0 @@
-/***************************************************************************
- * Video decoder for the W996[87]CF driver for Linux. *
- * *
- * Copyright (C) 2003 2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _W9968CF_DECODER_H_
-#define _W9968CF_DECODER_H_
-
-/* Comment/uncomment this for high/low quality of compressed video */
-#define W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-
-#ifdef W9968CF_DEC_FAST_LOWQUALITY_VIDEO
-static const unsigned char Y_QUANTABLE[64] = {
- 16, 11, 10, 16, 24, 40, 51, 61,
- 12, 12, 14, 19, 26, 58, 60, 55,
- 14, 13, 16, 24, 40, 57, 69, 56,
- 14, 17, 22, 29, 51, 87, 80, 62,
- 18, 22, 37, 56, 68, 109, 103, 77,
- 24, 35, 55, 64, 81, 104, 113, 92,
- 49, 64, 78, 87, 103, 121, 120, 101,
- 72, 92, 95, 98, 112, 100, 103, 99
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
- 17, 18, 24, 47, 99, 99, 99, 99,
- 18, 21, 26, 66, 99, 99, 99, 99,
- 24, 26, 56, 99, 99, 99, 99, 99,
- 47, 66, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99,
- 99, 99, 99, 99, 99, 99, 99, 99
-};
-#else
-static const unsigned char Y_QUANTABLE[64] = {
- 8, 5, 5, 8, 12, 20, 25, 30,
- 6, 6, 7, 9, 13, 29, 30, 27,
- 7, 6, 8, 12, 20, 28, 34, 28,
- 7, 8, 11, 14, 25, 43, 40, 31,
- 9, 11, 18, 28, 34, 54, 51, 38,
- 12, 17, 27, 32, 40, 52, 56, 46,
- 24, 32, 39, 43, 51, 60, 60, 50,
- 36, 46, 47, 49, 56, 50, 51, 49
-};
-
-static const unsigned char UV_QUANTABLE[64] = {
- 8, 9, 12, 23, 49, 49, 49, 49,
- 9, 10, 13, 33, 49, 49, 49, 49,
- 12, 13, 28, 49, 49, 49, 49, 49,
- 23, 33, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49,
- 49, 49, 49, 49, 49, 49, 49, 49
-};
-#endif
-
-#define W9968CF_DEC_ERR_CORRUPTED_DATA -1
-#define W9968CF_DEC_ERR_BUF_OVERFLOW -2
-#define W9968CF_DEC_ERR_NO_SOI -3
-#define W9968CF_DEC_ERR_NO_SOF0 -4
-#define W9968CF_DEC_ERR_NO_SOS -5
-#define W9968CF_DEC_ERR_NO_EOI -6
-
-extern void w9968cf_init_decoder(void);
-extern int w9968cf_check_headers(const unsigned char* Pin,
- const unsigned long BUF_SIZE);
-extern int w9968cf_decode(const char* Pin, const unsigned long BUF_SIZE,
- const unsigned W, const unsigned H, char* Pout);
-
-#endif /* _W9968CF_DECODER_H_ */
diff --git a/drivers/media/video/w9968cf_vpp.h b/drivers/media/video/w9968cf_vpp.h
deleted file mode 100644
index 88c9b6c0cc36..000000000000
--- a/drivers/media/video/w9968cf_vpp.h
+++ /dev/null
@@ -1,40 +0,0 @@
-/***************************************************************************
- * Interface for video post-processing functions for the W996[87]CF driver *
- * for Linux. *
- * *
- * Copyright (C) 2002-2004 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _W9968CF_VPP_H_
-#define _W9968CF_VPP_H_
-
-#include <linux/module.h>
-#include <asm/types.h>
-
-struct w9968cf_vpp_t {
- struct module* owner;
- int (*check_headers)(const unsigned char*, const unsigned long);
- int (*decode)(const char*, const unsigned long, const unsigned,
- const unsigned, char*);
- void (*swap_yuvbytes)(void*, unsigned long);
- void (*uyvy_to_rgbx)(u8*, unsigned long, u8*, u16, u8);
- void (*scale_up)(u8*, u8*, u16, u16, u16, u16, u16);
-
- u8 busy; /* read-only flag: module is/is not in use */
-};
-
-#endif /* _W9968CF_VPP_H_ */
diff --git a/drivers/media/video/wm8739.c b/drivers/media/video/wm8739.c
index a11b99b4226b..a22f765e968a 100644
--- a/drivers/media/video/wm8739.c
+++ b/drivers/media/video/wm8739.c
@@ -27,11 +27,10 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("wm8739 driver");
MODULE_AUTHOR("T. Adachi, Hans Verkuil");
@@ -54,12 +53,14 @@ enum {
struct wm8739_state {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct {
+ /* audio cluster */
+ struct v4l2_ctrl *volume;
+ struct v4l2_ctrl *mute;
+ struct v4l2_ctrl *balance;
+ };
u32 clock_freq;
- u8 muted;
- u16 volume;
- u16 balance;
- u8 vol_l; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
- u8 vol_r; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
};
static inline struct wm8739_state *to_state(struct v4l2_subdev *sd)
@@ -67,6 +68,11 @@ static inline struct wm8739_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct wm8739_state, sd);
}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct wm8739_state, hdl)->sd;
+}
+
/* ------------------------------------------------------------------------ */
static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val)
@@ -89,58 +95,17 @@ static int wm8739_write(struct v4l2_subdev *sd, int reg, u16 val)
return -1;
}
-/* write regs to set audio volume etc */
-static void wm8739_set_audio(struct v4l2_subdev *sd)
-{
- 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(sd, R0, (state->vol_l & 0x1f) | mute);
- wm8739_write(sd, R1, (state->vol_r & 0x1f) | mute);
-}
-
-static int wm8739_g_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
-{
- struct wm8739_state *state = to_state(sd);
-
- switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- ctrl->value = state->muted;
- break;
-
- case V4L2_CID_AUDIO_VOLUME:
- ctrl->value = state->volume;
- break;
-
- case V4L2_CID_AUDIO_BALANCE:
- ctrl->value = state->balance;
- break;
-
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int wm8739_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
+static int wm8739_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(ctrl);
struct wm8739_state *state = to_state(sd);
unsigned int work_l, work_r;
+ u8 vol_l; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
+ u8 vol_r; /* +12dB to -34.5dB 1.5dB step (5bit) def:0dB */
+ u16 mute;
switch (ctrl->id) {
- case V4L2_CID_AUDIO_MUTE:
- state->muted = ctrl->value;
- break;
-
case V4L2_CID_AUDIO_VOLUME:
- state->volume = ctrl->value;
- break;
-
- case V4L2_CID_AUDIO_BALANCE:
- state->balance = ctrl->value;
break;
default:
@@ -148,52 +113,25 @@ static int wm8739_s_ctrl(struct v4l2_subdev *sd, struct v4l2_control *ctrl)
}
/* normalize ( 65535 to 0 -> 31 to 0 (12dB to -34.5dB) ) */
- work_l = (min(65536 - state->balance, 32768) * state->volume) / 32768;
- work_r = (min(state->balance, (u16)32768) * state->volume) / 32768;
+ work_l = (min(65536 - state->balance->val, 32768) * state->volume->val) / 32768;
+ work_r = (min(state->balance->val, 32768) * state->volume->val) / 32768;
- state->vol_l = (long)work_l * 31 / 65535;
- state->vol_r = (long)work_r * 31 / 65535;
+ vol_l = (long)work_l * 31 / 65535;
+ vol_r = (long)work_r * 31 / 65535;
/* set audio volume etc. */
- wm8739_set_audio(sd);
+ mute = state->mute->val ? 0x80 : 0;
+
+ /* Volume setting: bits 0-4, 0x1f = 12 dB, 0x00 = -34.5 dB
+ * Default setting: 0x17 = 0 dB
+ */
+ wm8739_write(sd, R0, (vol_l & 0x1f) | mute);
+ wm8739_write(sd, R1, (vol_r & 0x1f) | mute);
return 0;
}
/* ------------------------------------------------------------------------ */
-static struct v4l2_queryctrl wm8739_qctrl[] = {
- {
- .id = V4L2_CID_AUDIO_VOLUME,
- .name = "Volume",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 58880,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }, {
- .id = V4L2_CID_AUDIO_MUTE,
- .name = "Mute",
- .minimum = 0,
- .maximum = 1,
- .step = 1,
- .default_value = 1,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_BOOLEAN,
- }, {
- .id = V4L2_CID_AUDIO_BALANCE,
- .name = "Balance",
- .minimum = 0,
- .maximum = 65535,
- .step = 65535/100,
- .default_value = 32768,
- .flags = 0,
- .type = V4L2_CTRL_TYPE_INTEGER,
- }
-};
-
-/* ------------------------------------------------------------------------ */
-
static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
{
struct wm8739_state *state = to_state(sd);
@@ -222,18 +160,6 @@ static int wm8739_s_clock_freq(struct v4l2_subdev *sd, u32 audiofreq)
return 0;
}
-static int wm8739_queryctrl(struct v4l2_subdev *sd, struct v4l2_queryctrl *qc)
-{
- 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;
-}
-
static int wm8739_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -246,21 +172,26 @@ 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)" : "");
+ v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
return 0;
}
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops wm8739_ctrl_ops = {
+ .s_ctrl = wm8739_s_ctrl,
+};
+
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,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
};
static const struct v4l2_subdev_audio_ops wm8739_audio_ops = {
@@ -289,17 +220,28 @@ static int wm8739_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kmalloc(sizeof(struct wm8739_state), GFP_KERNEL);
+ state = kzalloc(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;
- state->balance = 32768;
- /* normalize (12dB(31) to -34.5dB(0) [0dB(23)] -> 65535 to 0) */
- state->volume = ((long)state->vol_l + 1) * 65535 / 31;
+ v4l2_ctrl_handler_init(&state->hdl, 2);
+ state->volume = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
+ V4L2_CID_AUDIO_VOLUME, 0, 65535, 65535 / 100, 50736);
+ state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ state->balance = v4l2_ctrl_new_std(&state->hdl, &wm8739_ctrl_ops,
+ V4L2_CID_AUDIO_BALANCE, 0, 65535, 65535 / 100, 32768);
+ sd->ctrl_handler = &state->hdl;
+ if (state->hdl.error) {
+ int err = state->hdl.error;
+
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return err;
+ }
+ v4l2_ctrl_cluster(3, &state->volume);
+
state->clock_freq = 48000;
/* Initialize wm8739 */
@@ -318,15 +260,17 @@ static int wm8739_probe(struct i2c_client *client,
/* activate */
wm8739_write(sd, R9, 0x001);
/* set volume/mute */
- wm8739_set_audio(sd);
+ v4l2_ctrl_handler_setup(&state->hdl);
return 0;
}
static int wm8739_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct wm8739_state *state = to_state(sd);
v4l2_device_unregister_subdev(sd);
+ v4l2_ctrl_handler_free(&state->hdl);
kfree(to_state(sd));
return 0;
}
@@ -337,9 +281,25 @@ static const struct i2c_device_id wm8739_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8739_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "wm8739",
- .probe = wm8739_probe,
- .remove = wm8739_remove,
- .id_table = wm8739_id,
+static struct i2c_driver wm8739_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "wm8739",
+ },
+ .probe = wm8739_probe,
+ .remove = wm8739_remove,
+ .id_table = wm8739_id,
};
+
+static __init int init_wm8739(void)
+{
+ return i2c_add_driver(&wm8739_driver);
+}
+
+static __exit void exit_wm8739(void)
+{
+ i2c_del_driver(&wm8739_driver);
+}
+
+module_init(init_wm8739);
+module_exit(exit_wm8739);
diff --git a/drivers/media/video/wm8775.c b/drivers/media/video/wm8775.c
index 5c2ba599c0c7..fe8ef6419f83 100644
--- a/drivers/media/video/wm8775.c
+++ b/drivers/media/video/wm8775.c
@@ -31,11 +31,10 @@
#include <linux/ioctl.h>
#include <asm/uaccess.h>
#include <linux/i2c.h>
-#include <linux/i2c-id.h>
#include <linux/videodev2.h>
#include <media/v4l2-device.h>
#include <media/v4l2-chip-ident.h>
-#include <media/v4l2-i2c-drv.h>
+#include <media/v4l2-ctrls.h>
MODULE_DESCRIPTION("wm8775 driver");
MODULE_AUTHOR("Ulf Eklund, Hans Verkuil");
@@ -53,8 +52,9 @@ enum {
struct wm8775_state {
struct v4l2_subdev sd;
+ struct v4l2_ctrl_handler hdl;
+ struct v4l2_ctrl *mute;
u8 input; /* Last selected input (0-0xf) */
- u8 muted;
};
static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
@@ -62,6 +62,11 @@ static inline struct wm8775_state *to_state(struct v4l2_subdev *sd)
return container_of(sd, struct wm8775_state, sd);
}
+static inline struct v4l2_subdev *to_sd(struct v4l2_ctrl *ctrl)
+{
+ return &container_of(ctrl->handler, struct wm8775_state, hdl)->sd;
+}
+
static int wm8775_write(struct v4l2_subdev *sd, int reg, u16 val)
{
struct i2c_client *client = v4l2_get_subdevdata(sd);
@@ -95,7 +100,7 @@ static int wm8775_s_routing(struct v4l2_subdev *sd,
return -EINVAL;
}
state->input = input;
- if (state->muted)
+ if (!v4l2_ctrl_g_ctrl(state->mute))
return 0;
wm8775_write(sd, R21, 0x0c0);
wm8775_write(sd, R14, 0x1d4);
@@ -104,29 +109,21 @@ static int wm8775_s_routing(struct v4l2_subdev *sd,
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)
+static int wm8775_s_ctrl(struct v4l2_ctrl *ctrl)
{
+ struct v4l2_subdev *sd = to_sd(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;
+ switch (ctrl->id) {
+ case V4L2_CID_AUDIO_MUTE:
+ wm8775_write(sd, R21, 0x0c0);
+ wm8775_write(sd, R14, 0x1d4);
+ wm8775_write(sd, R15, 0x1d4);
+ if (!ctrl->val)
+ wm8775_write(sd, R21, 0x100 + state->input);
+ return 0;
+ }
+ return -EINVAL;
}
static int wm8775_g_chip_ident(struct v4l2_subdev *sd, struct v4l2_dbg_chip_ident *chip)
@@ -140,8 +137,8 @@ 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)" : "");
+ v4l2_info(sd, "Input: %d\n", state->input);
+ v4l2_ctrl_handler_log_status(&state->hdl, sd->name);
return 0;
}
@@ -162,11 +159,20 @@ static int wm8775_s_frequency(struct v4l2_subdev *sd, struct v4l2_frequency *fre
/* ----------------------------------------------------------------------- */
+static const struct v4l2_ctrl_ops wm8775_ctrl_ops = {
+ .s_ctrl = wm8775_s_ctrl,
+};
+
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,
+ .g_ext_ctrls = v4l2_subdev_g_ext_ctrls,
+ .try_ext_ctrls = v4l2_subdev_try_ext_ctrls,
+ .s_ext_ctrls = v4l2_subdev_s_ext_ctrls,
+ .g_ctrl = v4l2_subdev_g_ctrl,
+ .s_ctrl = v4l2_subdev_s_ctrl,
+ .queryctrl = v4l2_subdev_queryctrl,
+ .querymenu = v4l2_subdev_querymenu,
};
static const struct v4l2_subdev_tuner_ops wm8775_tuner_ops = {
@@ -205,13 +211,24 @@ static int wm8775_probe(struct i2c_client *client,
v4l_info(client, "chip found @ 0x%02x (%s)\n",
client->addr << 1, client->adapter->name);
- state = kmalloc(sizeof(struct wm8775_state), GFP_KERNEL);
+ state = kzalloc(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;
+
+ v4l2_ctrl_handler_init(&state->hdl, 1);
+ state->mute = v4l2_ctrl_new_std(&state->hdl, &wm8775_ctrl_ops,
+ V4L2_CID_AUDIO_MUTE, 0, 1, 1, 0);
+ sd->ctrl_handler = &state->hdl;
+ if (state->hdl.error) {
+ int err = state->hdl.error;
+
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
+ return err;
+ }
/* Initialize wm8775 */
@@ -248,9 +265,11 @@ static int wm8775_probe(struct i2c_client *client,
static int wm8775_remove(struct i2c_client *client)
{
struct v4l2_subdev *sd = i2c_get_clientdata(client);
+ struct wm8775_state *state = to_state(sd);
v4l2_device_unregister_subdev(sd);
- kfree(to_state(sd));
+ v4l2_ctrl_handler_free(&state->hdl);
+ kfree(state);
return 0;
}
@@ -260,9 +279,25 @@ static const struct i2c_device_id wm8775_id[] = {
};
MODULE_DEVICE_TABLE(i2c, wm8775_id);
-static struct v4l2_i2c_driver_data v4l2_i2c_data = {
- .name = "wm8775",
- .probe = wm8775_probe,
- .remove = wm8775_remove,
- .id_table = wm8775_id,
+static struct i2c_driver wm8775_driver = {
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = "wm8775",
+ },
+ .probe = wm8775_probe,
+ .remove = wm8775_remove,
+ .id_table = wm8775_id,
};
+
+static __init int init_wm8775(void)
+{
+ return i2c_add_driver(&wm8775_driver);
+}
+
+static __exit void exit_wm8775(void)
+{
+ i2c_del_driver(&wm8775_driver);
+}
+
+module_init(init_wm8775);
+module_exit(exit_wm8775);
diff --git a/drivers/media/video/zc0301/Kconfig b/drivers/media/video/zc0301/Kconfig
deleted file mode 100644
index a7e610e0be9e..000000000000
--- a/drivers/media/video/zc0301/Kconfig
+++ /dev/null
@@ -1,15 +0,0 @@
-config USB_ZC0301
- tristate "USB ZC0301[P] webcam support (DEPRECATED)"
- depends on VIDEO_V4L2
- default n
- ---help---
- This driver is DEPRECATED please use the gspca zc3xx module
- instead.
-
- Say Y here if you want support for cameras based on the ZC0301 or
- ZC0301P Image Processors and Control Chips.
-
- See <file:Documentation/video4linux/zc0301.txt> for more info.
-
- To compile this driver as a module, choose M here: the
- module will be called zc0301.
diff --git a/drivers/media/video/zc0301/Makefile b/drivers/media/video/zc0301/Makefile
deleted file mode 100644
index d9e6d97fade6..000000000000
--- a/drivers/media/video/zc0301/Makefile
+++ /dev/null
@@ -1,3 +0,0 @@
-zc0301-objs := zc0301_core.o zc0301_pb0330.o zc0301_pas202bcb.o
-
-obj-$(CONFIG_USB_ZC0301) += zc0301.o
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
deleted file mode 100644
index b1b5cceb4baa..000000000000
--- a/drivers/media/video/zc0301/zc0301.h
+++ /dev/null
@@ -1,196 +0,0 @@
-/***************************************************************************
- * V4L2 driver for ZC0301[P] Image Processor and Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _ZC0301_H_
-#define _ZC0301_H_
-
-#include <linux/version.h>
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <media/v4l2-common.h>
-#include <media/v4l2-ioctl.h>
-#include <linux/device.h>
-#include <linux/list.h>
-#include <linux/spinlock.h>
-#include <linux/time.h>
-#include <linux/wait.h>
-#include <linux/types.h>
-#include <linux/param.h>
-#include <linux/mutex.h>
-#include <linux/rwsem.h>
-#include <linux/stddef.h>
-#include <linux/string.h>
-#include <linux/kref.h>
-
-#include "zc0301_sensor.h"
-
-/*****************************************************************************/
-
-#define ZC0301_DEBUG
-#define ZC0301_DEBUG_LEVEL 2
-#define ZC0301_MAX_DEVICES 64
-#define ZC0301_FORCE_MUNMAP 0
-#define ZC0301_MAX_FRAMES 32
-#define ZC0301_COMPRESSION_QUALITY 0
-#define ZC0301_URBS 2
-#define ZC0301_ISO_PACKETS 7
-#define ZC0301_ALTERNATE_SETTING 7
-#define ZC0301_URB_TIMEOUT msecs_to_jiffies(2 * ZC0301_ISO_PACKETS)
-#define ZC0301_CTRL_TIMEOUT 100
-#define ZC0301_FRAME_TIMEOUT 2
-
-/*****************************************************************************/
-
-ZC0301_ID_TABLE
-ZC0301_SENSOR_TABLE
-
-enum zc0301_frame_state {
- F_UNUSED,
- F_QUEUED,
- F_GRABBING,
- F_DONE,
- F_ERROR,
-};
-
-struct zc0301_frame_t {
- void* bufmem;
- struct v4l2_buffer buf;
- enum zc0301_frame_state state;
- struct list_head frame;
- unsigned long vma_use_count;
-};
-
-enum zc0301_dev_state {
- DEV_INITIALIZED = 0x01,
- DEV_DISCONNECTED = 0x02,
- DEV_MISCONFIGURED = 0x04,
-};
-
-enum zc0301_io_method {
- IO_NONE,
- IO_READ,
- IO_MMAP,
-};
-
-enum zc0301_stream_state {
- STREAM_OFF,
- STREAM_INTERRUPT,
- STREAM_ON,
-};
-
-struct zc0301_module_param {
- u8 force_munmap;
- u16 frame_timeout;
-};
-
-static DECLARE_RWSEM(zc0301_dev_lock);
-
-struct zc0301_device {
- struct video_device* v4ldev;
-
- struct zc0301_sensor sensor;
-
- struct usb_device* usbdev;
- struct urb* urb[ZC0301_URBS];
- void* transfer_buffer[ZC0301_URBS];
- u8* control_buffer;
-
- struct zc0301_frame_t *frame_current, frame[ZC0301_MAX_FRAMES];
- struct list_head inqueue, outqueue;
- u32 frame_count, nbuffers, nreadbuffers;
-
- enum zc0301_io_method io;
- enum zc0301_stream_state stream;
-
- struct v4l2_jpegcompression compression;
-
- struct zc0301_module_param module_param;
-
- struct kref kref;
- enum zc0301_dev_state state;
- u8 users;
-
- struct completion probe;
- struct mutex open_mutex, fileop_mutex;
- spinlock_t queue_lock;
- wait_queue_head_t wait_open, wait_frame, wait_stream;
-};
-
-/*****************************************************************************/
-
-struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id)
-{
- return usb_match_id(usb_ifnum_to_if(cam->usbdev, 0), id) ? cam : NULL;
-}
-
-void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor)
-{
- memcpy(&cam->sensor, sensor, sizeof(struct zc0301_sensor));
-}
-
-/*****************************************************************************/
-
-#undef DBG
-#undef KDBG
-#ifdef ZC0301_DEBUG
-# define DBG(level, fmt, args...) \
-do { \
- if (debug >= (level)) { \
- if ((level) == 1) \
- dev_err(&cam->usbdev->dev, fmt "\n", ## args); \
- else if ((level) == 2) \
- dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
- else if ((level) >= 3) \
- dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
- __FILE__, __func__, __LINE__ , ## args); \
- } \
-} while (0)
-# define KDBG(level, fmt, args...) \
-do { \
- if (debug >= (level)) { \
- if ((level) == 1 || (level) == 2) \
- pr_info("zc0301: " fmt "\n", ## args); \
- else if ((level) == 3) \
- pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
- __func__, __LINE__ , ## args); \
- } \
-} while (0)
-# define V4LDBG(level, name, cmd) \
-do { \
- if (debug >= (level)) \
- v4l_print_ioctl(name, cmd); \
-} while (0)
-#else
-# define DBG(level, fmt, args...) do {;} while(0)
-# define KDBG(level, fmt, args...) do {;} while(0)
-# define V4LDBG(level, name, cmd) do {;} while(0)
-#endif
-
-#undef PDBG
-#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
- __LINE__ , ## args)
-
-#undef PDBGG
-#define PDBGG(fmt, args...) do {;} while(0) /* placeholder */
-
-#endif /* _ZC0301_H_ */
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
deleted file mode 100644
index bb51cfb0c647..000000000000
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ /dev/null
@@ -1,2098 +0,0 @@
-/***************************************************************************
- * Video4Linux2 driver for ZC0301[P] Image Processor and Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * Informations about the chip internals needed to enable the I2C protocol *
- * have been taken from the documentation of the ZC030x Video4Linux1 *
- * driver written by Andrew Birkett <andy@nobugs.org> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/kernel.h>
-#include <linux/param.h>
-#include <linux/errno.h>
-#include <linux/slab.h>
-#include <linux/device.h>
-#include <linux/fs.h>
-#include <linux/delay.h>
-#include <linux/compiler.h>
-#include <linux/ioctl.h>
-#include <linux/poll.h>
-#include <linux/stat.h>
-#include <linux/mm.h>
-#include <linux/vmalloc.h>
-#include <linux/page-flags.h>
-#include <asm/byteorder.h>
-#include <asm/page.h>
-#include <asm/uaccess.h>
-
-#include "zc0301.h"
-
-/*****************************************************************************/
-
-#define ZC0301_MODULE_NAME "V4L2 driver for ZC0301[P] " \
- "Image Processor and Control Chip"
-#define ZC0301_MODULE_AUTHOR "(C) 2006-2007 Luca Risolia"
-#define ZC0301_AUTHOR_EMAIL "<luca.risolia@studio.unibo.it>"
-#define ZC0301_MODULE_LICENSE "GPL"
-#define ZC0301_MODULE_VERSION "1:1.10"
-#define ZC0301_MODULE_VERSION_CODE KERNEL_VERSION(1, 1, 10)
-
-/*****************************************************************************/
-
-MODULE_DEVICE_TABLE(usb, zc0301_id_table);
-
-MODULE_AUTHOR(ZC0301_MODULE_AUTHOR " " ZC0301_AUTHOR_EMAIL);
-MODULE_DESCRIPTION(ZC0301_MODULE_NAME);
-MODULE_VERSION(ZC0301_MODULE_VERSION);
-MODULE_LICENSE(ZC0301_MODULE_LICENSE);
-
-static short video_nr[] = {[0 ... ZC0301_MAX_DEVICES-1] = -1};
-module_param_array(video_nr, short, NULL, 0444);
-MODULE_PARM_DESC(video_nr,
- "\n<-1|n[,...]> Specify V4L2 minor mode number."
- "\n -1 = use next available (default)"
- "\n n = use minor number n (integer >= 0)"
- "\nYou can specify up to "
- __MODULE_STRING(ZC0301_MAX_DEVICES) " cameras this way."
- "\nFor example:"
- "\nvideo_nr=-1,2,-1 would assign minor number 2 to"
- "\nthe second registered camera and use auto for the first"
- "\none and for every other camera."
- "\n");
-
-static short force_munmap[] = {[0 ... ZC0301_MAX_DEVICES-1] =
- ZC0301_FORCE_MUNMAP};
-module_param_array(force_munmap, bool, NULL, 0444);
-MODULE_PARM_DESC(force_munmap,
- "\n<0|1[,...]> Force the application to unmap previously"
- "\nmapped buffer memory before calling any VIDIOC_S_CROP or"
- "\nVIDIOC_S_FMT ioctl's. Not all the applications support"
- "\nthis feature. This parameter is specific for each"
- "\ndetected camera."
- "\n 0 = do not force memory unmapping"
- "\n 1 = force memory unmapping (save memory)"
- "\nDefault value is "__MODULE_STRING(ZC0301_FORCE_MUNMAP)"."
- "\n");
-
-static unsigned int frame_timeout[] = {[0 ... ZC0301_MAX_DEVICES-1] =
- ZC0301_FRAME_TIMEOUT};
-module_param_array(frame_timeout, uint, NULL, 0644);
-MODULE_PARM_DESC(frame_timeout,
- "\n<n[,...]> Timeout for a video frame in seconds."
- "\nThis parameter is specific for each detected camera."
- "\nDefault value is "__MODULE_STRING(ZC0301_FRAME_TIMEOUT)"."
- "\n");
-
-#ifdef ZC0301_DEBUG
-static unsigned short debug = ZC0301_DEBUG_LEVEL;
-module_param(debug, ushort, 0644);
-MODULE_PARM_DESC(debug,
- "\n<n> Debugging information level, from 0 to 3:"
- "\n0 = none (use carefully)"
- "\n1 = critical errors"
- "\n2 = significant informations"
- "\n3 = more verbose messages"
- "\nLevel 3 is useful for testing only, when only "
- "one device is used."
- "\nDefault value is "__MODULE_STRING(ZC0301_DEBUG_LEVEL)"."
- "\n");
-#endif
-
-/*****************************************************************************/
-
-static u32
-zc0301_request_buffers(struct zc0301_device* cam, u32 count,
- enum zc0301_io_method io)
-{
- struct v4l2_pix_format* p = &(cam->sensor.pix_format);
- struct v4l2_rect* r = &(cam->sensor.cropcap.bounds);
- const size_t imagesize = cam->module_param.force_munmap ||
- io == IO_READ ?
- (p->width * p->height * p->priv) / 8 :
- (r->width * r->height * p->priv) / 8;
- void* buff = NULL;
- u32 i;
-
- if (count > ZC0301_MAX_FRAMES)
- count = ZC0301_MAX_FRAMES;
-
- cam->nbuffers = count;
- while (cam->nbuffers > 0) {
- if ((buff = vmalloc_32_user(cam->nbuffers *
- PAGE_ALIGN(imagesize))))
- break;
- cam->nbuffers--;
- }
-
- for (i = 0; i < cam->nbuffers; i++) {
- cam->frame[i].bufmem = buff + i*PAGE_ALIGN(imagesize);
- cam->frame[i].buf.index = i;
- cam->frame[i].buf.m.offset = i*PAGE_ALIGN(imagesize);
- cam->frame[i].buf.length = imagesize;
- cam->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cam->frame[i].buf.sequence = 0;
- cam->frame[i].buf.field = V4L2_FIELD_NONE;
- cam->frame[i].buf.memory = V4L2_MEMORY_MMAP;
- cam->frame[i].buf.flags = 0;
- }
-
- return cam->nbuffers;
-}
-
-
-static void zc0301_release_buffers(struct zc0301_device* cam)
-{
- if (cam->nbuffers) {
- vfree(cam->frame[0].bufmem);
- cam->nbuffers = 0;
- }
- cam->frame_current = NULL;
-}
-
-
-static void zc0301_empty_framequeues(struct zc0301_device* cam)
-{
- u32 i;
-
- INIT_LIST_HEAD(&cam->inqueue);
- INIT_LIST_HEAD(&cam->outqueue);
-
- for (i = 0; i < ZC0301_MAX_FRAMES; i++) {
- cam->frame[i].state = F_UNUSED;
- cam->frame[i].buf.bytesused = 0;
- }
-}
-
-
-static void zc0301_requeue_outqueue(struct zc0301_device* cam)
-{
- struct zc0301_frame_t *i;
-
- list_for_each_entry(i, &cam->outqueue, frame) {
- i->state = F_QUEUED;
- list_add(&i->frame, &cam->inqueue);
- }
-
- INIT_LIST_HEAD(&cam->outqueue);
-}
-
-
-static void zc0301_queue_unusedframes(struct zc0301_device* cam)
-{
- unsigned long lock_flags;
- u32 i;
-
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].state == F_UNUSED) {
- cam->frame[i].state = F_QUEUED;
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_add_tail(&cam->frame[i].frame, &cam->inqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
- }
-}
-
-/*****************************************************************************/
-
-int zc0301_write_reg(struct zc0301_device* cam, u16 index, u16 value)
-{
- struct usb_device* udev = cam->usbdev;
- int res;
-
- res = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0xa0, 0x40,
- value, index, NULL, 0, ZC0301_CTRL_TIMEOUT);
- if (res < 0) {
- DBG(3, "Failed to write a register (index 0x%04X, "
- "value 0x%02X, error %d)",index, value, res);
- return -1;
- }
-
- return 0;
-}
-
-
-int zc0301_read_reg(struct zc0301_device* cam, u16 index)
-{
- struct usb_device* udev = cam->usbdev;
- u8* buff = cam->control_buffer;
- int res;
-
- res = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0xa1, 0xc0,
- 0x0001, index, buff, 1, ZC0301_CTRL_TIMEOUT);
- if (res < 0)
- DBG(3, "Failed to read a register (index 0x%04X, error %d)",
- index, res);
-
- PDBGG("Read: index 0x%04X, value: 0x%04X", index, (int)(*buff));
-
- return (res >= 0) ? (int)(*buff) : -1;
-}
-
-
-int zc0301_i2c_read(struct zc0301_device* cam, u16 address, u8 length)
-{
- int err = 0, res, r0, r1;
-
- err += zc0301_write_reg(cam, 0x0092, address);
- err += zc0301_write_reg(cam, 0x0090, 0x02);
-
- msleep(1);
-
- res = zc0301_read_reg(cam, 0x0091);
- if (res < 0)
- err += res;
- r0 = zc0301_read_reg(cam, 0x0095);
- if (r0 < 0)
- err += r0;
- r1 = zc0301_read_reg(cam, 0x0096);
- if (r1 < 0)
- err += r1;
-
- res = (length <= 1) ? r0 : r0 | (r1 << 8);
-
- if (err)
- DBG(3, "I2C read failed at address 0x%04X, value: 0x%04X",
- address, res);
-
-
- PDBGG("I2C read: address 0x%04X, value: 0x%04X", address, res);
-
- return err ? -1 : res;
-}
-
-
-int zc0301_i2c_write(struct zc0301_device* cam, u16 address, u16 value)
-{
- int err = 0, res;
-
- err += zc0301_write_reg(cam, 0x0092, address);
- err += zc0301_write_reg(cam, 0x0093, value & 0xff);
- err += zc0301_write_reg(cam, 0x0094, value >> 8);
- err += zc0301_write_reg(cam, 0x0090, 0x01);
-
- msleep(1);
-
- res = zc0301_read_reg(cam, 0x0091);
- if (res < 0)
- err += res;
-
- if (err)
- DBG(3, "I2C write failed at address 0x%04X, value: 0x%04X",
- address, value);
-
- PDBGG("I2C write: address 0x%04X, value: 0x%04X", address, value);
-
- return err ? -1 : 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_urb_complete(struct urb *urb)
-{
- struct zc0301_device* cam = urb->context;
- struct zc0301_frame_t** f;
- size_t imagesize;
- u8 i;
- int err = 0;
-
- if (urb->status == -ENOENT)
- return;
-
- f = &cam->frame_current;
-
- if (cam->stream == STREAM_INTERRUPT) {
- cam->stream = STREAM_OFF;
- if ((*f))
- (*f)->state = F_QUEUED;
- DBG(3, "Stream interrupted");
- wake_up(&cam->wait_stream);
- }
-
- if (cam->state & DEV_DISCONNECTED)
- return;
-
- if (cam->state & DEV_MISCONFIGURED) {
- wake_up_interruptible(&cam->wait_frame);
- return;
- }
-
- if (cam->stream == STREAM_OFF || list_empty(&cam->inqueue))
- goto resubmit_urb;
-
- if (!(*f))
- (*f) = list_entry(cam->inqueue.next, struct zc0301_frame_t,
- frame);
-
- imagesize = (cam->sensor.pix_format.width *
- cam->sensor.pix_format.height *
- cam->sensor.pix_format.priv) / 8;
-
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned int len, status;
- void *pos;
- u16* soi;
- u8 sof;
-
- len = urb->iso_frame_desc[i].actual_length;
- status = urb->iso_frame_desc[i].status;
- pos = urb->iso_frame_desc[i].offset + urb->transfer_buffer;
-
- if (status) {
- DBG(3, "Error in isochronous frame");
- (*f)->state = F_ERROR;
- continue;
- }
-
- sof = (*(soi = pos) == 0xd8ff);
-
- PDBGG("Isochrnous frame: length %u, #%u i,", len, i);
-
- if ((*f)->state == F_QUEUED || (*f)->state == F_ERROR)
-start_of_frame:
- if (sof) {
- (*f)->state = F_GRABBING;
- (*f)->buf.bytesused = 0;
- do_gettimeofday(&(*f)->buf.timestamp);
- DBG(3, "SOF detected: new video frame");
- }
-
- if ((*f)->state == F_GRABBING) {
- if (sof && (*f)->buf.bytesused)
- goto end_of_frame;
-
- if ((*f)->buf.bytesused + len > imagesize) {
- DBG(3, "Video frame size exceeded");
- (*f)->state = F_ERROR;
- continue;
- }
-
- memcpy((*f)->bufmem+(*f)->buf.bytesused, pos, len);
- (*f)->buf.bytesused += len;
-
- if ((*f)->buf.bytesused == imagesize) {
- u32 b;
-end_of_frame:
- b = (*f)->buf.bytesused;
- (*f)->state = F_DONE;
- (*f)->buf.sequence= ++cam->frame_count;
- spin_lock(&cam->queue_lock);
- list_move_tail(&(*f)->frame, &cam->outqueue);
- if (!list_empty(&cam->inqueue))
- (*f) = list_entry(cam->inqueue.next,
- struct zc0301_frame_t,
- frame);
- else
- (*f) = NULL;
- spin_unlock(&cam->queue_lock);
- DBG(3, "Video frame captured: : %lu bytes",
- (unsigned long)(b));
-
- if (!(*f))
- goto resubmit_urb;
-
- if (sof)
- goto start_of_frame;
- }
- }
- }
-
-resubmit_urb:
- urb->dev = cam->usbdev;
- err = usb_submit_urb(urb, GFP_ATOMIC);
- if (err < 0 && err != -EPERM) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "usb_submit_urb() failed");
- }
-
- wake_up_interruptible(&cam->wait_frame);
-}
-
-
-static int zc0301_start_transfer(struct zc0301_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- struct usb_host_interface* altsetting = usb_altnum_to_altsetting(
- usb_ifnum_to_if(udev, 0),
- ZC0301_ALTERNATE_SETTING);
- const unsigned int psz = le16_to_cpu(altsetting->
- endpoint[0].desc.wMaxPacketSize);
- struct urb* urb;
- s8 i, j;
- int err = 0;
-
- for (i = 0; i < ZC0301_URBS; i++) {
- cam->transfer_buffer[i] = kzalloc(ZC0301_ISO_PACKETS * psz,
- GFP_KERNEL);
- if (!cam->transfer_buffer[i]) {
- err = -ENOMEM;
- DBG(1, "Not enough memory");
- goto free_buffers;
- }
- }
-
- for (i = 0; i < ZC0301_URBS; i++) {
- urb = usb_alloc_urb(ZC0301_ISO_PACKETS, GFP_KERNEL);
- cam->urb[i] = urb;
- if (!urb) {
- err = -ENOMEM;
- DBG(1, "usb_alloc_urb() failed");
- goto free_urbs;
- }
- urb->dev = udev;
- urb->context = cam;
- urb->pipe = usb_rcvisocpipe(udev, 1);
- urb->transfer_flags = URB_ISO_ASAP;
- urb->number_of_packets = ZC0301_ISO_PACKETS;
- urb->complete = zc0301_urb_complete;
- urb->transfer_buffer = cam->transfer_buffer[i];
- urb->transfer_buffer_length = psz * ZC0301_ISO_PACKETS;
- urb->interval = 1;
- for (j = 0; j < ZC0301_ISO_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = psz * j;
- urb->iso_frame_desc[j].length = psz;
- }
- }
-
- err = usb_set_interface(udev, 0, ZC0301_ALTERNATE_SETTING);
- if (err) {
- DBG(1, "usb_set_interface() failed");
- goto free_urbs;
- }
-
- cam->frame_current = NULL;
-
- for (i = 0; i < ZC0301_URBS; i++) {
- err = usb_submit_urb(cam->urb[i], GFP_KERNEL);
- if (err) {
- for (j = i-1; j >= 0; j--)
- usb_kill_urb(cam->urb[j]);
- DBG(1, "usb_submit_urb() failed, error %d", err);
- goto free_urbs;
- }
- }
-
- return 0;
-
-free_urbs:
- for (i = 0; (i < ZC0301_URBS) && cam->urb[i]; i++)
- usb_free_urb(cam->urb[i]);
-
-free_buffers:
- for (i = 0; (i < ZC0301_URBS) && cam->transfer_buffer[i]; i++)
- kfree(cam->transfer_buffer[i]);
-
- return err;
-}
-
-
-static int zc0301_stop_transfer(struct zc0301_device* cam)
-{
- struct usb_device *udev = cam->usbdev;
- s8 i;
- int err = 0;
-
- if (cam->state & DEV_DISCONNECTED)
- return 0;
-
- for (i = ZC0301_URBS-1; i >= 0; i--) {
- usb_kill_urb(cam->urb[i]);
- usb_free_urb(cam->urb[i]);
- kfree(cam->transfer_buffer[i]);
- }
-
- err = usb_set_interface(udev, 0, 0); /* 0 Mb/s */
- if (err)
- DBG(3, "usb_set_interface() failed");
-
- return err;
-}
-
-
-static int zc0301_stream_interrupt(struct zc0301_device* cam)
-{
- long timeout;
-
- cam->stream = STREAM_INTERRUPT;
- timeout = wait_event_timeout(cam->wait_stream,
- (cam->stream == STREAM_OFF) ||
- (cam->state & DEV_DISCONNECTED),
- ZC0301_URB_TIMEOUT);
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- else if (cam->stream != STREAM_OFF) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "URB timeout reached. The camera is misconfigured. To "
- "use it, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_set_compression(struct zc0301_device* cam,
- struct v4l2_jpegcompression* compression)
-{
- int r, err = 0;
-
- if ((r = zc0301_read_reg(cam, 0x0008)) < 0)
- err += r;
- err += zc0301_write_reg(cam, 0x0008, r | 0x11 | compression->quality);
-
- return err ? -EIO : 0;
-}
-
-
-static int zc0301_init(struct zc0301_device* cam)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- struct v4l2_queryctrl *qctrl;
- struct v4l2_rect* rect;
- u8 i = 0;
- int err = 0;
-
- if (!(cam->state & DEV_INITIALIZED)) {
- mutex_init(&cam->open_mutex);
- init_waitqueue_head(&cam->wait_open);
- qctrl = s->qctrl;
- rect = &(s->cropcap.defrect);
- cam->compression.quality = ZC0301_COMPRESSION_QUALITY;
- } else { /* use current values */
- qctrl = s->_qctrl;
- rect = &(s->_rect);
- }
-
- if (s->init) {
- err = s->init(cam);
- if (err) {
- DBG(3, "Sensor initialization failed");
- return err;
- }
- }
-
- if ((err = zc0301_set_compression(cam, &cam->compression))) {
- DBG(3, "set_compression() failed");
- return err;
- }
-
- if (s->set_crop)
- if ((err = s->set_crop(cam, rect))) {
- DBG(3, "set_crop() failed");
- return err;
- }
-
- if (s->set_ctrl) {
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (s->qctrl[i].id != 0 &&
- !(s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)) {
- ctrl.id = s->qctrl[i].id;
- ctrl.value = qctrl[i].default_value;
- err = s->set_ctrl(cam, &ctrl);
- if (err) {
- DBG(3, "Set %s control failed",
- s->qctrl[i].name);
- return err;
- }
- DBG(3, "Image sensor supports '%s' control",
- s->qctrl[i].name);
- }
- }
-
- if (!(cam->state & DEV_INITIALIZED)) {
- mutex_init(&cam->fileop_mutex);
- spin_lock_init(&cam->queue_lock);
- init_waitqueue_head(&cam->wait_frame);
- init_waitqueue_head(&cam->wait_stream);
- cam->nreadbuffers = 2;
- memcpy(s->_qctrl, s->qctrl, sizeof(s->qctrl));
- memcpy(&(s->_rect), &(s->cropcap.defrect),
- sizeof(struct v4l2_rect));
- cam->state |= DEV_INITIALIZED;
- }
-
- DBG(2, "Initialization succeeded");
- return 0;
-}
-
-/*****************************************************************************/
-
-static void zc0301_release_resources(struct kref *kref)
-{
- struct zc0301_device *cam = container_of(kref, struct zc0301_device,
- kref);
- DBG(2, "V4L2 device %s deregistered",
- video_device_node_name(cam->v4ldev));
- video_set_drvdata(cam->v4ldev, NULL);
- video_unregister_device(cam->v4ldev);
- usb_put_dev(cam->usbdev);
- kfree(cam->control_buffer);
- kfree(cam);
-}
-
-
-static int zc0301_open(struct file *filp)
-{
- struct zc0301_device* cam;
- int err = 0;
-
- if (!down_read_trylock(&zc0301_dev_lock))
- return -EAGAIN;
-
- cam = video_drvdata(filp);
-
- if (wait_for_completion_interruptible(&cam->probe)) {
- up_read(&zc0301_dev_lock);
- return -ERESTARTSYS;
- }
-
- kref_get(&cam->kref);
-
- if (mutex_lock_interruptible(&cam->open_mutex)) {
- kref_put(&cam->kref, zc0301_release_resources);
- up_read(&zc0301_dev_lock);
- return -ERESTARTSYS;
- }
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- err = -ENODEV;
- goto out;
- }
-
- if (cam->users) {
- DBG(2, "Device %s is busy...",
- video_device_node_name(cam->v4ldev));
- DBG(3, "Simultaneous opens are not supported");
- if ((filp->f_flags & O_NONBLOCK) ||
- (filp->f_flags & O_NDELAY)) {
- err = -EWOULDBLOCK;
- goto out;
- }
- DBG(2, "A blocking open() has been requested. Wait for the "
- "device to be released...");
- up_read(&zc0301_dev_lock);
- err = wait_event_interruptible_exclusive(cam->wait_open,
- (cam->state & DEV_DISCONNECTED)
- || !cam->users);
- down_read(&zc0301_dev_lock);
- if (err)
- goto out;
- if (cam->state & DEV_DISCONNECTED) {
- err = -ENODEV;
- goto out;
- }
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- err = zc0301_init(cam);
- if (err) {
- DBG(1, "Initialization failed again. "
- "I will retry on next open().");
- goto out;
- }
- cam->state &= ~DEV_MISCONFIGURED;
- }
-
- if ((err = zc0301_start_transfer(cam)))
- goto out;
-
- filp->private_data = cam;
- cam->users++;
- cam->io = IO_NONE;
- cam->stream = STREAM_OFF;
- cam->nbuffers = 0;
- cam->frame_count = 0;
- zc0301_empty_framequeues(cam);
-
- DBG(3, "Video device %s is open",
- video_device_node_name(cam->v4ldev));
-
-out:
- mutex_unlock(&cam->open_mutex);
- if (err)
- kref_put(&cam->kref, zc0301_release_resources);
- up_read(&zc0301_dev_lock);
- return err;
-}
-
-
-static int zc0301_release(struct file *filp)
-{
- struct zc0301_device* cam;
-
- down_write(&zc0301_dev_lock);
-
- cam = video_drvdata(filp);
-
- zc0301_stop_transfer(cam);
- zc0301_release_buffers(cam);
- cam->users--;
- wake_up_interruptible_nr(&cam->wait_open, 1);
-
- DBG(3, "Video device %s closed",
- video_device_node_name(cam->v4ldev));
-
- kref_put(&cam->kref, zc0301_release_resources);
-
- up_write(&zc0301_dev_lock);
-
- return 0;
-}
-
-
-static ssize_t
-zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
-{
- struct zc0301_device *cam = video_drvdata(filp);
- struct zc0301_frame_t* f, * i;
- unsigned long lock_flags;
- long timeout;
- int err = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (cam->io == IO_MMAP) {
- DBG(3, "Close and open the device again to choose the read "
- "method");
- mutex_unlock(&cam->fileop_mutex);
- return -EBUSY;
- }
-
- if (cam->io == IO_NONE) {
- if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
- DBG(1, "read() failed, not enough memory");
- mutex_unlock(&cam->fileop_mutex);
- return -ENOMEM;
- }
- cam->io = IO_READ;
- cam->stream = STREAM_ON;
- }
-
- if (list_empty(&cam->inqueue)) {
- if (!list_empty(&cam->outqueue))
- zc0301_empty_framequeues(cam);
- zc0301_queue_unusedframes(cam);
- }
-
- if (!count) {
- mutex_unlock(&cam->fileop_mutex);
- return 0;
- }
-
- if (list_empty(&cam->outqueue)) {
- if (filp->f_flags & O_NONBLOCK) {
- mutex_unlock(&cam->fileop_mutex);
- return -EAGAIN;
- }
- timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED),
- msecs_to_jiffies(
- cam->module_param.frame_timeout * 1000
- )
- );
- if (timeout < 0) {
- mutex_unlock(&cam->fileop_mutex);
- return timeout;
- }
- if (cam->state & DEV_DISCONNECTED) {
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
- if (!timeout || (cam->state & DEV_MISCONFIGURED)) {
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
- }
-
- f = list_entry(cam->outqueue.prev, struct zc0301_frame_t, frame);
-
- if (count > f->buf.bytesused)
- count = f->buf.bytesused;
-
- if (copy_to_user(buf, f->bufmem, count)) {
- err = -EFAULT;
- goto exit;
- }
- *f_pos += count;
-
-exit:
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_for_each_entry(i, &cam->outqueue, frame)
- i->state = F_UNUSED;
- INIT_LIST_HEAD(&cam->outqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- zc0301_queue_unusedframes(cam);
-
- PDBGG("Frame #%lu, bytes read: %zu",
- (unsigned long)f->buf.index, count);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return err ? err : count;
-}
-
-
-static unsigned int zc0301_poll(struct file *filp, poll_table *wait)
-{
- struct zc0301_device *cam = video_drvdata(filp);
- struct zc0301_frame_t* f;
- unsigned long lock_flags;
- unsigned int mask = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return POLLERR;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- goto error;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- goto error;
- }
-
- if (cam->io == IO_NONE) {
- if (!zc0301_request_buffers(cam, cam->nreadbuffers, IO_READ)) {
- DBG(1, "poll() failed, not enough memory");
- goto error;
- }
- cam->io = IO_READ;
- cam->stream = STREAM_ON;
- }
-
- if (cam->io == IO_READ) {
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_for_each_entry(f, &cam->outqueue, frame)
- f->state = F_UNUSED;
- INIT_LIST_HEAD(&cam->outqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
- zc0301_queue_unusedframes(cam);
- }
-
- poll_wait(filp, &cam->wait_frame, wait);
-
- if (!list_empty(&cam->outqueue))
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&cam->fileop_mutex);
-
- return mask;
-
-error:
- mutex_unlock(&cam->fileop_mutex);
- return POLLERR;
-}
-
-
-static void zc0301_vm_open(struct vm_area_struct* vma)
-{
- struct zc0301_frame_t* f = vma->vm_private_data;
- f->vma_use_count++;
-}
-
-
-static void zc0301_vm_close(struct vm_area_struct* vma)
-{
- /* NOTE: buffers are not freed here */
- struct zc0301_frame_t* f = vma->vm_private_data;
- f->vma_use_count--;
-}
-
-
-static const struct vm_operations_struct zc0301_vm_ops = {
- .open = zc0301_vm_open,
- .close = zc0301_vm_close,
-};
-
-
-static int zc0301_mmap(struct file* filp, struct vm_area_struct *vma)
-{
- struct zc0301_device *cam = video_drvdata(filp);
- unsigned long size = vma->vm_end - vma->vm_start,
- start = vma->vm_start;
- void *pos;
- u32 i;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- if (!(vma->vm_flags & (VM_WRITE | VM_READ))) {
- mutex_unlock(&cam->fileop_mutex);
- return -EACCES;
- }
-
- if (cam->io != IO_MMAP ||
- size != PAGE_ALIGN(cam->frame[0].buf.length)) {
- mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
- }
-
- for (i = 0; i < cam->nbuffers; i++) {
- if ((cam->frame[i].buf.m.offset>>PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
- if (i == cam->nbuffers) {
- mutex_unlock(&cam->fileop_mutex);
- return -EINVAL;
- }
-
- vma->vm_flags |= VM_IO;
- vma->vm_flags |= VM_RESERVED;
-
- pos = cam->frame[i].bufmem;
- while (size > 0) { /* size is page-aligned */
- if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- mutex_unlock(&cam->fileop_mutex);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
-
- vma->vm_ops = &zc0301_vm_ops;
- vma->vm_private_data = &cam->frame[i];
- zc0301_vm_open(vma);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return 0;
-}
-
-/*****************************************************************************/
-
-static int
-zc0301_vidioc_querycap(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_capability cap = {
- .driver = "zc0301",
- .version = ZC0301_MODULE_VERSION_CODE,
- .capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_READWRITE |
- V4L2_CAP_STREAMING,
- };
-
- strlcpy(cap.card, cam->v4ldev->name, sizeof(cap.card));
- if (usb_make_path(cam->usbdev, cap.bus_info, sizeof(cap.bus_info)) < 0)
- strlcpy(cap.bus_info, dev_name(&cam->usbdev->dev),
- sizeof(cap.bus_info));
-
- if (copy_to_user(arg, &cap, sizeof(cap)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_enuminput(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_input i;
-
- if (copy_from_user(&i, arg, sizeof(i)))
- return -EFAULT;
-
- if (i.index)
- return -EINVAL;
-
- memset(&i, 0, sizeof(i));
- strcpy(i.name, "Camera");
- i.type = V4L2_INPUT_TYPE_CAMERA;
-
- if (copy_to_user(arg, &i, sizeof(i)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_input(struct zc0301_device* cam, void __user * arg)
-{
- int index = 0;
-
- if (copy_to_user(arg, &index, sizeof(index)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_s_input(struct zc0301_device* cam, void __user * arg)
-{
- int index;
-
- if (copy_from_user(&index, arg, sizeof(index)))
- return -EFAULT;
-
- if (index != 0)
- return -EINVAL;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_query_ctrl(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_queryctrl qc;
- u8 i;
-
- if (copy_from_user(&qc, arg, sizeof(qc)))
- return -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (qc.id && qc.id == s->qctrl[i].id) {
- memcpy(&qc, &(s->qctrl[i]), sizeof(qc));
- if (copy_to_user(arg, &qc, sizeof(qc)))
- return -EFAULT;
- return 0;
- }
-
- return -EINVAL;
-}
-
-
-static int
-zc0301_vidioc_g_ctrl(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- int err = 0;
- u8 i;
-
- if (!s->get_ctrl && !s->set_ctrl)
- return -EINVAL;
-
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
-
- if (!s->get_ctrl) {
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++)
- if (ctrl.id == s->qctrl[i].id) {
- ctrl.value = s->_qctrl[i].default_value;
- goto exit;
- }
- return -EINVAL;
- } else
- err = s->get_ctrl(cam, &ctrl);
-
-exit:
- if (copy_to_user(arg, &ctrl, sizeof(ctrl)))
- return -EFAULT;
-
- return err;
-}
-
-
-static int
-zc0301_vidioc_s_ctrl(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_control ctrl;
- u8 i;
- int err = 0;
-
- if (!s->set_ctrl)
- return -EINVAL;
-
- if (copy_from_user(&ctrl, arg, sizeof(ctrl)))
- return -EFAULT;
-
- for (i = 0; i < ARRAY_SIZE(s->qctrl); i++) {
- if (ctrl.id == s->qctrl[i].id) {
- if (s->qctrl[i].flags & V4L2_CTRL_FLAG_DISABLED)
- return -EINVAL;
- if (ctrl.value < s->qctrl[i].minimum ||
- ctrl.value > s->qctrl[i].maximum)
- return -ERANGE;
- ctrl.value -= ctrl.value % s->qctrl[i].step;
- break;
- }
- }
- if (i == ARRAY_SIZE(s->qctrl))
- return -EINVAL;
- if ((err = s->set_ctrl(cam, &ctrl)))
- return err;
-
- s->_qctrl[i].default_value = ctrl.value;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_cropcap(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_cropcap* cc = &(cam->sensor.cropcap);
-
- cc->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- cc->pixelaspect.numerator = 1;
- cc->pixelaspect.denominator = 1;
-
- if (copy_to_user(arg, cc, sizeof(*cc)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_crop(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_crop crop = {
- .type = V4L2_BUF_TYPE_VIDEO_CAPTURE,
- };
-
- memcpy(&(crop.c), &(s->_rect), sizeof(struct v4l2_rect));
-
- if (copy_to_user(arg, &crop, sizeof(crop)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_s_crop(struct zc0301_device* cam, void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_crop crop;
- struct v4l2_rect* rect;
- struct v4l2_rect* bounds = &(s->cropcap.bounds);
- const enum zc0301_stream_state stream = cam->stream;
- const u32 nbuffers = cam->nbuffers;
- u32 i;
- int err = 0;
-
- if (copy_from_user(&crop, arg, sizeof(crop)))
- return -EFAULT;
-
- rect = &(crop.c);
-
- if (crop.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (cam->module_param.force_munmap)
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_S_CROP failed. "
- "Unmap the buffers first.");
- return -EBUSY;
- }
-
- if (!s->set_crop) {
- memcpy(rect, &(s->_rect), sizeof(*rect));
- if (copy_to_user(arg, &crop, sizeof(crop)))
- return -EFAULT;
- return 0;
- }
-
- rect->left &= ~7L;
- rect->top &= ~7L;
- if (rect->width < 8)
- rect->width = 8;
- if (rect->height < 8)
- rect->height = 8;
- if (rect->width > bounds->width)
- rect->width = bounds->width;
- if (rect->height > bounds->height)
- rect->height = bounds->height;
- if (rect->left < bounds->left)
- rect->left = bounds->left;
- if (rect->top < bounds->top)
- rect->top = bounds->top;
- if (rect->left + rect->width > bounds->left + bounds->width)
- rect->left = bounds->left+bounds->width - rect->width;
- if (rect->top + rect->height > bounds->top + bounds->height)
- rect->top = bounds->top+bounds->height - rect->height;
- rect->width &= ~7L;
- rect->height &= ~7L;
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- if (copy_to_user(arg, &crop, sizeof(crop))) {
- cam->stream = stream;
- return -EFAULT;
- }
-
- if (cam->module_param.force_munmap || cam->io == IO_READ)
- zc0301_release_buffers(cam);
-
- if (s->set_crop)
- err += s->set_crop(cam, rect);
-
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_CROP failed because of hardware problems. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- s->pix_format.width = rect->width;
- s->pix_format.height = rect->height;
- memcpy(&(s->_rect), rect, sizeof(*rect));
-
- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
- nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_CROP failed because of not enough memory. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -ENOMEM;
- }
-
- if (cam->io == IO_READ)
- zc0301_empty_framequeues(cam);
- else if (cam->module_param.force_munmap)
- zc0301_requeue_outqueue(cam);
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_framesizes(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_frmsizeenum frmsize;
-
- if (copy_from_user(&frmsize, arg, sizeof(frmsize)))
- return -EFAULT;
-
- if (frmsize.index != 0 && frmsize.index != 1)
- return -EINVAL;
-
- if (frmsize.pixel_format != V4L2_PIX_FMT_JPEG)
- return -EINVAL;
-
- frmsize.type = V4L2_FRMSIZE_TYPE_DISCRETE;
-
- if (frmsize.index == 1) {
- frmsize.discrete.width = cam->sensor.cropcap.defrect.width;
- frmsize.discrete.height = cam->sensor.cropcap.defrect.height;
- }
- memset(&frmsize.reserved, 0, sizeof(frmsize.reserved));
-
- if (copy_to_user(arg, &frmsize, sizeof(frmsize)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_enum_fmt(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_fmtdesc fmtd;
-
- if (copy_from_user(&fmtd, arg, sizeof(fmtd)))
- return -EFAULT;
-
- if (fmtd.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- if (fmtd.index == 0) {
- strcpy(fmtd.description, "JPEG");
- fmtd.pixelformat = V4L2_PIX_FMT_JPEG;
- fmtd.flags = V4L2_FMT_FLAG_COMPRESSED;
- } else
- return -EINVAL;
-
- fmtd.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- memset(&fmtd.reserved, 0, sizeof(fmtd.reserved));
-
- if (copy_to_user(arg, &fmtd, sizeof(fmtd)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_fmt(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_format format;
- struct v4l2_pix_format* pfmt = &(cam->sensor.pix_format);
-
- if (copy_from_user(&format, arg, sizeof(format)))
- return -EFAULT;
-
- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- pfmt->bytesperline = 0;
- pfmt->sizeimage = pfmt->height * ((pfmt->width*pfmt->priv)/8);
- pfmt->field = V4L2_FIELD_NONE;
- memcpy(&(format.fmt.pix), pfmt, sizeof(*pfmt));
-
- if (copy_to_user(arg, &format, sizeof(format)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_try_s_fmt(struct zc0301_device* cam, unsigned int cmd,
- void __user * arg)
-{
- struct zc0301_sensor* s = &cam->sensor;
- struct v4l2_format format;
- struct v4l2_pix_format* pix;
- struct v4l2_pix_format* pfmt = &(s->pix_format);
- struct v4l2_rect* bounds = &(s->cropcap.bounds);
- struct v4l2_rect rect;
- const enum zc0301_stream_state stream = cam->stream;
- const u32 nbuffers = cam->nbuffers;
- u32 i;
- int err = 0;
-
- if (copy_from_user(&format, arg, sizeof(format)))
- return -EFAULT;
-
- pix = &(format.fmt.pix);
-
- if (format.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- memcpy(&rect, &(s->_rect), sizeof(rect));
-
- if (!s->set_crop) {
- pix->width = rect.width;
- pix->height = rect.height;
- } else {
- rect.width = pix->width;
- rect.height = pix->height;
- }
-
- if (rect.width < 8)
- rect.width = 8;
- if (rect.height < 8)
- rect.height = 8;
- if (rect.width > bounds->left + bounds->width - rect.left)
- rect.width = bounds->left + bounds->width - rect.left;
- if (rect.height > bounds->top + bounds->height - rect.top)
- rect.height = bounds->top + bounds->height - rect.top;
- rect.width &= ~7L;
- rect.height &= ~7L;
-
- pix->width = rect.width;
- pix->height = rect.height;
- pix->pixelformat = pfmt->pixelformat;
- pix->priv = pfmt->priv;
- pix->colorspace = pfmt->colorspace;
- pix->bytesperline = 0;
- pix->sizeimage = pix->height * ((pix->width * pix->priv) / 8);
- pix->field = V4L2_FIELD_NONE;
-
- if (cmd == VIDIOC_TRY_FMT) {
- if (copy_to_user(arg, &format, sizeof(format)))
- return -EFAULT;
- return 0;
- }
-
- if (cam->module_param.force_munmap)
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_S_FMT failed. "
- "Unmap the buffers first.");
- return -EBUSY;
- }
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- if (copy_to_user(arg, &format, sizeof(format))) {
- cam->stream = stream;
- return -EFAULT;
- }
-
- if (cam->module_param.force_munmap || cam->io == IO_READ)
- zc0301_release_buffers(cam);
-
- if (s->set_crop)
- err += s->set_crop(cam, &rect);
-
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_FMT failed because of hardware problems. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- memcpy(pfmt, pix, sizeof(*pix));
- memcpy(&(s->_rect), &rect, sizeof(rect));
-
- if ((cam->module_param.force_munmap || cam->io == IO_READ) &&
- nbuffers != zc0301_request_buffers(cam, nbuffers, cam->io)) {
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_FMT failed because of not enough memory. To "
- "use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -ENOMEM;
- }
-
- if (cam->io == IO_READ)
- zc0301_empty_framequeues(cam);
- else if (cam->module_param.force_munmap)
- zc0301_requeue_outqueue(cam);
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
- if (copy_to_user(arg, &cam->compression, sizeof(cam->compression)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_s_jpegcomp(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_jpegcompression jc;
- const enum zc0301_stream_state stream = cam->stream;
- int err = 0;
-
- if (copy_from_user(&jc, arg, sizeof(jc)))
- return -EFAULT;
-
- if (jc.quality != 0)
- return -EINVAL;
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- err += zc0301_set_compression(cam, &jc);
- if (err) { /* atomic, no rollback in ioctl() */
- cam->state |= DEV_MISCONFIGURED;
- DBG(1, "VIDIOC_S_JPEGCOMP failed because of hardware "
- "problems. To use the camera, close and open %s again.",
- video_device_node_name(cam->v4ldev));
- return -EIO;
- }
-
- cam->compression.quality = jc.quality;
-
- cam->stream = stream;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_reqbufs(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_requestbuffers rb;
- u32 i;
- int err;
-
- if (copy_from_user(&rb, arg, sizeof(rb)))
- return -EFAULT;
-
- if (rb.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- rb.memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (cam->io == IO_READ) {
- DBG(3, "Close and open the device again to choose the mmap "
- "I/O method");
- return -EBUSY;
- }
-
- for (i = 0; i < cam->nbuffers; i++)
- if (cam->frame[i].vma_use_count) {
- DBG(3, "VIDIOC_REQBUFS failed. "
- "Previous buffers are still mapped.");
- return -EBUSY;
- }
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- zc0301_empty_framequeues(cam);
-
- zc0301_release_buffers(cam);
- if (rb.count)
- rb.count = zc0301_request_buffers(cam, rb.count, IO_MMAP);
-
- if (copy_to_user(arg, &rb, sizeof(rb))) {
- zc0301_release_buffers(cam);
- cam->io = IO_NONE;
- return -EFAULT;
- }
-
- cam->io = rb.count ? IO_MMAP : IO_NONE;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_querybuf(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_buffer b;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b.index >= cam->nbuffers || cam->io != IO_MMAP)
- return -EINVAL;
-
- memcpy(&b, &cam->frame[b.index].buf, sizeof(b));
-
- if (cam->frame[b.index].vma_use_count)
- b.flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (cam->frame[b.index].state == F_DONE)
- b.flags |= V4L2_BUF_FLAG_DONE;
- else if (cam->frame[b.index].state != F_UNUSED)
- b.flags |= V4L2_BUF_FLAG_QUEUED;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_qbuf(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_buffer b;
- unsigned long lock_flags;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b.index >= cam->nbuffers || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (cam->frame[b.index].state != F_UNUSED)
- return -EINVAL;
-
- cam->frame[b.index].state = F_QUEUED;
-
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- list_add_tail(&cam->frame[b.index].frame, &cam->inqueue);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- PDBGG("Frame #%lu queued", (unsigned long)b.index);
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_dqbuf(struct zc0301_device* cam, struct file* filp,
- void __user * arg)
-{
- struct v4l2_buffer b;
- struct zc0301_frame_t *f;
- unsigned long lock_flags;
- long timeout;
-
- if (copy_from_user(&b, arg, sizeof(b)))
- return -EFAULT;
-
- if (b.type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io!= IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&cam->outqueue)) {
- if (cam->stream == STREAM_OFF)
- return -EINVAL;
- if (filp->f_flags & O_NONBLOCK)
- return -EAGAIN;
- timeout = wait_event_interruptible_timeout
- ( cam->wait_frame,
- (!list_empty(&cam->outqueue)) ||
- (cam->state & DEV_DISCONNECTED) ||
- (cam->state & DEV_MISCONFIGURED),
- cam->module_param.frame_timeout *
- 1000 * msecs_to_jiffies(1) );
- if (timeout < 0)
- return timeout;
- if (cam->state & DEV_DISCONNECTED)
- return -ENODEV;
- if (!timeout || (cam->state & DEV_MISCONFIGURED))
- return -EIO;
- }
-
- spin_lock_irqsave(&cam->queue_lock, lock_flags);
- f = list_entry(cam->outqueue.next, struct zc0301_frame_t, frame);
- list_del(cam->outqueue.next);
- spin_unlock_irqrestore(&cam->queue_lock, lock_flags);
-
- f->state = F_UNUSED;
-
- memcpy(&b, &f->buf, sizeof(b));
- if (f->vma_use_count)
- b.flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (copy_to_user(arg, &b, sizeof(b)))
- return -EFAULT;
-
- PDBGG("Frame #%lu dequeued", (unsigned long)f->buf.index);
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_streamon(struct zc0301_device* cam, void __user * arg)
-{
- int type;
-
- if (copy_from_user(&type, arg, sizeof(type)))
- return -EFAULT;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- cam->stream = STREAM_ON;
-
- DBG(3, "Stream on");
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_streamoff(struct zc0301_device* cam, void __user * arg)
-{
- int type, err;
-
- if (copy_from_user(&type, arg, sizeof(type)))
- return -EFAULT;
-
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || cam->io != IO_MMAP)
- return -EINVAL;
-
- if (cam->stream == STREAM_ON)
- if ((err = zc0301_stream_interrupt(cam)))
- return err;
-
- zc0301_empty_framequeues(cam);
-
- DBG(3, "Stream off");
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_g_parm(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_streamparm sp;
-
- if (copy_from_user(&sp, arg, sizeof(sp)))
- return -EFAULT;
-
- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp.parm.capture.extendedmode = 0;
- sp.parm.capture.readbuffers = cam->nreadbuffers;
-
- if (copy_to_user(arg, &sp, sizeof(sp)))
- return -EFAULT;
-
- return 0;
-}
-
-
-static int
-zc0301_vidioc_s_parm(struct zc0301_device* cam, void __user * arg)
-{
- struct v4l2_streamparm sp;
-
- if (copy_from_user(&sp, arg, sizeof(sp)))
- return -EFAULT;
-
- if (sp.type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
-
- sp.parm.capture.extendedmode = 0;
-
- if (sp.parm.capture.readbuffers == 0)
- sp.parm.capture.readbuffers = cam->nreadbuffers;
-
- if (sp.parm.capture.readbuffers > ZC0301_MAX_FRAMES)
- sp.parm.capture.readbuffers = ZC0301_MAX_FRAMES;
-
- if (copy_to_user(arg, &sp, sizeof(sp)))
- return -EFAULT;
-
- cam->nreadbuffers = sp.parm.capture.readbuffers;
-
- return 0;
-}
-
-
-static long zc0301_ioctl_v4l2(struct file *filp,
- unsigned int cmd, void __user *arg)
-{
- struct zc0301_device *cam = video_drvdata(filp);
-
- switch (cmd) {
-
- case VIDIOC_QUERYCAP:
- return zc0301_vidioc_querycap(cam, arg);
-
- case VIDIOC_ENUMINPUT:
- return zc0301_vidioc_enuminput(cam, arg);
-
- case VIDIOC_G_INPUT:
- return zc0301_vidioc_g_input(cam, arg);
-
- case VIDIOC_S_INPUT:
- return zc0301_vidioc_s_input(cam, arg);
-
- case VIDIOC_QUERYCTRL:
- return zc0301_vidioc_query_ctrl(cam, arg);
-
- case VIDIOC_G_CTRL:
- return zc0301_vidioc_g_ctrl(cam, arg);
-
- case VIDIOC_S_CTRL:
- return zc0301_vidioc_s_ctrl(cam, arg);
-
- case VIDIOC_CROPCAP:
- return zc0301_vidioc_cropcap(cam, arg);
-
- case VIDIOC_G_CROP:
- return zc0301_vidioc_g_crop(cam, arg);
-
- case VIDIOC_S_CROP:
- return zc0301_vidioc_s_crop(cam, arg);
-
- case VIDIOC_ENUM_FMT:
- return zc0301_vidioc_enum_fmt(cam, arg);
-
- case VIDIOC_G_FMT:
- return zc0301_vidioc_g_fmt(cam, arg);
-
- case VIDIOC_TRY_FMT:
- case VIDIOC_S_FMT:
- return zc0301_vidioc_try_s_fmt(cam, cmd, arg);
-
- case VIDIOC_ENUM_FRAMESIZES:
- return zc0301_vidioc_enum_framesizes(cam, arg);
-
- case VIDIOC_G_JPEGCOMP:
- return zc0301_vidioc_g_jpegcomp(cam, arg);
-
- case VIDIOC_S_JPEGCOMP:
- return zc0301_vidioc_s_jpegcomp(cam, arg);
-
- case VIDIOC_REQBUFS:
- return zc0301_vidioc_reqbufs(cam, arg);
-
- case VIDIOC_QUERYBUF:
- return zc0301_vidioc_querybuf(cam, arg);
-
- case VIDIOC_QBUF:
- return zc0301_vidioc_qbuf(cam, arg);
-
- case VIDIOC_DQBUF:
- return zc0301_vidioc_dqbuf(cam, filp, arg);
-
- case VIDIOC_STREAMON:
- return zc0301_vidioc_streamon(cam, arg);
-
- case VIDIOC_STREAMOFF:
- return zc0301_vidioc_streamoff(cam, arg);
-
- case VIDIOC_G_PARM:
- return zc0301_vidioc_g_parm(cam, arg);
-
- case VIDIOC_S_PARM:
- return zc0301_vidioc_s_parm(cam, arg);
-
- case VIDIOC_G_STD:
- case VIDIOC_S_STD:
- case VIDIOC_QUERYSTD:
- case VIDIOC_ENUMSTD:
- case VIDIOC_QUERYMENU:
- case VIDIOC_ENUM_FRAMEINTERVALS:
- return -EINVAL;
-
- default:
- return -EINVAL;
-
- }
-}
-
-
-static long zc0301_ioctl(struct file *filp,
- unsigned int cmd, unsigned long arg)
-{
- struct zc0301_device *cam = video_drvdata(filp);
- int err = 0;
-
- if (mutex_lock_interruptible(&cam->fileop_mutex))
- return -ERESTARTSYS;
-
- if (cam->state & DEV_DISCONNECTED) {
- DBG(1, "Device not present");
- mutex_unlock(&cam->fileop_mutex);
- return -ENODEV;
- }
-
- if (cam->state & DEV_MISCONFIGURED) {
- DBG(1, "The camera is misconfigured. Close and open it "
- "again.");
- mutex_unlock(&cam->fileop_mutex);
- return -EIO;
- }
-
- V4LDBG(3, "zc0301", cmd);
-
- err = zc0301_ioctl_v4l2(filp, cmd, (void __user *)arg);
-
- mutex_unlock(&cam->fileop_mutex);
-
- return err;
-}
-
-
-static const struct v4l2_file_operations zc0301_fops = {
- .owner = THIS_MODULE,
- .open = zc0301_open,
- .release = zc0301_release,
- .ioctl = zc0301_ioctl,
- .read = zc0301_read,
- .poll = zc0301_poll,
- .mmap = zc0301_mmap,
-};
-
-/*****************************************************************************/
-
-static int
-zc0301_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
-{
- struct usb_device *udev = interface_to_usbdev(intf);
- struct zc0301_device* cam;
- static unsigned int dev_nr;
- unsigned int i;
- int err = 0;
-
- if (!(cam = kzalloc(sizeof(struct zc0301_device), GFP_KERNEL)))
- return -ENOMEM;
-
- cam->usbdev = udev;
-
- if (!(cam->control_buffer = kzalloc(4, GFP_KERNEL))) {
- DBG(1, "kmalloc() failed");
- err = -ENOMEM;
- goto fail;
- }
-
- if (!(cam->v4ldev = video_device_alloc())) {
- DBG(1, "video_device_alloc() failed");
- err = -ENOMEM;
- goto fail;
- }
-
- DBG(2, "ZC0301[P] Image Processor and Control Chip detected "
- "(vid/pid 0x%04X:0x%04X)",id->idVendor, id->idProduct);
-
- for (i = 0; zc0301_sensor_table[i]; i++) {
- err = zc0301_sensor_table[i](cam);
- if (!err)
- break;
- }
-
- if (!err)
- DBG(2, "%s image sensor detected", cam->sensor.name);
- else {
- DBG(1, "No supported image sensor detected");
- err = -ENODEV;
- goto fail;
- }
-
- if (zc0301_init(cam)) {
- DBG(1, "Initialization failed. I will retry on open().");
- cam->state |= DEV_MISCONFIGURED;
- }
-
- strcpy(cam->v4ldev->name, "ZC0301[P] PC Camera");
- cam->v4ldev->fops = &zc0301_fops;
- cam->v4ldev->release = video_device_release;
- cam->v4ldev->parent = &udev->dev;
- video_set_drvdata(cam->v4ldev, cam);
-
- init_completion(&cam->probe);
-
- err = video_register_device(cam->v4ldev, VFL_TYPE_GRABBER,
- video_nr[dev_nr]);
- if (err) {
- DBG(1, "V4L2 device registration failed");
- if (err == -ENFILE && video_nr[dev_nr] == -1)
- DBG(1, "Free /dev/videoX node not found");
- video_nr[dev_nr] = -1;
- dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
- complete_all(&cam->probe);
- goto fail;
- }
-
- DBG(2, "V4L2 device registered as %s",
- video_device_node_name(cam->v4ldev));
-
- cam->module_param.force_munmap = force_munmap[dev_nr];
- cam->module_param.frame_timeout = frame_timeout[dev_nr];
-
- dev_nr = (dev_nr < ZC0301_MAX_DEVICES-1) ? dev_nr+1 : 0;
-
- usb_set_intfdata(intf, cam);
- kref_init(&cam->kref);
- usb_get_dev(cam->usbdev);
-
- complete_all(&cam->probe);
-
- return 0;
-
-fail:
- if (cam) {
- kfree(cam->control_buffer);
- if (cam->v4ldev)
- video_device_release(cam->v4ldev);
- kfree(cam);
- }
- return err;
-}
-
-
-static void zc0301_usb_disconnect(struct usb_interface* intf)
-{
- struct zc0301_device* cam;
-
- down_write(&zc0301_dev_lock);
-
- cam = usb_get_intfdata(intf);
-
- DBG(2, "Disconnecting %s...", cam->v4ldev->name);
-
- if (cam->users) {
- DBG(2, "Device %s is open! Deregistration and "
- "memory deallocation are deferred.",
- video_device_node_name(cam->v4ldev));
- cam->state |= DEV_MISCONFIGURED;
- zc0301_stop_transfer(cam);
- cam->state |= DEV_DISCONNECTED;
- wake_up_interruptible(&cam->wait_frame);
- wake_up(&cam->wait_stream);
- } else
- cam->state |= DEV_DISCONNECTED;
-
- wake_up_interruptible_all(&cam->wait_open);
-
- kref_put(&cam->kref, zc0301_release_resources);
-
- up_write(&zc0301_dev_lock);
-}
-
-
-static struct usb_driver zc0301_usb_driver = {
- .name = "zc0301",
- .id_table = zc0301_id_table,
- .probe = zc0301_usb_probe,
- .disconnect = zc0301_usb_disconnect,
-};
-
-/*****************************************************************************/
-
-static int __init zc0301_module_init(void)
-{
- int err = 0;
-
- KDBG(2, ZC0301_MODULE_NAME " v" ZC0301_MODULE_VERSION);
- KDBG(3, ZC0301_MODULE_AUTHOR);
-
- if ((err = usb_register(&zc0301_usb_driver)))
- KDBG(1, "usb_register() failed");
-
- return err;
-}
-
-
-static void __exit zc0301_module_exit(void)
-{
- usb_deregister(&zc0301_usb_driver);
-}
-
-
-module_init(zc0301_module_init);
-module_exit(zc0301_module_exit);
diff --git a/drivers/media/video/zc0301/zc0301_pas202bcb.c b/drivers/media/video/zc0301/zc0301_pas202bcb.c
deleted file mode 100644
index 24b0dfba357e..000000000000
--- a/drivers/media/video/zc0301/zc0301_pas202bcb.c
+++ /dev/null
@@ -1,362 +0,0 @@
-/***************************************************************************
- * Plug-in for PAS202BCB image sensor connected to the ZC0301 Image *
- * Processor and Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
- * driver maintained by Michel Xhaard <mxhaard@magic.fr> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * 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. *
- ***************************************************************************/
-
-/*
- NOTE: Sensor controls are disabled for now, becouse changing them while
- streaming sometimes results in out-of-sync video frames. We'll use
- the default initialization, until we know how to stop and start video
- in the chip. However, the image quality still looks good under various
- light conditions.
-*/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pas202bcb;
-
-
-static int pas202bcb_init(struct zc0301_device* cam)
-{
- int err = 0;
-
- err += zc0301_write_reg(cam, 0x0002, 0x00);
- err += zc0301_write_reg(cam, 0x0003, 0x02);
- err += zc0301_write_reg(cam, 0x0004, 0x80);
- err += zc0301_write_reg(cam, 0x0005, 0x01);
- err += zc0301_write_reg(cam, 0x0006, 0xE0);
- err += zc0301_write_reg(cam, 0x0098, 0x00);
- err += zc0301_write_reg(cam, 0x009A, 0x03);
- err += zc0301_write_reg(cam, 0x011A, 0x00);
- err += zc0301_write_reg(cam, 0x011C, 0x03);
- err += zc0301_write_reg(cam, 0x009B, 0x01);
- err += zc0301_write_reg(cam, 0x009C, 0xE6);
- err += zc0301_write_reg(cam, 0x009D, 0x02);
- err += zc0301_write_reg(cam, 0x009E, 0x86);
-
- err += zc0301_i2c_write(cam, 0x02, 0x02);
- err += zc0301_i2c_write(cam, 0x0A, 0x01);
- err += zc0301_i2c_write(cam, 0x0B, 0x01);
- err += zc0301_i2c_write(cam, 0x0D, 0x00);
- err += zc0301_i2c_write(cam, 0x12, 0x05);
- err += zc0301_i2c_write(cam, 0x13, 0x63);
- err += zc0301_i2c_write(cam, 0x15, 0x70);
-
- err += zc0301_write_reg(cam, 0x0101, 0xB7);
- err += zc0301_write_reg(cam, 0x0100, 0x0D);
- err += zc0301_write_reg(cam, 0x0189, 0x06);
- err += zc0301_write_reg(cam, 0x01AD, 0x00);
- err += zc0301_write_reg(cam, 0x01C5, 0x03);
- err += zc0301_write_reg(cam, 0x01CB, 0x13);
- err += zc0301_write_reg(cam, 0x0250, 0x08);
- err += zc0301_write_reg(cam, 0x0301, 0x08);
- err += zc0301_write_reg(cam, 0x018D, 0x70);
- err += zc0301_write_reg(cam, 0x0008, 0x03);
- err += zc0301_write_reg(cam, 0x01C6, 0x04);
- err += zc0301_write_reg(cam, 0x01CB, 0x07);
- err += zc0301_write_reg(cam, 0x0120, 0x11);
- err += zc0301_write_reg(cam, 0x0121, 0x37);
- err += zc0301_write_reg(cam, 0x0122, 0x58);
- err += zc0301_write_reg(cam, 0x0123, 0x79);
- err += zc0301_write_reg(cam, 0x0124, 0x91);
- err += zc0301_write_reg(cam, 0x0125, 0xA6);
- err += zc0301_write_reg(cam, 0x0126, 0xB8);
- err += zc0301_write_reg(cam, 0x0127, 0xC7);
- err += zc0301_write_reg(cam, 0x0128, 0xD3);
- err += zc0301_write_reg(cam, 0x0129, 0xDE);
- err += zc0301_write_reg(cam, 0x012A, 0xE6);
- err += zc0301_write_reg(cam, 0x012B, 0xED);
- err += zc0301_write_reg(cam, 0x012C, 0xF3);
- err += zc0301_write_reg(cam, 0x012D, 0xF8);
- err += zc0301_write_reg(cam, 0x012E, 0xFB);
- err += zc0301_write_reg(cam, 0x012F, 0xFF);
- err += zc0301_write_reg(cam, 0x0130, 0x26);
- err += zc0301_write_reg(cam, 0x0131, 0x23);
- err += zc0301_write_reg(cam, 0x0132, 0x20);
- err += zc0301_write_reg(cam, 0x0133, 0x1C);
- err += zc0301_write_reg(cam, 0x0134, 0x16);
- err += zc0301_write_reg(cam, 0x0135, 0x13);
- err += zc0301_write_reg(cam, 0x0136, 0x10);
- err += zc0301_write_reg(cam, 0x0137, 0x0D);
- err += zc0301_write_reg(cam, 0x0138, 0x0B);
- err += zc0301_write_reg(cam, 0x0139, 0x09);
- err += zc0301_write_reg(cam, 0x013A, 0x07);
- err += zc0301_write_reg(cam, 0x013B, 0x06);
- err += zc0301_write_reg(cam, 0x013C, 0x05);
- err += zc0301_write_reg(cam, 0x013D, 0x04);
- err += zc0301_write_reg(cam, 0x013E, 0x03);
- err += zc0301_write_reg(cam, 0x013F, 0x02);
- err += zc0301_write_reg(cam, 0x010A, 0x4C);
- err += zc0301_write_reg(cam, 0x010B, 0xF5);
- err += zc0301_write_reg(cam, 0x010C, 0xFF);
- err += zc0301_write_reg(cam, 0x010D, 0xF9);
- err += zc0301_write_reg(cam, 0x010E, 0x51);
- err += zc0301_write_reg(cam, 0x010F, 0xF5);
- err += zc0301_write_reg(cam, 0x0110, 0xFB);
- err += zc0301_write_reg(cam, 0x0111, 0xED);
- err += zc0301_write_reg(cam, 0x0112, 0x5F);
- err += zc0301_write_reg(cam, 0x0180, 0x00);
- err += zc0301_write_reg(cam, 0x0019, 0x00);
- err += zc0301_write_reg(cam, 0x0087, 0x20);
- err += zc0301_write_reg(cam, 0x0088, 0x21);
-
- err += zc0301_i2c_write(cam, 0x20, 0x02);
- err += zc0301_i2c_write(cam, 0x21, 0x1B);
- err += zc0301_i2c_write(cam, 0x03, 0x44);
- err += zc0301_i2c_write(cam, 0x0E, 0x01);
- err += zc0301_i2c_write(cam, 0x0F, 0x00);
-
- err += zc0301_write_reg(cam, 0x01A9, 0x14);
- err += zc0301_write_reg(cam, 0x01AA, 0x24);
- err += zc0301_write_reg(cam, 0x0190, 0x00);
- err += zc0301_write_reg(cam, 0x0191, 0x02);
- err += zc0301_write_reg(cam, 0x0192, 0x1B);
- err += zc0301_write_reg(cam, 0x0195, 0x00);
- err += zc0301_write_reg(cam, 0x0196, 0x00);
- err += zc0301_write_reg(cam, 0x0197, 0x4D);
- err += zc0301_write_reg(cam, 0x018C, 0x10);
- err += zc0301_write_reg(cam, 0x018F, 0x20);
- err += zc0301_write_reg(cam, 0x001D, 0x44);
- err += zc0301_write_reg(cam, 0x001E, 0x6F);
- err += zc0301_write_reg(cam, 0x001F, 0xAD);
- err += zc0301_write_reg(cam, 0x0020, 0xEB);
- err += zc0301_write_reg(cam, 0x0087, 0x0F);
- err += zc0301_write_reg(cam, 0x0088, 0x0E);
- err += zc0301_write_reg(cam, 0x0180, 0x40);
- err += zc0301_write_reg(cam, 0x0192, 0x1B);
- err += zc0301_write_reg(cam, 0x0191, 0x02);
- err += zc0301_write_reg(cam, 0x0190, 0x00);
- err += zc0301_write_reg(cam, 0x0116, 0x1D);
- err += zc0301_write_reg(cam, 0x0117, 0x40);
- err += zc0301_write_reg(cam, 0x0118, 0x99);
- err += zc0301_write_reg(cam, 0x0180, 0x42);
- err += zc0301_write_reg(cam, 0x0116, 0x1D);
- err += zc0301_write_reg(cam, 0x0117, 0x40);
- err += zc0301_write_reg(cam, 0x0118, 0x99);
- err += zc0301_write_reg(cam, 0x0007, 0x00);
-
- err += zc0301_i2c_write(cam, 0x11, 0x01);
-
- msleep(100);
-
- return err;
-}
-
-
-static int pas202bcb_get_ctrl(struct zc0301_device* cam,
- struct v4l2_control* ctrl)
-{
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- {
- int r1 = zc0301_i2c_read(cam, 0x04, 1),
- r2 = zc0301_i2c_read(cam, 0x05, 1);
- if (r1 < 0 || r2 < 0)
- return -EIO;
- ctrl->value = (r1 << 6) | (r2 & 0x3f);
- }
- return 0;
- case V4L2_CID_RED_BALANCE:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x09, 1)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case V4L2_CID_BLUE_BALANCE:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x07, 1)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case V4L2_CID_GAIN:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x10, 1)) < 0)
- return -EIO;
- ctrl->value &= 0x1f;
- return 0;
- case ZC0301_V4L2_CID_GREEN_BALANCE:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x08, 1)) < 0)
- return -EIO;
- ctrl->value &= 0x0f;
- return 0;
- case ZC0301_V4L2_CID_DAC_MAGNITUDE:
- if ((ctrl->value = zc0301_i2c_read(cam, 0x0c, 1)) < 0)
- return -EIO;
- return 0;
- default:
- return -EINVAL;
- }
-}
-
-
-static int pas202bcb_set_ctrl(struct zc0301_device* cam,
- const struct v4l2_control* ctrl)
-{
- int err = 0;
-
- switch (ctrl->id) {
- case V4L2_CID_EXPOSURE:
- err += zc0301_i2c_write(cam, 0x04, ctrl->value >> 6);
- err += zc0301_i2c_write(cam, 0x05, ctrl->value & 0x3f);
- break;
- case V4L2_CID_RED_BALANCE:
- err += zc0301_i2c_write(cam, 0x09, ctrl->value);
- break;
- case V4L2_CID_BLUE_BALANCE:
- err += zc0301_i2c_write(cam, 0x07, ctrl->value);
- break;
- case V4L2_CID_GAIN:
- err += zc0301_i2c_write(cam, 0x10, ctrl->value);
- break;
- case ZC0301_V4L2_CID_GREEN_BALANCE:
- err += zc0301_i2c_write(cam, 0x08, ctrl->value);
- break;
- case ZC0301_V4L2_CID_DAC_MAGNITUDE:
- err += zc0301_i2c_write(cam, 0x0c, ctrl->value);
- break;
- default:
- return -EINVAL;
- }
- err += zc0301_i2c_write(cam, 0x11, 0x01);
-
- return err ? -EIO : 0;
-}
-
-
-static struct zc0301_sensor pas202bcb = {
- .name = "PAS202BCB",
- .init = &pas202bcb_init,
- .qctrl = {
- {
- .id = V4L2_CID_EXPOSURE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "exposure",
- .minimum = 0x01e5,
- .maximum = 0x3fff,
- .step = 0x0001,
- .default_value = 0x01e5,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_GAIN,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "global gain",
- .minimum = 0x00,
- .maximum = 0x1f,
- .step = 0x01,
- .default_value = 0x0c,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = ZC0301_V4L2_CID_DAC_MAGNITUDE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "DAC magnitude",
- .minimum = 0x00,
- .maximum = 0xff,
- .step = 0x01,
- .default_value = 0x00,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_RED_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "red balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x01,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = V4L2_CID_BLUE_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "blue balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x05,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- {
- .id = ZC0301_V4L2_CID_GREEN_BALANCE,
- .type = V4L2_CTRL_TYPE_INTEGER,
- .name = "green balance",
- .minimum = 0x00,
- .maximum = 0x0f,
- .step = 0x01,
- .default_value = 0x00,
- .flags = V4L2_CTRL_FLAG_DISABLED,
- },
- },
- .get_ctrl = &pas202bcb_get_ctrl,
- .set_ctrl = &pas202bcb_set_ctrl,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_JPEG,
- .priv = 8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- },
-};
-
-
-int zc0301_probe_pas202bcb(struct zc0301_device* cam)
-{
- int r0 = 0, r1 = 0, err = 0;
- unsigned int pid = 0;
-
- err += zc0301_write_reg(cam, 0x0000, 0x01);
- err += zc0301_write_reg(cam, 0x0010, 0x0e);
- err += zc0301_write_reg(cam, 0x0001, 0x01);
- err += zc0301_write_reg(cam, 0x0012, 0x03);
- err += zc0301_write_reg(cam, 0x0012, 0x01);
- err += zc0301_write_reg(cam, 0x008d, 0x08);
-
- msleep(10);
-
- r0 = zc0301_i2c_read(cam, 0x00, 1);
- r1 = zc0301_i2c_read(cam, 0x01, 1);
-
- if (r0 < 0 || r1 < 0 || err)
- return -EIO;
-
- pid = (r0 << 4) | ((r1 & 0xf0) >> 4);
- if (pid != 0x017)
- return -ENODEV;
-
- zc0301_attach_sensor(cam, &pas202bcb);
-
- return 0;
-}
diff --git a/drivers/media/video/zc0301/zc0301_pb0330.c b/drivers/media/video/zc0301/zc0301_pb0330.c
deleted file mode 100644
index 9519aba3612e..000000000000
--- a/drivers/media/video/zc0301/zc0301_pb0330.c
+++ /dev/null
@@ -1,188 +0,0 @@
-/***************************************************************************
- * Plug-in for PB-0330 image sensor connected to the ZC0301P Image *
- * Processor and Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * Initialization values of the ZC0301[P] have been taken from the SPCA5XX *
- * driver maintained by Michel Xhaard <mxhaard@magic.fr> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#include <linux/delay.h>
-#include "zc0301_sensor.h"
-
-
-static struct zc0301_sensor pb0330;
-
-
-static int pb0330_init(struct zc0301_device* cam)
-{
- int err = 0;
-
- err += zc0301_write_reg(cam, 0x0000, 0x01);
- err += zc0301_write_reg(cam, 0x0008, 0x03);
- err += zc0301_write_reg(cam, 0x0010, 0x0A);
- err += zc0301_write_reg(cam, 0x0002, 0x00);
- err += zc0301_write_reg(cam, 0x0003, 0x02);
- err += zc0301_write_reg(cam, 0x0004, 0x80);
- err += zc0301_write_reg(cam, 0x0005, 0x01);
- err += zc0301_write_reg(cam, 0x0006, 0xE0);
- err += zc0301_write_reg(cam, 0x0001, 0x01);
- err += zc0301_write_reg(cam, 0x0012, 0x05);
- err += zc0301_write_reg(cam, 0x0012, 0x07);
- err += zc0301_write_reg(cam, 0x0098, 0x00);
- err += zc0301_write_reg(cam, 0x009A, 0x00);
- err += zc0301_write_reg(cam, 0x011A, 0x00);
- err += zc0301_write_reg(cam, 0x011C, 0x00);
- err += zc0301_write_reg(cam, 0x0012, 0x05);
-
- err += zc0301_i2c_write(cam, 0x01, 0x0006);
- err += zc0301_i2c_write(cam, 0x02, 0x0011);
- err += zc0301_i2c_write(cam, 0x03, 0x01E7);
- err += zc0301_i2c_write(cam, 0x04, 0x0287);
- err += zc0301_i2c_write(cam, 0x06, 0x0003);
- err += zc0301_i2c_write(cam, 0x07, 0x3002);
- err += zc0301_i2c_write(cam, 0x20, 0x1100);
- err += zc0301_i2c_write(cam, 0x2F, 0xF7B0);
- err += zc0301_i2c_write(cam, 0x30, 0x0005);
- err += zc0301_i2c_write(cam, 0x31, 0x0000);
- err += zc0301_i2c_write(cam, 0x34, 0x0100);
- err += zc0301_i2c_write(cam, 0x35, 0x0060);
- err += zc0301_i2c_write(cam, 0x3D, 0x068F);
- err += zc0301_i2c_write(cam, 0x40, 0x01E0);
- err += zc0301_i2c_write(cam, 0x58, 0x0078);
- err += zc0301_i2c_write(cam, 0x62, 0x0411);
-
- err += zc0301_write_reg(cam, 0x0087, 0x10);
- err += zc0301_write_reg(cam, 0x0101, 0x37);
- err += zc0301_write_reg(cam, 0x0012, 0x05);
- err += zc0301_write_reg(cam, 0x0100, 0x0D);
- err += zc0301_write_reg(cam, 0x0189, 0x06);
- err += zc0301_write_reg(cam, 0x01AD, 0x00);
- err += zc0301_write_reg(cam, 0x01C5, 0x03);
- err += zc0301_write_reg(cam, 0x01CB, 0x13);
- err += zc0301_write_reg(cam, 0x0250, 0x08);
- err += zc0301_write_reg(cam, 0x0301, 0x08);
- err += zc0301_write_reg(cam, 0x01A8, 0x60);
- err += zc0301_write_reg(cam, 0x018D, 0x6C);
- err += zc0301_write_reg(cam, 0x01AD, 0x09);
- err += zc0301_write_reg(cam, 0x01AE, 0x15);
- err += zc0301_write_reg(cam, 0x010A, 0x50);
- err += zc0301_write_reg(cam, 0x010B, 0xF8);
- err += zc0301_write_reg(cam, 0x010C, 0xF8);
- err += zc0301_write_reg(cam, 0x010D, 0xF8);
- err += zc0301_write_reg(cam, 0x010E, 0x50);
- err += zc0301_write_reg(cam, 0x010F, 0xF8);
- err += zc0301_write_reg(cam, 0x0110, 0xF8);
- err += zc0301_write_reg(cam, 0x0111, 0xF8);
- err += zc0301_write_reg(cam, 0x0112, 0x50);
- err += zc0301_write_reg(cam, 0x0008, 0x03);
- err += zc0301_write_reg(cam, 0x01C6, 0x08);
- err += zc0301_write_reg(cam, 0x01CB, 0x0F);
- err += zc0301_write_reg(cam, 0x010A, 0x50);
- err += zc0301_write_reg(cam, 0x010B, 0xF8);
- err += zc0301_write_reg(cam, 0x010C, 0xF8);
- err += zc0301_write_reg(cam, 0x010D, 0xF8);
- err += zc0301_write_reg(cam, 0x010E, 0x50);
- err += zc0301_write_reg(cam, 0x010F, 0xF8);
- err += zc0301_write_reg(cam, 0x0110, 0xF8);
- err += zc0301_write_reg(cam, 0x0111, 0xF8);
- err += zc0301_write_reg(cam, 0x0112, 0x50);
- err += zc0301_write_reg(cam, 0x0180, 0x00);
- err += zc0301_write_reg(cam, 0x0019, 0x00);
-
- err += zc0301_i2c_write(cam, 0x05, 0x0066);
- err += zc0301_i2c_write(cam, 0x09, 0x02B2);
- err += zc0301_i2c_write(cam, 0x10, 0x0002);
-
- err += zc0301_write_reg(cam, 0x011D, 0x60);
- err += zc0301_write_reg(cam, 0x0190, 0x00);
- err += zc0301_write_reg(cam, 0x0191, 0x07);
- err += zc0301_write_reg(cam, 0x0192, 0x8C);
- err += zc0301_write_reg(cam, 0x0195, 0x00);
- err += zc0301_write_reg(cam, 0x0196, 0x00);
- err += zc0301_write_reg(cam, 0x0197, 0x8A);
- err += zc0301_write_reg(cam, 0x018C, 0x10);
- err += zc0301_write_reg(cam, 0x018F, 0x20);
- err += zc0301_write_reg(cam, 0x01A9, 0x14);
- err += zc0301_write_reg(cam, 0x01AA, 0x24);
- err += zc0301_write_reg(cam, 0x001D, 0xD7);
- err += zc0301_write_reg(cam, 0x001E, 0xF0);
- err += zc0301_write_reg(cam, 0x001F, 0xF8);
- err += zc0301_write_reg(cam, 0x0020, 0xFF);
- err += zc0301_write_reg(cam, 0x01AD, 0x09);
- err += zc0301_write_reg(cam, 0x01AE, 0x15);
- err += zc0301_write_reg(cam, 0x0180, 0x40);
- err += zc0301_write_reg(cam, 0x0180, 0x42);
-
- msleep(100);
-
- return err;
-}
-
-
-static struct zc0301_sensor pb0330 = {
- .name = "PB-0330",
- .init = &pb0330_init,
- .cropcap = {
- .bounds = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- .defrect = {
- .left = 0,
- .top = 0,
- .width = 640,
- .height = 480,
- },
- },
- .pix_format = {
- .width = 640,
- .height = 480,
- .pixelformat = V4L2_PIX_FMT_JPEG,
- .priv = 8,
- .colorspace = V4L2_COLORSPACE_JPEG,
- },
-};
-
-
-int zc0301_probe_pb0330(struct zc0301_device* cam)
-{
- int r0, err = 0;
-
- err += zc0301_write_reg(cam, 0x0000, 0x01);
- err += zc0301_write_reg(cam, 0x0010, 0x0a);
- err += zc0301_write_reg(cam, 0x0001, 0x01);
- err += zc0301_write_reg(cam, 0x0012, 0x03);
- err += zc0301_write_reg(cam, 0x0012, 0x01);
-
- msleep(10);
-
- r0 = zc0301_i2c_read(cam, 0x00, 2);
-
- if (r0 < 0 || err)
- return -EIO;
-
- if (r0 != 0x8243)
- return -ENODEV;
-
- zc0301_attach_sensor(cam, &pb0330);
-
- return 0;
-}
diff --git a/drivers/media/video/zc0301/zc0301_sensor.h b/drivers/media/video/zc0301/zc0301_sensor.h
deleted file mode 100644
index 0be783c203f7..000000000000
--- a/drivers/media/video/zc0301/zc0301_sensor.h
+++ /dev/null
@@ -1,107 +0,0 @@
-/***************************************************************************
- * API for image sensors connected to the ZC0301[P] Image Processor and *
- * Control Chip *
- * *
- * Copyright (C) 2006-2007 by Luca Risolia <luca.risolia@studio.unibo.it> *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- * You should have received a copy of the GNU General Public License *
- * along with this program; if not, write to the Free Software *
- * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
- ***************************************************************************/
-
-#ifndef _ZC0301_SENSOR_H_
-#define _ZC0301_SENSOR_H_
-
-#include <linux/usb.h>
-#include <linux/videodev2.h>
-#include <linux/device.h>
-#include <linux/stddef.h>
-#include <linux/errno.h>
-#include <asm/types.h>
-
-struct zc0301_device;
-struct zc0301_sensor;
-
-/*****************************************************************************/
-
-extern int zc0301_probe_pas202bcb(struct zc0301_device* cam);
-extern int zc0301_probe_pb0330(struct zc0301_device* cam);
-
-#define ZC0301_SENSOR_TABLE \
-/* Weak detections must go at the end of the list */ \
-static int (*zc0301_sensor_table[])(struct zc0301_device*) = { \
- &zc0301_probe_pas202bcb, \
- &zc0301_probe_pb0330, \
- NULL, \
-};
-
-extern struct zc0301_device*
-zc0301_match_id(struct zc0301_device* cam, const struct usb_device_id *id);
-
-extern void
-zc0301_attach_sensor(struct zc0301_device* cam, struct zc0301_sensor* sensor);
-
-#define ZC0301_USB_DEVICE(vend, prod, intclass) \
- .match_flags = USB_DEVICE_ID_MATCH_DEVICE | \
- USB_DEVICE_ID_MATCH_INT_CLASS, \
- .idVendor = (vend), \
- .idProduct = (prod), \
- .bInterfaceClass = (intclass)
-
-#if !defined CONFIG_USB_GSPCA_ZC3XX && !defined CONFIG_USB_GSPCA_ZC3XX_MODULE
-#define ZC0301_ID_TABLE \
-static const struct usb_device_id zc0301_id_table[] = { \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
- { ZC0301_USB_DEVICE(0x0ac8, 0x303b, 0xff), }, /* PB-0330 */ \
- { } \
-};
-#else
-#define ZC0301_ID_TABLE \
-static const struct usb_device_id zc0301_id_table[] = { \
- { ZC0301_USB_DEVICE(0x046d, 0x08ae, 0xff), }, /* PAS202 */ \
- { } \
-};
-#endif
-
-/*****************************************************************************/
-
-extern int zc0301_write_reg(struct zc0301_device*, u16 index, u16 value);
-extern int zc0301_read_reg(struct zc0301_device*, u16 index);
-extern int zc0301_i2c_write(struct zc0301_device*, u16 address, u16 value);
-extern int zc0301_i2c_read(struct zc0301_device*, u16 address, u8 length);
-
-/*****************************************************************************/
-
-#define ZC0301_MAX_CTRLS (V4L2_CID_LASTP1 - V4L2_CID_BASE + 10)
-#define ZC0301_V4L2_CID_DAC_MAGNITUDE (V4L2_CID_PRIVATE_BASE + 0)
-#define ZC0301_V4L2_CID_GREEN_BALANCE (V4L2_CID_PRIVATE_BASE + 1)
-
-struct zc0301_sensor {
- char name[32];
-
- struct v4l2_queryctrl qctrl[ZC0301_MAX_CTRLS];
- struct v4l2_cropcap cropcap;
- struct v4l2_pix_format pix_format;
-
- int (*init)(struct zc0301_device*);
- int (*get_ctrl)(struct zc0301_device*, struct v4l2_control* ctrl);
- int (*set_ctrl)(struct zc0301_device*,
- const struct v4l2_control* ctrl);
- int (*set_crop)(struct zc0301_device*, const struct v4l2_rect* rect);
-
- /* Private */
- struct v4l2_queryctrl _qctrl[ZC0301_MAX_CTRLS];
- struct v4l2_rect _rect;
-};
-
-#endif /* _ZC0301_SENSOR_H_ */
diff --git a/drivers/media/video/zoran/videocodec.c b/drivers/media/video/zoran/videocodec.c
index cf24956f3204..c01071635290 100644
--- a/drivers/media/video/zoran/videocodec.c
+++ b/drivers/media/video/zoran/videocodec.c
@@ -107,15 +107,14 @@ videocodec_attach (struct videocodec_master *master)
if (!try_module_get(h->codec->owner))
return NULL;
- codec =
- kmalloc(sizeof(struct videocodec), GFP_KERNEL);
+ codec = kmemdup(h->codec, sizeof(struct videocodec),
+ GFP_KERNEL);
if (!codec) {
dprintk(1,
KERN_ERR
"videocodec_attach: no mem\n");
goto out_module_put;
}
- memcpy(codec, h->codec, sizeof(struct videocodec));
snprintf(codec->name, sizeof(codec->name),
"%s[%d]", codec->name, h->attached);
diff --git a/drivers/media/video/zoran/videocodec.h b/drivers/media/video/zoran/videocodec.h
index 5c27b251354e..b654bfff8740 100644
--- a/drivers/media/video/zoran/videocodec.h
+++ b/drivers/media/video/zoran/videocodec.h
@@ -56,7 +56,7 @@
the slave is bound to it). Otherwise it doesn't need this functions and
therfor they may not be initialized.
- The other fuctions are just for convenience, as they are for sure used by
+ The other functions are just for convenience, as they are for sure used by
most/all of the codecs. The last ones may be ommited, too.
See the structure declaration below for more information and which data has
diff --git a/drivers/media/video/zoran/zoran.h b/drivers/media/video/zoran/zoran.h
index 8997add1248e..4bb368e6fd47 100644
--- a/drivers/media/video/zoran/zoran.h
+++ b/drivers/media/video/zoran/zoran.h
@@ -33,15 +33,6 @@
#include <media/v4l2-device.h>
-#define ZORAN_VIDMODE_PAL 0
-#define ZORAN_VIDMODE_NTSC 1
-#define ZORAN_VIDMODE_SECAM 2
-
-struct zoran_requestbuffers {
- unsigned long count; /* Number of buffers for MJPEG grabbing */
- unsigned long size; /* Size PER BUFFER in bytes */
-};
-
struct zoran_sync {
unsigned long frame; /* number of buffer that has been free'd */
unsigned long length; /* number of code bytes in buffer (capture only) */
@@ -49,102 +40,6 @@ struct zoran_sync {
struct timeval timestamp; /* timestamp */
};
-struct zoran_status {
- int input; /* Input channel, has to be set prior to BUZIOC_G_STATUS */
- int signal; /* Returned: 1 if valid video signal detected */
- int norm; /* Returned: ZORAN_VIDMODE_PAL or ZORAN_VIDMODE_NTSC */
- int color; /* Returned: 1 if color signal detected */
-};
-
-struct zoran_params {
-
- /* The following parameters can only be queried */
-
- int major_version; /* Major version number of driver */
- int minor_version; /* Minor version number of driver */
-
- /* Main control parameters */
-
- int input; /* Input channel: 0 = Composite, 1 = S-VHS */
- int norm; /* Norm: ZORAN_VIDMODE_PAL or ZORAN_VIDMODE_NTSC */
- int decimation; /* decimation of captured video,
- * enlargement of video played back.
- * Valid values are 1, 2, 4 or 0.
- * 0 is a special value where the user
- * has full control over video scaling */
-
- /* The following parameters only have to be set if decimation==0,
- * for other values of decimation they provide the data how the image is captured */
-
- int HorDcm; /* Horizontal decimation: 1, 2 or 4 */
- int VerDcm; /* Vertical decimation: 1 or 2 */
- int TmpDcm; /* Temporal decimation: 1 or 2,
- * if TmpDcm==2 in capture every second frame is dropped,
- * in playback every frame is played twice */
- int field_per_buff; /* Number of fields per buffer: 1 or 2 */
- int img_x; /* start of image in x direction */
- int img_y; /* start of image in y direction */
- int img_width; /* image width BEFORE decimation,
- * must be a multiple of HorDcm*16 */
- int img_height; /* image height BEFORE decimation,
- * must be a multiple of VerDcm*8 */
-
- /* --- End of parameters for decimation==0 only --- */
-
- /* JPEG control parameters */
-
- int quality; /* Measure for quality of compressed images.
- * Scales linearly with the size of the compressed images.
- * Must be beetween 0 and 100, 100 is a compression
- * ratio of 1:4 */
-
- int odd_even; /* Which field should come first ??? */
-
- int APPn; /* Number of APP segment to be written, must be 0..15 */
- int APP_len; /* Length of data in JPEG APPn segment */
- char APP_data[60]; /* Data in the JPEG APPn segment. */
-
- int COM_len; /* Length of data in JPEG COM segment */
- char COM_data[60]; /* Data in JPEG COM segment */
-
- unsigned long jpeg_markers; /* Which markers should go into the JPEG output.
- * Unless you exactly know what you do, leave them untouched.
- * Inluding less markers will make the resulting code
- * smaller, but there will be fewer applications
- * which can read it.
- * The presence of the APP and COM marker is
- * influenced by APP0_len and COM_len ONLY! */
-#define JPEG_MARKER_DHT (1<<3) /* Define Huffman Tables */
-#define JPEG_MARKER_DQT (1<<4) /* Define Quantization Tables */
-#define JPEG_MARKER_DRI (1<<5) /* Define Restart Interval */
-#define JPEG_MARKER_COM (1<<6) /* Comment segment */
-#define JPEG_MARKER_APP (1<<7) /* App segment, driver will allways use APP0 */
-
- int VFIFO_FB; /* Flag for enabling Video Fifo Feedback.
- * If this flag is turned on and JPEG decompressing
- * is going to the screen, the decompress process
- * is stopped every time the Video Fifo is full.
- * This enables a smooth decompress to the screen
- * but the video output signal will get scrambled */
-
- /* Misc */
-
- char reserved[312]; /* Makes 512 bytes for this structure */
-};
-
-/*
-Private IOCTL to set up for displaying MJPEG
-*/
-#define BUZIOC_G_PARAMS _IOR ('v', BASE_VIDIOC_PRIVATE+0, struct zoran_params)
-#define BUZIOC_S_PARAMS _IOWR('v', BASE_VIDIOC_PRIVATE+1, struct zoran_params)
-#define BUZIOC_REQBUFS _IOWR('v', BASE_VIDIOC_PRIVATE+2, struct zoran_requestbuffers)
-#define BUZIOC_QBUF_CAPT _IOW ('v', BASE_VIDIOC_PRIVATE+3, int)
-#define BUZIOC_QBUF_PLAY _IOW ('v', BASE_VIDIOC_PRIVATE+4, int)
-#define BUZIOC_SYNC _IOR ('v', BASE_VIDIOC_PRIVATE+5, struct zoran_sync)
-#define BUZIOC_G_STATUS _IOWR('v', BASE_VIDIOC_PRIVATE+6, struct zoran_status)
-
-
-#ifdef __KERNEL__
#define MAJOR_VERSION 0 /* driver major version */
#define MINOR_VERSION 10 /* driver minor version */
@@ -341,10 +236,8 @@ struct card_info {
enum card_type type;
char name[32];
const char *i2c_decoder; /* i2c decoder device */
- const char *mod_decoder; /* i2c decoder module */
const unsigned short *addrs_decoder;
const char *i2c_encoder; /* i2c encoder device */
- const char *mod_encoder; /* i2c encoder module */
const unsigned short *addrs_encoder;
u16 video_vfe, video_codec; /* videocodec types */
u16 audio_chip; /* audio type */
@@ -390,8 +283,9 @@ struct zoran {
struct videocodec *vfe; /* video front end */
struct mutex resource_lock; /* prevent evil stuff */
+ struct mutex other_lock; /* please merge with above */
- u8 initialized; /* flag if zoran has been correctly initalized */
+ u8 initialized; /* flag if zoran has been correctly initialized */
int user; /* number of current users */
struct card_info card;
struct tvnorm *timing;
@@ -508,6 +402,4 @@ static inline struct zoran *to_zoran(struct v4l2_device *v4l2_dev)
#define btor(dat,adr) btwrite((dat) | btread(adr), adr)
#define btaor(dat,mask,adr) btwrite((dat) | ((mask) & btread(adr)), adr)
-#endif /* __kernel__ */
-
#endif
diff --git a/drivers/media/video/zoran/zoran_card.c b/drivers/media/video/zoran/zoran_card.c
index bfcd3aef50f9..9f2bac519647 100644
--- a/drivers/media/video/zoran/zoran_card.c
+++ b/drivers/media/video/zoran/zoran_card.c
@@ -379,7 +379,6 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC10_old,
.name = "DC10(old)",
.i2c_decoder = "vpx3220a",
- .mod_decoder = "vpx3220",
.addrs_decoder = vpx3220_addrs,
.video_codec = CODEC_TYPE_ZR36050,
.video_vfe = CODEC_TYPE_ZR36016,
@@ -409,10 +408,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC10_new,
.name = "DC10(new)",
.i2c_decoder = "saa7110",
- .mod_decoder = "saa7110",
.addrs_decoder = saa7110_addrs,
.i2c_encoder = "adv7175",
- .mod_encoder = "adv7175",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36060,
@@ -440,10 +437,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC10plus,
.name = "DC10plus",
.i2c_decoder = "saa7110",
- .mod_decoder = "saa7110",
.addrs_decoder = saa7110_addrs,
.i2c_encoder = "adv7175",
- .mod_encoder = "adv7175",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36060,
@@ -472,10 +467,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC30,
.name = "DC30",
.i2c_decoder = "vpx3220a",
- .mod_decoder = "vpx3220",
.addrs_decoder = vpx3220_addrs,
.i2c_encoder = "adv7175",
- .mod_encoder = "adv7175",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36050,
.video_vfe = CODEC_TYPE_ZR36016,
@@ -505,10 +498,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = DC30plus,
.name = "DC30plus",
.i2c_decoder = "vpx3220a",
- .mod_decoder = "vpx3220",
.addrs_decoder = vpx3220_addrs,
.i2c_encoder = "adv7175",
- .mod_encoder = "adv7175",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36050,
.video_vfe = CODEC_TYPE_ZR36016,
@@ -538,10 +529,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = LML33,
.name = "LML33",
.i2c_decoder = "bt819a",
- .mod_decoder = "bt819",
.addrs_decoder = bt819_addrs,
.i2c_encoder = "bt856",
- .mod_encoder = "bt856",
.addrs_encoder = bt856_addrs,
.video_codec = CODEC_TYPE_ZR36060,
@@ -569,10 +558,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = LML33R10,
.name = "LML33R10",
.i2c_decoder = "saa7114",
- .mod_decoder = "saa7115",
.addrs_decoder = saa7114_addrs,
.i2c_encoder = "adv7170",
- .mod_encoder = "adv7170",
.addrs_encoder = adv717x_addrs,
.video_codec = CODEC_TYPE_ZR36060,
@@ -600,10 +587,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
.type = BUZ,
.name = "Buz",
.i2c_decoder = "saa7111",
- .mod_decoder = "saa7115",
.addrs_decoder = saa7111_addrs,
.i2c_encoder = "saa7185",
- .mod_encoder = "saa7185",
.addrs_encoder = saa7185_addrs,
.video_codec = CODEC_TYPE_ZR36060,
@@ -633,10 +618,8 @@ static struct card_info zoran_cards[NUM_CARDS] __devinitdata = {
/* AverMedia chose not to brand the 6-Eyes. Thus it
can't be autodetected, and requires card=x. */
.i2c_decoder = "ks0127",
- .mod_decoder = "ks0127",
.addrs_decoder = ks0127_addrs,
.i2c_encoder = "bt866",
- .mod_encoder = "bt866",
.addrs_encoder = bt866_addrs,
.video_codec = CODEC_TYPE_ZR36060,
@@ -960,7 +943,7 @@ zoran_open_init_params (struct zoran *zr)
memset(zr->jpg_settings.jpg_comp.COM_data, 0,
sizeof(zr->jpg_settings.jpg_comp.COM_data));
zr->jpg_settings.jpg_comp.jpeg_markers =
- JPEG_MARKER_DHT | JPEG_MARKER_DQT;
+ V4L2_JPEG_MARKER_DHT | V4L2_JPEG_MARKER_DQT;
i = zoran_check_jpg_settings(zr, &zr->jpg_settings, 0);
if (i)
dprintk(1, KERN_ERR "%s: %s internal error\n",
@@ -1058,7 +1041,7 @@ zr36057_init (struct zoran *zr)
/* allocate memory *before* doing anything to the hardware
* in case allocation fails */
zr->stat_com = kzalloc(BUZ_NUM_STAT_COM * 4, GFP_KERNEL);
- zr->video_dev = kmalloc(sizeof(struct video_device), GFP_KERNEL);
+ zr->video_dev = video_device_alloc();
if (!zr->stat_com || !zr->video_dev) {
dprintk(1,
KERN_ERR
@@ -1244,6 +1227,7 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
snprintf(ZR_DEVNAME(zr), sizeof(ZR_DEVNAME(zr)), "MJPEG[%u]", zr->id);
spin_lock_init(&zr->spinlock);
mutex_init(&zr->resource_lock);
+ mutex_init(&zr->other_lock);
if (pci_enable_device(pdev))
goto zr_unreg;
pci_read_config_byte(zr->pci_dev, PCI_CLASS_REVISION, &zr->revision);
@@ -1359,13 +1343,12 @@ static int __devinit zoran_probe(struct pci_dev *pdev,
}
zr->decoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
- &zr->i2c_adapter, zr->card.mod_decoder, zr->card.i2c_decoder,
+ &zr->i2c_adapter, zr->card.i2c_decoder,
0, zr->card.addrs_decoder);
- if (zr->card.mod_encoder)
+ if (zr->card.i2c_encoder)
zr->encoder = v4l2_i2c_new_subdev(&zr->v4l2_dev,
- &zr->i2c_adapter,
- zr->card.mod_encoder, zr->card.i2c_encoder,
+ &zr->i2c_adapter, zr->card.i2c_encoder,
0, zr->card.addrs_encoder);
dprintk(2,
diff --git a/drivers/media/video/zoran/zoran_device.c b/drivers/media/video/zoran/zoran_device.c
index e6ad4b205611..e8a27844bf39 100644
--- a/drivers/media/video/zoran/zoran_device.c
+++ b/drivers/media/video/zoran/zoran_device.c
@@ -484,7 +484,7 @@ zr36057_overlay (struct zoran *zr,
zr->overlay_settings.format);
/* Start and length of each line MUST be 4-byte aligned.
- * This should be allready checked before the call to this routine.
+ * This should be already checked before the call to this routine.
* All error messages are internal driver checking only! */
/* video display top and bottom registers */
@@ -1470,8 +1470,7 @@ zoran_irq (int irq,
(zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS ||
zr->codec_mode == BUZ_MODE_MOTION_COMPRESS)) {
if (zr36067_debug > 1 && (!zr->frame_num || zr->JPEG_error)) {
- char sc[] = "0000";
- char sv[5];
+ char sv[BUZ_NUM_STAT_COM + 1];
int i;
printk(KERN_INFO
@@ -1481,12 +1480,9 @@ zoran_irq (int irq,
zr->jpg_settings.field_per_buff,
zr->JPEG_missed);
- strcpy(sv, sc);
- for (i = 0; i < 4; i++) {
- if (le32_to_cpu(zr->stat_com[i]) & 1)
- sv[i] = '1';
- }
- sv[4] = 0;
+ for (i = 0; i < BUZ_NUM_STAT_COM; i++)
+ sv[i] = le32_to_cpu(zr->stat_com[i]) & 1 ? '1' : '0';
+ sv[BUZ_NUM_STAT_COM] = 0;
printk(KERN_INFO
"%s: stat_com=%s queue_state=%ld/%ld/%ld/%ld\n",
ZR_DEVNAME(zr), sv,
@@ -1527,7 +1523,7 @@ zoran_irq (int irq,
zr->JPEG_missed > 25 ||
zr->JPEG_error == 1 ||
((zr->codec_mode == BUZ_MODE_MOTION_DECOMPRESS) &&
- (zr->frame_num & (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) {
+ (zr->frame_num && (zr->JPEG_missed > zr->jpg_settings.field_per_buff)))) {
error_handler(zr, astat, stat);
}
diff --git a/drivers/media/video/zoran/zoran_driver.c b/drivers/media/video/zoran/zoran_driver.c
index 6f89d0a096ea..7c3921de9589 100644
--- a/drivers/media/video/zoran/zoran_driver.c
+++ b/drivers/media/video/zoran/zoran_driver.c
@@ -49,7 +49,6 @@
#include <linux/module.h>
#include <linux/delay.h>
#include <linux/slab.h>
-#include <linux/smp_lock.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/wait.h>
@@ -913,7 +912,7 @@ static int zoran_open(struct file *file)
dprintk(2, KERN_INFO "%s: %s(%s, pid=[%d]), users(-)=%d\n",
ZR_DEVNAME(zr), __func__, current->comm, task_pid_nr(current), zr->user + 1);
- lock_kernel();
+ mutex_lock(&zr->other_lock);
if (zr->user >= 2048) {
dprintk(1, KERN_ERR "%s: too many users (%d) on device\n",
@@ -963,14 +962,14 @@ static int zoran_open(struct file *file)
file->private_data = fh;
fh->zr = zr;
zoran_open_init_session(fh);
- unlock_kernel();
+ mutex_unlock(&zr->other_lock);
return 0;
fail_fh:
kfree(fh);
fail_unlock:
- unlock_kernel();
+ mutex_unlock(&zr->other_lock);
dprintk(2, KERN_INFO "%s: open failed (%d), users(-)=%d\n",
ZR_DEVNAME(zr), res, zr->user);
@@ -989,7 +988,7 @@ zoran_close(struct file *file)
/* kernel locks (fs/device.c), so don't do that ourselves
* (prevents deadlocks) */
- /*mutex_lock(&zr->resource_lock);*/
+ mutex_lock(&zr->other_lock);
zoran_close_end_session(fh);
@@ -1023,6 +1022,7 @@ zoran_close(struct file *file)
encoder_call(zr, video, s_routing, 2, 0, 0);
}
}
+ mutex_unlock(&zr->other_lock);
file->private_data = NULL;
kfree(fh->overlay_mask);
@@ -1177,7 +1177,7 @@ static int setup_window(struct zoran_fh *fh, int x, int y, int width, int height
if (height > BUZ_MAX_HEIGHT)
height = BUZ_MAX_HEIGHT;
- /* Check for vaild parameters */
+ /* Check for invalid parameters */
if (width < BUZ_MIN_WIDTH || height < BUZ_MIN_HEIGHT ||
width > BUZ_MAX_WIDTH || height > BUZ_MAX_HEIGHT) {
dprintk(1,
@@ -1528,323 +1528,6 @@ zoran_set_input (struct zoran *zr,
* ioctl routine
*/
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
-static long zoran_default(struct file *file, void *__fh, int cmd, void *arg)
-{
- struct zoran_fh *fh = __fh;
- struct zoran *zr = fh->zr;
- struct zoran_jpg_settings settings;
-
- switch (cmd) {
- case BUZIOC_G_PARAMS:
- {
- struct zoran_params *bparams = arg;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_G_PARAMS\n", ZR_DEVNAME(zr));
-
- memset(bparams, 0, sizeof(struct zoran_params));
- bparams->major_version = MAJOR_VERSION;
- bparams->minor_version = MINOR_VERSION;
-
- mutex_lock(&zr->resource_lock);
-
- if (zr->norm & V4L2_STD_NTSC)
- bparams->norm = ZORAN_VIDMODE_NTSC;
- else if (zr->norm & V4L2_STD_SECAM)
- bparams->norm = ZORAN_VIDMODE_SECAM;
- else
- bparams->norm = ZORAN_VIDMODE_PAL;
-
- bparams->input = zr->input;
-
- bparams->decimation = fh->jpg_settings.decimation;
- bparams->HorDcm = fh->jpg_settings.HorDcm;
- bparams->VerDcm = fh->jpg_settings.VerDcm;
- bparams->TmpDcm = fh->jpg_settings.TmpDcm;
- bparams->field_per_buff = fh->jpg_settings.field_per_buff;
- bparams->img_x = fh->jpg_settings.img_x;
- bparams->img_y = fh->jpg_settings.img_y;
- bparams->img_width = fh->jpg_settings.img_width;
- bparams->img_height = fh->jpg_settings.img_height;
- bparams->odd_even = fh->jpg_settings.odd_even;
-
- bparams->quality = fh->jpg_settings.jpg_comp.quality;
- bparams->APPn = fh->jpg_settings.jpg_comp.APPn;
- bparams->APP_len = fh->jpg_settings.jpg_comp.APP_len;
- memcpy(bparams->APP_data,
- fh->jpg_settings.jpg_comp.APP_data,
- sizeof(bparams->APP_data));
- bparams->COM_len = zr->jpg_settings.jpg_comp.COM_len;
- memcpy(bparams->COM_data,
- fh->jpg_settings.jpg_comp.COM_data,
- sizeof(bparams->COM_data));
- bparams->jpeg_markers =
- fh->jpg_settings.jpg_comp.jpeg_markers;
-
- mutex_unlock(&zr->resource_lock);
-
- bparams->VFIFO_FB = 0;
-
- return 0;
- }
-
- case BUZIOC_S_PARAMS:
- {
- struct zoran_params *bparams = arg;
- int res = 0;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_S_PARAMS\n", ZR_DEVNAME(zr));
-
- settings.decimation = bparams->decimation;
- settings.HorDcm = bparams->HorDcm;
- settings.VerDcm = bparams->VerDcm;
- settings.TmpDcm = bparams->TmpDcm;
- settings.field_per_buff = bparams->field_per_buff;
- settings.img_x = bparams->img_x;
- settings.img_y = bparams->img_y;
- settings.img_width = bparams->img_width;
- settings.img_height = bparams->img_height;
- settings.odd_even = bparams->odd_even;
-
- settings.jpg_comp.quality = bparams->quality;
- settings.jpg_comp.APPn = bparams->APPn;
- settings.jpg_comp.APP_len = bparams->APP_len;
- memcpy(settings.jpg_comp.APP_data, bparams->APP_data,
- sizeof(bparams->APP_data));
- settings.jpg_comp.COM_len = bparams->COM_len;
- memcpy(settings.jpg_comp.COM_data, bparams->COM_data,
- sizeof(bparams->COM_data));
- settings.jpg_comp.jpeg_markers = bparams->jpeg_markers;
-
- mutex_lock(&zr->resource_lock);
-
- if (zr->codec_mode != BUZ_MODE_IDLE) {
- dprintk(1,
- KERN_ERR
- "%s: BUZIOC_S_PARAMS called, but Buz in capture/playback mode\n",
- ZR_DEVNAME(zr));
- res = -EINVAL;
- goto sparams_unlock_and_return;
- }
-
- /* Check the params first before overwriting our
- * nternal values */
- if (zoran_check_jpg_settings(zr, &settings, 0)) {
- res = -EINVAL;
- goto sparams_unlock_and_return;
- }
-
- fh->jpg_settings = settings;
-sparams_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_REQBUFS:
- {
- struct zoran_requestbuffers *breq = arg;
- int res = 0;
-
- dprintk(3,
- KERN_DEBUG
- "%s: BUZIOC_REQBUFS - count=%lu, size=%lu\n",
- ZR_DEVNAME(zr), breq->count, breq->size);
-
- /* Enforce reasonable lower and upper limits */
- if (breq->count < 4)
- breq->count = 4; /* Could be choosen smaller */
- if (breq->count > jpg_nbufs)
- breq->count = jpg_nbufs;
- breq->size = PAGE_ALIGN(breq->size);
- if (breq->size < 8192)
- breq->size = 8192; /* Arbitrary */
- /* breq->size is limited by 1 page for the stat_com
- * tables to a Maximum of 2 MB */
- if (breq->size > jpg_bufsize)
- breq->size = jpg_bufsize;
-
- mutex_lock(&zr->resource_lock);
-
- if (fh->buffers.allocated) {
- dprintk(1,
- KERN_ERR
- "%s: BUZIOC_REQBUFS - buffers already allocated\n",
- ZR_DEVNAME(zr));
- res = -EBUSY;
- goto jpgreqbuf_unlock_and_return;
- }
-
- /* The next mmap will map the MJPEG buffers - could
- * also be *_PLAY, but it doesn't matter here */
- map_mode_jpg(fh, 0);
- fh->buffers.num_buffers = breq->count;
- fh->buffers.buffer_size = breq->size;
-
- if (jpg_fbuffer_alloc(fh)) {
- res = -ENOMEM;
- goto jpgreqbuf_unlock_and_return;
- }
-
-jpgreqbuf_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_QBUF_CAPT:
- {
- int *frame = arg, res;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_CAPT - frame=%d\n",
- ZR_DEVNAME(zr), *frame);
-
- mutex_lock(&zr->resource_lock);
- res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_COMPRESS);
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_QBUF_PLAY:
- {
- int *frame = arg, res;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_QBUF_PLAY - frame=%d\n",
- ZR_DEVNAME(zr), *frame);
-
- mutex_lock(&zr->resource_lock);
- res = jpg_qbuf(fh, *frame, BUZ_MODE_MOTION_DECOMPRESS);
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_SYNC:
- {
- struct zoran_sync *bsync = arg;
- int res;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_SYNC\n", ZR_DEVNAME(zr));
-
- mutex_lock(&zr->resource_lock);
-
- if (fh->map_mode == ZORAN_MAP_MODE_RAW) {
- dprintk(2, KERN_WARNING
- "%s: %s - not in jpg capture mode\n",
- ZR_DEVNAME(zr), __func__);
- res = -EINVAL;
- } else {
- res = jpg_sync(fh, bsync);
- }
- mutex_unlock(&zr->resource_lock);
-
- return res;
- }
-
- case BUZIOC_G_STATUS:
- {
- struct zoran_status *bstat = arg;
- int status = 0, res = 0;
- v4l2_std_id norm;
-
- dprintk(3, KERN_DEBUG "%s: BUZIOC_G_STATUS\n", ZR_DEVNAME(zr));
-
- if (zr->codec_mode != BUZ_MODE_IDLE) {
- dprintk(1,
- KERN_ERR
- "%s: BUZIOC_G_STATUS called but Buz in capture/playback mode\n",
- ZR_DEVNAME(zr));
- return -EINVAL;
- }
-
- mutex_lock(&zr->resource_lock);
-
- if (zr->codec_mode != BUZ_MODE_IDLE) {
- dprintk(1,
- KERN_ERR
- "%s: BUZIOC_G_STATUS called, but Buz in capture/playback mode\n",
- ZR_DEVNAME(zr));
- res = -EINVAL;
- goto gstat_unlock_and_return;
- }
-
- decoder_call(zr, video, s_routing,
- zr->card.input[bstat->input].muxsel, 0, 0);
-
- /* sleep 1 second */
- ssleep(1);
-
- /* Get status of video decoder */
- decoder_call(zr, video, querystd, &norm);
- decoder_call(zr, video, g_input_status, &status);
-
- /* restore previous input and norm */
- decoder_call(zr, video, s_routing,
- zr->card.input[zr->input].muxsel, 0, 0);
-gstat_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- if (!res) {
- bstat->signal =
- (status & V4L2_IN_ST_NO_SIGNAL) ? 0 : 1;
- if (norm & V4L2_STD_NTSC)
- bstat->norm = ZORAN_VIDMODE_NTSC;
- else if (norm & V4L2_STD_SECAM)
- bstat->norm = ZORAN_VIDMODE_SECAM;
- else
- bstat->norm = ZORAN_VIDMODE_PAL;
-
- bstat->color =
- (status & V4L2_IN_ST_NO_COLOR) ? 0 : 1;
- }
-
- return res;
- }
-
- default:
- return -EINVAL;
- }
-}
-
-static int zoran_vidiocgmbuf(struct file *file, void *__fh, struct video_mbuf *vmbuf)
-{
- struct zoran_fh *fh = __fh;
- struct zoran *zr = fh->zr;
- int i, res = 0;
-
-
- mutex_lock(&zr->resource_lock);
-
- if (fh->buffers.allocated) {
- dprintk(1,
- KERN_ERR
- "%s: VIDIOCGMBUF - buffers already allocated\n",
- ZR_DEVNAME(zr));
- res = -EINVAL;
- goto v4l1reqbuf_unlock_and_return;
- }
-
- /* The next mmap will map the V4L buffers */
- map_mode_raw(fh);
-
- if (v4l_fbuffer_alloc(fh)) {
- res = -ENOMEM;
- goto v4l1reqbuf_unlock_and_return;
- }
-
- vmbuf->size = fh->buffers.num_buffers * fh->buffers.buffer_size;
- vmbuf->frames = fh->buffers.num_buffers;
- for (i = 0; i < vmbuf->frames; i++)
- vmbuf->offsets[i] = i * fh->buffers.buffer_size;
-
-v4l1reqbuf_unlock_and_return:
- mutex_unlock(&zr->resource_lock);
-
- return res;
-}
-#endif
-
static int zoran_querycap(struct file *file, void *__fh, struct v4l2_capability *cap)
{
struct zoran_fh *fh = __fh;
@@ -2533,6 +2216,7 @@ static int zoran_dqbuf(struct file *file, void *__fh, struct v4l2_buffer *buf)
res = -EAGAIN;
goto dqbuf_unlock_and_return;
}
+ bs.frame = 0; /* suppress compiler warning */
res = jpg_sync(fh, &bs);
if (res)
goto dqbuf_unlock_and_return;
@@ -2766,11 +2450,6 @@ static int zoran_enum_input(struct file *file, void *__fh,
if (inp->index >= zr->card.inputs)
return -EINVAL;
- else {
- int id = inp->index;
- memset(inp, 0, sizeof(*inp));
- inp->index = id;
- }
strncpy(inp->name, zr->card.input[inp->index].name,
sizeof(inp->name) - 1);
@@ -2820,7 +2499,6 @@ static int zoran_enum_output(struct file *file, void *__fh,
if (outp->index != 0)
return -EINVAL;
- memset(outp, 0, sizeof(*outp));
outp->index = 0;
outp->type = V4L2_OUTPUT_TYPE_ANALOGVGAOVERLAY;
strncpy(outp->name, "Autodetect", sizeof(outp->name)-1);
@@ -3322,7 +3000,7 @@ zoran_mmap (struct file *file,
mmap_unlock_and_return:
mutex_unlock(&zr->resource_lock);
- return 0;
+ return res;
}
static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
@@ -3364,17 +3042,28 @@ static const struct v4l2_ioctl_ops zoran_ioctl_ops = {
.vidioc_queryctrl = zoran_queryctrl,
.vidioc_s_ctrl = zoran_s_ctrl,
.vidioc_g_ctrl = zoran_g_ctrl,
-#ifdef CONFIG_VIDEO_V4L1_COMPAT
- .vidioc_default = zoran_default,
- .vidiocgmbuf = zoran_vidiocgmbuf,
-#endif
};
+/* please use zr->resource_lock consistently and kill this wrapper */
+static long zoran_ioctl(struct file *file, unsigned int cmd,
+ unsigned long arg)
+{
+ struct zoran_fh *fh = file->private_data;
+ struct zoran *zr = fh->zr;
+ int ret;
+
+ mutex_lock(&zr->other_lock);
+ ret = video_ioctl2(file, cmd, arg);
+ mutex_unlock(&zr->other_lock);
+
+ return ret;
+}
+
static const struct v4l2_file_operations zoran_fops = {
.owner = THIS_MODULE,
.open = zoran_open,
.release = zoran_close,
- .ioctl = video_ioctl2,
+ .unlocked_ioctl = zoran_ioctl,
.read = zoran_read,
.write = zoran_write,
.mmap = zoran_mmap,
diff --git a/drivers/media/video/zoran/zr36050.c b/drivers/media/video/zoran/zr36050.c
index 639dd87c663f..e1985609af4b 100644
--- a/drivers/media/video/zoran/zr36050.c
+++ b/drivers/media/video/zoran/zr36050.c
@@ -236,7 +236,7 @@ zr36050_pushit (struct zr36050 *ptr,
Could be variable, but until it's not needed it they are just fixed to save
memory. Otherwise expand zr36050 structure with arrays, push the values to
- it and initalize from there, as e.g. the linux zr36057/60 driver does it.
+ it and initialize from there, as e.g. the linux zr36057/60 driver does it.
========================================================================= */
static const char zr36050_dqt[0x86] = {
diff --git a/drivers/media/video/zoran/zr36060.c b/drivers/media/video/zoran/zr36060.c
index 008746ff7746..5e4f57cbf314 100644
--- a/drivers/media/video/zoran/zr36060.c
+++ b/drivers/media/video/zoran/zr36060.c
@@ -227,7 +227,7 @@ zr36060_pushit (struct zr36060 *ptr,
Could be variable, but until it's not needed it they are just fixed to save
memory. Otherwise expand zr36060 structure with arrays, push the values to
- it and initalize from there, as e.g. the linux zr36057/60 driver does it.
+ it and initialize from there, as e.g. the linux zr36057/60 driver does it.
========================================================================= */
static const char zr36060_dqt[0x86] = {
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index a82b5bd18d26..7dfb01e9930e 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -572,7 +572,7 @@ static int zr364xx_got_frame(struct zr364xx_camera *cam, int jpgsize)
DBG("wakeup [buf/i] [%p/%d]\n", buf, buf->vb.i);
unlock:
spin_unlock_irqrestore(&cam->slock, flags);
- return 0;
+ return rc;
}
/* this function moves the usb stream read pipe data
@@ -1304,7 +1304,7 @@ static int zr364xx_open(struct file *file)
NULL, &cam->slock,
cam->type,
V4L2_FIELD_NONE,
- sizeof(struct zr364xx_buffer), cam);
+ sizeof(struct zr364xx_buffer), cam, NULL);
/* Added some delay here, since opening/closing the camera quickly,
* like Ekiga does during its startup, can crash the webcam