summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorStephen Rothwell <sfr@canb.auug.org.au>2008-04-15 13:49:50 +1000
committerStephen Rothwell <sfr@canb.auug.org.au>2008-04-15 13:49:50 +1000
commit22c366d5188546549074a33e427384ffbe30cd9f (patch)
tree18169a360609e7c197ced9d2ebaf35a7fc3050b7
parent8b09eea5d215b81f686e52407e411b469d59773b (diff)
parentb598438043938144e95d9f5e2a0ca2adaaf63ec7 (diff)
Merge commit 'v4l-dvb/stable'
-rw-r--r--Documentation/video4linux/CARDLIST.bttv2
-rw-r--r--Documentation/video4linux/CARDLIST.cx889
-rw-r--r--Documentation/video4linux/CARDLIST.saa71349
-rw-r--r--arch/arm/mach-pxa/devices.c32
-rw-r--r--arch/arm/mach-pxa/pcm990-baseboard.c86
-rw-r--r--drivers/media/Kconfig2
-rw-r--r--drivers/media/common/ir-functions.c2
-rw-r--r--drivers/media/common/ir-keymaps.c96
-rw-r--r--drivers/media/common/saa7146_vbi.c4
-rw-r--r--drivers/media/common/saa7146_video.c4
-rw-r--r--drivers/media/dvb/b2c2/Kconfig1
-rw-r--r--drivers/media/dvb/b2c2/Makefile1
-rw-r--r--drivers/media/dvb/b2c2/flexcop-common.h17
-rw-r--r--drivers/media/dvb/b2c2/flexcop-eeprom.c9
-rw-r--r--drivers/media/dvb/b2c2/flexcop-fe-tuner.c113
-rw-r--r--drivers/media/dvb/b2c2/flexcop-i2c.c180
-rw-r--r--drivers/media/dvb/b2c2/flexcop-pci.c2
-rw-r--r--drivers/media/dvb/b2c2/flexcop-usb.c17
-rw-r--r--drivers/media/dvb/b2c2/flexcop.c10
-rw-r--r--drivers/media/dvb/bt8xx/Kconfig2
-rw-r--r--drivers/media/dvb/bt8xx/Makefile5
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.c14
-rw-r--r--drivers/media/dvb/bt8xx/dvb-bt8xx.h2
-rw-r--r--drivers/media/dvb/dvb-core/demux.h2
-rw-r--r--drivers/media/dvb/dvb-core/dmxdev.c10
-rw-r--r--drivers/media/dvb/dvb-core/dvb_demux.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvb_net.c2
-rw-r--r--drivers/media/dvb/dvb-core/dvbdev.c2
-rw-r--r--drivers/media/dvb/dvb-usb/Kconfig1
-rw-r--r--drivers/media/dvb/dvb-usb/cxusb.c13
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700.h4
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_core.c4
-rw-r--r--drivers/media/dvb/dvb-usb/dib0700_devices.c325
-rw-r--r--drivers/media/dvb/dvb-usb/dvb-usb-ids.h13
-rw-r--r--drivers/media/dvb/dvb-usb/ttusb2.c62
-rw-r--r--drivers/media/dvb/frontends/Kconfig7
-rw-r--r--drivers/media/dvb/frontends/Makefile1
-rw-r--r--drivers/media/dvb/frontends/cx22702.c2
-rw-r--r--drivers/media/dvb/frontends/cx24123.c304
-rw-r--r--drivers/media/dvb/frontends/cx24123.h21
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.c260
-rw-r--r--drivers/media/dvb/frontends/dvb-pll.h31
-rw-r--r--drivers/media/dvb/frontends/isl6405.c164
-rw-r--r--drivers/media/dvb/frontends/isl6405.h74
-rw-r--r--drivers/media/dvb/frontends/lgdt330x.c2
-rw-r--r--drivers/media/dvb/frontends/nxt6000.c2
-rw-r--r--drivers/media/dvb/frontends/s5h1409.c2
-rw-r--r--drivers/media/dvb/frontends/s5h1420.c2
-rw-r--r--drivers/media/dvb/frontends/sp8870.c12
-rw-r--r--drivers/media/dvb/frontends/tda1004x.h1
-rw-r--r--drivers/media/dvb/frontends/tda10086.c2
-rw-r--r--drivers/media/dvb/frontends/tda18271-common.c57
-rw-r--r--drivers/media/dvb/frontends/tda18271-fe.c418
-rw-r--r--drivers/media/dvb/frontends/tda18271-priv.h16
-rw-r--r--drivers/media/dvb/frontends/tda18271-tables.c84
-rw-r--r--drivers/media/dvb/frontends/tda18271.h23
-rw-r--r--drivers/media/dvb/frontends/tda826x.c2
-rw-r--r--drivers/media/dvb/frontends/tda827x.c167
-rw-r--r--drivers/media/dvb/frontends/tda827x.h4
-rw-r--r--drivers/media/dvb/frontends/ves1x93.c2
-rw-r--r--drivers/media/dvb/frontends/xc5000.c2
-rw-r--r--drivers/media/dvb/frontends/zl10353.c2
-rw-r--r--drivers/media/dvb/ttpci/budget-ci.c2
-rw-r--r--drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c4
-rw-r--r--drivers/media/radio/dsbr100.c2
-rw-r--r--drivers/media/radio/miropcm20-radio.c2
-rw-r--r--drivers/media/radio/miropcm20-rds.c2
-rw-r--r--drivers/media/radio/radio-aimslab.c2
-rw-r--r--drivers/media/radio/radio-aztech.c2
-rw-r--r--drivers/media/radio/radio-cadet.c12
-rw-r--r--drivers/media/radio/radio-gemtek-pci.c2
-rw-r--r--drivers/media/radio/radio-gemtek.c2
-rw-r--r--drivers/media/radio/radio-maestro.c2
-rw-r--r--drivers/media/radio/radio-maxiradio.c2
-rw-r--r--drivers/media/radio/radio-rtrack2.c2
-rw-r--r--drivers/media/radio/radio-sf16fmi.c2
-rw-r--r--drivers/media/radio/radio-sf16fmr2.c104
-rw-r--r--drivers/media/radio/radio-si470x.c59
-rw-r--r--drivers/media/radio/radio-terratec.c2
-rw-r--r--drivers/media/radio/radio-trust.c2
-rw-r--r--drivers/media/radio/radio-typhoon.c4
-rw-r--r--drivers/media/radio/radio-zoltrix.c2
-rw-r--r--drivers/media/video/Kconfig45
-rw-r--r--drivers/media/video/Makefile9
-rw-r--r--drivers/media/video/adv7170.c2
-rw-r--r--drivers/media/video/adv7175.c2
-rw-r--r--drivers/media/video/arv.c6
-rw-r--r--drivers/media/video/bt819.c2
-rw-r--r--drivers/media/video/bt856.c2
-rw-r--r--drivers/media/video/bt8xx/bttv-cards.c55
-rw-r--r--drivers/media/video/bt8xx/bttv-driver.c33
-rw-r--r--drivers/media/video/bt8xx/bttv-input.c6
-rw-r--r--drivers/media/video/bt8xx/bttv-vbi.c2
-rw-r--r--drivers/media/video/bt8xx/bttv.h3
-rw-r--r--drivers/media/video/bt8xx/bttvp.h1
-rw-r--r--drivers/media/video/bw-qcam.c6
-rw-r--r--drivers/media/video/c-qcam.c6
-rw-r--r--drivers/media/video/cafe_ccic.c4
-rw-r--r--drivers/media/video/cpia.c2
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c4
-rw-r--r--drivers/media/video/cpia2/cpia2_usb.c2
-rw-r--r--drivers/media/video/cpia2/cpia2_v4l.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c15
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c2
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c4
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c91
-rw-r--r--drivers/media/video/cx25840/cx25840-core.h2
-rw-r--r--drivers/media/video/cx25840/cx25840-firmware.c11
-rw-r--r--drivers/media/video/cx25840/cx25840-vbi.c6
-rw-r--r--drivers/media/video/cx88/Kconfig1
-rw-r--r--drivers/media/video/cx88/cx88-alsa.c8
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c10
-rw-r--r--drivers/media/video/cx88/cx88-cards.c581
-rw-r--r--drivers/media/video/cx88/cx88-core.c13
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c245
-rw-r--r--drivers/media/video/cx88/cx88-i2c.c4
-rw-r--r--drivers/media/video/cx88/cx88-input.c15
-rw-r--r--drivers/media/video/cx88/cx88-mpeg.c4
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c6
-rw-r--r--drivers/media/video/cx88/cx88-vbi.c2
-rw-r--r--drivers/media/video/cx88/cx88-video.c63
-rw-r--r--drivers/media/video/cx88/cx88.h14
-rw-r--r--drivers/media/video/dabfirmware.h7
-rw-r--r--drivers/media/video/dabusb.c8
-rw-r--r--drivers/media/video/dpc7146.c4
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c24
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c4
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c2
-rw-r--r--drivers/media/video/et61x251/et61x251_core.c4
-rw-r--r--drivers/media/video/hexium_gemini.c4
-rw-r--r--drivers/media/video/hexium_orion.c4
-rw-r--r--drivers/media/video/ir-kbd-i2c.c26
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.c7
-rw-r--r--drivers/media/video/ivtv/ivtv-cards.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.c44
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c2
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c36
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c25
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c38
-rw-r--r--drivers/media/video/meye.c14
-rw-r--r--drivers/media/video/msp3400-kthreads.c15
-rw-r--r--drivers/media/video/mt20xx.c7
-rw-r--r--drivers/media/video/mt9m001.c722
-rw-r--r--drivers/media/video/mt9v022.c844
-rw-r--r--drivers/media/video/mxb.c4
-rw-r--r--drivers/media/video/ov511.c2
-rw-r--r--drivers/media/video/pms.c6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c116
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.h8
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c19
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debug.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c52
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.h57
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c10
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h9
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h20
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c394
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h23
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c9
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c186
-rw-r--r--drivers/media/video/pwc/pwc-if.c10
-rw-r--r--drivers/media/video/pxa_camera.c1000
-rw-r--r--drivers/media/video/saa5249.c2
-rw-r--r--drivers/media/video/saa6588.c8
-rw-r--r--drivers/media/video/saa7110.c2
-rw-r--r--drivers/media/video/saa7111.c2
-rw-r--r--drivers/media/video/saa7114.c2
-rw-r--r--drivers/media/video/saa7115.c4
-rw-r--r--drivers/media/video/saa711x.c2
-rw-r--r--drivers/media/video/saa7134/Kconfig1
-rw-r--r--drivers/media/video/saa7134/saa7134-alsa.c12
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c427
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c52
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c418
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c4
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-reg.h3
-rw-r--r--drivers/media/video/saa7134/saa7134-ts.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-tvaudio.c21
-rw-r--r--drivers/media/video/saa7134/saa7134-vbi.c2
-rw-r--r--drivers/media/video/saa7134/saa7134-video.c17
-rw-r--r--drivers/media/video/saa7134/saa7134.h22
-rw-r--r--drivers/media/video/saa7185.c2
-rw-r--r--drivers/media/video/se401.c6
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c12
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h5
-rw-r--r--drivers/media/video/soc_camera.c1033
-rw-r--r--drivers/media/video/stk-webcam.c4
-rw-r--r--drivers/media/video/stradis.c6
-rw-r--r--drivers/media/video/stv680.c11
-rw-r--r--drivers/media/video/tda8290.c12
-rw-r--r--drivers/media/video/tda8290.h2
-rw-r--r--drivers/media/video/tda9840.c2
-rw-r--r--drivers/media/video/tda9887.c42
-rw-r--r--drivers/media/video/tea5761.c7
-rw-r--r--drivers/media/video/tea5767.c34
-rw-r--r--drivers/media/video/tea6415c.c2
-rw-r--r--drivers/media/video/tea6420.c2
-rw-r--r--drivers/media/video/tuner-core.c47
-rw-r--r--drivers/media/video/tuner-i2c.h118
-rw-r--r--drivers/media/video/tuner-simple.c861
-rw-r--r--drivers/media/video/tuner-simple.h11
-rw-r--r--drivers/media/video/tuner-types.c188
-rw-r--r--drivers/media/video/tuner-xc2028.c57
-rw-r--r--drivers/media/video/tvaudio.c8
-rw-r--r--drivers/media/video/tveeprom.c103
-rw-r--r--drivers/media/video/tvp5150.c2
-rw-r--r--drivers/media/video/usbvideo/ibmcam.c2
-rw-r--r--drivers/media/video/usbvideo/konicawc.c2
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c2
-rw-r--r--drivers/media/video/usbvideo/ultracam.c4
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c8
-rw-r--r--drivers/media/video/usbvideo/vicam.c2
-rw-r--r--drivers/media/video/usbvision/usbvision-core.c45
-rw-r--r--drivers/media/video/usbvision/usbvision-i2c.c8
-rw-r--r--drivers/media/video/usbvision/usbvision-video.c46
-rw-r--r--drivers/media/video/v4l1-compat.c1737
-rw-r--r--drivers/media/video/videobuf-core.c168
-rw-r--r--drivers/media/video/videobuf-dma-sg.c137
-rw-r--r--drivers/media/video/videobuf-dvb.c2
-rw-r--r--drivers/media/video/videobuf-vmalloc.c49
-rw-r--r--drivers/media/video/videocodec.c4
-rw-r--r--drivers/media/video/vino.c10
-rw-r--r--drivers/media/video/vivi.c334
-rw-r--r--drivers/media/video/vpx3220.c2
-rw-r--r--drivers/media/video/w9966.c6
-rw-r--r--drivers/media/video/w9968cf.c4
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c4
-rw-r--r--drivers/media/video/zoran_card.c6
-rw-r--r--drivers/media/video/zoran_card.h2
-rw-r--r--drivers/media/video/zoran_device.c12
-rw-r--r--drivers/media/video/zoran_driver.c4
-rw-r--r--drivers/media/video/zr36016.c5
-rw-r--r--drivers/media/video/zr36050.c5
-rw-r--r--drivers/media/video/zr36060.c6
-rw-r--r--drivers/media/video/zr364xx.c4
-rw-r--r--include/asm-arm/arch-pxa/camera.h48
-rw-r--r--include/asm-arm/arch-pxa/pxa-regs.h147
-rw-r--r--include/linux/dvb/dmx.h3
-rw-r--r--include/linux/meye.h2
-rw-r--r--include/linux/videodev2.h55
-rw-r--r--include/media/ir-common.h2
-rw-r--r--include/media/soc_camera.h179
-rw-r--r--include/media/tuner-types.h17
-rw-r--r--include/media/tuner.h2
-rw-r--r--include/media/v4l2-chip-ident.h6
-rw-r--r--include/media/videobuf-core.h9
-rw-r--r--include/media/videobuf-dma-sg.h14
255 files changed, 11100 insertions, 3609 deletions
diff --git a/Documentation/video4linux/CARDLIST.bttv b/Documentation/video4linux/CARDLIST.bttv
index d97cf7cc6088..f32efb6fb12c 100644
--- a/Documentation/video4linux/CARDLIST.bttv
+++ b/Documentation/video4linux/CARDLIST.bttv
@@ -148,3 +148,5 @@
147 -> VoodooTV 200 (USA) [121a:3000]
148 -> DViCO FusionHDTV 2 [dbc0:d200]
149 -> Typhoon TV-Tuner PCI (50684)
+150 -> Geovision GV-600 [008a:763c]
+151 -> Kozumi KTV-01C
diff --git a/Documentation/video4linux/CARDLIST.cx88 b/Documentation/video4linux/CARDLIST.cx88
index bc5593bd9704..543957346469 100644
--- a/Documentation/video4linux/CARDLIST.cx88
+++ b/Documentation/video4linux/CARDLIST.cx88
@@ -57,3 +57,12 @@
56 -> Hauppauge WinTV-HVR1300 DVB-T/Hybrid MPEG Encoder [0070:9600,0070:9601,0070:9602]
57 -> ADS Tech Instant Video PCI [1421:0390]
58 -> Pinnacle PCTV HD 800i [11bd:0051]
+ 59 -> DViCO FusionHDTV 5 PCI nano [18ac:d530]
+ 60 -> Pinnacle Hybrid PCTV [12ab:1788]
+ 61 -> Winfast TV2000 XP Global [107d:6f18]
+ 62 -> PowerColor Real Angel 330 [14f1:ea3d]
+ 63 -> Geniatech X8000-MT DVBT [14f1:8852]
+ 64 -> DViCO FusionHDTV DVB-T PRO [18ac:db30]
+ 65 -> DViCO FusionHDTV 7 Gold [18ac:d610]
+ 66 -> Prolink Pixelview MPEG 8000GT [1554:4935]
+ 67 -> Kworld PlusTV HD PCI 120 (ATSC 120) [17de:08c1]
diff --git a/Documentation/video4linux/CARDLIST.saa7134 b/Documentation/video4linux/CARDLIST.saa7134
index 0424901ebc78..fe925b335c94 100644
--- a/Documentation/video4linux/CARDLIST.saa7134
+++ b/Documentation/video4linux/CARDLIST.saa7134
@@ -131,3 +131,12 @@
130 -> Beholder BeholdTV M6 / BeholdTV M6 Extra [5ace:6190,5ace:6193]
131 -> Twinhan Hybrid DTV-DVB 3056 PCI [1822:0022]
132 -> Genius TVGO AM11MCE
+133 -> NXP Snake DVB-S reference design
+134 -> Medion/Creatix CTX953 Hybrid [16be:0010]
+135 -> MSI TV@nywhere A/D v1.1 [1462:8625]
+136 -> AVerMedia Cardbus TV/Radio (E506R) [1461:f436]
+137 -> AVerMedia Hybrid TV/Radio (A16D) [1461:f936]
+138 -> Avermedia M115 [1461:a836]
+139 -> Compro VideoMate T750 [185b:c900]
+140 -> Avermedia DVB-S Pro A700 [1461:a7a1]
+141 -> Avermedia DVB-S Hybrid+FM A700 [1461:a7a2]
diff --git a/arch/arm/mach-pxa/devices.c b/arch/arm/mach-pxa/devices.c
index bfccb80ac8ef..3838aabdf338 100644
--- a/arch/arm/mach-pxa/devices.c
+++ b/arch/arm/mach-pxa/devices.c
@@ -11,6 +11,7 @@
#include <asm/arch/irda.h>
#include <asm/arch/i2c.h>
#include <asm/arch/ohci.h>
+#include <asm/arch/camera.h>
#include "devices.h"
@@ -540,6 +541,37 @@ struct platform_device pxa27x_device_ssp3 = {
.resource = pxa27x_resource_ssp3,
.num_resources = ARRAY_SIZE(pxa27x_resource_ssp3),
};
+
+static struct resource pxa27x_resource_camera[] = {
+ [0] = {
+ .start = 0x50000000,
+ .end = 0x50000fff,
+ .flags = IORESOURCE_MEM,
+ },
+ [1] = {
+ .start = IRQ_CAMERA,
+ .end = IRQ_CAMERA,
+ .flags = IORESOURCE_IRQ,
+ },
+};
+
+static u64 pxa27x_dma_mask_camera = DMA_BIT_MASK(32);
+
+static struct platform_device pxa27x_device_camera = {
+ .name = "pxa27x-camera",
+ .id = 0, /* This is used to put cameras on this interface */
+ .dev = {
+ .dma_mask = &pxa27x_dma_mask_camera,
+ .coherent_dma_mask = 0xffffffff,
+ },
+ .num_resources = ARRAY_SIZE(pxa27x_resource_camera),
+ .resource = pxa27x_resource_camera,
+};
+
+void __init pxa_set_camera_info(struct pxacamera_platform_data *info)
+{
+ pxa_register_device(&pxa27x_device_camera, info);
+}
#endif /* CONFIG_PXA27x || CONFIG_PXA3xx */
#ifdef CONFIG_PXA3xx
diff --git a/arch/arm/mach-pxa/pcm990-baseboard.c b/arch/arm/mach-pxa/pcm990-baseboard.c
index 3dda16a20049..07ac050f2b4e 100644
--- a/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -23,6 +23,13 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/ide.h>
+#include <linux/i2c.h>
+
+#include <media/soc_camera.h>
+
+#include <asm/gpio.h>
+#include <asm/arch/i2c.h>
+#include <asm/arch/camera.h>
#include <asm/mach/map.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/mmc.h>
@@ -258,6 +265,76 @@ static struct pxaohci_platform_data pcm990_ohci_platform_data = {
};
/*
+ * PXA27x Camera specific stuff
+ */
+#if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
+static int pcm990_pxacamera_init(struct device *dev)
+{
+ pxa_gpio_mode(GPIO98_CIF_DD0_MD);
+ pxa_gpio_mode(GPIO105_CIF_DD1_MD);
+ pxa_gpio_mode(GPIO104_CIF_DD2_MD);
+ pxa_gpio_mode(GPIO103_CIF_DD3_MD);
+ pxa_gpio_mode(GPIO95_CIF_DD4_MD);
+ pxa_gpio_mode(GPIO94_CIF_DD5_MD);
+ pxa_gpio_mode(GPIO93_CIF_DD6_MD);
+ pxa_gpio_mode(GPIO108_CIF_DD7_MD);
+ pxa_gpio_mode(GPIO107_CIF_DD8_MD);
+ pxa_gpio_mode(GPIO106_CIF_DD9_MD);
+ pxa_gpio_mode(GPIO42_CIF_MCLK_MD);
+ pxa_gpio_mode(GPIO45_CIF_PCLK_MD);
+ pxa_gpio_mode(GPIO43_CIF_FV_MD);
+ pxa_gpio_mode(GPIO44_CIF_LV_MD);
+
+ return 0;
+}
+
+/*
+ * CICR4: PCLK_EN: Pixel clock is supplied by the sensor
+ * MCLK_EN: Master clock is generated by PXA
+ * PCP: Data sampled on the falling edge of pixel clock
+ */
+struct pxacamera_platform_data pcm990_pxacamera_platform_data = {
+ .init = pcm990_pxacamera_init,
+ .flags = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 | PXA_CAMERA_DATAWIDTH_10 |
+ PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN/* | PXA_CAMERA_PCP*/,
+ .mclk_10khz = 1000,
+};
+
+#include <linux/i2c/pca953x.h>
+
+static struct pca953x_platform_data pca9536_data = {
+ .gpio_base = NR_BUILTIN_GPIO + 1,
+};
+
+static struct soc_camera_link iclink[] = {
+ {
+ .bus_id = 0, /* Must match with the camera ID above */
+ .gpio = NR_BUILTIN_GPIO + 1,
+ }, {
+ .bus_id = 0, /* Must match with the camera ID above */
+ }
+};
+
+/* Board I2C devices. */
+static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
+ {
+ /* Must initialize before the camera(s) */
+ I2C_BOARD_INFO("pca953x", 0x41),
+ .type = "pca9536",
+ .platform_data = &pca9536_data,
+ }, {
+ I2C_BOARD_INFO("mt9v022", 0x48),
+ .type = "mt9v022",
+ .platform_data = &iclink[0], /* With extender */
+ }, {
+ I2C_BOARD_INFO("mt9m001", 0x5d),
+ .type = "mt9m001",
+ .platform_data = &iclink[0], /* With extender */
+ },
+};
+#endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
+
+/*
* AC97 support
* Note: The connected AC97 mixer also reports interrupts at PCM990_AC97_IRQ
*/
@@ -326,5 +403,14 @@ void __init pcm990_baseboard_init(void)
/* USB host */
pxa_set_ohci_info(&pcm990_ohci_platform_data);
+ pxa_set_i2c_info(NULL);
+
+#if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
+ pxa_set_camera_info(&pcm990_pxacamera_platform_data);
+
+ i2c_register_board_info(0, pcm990_i2c_devices,
+ ARRAY_SIZE(pcm990_i2c_devices));
+#endif
+
printk(KERN_INFO"PCM-990 Evaluation baseboard initialized\n");
}
diff --git a/drivers/media/Kconfig b/drivers/media/Kconfig
index 11950698a2e7..1f7244cffe2f 100644
--- a/drivers/media/Kconfig
+++ b/drivers/media/Kconfig
@@ -155,7 +155,7 @@ config VIDEOBUF_GEN
tristate
config VIDEOBUF_DMA_SG
- depends on PCI
+ depends on HAS_DMA
select VIDEOBUF_GEN
tristate
diff --git a/drivers/media/common/ir-functions.c b/drivers/media/common/ir-functions.c
index bb2a027b9483..266505207925 100644
--- a/drivers/media/common/ir-functions.c
+++ b/drivers/media/common/ir-functions.c
@@ -34,7 +34,7 @@ static int repeat = 1;
module_param(repeat, int, 0444);
MODULE_PARM_DESC(repeat,"auto-repeat for IR keys (default: on)");
-static int debug = 0; /* debug level (0,1,2) */
+static int debug; /* debug level (0,1,2) */
module_param(debug, int, 0644);
#define dprintk(level, fmt, arg...) if (debug >= level) \
diff --git a/drivers/media/common/ir-keymaps.c b/drivers/media/common/ir-keymaps.c
index 2ab5a120470d..c5d10bdf4286 100644
--- a/drivers/media/common/ir-keymaps.c
+++ b/drivers/media/common/ir-keymaps.c
@@ -212,6 +212,51 @@ IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE] = {
EXPORT_SYMBOL_GPL(ir_codes_pixelview);
+/*
+ Mauro Carvalho Chehab <mchehab@infradead.org>
+ present on PV MPEG 8000GT
+ */
+IR_KEYTAB_TYPE ir_codes_pixelview_new[IR_KEYTAB_SIZE] = {
+ [0x3c] = KEY_PAUSE, /* Timeshift */
+ [0x12] = KEY_POWER,
+
+ [0x3d] = KEY_1,
+ [0x38] = KEY_2,
+ [0x18] = KEY_3,
+ [0x35] = KEY_4,
+ [0x39] = KEY_5,
+ [0x15] = KEY_6,
+ [0x36] = KEY_7,
+ [0x3a] = KEY_8,
+ [0x1e] = KEY_9,
+ [0x3e] = KEY_0,
+
+ [0x1c] = KEY_AGAIN, /* LOOP */
+ [0x3f] = KEY_MEDIA, /* Source */
+ [0x1f] = KEY_LAST, /* +100 */
+ [0x1b] = KEY_MUTE,
+
+ [0x17] = KEY_CHANNELDOWN,
+ [0x16] = KEY_CHANNELUP,
+ [0x10] = KEY_VOLUMEUP,
+ [0x14] = KEY_VOLUMEDOWN,
+ [0x13] = KEY_ZOOM,
+
+ [0x19] = KEY_SHUFFLE, /* SNAPSHOT */
+ [0x1a] = KEY_SEARCH, /* scan */
+
+ [0x37] = KEY_REWIND, /* << */
+ [0x32] = KEY_RECORD, /* o (red) */
+ [0x33] = KEY_FORWARD, /* >> */
+ [0x11] = KEY_STOP, /* square */
+ [0x3b] = KEY_PLAY, /* > */
+ [0x30] = KEY_PLAYPAUSE, /* || */
+
+ [0x31] = KEY_TV,
+ [0x34] = KEY_RADIO,
+};
+EXPORT_SYMBOL_GPL(ir_codes_pixelview_new);
+
IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE] = {
[ 0x00 ] = KEY_0,
[ 0x01 ] = KEY_1,
@@ -1157,7 +1202,8 @@ EXPORT_SYMBOL_GPL(ir_codes_purpletv);
/* Mapping for the 28 key remote control as seen at
http://www.sednacomputer.com/photo/cardbus-tv.jpg
- Pavel Mihaylov <bin@bash.info> */
+ Pavel Mihaylov <bin@bash.info>
+ Also for the remote bundled with Kozumi KTV-01C card */
IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE] = {
[ 0x00 ] = KEY_0,
[ 0x01 ] = KEY_1,
@@ -1188,6 +1234,11 @@ IR_KEYTAB_TYPE ir_codes_pctv_sedna[IR_KEYTAB_SIZE] = {
[ 0x1c ] = KEY_RADIO, /* FM Radio */
[ 0x1d ] = KEY_RECORD,
[ 0x1e ] = KEY_PAUSE,
+ /* additional codes for Kozumi's remote */
+ [0x14] = KEY_INFO, /* OSD */
+ [0x16] = KEY_OK, /* OK */
+ [0x17] = KEY_DIGITS, /* Plus */
+ [0x1f] = KEY_PLAY, /* Play */
};
EXPORT_SYMBOL_GPL(ir_codes_pctv_sedna);
@@ -2033,3 +2084,46 @@ IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE] = {
[0x50] = KEY_BLUE,
};
EXPORT_SYMBOL_GPL(ir_codes_genius_tvgo_a11mce);
+
+/*
+ * Remote control for Powercolor Real Angel 330
+ * Daniel Fraga <fragabr@gmail.com>
+ */
+IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE] = {
+ [0x38] = KEY_SWITCHVIDEOMODE, /* switch inputs */
+ [0x0c] = KEY_MEDIA, /* Turn ON/OFF App */
+ [0x00] = KEY_0,
+ [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,
+ [0x0a] = KEY_DIGITS, /* single, double, tripple digit */
+ [0x29] = KEY_PREVIOUS, /* previous channel */
+ [0x12] = KEY_BRIGHTNESSUP,
+ [0x13] = KEY_BRIGHTNESSDOWN,
+ [0x2b] = KEY_MODE, /* stereo/mono */
+ [0x2c] = KEY_TEXT, /* teletext */
+ [0x20] = KEY_UP, /* channel up */
+ [0x21] = KEY_DOWN, /* channel down */
+ [0x10] = KEY_RIGHT, /* volume up */
+ [0x11] = KEY_LEFT, /* volume down */
+ [0x0d] = KEY_MUTE,
+ [0x1f] = KEY_RECORD,
+ [0x17] = KEY_PLAY,
+ [0x16] = KEY_PAUSE,
+ [0x0b] = KEY_STOP,
+ [0x27] = KEY_FASTFORWARD,
+ [0x26] = KEY_REWIND,
+ [0x1e] = KEY_SEARCH, /* autoscan */
+ [0x0e] = KEY_SHUFFLE, /* snapshot */
+ [0x2d] = KEY_SETUP,
+ [0x0f] = KEY_SCREEN, /* full screen */
+ [0x14] = KEY_RADIO, /* FM radio */
+ [0x25] = KEY_POWER, /* power */
+};
+EXPORT_SYMBOL_GPL(ir_codes_powercolor_real_angel);
diff --git a/drivers/media/common/saa7146_vbi.c b/drivers/media/common/saa7146_vbi.c
index bfbd5a841ebf..74e2b56ecb5b 100644
--- a/drivers/media/common/saa7146_vbi.c
+++ b/drivers/media/common/saa7146_vbi.c
@@ -407,8 +407,8 @@ static int vbi_open(struct saa7146_dev *dev, struct file *file)
fh->vbi_fmt.start[1] = 312;
fh->vbi_fmt.count[1] = 16;
- videobuf_queue_pci_init(&fh->vbi_q, &vbi_qops,
- dev->pci, &dev->slock,
+ videobuf_queue_sg_init(&fh->vbi_q, &vbi_qops,
+ &dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VBI_CAPTURE,
V4L2_FIELD_SEQ_TB, // FIXME: does this really work?
sizeof(struct saa7146_buf),
diff --git a/drivers/media/common/saa7146_video.c b/drivers/media/common/saa7146_video.c
index 66fdbd0e6a6d..3cbc6ebbe649 100644
--- a/drivers/media/common/saa7146_video.c
+++ b/drivers/media/common/saa7146_video.c
@@ -1410,8 +1410,8 @@ static int video_open(struct saa7146_dev *dev, struct file *file)
sfmt = 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_pci_init(&fh->video_q, &video_qops,
- dev->pci, &dev->slock,
+ videobuf_queue_sg_init(&fh->video_q, &video_qops,
+ &dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7146_buf),
diff --git a/drivers/media/dvb/b2c2/Kconfig b/drivers/media/dvb/b2c2/Kconfig
index 3197aeb61d1f..ffcbc7610856 100644
--- a/drivers/media/dvb/b2c2/Kconfig
+++ b/drivers/media/dvb/b2c2/Kconfig
@@ -9,6 +9,7 @@ config DVB_B2C2_FLEXCOP
select DVB_STV0297 if !DVB_FE_CUSTOMISE
select DVB_BCM3510 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
help
Support for the digital TV receiver chip made by B2C2 Inc. included in
Technisats PCI cards and USB boxes.
diff --git a/drivers/media/dvb/b2c2/Makefile b/drivers/media/dvb/b2c2/Makefile
index e97ff60a1eff..7d5334106d5a 100644
--- a/drivers/media/dvb/b2c2/Makefile
+++ b/drivers/media/dvb/b2c2/Makefile
@@ -13,3 +13,4 @@ b2c2-flexcop-usb-objs = flexcop-usb.o
obj-$(CONFIG_DVB_B2C2_FLEXCOP_USB) += b2c2-flexcop-usb.o
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
+EXTRA_CFLAGS += -Idrivers/media/video/
diff --git a/drivers/media/dvb/b2c2/flexcop-common.h b/drivers/media/dvb/b2c2/flexcop-common.h
index 5a6c4fe249e7..8ce06336e76f 100644
--- a/drivers/media/dvb/b2c2/flexcop-common.h
+++ b/drivers/media/dvb/b2c2/flexcop-common.h
@@ -44,6 +44,14 @@ struct flexcop_dma {
u32 size; /* size of each address in bytes */
};
+struct flexcop_i2c_adapter {
+ struct flexcop_device *fc;
+ struct i2c_adapter i2c_adap;
+
+ u8 no_base_addr;
+ flexcop_i2c_port_t port;
+};
+
/* Control structure for data definitions that are common to
* the B2C2-based PCI and USB devices.
*/
@@ -72,7 +80,7 @@ struct flexcop_device {
struct dmx_frontend mem_frontend;
int (*fe_sleep) (struct dvb_frontend *);
- struct i2c_adapter i2c_adap;
+ struct flexcop_i2c_adapter fc_i2c_adap[3];
struct mutex i2c_mutex;
struct module *owner;
@@ -87,7 +95,8 @@ struct flexcop_device {
int (*write_ibi_reg) (struct flexcop_device *, flexcop_ibi_register, flexcop_ibi_value);
- int (*i2c_request) (struct flexcop_device*, flexcop_access_op_t, flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+ int (*i2c_request) (struct flexcop_i2c_adapter*,
+ flexcop_access_op_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
int (*stream_control) (struct flexcop_device*, int);
int (*get_mac_addr) (struct flexcop_device *fc, int extended);
@@ -128,8 +137,8 @@ int flexcop_eeprom_check_mac_addr(struct flexcop_device *fc, int extended);
* one. We have it in flexcop-i2c.c, because it is going via the actual
* I2C-channel of the flexcop.
*/
-int flexcop_i2c_request(struct flexcop_device*, flexcop_access_op_t,
- flexcop_i2c_port_t, u8 chipaddr, u8 addr, u8 *buf, u16 len);
+int flexcop_i2c_request(struct flexcop_i2c_adapter*, flexcop_access_op_t,
+ u8 chipaddr, u8 addr, u8 *buf, u16 len);
/* from flexcop-sram.c */
int flexcop_sram_set_dest(struct flexcop_device *fc, flexcop_sram_dest_t dest, flexcop_sram_dest_target_t target);
diff --git a/drivers/media/dvb/b2c2/flexcop-eeprom.c b/drivers/media/dvb/b2c2/flexcop-eeprom.c
index bbcf070a178d..8a8ae8a3e6ba 100644
--- a/drivers/media/dvb/b2c2/flexcop-eeprom.c
+++ b/drivers/media/dvb/b2c2/flexcop-eeprom.c
@@ -114,15 +114,18 @@ static int flexcop_eeprom_request(struct flexcop_device *fc, flexcop_access_op_t
{
int i,ret = 0;
u8 chipaddr = 0x50 | ((addr >> 8) & 3);
- for (i = 0; i < retries; i++)
- if ((ret = fc->i2c_request(fc,op,FC_I2C_PORT_EEPROM,chipaddr,addr & 0xff,buf,len)) == 0)
+ for (i = 0; i < retries; i++) {
+ ret = fc->i2c_request(&fc->fc_i2c_adap[1], op, chipaddr,
+ addr & 0xff, buf, len);
+ if (ret == 0)
break;
+ }
return ret;
}
static int flexcop_eeprom_lrc_read(struct flexcop_device *fc, u16 addr, u8 *buf, u16 len, int retries)
{
- int ret = flexcop_eeprom_request(fc,FC_READ,addr,buf,len,retries);
+ int ret = flexcop_eeprom_request(fc, FC_READ, addr, buf, len, retries);
if (ret == 0)
if (calc_lrc(buf, len - 1) != buf[len - 1])
ret = -EINVAL;
diff --git a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 0378fd646591..46d6f5d8cd1c 100644
--- a/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -5,6 +5,8 @@
*
* see flexcop.c for copyright information.
*/
+#include <media/tuner.h>
+
#include "flexcop.h"
#include "stv0299.h"
@@ -15,6 +17,7 @@
#include "mt312.h"
#include "lgdt330x.h"
#include "dvb-pll.h"
+#include "tuner-simple.h"
/* lnb control */
@@ -180,13 +183,13 @@ static int samsung_tbmu24112_tuner_set_params(struct dvb_frontend* fe, struct dv
buf[2] = 0x84; /* 0xC4 */
buf[3] = 0x08;
- if (params->frequency < 1500000) buf[3] |= 0x10;
+ if (params->frequency < 1500000)
+ buf[3] |= 0x10;
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1) {
+ if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
return -EIO;
- }
return 0;
}
@@ -337,7 +340,7 @@ static int skystar23_samsung_tbdu18132_tuner_set_params(struct dvb_frontend* fe,
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
- if (i2c_transfer(&fc->i2c_adap, &msg, 1) != 1)
+ if (i2c_transfer(&fc->fc_i2c_adap[0].i2c_adap, &msg, 1) != 1)
return -EIO;
return 0;
}
@@ -386,10 +389,11 @@ static int alps_tdee4_stv0297_tuner_set_params(struct dvb_frontend* fe,
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 0);
deb_tuner("tuner buffer for %d Hz: %x %x %x %x\n",fep->frequency, buf[0],buf[1],buf[2],buf[3]);
- ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_TUNER, 0x61, buf[0], &buf[1], 3);
+ ret = fc->i2c_request(&fc->fc_i2c_adap[2],
+ FC_WRITE, 0x61, buf[0], &buf[1], 3);
deb_tuner("tuner write returned: %d\n",ret);
- return 0;
+ return ret;
}
static u8 alps_tdee4_stv0297_inittab[] = {
@@ -476,52 +480,67 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
int flexcop_frontend_init(struct flexcop_device *fc)
{
struct dvb_frontend_ops *ops;
+ struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap;
/* try the sky v2.6 (stv0299/Samsung tbmu24112(sl1935)) */
- if ((fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, &fc->i2c_adap)) != NULL) {
+ fc->fe = dvb_attach(stv0299_attach, &samsung_tbmu24112_config, i2c);
+ if (fc->fe != NULL) {
ops = &fc->fe->ops;
ops->tuner_ops.set_params = samsung_tbmu24112_tuner_set_params;
ops->set_voltage = flexcop_set_voltage;
- fc->fe_sleep = ops->sleep;
- ops->sleep = flexcop_sleep;
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
+
+ fc->dev_type = FC_SKY;
+ goto fe_found;
+ }
- fc->dev_type = FC_SKY;
- info("found the stv0299 at i2c address: 0x%02x",samsung_tbmu24112_config.demod_address);
- } else
/* try the air dvb-t (mt352/Samsung tdtc9251dh0(??)) */
- if ((fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, &fc->i2c_adap)) != NULL ) {
- fc->dev_type = FC_AIR_DVB;
+ fc->fe = dvb_attach(mt352_attach, &samsung_tdtc9251dh0_config, i2c);
+ if (fc->fe != NULL) {
+ fc->dev_type = FC_AIR_DVB;
fc->fe->ops.tuner_ops.calc_regs = samsung_tdtc9251dh0_calc_regs;
- info("found the mt352 at i2c address: 0x%02x",samsung_tdtc9251dh0_config.demod_address);
- } else
+ goto fe_found;
+ }
+
/* try the air atsc 2nd generation (nxt2002) */
- if ((fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, &fc->i2c_adap)) != NULL) {
- fc->dev_type = FC_AIR_ATSC2;
+ fc->fe = dvb_attach(nxt200x_attach, &samsung_tbmv_config, i2c);
+ if (fc->fe != NULL) {
+ fc->dev_type = FC_AIR_ATSC2;
dvb_attach(dvb_pll_attach, fc->fe, 0x61, NULL, DVB_PLL_SAMSUNG_TBMV);
- info("found the nxt2002 at i2c address: 0x%02x",samsung_tbmv_config.demod_address);
- } else
- /* try the air atsc 3nd generation (lgdt3303) */
- if ((fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, &fc->i2c_adap)) != NULL) {
- fc->dev_type = FC_AIR_ATSC3;
- dvb_attach(dvb_pll_attach, fc->fe, 0x61, &fc->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
- info("found the lgdt3303 at i2c address: 0x%02x",air2pc_atsc_hd5000_config.demod_address);
- } else
+ goto fe_found;
+ }
+
+ fc->fe = dvb_attach(lgdt330x_attach, &air2pc_atsc_hd5000_config, i2c);
+ if (fc->fe != NULL) {
+ fc->dev_type = FC_AIR_ATSC3;
+ dvb_attach(simple_tuner_attach, fc->fe, i2c, 0x61,
+ TUNER_LG_TDVS_H06XF);
+ goto fe_found;
+ }
+
/* try the air atsc 1nd generation (bcm3510)/panasonic ct10s */
- if ((fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, &fc->i2c_adap)) != NULL) {
- fc->dev_type = FC_AIR_ATSC1;
- info("found the bcm3510 at i2c address: 0x%02x",air2pc_atsc_first_gen_config.demod_address);
- } else
+ fc->fe = dvb_attach(bcm3510_attach, &air2pc_atsc_first_gen_config, i2c);
+ if (fc->fe != NULL) {
+ fc->dev_type = FC_AIR_ATSC1;
+ goto fe_found;
+ }
+
/* try the cable dvb (stv0297) */
- if ((fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, &fc->i2c_adap)) != NULL) {
- fc->dev_type = FC_CABLE;
+ fc->fe = dvb_attach(stv0297_attach, &alps_tdee4_stv0297_config, i2c);
+ if (fc->fe != NULL) {
+ fc->dev_type = FC_CABLE;
fc->fe->ops.tuner_ops.set_params = alps_tdee4_stv0297_tuner_set_params;
- info("found the stv0297 at i2c address: 0x%02x",alps_tdee4_stv0297_config.demod_address);
- } else
+ goto fe_found;
+ }
+
/* try the sky v2.3 (vp310/Samsung tbdu18132(tsa5059)) */
- if ((fc->fe = dvb_attach(vp310_mt312_attach, &skystar23_samsung_tbdu18132_config, &fc->i2c_adap)) != NULL) {
+ fc->fe = dvb_attach(vp310_mt312_attach,
+ &skystar23_samsung_tbdu18132_config, i2c);
+ if (fc->fe != NULL) {
ops = &fc->fe->ops;
ops->tuner_ops.set_params = skystar23_samsung_tbdu18132_tuner_set_params;
@@ -535,19 +554,21 @@ int flexcop_frontend_init(struct flexcop_device *fc)
ops->sleep = flexcop_sleep;
fc->dev_type = FC_SKY_OLD;
- info("found the vp310 (aka mt312) at i2c address: 0x%02x",skystar23_samsung_tbdu18132_config.demod_address);
+ goto fe_found;
}
- if (fc->fe == NULL) {
- err("no frontend driver found for this B2C2/FlexCop adapter");
- return -ENODEV;
- } else {
- if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
- err("frontend registration failed!");
- dvb_frontend_detach(fc->fe);
- fc->fe = NULL;
- return -EINVAL;
- }
+ err("no frontend driver found for this B2C2/FlexCop adapter");
+ return -ENODEV;
+
+fe_found:
+ info("found '%s' .", fc->fe->ops.info.name);
+ if (dvb_register_frontend(&fc->dvb_adapter, fc->fe)) {
+ err("frontend registration failed!");
+ ops = &fc->fe->ops;
+ if (ops->release != NULL)
+ ops->release(fc->fe);
+ fc->fe = NULL;
+ return -EINVAL;
}
fc->init_state |= FC_STATE_FE_INIT;
return 0;
diff --git a/drivers/media/dvb/b2c2/flexcop-i2c.c b/drivers/media/dvb/b2c2/flexcop-i2c.c
index 6bf858a436c9..55973eaf3711 100644
--- a/drivers/media/dvb/b2c2/flexcop-i2c.c
+++ b/drivers/media/dvb/b2c2/flexcop-i2c.c
@@ -9,6 +9,8 @@
#define FC_MAX_I2C_RETRIES 100000
+/* #define DUMP_I2C_MESSAGES */
+
static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r100)
{
int i;
@@ -38,30 +40,25 @@ static int flexcop_i2c_operation(struct flexcop_device *fc, flexcop_ibi_value *r
return -EREMOTEIO;
}
-static int flexcop_i2c_read4(struct flexcop_device *fc, flexcop_ibi_value r100, u8 *buf)
+static int flexcop_i2c_read4(struct flexcop_i2c_adapter *i2c,
+ flexcop_ibi_value r100, u8 *buf)
{
flexcop_ibi_value r104;
int len = r100.tw_sm_c_100.total_bytes, /* remember total_bytes is buflen-1 */
ret;
- if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
- /* The Cablestar needs a different kind of i2c-transfer (does not
- * support "Repeat Start"):
- * wait for the ACK failure,
- * and do a subsequent read with the Bit 30 enabled
- */
- r100.tw_sm_c_100.no_base_addr_ack_error = 1;
- if ((ret = flexcop_i2c_operation(fc,&r100)) != 0) {
- deb_i2c("no_base_addr read failed. %d\n",ret);
- return ret;
- }
+ r100.tw_sm_c_100.no_base_addr_ack_error = i2c->no_base_addr;
+ ret = flexcop_i2c_operation(i2c->fc, &r100);
+ if (ret != 0) {
+ deb_i2c("read failed. %d\n", ret);
+ return ret;
}
buf[0] = r100.tw_sm_c_100.data1_reg;
if (len > 0) {
- r104 = fc->read_ibi_reg(fc,tw_sm_c_104);
- deb_i2c("read: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
+ r104 = i2c->fc->read_ibi_reg(i2c->fc, tw_sm_c_104);
+ deb_i2c("read: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
/* there is at least one more byte, otherwise we wouldn't be here */
buf[1] = r104.tw_sm_c_104.data2_reg;
@@ -85,17 +82,22 @@ static int flexcop_i2c_write4(struct flexcop_device *fc, flexcop_ibi_value r100,
r104.tw_sm_c_104.data3_reg = len > 1 ? buf[2] : 0;
r104.tw_sm_c_104.data4_reg = len > 2 ? buf[3] : 0;
- deb_i2c("write: r100: %08x, r104: %08x\n",r100.raw,r104.raw);
+ deb_i2c("write: r100: %08x, r104: %08x\n", r100.raw, r104.raw);
/* write the additional i2c data before doing the actual i2c operation */
- fc->write_ibi_reg(fc,tw_sm_c_104,r104);
- return flexcop_i2c_operation(fc,&r100);
+ fc->write_ibi_reg(fc, tw_sm_c_104, r104);
+ return flexcop_i2c_operation(fc, &r100);
}
-int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
- flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+int flexcop_i2c_request(struct flexcop_i2c_adapter *i2c,
+ flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
{
int ret;
+
+#ifdef DUMP_I2C_MESSAGES
+ int i;
+#endif
+
u16 bytes_to_transfer;
flexcop_ibi_value r100;
@@ -103,7 +105,25 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
r100.raw = 0;
r100.tw_sm_c_100.chipaddr = chipaddr;
r100.tw_sm_c_100.twoWS_rw = op;
- r100.tw_sm_c_100.twoWS_port_reg = port;
+ r100.tw_sm_c_100.twoWS_port_reg = i2c->port;
+
+#ifdef DUMP_I2C_MESSAGES
+ printk(KERN_DEBUG "%d ", i2c->port);
+ if (op == FC_READ)
+ printk("rd(");
+ else
+ printk("wr(");
+
+ printk("%02x): %02x ", chipaddr, addr);
+#endif
+
+ /* in that case addr is the only value ->
+ * we write it twice as baseaddr and val0
+ * BBTI is doing it like that for ISL6421 at least */
+ if (i2c->no_base_addr && len == 0 && op == FC_WRITE) {
+ buf = &addr;
+ len = 1;
+ }
while (len != 0) {
bytes_to_transfer = len > 4 ? 4 : len;
@@ -112,9 +132,14 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
r100.tw_sm_c_100.baseaddr = addr;
if (op == FC_READ)
- ret = flexcop_i2c_read4(fc, r100, buf);
+ ret = flexcop_i2c_read4(i2c, r100, buf);
else
- ret = flexcop_i2c_write4(fc,r100, buf);
+ ret = flexcop_i2c_write4(i2c->fc, r100, buf);
+
+#ifdef DUMP_I2C_MESSAGES
+ for (i = 0; i < bytes_to_transfer; i++)
+ printk("%02x ", buf[i]);
+#endif
if (ret < 0)
return ret;
@@ -122,7 +147,11 @@ int flexcop_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
buf += bytes_to_transfer;
addr += bytes_to_transfer;
len -= bytes_to_transfer;
- };
+ }
+
+#ifdef DUMP_I2C_MESSAGES
+ printk("\n");
+#endif
return 0;
}
@@ -132,7 +161,7 @@ EXPORT_SYMBOL(flexcop_i2c_request);
/* master xfer callback for demodulator */
static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs[], int num)
{
- struct flexcop_device *fc = i2c_get_adapdata(i2c_adap);
+ struct flexcop_i2c_adapter *i2c = i2c_get_adapdata(i2c_adap);
int i, ret = 0;
/* Some drivers use 1 byte or 0 byte reads as probes, which this
@@ -142,34 +171,29 @@ static int flexcop_master_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msgs
if (num == 1 && msgs[0].flags == I2C_M_RD && msgs[0].len <= 1)
return 1;
- if (mutex_lock_interruptible(&fc->i2c_mutex))
+ if (mutex_lock_interruptible(&i2c->fc->i2c_mutex))
return -ERESTARTSYS;
- /* reading */
- if (num == 2 &&
- msgs[0].flags == 0 &&
- msgs[1].flags == I2C_M_RD &&
- msgs[0].buf != NULL &&
- msgs[1].buf != NULL) {
-
- ret = fc->i2c_request(fc, FC_READ, FC_I2C_PORT_DEMOD, msgs[0].addr, msgs[0].buf[0], msgs[1].buf, msgs[1].len);
-
- } else for (i = 0; i < num; i++) { /* writing command */
- if (msgs[i].flags != 0 || msgs[i].buf == NULL || msgs[i].len < 2) {
- ret = -EINVAL;
+ for (i = 0; i < num; i++) {
+ /* reading */
+ if (i+1 < num && (msgs[i+1].flags == I2C_M_RD)) {
+ ret = i2c->fc->i2c_request(i2c, FC_READ, msgs[i].addr,
+ msgs[i].buf[0], msgs[i+1].buf, msgs[i+1].len);
+ i++; /* skip the following message */
+ } else /* writing */
+ ret = i2c->fc->i2c_request(i2c, FC_WRITE, msgs[i].addr,
+ msgs[i].buf[0], &msgs[i].buf[1],
+ msgs[i].len - 1);
+ if (ret < 0) {
+ err("i2c master_xfer failed");
break;
}
-
- ret = fc->i2c_request(fc, FC_WRITE, FC_I2C_PORT_DEMOD, msgs[i].addr, msgs[i].buf[0], &msgs[i].buf[1], msgs[i].len - 1);
}
- if (ret < 0)
- err("i2c master_xfer failed");
- else
- ret = num;
-
- mutex_unlock(&fc->i2c_mutex);
+ mutex_unlock(&i2c->fc->i2c_mutex);
+ if (ret == 0)
+ ret = num;
return ret;
}
@@ -189,28 +213,68 @@ int flexcop_i2c_init(struct flexcop_device *fc)
mutex_init(&fc->i2c_mutex);
- memset(&fc->i2c_adap, 0, sizeof(struct i2c_adapter));
- strncpy(fc->i2c_adap.name, "B2C2 FlexCop device",
- sizeof(fc->i2c_adap.name));
-
- i2c_set_adapdata(&fc->i2c_adap,fc);
+ fc->fc_i2c_adap[0].fc = fc;
+ fc->fc_i2c_adap[1].fc = fc;
+ fc->fc_i2c_adap[2].fc = fc;
+
+ fc->fc_i2c_adap[0].port = FC_I2C_PORT_DEMOD;
+ fc->fc_i2c_adap[1].port = FC_I2C_PORT_EEPROM;
+ fc->fc_i2c_adap[2].port = FC_I2C_PORT_TUNER;
+
+ strncpy(fc->fc_i2c_adap[0].i2c_adap.name,
+ "B2C2 FlexCop I2C to demod", I2C_NAME_SIZE);
+ strncpy(fc->fc_i2c_adap[1].i2c_adap.name,
+ "B2C2 FlexCop I2C to eeprom", I2C_NAME_SIZE);
+ strncpy(fc->fc_i2c_adap[2].i2c_adap.name,
+ "B2C2 FlexCop I2C to tuner", I2C_NAME_SIZE);
+
+ i2c_set_adapdata(&fc->fc_i2c_adap[0].i2c_adap, &fc->fc_i2c_adap[0]);
+ 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;
+ fc->fc_i2c_adap[0].i2c_adap.algo_data =
+ fc->fc_i2c_adap[1].i2c_adap.algo_data =
+ fc->fc_i2c_adap[2].i2c_adap.algo_data = NULL;
+ fc->fc_i2c_adap[0].i2c_adap.dev.parent =
+ fc->fc_i2c_adap[1].i2c_adap.dev.parent =
+ fc->fc_i2c_adap[2].i2c_adap.dev.parent = fc->dev;
+
+ ret = i2c_add_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+ if (ret < 0)
+ return ret;
- fc->i2c_adap.class = I2C_CLASS_TV_DIGITAL;
- fc->i2c_adap.algo = &flexcop_algo;
- fc->i2c_adap.algo_data = NULL;
- fc->i2c_adap.dev.parent = fc->dev;
+ ret = i2c_add_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+ if (ret < 0)
+ goto adap_1_failed;
- if ((ret = i2c_add_adapter(&fc->i2c_adap)) < 0)
- return ret;
+ ret = i2c_add_adapter(&fc->fc_i2c_adap[2].i2c_adap);
+ if (ret < 0)
+ goto adap_2_failed;
fc->init_state |= FC_STATE_I2C_INIT;
return 0;
+
+adap_2_failed:
+ i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+adap_1_failed:
+ i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+
+ return ret;
}
void flexcop_i2c_exit(struct flexcop_device *fc)
{
- if (fc->init_state & FC_STATE_I2C_INIT)
- i2c_del_adapter(&fc->i2c_adap);
+ if (fc->init_state & FC_STATE_I2C_INIT) {
+ i2c_del_adapter(&fc->fc_i2c_adap[2].i2c_adap);
+ i2c_del_adapter(&fc->fc_i2c_adap[1].i2c_adap);
+ i2c_del_adapter(&fc->fc_i2c_adap[0].i2c_adap);
+ }
fc->init_state &= ~FC_STATE_I2C_INIT;
}
diff --git a/drivers/media/dvb/b2c2/flexcop-pci.c b/drivers/media/dvb/b2c2/flexcop-pci.c
index 01af4d237eb1..5b30dfc7846b 100644
--- a/drivers/media/dvb/b2c2/flexcop-pci.c
+++ b/drivers/media/dvb/b2c2/flexcop-pci.c
@@ -32,7 +32,7 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently jus
#define deb_irq(args...) dprintk(0x08,args)
#define deb_chk(args...) dprintk(0x10,args)
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS);
diff --git a/drivers/media/dvb/b2c2/flexcop-usb.c b/drivers/media/dvb/b2c2/flexcop-usb.c
index 87fb75f0d1cf..449fb5c3d0b1 100644
--- a/drivers/media/dvb/b2c2/flexcop-usb.c
+++ b/drivers/media/dvb/b2c2/flexcop-usb.c
@@ -211,10 +211,11 @@ static int flexcop_usb_utility_req(struct flexcop_usb *fc_usb, int set,
#endif
/* usb i2c stuff */
-static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb,
+static int flexcop_usb_i2c_req(struct flexcop_i2c_adapter *i2c,
flexcop_usb_request_t req, flexcop_usb_i2c_function_t func,
- flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
+ u8 chipaddr, u8 addr, u8 *buf, u8 buflen)
{
+ struct flexcop_usb *fc_usb = i2c->fc->bus_specific;
u16 wValue, wIndex;
int nWaitTime,pipe,len;
// u8 dwRequestType;
@@ -242,7 +243,7 @@ static int flexcop_usb_i2c_req(struct flexcop_usb *fc_usb,
deb_info("unsupported function for i2c_req %x\n",func);
return -EINVAL;
}
- wValue = (func << 8 ) | (port << 4);
+ wValue = (func << 8) | (i2c->port << 4);
wIndex = (chipaddr << 8 ) | addr;
deb_i2c("i2c %2d: %02x %02x %02x %02x %02x %02x\n",func,request_type,req,
@@ -274,13 +275,15 @@ static int flexcop_usb_write_ibi_reg(struct flexcop_device *fc, flexcop_ibi_regi
return flexcop_usb_readwrite_dw(fc,reg, &val.raw, 0);
}
-static int flexcop_usb_i2c_request(struct flexcop_device *fc, flexcop_access_op_t op,
- flexcop_i2c_port_t port, u8 chipaddr, u8 addr, u8 *buf, u16 len)
+static int flexcop_usb_i2c_request(struct flexcop_i2c_adapter *i2c,
+ flexcop_access_op_t op, u8 chipaddr, u8 addr, u8 *buf, u16 len)
{
if (op == FC_READ)
- return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_READ,port,chipaddr,addr,buf,len);
+ return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+ USB_FUNC_I2C_READ, chipaddr, addr, buf, len);
else
- return flexcop_usb_i2c_req(fc->bus_specific,B2C2_USB_I2C_REQUEST,USB_FUNC_I2C_WRITE,port,chipaddr,addr,buf,len);
+ return flexcop_usb_i2c_req(i2c, B2C2_USB_I2C_REQUEST,
+ USB_FUNC_I2C_WRITE, chipaddr, addr, buf, len);
}
static void flexcop_usb_process_frame(struct flexcop_usb *fc_usb, u8 *buffer, int buffer_length)
diff --git a/drivers/media/dvb/b2c2/flexcop.c b/drivers/media/dvb/b2c2/flexcop.c
index 2ddafd071c97..205146c24129 100644
--- a/drivers/media/dvb/b2c2/flexcop.c
+++ b/drivers/media/dvb/b2c2/flexcop.c
@@ -257,6 +257,12 @@ int flexcop_device_initialize(struct flexcop_device *fc)
if ((ret = flexcop_dvb_init(fc)))
goto error;
+ /* i2c has to be done before doing EEProm stuff -
+ * because the EEProm is accessed via i2c */
+ ret = flexcop_i2c_init(fc);
+ if (ret)
+ goto error;
+
/* do the MAC address reading after initializing the dvb_adapter */
if (fc->get_mac_addr(fc, 0) == 0) {
u8 *b = fc->dvb_adapter.proposed_mac;
@@ -266,10 +272,6 @@ int flexcop_device_initialize(struct flexcop_device *fc)
} else
warn("reading of MAC address failed.\n");
-
- if ((ret = flexcop_i2c_init(fc)))
- goto error;
-
if ((ret = flexcop_frontend_init(fc)))
goto error;
diff --git a/drivers/media/dvb/bt8xx/Kconfig b/drivers/media/dvb/bt8xx/Kconfig
index ea666174e988..902c762e0b7f 100644
--- a/drivers/media/dvb/bt8xx/Kconfig
+++ b/drivers/media/dvb/bt8xx/Kconfig
@@ -7,8 +7,8 @@ config DVB_BT8XX
select DVB_CX24110 if !DVB_FE_CUSTOMISE
select DVB_OR51211 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
- select DVB_PLL if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
select FW_LOADER
help
Support for PCI cards based on the Bt8xx PCI bridge. Examples are
diff --git a/drivers/media/dvb/bt8xx/Makefile b/drivers/media/dvb/bt8xx/Makefile
index 84cf70504d17..9d3e68b5d6eb 100644
--- a/drivers/media/dvb/bt8xx/Makefile
+++ b/drivers/media/dvb/bt8xx/Makefile
@@ -1,3 +1,6 @@
obj-$(CONFIG_DVB_BT8XX) += bt878.o dvb-bt8xx.o dst.o dst_ca.o
-EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/video/bt8xx -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+EXTRA_CFLAGS += -Idrivers/media/video/bt8xx
+EXTRA_CFLAGS += -Idrivers/media/video
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.c b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
index dedd30a8356b..65081f161544 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.c
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.c
@@ -41,9 +41,9 @@ module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
#define dprintk( args... ) \
- do \
+ do { \
if (debug) printk(KERN_DEBUG args); \
- while (0)
+ } while (0)
#define IF_FREQUENCYx6 217 /* 6 * 36.16666666667MHz */
@@ -609,8 +609,9 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
lgdt330x_reset(card);
card->fe = dvb_attach(lgdt330x_attach, &tdvs_tua6034_config, card->i2c_adapter);
if (card->fe != NULL) {
- dvb_attach(dvb_pll_attach, card->fe, 0x61,
- card->i2c_adapter, DVB_PLL_LG_TDVS_H06XF);
+ dvb_attach(simple_tuner_attach, card->fe,
+ card->i2c_adapter, 0x61,
+ TUNER_LG_TDVS_H06XF);
dprintk ("dvb_bt8xx: lgdt330x detected\n");
}
break;
@@ -692,8 +693,9 @@ static void frontend_init(struct dvb_bt8xx_card *card, u32 type)
case BTTV_BOARD_PC_HDTV:
card->fe = dvb_attach(or51211_attach, &or51211_config, card->i2c_adapter);
if (card->fe != NULL)
- dvb_attach(dvb_pll_attach, card->fe, 0x61,
- card->i2c_adapter, DVB_PLL_FCV1236D);
+ dvb_attach(simple_tuner_attach, card->fe,
+ card->i2c_adapter, 0x61,
+ TUNER_PHILIPS_FCV1236D);
break;
}
diff --git a/drivers/media/dvb/bt8xx/dvb-bt8xx.h b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
index 436880e68672..4499ed2ac0ed 100644
--- a/drivers/media/dvb/bt8xx/dvb-bt8xx.h
+++ b/drivers/media/dvb/bt8xx/dvb-bt8xx.h
@@ -38,7 +38,7 @@
#include "or51211.h"
#include "lgdt330x.h"
#include "zl10353.h"
-#include "dvb-pll.h"
+#include "tuner-simple.h"
struct dvb_bt8xx_card {
struct mutex lock;
diff --git a/drivers/media/dvb/dvb-core/demux.h b/drivers/media/dvb/dvb-core/demux.h
index 0c1d87c5227a..b0d347daae47 100644
--- a/drivers/media/dvb/dvb-core/demux.h
+++ b/drivers/media/dvb/dvb-core/demux.h
@@ -80,6 +80,8 @@ enum dmx_success {
#define TS_PAYLOAD_ONLY 2 /* in case TS_PACKET is set, only send the TS
payload (<=184 bytes per packet) to callback */
#define TS_DECODER 4 /* send stream to built-in decoder (if present) */
+#define TS_DEMUX 8 /* in case TS_PACKET is set, send the TS to
+ the demux device, not to the dvr device */
/* PES type for filters which write to built-in decoder */
/* these should be kept identical to the types in dmx.h */
diff --git a/drivers/media/dvb/dvb-core/dmxdev.c b/drivers/media/dvb/dvb-core/dmxdev.c
index f94bc31e3b33..716735f03f55 100644
--- a/drivers/media/dvb/dvb-core/dmxdev.c
+++ b/drivers/media/dvb/dvb-core/dmxdev.c
@@ -374,7 +374,8 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
return 0;
}
- if (dmxdevfilter->params.pes.output == DMX_OUT_TAP)
+ if (dmxdevfilter->params.pes.output == DMX_OUT_TAP
+ || dmxdevfilter->params.pes.output == DMX_OUT_TSDEMUX_TAP)
buffer = &dmxdevfilter->buffer;
else
buffer = &dmxdevfilter->dev->dvr_buffer;
@@ -620,9 +621,10 @@ static int dvb_dmxdev_filter_start(struct dmxdev_filter *filter)
if (otype == DMX_OUT_TS_TAP)
ts_type |= TS_PACKET;
-
- if (otype == DMX_OUT_TAP)
- ts_type |= TS_PAYLOAD_ONLY | TS_PACKET;
+ else if (otype == DMX_OUT_TSDEMUX_TAP)
+ ts_type |= TS_PACKET | TS_DEMUX;
+ else if (otype == DMX_OUT_TAP)
+ ts_type |= TS_PACKET | TS_DEMUX | TS_PAYLOAD_ONLY;
ret = dmxdev->demux->allocate_ts_feed(dmxdev->demux,
tsfeed,
diff --git a/drivers/media/dvb/dvb-core/dvb_demux.c b/drivers/media/dvb/dvb-core/dvb_demux.c
index 7959020f9317..988d14302cb1 100644
--- a/drivers/media/dvb/dvb-core/dvb_demux.c
+++ b/drivers/media/dvb/dvb-core/dvb_demux.c
@@ -368,7 +368,7 @@ static inline void dvb_dmx_swfilter_packet_type(struct dvb_demux_feed *feed,
#define DVR_FEED(f) \
(((f)->type == DMX_TYPE_TS) && \
((f)->feed.ts.is_filtering) && \
- (((f)->ts_type & (TS_PACKET|TS_PAYLOAD_ONLY)) == TS_PACKET))
+ (((f)->ts_type & (TS_PACKET | TS_DEMUX)) == TS_PACKET))
static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
{
diff --git a/drivers/media/dvb/dvb-core/dvb_net.c b/drivers/media/dvb/dvb-core/dvb_net.c
index 4c8b62e2c035..efaa297ac34d 100644
--- a/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/drivers/media/dvb/dvb-core/dvb_net.c
@@ -354,7 +354,7 @@ static void dvb_net_ule( struct net_device *dev, const u8 *buf, size_t buf_len )
#ifdef ULE_DEBUG
/* The code inside ULE_DEBUG keeps a history of the last 100 TS cells processed. */
static unsigned char ule_hist[100*TS_SZ];
- static unsigned char *ule_where = ule_hist, ule_dump = 0;
+ static unsigned char *ule_where = ule_hist, ule_dump;
#endif
/* For all TS cells in current buffer.
diff --git a/drivers/media/dvb/dvb-core/dvbdev.c b/drivers/media/dvb/dvb-core/dvbdev.c
index 18738faecbbc..ce5122e220f6 100644
--- a/drivers/media/dvb/dvb-core/dvbdev.c
+++ b/drivers/media/dvb/dvb-core/dvbdev.c
@@ -97,7 +97,7 @@ static int dvb_device_open(struct inode *inode, struct file *file)
}
-static struct file_operations dvb_device_fops =
+static const struct file_operations dvb_device_fops =
{
.owner = THIS_MODULE,
.open = dvb_device_open,
diff --git a/drivers/media/dvb/dvb-usb/Kconfig b/drivers/media/dvb/dvb-usb/Kconfig
index d73934dd4c57..3c8493d2026d 100644
--- a/drivers/media/dvb/dvb-usb/Kconfig
+++ b/drivers/media/dvb/dvb-usb/Kconfig
@@ -105,6 +105,7 @@ config DVB_USB_CXUSB
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select DVB_MT352 if !DVB_FE_CUSTOMISE
select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
help
Say Y here to support the Conexant USB2.0 hybrid reference design.
Currently, only DVB and ATSC modes are supported, analog mode
diff --git a/drivers/media/dvb/dvb-usb/cxusb.c b/drivers/media/dvb/dvb-usb/cxusb.c
index c58365005ac1..b75b2b7a1330 100644
--- a/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/drivers/media/dvb/dvb-usb/cxusb.c
@@ -23,6 +23,8 @@
*
* see Documentation/dvb/README.dvb-usb for more information
*/
+#include <media/tuner.h>
+
#include "cxusb.h"
#include "cx22702.h"
@@ -32,6 +34,7 @@
#include "zl10353.h"
#include "tuner-xc2028.h"
#include "tuner-xc2028-types.h"
+#include "tuner-simple.h"
/* debug */
static int dvb_usb_cxusb_debug;
@@ -450,8 +453,9 @@ static struct mt352_config cxusb_mt352_xc3028_config = {
/* Callbacks for DVB USB */
static int cxusb_fmd1216me_tuner_attach(struct dvb_usb_adapter *adap)
{
- dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
- DVB_PLL_FMD1216ME);
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3);
return 0;
}
@@ -477,8 +481,8 @@ static int cxusb_dtt7579_tuner_attach(struct dvb_usb_adapter *adap)
static int cxusb_lgh064f_tuner_attach(struct dvb_usb_adapter *adap)
{
- dvb_attach(dvb_pll_attach, adap->fe, 0x61, &adap->dev->i2c_adap,
- DVB_PLL_LG_TDVS_H06XF);
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->dev->i2c_adap, 0x61, TUNER_LG_TDVS_H06XF);
return 0;
}
@@ -509,7 +513,6 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
struct xc2028_config cfg = {
.i2c_adap = &adap->dev->i2c_adap,
.i2c_addr = 0x61,
- .video_dev = adap->dev,
.callback = dvico_bluebird_xc2028_callback,
};
static struct xc2028_ctrl ctl = {
diff --git a/drivers/media/dvb/dvb-usb/dib0700.h b/drivers/media/dvb/dvb-usb/dib0700.h
index 4a903ea95896..66d4dc6ba46f 100644
--- a/drivers/media/dvb/dvb-usb/dib0700.h
+++ b/drivers/media/dvb/dvb-usb/dib0700.h
@@ -37,6 +37,7 @@ struct dib0700_state {
u8 channel_state;
u16 mt2060_if1[2];
u8 rc_toggle;
+ u8 rc_counter;
u8 is_dib7000pc;
};
@@ -44,12 +45,15 @@ extern int dib0700_set_gpio(struct dvb_usb_device *, enum dib07x0_gpios gpio, u8
extern int dib0700_ctrl_clock(struct dvb_usb_device *d, u32 clk_MHz, u8 clock_out_gp3);
extern int dib0700_ctrl_rd(struct dvb_usb_device *d, u8 *tx, u8 txlen, u8 *rx, u8 rxlen);
extern int dib0700_download_firmware(struct usb_device *udev, const struct firmware *fw);
+extern int dib0700_rc_setup(struct dvb_usb_device *d);
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_device_count;
+extern int dvb_usb_dib0700_ir_proto;
extern struct dvb_usb_device_properties dib0700_devices[];
extern struct usb_device_id dib0700_usb_id_table[];
+
#endif
diff --git a/drivers/media/dvb/dvb-usb/dib0700_core.c b/drivers/media/dvb/dvb-usb/dib0700_core.c
index c9857d5c6982..4b3836e63be9 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_core.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_core.c
@@ -13,7 +13,7 @@ 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);
-static int dvb_usb_dib0700_ir_proto = 1;
+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).");
@@ -261,7 +261,7 @@ int dib0700_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
return dib0700_ctrl_wr(adap->dev, b, 4);
}
-static int dib0700_rc_setup(struct dvb_usb_device *d)
+int dib0700_rc_setup(struct dvb_usb_device *d)
{
u8 rc_setup[3] = {REQUEST_SET_RC, dvb_usb_dib0700_ir_proto, 0};
int i = dib0700_ctrl_wr(d, rc_setup, 3);
diff --git a/drivers/media/dvb/dvb-usb/dib0700_devices.c b/drivers/media/dvb/dvb-usb/dib0700_devices.c
index e7093826e975..6477fc66cc23 100644
--- a/drivers/media/dvb/dvb-usb/dib0700_devices.c
+++ b/drivers/media/dvb/dvb-usb/dib0700_devices.c
@@ -13,6 +13,7 @@
#include "dib7000p.h"
#include "mt2060.h"
#include "mt2266.h"
+#include "tuner-xc2028.h"
#include "dib0070.h"
static int force_lna_activation;
@@ -297,10 +298,156 @@ static int stk7700d_tuner_attach(struct dvb_usb_adapter *adap)
&stk7700d_mt2266_config[adap->id]) == NULL ? -ENODEV : 0;;
}
+/* STK7700-PH: Digital/Analog Hybrid Tuner, e.h. Cinergy HT USB HE */
+struct dibx000_agc_config xc3028_agc_config = {
+ BAND_VHF | BAND_UHF, /* band_caps */
+
+ /* P_agc_use_sd_mod1=0, P_agc_use_sd_mod2=0, P_agc_freq_pwm_div=0,
+ * P_agc_inv_pwm1=0, P_agc_inv_pwm2=0, P_agc_inh_dc_rv_est=0,
+ * P_agc_time_est=3, P_agc_freeze=0, P_agc_nb_est=2, P_agc_write=0 */
+ (0 << 15) | (0 << 14) | (0 << 11) | (0 << 10) | (0 << 9) | (0 << 8) |
+ (3 << 5) | (0 << 4) | (2 << 1) | (0 << 0), /* setup */
+
+ 712, /* inv_gain */
+ 21, /* time_stabiliz */
+
+ 0, /* alpha_level */
+ 118, /* thlock */
+
+ 0, /* wbd_inv */
+ 2867, /* wbd_ref */
+ 0, /* wbd_sel */
+ 2, /* wbd_alpha */
+
+ 0, /* agc1_max */
+ 0, /* agc1_min */
+ 39718, /* agc2_max */
+ 9930, /* agc2_min */
+ 0, /* agc1_pt1 */
+ 0, /* agc1_pt2 */
+ 0, /* agc1_pt3 */
+ 0, /* agc1_slope1 */
+ 0, /* agc1_slope2 */
+ 0, /* agc2_pt1 */
+ 128, /* agc2_pt2 */
+ 29, /* agc2_slope1 */
+ 29, /* agc2_slope2 */
+
+ 17, /* alpha_mant */
+ 27, /* alpha_exp */
+ 23, /* beta_mant */
+ 51, /* beta_exp */
+
+ 1, /* perform_agc_softsplit */
+};
+
+/* PLL Configuration for COFDM BW_MHz = 8.00 with external clock = 30.00 */
+struct dibx000_bandwidth_config xc3028_bw_config = {
+ 60000, 30000, /* internal, sampling */
+ 1, 8, 3, 1, 0, /* pll_cfg: prediv, ratio, range, reset, bypass */
+ 0, 0, 1, 1, 0, /* misc: refdiv, bypclk_div, IO_CLK_en_core, ADClkSrc,
+ modulo */
+ (3 << 14) | (1 << 12) | (524 << 0), /* sad_cfg: refsel, sel, freq_15k */
+ (1 << 25) | 5816102, /* ifreq = 5.200000 MHz */
+ 20452225, /* timf */
+ 30000000, /* xtal_hz */
+};
+
+static struct dib7000p_config stk7700ph_dib7700_xc3028_config = {
+ .output_mpeg2_in_188_bytes = 1,
+ .tuner_is_baseband = 1,
+
+ .agc_config_count = 1,
+ .agc = &xc3028_agc_config,
+ .bw = &xc3028_bw_config,
+
+ .gpio_dir = DIB7000P_GPIO_DEFAULT_DIRECTIONS,
+ .gpio_val = DIB7000P_GPIO_DEFAULT_VALUES,
+ .gpio_pwm_pos = DIB7000P_GPIO_DEFAULT_PWM_POS,
+};
+
+static int stk7700ph_xc3028_callback(void *ptr, int command, int arg)
+{
+ struct dvb_usb_adapter *adap = ptr;
+
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ /* Send the tuner in then out of reset */
+ dib7000p_set_gpio(adap->fe, 8, 0, 0); msleep(10);
+ dib7000p_set_gpio(adap->fe, 8, 0, 1);
+ break;
+ case XC2028_RESET_CLK:
+ break;
+ default:
+ err("%s: unknown command %d, arg %d\n", __func__,
+ command, arg);
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static struct xc2028_ctrl stk7700ph_xc3028_ctrl = {
+ .fname = XC2028_DEFAULT_FIRMWARE,
+ .max_len = 64,
+ .demod = XC3028_FE_DIBCOM52,
+};
+
+static struct xc2028_config stk7700ph_xc3028_config = {
+ .i2c_addr = 0x61,
+ .callback = stk7700ph_xc3028_callback,
+ .ctrl = &stk7700ph_xc3028_ctrl,
+};
+
+static int stk7700ph_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ struct usb_device_descriptor *desc = &adap->dev->udev->descriptor;
+
+ if (desc->idVendor == USB_VID_PINNACLE &&
+ desc->idProduct == USB_PID_PINNACLE_EXPRESSCARD_320CX)
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 0);
+ else
+ dib0700_set_gpio(adap->dev, GPIO6, GPIO_OUT, 1);
+ msleep(20);
+ 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);
+ msleep(10);
+ dib0700_set_gpio(adap->dev, GPIO10, GPIO_OUT, 1);
+ msleep(20);
+ dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
+ msleep(10);
+
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ &stk7700ph_dib7700_xc3028_config);
+
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ &stk7700ph_dib7700_xc3028_config);
+
+ return adap->fe == NULL ? -ENODEV : 0;
+}
+
+static int stk7700ph_tuner_attach(struct dvb_usb_adapter *adap)
+{
+ struct i2c_adapter *tun_i2c;
+
+ tun_i2c = dib7000p_get_i2c_master(adap->fe,
+ DIBX000_I2C_INTERFACE_TUNER, 1);
+
+ stk7700ph_xc3028_config.i2c_adap = tun_i2c;
+ stk7700ph_xc3028_config.video_dev = adap;
+
+ return dvb_attach(xc2028_attach, adap->fe, &stk7700ph_xc3028_config)
+ == NULL ? -ENODEV : 0;
+}
+
#define DEFAULT_RC_INTERVAL 150
static u8 rc_request[] = { REQUEST_POLL_RC, 0 };
+/* Number of keypresses to ignore before start repeating */
+#define RC_REPEAT_DELAY 2
+
static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
{
u8 key[4];
@@ -314,18 +461,67 @@ static int dib0700_rc_query(struct dvb_usb_device *d, u32 *event, int *state)
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[3-1]!=st->rc_toggle) {
+
+ /* 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: {
+ /* 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 (keymap[i].custom == key[3-2] && keymap[i].data == key[3-3]) {
+ st->rc_counter = 0;
+ *event = keymap[i].event;
+ *state = REMOTE_KEY_PRESSED;
+ d->last_event = keymap[i].event;
+ return 0;
+ }
+ }
+ break;
+ }
+ default: {
+ /* RC-5 protocol changes toggle bit on new keypress */
+ for (i = 0; i < d->props.rc_key_map_size; i++) {
+ if (keymap[i].custom == key[3-2] && keymap[i].data == 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];
+ st->rc_toggle = key[3-1];
+ d->last_event = keymap[i].event;
return 0;
}
}
- err("Unknown remote controller key : %2X %2X",(int)key[3-2],(int)key[3-3]);
+ 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;
}
@@ -794,6 +990,10 @@ static struct dib7000p_config dib7070p_dib7000p_config = {
/* STK7070P */
static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
{
+ if (adap->dev->udev->descriptor.idVendor == USB_VID_PINNACLE &&
+ adap->dev->udev->descriptor.idProduct == 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);
@@ -808,9 +1008,11 @@ static int stk7070p_frontend_attach(struct dvb_usb_adapter *adap)
msleep(10);
dib0700_set_gpio(adap->dev, GPIO0, GPIO_OUT, 1);
- dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18, &dib7070p_dib7000p_config);
+ dib7000p_i2c_enumeration(&adap->dev->i2c_adap, 1, 18,
+ &dib7070p_dib7000p_config);
- adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80, &dib7070p_dib7000p_config);
+ adap->fe = dvb_attach(dib7000p_attach, &adap->dev->i2c_adap, 0x80,
+ &dib7070p_dib7000p_config);
return adap->fe == NULL ? -ENODEV : 0;
}
@@ -878,34 +1080,43 @@ static int stk7070pd_frontend_attach1(struct dvb_usb_adapter *adap)
/* DVB-USB and USB stuff follows */
struct usb_device_id dib0700_usb_id_table[] = {
/* 0 */ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) },
-
- { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
- { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
- { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700P_PC) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_500_2) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK) },
/* 5 */ { USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR) },
- { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) },
- { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) },
- { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
- { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
+ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500) },
+ { USB_DEVICE(USB_VID_UNIWILL, USB_PID_UNIWILL_STK7700P) },
+ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_2) },
/* 10 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_VOLAR_2) },
- { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) },
- { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
- { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV2000E) },
+ { USB_DEVICE(USB_VID_TERRATEC,
+ USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_TD_STICK) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7700D) },
/* 15 */{ USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070P) },
- { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
- { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) },
- { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
- { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV_DVB_T_FLASH) },
+ { USB_DEVICE(USB_VID_DIBCOM, USB_PID_DIBCOM_STK7070PD) },
+ { USB_DEVICE(USB_VID_PINNACLE,
+ USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T) },
+ { USB_DEVICE(USB_VID_COMPRO, USB_PID_COMPRO_VIDEOMATE_U500_PC) },
/* 20 */{ USB_DEVICE(USB_VID_AVERMEDIA, USB_PID_AVERMEDIA_EXPRESS) },
- { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) },
- { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
- { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) },
- { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) },
-/* 25 */ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
- { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
- { 0 } /* Terminating entry */
+ { USB_DEVICE(USB_VID_GIGABYTE, USB_PID_GIGABYTE_U7000) },
+ { USB_DEVICE(USB_VID_ULTIMA_ELECTRONIC, USB_PID_ARTEC_T14BR) },
+ { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3000) },
+ { USB_DEVICE(USB_VID_ASUS, USB_PID_ASUS_U3100) },
+/* 25 */{ USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_NOVA_T_STICK_3) },
+ { USB_DEVICE(USB_VID_HAUPPAUGE, USB_PID_HAUPPAUGE_MYTV_T) },
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_USB_XE) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_EXPRESSCARD_320CX) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV72E) },
+/* 30 */{ USB_DEVICE(USB_VID_PINNACLE, USB_PID_PINNACLE_PCTV73E) },
+ { USB_DEVICE(USB_VID_YUAN, USB_PID_YUAN_EC372S) },
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_HT_EXPRESS) },
+ { USB_DEVICE(USB_VID_TERRATEC, USB_PID_TERRATEC_CINERGY_T_XXS) },
+ { USB_DEVICE(USB_VID_LEADTEK, USB_PID_WINFAST_DTV_DONGLE_STK7700P_2) },
+ { 0 } /* Terminating entry */
};
MODULE_DEVICE_TABLE(usb, dib0700_usb_id_table);
@@ -969,7 +1180,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
},
{ "Leadtek Winfast DTV Dongle (STK7700P based)",
- { &dib0700_usb_id_table[8], NULL },
+ { &dib0700_usb_id_table[8], &dib0700_usb_id_table[34] },
{ NULL },
},
{ "AVerMedia AVerTV DVB-T Express",
@@ -1069,12 +1280,16 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .num_device_descs = 1,
+ .num_device_descs = 2,
.devices = {
{ "ASUS My Cinema U3000 Mini DVBT Tuner",
{ &dib0700_usb_id_table[23], NULL },
{ NULL },
},
+ { "Yuan EC372S",
+ { &dib0700_usb_id_table[31], NULL },
+ { NULL },
+ }
}
}, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
@@ -1090,7 +1305,7 @@ struct dvb_usb_device_properties dib0700_devices[] = {
},
},
- .num_device_descs = 6,
+ .num_device_descs = 9,
.devices = {
{ "DiBcom STK7070P reference design",
{ &dib0700_usb_id_table[15], NULL },
@@ -1116,6 +1331,18 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ &dib0700_usb_id_table[26], NULL },
{ NULL },
},
+ { "Pinnacle PCTV 72e",
+ { &dib0700_usb_id_table[29], NULL },
+ { NULL },
+ },
+ { "Pinnacle PCTV 73e",
+ { &dib0700_usb_id_table[30], NULL },
+ { NULL },
+ },
+ { "Terratec Cinergy T USB XXS",
+ { &dib0700_usb_id_table[33], NULL },
+ { NULL },
+ },
},
.rc_interval = DEFAULT_RC_INTERVAL,
@@ -1155,6 +1382,40 @@ struct dvb_usb_device_properties dib0700_devices[] = {
{ NULL },
}
}
+ }, { DIB0700_DEFAULT_DEVICE_PROPERTIES,
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .frontend_attach = stk7700ph_frontend_attach,
+ .tuner_attach = stk7700ph_tuner_attach,
+
+ DIB0700_DEFAULT_STREAMING_CONFIG(0x02),
+
+ .size_of_priv = sizeof(struct
+ dib0700_adapter_state),
+ },
+ },
+
+ .num_device_descs = 3,
+ .devices = {
+ { "Terratec Cinergy HT USB XE",
+ { &dib0700_usb_id_table[27], NULL },
+ { NULL },
+ },
+ { "Pinnacle Expresscard 320cx",
+ { &dib0700_usb_id_table[28], NULL },
+ { NULL },
+ },
+ { "Terratec Cinergy HT Express",
+ { &dib0700_usb_id_table[32], NULL },
+ { NULL },
+ },
+ },
+ .rc_interval = DEFAULT_RC_INTERVAL,
+ .rc_key_map = dib0700_rc_keys,
+ .rc_key_map_size = ARRAY_SIZE(dib0700_rc_keys),
+ .rc_query = dib0700_rc_query
},
};
diff --git a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index aa4844ef875e..34245d1b7dd9 100644
--- a/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -40,14 +40,15 @@
#define USB_VID_MSI 0x0db0
#define USB_VID_OPERA1 0x695c
#define USB_VID_PINNACLE 0x2304
+#define USB_VID_TECHNOTREND 0x0b48
#define USB_VID_TERRATEC 0x0ccd
#define USB_VID_VISIONPLUS 0x13d3
#define USB_VID_TWINHAN 0x1822
#define USB_VID_ULTIMA_ELECTRONIC 0x05d8
#define USB_VID_UNIWILL 0x1584
#define USB_VID_WIDEVIEW 0x14aa
-/* dom : pour gigabyte u7000 */
#define USB_VID_GIGABYTE 0x1044
+#define USB_VID_YUAN 0x1164
/* Product IDs */
@@ -134,10 +135,17 @@
#define USB_PID_AVERMEDIA_EXPRESS 0xb568
#define USB_PID_AVERMEDIA_VOLAR 0xa807
#define USB_PID_AVERMEDIA_VOLAR_2 0xb808
+#define USB_PID_TECHNOTREND_CONNECT_S2400 0x3006
#define USB_PID_TERRATEC_CINERGY_DT_XS_DIVERSITY 0x005a
+#define USB_PID_TERRATEC_CINERGY_HT_USB_XE 0x0058
+#define USB_PID_TERRATEC_CINERGY_HT_EXPRESS 0x0060
+#define USB_PID_TERRATEC_CINERGY_T_XXS 0x0078
+#define USB_PID_PINNACLE_EXPRESSCARD_320CX 0x022e
#define USB_PID_PINNACLE_PCTV2000E 0x022c
#define USB_PID_PINNACLE_PCTV_DVB_T_FLASH 0x0228
#define USB_PID_PINNACLE_PCTV_DUAL_DIVERSITY_DVB_T 0x0229
+#define USB_PID_PINNACLE_PCTV72E 0x0236
+#define USB_PID_PINNACLE_PCTV73E 0x0237
#define USB_PID_PCTV_200E 0x020e
#define USB_PID_PCTV_400E 0x020f
#define USB_PID_PCTV_450E 0x0222
@@ -172,6 +180,7 @@
#define USB_PID_WINFAST_DTV_DONGLE_COLD 0x6025
#define USB_PID_WINFAST_DTV_DONGLE_WARM 0x6026
#define USB_PID_WINFAST_DTV_DONGLE_STK7700P 0x6f00
+#define USB_PID_WINFAST_DTV_DONGLE_STK7700P_2 0x6f01
#define USB_PID_GENPIX_8PSK_REV_1_COLD 0x0200
#define USB_PID_GENPIX_8PSK_REV_1_WARM 0x0201
#define USB_PID_GENPIX_8PSK_REV_2 0x0202
@@ -183,9 +192,9 @@
#define USB_PID_OPERA1_WARM 0x3829
#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_COLD 0x0514
#define USB_PID_LIFEVIEW_TV_WALKER_TWIN_WARM 0x0513
-/* dom pour gigabyte u7000 */
#define USB_PID_GIGABYTE_U7000 0x7001
#define USB_PID_ASUS_U3000 0x171f
#define USB_PID_ASUS_U3100 0x173f
+#define USB_PID_YUAN_EC372S 0x1edc
#endif
diff --git a/drivers/media/dvb/dvb-usb/ttusb2.c b/drivers/media/dvb/dvb-usb/ttusb2.c
index 3b9da9c25c6e..0eb33378254b 100644
--- a/drivers/media/dvb/dvb-usb/ttusb2.c
+++ b/drivers/media/dvb/dvb-usb/ttusb2.c
@@ -176,17 +176,23 @@ 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 int ttusb2_probe(struct usb_interface *intf,
const struct usb_device_id *id)
{
- return dvb_usb_device_init(intf,&ttusb2_properties,THIS_MODULE,NULL);
+ if (dvb_usb_device_init(intf, &ttusb2_properties, THIS_MODULE, NULL) == 0 ||
+ dvb_usb_device_init(intf, &ttusb2_properties_s2400, THIS_MODULE, NULL) == 0)
+ return 0;
+ return -ENODEV;
}
static struct usb_device_id ttusb2_table [] = {
- { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
- { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
- {} /* Terminating entry */
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_400E) },
+ { USB_DEVICE(USB_VID_PINNACLE, USB_PID_PCTV_450E) },
+ { USB_DEVICE(USB_VID_TECHNOTREND,
+ USB_PID_TECHNOTREND_CONNECT_S2400) },
+ {} /* Terminating entry */
};
MODULE_DEVICE_TABLE (usb, ttusb2_table);
@@ -242,6 +248,54 @@ static struct dvb_usb_device_properties ttusb2_properties = {
}
};
+static struct dvb_usb_device_properties ttusb2_properties_s2400 = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+
+ .usb_ctrl = CYPRESS_FX2,
+ .firmware = "dvb-usb-tt-s2400-01.fw",
+
+ .size_of_priv = sizeof(struct ttusb2_state),
+
+ .num_adapters = 1,
+ .adapter = {
+ {
+ .streaming_ctrl = NULL,
+
+ .frontend_attach = ttusb2_frontend_attach,
+ .tuner_attach = ttusb2_tuner_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 S-2400",
+ { &ttusb2_table[2], NULL },
+ { NULL },
+ },
+ }
+};
+
static struct usb_driver ttusb2_driver = {
.name = "dvb_usb_ttusb2",
.probe = ttusb2_probe,
diff --git a/drivers/media/dvb/frontends/Kconfig b/drivers/media/dvb/frontends/Kconfig
index 9ad86ce4a4e5..0209644f222a 100644
--- a/drivers/media/dvb/frontends/Kconfig
+++ b/drivers/media/dvb/frontends/Kconfig
@@ -379,6 +379,13 @@ config DVB_LNBP21
help
An SEC control chip.
+config DVB_ISL6405
+ tristate "ISL6405 SEC controller"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ An SEC control chip.
+
config DVB_ISL6421
tristate "ISL6421 SEC controller"
depends on DVB_CORE && I2C
diff --git a/drivers/media/dvb/frontends/Makefile b/drivers/media/dvb/frontends/Makefile
index 16bd107ebd32..23304b3774b5 100644
--- a/drivers/media/dvb/frontends/Makefile
+++ b/drivers/media/dvb/frontends/Makefile
@@ -38,6 +38,7 @@ obj-$(CONFIG_DVB_S5H1420) += s5h1420.o
obj-$(CONFIG_DVB_LGDT330X) += lgdt330x.o
obj-$(CONFIG_DVB_CX24123) += cx24123.o
obj-$(CONFIG_DVB_LNBP21) += lnbp21.o
+obj-$(CONFIG_DVB_ISL6405) += isl6405.o
obj-$(CONFIG_DVB_ISL6421) += isl6421.o
obj-$(CONFIG_DVB_TDA10086) += tda10086.o
obj-$(CONFIG_DVB_TDA826X) += tda826x.o
diff --git a/drivers/media/dvb/frontends/cx22702.c b/drivers/media/dvb/frontends/cx22702.c
index 1dc164d5488c..406c4cfa82bb 100644
--- a/drivers/media/dvb/frontends/cx22702.c
+++ b/drivers/media/dvb/frontends/cx22702.c
@@ -48,7 +48,7 @@ struct cx22702_state {
u8 prevUCBlocks;
};
-static int debug = 0;
+static int debug;
#define dprintk if (debug) printk
/* Register values to initialise the demod */
diff --git a/drivers/media/dvb/frontends/cx24123.c b/drivers/media/dvb/frontends/cx24123.c
index d74fdbd63361..7f68d78c6558 100644
--- a/drivers/media/dvb/frontends/cx24123.c
+++ b/drivers/media/dvb/frontends/cx24123.c
@@ -1,24 +1,26 @@
/*
- Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
-
- Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
-
- Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
-
- This program is free software; 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.
-*/
+ * Conexant cx24123/cx24109 - DVB QPSK Satellite demod/tuner driver
+ *
+ * Copyright (C) 2005 Steven Toth <stoth@hauppauge.com>
+ *
+ * Support for KWorld DVB-S 100 by Vadim Catana <skystar@moldova.cc>
+ *
+ * Support for CX24123/CX24113-NIM by Patrick Boettcher <pb@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 the Free Software Foundation; either version 2 of
+ * the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#include <linux/slab.h>
#include <linux/kernel.h>
@@ -32,9 +34,16 @@
static int force_band;
static int debug;
+
+#define info(args...) do { printk(KERN_INFO "CX24123: " args); } while (0)
+#define err(args...) do { printk(KERN_ERR "CX24123: " args); } while (0)
+
#define dprintk(args...) \
do { \
- if (debug) printk (KERN_DEBUG "cx24123: " args); \
+ if (debug) { \
+ printk(KERN_DEBUG "CX24123: %s: ", __func__); \
+ printk(args); \
+ } \
} while (0)
struct cx24123_state
@@ -51,6 +60,10 @@ struct cx24123_state
u32 pllarg;
u32 FILTune;
+ struct i2c_adapter tuner_i2c_adapter;
+
+ u8 demod_rev;
+
/* The Demod/Tuner can't easily provide these, we cache them */
u32 currentfreq;
u32 currentsymbolrate;
@@ -225,48 +238,52 @@ static struct {
{0x67, 0x83}, /* Non-DCII symbol clock */
};
-static int cx24123_writereg(struct cx24123_state* state, int reg, int data)
+static int cx24123_i2c_writereg(struct cx24123_state *state,
+ u8 i2c_addr, int reg, int data)
{
u8 buf[] = { reg, data };
- struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
+ struct i2c_msg msg = {
+ .addr = i2c_addr, .flags = 0, .buf = buf, .len = 2
+ };
int err;
- if (debug>1)
- printk("cx24123: %s: write reg 0x%02x, value 0x%02x\n",
- __FUNCTION__,reg, data);
+ /* printk(KERN_DEBUG "wr(%02x): %02x %02x\n", i2c_addr, reg, data); */
if ((err = i2c_transfer(state->i2c, &msg, 1)) != 1) {
printk("%s: writereg error(err == %i, reg == 0x%02x,"
- " data == 0x%02x)\n", __FUNCTION__, err, reg, data);
- return -EREMOTEIO;
+ " data == 0x%02x)\n", __func__, err, reg, data);
+ return err;
}
return 0;
}
-static int cx24123_readreg(struct cx24123_state* state, u8 reg)
+static int cx24123_i2c_readreg(struct cx24123_state *state, u8 i2c_addr, u8 reg)
{
int ret;
- u8 b0[] = { reg };
- u8 b1[] = { 0 };
+ u8 b = 0;
struct i2c_msg msg[] = {
- { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 },
- { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 }
+ { .addr = i2c_addr, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = i2c_addr, .flags = I2C_M_RD, .buf = &b, .len = 1 }
};
ret = i2c_transfer(state->i2c, msg, 2);
if (ret != 2) {
- printk("%s: reg=0x%x (error=%d)\n", __FUNCTION__, reg, ret);
+ err("%s: reg=0x%x (error=%d)\n", __func__, reg, ret);
return ret;
}
- if (debug>1)
- printk("cx24123: read reg 0x%02x, value 0x%02x\n",reg, ret);
+ /* printk(KERN_DEBUG "rd(%02x): %02x %02x\n", i2c_addr, reg, b); */
- return b1[0];
+ return b;
}
+#define cx24123_readreg(state, reg) \
+ cx24123_i2c_readreg(state, state->config->demod_address, reg)
+#define cx24123_writereg(state, reg, val) \
+ cx24123_i2c_writereg(state, state->config->demod_address, reg, val)
+
static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_inversion_t inversion)
{
u8 nom_reg = cx24123_readreg(state, 0x0e);
@@ -274,17 +291,17 @@ static int cx24123_set_inversion(struct cx24123_state* state, fe_spectral_invers
switch (inversion) {
case INVERSION_OFF:
- dprintk("%s: inversion off\n",__FUNCTION__);
+ dprintk("inversion off\n");
cx24123_writereg(state, 0x0e, nom_reg & ~0x80);
cx24123_writereg(state, 0x10, auto_reg | 0x80);
break;
case INVERSION_ON:
- dprintk("%s: inversion on\n",__FUNCTION__);
+ dprintk("inversion on\n");
cx24123_writereg(state, 0x0e, nom_reg | 0x80);
cx24123_writereg(state, 0x10, auto_reg | 0x80);
break;
case INVERSION_AUTO:
- dprintk("%s: inversion auto\n",__FUNCTION__);
+ dprintk("inversion auto\n");
cx24123_writereg(state, 0x10, auto_reg & ~0x80);
break;
default:
@@ -301,10 +318,10 @@ static int cx24123_get_inversion(struct cx24123_state* state, fe_spectral_invers
val = cx24123_readreg(state, 0x1b) >> 7;
if (val == 0) {
- dprintk("%s: read inversion off\n",__FUNCTION__);
+ dprintk("read inversion off\n");
*inversion = INVERSION_OFF;
} else {
- dprintk("%s: read inversion on\n",__FUNCTION__);
+ dprintk("read inversion on\n");
*inversion = INVERSION_ON;
}
@@ -326,42 +343,42 @@ static int cx24123_set_fec(struct cx24123_state* state, fe_code_rate_t fec)
switch (fec) {
case FEC_1_2:
- dprintk("%s: set FEC to 1/2\n",__FUNCTION__);
+ dprintk("set FEC to 1/2\n");
cx24123_writereg(state, 0x0e, nom_reg | 0x01);
cx24123_writereg(state, 0x0f, 0x02);
break;
case FEC_2_3:
- dprintk("%s: set FEC to 2/3\n",__FUNCTION__);
+ dprintk("set FEC to 2/3\n");
cx24123_writereg(state, 0x0e, nom_reg | 0x02);
cx24123_writereg(state, 0x0f, 0x04);
break;
case FEC_3_4:
- dprintk("%s: set FEC to 3/4\n",__FUNCTION__);
+ dprintk("set FEC to 3/4\n");
cx24123_writereg(state, 0x0e, nom_reg | 0x03);
cx24123_writereg(state, 0x0f, 0x08);
break;
case FEC_4_5:
- dprintk("%s: set FEC to 4/5\n",__FUNCTION__);
+ dprintk("set FEC to 4/5\n");
cx24123_writereg(state, 0x0e, nom_reg | 0x04);
cx24123_writereg(state, 0x0f, 0x10);
break;
case FEC_5_6:
- dprintk("%s: set FEC to 5/6\n",__FUNCTION__);
+ dprintk("set FEC to 5/6\n");
cx24123_writereg(state, 0x0e, nom_reg | 0x05);
cx24123_writereg(state, 0x0f, 0x20);
break;
case FEC_6_7:
- dprintk("%s: set FEC to 6/7\n",__FUNCTION__);
+ dprintk("set FEC to 6/7\n");
cx24123_writereg(state, 0x0e, nom_reg | 0x06);
cx24123_writereg(state, 0x0f, 0x40);
break;
case FEC_7_8:
- dprintk("%s: set FEC to 7/8\n",__FUNCTION__);
+ dprintk("set FEC to 7/8\n");
cx24123_writereg(state, 0x0e, nom_reg | 0x07);
cx24123_writereg(state, 0x0f, 0x80);
break;
case FEC_AUTO:
- dprintk("%s: set FEC to auto\n",__FUNCTION__);
+ dprintk("set FEC to auto\n");
cx24123_writereg(state, 0x0f, 0xfe);
break;
default:
@@ -490,7 +507,8 @@ static int cx24123_set_symbolrate(struct cx24123_state* state, u32 srate)
tmp = cx24123_readreg(state, 0x0c) & ~0xe0;
cx24123_writereg(state, 0x0c, tmp | sample_gain << 5);
- dprintk("%s: srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n", __FUNCTION__, srate, ratio, sample_rate, sample_gain);
+ dprintk("srate=%d, ratio=0x%08x, sample_rate=%i sample_gain=%d\n",
+ srate, ratio, sample_rate, sample_gain);
return 0;
}
@@ -570,7 +588,7 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
struct cx24123_state *state = fe->demodulator_priv;
unsigned long timeout;
- dprintk("%s: pll writereg called, data=0x%08x\n",__FUNCTION__,data);
+ dprintk("pll writereg called, data=0x%08x\n", data);
/* align the 21 bytes into to bit23 boundary */
data = data << 3;
@@ -583,7 +601,8 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
cx24123_writereg(state, 0x22, (data >> 16) & 0xff);
while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
if (time_after(jiffies, timeout)) {
- printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+ err("%s: demodulator is not responding, "\
+ "possibly hung, aborting.\n", __func__);
return -EREMOTEIO;
}
msleep(10);
@@ -594,7 +613,8 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
cx24123_writereg(state, 0x22, (data>>8) & 0xff );
while ((cx24123_readreg(state, 0x20) & 0x40) == 0) {
if (time_after(jiffies, timeout)) {
- printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+ err("%s: demodulator is not responding, "\
+ "possibly hung, aborting.\n", __func__);
return -EREMOTEIO;
}
msleep(10);
@@ -605,7 +625,8 @@ static int cx24123_pll_writereg(struct dvb_frontend* fe, struct dvb_frontend_par
cx24123_writereg(state, 0x22, (data) & 0xff );
while ((cx24123_readreg(state, 0x20) & 0x80)) {
if (time_after(jiffies, timeout)) {
- printk("%s: demodulator is not responding, possibly hung, aborting.\n", __FUNCTION__);
+ err("%s: demodulator is not responding," \
+ "possibly hung, aborting.\n", __func__);
return -EREMOTEIO;
}
msleep(10);
@@ -626,7 +647,7 @@ static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_paramet
dprintk("frequency=%i\n", p->frequency);
if (cx24123_pll_calculate(fe, p) != 0) {
- printk("%s: cx24123_pll_calcutate failed\n",__FUNCTION__);
+ err("%s: cx24123_pll_calcutate failed\n", __func__);
return -EINVAL;
}
@@ -643,18 +664,38 @@ static int cx24123_pll_tune(struct dvb_frontend* fe, struct dvb_frontend_paramet
cx24123_writereg(state, 0x27, state->FILTune >> 2);
cx24123_writereg(state, 0x28, val | (state->FILTune & 0x3));
- dprintk("%s: pll tune VCA=%d, band=%d, pll=%d\n",__FUNCTION__,state->VCAarg,
- state->bandselectarg,state->pllarg);
+ dprintk("pll tune VCA=%d, band=%d, pll=%d\n", state->VCAarg,
+ state->bandselectarg, state->pllarg);
return 0;
}
+
+/*
+ * 0x23:
+ * [7:7] = BTI enabled
+ * [6:6] = I2C repeater enabled
+ * [5:5] = I2C repeater start
+ * [0:0] = BTI start
+ */
+
+/* mode == 1 -> i2c-repeater, 0 -> bti */
+static int cx24123_repeater_mode(struct cx24123_state *state, u8 mode, u8 start)
+{
+ u8 r = cx24123_readreg(state, 0x23) & 0x1e;
+ if (mode)
+ r |= (1 << 6) | (start << 5);
+ else
+ r |= (1 << 7) | (start);
+ return cx24123_writereg(state, 0x23, r);
+}
+
static int cx24123_initfe(struct dvb_frontend* fe)
{
struct cx24123_state *state = fe->demodulator_priv;
int i;
- dprintk("%s: init frontend\n",__FUNCTION__);
+ dprintk("init frontend\n");
/* Configure the demod to a good set of defaults */
for (i = 0; i < ARRAY_SIZE(cx24123_regdata); i++)
@@ -664,6 +705,9 @@ static int cx24123_initfe(struct dvb_frontend* fe)
if(state->config->lnb_polarity)
cx24123_writereg(state, 0x32, cx24123_readreg(state, 0x32) | 0x02);
+ if (state->config->dont_use_pll)
+ cx24123_repeater_mode(state, 1, 0);
+
return 0;
}
@@ -676,10 +720,10 @@ static int cx24123_set_voltage(struct dvb_frontend* fe, fe_sec_voltage_t voltage
switch (voltage) {
case SEC_VOLTAGE_13:
- dprintk("%s: setting voltage 13V\n", __FUNCTION__);
+ dprintk("setting voltage 13V\n");
return cx24123_writereg(state, 0x29, val & 0x7f);
case SEC_VOLTAGE_18:
- dprintk("%s: setting voltage 18V\n", __FUNCTION__);
+ dprintk("setting voltage 18V\n");
return cx24123_writereg(state, 0x29, val | 0x80);
case SEC_VOLTAGE_OFF:
/* already handled in cx88-dvb */
@@ -697,7 +741,8 @@ static void cx24123_wait_for_diseqc(struct cx24123_state *state)
unsigned long timeout = jiffies + msecs_to_jiffies(200);
while (!(cx24123_readreg(state, 0x29) & 0x40)) {
if(time_after(jiffies, timeout)) {
- printk("%s: diseqc queue not ready, command may be lost.\n", __FUNCTION__);
+ err("%s: diseqc queue not ready, " \
+ "command may be lost.\n", __func__);
break;
}
msleep(10);
@@ -709,7 +754,7 @@ static int cx24123_send_diseqc_msg(struct dvb_frontend* fe, struct dvb_diseqc_ma
struct cx24123_state *state = fe->demodulator_priv;
int i, val, tone;
- dprintk("%s:\n",__FUNCTION__);
+ dprintk("\n");
/* stop continuous tone if enabled */
tone = cx24123_readreg(state, 0x29);
@@ -744,7 +789,7 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
struct cx24123_state *state = fe->demodulator_priv;
int val, tone;
- dprintk("%s:\n", __FUNCTION__);
+ dprintk("\n");
/* stop continuous tone if enabled */
tone = cx24123_readreg(state, 0x29);
@@ -778,13 +823,21 @@ static int cx24123_diseqc_send_burst(struct dvb_frontend* fe, fe_sec_mini_cmd_t
static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
{
struct cx24123_state *state = fe->demodulator_priv;
-
int sync = cx24123_readreg(state, 0x14);
- int lock = cx24123_readreg(state, 0x20);
*status = 0;
- if (lock & 0x01)
- *status |= FE_HAS_SIGNAL;
+ if (state->config->dont_use_pll) {
+ u32 tun_status = 0;
+ if (fe->ops.tuner_ops.get_status)
+ fe->ops.tuner_ops.get_status(fe, &tun_status);
+ if (tun_status & TUNER_STATUS_LOCKED)
+ *status |= FE_HAS_SIGNAL;
+ } else {
+ int lock = cx24123_readreg(state, 0x20);
+ if (lock & 0x01)
+ *status |= FE_HAS_SIGNAL;
+ }
+
if (sync & 0x02)
*status |= FE_HAS_CARRIER; /* Phase locked */
if (sync & 0x04)
@@ -803,7 +856,7 @@ static int cx24123_read_status(struct dvb_frontend* fe, fe_status_t* status)
* Configured to return the measurement of errors in blocks, because no UCBLOCKS value
* is available, so this value doubles up to satisfy both measurements
*/
-static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
+static int cx24123_read_ber(struct dvb_frontend *fe, u32 *ber)
{
struct cx24123_state *state = fe->demodulator_priv;
@@ -813,23 +866,24 @@ static int cx24123_read_ber(struct dvb_frontend* fe, u32* ber)
(cx24123_readreg(state, 0x1d) << 8 |
cx24123_readreg(state, 0x1e));
- dprintk("%s: BER = %d\n",__FUNCTION__,*ber);
+ dprintk("BER = %d\n", *ber);
return 0;
}
-static int cx24123_read_signal_strength(struct dvb_frontend* fe, u16* signal_strength)
+static int cx24123_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
{
struct cx24123_state *state = fe->demodulator_priv;
*signal_strength = cx24123_readreg(state, 0x3b) << 8; /* larger = better */
- dprintk("%s: Signal strength = %d\n",__FUNCTION__,*signal_strength);
+ dprintk("Signal strength = %d\n", *signal_strength);
return 0;
}
-static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
+static int cx24123_read_snr(struct dvb_frontend *fe, u16 *snr)
{
struct cx24123_state *state = fe->demodulator_priv;
@@ -838,16 +892,17 @@ static int cx24123_read_snr(struct dvb_frontend* fe, u16* snr)
*snr = 65535 - (((u16)cx24123_readreg(state, 0x18) << 8) |
(u16)cx24123_readreg(state, 0x19));
- dprintk("%s: read S/N index = %d\n",__FUNCTION__,*snr);
+ dprintk("read S/N index = %d\n", *snr);
return 0;
}
-static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
+static int cx24123_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
{
struct cx24123_state *state = fe->demodulator_priv;
- dprintk("%s: set_frontend\n",__FUNCTION__);
+ dprintk("\n");
if (state->config->set_ts_params)
state->config->set_ts_params(fe, 0);
@@ -858,13 +913,22 @@ static int cx24123_set_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
cx24123_set_inversion(state, p->inversion);
cx24123_set_fec(state, p->u.qpsk.fec_inner);
cx24123_set_symbolrate(state, p->u.qpsk.symbol_rate);
- cx24123_pll_tune(fe, p);
+
+ if (!state->config->dont_use_pll)
+ cx24123_pll_tune(fe, p);
+ else if (fe->ops.tuner_ops.set_params)
+ fe->ops.tuner_ops.set_params(fe, p);
+ else
+ err("it seems I don't have a tuner...");
/* Enable automatic aquisition and reset cycle */
cx24123_writereg(state, 0x03, (cx24123_readreg(state, 0x03) | 0x07));
cx24123_writereg(state, 0x00, 0x10);
cx24123_writereg(state, 0x00, 0);
+ if (state->config->agc_callback)
+ state->config->agc_callback(fe);
+
return 0;
}
@@ -872,14 +936,14 @@ static int cx24123_get_frontend(struct dvb_frontend* fe, struct dvb_frontend_par
{
struct cx24123_state *state = fe->demodulator_priv;
- dprintk("%s: get_frontend\n",__FUNCTION__);
+ dprintk("\n");
if (cx24123_get_inversion(state, &p->inversion) != 0) {
- printk("%s: Failed to get inversion status\n",__FUNCTION__);
+ err("%s: Failed to get inversion status\n", __func__);
return -EREMOTEIO;
}
if (cx24123_get_fec(state, &p->u.qpsk.fec_inner) != 0) {
- printk("%s: Failed to get fec status\n",__FUNCTION__);
+ err("%s: Failed to get fec status\n", __func__);
return -EREMOTEIO;
}
p->frequency = state->currentfreq;
@@ -900,13 +964,13 @@ static int cx24123_set_tone(struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
switch (tone) {
case SEC_TONE_ON:
- dprintk("%s: setting tone on\n", __FUNCTION__);
+ dprintk("setting tone on\n");
return cx24123_writereg(state, 0x29, val | 0x10);
case SEC_TONE_OFF:
- dprintk("%s: setting tone off\n",__FUNCTION__);
+ dprintk("setting tone off\n");
return cx24123_writereg(state, 0x29, val & 0xef);
default:
- printk("%s: CASE reached default with tone=%d\n", __FUNCTION__, tone);
+ err("CASE reached default with tone=%d\n", tone);
return -EINVAL;
}
@@ -939,47 +1003,86 @@ static int cx24123_get_algo(struct dvb_frontend *fe)
static void cx24123_release(struct dvb_frontend* fe)
{
struct cx24123_state* state = fe->demodulator_priv;
- dprintk("%s\n",__FUNCTION__);
+ dprintk("\n");
+ i2c_del_adapter(&state->tuner_i2c_adapter);
kfree(state);
}
+static int cx24123_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg msg[], int num)
+{
+ struct cx24123_state *state = i2c_get_adapdata(i2c_adap);
+ /* this repeater closes after the first stop */
+ cx24123_repeater_mode(state, 1, 1);
+ return i2c_transfer(state->i2c, msg, num);
+}
+
+static u32 cx24123_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm cx24123_tuner_i2c_algo = {
+ .master_xfer = cx24123_tuner_i2c_tuner_xfer,
+ .functionality = cx24123_tuner_i2c_func,
+};
+
+struct i2c_adapter *
+ cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+ struct cx24123_state *state = fe->demodulator_priv;
+ return &state->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(cx24123_get_tuner_i2c_adapter);
+
static struct dvb_frontend_ops cx24123_ops;
struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
struct i2c_adapter* i2c)
{
- struct cx24123_state* state = NULL;
- int ret;
-
- dprintk("%s\n",__FUNCTION__);
+ struct cx24123_state *state =
+ kzalloc(sizeof(struct cx24123_state), GFP_KERNEL);
+ dprintk("\n");
/* allocate memory for the internal state */
- state = kmalloc(sizeof(struct cx24123_state), GFP_KERNEL);
if (state == NULL) {
- printk("Unable to kmalloc\n");
+ err("Unable to kmalloc\n");
goto error;
}
/* setup the state */
state->config = config;
state->i2c = i2c;
- state->VCAarg = 0;
- state->VGAarg = 0;
- state->bandselectarg = 0;
- state->pllarg = 0;
- state->currentfreq = 0;
- state->currentsymbolrate = 0;
/* check if the demod is there */
- ret = cx24123_readreg(state, 0x00);
- if ((ret != 0xd1) && (ret != 0xe1)) {
- printk("Version != d1 or e1\n");
+ state->demod_rev = cx24123_readreg(state, 0x00);
+ switch (state->demod_rev) {
+ case 0xe1: info("detected CX24123C\n"); break;
+ case 0xd1: info("detected CX24123\n"); break;
+ default:
+ err("wrong demod revision: %x\n", state->demod_rev);
goto error;
}
/* create dvb_frontend */
memcpy(&state->frontend.ops, &cx24123_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
+
+ /* create tuner i2c adapter */
+ if (config->dont_use_pll)
+ cx24123_repeater_mode(state, 1, 0);
+
+ strncpy(state->tuner_i2c_adapter.name,
+ "CX24123 tuner I2C bus", I2C_NAME_SIZE);
+ 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);
+ if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
+ err("tuner i2c bus could not be initialized\n");
+ goto error;
+ }
+
return &state->frontend;
error:
@@ -1029,7 +1132,8 @@ MODULE_PARM_DESC(debug, "Activates frontend debugging (default:0)");
module_param(force_band, int, 0644);
MODULE_PARM_DESC(force_band, "Force a specific band select (1-9, default:off).");
-MODULE_DESCRIPTION("DVB Frontend module for Conexant cx24123/cx24109 hardware");
+MODULE_DESCRIPTION("DVB Frontend module for Conexant " \
+ "CX24123/CX24109/CX24113 hardware");
MODULE_AUTHOR("Steven Toth");
MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/cx24123.h b/drivers/media/dvb/frontends/cx24123.h
index 84f9e4f5c15e..81ebc3d2f19f 100644
--- a/drivers/media/dvb/frontends/cx24123.h
+++ b/drivers/media/dvb/frontends/cx24123.h
@@ -33,16 +33,27 @@ struct cx24123_config
/* 0 = LNB voltage normal, 1 = LNB voltage inverted */
int lnb_polarity;
+
+ /* this device has another tuner */
+ u8 dont_use_pll;
+ void (*agc_callback) (struct dvb_frontend *);
};
#if defined(CONFIG_DVB_CX24123) || (defined(CONFIG_DVB_CX24123_MODULE) && defined(MODULE))
-extern struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
- struct i2c_adapter* i2c);
+extern struct dvb_frontend *cx24123_attach(const struct cx24123_config *config,
+ struct i2c_adapter *i2c);
+extern struct i2c_adapter *cx24123_get_tuner_i2c_adapter(struct dvb_frontend *);
#else
-static inline struct dvb_frontend* cx24123_attach(const struct cx24123_config* config,
- struct i2c_adapter* i2c)
+static inline struct dvb_frontend *cx24123_attach(
+ const struct cx24123_config *config, struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+static struct i2c_adapter *
+ cx24123_get_tuner_i2c_adapter(struct dvb_frontend *fe)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif // CONFIG_DVB_CX24123
diff --git a/drivers/media/dvb/frontends/dvb-pll.c b/drivers/media/dvb/frontends/dvb-pll.c
index 8c8d7342d0b3..a054894ff481 100644
--- a/drivers/media/dvb/frontends/dvb-pll.c
+++ b/drivers/media/dvb/frontends/dvb-pll.c
@@ -44,14 +44,10 @@ struct dvb_pll_priv {
static unsigned int dvb_pll_devcount;
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
-static unsigned int input[DVB_PLL_MAX] = { [ 0 ... (DVB_PLL_MAX-1) ] = 0 };
-module_param_array(input, int, NULL, 0644);
-MODULE_PARM_DESC(input,"specify rf input choice, 0 for autoselect (default)");
-
static unsigned int id[DVB_PLL_MAX] =
{ [ 0 ... (DVB_PLL_MAX-1) ] = DVB_PLL_UNDEFINED };
module_param_array(id, int, NULL, 0644);
@@ -80,23 +76,6 @@ struct dvb_pll_desc {
/* ----------------------------------------------------------- */
/* descriptions */
-/* Set AGC TOP value to 103 dBuV:
- 0x80 = Control Byte
- 0x40 = 250 uA charge pump (irrelevant)
- 0x18 = Aux Byte to follow
- 0x06 = 64.5 kHz divider (irrelevant)
- 0x01 = Disable Vt (aka sleep)
-
- 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
- 0x50 = AGC Take over point = 103 dBuV */
-static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
-
-/* 0x04 = 166.67 kHz divider
-
- 0x80 = AGC Time constant 50ms Iagc = 9 uA
- 0x20 = AGC Take over point = 112 dBuV */
-static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
-
static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
.name = "Thomson dtt7579",
.min = 177000000,
@@ -112,19 +91,6 @@ static struct dvb_pll_desc dvb_pll_thomson_dtt7579 = {
},
};
-static struct dvb_pll_desc dvb_pll_thomson_dtt7610 = {
- .name = "Thomson dtt7610",
- .min = 44000000,
- .max = 958000000,
- .iffreq= 44000000,
- .count = 3,
- .entries = {
- { 157250000, 62500, 0x8e, 0x39 },
- { 454000000, 62500, 0x8e, 0x3a },
- { 999999999, 62500, 0x8e, 0x3c },
- },
-};
-
static void thomson_dtt759x_bw(struct dvb_frontend *fe, u8 *buf,
const struct dvb_frontend_parameters *params)
{
@@ -165,34 +131,6 @@ static struct dvb_pll_desc dvb_pll_lg_z201 = {
},
};
-static struct dvb_pll_desc dvb_pll_microtune_4042 = {
- .name = "Microtune 4042 FI5",
- .min = 57000000,
- .max = 858000000,
- .iffreq= 44000000,
- .count = 3,
- .entries = {
- { 162000000, 62500, 0x8e, 0xa1 },
- { 457000000, 62500, 0x8e, 0x91 },
- { 999999999, 62500, 0x8e, 0x31 },
- },
-};
-
-static struct dvb_pll_desc dvb_pll_thomson_dtt761x = {
- /* DTT 7611 7611A 7612 7613 7613A 7614 7615 7615A */
- .name = "Thomson dtt761x",
- .min = 57000000,
- .max = 863000000,
- .iffreq= 44000000,
- .count = 3,
- .initdata = tua603x_agc103,
- .entries = {
- { 147000000, 62500, 0x8e, 0x39 },
- { 417000000, 62500, 0x8e, 0x3a },
- { 999999999, 62500, 0x8e, 0x3c },
- },
-};
-
static struct dvb_pll_desc dvb_pll_unknown_1 = {
.name = "unknown 1", /* used by dntv live dvb-t */
.min = 174000000,
@@ -301,54 +239,6 @@ static struct dvb_pll_desc dvb_pll_tua6034 = {
},
};
-/* Infineon TUA6034
- * used in LG TDVS-H061F, LG TDVS-H062F and LG TDVS-H064F
- */
-static struct dvb_pll_desc dvb_pll_lg_tdvs_h06xf = {
- .name = "LG TDVS-H06xF",
- .min = 54000000,
- .max = 863000000,
- .iffreq= 44000000,
- .initdata = tua603x_agc103,
- .count = 3,
- .entries = {
- { 165000000, 62500, 0xce, 0x01 },
- { 450000000, 62500, 0xce, 0x02 },
- { 999999999, 62500, 0xce, 0x04 },
- },
-};
-
-/* Philips FMD1216ME
- * used in Medion Hybrid PCMCIA card and USB Box
- */
-static void fmd1216me_bw(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
-{
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
- params->frequency >= 158870000)
- buf[3] |= 0x08;
-}
-
-static struct dvb_pll_desc dvb_pll_fmd1216me = {
- .name = "Philips FMD1216ME",
- .min = 50870000,
- .max = 858000000,
- .iffreq= 36125000,
- .set = fmd1216me_bw,
- .initdata = tua603x_agc112,
- .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
- .count = 7,
- .entries = {
- { 143870000, 166667, 0xbc, 0x41 },
- { 158870000, 166667, 0xf4, 0x41 },
- { 329870000, 166667, 0xbc, 0x42 },
- { 441870000, 166667, 0xf4, 0x42 },
- { 625870000, 166667, 0xbc, 0x44 },
- { 803870000, 166667, 0xf4, 0x44 },
- { 999999999, 166667, 0xfc, 0x44 },
- }
-};
-
/* ALPS TDED4
* used in Nebula-Cards and USB boxes
*/
@@ -391,55 +281,6 @@ static struct dvb_pll_desc dvb_pll_tdhu2 = {
}
};
-/* Philips TUV1236D
- * used in ATI HDTV Wonder
- */
-static void tuv1236d_rf(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
-{
- struct dvb_pll_priv *priv = fe->tuner_priv;
- unsigned int new_rf = input[priv->nr];
-
- if ((new_rf == 0) || (new_rf > 2)) {
- switch (params->u.vsb.modulation) {
- case QAM_64:
- case QAM_256:
- new_rf = 1;
- break;
- case VSB_8:
- default:
- new_rf = 2;
- }
- }
-
- switch (new_rf) {
- case 1:
- buf[3] |= 0x08;
- break;
- case 2:
- buf[3] &= ~0x08;
- break;
- default:
- printk(KERN_WARNING
- "%s: unhandled rf input selection: %d",
- __FUNCTION__, new_rf);
- }
-}
-
-static struct dvb_pll_desc dvb_pll_tuv1236d = {
- .name = "Philips TUV1236D",
- .min = 54000000,
- .max = 864000000,
- .iffreq= 44000000,
- .set = tuv1236d_rf,
- .count = 3,
- .entries = {
- { 157250000, 62500, 0xc6, 0x41 },
- { 454000000, 62500, 0xc6, 0x42 },
- { 999999999, 62500, 0xc6, 0x44 },
- },
-};
-
/* Samsung TBMV30111IN / TBMV30712IN1
* used in Air2PC ATSC - 2nd generation (nxt2002)
*/
@@ -476,64 +317,6 @@ static struct dvb_pll_desc dvb_pll_philips_sd1878_tda8261 = {
},
};
-/*
- * Philips TD1316 Tuner.
- */
-static void td1316_bw(struct dvb_frontend *fe, u8 *buf,
- const struct dvb_frontend_parameters *params)
-{
- u8 band;
-
- /* determine band */
- if (params->frequency < 161000000)
- band = 1;
- else if (params->frequency < 444000000)
- band = 2;
- else
- band = 4;
-
- buf[3] |= band;
-
- /* setup PLL filter */
- if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
- buf[3] |= 1 << 3;
-}
-
-static struct dvb_pll_desc dvb_pll_philips_td1316 = {
- .name = "Philips TD1316",
- .min = 87000000,
- .max = 895000000,
- .iffreq= 36166667,
- .set = td1316_bw,
- .count = 9,
- .entries = {
- { 93834000, 166667, 0xca, 0x60},
- { 123834000, 166667, 0xca, 0xa0},
- { 163834000, 166667, 0xca, 0xc0},
- { 253834000, 166667, 0xca, 0x60},
- { 383834000, 166667, 0xca, 0xa0},
- { 443834000, 166667, 0xca, 0xc0},
- { 583834000, 166667, 0xca, 0x60},
- { 793834000, 166667, 0xca, 0xa0},
- { 858834000, 166667, 0xca, 0xe0},
- },
-};
-
-/* FE6600 used on DViCO Hybrid */
-static struct dvb_pll_desc dvb_pll_thomson_fe6600 = {
- .name = "Thomson FE6600",
- .min = 44250000,
- .max = 858000000,
- .iffreq= 36125000,
- .count = 4,
- .entries = {
- { 250000000, 166667, 0xb4, 0x12 },
- { 455000000, 166667, 0xfe, 0x11 },
- { 775500000, 166667, 0xbc, 0x18 },
- { 999999999, 166667, 0xf4, 0x18 },
- }
-};
-
static void opera1_bw(struct dvb_frontend *fe, u8 *buf,
const struct dvb_frontend_parameters *params)
{
@@ -560,50 +343,23 @@ static struct dvb_pll_desc dvb_pll_opera1 = {
}
};
-/* Philips FCV1236D
- */
-static struct dvb_pll_desc dvb_pll_fcv1236d = {
-/* Bit_0: RF Input select
- * Bit_1: 0=digital, 1=analog
- */
- .name = "Philips FCV1236D",
- .min = 53000000,
- .max = 803000000,
- .iffreq= 44000000,
- .count = 3,
- .entries = {
- { 159000000, 62500, 0x8e, 0xa0 },
- { 453000000, 62500, 0x8e, 0x90 },
- { 999999999, 62500, 0x8e, 0x30 },
- },
-};
-
/* ----------------------------------------------------------- */
static struct dvb_pll_desc *pll_list[] = {
[DVB_PLL_UNDEFINED] = NULL,
[DVB_PLL_THOMSON_DTT7579] = &dvb_pll_thomson_dtt7579,
[DVB_PLL_THOMSON_DTT759X] = &dvb_pll_thomson_dtt759x,
- [DVB_PLL_THOMSON_DTT7610] = &dvb_pll_thomson_dtt7610,
[DVB_PLL_LG_Z201] = &dvb_pll_lg_z201,
- [DVB_PLL_MICROTUNE_4042] = &dvb_pll_microtune_4042,
- [DVB_PLL_THOMSON_DTT761X] = &dvb_pll_thomson_dtt761x,
[DVB_PLL_UNKNOWN_1] = &dvb_pll_unknown_1,
[DVB_PLL_TUA6010XS] = &dvb_pll_tua6010xs,
[DVB_PLL_ENV57H1XD5] = &dvb_pll_env57h1xd5,
[DVB_PLL_TUA6034] = &dvb_pll_tua6034,
- [DVB_PLL_LG_TDVS_H06XF] = &dvb_pll_lg_tdvs_h06xf,
[DVB_PLL_TDA665X] = &dvb_pll_tda665x,
- [DVB_PLL_FMD1216ME] = &dvb_pll_fmd1216me,
[DVB_PLL_TDED4] = &dvb_pll_tded4,
- [DVB_PLL_TUV1236D] = &dvb_pll_tuv1236d,
[DVB_PLL_TDHU2] = &dvb_pll_tdhu2,
[DVB_PLL_SAMSUNG_TBMV] = &dvb_pll_samsung_tbmv,
[DVB_PLL_PHILIPS_SD1878_TDA8261] = &dvb_pll_philips_sd1878_tda8261,
- [DVB_PLL_PHILIPS_TD1316] = &dvb_pll_philips_td1316,
- [DVB_PLL_THOMSON_FE6600] = &dvb_pll_thomson_fe6600,
[DVB_PLL_OPERA1] = &dvb_pll_opera1,
- [DVB_PLL_FCV1236D] = &dvb_pll_fcv1236d,
};
/* ----------------------------------------------------------- */
@@ -849,20 +605,6 @@ struct dvb_frontend *dvb_pll_attach(struct dvb_frontend *fe, int pll_addr,
id[priv->nr] == pll_desc_id ?
"insmod option" : "autodetected");
}
- if ((debug) || (input[priv->nr] > 0)) {
- printk("dvb-pll[%d]", priv->nr);
- if (i2c != NULL)
- printk(" %d-%04x", i2c_adapter_id(i2c), pll_addr);
- printk(": tuner rf input will be ");
- switch (input[priv->nr]) {
- case 0:
- printk("autoselected\n");
- break;
- default:
- printk("set to input %d (insmod option)\n",
- input[priv->nr]);
- }
- }
return fe;
}
diff --git a/drivers/media/dvb/frontends/dvb-pll.h b/drivers/media/dvb/frontends/dvb-pll.h
index e93a8104052b..435146d9fa12 100644
--- a/drivers/media/dvb/frontends/dvb-pll.h
+++ b/drivers/media/dvb/frontends/dvb-pll.h
@@ -11,26 +11,17 @@
#define DVB_PLL_UNDEFINED 0
#define DVB_PLL_THOMSON_DTT7579 1
#define DVB_PLL_THOMSON_DTT759X 2
-#define DVB_PLL_THOMSON_DTT7610 3
-#define DVB_PLL_LG_Z201 4
-#define DVB_PLL_MICROTUNE_4042 5
-#define DVB_PLL_THOMSON_DTT761X 6
-#define DVB_PLL_UNKNOWN_1 7
-#define DVB_PLL_TUA6010XS 8
-#define DVB_PLL_ENV57H1XD5 9
-#define DVB_PLL_TUA6034 10
-#define DVB_PLL_LG_TDVS_H06XF 11
-#define DVB_PLL_TDA665X 12
-#define DVB_PLL_FMD1216ME 13
-#define DVB_PLL_TDED4 14
-#define DVB_PLL_TUV1236D 15
-#define DVB_PLL_TDHU2 16
-#define DVB_PLL_SAMSUNG_TBMV 17
-#define DVB_PLL_PHILIPS_SD1878_TDA8261 18
-#define DVB_PLL_PHILIPS_TD1316 19
-#define DVB_PLL_THOMSON_FE6600 20
-#define DVB_PLL_OPERA1 21
-#define DVB_PLL_FCV1236D 22
+#define DVB_PLL_LG_Z201 3
+#define DVB_PLL_UNKNOWN_1 4
+#define DVB_PLL_TUA6010XS 5
+#define DVB_PLL_ENV57H1XD5 6
+#define DVB_PLL_TUA6034 7
+#define DVB_PLL_TDA665X 8
+#define DVB_PLL_TDED4 9
+#define DVB_PLL_TDHU2 10
+#define DVB_PLL_SAMSUNG_TBMV 11
+#define DVB_PLL_PHILIPS_SD1878_TDA8261 12
+#define DVB_PLL_OPERA1 13
/**
* Attach a dvb-pll to the supplied frontend structure.
diff --git a/drivers/media/dvb/frontends/isl6405.c b/drivers/media/dvb/frontends/isl6405.c
new file mode 100644
index 000000000000..33d33f4d8867
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6405.c
@@ -0,0 +1,164 @@
+/*
+ * isl6405.c - driver for dual lnb supply and control ic ISL6405
+ *
+ * Copyright (C) 2008 Hartmut Hackmann
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+#include <linux/delay.h>
+#include <linux/errno.h>
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "dvb_frontend.h"
+#include "isl6405.h"
+
+struct isl6405 {
+ u8 config;
+ u8 override_or;
+ u8 override_and;
+ struct i2c_adapter *i2c;
+ u8 i2c_addr;
+};
+
+static int isl6405_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
+ struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0,
+ .buf = &isl6405->config,
+ .len = sizeof(isl6405->config) };
+
+ if (isl6405->override_or & 0x80) {
+ isl6405->config &= ~(ISL6405_VSEL2 | ISL6405_EN2);
+ switch (voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ isl6405->config |= ISL6405_EN2;
+ break;
+ case SEC_VOLTAGE_18:
+ isl6405->config |= (ISL6405_EN2 | ISL6405_VSEL2);
+ break;
+ default:
+ return -EINVAL;
+ }
+ } else {
+ isl6405->config &= ~(ISL6405_VSEL1 | ISL6405_EN1);
+ switch (voltage) {
+ case SEC_VOLTAGE_OFF:
+ break;
+ case SEC_VOLTAGE_13:
+ isl6405->config |= ISL6405_EN1;
+ break;
+ case SEC_VOLTAGE_18:
+ isl6405->config |= (ISL6405_EN1 | ISL6405_VSEL1);
+ break;
+ default:
+ return -EINVAL;
+ };
+ }
+ isl6405->config |= isl6405->override_or;
+ isl6405->config &= isl6405->override_and;
+
+ return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static int isl6405_enable_high_lnb_voltage(struct dvb_frontend *fe, long arg)
+{
+ struct isl6405 *isl6405 = (struct isl6405 *) fe->sec_priv;
+ struct i2c_msg msg = { .addr = isl6405->i2c_addr, .flags = 0,
+ .buf = &isl6405->config,
+ .len = sizeof(isl6405->config) };
+
+ if (isl6405->override_or & 0x80) {
+ if (arg)
+ isl6405->config |= ISL6405_LLC2;
+ else
+ isl6405->config &= ~ISL6405_LLC2;
+ } else {
+ if (arg)
+ isl6405->config |= ISL6405_LLC1;
+ else
+ isl6405->config &= ~ISL6405_LLC1;
+ }
+ isl6405->config |= isl6405->override_or;
+ isl6405->config &= isl6405->override_and;
+
+ return (i2c_transfer(isl6405->i2c, &msg, 1) == 1) ? 0 : -EIO;
+}
+
+static void isl6405_release(struct dvb_frontend *fe)
+{
+ /* power off */
+ isl6405_set_voltage(fe, SEC_VOLTAGE_OFF);
+
+ /* free */
+ kfree(fe->sec_priv);
+ fe->sec_priv = NULL;
+}
+
+struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
+ u8 i2c_addr, u8 override_set, u8 override_clear)
+{
+ struct isl6405 *isl6405 = kmalloc(sizeof(struct isl6405), GFP_KERNEL);
+ if (!isl6405)
+ return NULL;
+
+ /* default configuration */
+ if (override_set & 0x80)
+ isl6405->config = ISL6405_ISEL2;
+ else
+ isl6405->config = ISL6405_ISEL1;
+ isl6405->i2c = i2c;
+ isl6405->i2c_addr = i2c_addr;
+ fe->sec_priv = isl6405;
+
+ /* bits which should be forced to '1' */
+ isl6405->override_or = override_set;
+
+ /* bits which should be forced to '0' */
+ isl6405->override_and = ~override_clear;
+
+ /* detect if it is present or not */
+ if (isl6405_set_voltage(fe, SEC_VOLTAGE_OFF)) {
+ kfree(isl6405);
+ fe->sec_priv = NULL;
+ return NULL;
+ }
+
+ /* install release callback */
+ fe->ops.release_sec = isl6405_release;
+
+ /* override frontend ops */
+ fe->ops.set_voltage = isl6405_set_voltage;
+ fe->ops.enable_high_lnb_voltage = isl6405_enable_high_lnb_voltage;
+
+ return fe;
+}
+EXPORT_SYMBOL(isl6405_attach);
+
+MODULE_DESCRIPTION("Driver for lnb supply and control ic isl6405");
+MODULE_AUTHOR("Hartmut Hackmann & Oliver Endriss");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/dvb/frontends/isl6405.h b/drivers/media/dvb/frontends/isl6405.h
new file mode 100644
index 000000000000..9d4001a2237e
--- /dev/null
+++ b/drivers/media/dvb/frontends/isl6405.h
@@ -0,0 +1,74 @@
+/*
+ * isl6405.h - driver for dual lnb supply and control ic ISL6405
+ *
+ * Copyright (C) 2008 Hartmut Hackmann
+ * Copyright (C) 2006 Oliver Endriss
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ * Or, point your browser to http://www.gnu.org/copyleft/gpl.html
+ *
+ *
+ * the project's page is at http://www.linuxtv.org
+ */
+
+#ifndef _ISL6405_H
+#define _ISL6405_H
+
+#include <linux/dvb/frontend.h>
+
+/* system register bits */
+
+/* this bit selects register (control) 1 or 2
+ note that the bit maps are different */
+
+#define ISL6405_SR 0x80
+
+/* SR = 0 */
+#define ISL6405_OLF1 0x01
+#define ISL6405_EN1 0x02
+#define ISL6405_VSEL1 0x04
+#define ISL6405_LLC1 0x08
+#define ISL6405_ENT1 0x10
+#define ISL6405_ISEL1 0x20
+#define ISL6405_DCL 0x40
+
+/* SR = 1 */
+#define ISL6405_OLF2 0x01
+#define ISL6405_OTF 0x02
+#define ISL6405_EN2 0x04
+#define ISL6405_VSEL2 0x08
+#define ISL6405_LLC2 0x10
+#define ISL6405_ENT2 0x20
+#define ISL6405_ISEL2 0x40
+
+#if defined(CONFIG_DVB_ISL6405) || (defined(CONFIG_DVB_ISL6405_MODULE) && defined(MODULE))
+/* override_set and override_clear control which system register bits (above)
+ * to always set & clear
+ */
+extern struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c,
+ u8 i2c_addr, u8 override_set, u8 override_clear);
+#else
+static inline struct dvb_frontend *isl6405_attach(struct dvb_frontend *fe,
+ struct i2c_adapter *i2c, u8 i2c_addr,
+ u8 override_set, u8 override_clear)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_ISL6405 */
+
+#endif
diff --git a/drivers/media/dvb/frontends/lgdt330x.c b/drivers/media/dvb/frontends/lgdt330x.c
index bdc9fa88b86a..dc897a3903fc 100644
--- a/drivers/media/dvb/frontends/lgdt330x.c
+++ b/drivers/media/dvb/frontends/lgdt330x.c
@@ -49,7 +49,7 @@
/* Use Equalizer Mean Squared Error instead of Phaser Tracker MSE */
/* #define USE_EQMSE */
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"Turn on/off lgdt330x frontend debugging (default:off).");
#define dprintk(args...) \
diff --git a/drivers/media/dvb/frontends/nxt6000.c b/drivers/media/dvb/frontends/nxt6000.c
index d313d7dcf386..0eef22dbf8a0 100644
--- a/drivers/media/dvb/frontends/nxt6000.c
+++ b/drivers/media/dvb/frontends/nxt6000.c
@@ -38,7 +38,7 @@ struct nxt6000_state {
struct dvb_frontend frontend;
};
-static int debug = 0;
+static int debug;
#define dprintk if (debug) printk
static int nxt6000_writereg(struct nxt6000_state* state, u8 reg, u8 data)
diff --git a/drivers/media/dvb/frontends/s5h1409.c b/drivers/media/dvb/frontends/s5h1409.c
index 1a4d8319773c..1ca250378664 100644
--- a/drivers/media/dvb/frontends/s5h1409.c
+++ b/drivers/media/dvb/frontends/s5h1409.c
@@ -48,7 +48,7 @@ struct s5h1409_state {
u32 qam_state;
};
-static int debug = 0;
+static int debug;
#define dprintk if (debug) printk
/* Register values to initialise the demod, this will set VSB by default */
diff --git a/drivers/media/dvb/frontends/s5h1420.c b/drivers/media/dvb/frontends/s5h1420.c
index 2c2c344c4c64..7c64af91e5ac 100644
--- a/drivers/media/dvb/frontends/s5h1420.c
+++ b/drivers/media/dvb/frontends/s5h1420.c
@@ -53,7 +53,7 @@ static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
struct dvb_frontend_tune_settings* fesettings);
-static int debug = 0;
+static int debug;
#define dprintk if (debug) printk
static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
diff --git a/drivers/media/dvb/frontends/sp8870.c b/drivers/media/dvb/frontends/sp8870.c
index da876f7bfe32..f5b3bfc00436 100644
--- a/drivers/media/dvb/frontends/sp8870.c
+++ b/drivers/media/dvb/frontends/sp8870.c
@@ -449,15 +449,15 @@ static int sp8870_read_uncorrected_blocks (struct dvb_frontend* fe, u32* ublocks
return 0;
}
-// number of trials to recover from lockup
+/* number of trials to recover from lockup */
#define MAXTRIALS 5
-// maximum checks for data valid signal
+/* maximum checks for data valid signal */
#define MAXCHECKS 100
-// only for debugging: counter for detected lockups
-static int lockups = 0;
-// only for debugging: counter for channel switches
-static int switches = 0;
+/* only for debugging: counter for detected lockups */
+static int lockups;
+/* only for debugging: counter for channel switches */
+static int switches;
static int sp8870_set_frontend (struct dvb_frontend* fe, struct dvb_frontend_parameters *p)
{
diff --git a/drivers/media/dvb/frontends/tda1004x.h b/drivers/media/dvb/frontends/tda1004x.h
index abae84350142..ebb2c5f5a261 100644
--- a/drivers/media/dvb/frontends/tda1004x.h
+++ b/drivers/media/dvb/frontends/tda1004x.h
@@ -94,7 +94,6 @@ struct tda1004x_config
/* slave address and configuration of the tuner */
u8 tuner_address;
- u8 tuner_config;
u8 antenna_switch;
/* if the board uses another I2c Bridge (tda8290), its address */
diff --git a/drivers/media/dvb/frontends/tda10086.c b/drivers/media/dvb/frontends/tda10086.c
index 0d2b69a99ad4..143af96439b9 100644
--- a/drivers/media/dvb/frontends/tda10086.c
+++ b/drivers/media/dvb/frontends/tda10086.c
@@ -43,7 +43,7 @@ struct tda10086_state {
bool has_lock;
};
-static int debug = 0;
+static int debug;
#define dprintk(args...) \
do { \
if (debug) printk(KERN_DEBUG "tda10086: " args); \
diff --git a/drivers/media/dvb/frontends/tda18271-common.c b/drivers/media/dvb/frontends/tda18271-common.c
index bca570990613..e27a7620a32f 100644
--- a/drivers/media/dvb/frontends/tda18271-common.c
+++ b/drivers/media/dvb/frontends/tda18271-common.c
@@ -125,16 +125,16 @@ int tda18271_read_regs(struct dvb_frontend *fe)
unsigned char buf = 0x00;
int ret;
struct i2c_msg msg[] = {
- { .addr = priv->i2c_addr, .flags = 0,
+ { .addr = priv->i2c_props.addr, .flags = 0,
.buf = &buf, .len = 1 },
- { .addr = priv->i2c_addr, .flags = I2C_M_RD,
+ { .addr = priv->i2c_props.addr, .flags = I2C_M_RD,
.buf = regs, .len = 16 }
};
tda18271_i2c_gate_ctrl(fe, 1);
/* read all registers */
- ret = i2c_transfer(priv->i2c_adap, msg, 2);
+ ret = i2c_transfer(priv->i2c_props.adap, msg, 2);
tda18271_i2c_gate_ctrl(fe, 0);
@@ -155,16 +155,16 @@ int tda18271_read_extended(struct dvb_frontend *fe)
unsigned char buf = 0x00;
int ret, i;
struct i2c_msg msg[] = {
- { .addr = priv->i2c_addr, .flags = 0,
+ { .addr = priv->i2c_props.addr, .flags = 0,
.buf = &buf, .len = 1 },
- { .addr = priv->i2c_addr, .flags = I2C_M_RD,
+ { .addr = priv->i2c_props.addr, .flags = I2C_M_RD,
.buf = regdump, .len = TDA18271_NUM_REGS }
};
tda18271_i2c_gate_ctrl(fe, 1);
/* read all registers */
- ret = i2c_transfer(priv->i2c_adap, msg, 2);
+ ret = i2c_transfer(priv->i2c_props.adap, msg, 2);
tda18271_i2c_gate_ctrl(fe, 0);
@@ -192,7 +192,7 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
unsigned char buf[TDA18271_NUM_REGS + 1];
- struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+ struct i2c_msg msg = { .addr = priv->i2c_props.addr, .flags = 0,
.buf = buf, .len = len + 1 };
int i, ret;
@@ -205,7 +205,7 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
tda18271_i2c_gate_ctrl(fe, 1);
/* write registers */
- ret = i2c_transfer(priv->i2c_adap, &msg, 1);
+ ret = i2c_transfer(priv->i2c_props.adap, &msg, 1);
tda18271_i2c_gate_ctrl(fe, 0);
@@ -217,13 +217,29 @@ int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len)
/*---------------------------------------------------------------------*/
+int tda18271_charge_pump_source(struct dvb_frontend *fe,
+ enum tda18271_pll pll, int force)
+{
+ struct tda18271_priv *priv = fe->tuner_priv;
+ unsigned char *regs = priv->tda18271_regs;
+
+ int r_cp = (pll == TDA18271_CAL_PLL) ? R_EB7 : R_EB4;
+
+ regs[r_cp] &= ~0x20;
+ regs[r_cp] |= ((force & 1) << 5);
+ tda18271_write_regs(fe, r_cp, 1);
+
+ return 0;
+}
+
int tda18271_init_regs(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
tda_dbg("initializing registers for device @ %d-%04x\n",
- i2c_adapter_id(priv->i2c_adap), priv->i2c_addr);
+ i2c_adapter_id(priv->i2c_props.adap),
+ priv->i2c_props.addr);
/* initialize registers */
switch (priv->id) {
@@ -310,7 +326,12 @@ int tda18271_init_regs(struct dvb_frontend *fe)
regs[R_EB22] = 0x48;
regs[R_EB23] = 0xb0;
- tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
+ if (priv->small_i2c) {
+ tda18271_write_regs(fe, 0x00, 0x10);
+ tda18271_write_regs(fe, 0x10, 0x10);
+ tda18271_write_regs(fe, 0x20, 0x07);
+ } else
+ tda18271_write_regs(fe, 0x00, TDA18271_NUM_REGS);
/* setup agc1 gain */
regs[R_EB17] = 0x00;
@@ -349,24 +370,15 @@ int tda18271_init_regs(struct dvb_frontend *fe)
regs[R_MD2] = 0x08;
regs[R_MD3] = 0x00;
- switch (priv->id) {
- case TDA18271HDC1:
- tda18271_write_regs(fe, R_EP3, 11);
- break;
- case TDA18271HDC2:
- tda18271_write_regs(fe, R_EP3, 12);
- break;
- };
+ tda18271_write_regs(fe, R_EP3, 11);
if ((priv->id) == TDA18271HDC2) {
/* main pll cp source on */
- regs[R_EB4] = 0x61;
- tda18271_write_regs(fe, R_EB4, 1);
+ tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
msleep(1);
/* main pll cp source off */
- regs[R_EB4] = 0x41;
- tda18271_write_regs(fe, R_EB4, 1);
+ tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
}
msleep(5); /* pll locking */
@@ -398,6 +410,7 @@ int tda18271_init_regs(struct dvb_frontend *fe)
tda18271_write_regs(fe, R_EP3, 11);
msleep(5); /* pll locking */
+ /* launch detector */
tda18271_write_regs(fe, R_EP1, 1);
msleep(5); /* wanted mid measurement */
diff --git a/drivers/media/dvb/frontends/tda18271-fe.c b/drivers/media/dvb/frontends/tda18271-fe.c
index dfe72aaec380..b262100ae897 100644
--- a/drivers/media/dvb/frontends/tda18271-fe.c
+++ b/drivers/media/dvb/frontends/tda18271-fe.c
@@ -31,30 +31,23 @@ static int tda18271_cal_on_startup;
module_param_named(cal, tda18271_cal_on_startup, int, 0644);
MODULE_PARM_DESC(cal, "perform RF tracking filter calibration on startup");
-static LIST_HEAD(tda18271_list);
static DEFINE_MUTEX(tda18271_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
/*---------------------------------------------------------------------*/
-static int tda18271_ir_cal_init(struct dvb_frontend *fe)
+static inline int charge_pump_source(struct dvb_frontend *fe, int force)
{
struct tda18271_priv *priv = fe->tuner_priv;
- unsigned char *regs = priv->tda18271_regs;
-
- tda18271_read_regs(fe);
-
- /* test IR_CAL_OK to see if we need init */
- if ((regs[R_EP1] & 0x08) == 0)
- tda18271_init_regs(fe);
-
- return 0;
+ return tda18271_charge_pump_source(fe,
+ (priv->role == TDA18271_SLAVE) ?
+ TDA18271_CAL_PLL :
+ TDA18271_MAIN_PLL, force);
}
-/* ------------------------------------------------------------------ */
-
static int tda18271_channel_configuration(struct dvb_frontend *fe,
- u32 ifc, u32 freq, u32 bw, u8 std,
- int radio)
+ struct tda18271_std_map_item *map,
+ u32 freq, u32 bw)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
@@ -64,38 +57,34 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
/* set standard */
regs[R_EP3] &= ~0x1f; /* clear std bits */
- regs[R_EP3] |= std;
+ regs[R_EP3] |= (map->agc_mode << 3) | map->std;
+
+ /* set rfagc to high speed mode */
+ regs[R_EP3] &= ~0x04;
/* set cal mode to normal */
regs[R_EP4] &= ~0x03;
/* update IF output level & IF notch frequency */
regs[R_EP4] &= ~0x1c; /* clear if level bits */
+ regs[R_EP4] |= (map->if_lvl << 2);
switch (priv->mode) {
case TDA18271_ANALOG:
regs[R_MPD] &= ~0x80; /* IF notch = 0 */
break;
case TDA18271_DIGITAL:
- regs[R_EP4] |= 0x04; /* IF level = 1 */
regs[R_MPD] |= 0x80; /* IF notch = 1 */
break;
}
- if (radio)
- regs[R_EP4] |= 0x80;
- else
- regs[R_EP4] &= ~0x80;
+ /* update FM_RFn */
+ regs[R_EP4] &= ~0x80;
+ regs[R_EP4] |= map->fm_rfn << 7;
- /* update RF_TOP / IF_TOP */
- switch (priv->mode) {
- case TDA18271_ANALOG:
- regs[R_EB22] = 0x2c;
- break;
- case TDA18271_DIGITAL:
- regs[R_EB22] = 0x37;
- break;
- }
+ /* update rf top / if top */
+ regs[R_EB22] = 0x00;
+ regs[R_EB22] |= map->rfagc_top;
tda18271_write_regs(fe, R_EB22, 1);
/* --------------------------------------------------------------- */
@@ -117,8 +106,14 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
/* dual tuner and agc1 extra configuration */
- /* main vco when Master, cal vco when slave */
- regs[R_EB1] |= 0x04; /* FIXME: assumes master */
+ switch (priv->role) {
+ case TDA18271_MASTER:
+ regs[R_EB1] |= 0x04; /* main vco */
+ break;
+ case TDA18271_SLAVE:
+ regs[R_EB1] &= ~0x04; /* cal vco */
+ break;
+ }
/* agc1 always active */
regs[R_EB1] &= ~0x02;
@@ -130,25 +125,40 @@ static int tda18271_channel_configuration(struct dvb_frontend *fe,
/* --------------------------------------------------------------- */
- N = freq + ifc;
+ N = map->if_freq * 1000 + freq;
- /* FIXME: assumes master */
- tda18271_calc_main_pll(fe, N);
- tda18271_write_regs(fe, R_MPD, 4);
+ switch (priv->role) {
+ case TDA18271_MASTER:
+ tda18271_calc_main_pll(fe, N);
+ tda18271_write_regs(fe, R_MPD, 4);
+ break;
+ case TDA18271_SLAVE:
+ tda18271_calc_cal_pll(fe, N);
+ tda18271_write_regs(fe, R_CPD, 4);
+
+ regs[R_MPD] = regs[R_CPD] & 0x7f;
+ tda18271_write_regs(fe, R_MPD, 1);
+ break;
+ }
tda18271_write_regs(fe, R_TM, 7);
- /* main pll charge pump source */
- regs[R_EB4] |= 0x20;
- tda18271_write_regs(fe, R_EB4, 1);
+ /* force charge pump source */
+ charge_pump_source(fe, 1);
msleep(1);
- /* normal operation for the main pll */
- regs[R_EB4] &= ~0x20;
- tda18271_write_regs(fe, R_EB4, 1);
+ /* return pll to normal operation */
+ charge_pump_source(fe, 0);
- msleep(5);
+ msleep(20);
+
+ /* set rfagc to normal speed mode */
+ if (map->fm_rfn)
+ regs[R_EP3] &= ~0x04;
+ else
+ regs[R_EP3] |= 0x04;
+ tda18271_write_regs(fe, R_EP3, 1);
return 0;
}
@@ -195,8 +205,10 @@ static int tda18271_read_thermometer(struct dvb_frontend *fe)
return tm;
}
-static int tda18271_rf_tracking_filters_correction(struct dvb_frontend *fe,
- u32 freq)
+/* ------------------------------------------------------------------ */
+
+static int tda18271c2_rf_tracking_filters_correction(struct dvb_frontend *fe,
+ u32 freq)
{
struct tda18271_priv *priv = fe->tuner_priv;
struct tda18271_rf_tracking_filter_cal *map = priv->rf_cal_state;
@@ -296,12 +308,10 @@ static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
tda18271_write_regs(fe, R_EB13, 1);
/* main pll charge pump source */
- regs[R_EB4] |= 0x20;
- tda18271_write_regs(fe, R_EB4, 1);
+ tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 1);
/* cal pll charge pump source */
- regs[R_EB7] |= 0x20;
- tda18271_write_regs(fe, R_EB7, 1);
+ tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 1);
/* force dcdc converter to 0 V */
regs[R_EB14] = 0x00;
@@ -320,8 +330,8 @@ static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
/* set the internal calibration signal */
N = freq;
- tda18271_calc_main_pll(fe, N);
- tda18271_write_regs(fe, R_MPD, 4);
+ tda18271_calc_cal_pll(fe, N);
+ tda18271_write_regs(fe, R_CPD, 4);
/* downconvert internal calibration */
N += 1000000;
@@ -339,14 +349,12 @@ static int tda18271_calibrate_rf(struct dvb_frontend *fe, u32 freq)
/* --------------------------------------------------------------- */
/* normal operation for the main pll */
- regs[R_EB4] &= ~0x20;
- tda18271_write_regs(fe, R_EB4, 1);
+ tda18271_charge_pump_source(fe, TDA18271_MAIN_PLL, 0);
/* normal operation for the cal pll */
- regs[R_EB7] &= ~0x20;
- tda18271_write_regs(fe, R_EB7, 1);
+ tda18271_charge_pump_source(fe, TDA18271_CAL_PLL, 0);
- msleep(5); /* plls locking */
+ msleep(10); /* plls locking */
/* launch the rf tracking filters calibration */
regs[R_EB20] |= 0x20;
@@ -443,7 +451,7 @@ static int tda18271_powerscan(struct dvb_frontend *fe,
count += 200;
- if (count < count_limit)
+ if (count <= count_limit)
continue;
if (sgn <= 0)
@@ -587,7 +595,7 @@ static int tda18271_calc_rf_filter_curve(struct dvb_frontend *fe)
/* ------------------------------------------------------------------ */
-static int tda18271_rf_cal_init(struct dvb_frontend *fe)
+static int tda18271c2_rf_cal_init(struct dvb_frontend *fe)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
@@ -610,63 +618,13 @@ static int tda18271_rf_cal_init(struct dvb_frontend *fe)
return 0;
}
-static int tda18271_init(struct dvb_frontend *fe)
-{
- struct tda18271_priv *priv = fe->tuner_priv;
-
- mutex_lock(&priv->lock);
-
- /* power up */
- tda18271_set_standby_mode(fe, 0, 0, 0);
-
- /* initialization */
- tda18271_ir_cal_init(fe);
-
- if (priv->id == TDA18271HDC2)
- tda18271_rf_cal_init(fe);
-
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-static int tda18271c2_tune(struct dvb_frontend *fe,
- u32 ifc, u32 freq, u32 bw, u8 std, int radio)
-{
- struct tda18271_priv *priv = fe->tuner_priv;
-
- tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
-
- tda18271_init(fe);
-
- mutex_lock(&priv->lock);
-
- tda18271_rf_tracking_filters_correction(fe, freq);
-
- tda18271_channel_configuration(fe, ifc, freq, bw, std, radio);
-
- mutex_unlock(&priv->lock);
-
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static int tda18271c1_tune(struct dvb_frontend *fe,
- u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+static int tda18271c1_rf_tracking_filter_calibration(struct dvb_frontend *fe,
+ u32 freq, u32 bw)
{
struct tda18271_priv *priv = fe->tuner_priv;
unsigned char *regs = priv->tda18271_regs;
u32 N = 0;
- tda18271_init(fe);
-
- mutex_lock(&priv->lock);
-
- tda_dbg("freq = %d, ifc = %d\n", freq, ifc);
-
- /* RF tracking filter calibration */
-
/* calculate bp filter */
tda18271_calc_bp_filter(fe, &freq);
tda18271_write_regs(fe, R_EP1, 1);
@@ -737,7 +695,7 @@ static int tda18271c1_tune(struct dvb_frontend *fe,
regs[R_EB7] = 0x40;
tda18271_write_regs(fe, R_EB7, 1);
- msleep(10);
+ msleep(10); /* pll locking */
regs[R_EB20] = 0xec;
tda18271_write_regs(fe, R_EB20, 1);
@@ -752,74 +710,70 @@ static int tda18271c1_tune(struct dvb_frontend *fe,
if (0 == tda18271_calc_rf_cal(fe, &freq))
tda18271_write_regs(fe, R_EB14, 1);
- /* Channel Configuration */
+ return 0;
+}
- switch (priv->mode) {
- case TDA18271_ANALOG:
- regs[R_EB22] = 0x2c;
- break;
- case TDA18271_DIGITAL:
- regs[R_EB22] = 0x37;
- break;
- }
- tda18271_write_regs(fe, R_EB22, 1);
+/* ------------------------------------------------------------------ */
- regs[R_EP1] |= 0x40; /* set dis power level on */
+static int tda18271_ir_cal_init(struct dvb_frontend *fe)
+{
+ struct tda18271_priv *priv = fe->tuner_priv;
+ unsigned char *regs = priv->tda18271_regs;
- /* set standard */
- regs[R_EP3] &= ~0x1f; /* clear std bits */
+ tda18271_read_regs(fe);
- /* see table 22 */
- regs[R_EP3] |= std;
+ /* test IR_CAL_OK to see if we need init */
+ if ((regs[R_EP1] & 0x08) == 0)
+ tda18271_init_regs(fe);
- regs[R_EP4] &= ~0x03; /* set cal mode to normal */
+ return 0;
+}
- regs[R_EP4] &= ~0x1c; /* clear if level bits */
- switch (priv->mode) {
- case TDA18271_ANALOG:
- regs[R_MPD] &= ~0x80; /* IF notch = 0 */
- break;
- case TDA18271_DIGITAL:
- regs[R_EP4] |= 0x04;
- regs[R_MPD] |= 0x80;
- break;
- }
+static int tda18271_init(struct dvb_frontend *fe)
+{
+ struct tda18271_priv *priv = fe->tuner_priv;
- if (radio)
- regs[R_EP4] |= 0x80;
- else
- regs[R_EP4] &= ~0x80;
+ mutex_lock(&priv->lock);
- /* image rejection validity */
- tda18271_calc_ir_measure(fe, &freq);
+ /* power up */
+ tda18271_set_standby_mode(fe, 0, 0, 0);
- /* calculate MAIN PLL */
- N = freq + ifc;
+ /* initialization */
+ tda18271_ir_cal_init(fe);
- tda18271_calc_main_pll(fe, N);
+ if (priv->id == TDA18271HDC2)
+ tda18271c2_rf_cal_init(fe);
- tda18271_write_regs(fe, R_TM, 15);
- msleep(5);
mutex_unlock(&priv->lock);
return 0;
}
-static inline int tda18271_tune(struct dvb_frontend *fe,
- u32 ifc, u32 freq, u32 bw, u8 std, int radio)
+static int tda18271_tune(struct dvb_frontend *fe,
+ struct tda18271_std_map_item *map, u32 freq, u32 bw)
{
struct tda18271_priv *priv = fe->tuner_priv;
- int ret = -EINVAL;
+
+ tda_dbg("freq = %d, ifc = %d, bw = %d, agc_mode = %d, std = %d\n",
+ freq, map->if_freq, bw, map->agc_mode, map->std);
+
+ tda18271_init(fe);
+
+ mutex_lock(&priv->lock);
switch (priv->id) {
case TDA18271HDC1:
- ret = tda18271c1_tune(fe, ifc, freq, bw, std, radio);
+ tda18271c1_rf_tracking_filter_calibration(fe, freq, bw);
break;
case TDA18271HDC2:
- ret = tda18271c2_tune(fe, ifc, freq, bw, std, radio);
+ tda18271c2_rf_tracking_filters_correction(fe, freq);
break;
}
- return ret;
+ tda18271_channel_configuration(fe, map, freq, bw);
+
+ mutex_unlock(&priv->lock);
+
+ return 0;
}
/* ------------------------------------------------------------------ */
@@ -829,9 +783,8 @@ static int tda18271_set_params(struct dvb_frontend *fe,
{
struct tda18271_priv *priv = fe->tuner_priv;
struct tda18271_std_map *std_map = &priv->std;
+ struct tda18271_std_map_item *map;
int ret;
- u8 std;
- u16 sgIF;
u32 bw, freq = params->frequency;
priv->mode = TDA18271_DIGITAL;
@@ -840,13 +793,11 @@ static int tda18271_set_params(struct dvb_frontend *fe,
switch (params->u.vsb.modulation) {
case VSB_8:
case VSB_16:
- std = std_map->atsc_6.std_bits;
- sgIF = std_map->atsc_6.if_freq;
+ map = &std_map->atsc_6;
break;
case QAM_64:
case QAM_256:
- std = std_map->qam_6.std_bits;
- sgIF = std_map->qam_6.if_freq;
+ map = &std_map->qam_6;
break;
default:
tda_warn("modulation not set!\n");
@@ -861,18 +812,15 @@ static int tda18271_set_params(struct dvb_frontend *fe,
switch (params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
bw = 6000000;
- std = std_map->dvbt_6.std_bits;
- sgIF = std_map->dvbt_6.if_freq;
+ map = &std_map->dvbt_6;
break;
case BANDWIDTH_7_MHZ:
bw = 7000000;
- std = std_map->dvbt_7.std_bits;
- sgIF = std_map->dvbt_7.if_freq;
+ map = &std_map->dvbt_7;
break;
case BANDWIDTH_8_MHZ:
bw = 8000000;
- std = std_map->dvbt_8.std_bits;
- sgIF = std_map->dvbt_8.if_freq;
+ map = &std_map->dvbt_8;
break;
default:
tda_warn("bandwidth not set!\n");
@@ -887,7 +835,7 @@ static int tda18271_set_params(struct dvb_frontend *fe,
if (fe->ops.analog_ops.standby)
fe->ops.analog_ops.standby(fe);
- ret = tda18271_tune(fe, sgIF * 1000, freq, bw, std, 0);
+ ret = tda18271_tune(fe, map, freq, bw);
if (ret < 0)
goto fail;
@@ -904,57 +852,46 @@ static int tda18271_set_analog_params(struct dvb_frontend *fe,
{
struct tda18271_priv *priv = fe->tuner_priv;
struct tda18271_std_map *std_map = &priv->std;
+ struct tda18271_std_map_item *map;
char *mode;
- int ret, radio = 0;
- u8 std;
- u16 sgIF;
+ int ret;
u32 freq = params->frequency * 62500;
priv->mode = TDA18271_ANALOG;
if (params->mode == V4L2_TUNER_RADIO) {
- radio = 1;
freq = freq / 1000;
- std = std_map->fm_radio.std_bits;
- sgIF = std_map->fm_radio.if_freq;
+ map = &std_map->fm_radio;
mode = "fm";
} else if (params->std & V4L2_STD_MN) {
- std = std_map->atv_mn.std_bits;
- sgIF = std_map->atv_mn.if_freq;
+ map = &std_map->atv_mn;
mode = "MN";
} else if (params->std & V4L2_STD_B) {
- std = std_map->atv_b.std_bits;
- sgIF = std_map->atv_b.if_freq;
+ map = &std_map->atv_b;
mode = "B";
} else if (params->std & V4L2_STD_GH) {
- std = std_map->atv_gh.std_bits;
- sgIF = std_map->atv_gh.if_freq;
+ map = &std_map->atv_gh;
mode = "GH";
} else if (params->std & V4L2_STD_PAL_I) {
- std = std_map->atv_i.std_bits;
- sgIF = std_map->atv_i.if_freq;
+ map = &std_map->atv_i;
mode = "I";
} else if (params->std & V4L2_STD_DK) {
- std = std_map->atv_dk.std_bits;
- sgIF = std_map->atv_dk.if_freq;
+ map = &std_map->atv_dk;
mode = "DK";
} else if (params->std & V4L2_STD_SECAM_L) {
- std = std_map->atv_l.std_bits;
- sgIF = std_map->atv_l.if_freq;
+ map = &std_map->atv_l;
mode = "L";
} else if (params->std & V4L2_STD_SECAM_LC) {
- std = std_map->atv_lc.std_bits;
- sgIF = std_map->atv_lc.if_freq;
+ map = &std_map->atv_lc;
mode = "L'";
} else {
- std = std_map->atv_i.std_bits;
- sgIF = std_map->atv_i.if_freq;
+ map = &std_map->atv_i;
mode = "xx";
}
tda_dbg("setting tda18271 to system %s\n", mode);
- ret = tda18271_tune(fe, sgIF * 1000, freq, 0, std, radio);
+ ret = tda18271_tune(fe, map, freq, 0);
if (ret < 0)
goto fail;
@@ -986,16 +923,9 @@ static int tda18271_release(struct dvb_frontend *fe)
mutex_lock(&tda18271_list_mutex);
- priv->count--;
+ if (priv)
+ hybrid_tuner_release_state(priv);
- if (!priv->count) {
- tda_dbg("destroying instance @ %d-%04x\n",
- i2c_adapter_id(priv->i2c_adap),
- priv->i2c_addr);
- list_del(&priv->tda18271_list);
-
- kfree(priv);
- }
mutex_unlock(&tda18271_list_mutex);
fe->tuner_priv = NULL;
@@ -1020,15 +950,20 @@ static int tda18271_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
/* ------------------------------------------------------------------ */
#define tda18271_update_std(std_cfg, name) do { \
- if (map->std_cfg.if_freq + map->std_cfg.std_bits > 0) { \
+ if (map->std_cfg.if_freq + \
+ map->std_cfg.agc_mode + map->std_cfg.std + \
+ map->std_cfg.if_lvl + map->std_cfg.rfagc_top > 0) { \
tda_dbg("Using custom std config for %s\n", name); \
memcpy(&std->std_cfg, &map->std_cfg, \
sizeof(struct tda18271_std_map_item)); \
} } while (0)
#define tda18271_dump_std_item(std_cfg, name) do { \
- tda_dbg("(%s) if freq = %d, std bits = 0x%02x\n", \
- name, std->std_cfg.if_freq, std->std_cfg.std_bits); \
+ tda_dbg("(%s) if_freq = %d, agc_mode = %d, std = %d, " \
+ "if_lvl = %d, rfagc_top = 0x%02x\n", \
+ name, std->std_cfg.if_freq, \
+ std->std_cfg.agc_mode, std->std_cfg.std, \
+ std->std_cfg.if_lvl, std->std_cfg.rfagc_top); \
} while (0)
static int tda18271_dump_std_map(struct dvb_frontend *fe)
@@ -1037,20 +972,20 @@ static int tda18271_dump_std_map(struct dvb_frontend *fe)
struct tda18271_std_map *std = &priv->std;
tda_dbg("========== STANDARD MAP SETTINGS ==========\n");
- tda18271_dump_std_item(fm_radio, "fm");
- tda18271_dump_std_item(atv_b, "pal b");
- tda18271_dump_std_item(atv_dk, "pal dk");
- tda18271_dump_std_item(atv_gh, "pal gh");
- tda18271_dump_std_item(atv_i, "pal i");
- tda18271_dump_std_item(atv_l, "pal l");
- tda18271_dump_std_item(atv_lc, "pal l'");
+ tda18271_dump_std_item(fm_radio, " fm ");
+ tda18271_dump_std_item(atv_b, "atv b ");
+ tda18271_dump_std_item(atv_dk, "atv dk");
+ tda18271_dump_std_item(atv_gh, "atv gh");
+ tda18271_dump_std_item(atv_i, "atv i ");
+ tda18271_dump_std_item(atv_l, "atv l ");
+ tda18271_dump_std_item(atv_lc, "atv l'");
tda18271_dump_std_item(atv_mn, "atv mn");
tda18271_dump_std_item(atsc_6, "atsc 6");
tda18271_dump_std_item(dvbt_6, "dvbt 6");
tda18271_dump_std_item(dvbt_7, "dvbt 7");
tda18271_dump_std_item(dvbt_8, "dvbt 8");
- tda18271_dump_std_item(qam_6, "qam 6");
- tda18271_dump_std_item(qam_8, "qam 8");
+ tda18271_dump_std_item(qam_6, "qam 6 ");
+ tda18271_dump_std_item(qam_8, "qam 8 ");
return 0;
}
@@ -1109,7 +1044,8 @@ static int tda18271_get_id(struct dvb_frontend *fe)
}
tda_info("%s detected @ %d-%04x%s\n", name,
- i2c_adapter_id(priv->i2c_adap), priv->i2c_addr,
+ i2c_adapter_id(priv->i2c_props.adap),
+ priv->i2c_props.addr,
(0 == ret) ? "" : ", device not supported.");
return ret;
@@ -1136,45 +1072,28 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
struct tda18271_config *cfg)
{
struct tda18271_priv *priv = NULL;
- int state_found = 0;
+ int instance;
mutex_lock(&tda18271_list_mutex);
- list_for_each_entry(priv, &tda18271_list, tda18271_list) {
- if ((i2c_adapter_id(priv->i2c_adap) == i2c_adapter_id(i2c)) &&
- (priv->i2c_addr == addr)) {
- tda_dbg("attaching existing tuner @ %d-%04x\n",
- i2c_adapter_id(priv->i2c_adap),
- priv->i2c_addr);
- priv->count++;
- fe->tuner_priv = priv;
- state_found = 1;
- /* allow dvb driver to override i2c gate setting */
- if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
- priv->gate = cfg->gate;
- break;
- }
- }
- if (state_found == 0) {
- tda_dbg("creating new tuner instance @ %d-%04x\n",
- i2c_adapter_id(i2c), addr);
-
- priv = kzalloc(sizeof(struct tda18271_priv), GFP_KERNEL);
- if (priv == NULL) {
- mutex_unlock(&tda18271_list_mutex);
- return NULL;
- }
-
- priv->i2c_addr = addr;
- priv->i2c_adap = i2c;
+ instance = hybrid_tuner_request_state(struct tda18271_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c, addr, "tda18271");
+ switch (instance) {
+ case 0:
+ goto fail;
+ break;
+ case 1:
+ /* new tuner instance */
priv->gate = (cfg) ? cfg->gate : TDA18271_GATE_AUTO;
+ priv->role = (cfg) ? cfg->role : TDA18271_MASTER;
priv->cal_initialized = false;
mutex_init(&priv->lock);
- priv->count++;
fe->tuner_priv = priv;
- list_add_tail(&priv->tda18271_list, &tda18271_list);
+ if (cfg)
+ priv->small_i2c = cfg->small_i2c;
if (tda18271_get_id(fe) < 0)
goto fail;
@@ -1186,9 +1105,18 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
tda18271_init_regs(fe);
if ((tda18271_cal_on_startup) && (priv->id == TDA18271HDC2))
- tda18271_rf_cal_init(fe);
+ tda18271c2_rf_cal_init(fe);
mutex_unlock(&priv->lock);
+ break;
+ default:
+ /* existing tuner instance */
+ fe->tuner_priv = priv;
+
+ /* allow dvb driver to override i2c gate setting */
+ if ((cfg) && (cfg->gate != TDA18271_GATE_ANALOG))
+ priv->gate = cfg->gate;
+ break;
}
/* override default std map with values in config struct */
@@ -1200,7 +1128,7 @@ struct dvb_frontend *tda18271_attach(struct dvb_frontend *fe, u8 addr,
memcpy(&fe->ops.tuner_ops, &tda18271_tuner_ops,
sizeof(struct dvb_tuner_ops));
- if (tda18271_debug & DBG_MAP)
+ if (tda18271_debug & (DBG_MAP | DBG_ADV))
tda18271_dump_std_map(fe);
return fe;
@@ -1214,7 +1142,7 @@ EXPORT_SYMBOL_GPL(tda18271_attach);
MODULE_DESCRIPTION("NXP TDA18271HD analog / digital tuner driver");
MODULE_AUTHOR("Michael Krufky <mkrufky@linuxtv.org>");
MODULE_LICENSE("GPL");
-MODULE_VERSION("0.2");
+MODULE_VERSION("0.3");
/*
* Overrides for Emacs so that we follow Linus's tabbing style.
diff --git a/drivers/media/dvb/frontends/tda18271-priv.h b/drivers/media/dvb/frontends/tda18271-priv.h
index 7b939a5325fb..4b153bc557fe 100644
--- a/drivers/media/dvb/frontends/tda18271-priv.h
+++ b/drivers/media/dvb/frontends/tda18271-priv.h
@@ -24,6 +24,7 @@
#include <linux/kernel.h>
#include <linux/types.h>
#include <linux/mutex.h>
+#include "tuner-i2c.h"
#include "tda18271.h"
#define R_ID 0x00 /* ID byte */
@@ -85,6 +86,11 @@ struct tda18271_rf_tracking_filter_cal {
int rf_b2;
};
+enum tda18271_pll {
+ TDA18271_MAIN_PLL,
+ TDA18271_CAL_PLL,
+};
+
enum tda18271_mode {
TDA18271_ANALOG,
TDA18271_DIGITAL,
@@ -98,19 +104,19 @@ enum tda18271_ver {
};
struct tda18271_priv {
- u8 i2c_addr;
- struct i2c_adapter *i2c_adap;
unsigned char tda18271_regs[TDA18271_NUM_REGS];
- struct list_head tda18271_list;
+ struct list_head hybrid_tuner_instance_list;
+ struct tuner_i2c_props i2c_props;
enum tda18271_mode mode;
+ enum tda18271_role role;
enum tda18271_i2c_gate gate;
enum tda18271_ver id;
- unsigned int count;
unsigned int tm_rfcal;
unsigned int cal_initialized:1;
+ unsigned int small_i2c:1;
struct tda18271_map_layout *maps;
struct tda18271_std_map std;
@@ -188,6 +194,8 @@ extern int tda18271_read_extended(struct dvb_frontend *fe);
extern int tda18271_write_regs(struct dvb_frontend *fe, int idx, int len);
extern int tda18271_init_regs(struct dvb_frontend *fe);
+extern int tda18271_charge_pump_source(struct dvb_frontend *fe,
+ enum tda18271_pll pll, int force);
extern int tda18271_set_standby_mode(struct dvb_frontend *fe,
int sm, int sm_lt, int sm_xt);
diff --git a/drivers/media/dvb/frontends/tda18271-tables.c b/drivers/media/dvb/frontends/tda18271-tables.c
index e94afcfdc5bc..83e7561960c1 100644
--- a/drivers/media/dvb/frontends/tda18271-tables.c
+++ b/drivers/media/dvb/frontends/tda18271-tables.c
@@ -1187,37 +1187,65 @@ fail:
/*---------------------------------------------------------------------*/
static struct tda18271_std_map tda18271c1_std_map = {
- .fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
- .atv_b = { .if_freq = 6750, .std_bits = 0x0e },
- .atv_dk = { .if_freq = 7750, .std_bits = 0x0f },
- .atv_gh = { .if_freq = 7750, .std_bits = 0x0f },
- .atv_i = { .if_freq = 7750, .std_bits = 0x0f },
- .atv_l = { .if_freq = 7750, .std_bits = 0x0f },
- .atv_lc = { .if_freq = 1250, .std_bits = 0x0f },
- .atv_mn = { .if_freq = 5750, .std_bits = 0x0d },
- .atsc_6 = { .if_freq = 3250, .std_bits = 0x1c },
- .dvbt_6 = { .if_freq = 3300, .std_bits = 0x1c },
- .dvbt_7 = { .if_freq = 3800, .std_bits = 0x1d },
- .dvbt_8 = { .if_freq = 4300, .std_bits = 0x1e },
- .qam_6 = { .if_freq = 4000, .std_bits = 0x1d },
- .qam_8 = { .if_freq = 5000, .std_bits = 0x1f },
+ .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */
+ .atv_b = { .if_freq = 6750, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+ .atv_dk = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+ .atv_gh = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+ .atv_i = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+ .atv_l = { .if_freq = 7750, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+ .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 7,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0f */
+ .atv_mn = { .if_freq = 5750, .fm_rfn = 0, .agc_mode = 1, .std = 5,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */
+ .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+ .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+ .dvbt_7 = { .if_freq = 3800, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+ .dvbt_8 = { .if_freq = 4300, .fm_rfn = 0, .agc_mode = 3, .std = 6,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1e */
+ .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+ .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
};
static struct tda18271_std_map tda18271c2_std_map = {
- .fm_radio = { .if_freq = 1250, .std_bits = 0x18 },
- .atv_b = { .if_freq = 6000, .std_bits = 0x0d },
- .atv_dk = { .if_freq = 6900, .std_bits = 0x0e },
- .atv_gh = { .if_freq = 7100, .std_bits = 0x0e },
- .atv_i = { .if_freq = 7250, .std_bits = 0x0e },
- .atv_l = { .if_freq = 6900, .std_bits = 0x0e },
- .atv_lc = { .if_freq = 1250, .std_bits = 0x0e },
- .atv_mn = { .if_freq = 5400, .std_bits = 0x0c },
- .atsc_6 = { .if_freq = 3250, .std_bits = 0x1c },
- .dvbt_6 = { .if_freq = 3300, .std_bits = 0x1c },
- .dvbt_7 = { .if_freq = 3500, .std_bits = 0x1c },
- .dvbt_8 = { .if_freq = 4000, .std_bits = 0x1d },
- .qam_6 = { .if_freq = 4000, .std_bits = 0x1d },
- .qam_8 = { .if_freq = 5000, .std_bits = 0x1f },
+ .fm_radio = { .if_freq = 1250, .fm_rfn = 1, .agc_mode = 3, .std = 0,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x18 */
+ .atv_b = { .if_freq = 6000, .fm_rfn = 0, .agc_mode = 1, .std = 5,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0d */
+ .atv_dk = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+ .atv_gh = { .if_freq = 7100, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+ .atv_i = { .if_freq = 7250, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+ .atv_l = { .if_freq = 6900, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+ .atv_lc = { .if_freq = 1250, .fm_rfn = 0, .agc_mode = 1, .std = 6,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0e */
+ .atv_mn = { .if_freq = 5400, .fm_rfn = 0, .agc_mode = 1, .std = 4,
+ .if_lvl = 0, .rfagc_top = 0x2c, }, /* EP3[4:0] 0x0c */
+ .atsc_6 = { .if_freq = 3250, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+ .dvbt_6 = { .if_freq = 3300, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+ .dvbt_7 = { .if_freq = 3500, .fm_rfn = 0, .agc_mode = 3, .std = 4,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1c */
+ .dvbt_8 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+ .qam_6 = { .if_freq = 4000, .fm_rfn = 0, .agc_mode = 3, .std = 5,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1d */
+ .qam_8 = { .if_freq = 5000, .fm_rfn = 0, .agc_mode = 3, .std = 7,
+ .if_lvl = 1, .rfagc_top = 0x37, }, /* EP3[4:0] 0x1f */
};
/*---------------------------------------------------------------------*/
diff --git a/drivers/media/dvb/frontends/tda18271.h b/drivers/media/dvb/frontends/tda18271.h
index 24b0e35a2ab3..b547318c951b 100644
--- a/drivers/media/dvb/frontends/tda18271.h
+++ b/drivers/media/dvb/frontends/tda18271.h
@@ -26,7 +26,17 @@
struct tda18271_std_map_item {
u16 if_freq;
- u8 std_bits;
+
+ /* EP3[4:3] */
+ unsigned int agc_mode:2;
+ /* EP3[2:0] */
+ unsigned int std:3;
+ /* EP4[7] */
+ unsigned int fm_rfn:1;
+ /* EP4[4:2] */
+ unsigned int if_lvl:3;
+ /* EB22[6:0] */
+ unsigned int rfagc_top:7;
};
struct tda18271_std_map {
@@ -46,6 +56,11 @@ struct tda18271_std_map {
struct tda18271_std_map_item qam_8;
};
+enum tda18271_role {
+ TDA18271_MASTER = 0,
+ TDA18271_SLAVE,
+};
+
enum tda18271_i2c_gate {
TDA18271_GATE_AUTO = 0,
TDA18271_GATE_ANALOG,
@@ -56,8 +71,14 @@ struct tda18271_config {
/* override default if freq / std settings (optional) */
struct tda18271_std_map *std_map;
+ /* master / slave tuner: master uses main pll, slave uses cal pll */
+ enum tda18271_role role;
+
/* use i2c gate provided by analog or digital demod */
enum tda18271_i2c_gate gate;
+
+ /* some i2c providers cant write all 39 registers at once */
+ unsigned int small_i2c:1;
};
#if defined(CONFIG_DVB_TDA18271) || (defined(CONFIG_DVB_TDA18271_MODULE) && defined(MODULE))
diff --git a/drivers/media/dvb/frontends/tda826x.c b/drivers/media/dvb/frontends/tda826x.c
index bd3ebc284835..9a91eb0333d9 100644
--- a/drivers/media/dvb/frontends/tda826x.c
+++ b/drivers/media/dvb/frontends/tda826x.c
@@ -26,7 +26,7 @@
#include "tda826x.h"
-static int debug = 0;
+static int debug;
#define dprintk(args...) \
do { \
if (debug) printk(KERN_DEBUG "tda826x: " args); \
diff --git a/drivers/media/dvb/frontends/tda827x.c b/drivers/media/dvb/frontends/tda827x.c
index 229b11987a58..d30d2c9094d9 100644
--- a/drivers/media/dvb/frontends/tda827x.c
+++ b/drivers/media/dvb/frontends/tda827x.c
@@ -25,7 +25,7 @@
#include "tda827x.h"
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
@@ -142,7 +142,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
int i, tuner_freq, if_freq;
u32 N;
- dprintk("%s:\n", __FUNCTION__);
+ dprintk("%s:\n", __func__);
switch (params->u.ofdm.bandwidth) {
case BANDWIDTH_6_MHZ:
if_freq = 4000000;
@@ -186,7 +186,7 @@ static int tda827xo_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
printk("%s: could not write to tuner at addr: 0x%02x\n",
- __FUNCTION__, priv->i2c_addr << 1);
+ __func__, priv->i2c_addr << 1);
return -EIO;
}
msleep(500);
@@ -212,7 +212,7 @@ static int tda827xo_sleep(struct dvb_frontend *fe)
struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
.buf = buf, .len = sizeof(buf) };
- dprintk("%s:\n", __FUNCTION__);
+ dprintk("%s:\n", __func__);
if (fe->ops.i2c_gate_ctrl)
fe->ops.i2c_gate_ctrl(fe, 1);
i2c_transfer(priv->i2c_adap, &msg, 1);
@@ -389,6 +389,79 @@ static struct tda827xa_data tda827xa_analog[] = {
{ .lomax = 0, .svco = 0, .spd = 0, .scr = 0, .sbs = 0, .gc3 = 0}
};
+static int tda827xa_sleep(struct dvb_frontend *fe)
+{
+ struct tda827x_priv *priv = fe->tuner_priv;
+ static u8 buf[] = { 0x30, 0x90 };
+ struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+
+ dprintk("%s:\n", __func__);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ i2c_transfer(priv->i2c_adap, &msg, 1);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+
+ if (priv->cfg && priv->cfg->sleep)
+ priv->cfg->sleep(fe);
+
+ return 0;
+}
+
+static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
+ struct analog_parameters *params)
+{
+ struct tda827x_priv *priv = fe->tuner_priv;
+ unsigned char buf[] = {0x22, 0x01};
+ int arg;
+ int gp_func;
+ struct i2c_msg msg = { .addr = priv->cfg->switch_addr, .flags = 0,
+ .buf = buf, .len = sizeof(buf) };
+
+ if (NULL == priv->cfg) {
+ dprintk("tda827x_config not defined, cannot set LNA gain!\n");
+ return;
+ }
+ if (priv->cfg->config) {
+ if (high)
+ dprintk("setting LNA to high gain\n");
+ else
+ dprintk("setting LNA to low gain\n");
+ }
+ switch (priv->cfg->config) {
+ case 0: /* no LNA */
+ break;
+ case 1: /* switch is GPIO 0 of tda8290 */
+ case 2:
+ if (params == NULL) {
+ gp_func = 0;
+ arg = 0;
+ } else {
+ /* turn Vsync on */
+ gp_func = 1;
+ if (params->std & V4L2_STD_MN)
+ arg = 1;
+ else
+ arg = 0;
+ }
+ if (priv->cfg->tuner_callback)
+ priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
+ gp_func, arg);
+ buf[1] = high ? 0 : 1;
+ if (priv->cfg->config == 2)
+ buf[1] = high ? 1 : 0;
+ i2c_transfer(priv->i2c_adap, &msg, 1);
+ break;
+ case 3: /* switch with GPIO of saa713x */
+ if (priv->cfg->tuner_callback)
+ priv->cfg->tuner_callback(priv->i2c_adap->algo_data, 0, high);
+ break;
+ }
+}
+
static int tda827xa_set_params(struct dvb_frontend *fe,
struct dvb_frontend_parameters *params)
{
@@ -401,9 +474,9 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
int i, tuner_freq, if_freq;
u32 N;
- dprintk("%s:\n", __FUNCTION__);
- if (priv->cfg && priv->cfg->lna_gain)
- priv->cfg->lna_gain(fe, 1);
+ dprintk("%s:\n", __func__);
+
+ tda827xa_lna_gain(fe, 1, NULL);
msleep(20);
switch (params->u.ofdm.bandwidth) {
@@ -444,7 +517,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
printk("%s: could not write to tuner at addr: 0x%02x\n",
- __FUNCTION__, priv->i2c_addr << 1);
+ __func__, priv->i2c_addr << 1);
return -EIO;
}
buf[0] = 0x90;
@@ -474,8 +547,7 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
buf[1] >>= 4;
dprintk("tda8275a AGC2 gain is: %d\n", buf[1]);
if ((buf[1]) < 2) {
- if (priv->cfg && priv->cfg->lna_gain)
- priv->cfg->lna_gain(fe, 0);
+ tda827xa_lna_gain(fe, 0, NULL);
buf[0] = 0x60;
buf[1] = 0x0c;
if (fe->ops.i2c_gate_ctrl)
@@ -523,75 +595,6 @@ static int tda827xa_set_params(struct dvb_frontend *fe,
return 0;
}
-static int tda827xa_sleep(struct dvb_frontend *fe)
-{
- struct tda827x_priv *priv = fe->tuner_priv;
- static u8 buf[] = { 0x30, 0x90 };
- struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
- .buf = buf, .len = sizeof(buf) };
-
- dprintk("%s:\n", __FUNCTION__);
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 1);
-
- i2c_transfer(priv->i2c_adap, &msg, 1);
-
- if (fe->ops.i2c_gate_ctrl)
- fe->ops.i2c_gate_ctrl(fe, 0);
-
- if (priv->cfg && priv->cfg->sleep)
- priv->cfg->sleep(fe);
-
- return 0;
-}
-
-/* ------------------------------------------------------------------ */
-
-static void tda827xa_lna_gain(struct dvb_frontend *fe, int high,
- struct analog_parameters *params)
-{
- struct tda827x_priv *priv = fe->tuner_priv;
- unsigned char buf[] = {0x22, 0x01};
- int arg;
- struct i2c_msg msg = { .addr = priv->i2c_addr, .flags = 0,
- .buf = buf, .len = sizeof(buf) };
-
- if (NULL == priv->cfg) {
- dprintk("tda827x_config not defined, cannot set LNA gain!\n");
- return;
- }
-
- if (priv->cfg->config) {
- if (high)
- dprintk("setting LNA to high gain\n");
- else
- dprintk("setting LNA to low gain\n");
- }
- switch (*priv->cfg->config) {
- case 0: /* no LNA */
- break;
- case 1: /* switch is GPIO 0 of tda8290 */
- case 2:
- /* turn Vsync on */
- if (params->std & V4L2_STD_MN)
- arg = 1;
- else
- arg = 0;
- if (priv->cfg->tuner_callback)
- priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
- 1, arg);
- buf[1] = high ? 0 : 1;
- if (*priv->cfg->config == 2)
- buf[1] = high ? 1 : 0;
- i2c_transfer(priv->i2c_adap, &msg, 1);
- break;
- case 3: /* switch with GPIO of saa713x */
- if (priv->cfg->tuner_callback)
- priv->cfg->tuner_callback(priv->i2c_adap->algo_data,
- 0, high);
- break;
- }
-}
static int tda827xa_set_analog_params(struct dvb_frontend *fe,
struct analog_parameters *params)
@@ -726,7 +729,7 @@ static int tda827x_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
static int tda827x_init(struct dvb_frontend *fe)
{
struct tda827x_priv *priv = fe->tuner_priv;
- dprintk("%s:\n", __FUNCTION__);
+ dprintk("%s:\n", __func__);
if (priv->cfg && priv->cfg->init)
priv->cfg->init(fe);
@@ -794,7 +797,7 @@ static int tda827x_probe_version(struct dvb_frontend *fe)
fe->ops.i2c_gate_ctrl(fe, 1);
if (i2c_transfer(priv->i2c_adap, &msg, 1) != 1) {
printk("%s: could not read from tuner at addr: 0x%02x\n",
- __FUNCTION__, msg.addr << 1);
+ __func__, msg.addr << 1);
return -EIO;
}
if ((data & 0x3c) == 0) {
@@ -818,7 +821,7 @@ struct dvb_frontend *tda827x_attach(struct dvb_frontend *fe, int addr,
{
struct tda827x_priv *priv = NULL;
- dprintk("%s:\n", __FUNCTION__);
+ dprintk("%s:\n", __func__);
priv = kzalloc(sizeof(struct tda827x_priv), GFP_KERNEL);
if (priv == NULL)
return NULL;
diff --git a/drivers/media/dvb/frontends/tda827x.h b/drivers/media/dvb/frontends/tda827x.h
index 92eb65b4012b..cd3032f985cd 100644
--- a/drivers/media/dvb/frontends/tda827x.h
+++ b/drivers/media/dvb/frontends/tda827x.h
@@ -30,12 +30,12 @@
struct tda827x_config
{
/* saa7134 - provided callbacks */
- void (*lna_gain) (struct dvb_frontend *fe, int high);
int (*init) (struct dvb_frontend *fe);
int (*sleep) (struct dvb_frontend *fe);
/* interface to tda829x driver */
- unsigned int *config;
+ unsigned int config;
+ int switch_addr;
int (*tuner_callback) (void *dev, int command, int arg);
void (*agcf)(struct dvb_frontend *fe);
diff --git a/drivers/media/dvb/frontends/ves1x93.c b/drivers/media/dvb/frontends/ves1x93.c
index 23fd0303c91b..c041c81f9686 100644
--- a/drivers/media/dvb/frontends/ves1x93.c
+++ b/drivers/media/dvb/frontends/ves1x93.c
@@ -48,7 +48,7 @@ struct ves1x93_state {
u8 demod_type;
};
-static int debug = 0;
+static int debug;
#define dprintk if (debug) printk
#define DEMOD_VES1893 0
diff --git a/drivers/media/dvb/frontends/xc5000.c b/drivers/media/dvb/frontends/xc5000.c
index f642ca200b59..a5094b7f21fd 100644
--- a/drivers/media/dvb/frontends/xc5000.c
+++ b/drivers/media/dvb/frontends/xc5000.c
@@ -151,7 +151,7 @@ typedef struct {
#define FM_Radio_INPUT2 21
#define FM_Radio_INPUT1 22
-XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
+static XC_TV_STANDARD XC5000_Standard[MAX_TV_STANDARD] = {
{"M/N-NTSC/PAL-BTSC", 0x0400, 0x8020},
{"M/N-NTSC/PAL-A2", 0x0600, 0x8020},
{"M/N-NTSC/PAL-EIAJ", 0x0440, 0x8020},
diff --git a/drivers/media/dvb/frontends/zl10353.c b/drivers/media/dvb/frontends/zl10353.c
index 276e3b631dc2..3d508ff4b292 100644
--- a/drivers/media/dvb/frontends/zl10353.c
+++ b/drivers/media/dvb/frontends/zl10353.c
@@ -46,7 +46,7 @@ static int debug;
if (debug) printk(KERN_DEBUG "zl10353: " args); \
} while (0)
-static int debug_regs = 0;
+static int debug_regs;
static int zl10353_single_write(struct dvb_frontend *fe, u8 reg, u8 val)
{
diff --git a/drivers/media/dvb/ttpci/budget-ci.c b/drivers/media/dvb/ttpci/budget-ci.c
index 509349211d4f..0f476f75e03d 100644
--- a/drivers/media/dvb/ttpci/budget-ci.c
+++ b/drivers/media/dvb/ttpci/budget-ci.c
@@ -86,7 +86,7 @@ static int rc5_device = -1;
module_param(rc5_device, int, 0644);
MODULE_PARM_DESC(rc5_device, "only IR commands to given RC5 device (device = 0 - 31, any device = 255, default: autodetect)");
-static int ir_debug = 0;
+static int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug, "enable debugging information for IR decoding");
diff --git a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
index 7902ae1d9a18..1b3b6c1589f7 100644
--- a/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
+++ b/drivers/media/dvb/ttusb-budget/dvb-ttusb-budget.c
@@ -542,7 +542,7 @@ static void ttusb_handle_sec_data(struct ttusb_channel *channel,
const u8 * data, int len);
#endif
-static int numpkt = 0, numts, numstuff, numsec, numinvalid;
+static int numpkt, numts, numstuff, numsec, numinvalid;
static unsigned long lastj;
static void ttusb_process_muxpack(struct ttusb *ttusb, const u8 * muxpack,
@@ -1005,7 +1005,7 @@ static int stc_release(struct inode *inode, struct file *file)
return 0;
}
-static struct file_operations stc_fops = {
+static const struct file_operations stc_fops = {
.owner = THIS_MODULE,
.read = stc_read,
.open = stc_open,
diff --git a/drivers/media/radio/dsbr100.c b/drivers/media/radio/dsbr100.c
index 36c0e3651502..4e3f83e4e48f 100644
--- a/drivers/media/radio/dsbr100.c
+++ b/drivers/media/radio/dsbr100.c
@@ -438,7 +438,9 @@ static const struct file_operations usb_dsbr100_fops = {
.open = usb_dsbr100_open,
.release = usb_dsbr100_close,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/miropcm20-radio.c b/drivers/media/radio/miropcm20-radio.c
index 3ae56fef8c92..09fe6f1cdf14 100644
--- a/drivers/media/radio/miropcm20-radio.c
+++ b/drivers/media/radio/miropcm20-radio.c
@@ -221,7 +221,9 @@ static const struct file_operations pcm20_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = pcm20_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/miropcm20-rds.c b/drivers/media/radio/miropcm20-rds.c
index aed11477378b..06dfed9ef4c7 100644
--- a/drivers/media/radio/miropcm20-rds.c
+++ b/drivers/media/radio/miropcm20-rds.c
@@ -19,7 +19,7 @@
#include "miropcm20-rds-core.h"
static char * text_buffer;
-static int rds_users = 0;
+static int rds_users;
static int rds_f_open(struct inode *in, struct file *fi)
diff --git a/drivers/media/radio/radio-aimslab.c b/drivers/media/radio/radio-aimslab.c
index f0a67e93d7fd..edfa117521c7 100644
--- a/drivers/media/radio/radio-aimslab.c
+++ b/drivers/media/radio/radio-aimslab.c
@@ -383,7 +383,9 @@ static const struct file_operations rtrack_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-aztech.c b/drivers/media/radio/radio-aztech.c
index 9b1f7a99dac0..46cdb549eac7 100644
--- a/drivers/media/radio/radio-aztech.c
+++ b/drivers/media/radio/radio-aztech.c
@@ -346,7 +346,9 @@ static const struct file_operations aztech_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-cadet.c b/drivers/media/radio/radio-cadet.c
index 57b9e3adc8f0..b14db53ea456 100644
--- a/drivers/media/radio/radio-cadet.c
+++ b/drivers/media/radio/radio-cadet.c
@@ -69,13 +69,13 @@ static struct v4l2_queryctrl radio_qctrl[] = {
static int io=-1; /* default to isapnp activation */
static int radio_nr = -1;
-static int users=0;
-static int curtuner=0;
-static int tunestat=0;
-static int sigstrength=0;
+static int users;
+static int curtuner;
+static int tunestat;
+static int sigstrength;
static wait_queue_head_t read_queue;
static struct timer_list readtimer;
-static __u8 rdsin=0,rdsout=0,rdsstat=0;
+static __u8 rdsin, rdsout, rdsstat;
static unsigned char rdsbuf[RDS_BUFFER];
static spinlock_t cadet_io_lock;
@@ -563,7 +563,9 @@ static const struct file_operations cadet_fops = {
.read = cadet_read,
.ioctl = video_ioctl2,
.poll = cadet_poll,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-gemtek-pci.c b/drivers/media/radio/radio-gemtek-pci.c
index 99a323131333..de49be971480 100644
--- a/drivers/media/radio/radio-gemtek-pci.c
+++ b/drivers/media/radio/radio-gemtek-pci.c
@@ -368,7 +368,9 @@ static const struct file_operations gemtek_pci_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-gemtek.c b/drivers/media/radio/radio-gemtek.c
index 246422b49267..81f6aeb1cd11 100644
--- a/drivers/media/radio/radio-gemtek.c
+++ b/drivers/media/radio/radio-gemtek.c
@@ -397,7 +397,9 @@ static const struct file_operations gemtek_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek
};
diff --git a/drivers/media/radio/radio-maestro.c b/drivers/media/radio/radio-maestro.c
index bc51f4d23a5a..bddd3c409aa9 100644
--- a/drivers/media/radio/radio-maestro.c
+++ b/drivers/media/radio/radio-maestro.c
@@ -100,7 +100,9 @@ static const struct file_operations maestro_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-maxiradio.c b/drivers/media/radio/radio-maxiradio.c
index 8e184cfc1c94..0133ecf3e040 100644
--- a/drivers/media/radio/radio-maxiradio.c
+++ b/drivers/media/radio/radio-maxiradio.c
@@ -103,7 +103,9 @@ static const struct file_operations maxiradio_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-rtrack2.c b/drivers/media/radio/radio-rtrack2.c
index 82aedfc95d4f..070802103dc3 100644
--- a/drivers/media/radio/radio-rtrack2.c
+++ b/drivers/media/radio/radio-rtrack2.c
@@ -288,7 +288,9 @@ static const struct file_operations rtrack2_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-sf16fmi.c b/drivers/media/radio/radio-sf16fmi.c
index 53e114857377..66e052fd3909 100644
--- a/drivers/media/radio/radio-sf16fmi.c
+++ b/drivers/media/radio/radio-sf16fmi.c
@@ -288,7 +288,9 @@ static const struct file_operations fmi_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-sf16fmr2.c b/drivers/media/radio/radio-sf16fmr2.c
index ebc5fbbc38bb..b0ccf7cb5952 100644
--- a/drivers/media/radio/radio-sf16fmr2.c
+++ b/drivers/media/radio/radio-sf16fmr2.c
@@ -29,6 +29,8 @@ static struct mutex lock;
#include <linux/version.h> /* for KERNEL_VERSION MACRO */
#define RADIO_VERSION KERNEL_VERSION(0,0,2)
+#define AUD_VOL_INDEX 1
+
static struct v4l2_queryctrl radio_qctrl[] = {
{
.id = V4L2_CID_AUDIO_MUTE,
@@ -37,13 +39,14 @@ static struct v4l2_queryctrl radio_qctrl[] = {
.maximum = 1,
.default_value = 1,
.type = V4L2_CTRL_TYPE_BOOLEAN,
- },{
+ },
+ [AUD_VOL_INDEX] = {
.id = V4L2_CID_AUDIO_VOLUME,
.name = "Volume",
.minimum = 0,
- .maximum = 65535,
- .step = 1<<12,
- .default_value = 0xff,
+ .maximum = 15,
+ .step = 1,
+ .default_value = 0,
.type = V4L2_CTRL_TYPE_INTEGER,
}
};
@@ -61,7 +64,7 @@ static struct v4l2_queryctrl radio_qctrl[] = {
struct fmr2_device
{
int port;
- int curvol; /* 0-65535, if not volume 0 or 65535 */
+ int curvol; /* 0-15 */
int mute;
int stereo; /* card is producing stereo audio */
unsigned long curfreq; /* freq in kHz */
@@ -176,51 +179,35 @@ static int fmr2_setfreq(struct fmr2_device *dev)
/* !!! not tested, in my card this does't work !!! */
static int fmr2_setvolume(struct fmr2_device *dev)
{
- int i,a,n, port = dev->port;
+ int vol[16] = { 0x021, 0x084, 0x090, 0x104,
+ 0x110, 0x204, 0x210, 0x402,
+ 0x404, 0x408, 0x410, 0x801,
+ 0x802, 0x804, 0x808, 0x810 };
+ int i, a, port = dev->port;
+ int n = vol[dev->curvol & 0x0f];
- if (dev->card_type != 11) return 1;
+ if (dev->card_type != 11)
+ return 1;
- switch( (dev->curvol+(1<<11)) >> 12 )
- {
- case 0: case 1: n = 0x21; break;
- case 2: n = 0x84; break;
- case 3: n = 0x90; break;
- case 4: n = 0x104; break;
- case 5: n = 0x110; break;
- case 6: n = 0x204; break;
- case 7: n = 0x210; break;
- case 8: n = 0x402; break;
- case 9: n = 0x404; break;
- default:
- case 10: n = 0x408; break;
- case 11: n = 0x410; break;
- case 12: n = 0x801; break;
- case 13: n = 0x802; break;
- case 14: n = 0x804; break;
- case 15: n = 0x808; break;
- case 16: n = 0x810; break;
- }
- for(i=12;--i>=0;)
- {
+ for (i = 12; --i >= 0; ) {
a = ((n >> i) & 1) << 6; /* if (a=0) a= 0; else a= 0x40; */
- outb(a|4, port);
- wait(4,port);
- outb(a|0x24, port);
- wait(4,port);
- outb(a|4, port);
- wait(4,port);
+ outb(a | 4, port);
+ wait(4, port);
+ outb(a | 0x24, port);
+ wait(4, port);
+ outb(a | 4, port);
+ wait(4, port);
}
- for(i=6;--i>=0;)
- {
+ for (i = 6; --i >= 0; ) {
a = ((0x18 >> i) & 1) << 6;
- outb(a|4, port);
+ outb(a | 4, port);
wait(4,port);
- outb(a|0x24, port);
+ outb(a | 0x24, port);
wait(4,port);
outb(a|4, port);
wait(4,port);
}
- wait(4,port);
+ wait(4, port);
outb(0x14, port);
return 0;
@@ -312,16 +299,10 @@ static int vidioc_queryctrl(struct file *file, void *priv,
struct v4l2_queryctrl *qc)
{
int i;
- struct video_device *dev = video_devdata(file);
- struct fmr2_device *fmr2 = dev->priv;
for (i = 0; i < ARRAY_SIZE(radio_qctrl); i++) {
- if ((fmr2->card_type != 11)
- && V4L2_CID_AUDIO_VOLUME)
- radio_qctrl[i].step = 65535;
if (qc->id && qc->id == radio_qctrl[i].id) {
- memcpy(qc, &(radio_qctrl[i]),
- sizeof(*qc));
+ memcpy(qc, &radio_qctrl[i], sizeof(*qc));
return 0;
}
}
@@ -354,24 +335,13 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
switch (ctrl->id) {
case V4L2_CID_AUDIO_MUTE:
fmr2->mute = ctrl->value;
- if (fmr2->card_type != 11) {
- if (!fmr2->mute)
- fmr2->curvol = 65535;
- else
- fmr2->curvol = 0;
- }
break;
case V4L2_CID_AUDIO_VOLUME:
- fmr2->curvol = ctrl->value;
- if (fmr2->card_type != 11) {
- if (fmr2->curvol) {
- fmr2->curvol = 65535;
- fmr2->mute = 0;
- } else {
- fmr2->curvol = 0;
- fmr2->mute = 1;
- }
- }
+ if (ctrl->value > radio_qctrl[AUD_VOL_INDEX].maximum)
+ fmr2->curvol = radio_qctrl[AUD_VOL_INDEX].maximum;
+ else
+ fmr2->curvol = ctrl->value;
+
break;
default:
return -EINVAL;
@@ -387,6 +357,7 @@ static int vidioc_s_ctrl(struct file *file, void *priv,
mutex_lock(&lock);
if (fmr2->curvol && !fmr2->mute) {
fmr2_setvolume(fmr2);
+ /* Set frequency and unmute card */
fmr2_setfreq(fmr2);
} else
fmr2_mute(fmr2->port);
@@ -433,7 +404,9 @@ static const struct file_operations fmr2_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
@@ -487,6 +460,11 @@ static int __init fmr2_init(void)
fmr2_product_info(&fmr2_unit);
mutex_unlock(&lock);
debug_print((KERN_DEBUG "card_type %d\n", fmr2_unit.card_type));
+
+ /* Only card_type == 11 implements volume */
+ if (fmr2_unit.card_type != 11)
+ radio_qctrl[AUD_VOL_INDEX].maximum = 1;
+
return 0;
}
diff --git a/drivers/media/radio/radio-si470x.c b/drivers/media/radio/radio-si470x.c
index 649f14d2c013..77354ca6e8e9 100644
--- a/drivers/media/radio/radio-si470x.c
+++ b/drivers/media/radio/radio-si470x.c
@@ -85,6 +85,7 @@
* Oliver Neukum <oliver@neukum.org>
* Version 1.0.7
* - usb autosuspend support
+ * - unplugging fixed
*
* ToDo:
* - add seeking support
@@ -97,10 +98,10 @@
/* driver definitions */
#define DRIVER_AUTHOR "Tobias Lorenz <tobias.lorenz@gmx.net>"
#define DRIVER_NAME "radio-si470x"
-#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 6)
+#define DRIVER_KERNEL_VERSION KERNEL_VERSION(1, 0, 7)
#define DRIVER_CARD "Silicon Labs Si470x FM Radio Receiver"
#define DRIVER_DESC "USB radio driver for Si470x FM Radio Receivers"
-#define DRIVER_VERSION "1.0.6"
+#define DRIVER_VERSION "1.0.7"
/* kernel includes */
@@ -424,6 +425,7 @@ struct si470x_device {
/* driver management */
unsigned int users;
+ unsigned char disconnected;
/* Silabs internal registers (0..15) */
unsigned short registers[RADIO_REGISTER_NUM];
@@ -440,6 +442,12 @@ struct si470x_device {
/*
+ * Lock to prevent kfree of data before all users have releases the device.
+ */
+static DEFINE_MUTEX(open_close_lock);
+
+
+/*
* The frequency is set in units of 62.5 Hz when using V4L2_TUNER_CAP_LOW,
* 62.5 kHz otherwise.
* The tuner is able to have a channel spacing of 50, 100 or 200 kHz.
@@ -577,7 +585,7 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
usb_rcvintpipe(radio->usbdev, 1),
(void *) &buf, sizeof(buf), &size, usb_timeout);
if (size != sizeof(buf))
- printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_register: "
+ printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
"return size differs: %d != %zu\n", size, sizeof(buf));
if (retval < 0)
printk(KERN_WARNING DRIVER_NAME ": si470x_get_rds_registers: "
@@ -875,6 +883,8 @@ static void si470x_work(struct work_struct *work)
struct si470x_device *radio = container_of(work, struct si470x_device,
work.work);
+ if (radio->disconnected)
+ return;
if ((radio->registers[SYSCONFIG1] & SYSCONFIG1_RDS) == 0)
return;
@@ -1001,13 +1011,21 @@ static int si470x_fops_open(struct inode *inode, struct file *file)
static int si470x_fops_release(struct inode *inode, struct file *file)
{
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
- int retval;
+ int retval = 0;
if (!radio)
return -ENODEV;
+ mutex_lock(&open_close_lock);
radio->users--;
if (radio->users == 0) {
+ if (radio->disconnected) {
+ video_unregister_device(radio->videodev);
+ kfree(radio->buffer);
+ kfree(radio);
+ goto done;
+ }
+
/* stop rds reception */
cancel_delayed_work_sync(&radio->work);
@@ -1016,10 +1034,11 @@ static int si470x_fops_release(struct inode *inode, struct file *file)
retval = si470x_stop(radio);
usb_autopm_put_interface(radio->intf);
- return retval;
}
- return 0;
+done:
+ mutex_unlock(&open_close_lock);
+ return retval;
}
@@ -1032,7 +1051,9 @@ static const struct file_operations si470x_fops = {
.read = si470x_fops_read,
.poll = si470x_fops_poll,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.open = si470x_fops_open,
.release = si470x_fops_release,
};
@@ -1157,6 +1178,9 @@ static int si470x_vidioc_g_ctrl(struct file *file, void *priv,
{
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+ if (radio->disconnected)
+ return -EIO;
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
ctrl->value = radio->registers[SYSCONFIG2] &
@@ -1181,6 +1205,9 @@ static int si470x_vidioc_s_ctrl(struct file *file, void *priv,
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
int retval;
+ if (radio->disconnected)
+ return -EIO;
+
switch (ctrl->id) {
case V4L2_CID_AUDIO_VOLUME:
radio->registers[SYSCONFIG2] &= ~SYSCONFIG2_VOLUME;
@@ -1243,6 +1270,8 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
int retval;
+ if (radio->disconnected)
+ return -EIO;
if (tuner->index > 0)
return -EINVAL;
@@ -1299,6 +1328,8 @@ static int si470x_vidioc_s_tuner(struct file *file, void *priv,
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
int retval;
+ if (radio->disconnected)
+ return -EIO;
if (tuner->index > 0)
return -EINVAL;
@@ -1324,6 +1355,9 @@ static int si470x_vidioc_g_frequency(struct file *file, void *priv,
{
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
+ if (radio->disconnected)
+ return -EIO;
+
freq->type = V4L2_TUNER_RADIO;
freq->frequency = si470x_get_freq(radio);
@@ -1340,6 +1374,8 @@ static int si470x_vidioc_s_frequency(struct file *file, void *priv,
struct si470x_device *radio = video_get_drvdata(video_devdata(file));
int retval;
+ if (radio->disconnected)
+ return -EIO;
if (freq->type != V4L2_TUNER_RADIO)
return -EINVAL;
@@ -1510,11 +1546,16 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
{
struct si470x_device *radio = usb_get_intfdata(intf);
+ mutex_lock(&open_close_lock);
+ radio->disconnected = 1;
cancel_delayed_work_sync(&radio->work);
usb_set_intfdata(intf, NULL);
- video_unregister_device(radio->videodev);
- kfree(radio->buffer);
- kfree(radio);
+ if (radio->users == 0) {
+ video_unregister_device(radio->videodev);
+ kfree(radio->buffer);
+ kfree(radio);
+ }
+ mutex_unlock(&open_close_lock);
}
diff --git a/drivers/media/radio/radio-terratec.c b/drivers/media/radio/radio-terratec.c
index 535ffe8c8102..acc32080e9bd 100644
--- a/drivers/media/radio/radio-terratec.c
+++ b/drivers/media/radio/radio-terratec.c
@@ -360,7 +360,9 @@ static const struct file_operations terratec_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-trust.c b/drivers/media/radio/radio-trust.c
index c11981fed827..4ebdfbadeb9c 100644
--- a/drivers/media/radio/radio-trust.c
+++ b/drivers/media/radio/radio-trust.c
@@ -340,7 +340,9 @@ static const struct file_operations trust_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/radio/radio-typhoon.c b/drivers/media/radio/radio-typhoon.c
index 1366326474e5..8b9888337bd1 100644
--- a/drivers/media/radio/radio-typhoon.c
+++ b/drivers/media/radio/radio-typhoon.c
@@ -340,7 +340,9 @@ static const struct file_operations typhoon_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
@@ -404,7 +406,7 @@ MODULE_PARM_DESC(io, "I/O address of the Typhoon card (0x316 or 0x336)");
module_param(radio_nr, int, 0);
#ifdef MODULE
-static unsigned long mutefreq = 0;
+static unsigned long mutefreq;
module_param(mutefreq, ulong, 0);
MODULE_PARM_DESC(mutefreq, "Frequency used when muting the card (in kHz)");
#endif
diff --git a/drivers/media/radio/radio-zoltrix.c b/drivers/media/radio/radio-zoltrix.c
index 203f4373eeb8..43773c56c62f 100644
--- a/drivers/media/radio/radio-zoltrix.c
+++ b/drivers/media/radio/radio-zoltrix.c
@@ -401,7 +401,9 @@ static const struct file_operations zoltrix_fops =
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 1832966f53f3..de6a6208e344 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -836,4 +836,49 @@ config USB_STKWEBCAM
endif # V4L_USB_DRIVERS
+config SOC_CAMERA
+ tristate "SoC camera support"
+ depends on VIDEO_V4L2
+ select VIDEOBUF_DMA_SG
+ help
+ SoC Camera is a common API to several cameras, not connecting
+ over a bus like PCI or USB. For example some i2c camera connected
+ directly to the data bus of an SoC.
+
+config SOC_CAMERA_MT9M001
+ tristate "mt9m001 support"
+ depends on SOC_CAMERA
+ select GPIO_PCA953X if MT9M001_PCA9536_SWITCH
+ help
+ This driver supports MT9M001 cameras from Micron, monochrome
+ and colour models.
+
+config MT9M001_PCA9536_SWITCH
+ bool "pca9536 datawidth switch for mt9m001"
+ depends on SOC_CAMERA_MT9M001 && GENERIC_GPIO
+ help
+ Select this if your MT9M001 camera uses a PCA9536 I2C GPIO
+ extender to switch between 8 and 10 bit datawidth modes
+
+config SOC_CAMERA_MT9V022
+ tristate "mt9v022 support"
+ depends on SOC_CAMERA
+ select GPIO_PCA953X if MT9V022_PCA9536_SWITCH
+ help
+ This driver supports MT9V022 cameras from Micron
+
+config MT9V022_PCA9536_SWITCH
+ bool "pca9536 datawidth switch for mt9v022"
+ depends on SOC_CAMERA_MT9V022 && GENERIC_GPIO
+ help
+ Select this if your MT9V022 camera uses a PCA9536 I2C GPIO
+ extender to switch between 8 and 10 bit datawidth modes
+
+config VIDEO_PXA27x
+ tristate "PXA27x Quick Capture Interface driver"
+ depends on VIDEO_DEV && PXA27x
+ select SOC_CAMERA
+ ---help---
+ This is a v4l2 driver for the PXA27x Quick Capture Interface
+
endif # VIDEO_CAPTURE_DRIVERS
diff --git a/drivers/media/video/Makefile b/drivers/media/video/Makefile
index 3f209b32eeac..8b1e97a7caa3 100644
--- a/drivers/media/video/Makefile
+++ b/drivers/media/video/Makefile
@@ -4,7 +4,7 @@
zr36067-objs := zoran_procfs.o zoran_device.o \
zoran_driver.o zoran_card.o
-tuner-objs := tuner-core.o tuner-types.o
+tuner-objs := tuner-core.o
msp3400-objs := msp3400-driver.o msp3400-kthreads.o
@@ -87,6 +87,8 @@ obj-$(CONFIG_VIDEO_TUNER) += tuner.o
obj-$(CONFIG_TUNER_XC2028) += tuner-xc2028.o
obj-$(CONFIG_TUNER_SIMPLE) += tuner-simple.o
+# tuner-types will be merged into tuner-simple, in the future
+obj-$(CONFIG_TUNER_SIMPLE) += tuner-types.o
obj-$(CONFIG_TUNER_MT20XX) += mt20xx.o
obj-$(CONFIG_TUNER_TDA8290) += tda8290.o
obj-$(CONFIG_TUNER_TEA5767) += tea5767.o
@@ -135,5 +137,10 @@ obj-$(CONFIG_VIDEO_IVTV) += ivtv/
obj-$(CONFIG_VIDEO_VIVI) += vivi.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885/
+obj-$(CONFIG_VIDEO_PXA27x) += pxa_camera.o
+obj-$(CONFIG_SOC_CAMERA) += soc_camera.o
+obj-$(CONFIG_SOC_CAMERA_MT9M001) += mt9m001.o
+obj-$(CONFIG_SOC_CAMERA_MT9V022) += mt9v022.o
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/adv7170.c b/drivers/media/video/adv7170.c
index fea2e723e34b..f794f2dbfb32 100644
--- a/drivers/media/video/adv7170.c
+++ b/drivers/media/video/adv7170.c
@@ -56,7 +56,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(x) (x)->name
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/adv7175.c b/drivers/media/video/adv7175.c
index 10d4d89623f1..8ee07a68f702 100644
--- a/drivers/media/video/adv7175.c
+++ b/drivers/media/video/adv7175.c
@@ -52,7 +52,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(s) (s)->name
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/arv.c b/drivers/media/video/arv.c
index c94a4d0f2804..8c7d1958856b 100644
--- a/drivers/media/video/arv.c
+++ b/drivers/media/video/arv.c
@@ -125,8 +125,8 @@ static unsigned char yuv[MAX_AR_FRAME_BYTES];
/* default frequency */
#define DEFAULT_FREQ 50 /* 50 or 75 (MHz) is available as BCLK */
static int freq = DEFAULT_FREQ; /* BCLK: available 50 or 70 (MHz) */
-static int vga = 0; /* default mode(0:QVGA mode, other:VGA mode) */
-static int vga_interlace = 0; /* 0 is normal mode for, else interlace mode */
+static int vga; /* default mode(0:QVGA mode, other:VGA mode) */
+static int vga_interlace; /* 0 is normal mode for, else interlace mode */
module_param(freq, int, 0);
module_param(vga, int, 0);
module_param(vga_interlace, int, 0);
@@ -747,7 +747,9 @@ static const struct file_operations ar_fops = {
.release = video_exclusive_release,
.read = ar_read,
.ioctl = ar_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index e663cc045c41..8bfd5c75cb3a 100644
--- a/drivers/media/video/bt819.c
+++ b/drivers/media/video/bt819.c
@@ -57,7 +57,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(s) (s)->name
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/bt856.c b/drivers/media/video/bt856.c
index 7dee2e3235ad..98ee2d8feb34 100644
--- a/drivers/media/video/bt856.c
+++ b/drivers/media/video/bt856.c
@@ -56,7 +56,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(s) (s)->name
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/bt8xx/bttv-cards.c b/drivers/media/video/bt8xx/bttv-cards.c
index 7374c02dd183..f20a01cfc73e 100644
--- a/drivers/media/video/bt8xx/bttv-cards.c
+++ b/drivers/media/video/bt8xx/bttv-cards.c
@@ -71,6 +71,8 @@ static void kodicom4400r_init(struct bttv *btv);
static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input);
static void sigmaSQ_muxsel(struct bttv *btv, unsigned int input);
+static void geovision_muxsel(struct bttv *btv, unsigned int input);
+
static int terratec_active_radio_upgrade(struct bttv *btv);
static int tea5757_read(struct bttv *btv);
static int tea5757_write(struct bttv *btv, int value);
@@ -301,6 +303,7 @@ static struct CARD {
{ 0xd50018ac, BTTV_BOARD_DVICO_FUSIONHDTV_5_LITE, "DViCO FusionHDTV 5 Lite" },
{ 0x00261822, BTTV_BOARD_TWINHAN_DST, "DNTV Live! Mini "},
{ 0xd200dbc0, BTTV_BOARD_DVICO_FUSIONHDTV_2, "DViCO FusionHDTV 2" },
+ { 0x763c008a, BTTV_BOARD_GEOVISION_GV600, "GeoVision GV-600" },
{ 0, -1, NULL }
};
@@ -576,6 +579,8 @@ struct tvcard bttv_tvcards[] = {
.needs_tvaudio = 1,
.pll = PLL_28,
.tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
},
[BTTV_BOARD_WINVIEW_601] = {
.name = "Leadtek WinView 601",
@@ -2322,7 +2327,7 @@ struct tvcard bttv_tvcards[] = {
.tuner = 0,
.svhs = 2,
.muxsel = { 2, 3, 1, 0 },
- .tuner_type = TUNER_PHILIPS_ATSC,
+ .tuner_type = TUNER_PHILIPS_FCV1236D,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.has_dvb = 1,
@@ -2961,7 +2966,7 @@ struct tvcard bttv_tvcards[] = {
[BTTV_BOARD_DVICO_FUSIONHDTV_2] = {
.name = "DViCO FusionHDTV 2",
.tuner = 0,
- .tuner_type = TUNER_PHILIPS_ATSC, /* FCV1236D */
+ .tuner_type = TUNER_PHILIPS_FCV1236D,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.video_inputs = 3,
@@ -2992,6 +2997,45 @@ struct tvcard bttv_tvcards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
},
+ [BTTV_BOARD_GEOVISION_GV600] = {
+ /* emhn@usb.ve */
+ .name = "Geovision GV-600",
+ .video_inputs = 16,
+ .audio_inputs = 0,
+ .tuner = UNSET,
+ .svhs = UNSET,
+ .gpiomask = 0x0,
+ .muxsel = { 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2 },
+ .muxsel_hook = geovision_muxsel,
+ .gpiomux = { 0 },
+ .no_msp34xx = 1,
+ .pll = PLL_28,
+ .tuner_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ },
+ [BTTV_BOARD_KOZUMI_KTV_01C] = {
+ /* Mauro Lacy <mauro@lacy.com.ar>
+ * Based on MagicTV and Conceptronic CONTVFMi */
+
+ .name = "Kozumi KTV-01C",
+ .video_inputs = 3,
+ .audio_inputs = 1,
+ .tuner = 0,
+ .svhs = 2,
+ .gpiomask = 0x008007,
+ .muxsel = { 2, 3, 1, 1 },
+ .gpiomux = { 0, 1, 2, 2 }, /* CONTVFMi */
+ .gpiomute = 3, /* CONTVFMi */
+ .needs_tvaudio = 0,
+ .tuner_type = TUNER_PHILIPS_FM1216ME_MK3, /* TCL MK3 */
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .pll = PLL_28,
+ .has_radio = 1,
+ .has_remote = 1,
+ },
};
static const unsigned int bttv_num_tvcards = ARRAY_SIZE(bttv_tvcards);
@@ -3331,6 +3375,13 @@ static void sigmaSLC_muxsel(struct bttv *btv, unsigned int input)
gpio_bits( 3<<9, inmux<<9 );
}
+static void geovision_muxsel(struct bttv *btv, unsigned int input)
+{
+ unsigned int inmux = input % 16;
+ gpio_inout(0xf, 0xf);
+ gpio_bits(0xf, inmux);
+}
+
/* ----------------------------------------------------------------------- */
static void bttv_reset_audio(struct bttv *btv)
diff --git a/drivers/media/video/bt8xx/bttv-driver.c b/drivers/media/video/bt8xx/bttv-driver.c
index fcf8f2d208a8..79da9d01d715 100644
--- a/drivers/media/video/bt8xx/bttv-driver.c
+++ b/drivers/media/video/bt8xx/bttv-driver.c
@@ -2372,7 +2372,7 @@ static int setup_window(struct bttv_fh *fh, struct bttv *btv,
if (check_btres(fh, RESOURCE_OVERLAY)) {
struct bttv_buffer *new;
- new = videobuf_pci_alloc(sizeof(*new));
+ new = videobuf_sg_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv,fh,new);
@@ -2760,7 +2760,7 @@ static int bttv_overlay(struct file *file, void *f, unsigned int on)
mutex_lock(&fh->cap.vb_lock);
if (on) {
fh->ov.tvnorm = btv->tvnorm;
- new = videobuf_pci_alloc(sizeof(*new));
+ new = videobuf_sg_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
} else {
@@ -2834,7 +2834,7 @@ static int bttv_s_fbuf(struct file *file, void *f,
if (check_btres(fh, RESOURCE_OVERLAY)) {
struct bttv_buffer *new;
- new = videobuf_pci_alloc(sizeof(*new));
+ new = videobuf_sg_alloc(sizeof(*new));
new->crop = btv->crop[!!fh->do_crop].rect;
bttv_overlay_risc(btv, &fh->ov, fh->ovfmt, new);
retval = bttv_switch_overlay(btv, fh, new);
@@ -3117,12 +3117,18 @@ static int bttv_s_crop(struct file *file, void *f, struct v4l2_crop *crop)
static int bttv_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
+ if (unlikely(a->index))
+ return -EINVAL;
+
strcpy(a->name, "audio");
return 0;
}
static int bttv_s_audio(struct file *file, void *priv, struct v4l2_audio *a)
{
+ if (unlikely(a->index))
+ return -EINVAL;
+
return 0;
}
@@ -3184,7 +3190,7 @@ static unsigned int bttv_poll(struct file *file, poll_table *wait)
/* need to capture a new frame */
if (locked_btres(fh->btv,RESOURCE_VIDEO_STREAM))
goto err;
- fh->cap.read_buf = videobuf_pci_alloc(fh->cap.msize);
+ fh->cap.read_buf = videobuf_sg_alloc(fh->cap.msize);
if (NULL == fh->cap.read_buf)
goto err;
fh->cap.read_buf->memory = V4L2_MEMORY_USERPTR;
@@ -3251,14 +3257,14 @@ static int bttv_open(struct inode *inode, struct file *file)
fh->ov.setup_ok = 0;
v4l2_prio_open(&btv->prio,&fh->prio);
- videobuf_queue_pci_init(&fh->cap, &bttv_video_qops,
- btv->c.pci, &btv->s_lock,
+ videobuf_queue_sg_init(&fh->cap, &bttv_video_qops,
+ &btv->c.pci->dev, &btv->s_lock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct bttv_buffer),
fh);
- videobuf_queue_pci_init(&fh->vbi, &bttv_vbi_qops,
- btv->c.pci, &btv->s_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),
@@ -3510,7 +3516,7 @@ static int radio_enum_input(struct file *file, void *priv,
return -EINVAL;
strcpy(i->name, "Radio");
- i->type = V4L2_INPUT_TYPE_TUNER;
+ i->type = V4L2_INPUT_TYPE_TUNER;
return 0;
}
@@ -3518,10 +3524,9 @@ static int radio_enum_input(struct file *file, void *priv,
static int radio_g_audio(struct file *file, void *priv,
struct v4l2_audio *a)
{
- if (a->index != 0)
+ if (unlikely(a->index))
return -EINVAL;
- memset(a, 0, sizeof(*a));
strcpy(a->name, "Radio");
return 0;
@@ -3543,11 +3548,17 @@ static int radio_s_tuner(struct file *file, void *priv,
static int radio_s_audio(struct file *file, void *priv,
struct v4l2_audio *a)
{
+ if (unlikely(a->index))
+ return -EINVAL;
+
return 0;
}
static int radio_s_input(struct file *filp, void *priv, unsigned int i)
{
+ if (unlikely(i))
+ return -EINVAL;
+
return 0;
}
diff --git a/drivers/media/video/bt8xx/bttv-input.c b/drivers/media/video/bt8xx/bttv-input.c
index fc9ecb21eec6..a38af98f4cae 100644
--- a/drivers/media/video/bt8xx/bttv-input.c
+++ b/drivers/media/video/bt8xx/bttv-input.c
@@ -278,6 +278,12 @@ int bttv_input_init(struct bttv *btv)
ir->mask_keyup = 0x004000;
ir->polling = 50; /* ms */
break;
+ case BTTV_BOARD_KOZUMI_KTV_01C:
+ ir_codes = ir_codes_pctv_sedna;
+ ir->mask_keycode = 0x001f00;
+ ir->mask_keyup = 0x006000;
+ ir->polling = 50; /* ms */
+ break;
}
if (NULL == ir_codes) {
dprintk(KERN_INFO "Ooops: IR config error [card=%d]\n", btv->c.type);
diff --git a/drivers/media/video/bt8xx/bttv-vbi.c b/drivers/media/video/bt8xx/bttv-vbi.c
index 75fa82c7c735..bfdbc469e30f 100644
--- a/drivers/media/video/bt8xx/bttv-vbi.c
+++ b/drivers/media/video/bt8xx/bttv-vbi.c
@@ -54,7 +54,7 @@
#define VBI_DEFLINES 16
static unsigned int vbibufs = 4;
-static unsigned int vbi_debug = 0;
+static unsigned int vbi_debug;
module_param(vbibufs, int, 0444);
module_param(vbi_debug, int, 0644);
diff --git a/drivers/media/video/bt8xx/bttv.h b/drivers/media/video/bt8xx/bttv.h
index bf4c339a520c..f2393202904b 100644
--- a/drivers/media/video/bt8xx/bttv.h
+++ b/drivers/media/video/bt8xx/bttv.h
@@ -19,6 +19,7 @@
#include <media/ir-common.h>
#include <media/ir-kbd-i2c.h>
#include <media/i2c-addr.h>
+#include <media/tuner.h>
/* ---------------------------------------------------------- */
/* exported by bttv-cards.c */
@@ -173,6 +174,8 @@
#define BTTV_BOARD_VOODOOTV_200 0x93
#define BTTV_BOARD_DVICO_FUSIONHDTV_2 0x94
#define BTTV_BOARD_TYPHOON_TVTUNERPCI 0x95
+#define BTTV_BOARD_GEOVISION_GV600 0x96
+#define BTTV_BOARD_KOZUMI_KTV_01C 0x97
/* more card-specific defines */
diff --git a/drivers/media/video/bt8xx/bttvp.h b/drivers/media/video/bt8xx/bttvp.h
index 1305d315cfc5..03816b73f847 100644
--- a/drivers/media/video/bt8xx/bttvp.h
+++ b/drivers/media/video/bt8xx/bttvp.h
@@ -42,7 +42,6 @@
#include <linux/device.h>
#include <media/videobuf-dma-sg.h>
-#include <media/tuner.h>
#include <media/tveeprom.h>
#include <media/ir-common.h>
diff --git a/drivers/media/video/bw-qcam.c b/drivers/media/video/bw-qcam.c
index 032265383df2..b364adaae78d 100644
--- a/drivers/media/video/bw-qcam.c
+++ b/drivers/media/video/bw-qcam.c
@@ -523,7 +523,7 @@ static inline int qc_readbytes(struct qcam_device *q, char buffer[])
int ret=1;
unsigned int hi, lo;
unsigned int hi2, lo2;
- static int state = 0;
+ static int state;
if (buffer == NULL)
{
@@ -898,7 +898,9 @@ static const struct file_operations qcam_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = qcam_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.read = qcam_read,
.llseek = no_llseek,
};
@@ -912,7 +914,7 @@ static struct video_device qcam_template=
#define MAX_CAMS 4
static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams = 0;
+static unsigned int num_cams;
static int init_bwqcam(struct parport *port)
{
diff --git a/drivers/media/video/c-qcam.c b/drivers/media/video/c-qcam.c
index cf1546b5a7f1..2c85ced61150 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -69,7 +69,7 @@ struct qcam_device {
static int parport[MAX_CAMS] = { [1 ... MAX_CAMS-1] = -1 };
static int probe = 2;
-static int force_rgb = 0;
+static int force_rgb;
static int video_nr = -1;
static inline void qcam_set_ack(struct qcam_device *qcam, unsigned int i)
@@ -689,7 +689,9 @@ static const struct file_operations qcam_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = qcam_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.read = qcam_read,
.llseek = no_llseek,
};
@@ -741,7 +743,7 @@ static struct qcam_device *qcam_init(struct parport *port)
}
static struct qcam_device *qcams[MAX_CAMS];
-static unsigned int num_cams = 0;
+static unsigned int num_cams;
static int init_cqcam(struct parport *port)
{
diff --git a/drivers/media/video/cafe_ccic.c b/drivers/media/video/cafe_ccic.c
index 7ae499c9c54c..5195b1f3378a 100644
--- a/drivers/media/video/cafe_ccic.c
+++ b/drivers/media/video/cafe_ccic.c
@@ -65,7 +65,7 @@ MODULE_SUPPORTED_DEVICE("Video");
*/
#define MAX_DMA_BUFS 3
-static int alloc_bufs_at_read = 0;
+static int alloc_bufs_at_read;
module_param(alloc_bufs_at_read, bool, 0444);
MODULE_PARM_DESC(alloc_bufs_at_read,
"Non-zero value causes DMA buffers to be allocated when the "
@@ -99,7 +99,7 @@ MODULE_PARM_DESC(max_buffers,
"will be allowed to allocate. These buffers are big and live "
"in vmalloc space.");
-static int flip = 0;
+static int flip;
module_param(flip, bool, 0444);
MODULE_PARM_DESC(flip,
"If set, the sensor will be instructed to flip the image "
diff --git a/drivers/media/video/cpia.c b/drivers/media/video/cpia.c
index 7c630f5ee725..2a81376ef503 100644
--- a/drivers/media/video/cpia.c
+++ b/drivers/media/video/cpia.c
@@ -3792,7 +3792,9 @@ static const struct file_operations cpia_fops = {
.read = cpia_read,
.mmap = cpia_mmap,
.ioctl = cpia_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index a76bd786cf13..a439a56c3cc9 100644
--- a/drivers/media/video/cpia2/cpia2_core.c
+++ b/drivers/media/video/cpia2/cpia2_core.c
@@ -34,7 +34,7 @@
#include <linux/slab.h>
#include <linux/vmalloc.h>
-//#define _CPIA2_DEBUG_
+/* #define _CPIA2_DEBUG_ */
#include "cpia2patch.h"
@@ -48,7 +48,7 @@ static const char *block_name[] = {
};
#endif
-static unsigned int debugs_on = 0;//DEBUG_REG;
+static unsigned int debugs_on; /* default 0 - DEBUG_REG */
/******************************************************************************
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index d8e929863a88..a4574740350d 100644
--- a/drivers/media/video/cpia2/cpia2_usb.c
+++ b/drivers/media/video/cpia2/cpia2_usb.c
@@ -84,7 +84,7 @@ static struct usb_driver cpia2_driver = {
*****************************************************************************/
static void process_frame(struct camera_data *cam)
{
- static int frame_count = 0;
+ static int frame_count;
unsigned char *inbuff = cam->workbuff->data;
diff --git a/drivers/media/video/cpia2/cpia2_v4l.c b/drivers/media/video/cpia2/cpia2_v4l.c
index e378abec806d..7ce2789fa976 100644
--- a/drivers/media/video/cpia2/cpia2_v4l.c
+++ b/drivers/media/video/cpia2/cpia2_v4l.c
@@ -1927,7 +1927,9 @@ static const struct file_operations fops_template = {
.poll = cpia2_v4l_poll,
.ioctl = cpia2_ioctl,
.llseek = no_llseek,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.mmap = cpia2_mmap,
};
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 7f10b273598f..a77505daaed2 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -952,7 +952,7 @@ void cx23885_free_buffer(struct videobuf_queue *q, struct cx23885_buffer *buf)
videobuf_waiton(&buf->vb, 0, 0);
videobuf_dma_unmap(q, dma);
videobuf_dma_free(dma);
- btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+ btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index ed465c007cea..7bcd37aa8c90 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -39,6 +39,7 @@
#include "dvb-pll.h"
#include "tuner-xc2028.h"
#include "tuner-xc2028-types.h"
+#include "tuner-simple.h"
static unsigned int debug;
@@ -164,8 +165,10 @@ static struct tda829x_config tda829x_no_probe = {
};
static struct tda18271_std_map hauppauge_tda18271_std_map = {
- .atsc_6 = { .if_freq = 5380, .std_bits = 0x1b },
- .qam_6 = { .if_freq = 4000, .std_bits = 0x18 },
+ .atsc_6 = { .if_freq = 5380, .agc_mode = 3, .std = 3,
+ .if_lvl = 6, .rfagc_top = 0x37 },
+ .qam_6 = { .if_freq = 4000, .agc_mode = 3, .std = 0,
+ .if_lvl = 6, .rfagc_top = 0x37 },
};
static struct tda18271_config hauppauge_tda18271_config = {
@@ -271,8 +274,9 @@ static int dvb_register(struct cx23885_tsport *port)
&fusionhdtv_5_express,
&i2c_bus->i2c_adap);
if (port->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, port->dvb.frontend, 0x61,
- &i2c_bus->i2c_adap, DVB_PLL_LG_TDVS_H06XF);
+ dvb_attach(simple_tuner_attach, port->dvb.frontend,
+ &i2c_bus->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF);
}
break;
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
@@ -297,7 +301,6 @@ static int dvb_register(struct cx23885_tsport *port)
struct xc2028_config cfg = {
.i2c_adap = &i2c_bus->i2c_adap,
.i2c_addr = 0x61,
- .video_dev = port,
.callback = cx23885_hvr1500_xc3028_callback,
};
static struct xc2028_ctrl ctl = {
@@ -349,7 +352,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
/* dvb stuff */
printk("%s: cx23885 based dvb card\n", dev->name);
- videobuf_queue_pci_init(&port->dvb.dvbq, &dvb_qops, dev->pci, &port->slock,
+ videobuf_queue_sg_init(&port->dvb.dvbq, &dvb_qops, &dev->pci->dev, &port->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_TOP,
sizeof(struct cx23885_buffer), port);
err = dvb_register(port);
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 92fe0bd37c84..748c79a46549 100644
--- a/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/drivers/media/video/cx23885/cx23885-i2c.c
@@ -33,7 +33,7 @@ static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index d3c4d2c5cbe0..45bf2146a193 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -765,8 +765,8 @@ static int video_open(struct inode *inode, struct file *file)
fh->height = 240;
fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
- videobuf_queue_pci_init(&fh->vidq, &cx23885_video_qops,
- dev->pci, &dev->slock,
+ videobuf_queue_sg_init(&fh->vidq, &cx23885_video_qops,
+ &dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx23885_buffer),
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 756a1eeb274e..ae395f8cf292 100644
--- a/drivers/media/video/cx25840/cx25840-core.c
+++ b/drivers/media/video/cx25840/cx25840-core.c
@@ -352,7 +352,7 @@ static void cx23885_initialize(struct i2c_client *client)
static void input_change(struct i2c_client *client)
{
struct cx25840_state *state = i2c_get_clientdata(client);
- v4l2_std_id std = cx25840_get_v4lstd(client);
+ v4l2_std_id std = state->std;
/* Follow step 8c and 8d of section 3.16 in the cx25840 datasheet */
if (std & V4L2_STD_SECAM) {
@@ -523,32 +523,34 @@ static int set_input(struct i2c_client *client, enum cx25840_video_input vid_inp
/* ----------------------------------------------------------------------- */
-static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
+static int set_v4lstd(struct i2c_client *client)
{
- u8 fmt=0; /* zero is autodetect */
+ struct cx25840_state *state = i2c_get_clientdata(client);
+ u8 fmt = 0; /* zero is autodetect */
+ u8 pal_m = 0;
/* First tests should be against specific std */
- if (std == V4L2_STD_NTSC_M_JP) {
- fmt=0x2;
- } else if (std == V4L2_STD_NTSC_443) {
- fmt=0x3;
- } else if (std == V4L2_STD_PAL_M) {
- fmt=0x5;
- } else if (std == V4L2_STD_PAL_N) {
- fmt=0x6;
- } else if (std == V4L2_STD_PAL_Nc) {
- fmt=0x7;
- } else if (std == V4L2_STD_PAL_60) {
- fmt=0x8;
+ if (state->std == V4L2_STD_NTSC_M_JP) {
+ fmt = 0x2;
+ } else if (state->std == V4L2_STD_NTSC_443) {
+ fmt = 0x3;
+ } else if (state->std == V4L2_STD_PAL_M) {
+ pal_m = 1;
+ fmt = 0x5;
+ } else if (state->std == V4L2_STD_PAL_N) {
+ fmt = 0x6;
+ } else if (state->std == V4L2_STD_PAL_Nc) {
+ fmt = 0x7;
+ } else if (state->std == V4L2_STD_PAL_60) {
+ fmt = 0x8;
} else {
/* Then, test against generic ones */
- if (std & V4L2_STD_NTSC) {
- fmt=0x1;
- } else if (std & V4L2_STD_PAL) {
- fmt=0x4;
- } else if (std & V4L2_STD_SECAM) {
- fmt=0xc;
- }
+ if (state->std & V4L2_STD_NTSC)
+ fmt = 0x1;
+ else if (state->std & V4L2_STD_PAL)
+ fmt = 0x4;
+ else if (state->std & V4L2_STD_SECAM)
+ fmt = 0xc;
}
v4l_dbg(1, cx25840_debug, client, "changing video std to fmt %i\n",fmt);
@@ -563,42 +565,13 @@ static int set_v4lstd(struct i2c_client *client, v4l2_std_id std)
cx25840_and_or(client, 0x47b, ~6, 0);
}
cx25840_and_or(client, 0x400, ~0xf, fmt);
+ cx25840_and_or(client, 0x403, ~0x3, pal_m);
cx25840_vbi_setup(client);
+ if (!state->is_cx25836)
+ input_change(client);
return 0;
}
-v4l2_std_id cx25840_get_v4lstd(struct i2c_client * client)
-{
- struct cx25840_state *state = i2c_get_clientdata(client);
- /* check VID_FMT_SEL first */
- u8 fmt = cx25840_read(client, 0x400) & 0xf;
-
- if (!fmt) {
- /* check AFD_FMT_STAT if set to autodetect */
- fmt = cx25840_read(client, 0x40d) & 0xf;
- }
-
- switch (fmt) {
- case 0x1:
- {
- /* if the audio std is A2-M, then this is the South Korean
- NTSC standard */
- if (!state->is_cx25836 && cx25840_read(client, 0x805) == 2)
- return V4L2_STD_NTSC_M_KR;
- return V4L2_STD_NTSC_M;
- }
- case 0x2: return V4L2_STD_NTSC_M_JP;
- case 0x3: return V4L2_STD_NTSC_443;
- case 0x4: return V4L2_STD_PAL;
- case 0x5: return V4L2_STD_PAL_M;
- case 0x6: return V4L2_STD_PAL_N;
- case 0x7: return V4L2_STD_PAL_Nc;
- case 0x8: return V4L2_STD_PAL_60;
- case 0xc: return V4L2_STD_SECAM;
- default: return V4L2_STD_UNKNOWN;
- }
-}
-
/* ----------------------------------------------------------------------- */
static int set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
@@ -718,9 +691,10 @@ static int get_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
static int set_v4lfmt(struct i2c_client *client, struct v4l2_format *fmt)
{
+ struct cx25840_state *state = i2c_get_clientdata(client);
struct v4l2_pix_format *pix;
int HSC, VSC, Vsrc, Hsrc, filter, Vlines;
- int is_50Hz = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
+ int is_50Hz = !(state->std & V4L2_STD_525_60);
switch (fmt->type) {
case V4L2_BUF_TYPE_VIDEO_CAPTURE:
@@ -1096,12 +1070,15 @@ static int cx25840_command(struct i2c_client *client, unsigned int cmd,
}
case VIDIOC_G_STD:
- *(v4l2_std_id *)arg = cx25840_get_v4lstd(client);
+ *(v4l2_std_id *)arg = state->std;
break;
case VIDIOC_S_STD:
+ if (state->radio == 0 && state->std == *(v4l2_std_id *)arg)
+ return 0;
state->radio = 0;
- return set_v4lstd(client, *(v4l2_std_id *)arg);
+ state->std = *(v4l2_std_id *)arg;
+ return set_v4lstd(client);
case AUDC_SET_RADIO:
state->radio = 1;
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 95093edc9186..8bf797f48b09 100644
--- a/drivers/media/video/cx25840/cx25840-core.h
+++ b/drivers/media/video/cx25840/cx25840-core.h
@@ -38,6 +38,7 @@ struct cx25840_state {
struct i2c_client *c;
int pvr150_workaround;
int radio;
+ v4l2_std_id std;
enum cx25840_video_input vid_input;
enum cx25840_audio_input aud_input;
u32 audclk_freq;
@@ -60,7 +61,6 @@ 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);
-v4l2_std_id cx25840_get_v4lstd(struct i2c_client *client);
/* ----------------------------------------------------------------------- */
/* cx25850-firmware.c */
diff --git a/drivers/media/video/cx25840/cx25840-firmware.c b/drivers/media/video/cx25840/cx25840-firmware.c
index 1ddf724a2c74..620d295947ab 100644
--- a/drivers/media/video/cx25840/cx25840-firmware.c
+++ b/drivers/media/video/cx25840/cx25840-firmware.c
@@ -79,11 +79,9 @@ static int check_fw_load(struct i2c_client *client, int size)
return 0;
}
-static int fw_write(struct i2c_client *client, u8 * data, int size)
+static int fw_write(struct i2c_client *client, u8 *data, int size)
{
- int sent;
-
- if ((sent = i2c_master_send(client, data, size)) < size) {
+ if (i2c_master_send(client, data, size) < size) {
v4l_err(client, "firmware load i2c failure\n");
return -ENOSYS;
}
@@ -96,7 +94,7 @@ int cx25840_loadfw(struct i2c_client *client)
struct cx25840_state *state = i2c_get_clientdata(client);
const struct firmware *fw = NULL;
u8 buffer[4], *ptr;
- int size, send, retval;
+ int size, retval;
if (state->is_cx23885)
firmware = FWFILE_CX23885;
@@ -124,8 +122,7 @@ int cx25840_loadfw(struct i2c_client *client)
while (size > 0) {
ptr[0] = 0x08;
ptr[1] = 0x02;
- send = size > (FWSEND - 2) ? FWSEND : size + 2;
- retval = fw_write(client, ptr, send);
+ retval = fw_write(client, ptr, min(FWSEND, size + 2));
if (retval < 0) {
release_firmware(fw);
diff --git a/drivers/media/video/cx25840/cx25840-vbi.c b/drivers/media/video/cx25840/cx25840-vbi.c
index 6828f59b9d83..c754b9d13369 100644
--- a/drivers/media/video/cx25840/cx25840-vbi.c
+++ b/drivers/media/video/cx25840/cx25840-vbi.c
@@ -85,7 +85,7 @@ static int decode_vps(u8 * dst, u8 * p)
void cx25840_vbi_setup(struct i2c_client *client)
{
struct cx25840_state *state = i2c_get_clientdata(client);
- v4l2_std_id std = cx25840_get_v4lstd(client);
+ v4l2_std_id std = state->std;
int hblank,hactive,burst,vblank,vactive,sc,vblank656,src_decimation;
int luma_lpf,uv_lpf, comb;
u32 pll_int,pll_frac,pll_post;
@@ -242,7 +242,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
0, 0, V4L2_SLICED_VPS, 0, 0, /* 9 */
0, 0, 0, 0
};
- int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
+ int is_pal = !(state->std & V4L2_STD_525_60);
int i;
fmt = arg;
@@ -279,7 +279,7 @@ int cx25840_vbi(struct i2c_client *client, unsigned int cmd, void *arg)
case VIDIOC_S_FMT:
{
- int is_pal = !(cx25840_get_v4lstd(client) & V4L2_STD_525_60);
+ int is_pal = !(state->std & V4L2_STD_525_60);
int vbi_offset = is_pal ? 1 : 0;
int i, x;
u8 lcr[24];
diff --git a/drivers/media/video/cx88/Kconfig b/drivers/media/video/cx88/Kconfig
index 49d3813a9b48..bcf6d9ba063d 100644
--- a/drivers/media/video/cx88/Kconfig
+++ b/drivers/media/video/cx88/Kconfig
@@ -57,6 +57,7 @@ config VIDEO_CX88_DVB
select DVB_NXT200X if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+ select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB/ATSC cards based on the
Conexant 2388x chip.
diff --git a/drivers/media/video/cx88/cx88-alsa.c b/drivers/media/video/cx88/cx88-alsa.c
index 316b106c3511..2f5a4a4ba407 100644
--- a/drivers/media/video/cx88/cx88-alsa.c
+++ b/drivers/media/video/cx88/cx88-alsa.c
@@ -283,7 +283,7 @@ static int dsp_buffer_free(snd_cx88_card_t *chip)
BUG_ON(!chip->dma_size);
dprintk(2,"Freeing buffer\n");
- videobuf_pci_dma_unmap(chip->pci, chip->dma_risc);
+ videobuf_sg_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);
@@ -385,7 +385,7 @@ 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_pci_alloc(sizeof(*buf));
+ buf = videobuf_sg_alloc(sizeof(*buf));
if (NULL == buf)
return -ENOMEM;
@@ -396,14 +396,14 @@ static int snd_cx88_hw_params(struct snd_pcm_substream * substream,
buf->vb.height = chip->num_periods;
buf->vb.size = chip->dma_size;
- dma=videobuf_to_dma(&buf->vb);
+ dma = videobuf_to_dma(&buf->vb);
videobuf_dma_init(dma);
ret = videobuf_dma_init_kernel(dma, PCI_DMA_FROMDEVICE,
(PAGE_ALIGN(buf->vb.size) >> PAGE_SHIFT));
if (ret < 0)
goto error;
- ret = videobuf_pci_dma_map(chip->pci,dma);
+ ret = videobuf_sg_dma_map(&chip->pci->dev, dma);
if (ret < 0)
goto error;
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index a99e9d5950aa..8d54e7a90dc7 100644
--- a/drivers/media/video/cx88/cx88-blackbird.c
+++ b/drivers/media/video/cx88/cx88-blackbird.c
@@ -45,7 +45,7 @@ static unsigned int mpegbufs = 32;
module_param(mpegbufs,int,0644);
MODULE_PARM_DESC(mpegbufs,"number of mpeg buffers, range 2-32");
-static unsigned int debug = 0;
+static unsigned int debug;
module_param(debug,int,0644);
MODULE_PARM_DESC(debug,"enable debug messages [blackbird]");
@@ -693,7 +693,7 @@ static int blackbird_queryctrl(struct cx8802_dev *dev, struct v4l2_queryctrl *qc
return -EINVAL;
/* Standard V4L2 controls */
- if (cx8800_ctrl_query(qctrl) == 0)
+ if (cx8800_ctrl_query(dev->core, qctrl) == 0)
return 0;
/* MPEG V4L2 controls */
@@ -933,7 +933,7 @@ static int vidioc_queryctrl (struct file *file, void *priv,
qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
if (unlikely(qctrl->id == 0))
return -EINVAL;
- return cx8800_ctrl_query(qctrl);
+ return cx8800_ctrl_query(dev->core, qctrl);
}
static int vidioc_enum_input (struct file *file, void *priv,
@@ -1087,8 +1087,8 @@ static int mpeg_open(struct inode *inode, struct file *file)
file->private_data = fh;
fh->dev = dev;
- videobuf_queue_pci_init(&fh->mpegq, &blackbird_qops,
- dev->pci, &dev->slock,
+ videobuf_queue_sg_init(&fh->mpegq, &blackbird_qops,
+ &dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct cx88_buffer),
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 8c9a8adf52de..0534f589c725 100644
--- a/drivers/media/video/cx88/cx88-cards.c
+++ b/drivers/media/video/cx88/cx88-cards.c
@@ -44,6 +44,16 @@ static unsigned int latency = UNSET;
module_param(latency,int,0444);
MODULE_PARM_DESC(latency,"pci latency timer");
+#define info_printk(core, fmt, arg...) \
+ printk(KERN_INFO "%s: " fmt, core->name , ## arg)
+
+#define warn_printk(core, fmt, arg...) \
+ printk(KERN_WARNING "%s: " fmt, core->name , ## arg)
+
+#define err_printk(core, fmt, arg...) \
+ printk(KERN_ERR "%s: " fmt, core->name , ## arg)
+
+
/* ------------------------------------------------------------------ */
/* board config info */
@@ -1401,6 +1411,245 @@ static const struct cx88_board cx88_boards[] = {
}},
.mpeg = CX88_MPEG_DVB,
},
+ [CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO] = {
+ .name = "DViCO FusionHDTV 5 PCI nano",
+ /* xc3008 tuner, digital only for now */
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x000027df, /* Unconfirmed */
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x000027df, /* Unconfirmed */
+ .audioroute = 1,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x000027df, /* Unconfirmed */
+ .audioroute = 1,
+ } },
+ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_PINNACLE_HYBRID_PCTV] = {
+ .name = "Pinnacle Hybrid PCTV",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x004ff,
+ .gpio1 = 0x010ff,
+ .gpio2 = 0x0ff,
+ },
+ },
+ [CX88_BOARD_WINFAST_TV2000_XP_GLOBAL] = {
+ .name = "Winfast TV2000 XP Global",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0400, /* pin 2:mute = 0 (off?) */
+ .gpio1 = 0x0000,
+ .gpio2 = 0x0800, /* pin 19:audio = 0 (tv) */
+
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x0400, /* probably? or 0x0404 to turn mute on */
+ .gpio1 = 0x0000,
+ .gpio2 = 0x0808, /* pin 19:audio = 1 (line) */
+
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x004ff,
+ .gpio1 = 0x010ff,
+ .gpio2 = 0x0ff,
+ },
+ },
+ [CX88_BOARD_POWERCOLOR_REAL_ANGEL] = {
+ .name = "PowerColor Real Angel 330",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00ff,
+ .gpio1 = 0xf35d,
+ .gpio3 = 0x0000,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x00ff,
+ .gpio1 = 0xf37d,
+ .gpio3 = 0x0000,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x000ff,
+ .gpio1 = 0x0f37d,
+ .gpio3 = 0x00000,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x000ff,
+ .gpio1 = 0x0f35d,
+ .gpio3 = 0x00000,
+ },
+ },
+ [CX88_BOARD_GENIATECH_X8000_MT] = {
+ /* Also PowerColor Real Angel 330 and Geniatech X800 OEM */
+ .name = "Geniatech X8000-MT DVBT",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x00000000,
+ .gpio1 = 0x00e3e341,
+ .gpio2 = 0x00000000,
+ .gpio3 = 0x00000000,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x00000000,
+ .gpio1 = 0x00e3e361,
+ .gpio2 = 0x00000000,
+ .gpio3 = 0x00000000,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x00000000,
+ .gpio1 = 0x00e3e361,
+ .gpio2 = 0x00000000,
+ .gpio3 = 0x00000000,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x00000000,
+ .gpio1 = 0x00e3e341,
+ .gpio2 = 0x00000000,
+ .gpio3 = 0x00000000,
+ },
+ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO] = {
+ .name = "DViCO FusionHDTV DVB-T PRO",
+ .tuner_type = TUNER_ABSENT, /* XXX: Has XC3028 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = { {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x000067df,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x000067df,
+ } },
+ .mpeg = CX88_MPEG_DVB,
+ },
+ [CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD] = {
+ .name = "DViCO FusionHDTV 7 Gold",
+ .tuner_type = TUNER_XC5000,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = {{
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x10df,
+ },{
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x16d9,
+ },{
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x16d9,
+ }},
+ },
+ [CX88_BOARD_PROLINK_PV_8000GT] = {
+ .name = "Prolink Pixelview MPEG 8000GT",
+ .tuner_type = TUNER_XC2028,
+ .tuner_addr = 0x61,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x0ff,
+ .gpio2 = 0x0cfb,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio2 = 0x0cfb,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio2 = 0x0cfb,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio2 = 0x0cfb,
+ },
+ },
+ /* Both radio, analog and ATSC work with this board.
+ However, for analog to work, s5h1409 gate should be open,
+ otherwise, tuner-xc3028 won't be detected.
+ A proper fix require using the newer i2c methods to add
+ tuner-xc3028 without doing an i2c probe.
+ */
+ [CX88_BOARD_KWORLD_ATSC_120] = {
+ .name = "Kworld PlusTV HD PCI 120 (ATSC 120)",
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .input = { {
+ .type = CX88_VMUX_TELEVISION,
+ .vmux = 0,
+ .gpio0 = 0x000000ff,
+ .gpio1 = 0x0000f35d,
+ .gpio2 = 0x00000000,
+ }, {
+ .type = CX88_VMUX_COMPOSITE1,
+ .vmux = 1,
+ .gpio0 = 0x000000ff,
+ .gpio1 = 0x0000f37e,
+ .gpio2 = 0x00000000,
+ }, {
+ .type = CX88_VMUX_SVIDEO,
+ .vmux = 2,
+ .gpio0 = 0x000000ff,
+ .gpio1 = 0x0000f37e,
+ .gpio2 = 0x00000000,
+ } },
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0x000000ff,
+ .gpio1 = 0x0000f35d,
+ .gpio2 = 0x00000000,
+ },
+ .mpeg = CX88_MPEG_DVB,
+ },
};
/* ------------------------------------------------------------------ */
@@ -1605,7 +1854,11 @@ static const struct cx88_subid cx88_subids[] = {
.subdevice = 0xdb11,
.card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS,
/* Re-branded DViCO: UltraView DVB-T Plus */
- },{
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xdb30,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO,
+ }, {
.subvendor = 0x17de,
.subdevice = 0x0840,
.card = CX88_BOARD_KWORLD_HARDWARE_MPEG_TV_XPERT,
@@ -1714,6 +1967,38 @@ static const struct cx88_subid cx88_subids[] = {
.subvendor = 0x11bd,
.subdevice = 0x0051,
.card = CX88_BOARD_PINNACLE_PCTV_HD_800i,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xd530,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO,
+ }, {
+ .subvendor = 0x12ab,
+ .subdevice = 0x1788,
+ .card = CX88_BOARD_PINNACLE_HYBRID_PCTV,
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0xea3d,
+ .card = CX88_BOARD_POWERCOLOR_REAL_ANGEL,
+ }, {
+ .subvendor = 0x107d,
+ .subdevice = 0x6f18,
+ .card = CX88_BOARD_WINFAST_TV2000_XP_GLOBAL,
+ }, {
+ .subvendor = 0x14f1,
+ .subdevice = 0x8852,
+ .card = CX88_BOARD_GENIATECH_X8000_MT,
+ }, {
+ .subvendor = 0x18ac,
+ .subdevice = 0xd610,
+ .card = CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD,
+ }, {
+ .subvendor = 0x1554,
+ .subdevice = 0x4935,
+ .card = CX88_BOARD_PROLINK_PV_8000GT,
+ }, {
+ .subvendor = 0x17de,
+ .subdevice = 0x08c1,
+ .card = CX88_BOARD_KWORLD_ATSC_120,
},
};
@@ -1731,17 +2016,16 @@ static void leadtek_eeprom(struct cx88_core *core, u8 *eeprom_data)
if (eeprom_data[4] != 0x7d ||
eeprom_data[5] != 0x10 ||
eeprom_data[7] != 0x66) {
- printk(KERN_WARNING "%s: Leadtek eeprom invalid.\n",
- core->name);
+ warn_printk(core, "Leadtek eeprom invalid.\n");
return;
}
core->board.tuner_type = (eeprom_data[6] == 0x13) ?
TUNER_PHILIPS_FM1236_MK3 : TUNER_PHILIPS_FM1216ME_MK3;
- printk(KERN_INFO "%s: Leadtek Winfast 2000XP Expert config: "
- "tuner=%d, eeprom[0]=0x%02x\n",
- core->name, core->board.tuner_type, eeprom_data[0]);
+ info_printk(core, "Leadtek Winfast 2000XP Expert config: "
+ "tuner=%d, eeprom[0]=0x%02x\n",
+ core->board.tuner_type, eeprom_data[0]);
}
static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
@@ -1785,13 +2069,12 @@ static void hauppauge_eeprom(struct cx88_core *core, u8 *eeprom_data)
/* known */
break;
default:
- printk("%s: warning: unknown hauppauge model #%d\n",
- core->name, tv.model);
+ warn_printk(core, "warning: unknown hauppauge model #%d\n",
+ tv.model);
break;
}
- printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
- core->name, tv.model);
+ info_printk(core, "hauppauge eeprom: model=%d\n", tv.model);
}
/* ----------------------------------------------------------------------- */
@@ -1837,8 +2120,7 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
char *name = (eeprom_data[0x0d] < ARRAY_SIZE(gdi_tuner))
? gdi_tuner[eeprom_data[0x0d]].name : NULL;
- printk(KERN_INFO "%s: GDI: tuner=%s\n", core->name,
- name ? name : "unknown");
+ info_printk(core, "GDI: tuner=%s\n", name ? name : "unknown");
if (NULL == name)
return;
core->board.tuner_type = gdi_tuner[eeprom_data[0x0d]].id;
@@ -1846,6 +2128,75 @@ static void gdi_eeprom(struct cx88_core *core, u8 *eeprom_data)
CX88_RADIO : 0;
}
+/* ------------------------------------------------------------------- */
+/* some Divco specific stuff */
+static int cx88_dvico_xc2028_callback(struct cx88_core *core,
+ int command, int arg)
+{
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ cx_write(MO_GP0_IO, 0x101000);
+ mdelay(5);
+ cx_set(MO_GP0_IO, 0x101010);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+
+/* ----------------------------------------------------------------------- */
+/* some Geniatech specific stuff */
+
+static int cx88_xc3028_geniatech_tuner_callback(struct cx88_core *core,
+ int command, int mode)
+{
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ switch (INPUT(core->input).type) {
+ case CX88_RADIO:
+ break;
+ case CX88_VMUX_DVB:
+ cx_write(MO_GP1_IO, 0x030302);
+ mdelay(50);
+ break;
+ default:
+ cx_write(MO_GP1_IO, 0x030301);
+ mdelay(50);
+ }
+ cx_write(MO_GP1_IO, 0x101010);
+ mdelay(50);
+ cx_write(MO_GP1_IO, 0x101000);
+ mdelay(50);
+ cx_write(MO_GP1_IO, 0x101010);
+ mdelay(50);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+/* ------------------------------------------------------------------- */
+/* some Divco specific stuff */
+static int cx88_pv_8000gt_callback(struct cx88_core *core,
+ int command, int arg)
+{
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ cx_write(MO_GP2_IO, 0xcf7);
+ mdelay(50);
+ cx_write(MO_GP2_IO, 0xef5);
+ mdelay(50);
+ cx_write(MO_GP2_IO, 0xcf7);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
/* ----------------------------------------------------------------------- */
/* some DViCO specific stuff */
@@ -1874,32 +2225,85 @@ static void dvico_fusionhdtv_hybrid_init(struct cx88_core *core)
msg.len = (i != 12 ? 5 : 2);
err = i2c_transfer(&core->i2c_adap, &msg, 1);
if (err != 1) {
- printk("dvico_fusionhdtv_hybrid_init buf %d failed (err = %d)!\n", i, err);
+ warn_printk(core, "dvico_fusionhdtv_hybrid_init buf %d "
+ "failed (err = %d)!\n", i, err);
return;
}
}
}
+static int cx88_xc2028_tuner_callback(struct cx88_core *core,
+ int command, int arg)
+{
+ /* Board-specific callbacks */
+ switch (core->boardnr) {
+ case CX88_BOARD_WINFAST_TV2000_XP_GLOBAL:
+ case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+ case CX88_BOARD_GENIATECH_X8000_MT:
+ case CX88_BOARD_KWORLD_ATSC_120:
+ return cx88_xc3028_geniatech_tuner_callback(core,
+ command, arg);
+ case CX88_BOARD_PROLINK_PV_8000GT:
+ return cx88_pv_8000gt_callback(core, command, arg);
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+ return cx88_dvico_xc2028_callback(core, command, arg);
+ }
+
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ switch (INPUT(core->input).type) {
+ case CX88_RADIO:
+ info_printk(core, "setting GPIO to radio!\n");
+ cx_write(MO_GP0_IO, 0x4ff);
+ mdelay(250);
+ cx_write(MO_GP2_IO, 0xff);
+ mdelay(250);
+ break;
+ case CX88_VMUX_DVB: /* Digital TV*/
+ default: /* Analog TV */
+ info_printk(core, "setting GPIO to TV!\n");
+ break;
+ }
+ cx_write(MO_GP1_IO, 0x101010);
+ mdelay(250);
+ cx_write(MO_GP1_IO, 0x101000);
+ mdelay(250);
+ cx_write(MO_GP1_IO, 0x101010);
+ mdelay(250);
+ return 0;
+ }
+ return -EINVAL;
+}
+
/* ----------------------------------------------------------------------- */
/* Tuner callback function. Currently only needed for the Pinnacle *
* PCTV HD 800i with an xc5000 sillicon tuner. This is used for both *
* analog tuner attach (tuner-core.c) and dvb tuner attach (cx88-dvb.c) */
-int cx88_tuner_callback(void *priv, int command, int arg)
+static int cx88_xc5000_tuner_callback(struct cx88_core *core,
+ int command, int arg)
{
- struct i2c_algo_bit_data *i2c_algo = priv;
- struct cx88_core *core = i2c_algo->data;
-
- switch(core->boardnr) {
+ switch (core->boardnr) {
case CX88_BOARD_PINNACLE_PCTV_HD_800i:
- if(command == 0) { /* This is the reset command from xc5000 */
+ if (command == 0) { /* This is the reset command from xc5000 */
/* Reset XC5000 tuner via SYS_RSTO_pin */
cx_write(MO_SRST_IO, 0);
msleep(10);
cx_write(MO_SRST_IO, 1);
return 0;
+ } else {
+ err_printk(core, "xc5000: unknown tuner "
+ "callback command.\n");
+ return -EINVAL;
}
- else {
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+ if (command == 0) { /* This is the reset command from xc5000 */
+ cx_clear(MO_GP0_IO, 0x00000010);
+ msleep(10);
+ cx_set(MO_GP0_IO, 0x00000010);
+ return 0;
+ } else {
printk(KERN_ERR
"xc5000: unknown tuner callback command.\n");
return -EINVAL;
@@ -1908,6 +2312,36 @@ int cx88_tuner_callback(void *priv, int command, int arg)
}
return 0; /* Should never be here */
}
+
+int cx88_tuner_callback(void *priv, int command, int arg)
+{
+ struct i2c_algo_bit_data *i2c_algo = priv;
+ struct cx88_core *core;
+
+ if (!i2c_algo) {
+ printk(KERN_ERR "cx88: Error - i2c private data undefined.\n");
+ return -EINVAL;
+ }
+
+ core = i2c_algo->data;
+
+ if (!core) {
+ printk(KERN_ERR "cx88: Error - device struct undefined.\n");
+ return -EINVAL;
+ }
+
+ switch (core->board.tuner_type) {
+ case TUNER_XC2028:
+ info_printk(core, "Calling XC2028/3028 callback\n");
+ return cx88_xc2028_tuner_callback(core, command, arg);
+ case TUNER_XC5000:
+ info_printk(core, "Calling XC5000 callback\n");
+ return cx88_xc5000_tuner_callback(core, command, arg);
+ }
+ err_printk(core, "Error: Calling callback for tuner %d\n",
+ core->board.tuner_type);
+ return -EINVAL;
+}
EXPORT_SYMBOL(cx88_tuner_callback);
/* ----------------------------------------------------------------------- */
@@ -1918,23 +2352,25 @@ static void cx88_card_list(struct cx88_core *core, struct pci_dev *pci)
if (0 == pci->subsystem_vendor &&
0 == pci->subsystem_device) {
- printk("%s: Your board has no valid PCI Subsystem ID and thus can't\n"
+ printk(KERN_ERR
+ "%s: Your board has no valid PCI Subsystem ID and thus can't\n"
"%s: be autodetected. Please pass card=<n> insmod option to\n"
"%s: workaround that. Redirect complaints to the vendor of\n"
"%s: the TV card. Best regards,\n"
"%s: -- tux\n",
core->name,core->name,core->name,core->name,core->name);
} else {
- printk("%s: Your board isn't known (yet) to the driver. You can\n"
+ printk(KERN_ERR
+ "%s: Your board isn't known (yet) to the driver. You can\n"
"%s: try to pick one of the existing card configs via\n"
"%s: card=<n> insmod option. Updating to the latest\n"
"%s: version might help as well.\n",
core->name,core->name,core->name,core->name);
}
- printk("%s: Here is a list of valid choices for the card=<n> insmod option:\n",
- core->name);
+ err_printk(core, "Here is a list of valid choices for the card=<n> "
+ "insmod option:\n");
for (i = 0; i < ARRAY_SIZE(cx88_boards); i++)
- printk("%s: card=%d -> %s\n",
+ printk(KERN_ERR "%s: card=%d -> %s\n",
core->name, i, cx88_boards[i].name);
}
@@ -1951,9 +2387,57 @@ static void cx88_card_setup_pre_i2c(struct cx88_core *core)
cx_set(MO_GP0_IO, 0x00000080); /* 702 out of reset */
udelay(1000);
break;
+
+ case CX88_BOARD_PROLINK_PV_8000GT:
+ cx_write(MO_GP2_IO, 0xcf7);
+ mdelay(50);
+ cx_write(MO_GP2_IO, 0xef5);
+ mdelay(50);
+ cx_write(MO_GP2_IO, 0xcf7);
+ msleep(10);
+ break;
+
+ case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
+ /* Enable the xc5000 tuner */
+ cx_set(MO_GP0_IO, 0x00001010);
+ break;
}
}
+/*
+ * Sets board-dependent xc3028 configuration
+ */
+void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl)
+{
+ memset(ctl, 0, sizeof(*ctl));
+
+ ctl->fname = XC2028_DEFAULT_FIRMWARE;
+ ctl->max_len = 64;
+
+ switch (core->boardnr) {
+ case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+ /* Doesn't work with firmware version 2.7 */
+ ctl->fname = "xc3028-v25.fw";
+ break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+ ctl->scode_table = XC3028_FE_ZARLINK456;
+ break;
+ case CX88_BOARD_KWORLD_ATSC_120:
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+ ctl->demod = XC3028_FE_OREN538;
+ break;
+ case CX88_BOARD_PROLINK_PV_8000GT:
+ /*
+ * This board uses non-MTS firmware
+ */
+ break;
+ default:
+ ctl->demod = XC3028_FE_OREN538;
+ ctl->mts = 1;
+ }
+}
+EXPORT_SYMBOL_GPL(cx88_setup_xc3028);
+
static void cx88_card_setup(struct cx88_core *core)
{
static u8 eeprom[256];
@@ -1991,6 +2475,13 @@ static void cx88_card_setup(struct cx88_core *core)
cx_write(MO_GP0_IO, 0x000007f8);
cx_write(MO_GP1_IO, 0x00000001);
break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+ /* GPIO0:0 is hooked to demod reset */
+ /* GPIO0:4 is hooked to xc3028 reset */
+ cx_write(MO_GP0_IO, 0x00111100);
+ msleep(1);
+ cx_write(MO_GP0_IO, 0x00111111);
+ break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_DUAL:
/* GPIO0:6 is hooked to FX2 reset pin */
cx_set(MO_GP0_IO, 0x00004040);
@@ -2038,10 +2529,8 @@ static void cx88_card_setup(struct cx88_core *core)
for (i = 0; i < ARRAY_SIZE(buffer); i++)
if (2 != i2c_master_send(&core->i2c_client,
buffer[i],2))
- printk(KERN_WARNING
- "%s: Unable to enable "
- "tuner(%i).\n",
- core->name, i);
+ warn_printk(core, "Unable to enable "
+ "tuner(%i).\n", i);
}
break;
case CX88_BOARD_MSI_TVANYWHERE_MASTER:
@@ -2062,6 +2551,22 @@ static void cx88_card_setup(struct cx88_core *core)
cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &tea5767_cfg);
}
}
+
+ if (core->board.tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ /* Fills device-dependent initialization parameters */
+ cx88_setup_xc3028(core, &ctl);
+
+ /* Sends parameters to xc2028/3028 tuner */
+ memset(&xc2028_cfg, 0, sizeof(xc2028_cfg));
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+ info_printk(core, "Asking xc2028/3028 to load firmware %s\n",
+ ctl.fname);
+ cx88_call_i2c_clients(core, TUNER_SET_CONFIG, &xc2028_cfg);
+ }
}
/* ------------------------------------------------------------------ */
@@ -2178,9 +2683,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
memcpy(&core->board, &cx88_boards[core->boardnr], sizeof(core->board));
- printk(KERN_INFO "%s: subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
- core->name,pci->subsystem_vendor,
- pci->subsystem_device, core->board.name,
+ info_printk(core, "subsystem: %04x:%04x, board: %s [card=%d,%s]\n",
+ pci->subsystem_vendor, pci->subsystem_device, core->board.name,
core->boardnr, card[core->nr] == core->boardnr ?
"insmod option" : "autodetected");
@@ -2189,8 +2693,8 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
if (radio[core->nr] != UNSET)
core->board.radio_type = radio[core->nr];
- printk(KERN_INFO "%s: TV tuner type %d, Radio tuner type %d\n",
- core->name, core->board.tuner_type, core->board.radio_type);
+ info_printk(core, "TV tuner type %d, Radio tuner type %d\n",
+ core->board.tuner_type, core->board.radio_type);
/* init hardware */
cx88_reset(core);
@@ -2207,12 +2711,3 @@ struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr)
return core;
}
-
-/* ------------------------------------------------------------------ */
-
-/*
- * 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/cx88/cx88-core.c b/drivers/media/video/cx88/cx88-core.c
index 01e2ac98970b..6039a8f57b48 100644
--- a/drivers/media/video/cx88/cx88-core.c
+++ b/drivers/media/video/cx88/cx88-core.c
@@ -47,15 +47,15 @@ MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------ */
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
module_param(core_debug,int,0644);
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
-static unsigned int nicam = 0;
+static unsigned int nicam;
module_param(nicam,int,0644);
MODULE_PARM_DESC(nicam,"tv audio is nicam");
-static unsigned int nocomb = 0;
+static unsigned int nocomb;
module_param(nocomb,int,0644);
MODULE_PARM_DESC(nocomb,"disable comb filter");
@@ -219,7 +219,7 @@ cx88_free_buffer(struct videobuf_queue *q, struct cx88_buffer *buf)
videobuf_waiton(&buf->vb,0,0);
videobuf_dma_unmap(q, dma);
videobuf_dma_free(dma);
- btcx_riscmem_free((struct pci_dev *)q->dev, &buf->risc);
+ btcx_riscmem_free(to_pci_dev(q->dev), &buf->risc);
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
@@ -929,7 +929,10 @@ int cx88_set_tvnorm(struct cx88_core *core, v4l2_std_id norm)
dprintk(1,"set_tvnorm: MO_INPUT_FORMAT 0x%08x [old=0x%08x]\n",
cxiformat, cx_read(MO_INPUT_FORMAT) & 0x0f);
- cx_andor(MO_INPUT_FORMAT, 0xf, cxiformat);
+ /* Chroma AGC must be disabled if SECAM is used, we enable it
+ by default on PAL and NTSC */
+ cx_andor(MO_INPUT_FORMAT, 0x40f,
+ norm & V4L2_STD_SECAM ? cxiformat : cxiformat | 0x400);
// FIXME: as-is from DScaler
dprintk(1,"set_tvnorm: MO_OUTPUT_FORMAT 0x%08x [old=0x%08x]\n",
diff --git a/drivers/media/video/cx88/cx88-dvb.c b/drivers/media/video/cx88/cx88-dvb.c
index f7b41eb1bb5a..5e7c7fdb38ae 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -45,13 +45,16 @@
#include "nxt200x.h"
#include "cx24123.h"
#include "isl6421.h"
+#include "tuner-xc2028-types.h"
+#include "tuner-simple.h"
+#include "tda9887.h"
MODULE_DESCRIPTION("driver for cx2388x based DVB cards");
MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
-static unsigned int debug = 0;
+static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages [dvb]");
@@ -235,6 +238,19 @@ static struct zl10353_config dvico_fusionhdtv_hybrid = {
.no_tuner = 1,
};
+static struct zl10353_config dvico_fusionhdtv_xc3028 = {
+ .demod_address = 0x0f,
+ .if2 = 45600,
+ .no_tuner = 1,
+};
+
+static 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 = {
.demod_address = 0x0f,
};
@@ -357,6 +373,40 @@ static int geniatech_dvbs_set_voltage(struct dvb_frontend *fe,
return 0;
}
+static int cx88_pci_nano_callback(void *ptr, int command, int arg)
+{
+ struct cx88_core *core = ptr;
+
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ /* Send the tuner in then out of reset */
+ dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+
+ switch (core->boardnr) {
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+ /* GPIO-4 xc3028 tuner */
+
+ cx_set(MO_GP0_IO, 0x00001000);
+ cx_clear(MO_GP0_IO, 0x00000010);
+ msleep(100);
+ cx_set(MO_GP0_IO, 0x00000010);
+ msleep(100);
+ break;
+ }
+
+ break;
+ case XC2028_RESET_CLK:
+ dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+ break;
+ default:
+ dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
+ command, arg);
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
static struct cx24123_config geniatech_dvbs_config = {
.demod_address = 0x55,
.set_ts_params = cx24123_set_ts_param,
@@ -383,12 +433,76 @@ 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 = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
+static struct s5h1409_config kworld_atsc_120_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_SERIAL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .inversion = S5H1409_INVERSION_OFF,
+ .status_mode = S5H1409_DEMODLOCKING,
+ .mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
+};
+
static struct xc5000_config pinnacle_pctv_hd_800i_tuner_config = {
.i2c_address = 0x64,
.if_khz = 5380,
.tuner_callback = cx88_tuner_callback,
};
+static struct zl10353_config cx88_geniatech_x8000_mt = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+};
+
+static int attach_xc3028(u8 addr, struct cx8802_dev *dev)
+{
+ struct dvb_frontend *fe;
+ struct xc2028_ctrl ctl;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->core->i2c_adap,
+ .i2c_addr = addr,
+ .ctrl = &ctl,
+ .callback = cx88_tuner_callback,
+ };
+
+ if (!dev->dvb.frontend) {
+ printk(KERN_ERR "%s/2: dvb frontend not attached. "
+ "Can't attach xc3028\n",
+ dev->core->name);
+ return -EINVAL;
+ }
+
+ /*
+ * Some xc3028 devices may be hidden by an I2C gate. This is known
+ * to happen with some s5h1409-based devices.
+ * Now that I2C gate is open, sets up xc3028 configuration
+ */
+ cx88_setup_xc3028(dev->core, &ctl);
+
+ fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+ dev->core->name);
+ dvb_frontend_detach(dev->dvb.frontend);
+ dvb_unregister_frontend(dev->dvb.frontend);
+ dev->dvb.frontend = NULL;
+ return -EINVAL;
+ }
+
+ printk(KERN_INFO "%s/2: xc3028 attached\n",
+ dev->core->name);
+
+ return 0;
+}
+
static int dvb_register(struct cx8802_dev *dev)
{
/* init struct videobuf_dvb */
@@ -429,8 +543,9 @@ static int dvb_register(struct cx8802_dev *dev)
&hauppauge_hvr_config,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PLUS:
@@ -497,8 +612,9 @@ static int dvb_register(struct cx8802_dev *dev)
dev->dvb.frontend = dvb_attach(mt352_attach, &dntv_live_dvbt_pro_config,
&dev->vp3054->adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap, DVB_PLL_FMD1216ME);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_PHILIPS_FMD1216ME_MK3);
}
#else
printk(KERN_ERR "%s/2: built without vp3054 support\n", dev->core->name);
@@ -509,18 +625,36 @@ static int dvb_register(struct cx8802_dev *dev)
&dvico_fusionhdtv_hybrid,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- DVB_PLL_THOMSON_FE6600);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_THOMSON_FE6600);
}
break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO:
+ dev->dvb.frontend = dvb_attach(zl10353_attach,
+ &dvico_fusionhdtv_xc3028,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend == NULL)
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &dvico_fusionhdtv_mt352_xc3028,
+ &dev->core->i2c_adap);
+ /*
+ * On this board, the demod provides the I2C bus pullup.
+ * We must not permit gate_ctrl to be performed, or
+ * the xc3028 cannot communicate on the bus.
+ */
+ if (dev->dvb.frontend)
+ dev->dvb.frontend->ops.i2c_gate_ctrl = NULL;
+ if (attach_xc3028(0x61, dev) < 0)
+ return -EINVAL;
+ break;
case CX88_BOARD_PCHDTV_HD3000:
dev->dvb.frontend = dvb_attach(or51132_attach, &pchdtv_hd3000,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- DVB_PLL_THOMSON_DTT761X);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_THOMSON_DTT761X);
}
break;
case CX88_BOARD_DVICO_FUSIONHDTV_3_GOLD_Q:
@@ -540,9 +674,9 @@ static int dvb_register(struct cx8802_dev *dev)
&fusionhdtv_3_gold,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- DVB_PLL_MICROTUNE_4042);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_MICROTUNE_4042FI5);
}
}
break;
@@ -560,9 +694,9 @@ static int dvb_register(struct cx8802_dev *dev)
&fusionhdtv_3_gold,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- DVB_PLL_THOMSON_DTT761X);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_THOMSON_DTT761X);
}
}
break;
@@ -580,9 +714,11 @@ static int dvb_register(struct cx8802_dev *dev)
&fusionhdtv_5_gold,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- DVB_PLL_LG_TDVS_H06XF);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF);
+ dvb_attach(tda9887_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x43);
}
}
break;
@@ -600,9 +736,11 @@ static int dvb_register(struct cx8802_dev *dev)
&pchdtv_hd5500,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- &dev->core->i2c_adap,
- DVB_PLL_LG_TDVS_H06XF);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF);
+ dvb_attach(tda9887_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x43);
}
}
break;
@@ -611,8 +749,9 @@ static int dvb_register(struct cx8802_dev *dev)
&ati_hdtvwonder,
&dev->core->i2c_adap);
if (dev->dvb.frontend != NULL) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_TUV1236D);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->core->i2c_adap, 0x61,
+ TUNER_PHILIPS_TUV1236D);
}
break;
case CX88_BOARD_HAUPPAUGE_NOVASPLUS_S1:
@@ -658,14 +797,62 @@ static int dvb_register(struct cx8802_dev *dev)
&pinnacle_pctv_hd_800i_tuner_config);
}
break;
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+ dev->dvb.frontend = dvb_attach(s5h1409_attach,
+ &dvico_hdtv5_pci_nano_config,
+ &dev->core->i2c_adap);
+ if (dev->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->core->i2c_adap,
+ .i2c_addr = 0x61,
+ .callback = cx88_pci_nano_callback,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = "xc3028-v27.fw",
+ .max_len = 64,
+ .scode_table = OREN538,
+ };
+
+ fe = dvb_attach(xc2028_attach,
+ dev->dvb.frontend, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ case CX88_BOARD_PINNACLE_HYBRID_PCTV:
+ dev->dvb.frontend = dvb_attach(zl10353_attach,
+ &cx88_geniatech_x8000_mt,
+ &dev->core->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0)
+ return -EINVAL;
+ break;
+ case CX88_BOARD_GENIATECH_X8000_MT:
+ dev->ts_gen_cntrl = 0x00;
+
+ dev->dvb.frontend = dvb_attach(zl10353_attach,
+ &cx88_geniatech_x8000_mt,
+ &dev->core->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0)
+ return -EINVAL;
+ break;
+ case CX88_BOARD_KWORLD_ATSC_120:
+ dev->dvb.frontend = dvb_attach(s5h1409_attach,
+ &kworld_atsc_120_config,
+ &dev->core->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0)
+ return -EINVAL;
+ break;
default:
printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->core->name);
break;
}
if (NULL == dev->dvb.frontend) {
- printk(KERN_ERR "%s/2: frontend initialization failed\n", dev->core->name);
- return -1;
+ printk(KERN_ERR
+ "%s/2: frontend initialization failed\n",
+ dev->core->name);
+ return -EINVAL;
}
/* Ensure all frontends negotiate bus access */
@@ -744,8 +931,8 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
/* dvb stuff */
printk(KERN_INFO "%s/2: cx2388x based DVB/ATSC card\n", core->name);
- videobuf_queue_pci_init(&dev->dvb.dvbq, &dvb_qops,
- dev->pci, &dev->slock,
+ videobuf_queue_sg_init(&dev->dvb.dvbq, &dvb_qops,
+ &dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_TOP,
sizeof(struct cx88_buffer),
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 566b26af523e..c6b44732a082 100644
--- a/drivers/media/video/cx88/cx88-i2c.c
+++ b/drivers/media/video/cx88/cx88-i2c.c
@@ -35,11 +35,11 @@
#include "cx88.h"
#include <media/v4l2-common.h>
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
diff --git a/drivers/media/video/cx88/cx88-input.c b/drivers/media/video/cx88/cx88-input.c
index bb0911b4d2f6..53526d997a4e 100644
--- a/drivers/media/video/cx88/cx88-input.c
+++ b/drivers/media/video/cx88/cx88-input.c
@@ -57,7 +57,7 @@ struct cx88_IR {
u32 mask_keyup;
};
-static int ir_debug = 0;
+static int ir_debug;
module_param(ir_debug, int, 0644); /* debug level [IR] */
MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
@@ -258,6 +258,13 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir->mask_keyup = 0x80;
ir->polling = 1; /* ms */
break;
+ case CX88_BOARD_PROLINK_PV_8000GT:
+ ir_codes = ir_codes_pixelview_new;
+ ir->gpio_addr = MO_GP1_IO;
+ ir->mask_keycode = 0x3f;
+ ir->mask_keyup = 0x80;
+ ir->polling = 1; /* ms */
+ break;
case CX88_BOARD_KWORLD_LTV883:
ir_codes = ir_codes_pixelview;
ir->gpio_addr = MO_GP1_IO;
@@ -310,6 +317,12 @@ int cx88_ir_init(struct cx88_core *core, struct pci_dev *pci)
ir_type = IR_TYPE_RC5;
ir->sampling = 1;
break;
+ case CX88_BOARD_POWERCOLOR_REAL_ANGEL:
+ ir_codes = ir_codes_powercolor_real_angel;
+ ir->gpio_addr = MO_GP2_IO;
+ ir->mask_keycode = 0x7e;
+ ir->polling = 100; /* ms */
+ break;
}
if (NULL == ir_codes) {
diff --git a/drivers/media/video/cx88/cx88-mpeg.c b/drivers/media/video/cx88/cx88-mpeg.c
index e357f415db06..6467ca336142 100644
--- a/drivers/media/video/cx88/cx88-mpeg.c
+++ b/drivers/media/video/cx88/cx88-mpeg.c
@@ -39,7 +39,7 @@ MODULE_AUTHOR("Chris Pascoe <c.pascoe@itee.uq.edu.au>");
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
-static unsigned int debug = 0;
+static unsigned int debug;
module_param(debug,int,0644);
MODULE_PARM_DESC(debug,"enable debug messages [mpeg]");
@@ -613,6 +613,8 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
core->active_type_id != drv->type_id)
return -EBUSY;
+ core->input = CX88_VMUX_DVB;
+
if (drv->advise_acquire)
{
mutex_lock(&drv->core->lock);
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 76e5c78d8ae4..c574f450498f 100644
--- a/drivers/media/video/cx88/cx88-tvaudio.c
+++ b/drivers/media/video/cx88/cx88-tvaudio.c
@@ -53,15 +53,15 @@
#include "cx88.h"
-static unsigned int audio_debug = 0;
+static unsigned int audio_debug;
module_param(audio_debug, int, 0644);
MODULE_PARM_DESC(audio_debug, "enable debug messages [audio]");
-static unsigned int always_analog = 0;
+static unsigned int always_analog;
module_param(always_analog,int,0644);
MODULE_PARM_DESC(always_analog,"force analog audio out");
-static unsigned int radio_deemphasis = 0;
+static unsigned int radio_deemphasis;
module_param(radio_deemphasis,int,0644);
MODULE_PARM_DESC(radio_deemphasis, "Radio deemphasis time constant, "
"0=None, 1=50us (elsewhere), 2=75us (USA)");
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index d96ecfcf393a..0943060682bc 100644
--- a/drivers/media/video/cx88/cx88-vbi.c
+++ b/drivers/media/video/cx88/cx88-vbi.c
@@ -11,7 +11,7 @@ static unsigned int vbibufs = 4;
module_param(vbibufs,int,0644);
MODULE_PARM_DESC(vbibufs,"number of vbi buffers, range 2-32");
-static unsigned int vbi_debug = 0;
+static unsigned int vbi_debug;
module_param(vbi_debug,int,0644);
MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
diff --git a/drivers/media/video/cx88/cx88-video.c b/drivers/media/video/cx88/cx88-video.c
index 227179620d13..eea23f95edb7 100644
--- a/drivers/media/video/cx88/cx88-video.c
+++ b/drivers/media/video/cx88/cx88-video.c
@@ -63,11 +63,11 @@ MODULE_PARM_DESC(video_nr,"video device numbers");
MODULE_PARM_DESC(vbi_nr,"vbi device numbers");
MODULE_PARM_DESC(radio_nr,"radio device numbers");
-static unsigned int video_debug = 0;
+static unsigned int video_debug;
module_param(video_debug,int,0644);
MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
-static unsigned int irq_debug = 0;
+static unsigned int irq_debug;
module_param(irq_debug,int,0644);
MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
@@ -228,6 +228,30 @@ static struct cx88_ctrl cx8800_ctls[] = {
.mask = 0x00ff,
.shift = 0,
},{
+ .v = {
+ .id = V4L2_CID_CHROMA_AGC,
+ .name = "Chroma AGC",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0x1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },
+ .reg = MO_INPUT_FORMAT,
+ .mask = 1 << 10,
+ .shift = 10,
+ }, {
+ .v = {
+ .id = V4L2_CID_COLOR_KILLER,
+ .name = "Color killer",
+ .minimum = 0,
+ .maximum = 1,
+ .default_value = 0x1,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ },
+ .reg = MO_INPUT_FORMAT,
+ .mask = 1 << 9,
+ .shift = 9,
+ }, {
/* --- audio --- */
.v = {
.id = V4L2_CID_AUDIO_MUTE,
@@ -282,6 +306,8 @@ const u32 cx88_user_ctrls[] = {
V4L2_CID_AUDIO_VOLUME,
V4L2_CID_AUDIO_BALANCE,
V4L2_CID_AUDIO_MUTE,
+ V4L2_CID_CHROMA_AGC,
+ V4L2_CID_COLOR_KILLER,
0
};
EXPORT_SYMBOL(cx88_user_ctrls);
@@ -291,7 +317,7 @@ static const u32 *ctrl_classes[] = {
NULL
};
-int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
+int cx8800_ctrl_query(struct cx88_core *core, struct v4l2_queryctrl *qctrl)
{
int i;
@@ -306,6 +332,11 @@ int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl)
return 0;
}
*qctrl = cx8800_ctls[i].v;
+ /* Report chroma AGC as inactive when SECAM is selected */
+ if (cx8800_ctls[i].v.id == V4L2_CID_CHROMA_AGC &&
+ core->tvnorm & V4L2_STD_SECAM)
+ qctrl->flags |= V4L2_CTRL_FLAG_INACTIVE;
+
return 0;
}
EXPORT_SYMBOL(cx8800_ctrl_query);
@@ -776,14 +807,14 @@ static int video_open(struct inode *inode, struct file *file)
fh->height = 240;
fh->fmt = format_by_fourcc(V4L2_PIX_FMT_BGR24);
- videobuf_queue_pci_init(&fh->vidq, &cx8800_video_qops,
- dev->pci, &dev->slock,
+ 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);
- videobuf_queue_pci_init(&fh->vbiq, &cx8800_vbi_qops,
- dev->pci, &dev->slock,
+ 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),
@@ -976,6 +1007,12 @@ int cx88_set_control(struct cx88_core *core, struct v4l2_control *ctl)
}
mask=0xffff;
break;
+ case V4L2_CID_CHROMA_AGC:
+ /* Do not allow chroma AGC to be enabled for SECAM */
+ value = ((ctl->value - c->off) << c->shift) & c->mask;
+ if (core->tvnorm & V4L2_STD_SECAM && value)
+ return -EINVAL;
+ break;
default:
value = ((ctl->value - c->off) << c->shift) & c->mask;
break;
@@ -1268,10 +1305,12 @@ static int vidioc_s_input (struct file *file, void *priv, unsigned int i)
static int vidioc_queryctrl (struct file *file, void *priv,
struct v4l2_queryctrl *qctrl)
{
+ struct cx88_core *core = ((struct cx8800_fh *)priv)->dev->core;
+
qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
if (unlikely(qctrl->id == 0))
return -EINVAL;
- return cx8800_ctrl_query(qctrl);
+ return cx8800_ctrl_query(core, qctrl);
}
static int vidioc_g_ctrl (struct file *file, void *priv,
@@ -1832,8 +1871,11 @@ static int __devinit cx8800_initdev(struct pci_dev *pci_dev,
switch (core->boardnr) {
case CX88_BOARD_DVICO_FUSIONHDTV_5_GOLD:
- request_module("ir-kbd-i2c");
+ case CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD:
request_module("rtc-isl1208");
+ /* break intentionally omitted */
+ case CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO:
+ request_module("ir-kbd-i2c");
}
/* register v4l devices */
@@ -1917,6 +1959,9 @@ static void __devexit cx8800_finidev(struct pci_dev *pci_dev)
core->kthread = NULL;
}
+ if (core->ir)
+ cx88_ir_stop(core, core->ir);
+
cx88_shutdown(core); /* FIXME */
pci_disable_device(pci_dev);
diff --git a/drivers/media/video/cx88/cx88.h b/drivers/media/video/cx88/cx88.h
index 37e6d2e4002f..14ac173f4071 100644
--- a/drivers/media/video/cx88/cx88.h
+++ b/drivers/media/video/cx88/cx88.h
@@ -37,6 +37,7 @@
#include "btcx-risc.h"
#include "cx88-reg.h"
+#include "tuner-xc2028.h"
#include <linux/version.h>
#include <linux/mutex.h>
@@ -211,6 +212,15 @@ extern struct sram_channel cx88_sram_channels[];
#define CX88_BOARD_HAUPPAUGE_HVR1300 56
#define CX88_BOARD_ADSTECH_PTV_390 57
#define CX88_BOARD_PINNACLE_PCTV_HD_800i 58
+#define CX88_BOARD_DVICO_FUSIONHDTV_5_PCI_NANO 59
+#define CX88_BOARD_PINNACLE_HYBRID_PCTV 60
+#define CX88_BOARD_WINFAST_TV2000_XP_GLOBAL 61
+#define CX88_BOARD_POWERCOLOR_REAL_ANGEL 62
+#define CX88_BOARD_GENIATECH_X8000_MT 63
+#define CX88_BOARD_DVICO_FUSIONHDTV_DVB_T_PRO 64
+#define CX88_BOARD_DVICO_FUSIONHDTV_7_GOLD 65
+#define CX88_BOARD_PROLINK_PV_8000GT 66
+#define CX88_BOARD_KWORLD_ATSC_120 67
enum cx88_itype {
CX88_VMUX_COMPOSITE1 = 1,
@@ -595,6 +605,7 @@ extern int cx88_tuner_callback(void *dev, int command, int arg);
extern int cx88_get_resources(const struct cx88_core *core,
struct pci_dev *pci);
extern struct cx88_core *cx88_core_create(struct pci_dev *pci, int nr);
+extern void cx88_setup_xc3028(struct cx88_core *core, struct xc2028_ctrl *ctl);
/* ----------------------------------------------------------- */
/* cx88-tvaudio.c */
@@ -640,7 +651,8 @@ void cx8802_cancel_buffers(struct cx8802_dev *dev);
/* ----------------------------------------------------------- */
/* cx88-video.c*/
extern const u32 cx88_user_ctrls[];
-extern int cx8800_ctrl_query(struct v4l2_queryctrl *qctrl);
+extern int cx8800_ctrl_query(struct cx88_core *core,
+ struct v4l2_queryctrl *qctrl);
int cx88_enum_input (struct cx88_core *core,struct v4l2_input *i);
int cx88_set_freq (struct cx88_core *core,struct v4l2_frequency *f);
int cx88_get_control(struct cx88_core *core, struct v4l2_control *ctl);
diff --git a/drivers/media/video/dabfirmware.h b/drivers/media/video/dabfirmware.h
index d14d803566a3..cbd92635993d 100644
--- a/drivers/media/video/dabfirmware.h
+++ b/drivers/media/video/dabfirmware.h
@@ -1,5 +1,12 @@
/*
* dabdata.h - dab usb firmware and bitstream data
+ *
+ * Copyright (C) 1999 BayCom GmbH
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that redistributions of source
+ * code retain the above copyright notice and this comment without
+ * modification.
*/
static INTEL_HEX_RECORD firmware[] = {
diff --git a/drivers/media/video/dabusb.c b/drivers/media/video/dabusb.c
index a5731f90be0f..8d1f8ee2a533 100644
--- a/drivers/media/video/dabusb.c
+++ b/drivers/media/video/dabusb.c
@@ -205,7 +205,7 @@ static void dabusb_iso_complete (struct urb *purb)
/*-------------------------------------------------------------------*/
static int dabusb_alloc_buffers (pdabusb_t s)
{
- int buffers = 0;
+ 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));
@@ -216,7 +216,7 @@ static int dabusb_alloc_buffers (pdabusb_t s)
dbg("dabusb_alloc_buffers pipesize:%d packets:%d transfer_buffer_len:%d",
pipesize, packets, transfer_buffer_length);
- while (buffers < (s->total_buffer_size << 10)) {
+ while (transfer_len < (s->total_buffer_size << 10)) {
b = kzalloc(sizeof (buff_t), GFP_KERNEL);
if (!b) {
err("kzalloc(sizeof(buff_t))==NULL");
@@ -251,10 +251,10 @@ static int dabusb_alloc_buffers (pdabusb_t s)
b->purb->iso_frame_desc[i].length = pipesize;
}
- buffers += transfer_buffer_length;
+ transfer_len += transfer_buffer_length;
list_add_tail (&b->buff_list, &s->free_buff_list);
}
- s->got_mem = buffers;
+ s->got_mem = transfer_len;
return 0;
diff --git a/drivers/media/video/dpc7146.c b/drivers/media/video/dpc7146.c
index 9ceb6b2f3949..88d6df71d051 100644
--- a/drivers/media/video/dpc7146.c
+++ b/drivers/media/video/dpc7146.c
@@ -54,11 +54,11 @@
#define DPC_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "debug verbosity");
-static int dpc_num = 0;
+static int dpc_num;
#define DPC_INPUTS 2
static struct v4l2_input dpc_inputs[DPC_INPUTS] = {
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index aae7753fef11..94aed008f83b 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -331,7 +331,7 @@ struct em28xx_board em28xx_boards[] = {
.name = "Kworld USB2800",
.is_em2800 = 1,
.vchannels = 3,
- .tuner_type = TUNER_PHILIPS_ATSC,
+ .tuner_type = TUNER_PHILIPS_FCV1236D,
.tda9887_conf = TDA9887_PRESENT,
.decoder = EM28XX_SAA7113,
.input = { {
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index c1caaa855b99..4ebef10b5722 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -31,7 +31,7 @@
/* #define ENABLE_DEBUG_ISOC_FRAMES */
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
module_param(core_debug,int,0644);
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
@@ -40,7 +40,7 @@ MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
printk(KERN_INFO "%s %s :"fmt, \
dev->name, __FUNCTION__ , ##arg); } while (0)
-static unsigned int reg_debug = 0;
+static unsigned int reg_debug;
module_param(reg_debug,int,0644);
MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
@@ -49,7 +49,7 @@ MODULE_PARM_DESC(reg_debug,"enable debug messages [URB reg]");
printk(KERN_INFO "%s %s :"fmt, \
dev->name, __FUNCTION__ , ##arg); } while (0)
-static unsigned int isoc_debug = 0;
+static unsigned int isoc_debug;
module_param(isoc_debug,int,0644);
MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
@@ -813,19 +813,27 @@ int em28xx_set_alternate(struct em28xx *dev)
{
int errCode, prev_alt = dev->alt;
int i;
- unsigned int min_pkt_size = dev->bytesperline+4;
+ unsigned int min_pkt_size = dev->bytesperline + 4;
- /* When image size is bigger than a ceirtain value,
+ /* When image size is bigger than a certain value,
the frame size should be increased, otherwise, only
green screen will be received.
*/
if (dev->frame_size > 720*240*2)
min_pkt_size *= 2;
- for (i = 0; i < dev->num_alt; i++)
- if (dev->alt_max_pkt_size[i] >= min_pkt_size)
+ for (i = 0; i < dev->num_alt; i++) {
+ /* stop when the selected alt setting offers enough bandwidth */
+ if (dev->alt_max_pkt_size[i] >= min_pkt_size) {
+ dev->alt = i;
break;
- dev->alt = i;
+ /* otherwise make sure that we end up with the maximum bandwidth
+ because the min_pkt_size equation might be wrong...
+ */
+ } else if (dev->alt_max_pkt_size[i] >
+ dev->alt_max_pkt_size[dev->alt])
+ dev->alt = i;
+ }
if (dev->alt != prev_alt) {
em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index cacd04d46e99..c3d98d81c335 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -33,11 +33,11 @@
/* ----------------------------------------------------------- */
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 4abe6701a770..c8264f40aa0d 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -74,7 +74,7 @@ MODULE_PARM_DESC(video_nr, "video device numbers");
MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
-static unsigned int video_debug = 0;
+static unsigned int video_debug;
module_param(video_debug,int,0644);
MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 06b6a3ae06c4..5e749c528a62 100644
--- a/drivers/media/video/et61x251/et61x251_core.c
+++ b/drivers/media/video/et61x251/et61x251_core.c
@@ -2523,7 +2523,9 @@ static const struct file_operations et61x251_fops = {
.open = et61x251_open,
.release = et61x251_release,
.ioctl = et61x251_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.read = et61x251_read,
.poll = et61x251_poll,
.mmap = et61x251_mmap,
@@ -2538,7 +2540,7 @@ et61x251_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct et61x251_device* cam;
- static unsigned int dev_nr = 0;
+ static unsigned int dev_nr;
unsigned int i;
int err = 0;
diff --git a/drivers/media/video/hexium_gemini.c b/drivers/media/video/hexium_gemini.c
index c7fed3405655..352f84d440fb 100644
--- a/drivers/media/video/hexium_gemini.c
+++ b/drivers/media/video/hexium_gemini.c
@@ -25,12 +25,12 @@
#include <media/saa7146_vv.h>
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "debug verbosity");
/* global variables */
-static int hexium_num = 0;
+static int hexium_num;
#define HEXIUM_GEMINI 4
#define HEXIUM_GEMINI_DUAL 5
diff --git a/drivers/media/video/hexium_orion.c b/drivers/media/video/hexium_orion.c
index 137c4736da04..8d3c1482e7ea 100644
--- a/drivers/media/video/hexium_orion.c
+++ b/drivers/media/video/hexium_orion.c
@@ -25,12 +25,12 @@
#include <media/saa7146_vv.h>
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "debug verbosity");
/* global variables */
-static int hexium_num = 0;
+static int hexium_num;
#define HEXIUM_HV_PCI6_ORION 1
#define HEXIUM_ORION_1SVHS_3BNC 2
diff --git a/drivers/media/video/ir-kbd-i2c.c b/drivers/media/video/ir-kbd-i2c.c
index 9851987b95fb..81458fb405e2 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -51,7 +51,7 @@
static int debug;
module_param(debug, int, 0644); /* debug level (0,1,2) */
-static int hauppauge = 0;
+static int hauppauge;
module_param(hauppauge, int, 0644); /* Choose Hauppauge remote */
MODULE_PARM_DESC(hauppauge, "Specify Hauppauge remote: 0=black, 1=grey (defaults to 0)");
@@ -509,10 +509,10 @@ static int ir_probe(struct i2c_adapter *adap)
static const int probe_em28XX[] = { 0x30, 0x47, -1 };
static const int probe_cx88[] = { 0x18, 0x6b, 0x71, -1 };
static const int probe_cx23885[] = { 0x6b, -1 };
- const int *probe = NULL;
- struct i2c_client c;
+ const int *probe;
+ struct i2c_client *c;
unsigned char buf;
- int i,rc;
+ int i, rc;
switch (adap->id) {
case I2C_HW_B_BT848:
@@ -533,23 +533,27 @@ static int ir_probe(struct i2c_adapter *adap)
case I2C_HW_B_CX23885:
probe = probe_cx23885;
break;
- }
- if (NULL == probe)
+ default:
return 0;
+ }
+
+ c = kzalloc(sizeof(*c), GFP_KERNEL);
+ if (!c)
+ return -ENOMEM;
- memset(&c,0,sizeof(c));
- c.adapter = adap;
+ c->adapter = adap;
for (i = 0; -1 != probe[i]; i++) {
- c.addr = probe[i];
- rc = i2c_master_recv(&c,&buf,0);
+ c->addr = probe[i];
+ rc = i2c_master_recv(c, &buf, 0);
dprintk(1,"probe 0x%02x @ %s: %s\n",
probe[i], adap->name,
(0 == rc) ? "yes" : "no");
if (0 == rc) {
- ir_attach(adap,probe[i],0,0);
+ ir_attach(adap, probe[i], 0, 0);
break;
}
}
+ kfree(c);
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index f23c6b8d6911..e908649ea37c 100644
--- a/drivers/media/video/ivtv/ivtv-cards.c
+++ b/drivers/media/video/ivtv/ivtv-cards.c
@@ -416,11 +416,10 @@ static const struct ivtv_card ivtv_card_avc2410 = {
on the country/region setting of the user to decide which tuner
is available. */
.tuners = {
- /* This tuner has been verified for the AVC2410 */
{ .std = V4L2_STD_625_50, .tuner = TUNER_PHILIPS_FM1216ME_MK3 },
- /* This is a good guess, but I'm not totally sure this is
- the correct tuner for NTSC. */
- { .std = V4L2_STD_ALL, .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ { .std = V4L2_STD_ALL - V4L2_STD_NTSC_M_JP,
+ .tuner = TUNER_PHILIPS_FM1236_MK3 },
+ { .std = V4L2_STD_NTSC_M_JP, .tuner = TUNER_PHILIPS_FQ1286 },
},
.pci_list = ivtv_pci_avc2410,
.i2c = &ivtv_i2c_std,
diff --git a/drivers/media/video/ivtv/ivtv-cards.h b/drivers/media/video/ivtv/ivtv-cards.h
index 191aafdd9968..9186fa2ee5fc 100644
--- a/drivers/media/video/ivtv/ivtv-cards.h
+++ b/drivers/media/video/ivtv/ivtv-cards.h
@@ -119,7 +119,7 @@
#define IVTV_CARD_MAX_VIDEO_INPUTS 6
#define IVTV_CARD_MAX_AUDIO_INPUTS 3
-#define IVTV_CARD_MAX_TUNERS 2
+#define IVTV_CARD_MAX_TUNERS 3
/* SAA71XX HW inputs */
#define IVTV_SAA71XX_COMPOSITE0 0
diff --git a/drivers/media/video/ivtv/ivtv-driver.c b/drivers/media/video/ivtv/ivtv-driver.c
index 948ca35e7ee8..1ed77167b125 100644
--- a/drivers/media/video/ivtv/ivtv-driver.c
+++ b/drivers/media/video/ivtv/ivtv-driver.c
@@ -101,7 +101,7 @@ static int radio[IVTV_MAX_CARDS] = { -1, -1, -1, -1, -1, -1, -1, -1,
static unsigned int cardtype_c = 1;
static unsigned int tuner_c = 1;
static unsigned int radio_c = 1;
-static char pal[] = "--";
+static char pal[] = "---";
static char secam[] = "--";
static char ntsc[] = "-";
@@ -126,12 +126,13 @@ static int dec_mpg_buffers = IVTV_DEFAULT_DEC_MPG_BUFFERS;
static int dec_yuv_buffers = IVTV_DEFAULT_DEC_YUV_BUFFERS;
static int dec_vbi_buffers = IVTV_DEFAULT_DEC_VBI_BUFFERS;
-static int ivtv_yuv_mode = 0;
-static int ivtv_yuv_threshold=-1;
+static int ivtv_yuv_mode;
+static int ivtv_yuv_threshold = -1;
static int ivtv_pci_latency = 1;
-int ivtv_debug = 0;
+int ivtv_debug;
+static int tunertype = -1;
static int newi2c = -1;
module_param_array(tuner, int, &tuner_c, 0644);
@@ -154,6 +155,7 @@ module_param(dec_mpg_buffers, int, 0644);
module_param(dec_yuv_buffers, int, 0644);
module_param(dec_vbi_buffers, int, 0644);
+module_param(tunertype, int, 0644);
module_param(newi2c, int, 0644);
MODULE_PARM_DESC(tuner, "Tuner type selection,\n"
@@ -190,9 +192,14 @@ MODULE_PARM_DESC(cardtype,
"\t\t\t24 = AverMedia EZMaker PCI Deluxe\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");
-MODULE_PARM_DESC(secam, "Set SECAM standard: B, G, H, D, K, L, LC");
-MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J, K");
+MODULE_PARM_DESC(pal, "Set PAL standard: BGH, DK, I, M, N, Nc, 60");
+MODULE_PARM_DESC(secam, "Set SECAM standard: BGH, DK, L, LC");
+MODULE_PARM_DESC(ntsc, "Set NTSC standard: M, J (Japan), K (South Korea)");
+MODULE_PARM_DESC(tunertype,
+ "Specify tuner type:\n"
+ "\t\t\t 0 = tuner for PAL-B/G/H/D/K/I, SECAM-B/G/H/D/K/L/Lc\n"
+ "\t\t\t 1 = tuner for NTSC-M/J/K, PAL-M/N/Nc\n"
+ "\t\t\t-1 = Autodetect (default)\n");
MODULE_PARM_DESC(debug,
"Debug level (bitmask). Default: 0\n"
"\t\t\t 1/0x0001: warning\n"
@@ -490,30 +497,35 @@ static v4l2_std_id ivtv_parse_std(struct ivtv *itv)
{
switch (pal[0]) {
case '6':
+ tunertype = 0;
return V4L2_STD_PAL_60;
case 'b':
case 'B':
case 'g':
case 'G':
- return V4L2_STD_PAL_BG;
case 'h':
case 'H':
- return V4L2_STD_PAL_H;
+ tunertype = 0;
+ return V4L2_STD_PAL_BG | V4L2_STD_PAL_H;
case 'n':
case 'N':
+ tunertype = 1;
if (pal[1] == 'c' || pal[1] == 'C')
return V4L2_STD_PAL_Nc;
return V4L2_STD_PAL_N;
case 'i':
case 'I':
+ tunertype = 0;
return V4L2_STD_PAL_I;
case 'd':
case 'D':
case 'k':
case 'K':
+ tunertype = 0;
return V4L2_STD_PAL_DK;
case 'M':
case 'm':
+ tunertype = 1;
return V4L2_STD_PAL_M;
case '-':
break;
@@ -529,14 +541,17 @@ static v4l2_std_id ivtv_parse_std(struct ivtv *itv)
case 'G':
case 'h':
case 'H':
+ tunertype = 0;
return V4L2_STD_SECAM_B | V4L2_STD_SECAM_G | V4L2_STD_SECAM_H;
case 'd':
case 'D':
case 'k':
case 'K':
+ tunertype = 0;
return V4L2_STD_SECAM_DK;
case 'l':
case 'L':
+ tunertype = 0;
if (secam[1] == 'C' || secam[1] == 'c')
return V4L2_STD_SECAM_LC;
return V4L2_STD_SECAM_L;
@@ -550,12 +565,15 @@ static v4l2_std_id ivtv_parse_std(struct ivtv *itv)
switch (ntsc[0]) {
case 'm':
case 'M':
+ tunertype = 1;
return V4L2_STD_NTSC_M;
case 'j':
case 'J':
+ tunertype = 1;
return V4L2_STD_NTSC_M_JP;
case 'k':
case 'K':
+ tunertype = 1;
return V4L2_STD_NTSC_M_KR;
case '-':
break;
@@ -584,8 +602,13 @@ static void ivtv_process_options(struct ivtv *itv)
itv->options.tuner = tuner[itv->num];
itv->options.radio = radio[itv->num];
itv->options.newi2c = newi2c;
-
+ if (tunertype < -1 || tunertype > 1) {
+ IVTV_WARN("Invalid tunertype argument, will autodetect instead\n");
+ tunertype = -1;
+ }
itv->std = ivtv_parse_std(itv);
+ if (itv->std == 0 && tunertype >= 0)
+ itv->std = tunertype ? V4L2_STD_MN : (V4L2_STD_ALL & ~V4L2_STD_MN);
itv->has_cx23415 = (itv->dev->device == PCI_DEVICE_ID_IVTV15);
chipname = itv->has_cx23415 ? "cx23415" : "cx23416";
if (itv->options.cardtype == -1) {
@@ -711,6 +734,7 @@ static int __devinit ivtv_init_struct1(struct ivtv *itv)
itv->yuv_info.lace_mode = ivtv_yuv_mode;
itv->yuv_info.lace_threshold = ivtv_yuv_threshold;
itv->yuv_info.max_frames_buffered = 3;
+ itv->yuv_info.track_osd = 1;
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 536140f0c19e..ba06e813c58c 100644
--- a/drivers/media/video/ivtv/ivtv-driver.h
+++ b/drivers/media/video/ivtv/ivtv-driver.h
@@ -456,6 +456,8 @@ struct yuv_playback_info
int v_filter_2;
int h_filter;
+ u8 track_osd; /* Should yuv output track the OSD size & position */
+
u32 osd_x_offset;
u32 osd_y_offset;
diff --git a/drivers/media/video/ivtv/ivtv-fileops.c b/drivers/media/video/ivtv/ivtv-fileops.c
index 6fb96f19a866..d949a81339d5 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -753,7 +753,7 @@ unsigned int ivtv_v4l2_enc_poll(struct file *filp, poll_table * wait)
IVTV_DEBUG_HI_FILE("Encoder poll\n");
poll_wait(filp, &s->waitq, wait);
- if (eof || s->q_full.length)
+ if (eof || s->q_full.length || s->q_io.length)
return POLLIN | POLLRDNORM;
return 0;
}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index edef2a579617..1beb296a1763 100644
--- a/drivers/media/video/ivtv/ivtv-ioctl.c
+++ b/drivers/media/video/ivtv/ivtv-ioctl.c
@@ -712,6 +712,7 @@ static int ivtv_debug_ioctls(struct file *filp, unsigned int cmd, void *arg)
int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void *arg)
{
struct ivtv_open_id *id = NULL;
+ struct yuv_playback_info *yi = &itv->yuv_info;
u32 data[CX2341X_MBOX_MAX_DATA];
int streamtype = 0;
@@ -827,8 +828,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
case VIDIOC_CROPCAP: {
struct v4l2_cropcap *cropcap = arg;
- if (cropcap->type != V4L2_BUF_TYPE_VIDEO_CAPTURE &&
- cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
+ if (cropcap->type != V4L2_BUF_TYPE_VIDEO_OUTPUT)
return -EINVAL;
cropcap->bounds.top = cropcap->bounds.left = 0;
cropcap->bounds.width = 720;
@@ -837,8 +837,14 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
cropcap->pixelaspect.numerator = itv->is_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_50hz ? 54 : 11;
} else if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- cropcap->bounds.width = itv->yuv_info.osd_full_w;
- cropcap->bounds.height = itv->yuv_info.osd_full_h;
+ if (yi->track_osd) {
+ cropcap->bounds.width = yi->osd_full_w;
+ cropcap->bounds.height = yi->osd_full_h;
+ } else {
+ cropcap->bounds.width = 720;
+ cropcap->bounds.height =
+ itv->is_out_50hz ? 576 : 480;
+ }
cropcap->pixelaspect.numerator = itv->is_out_50hz ? 59 : 10;
cropcap->pixelaspect.denominator = itv->is_out_50hz ? 54 : 11;
} else {
@@ -856,7 +862,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV) {
- itv->yuv_info.main_rect = crop->c;
+ yi->main_rect = crop->c;
return 0;
} else {
if (!ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
@@ -867,9 +873,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
}
return -EINVAL;
}
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- return itv->video_dec_func(itv, VIDIOC_S_CROP, arg);
+ return -EINVAL;
}
case VIDIOC_G_CROP: {
@@ -878,14 +882,12 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
if (crop->type == V4L2_BUF_TYPE_VIDEO_OUTPUT &&
(itv->v4l2_cap & V4L2_CAP_VIDEO_OUTPUT)) {
if (streamtype == IVTV_DEC_STREAM_TYPE_YUV)
- crop->c = itv->yuv_info.main_rect;
+ crop->c = yi->main_rect;
else
crop->c = itv->main_rect;
return 0;
}
- if (crop->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- return itv->video_dec_func(itv, VIDIOC_G_CROP, arg);
+ return -EINVAL;
}
case VIDIOC_ENUM_FMT: {
@@ -1070,11 +1072,10 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
itv->main_rect.height = itv->params.height;
ivtv_vapi(itv, CX2341X_OSD_SET_FRAMEBUFFER_WINDOW, 4,
720, itv->main_rect.height, 0, 0);
- itv->yuv_info.main_rect = itv->main_rect;
+ yi->main_rect = itv->main_rect;
if (!itv->osd_info) {
- itv->yuv_info.osd_full_w = 720;
- itv->yuv_info.osd_full_h =
- itv->is_out_50hz ? 576 : 480;
+ yi->osd_full_w = 720;
+ yi->osd_full_h = itv->is_out_50hz ? 576 : 480;
}
}
break;
@@ -1272,6 +1273,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
else
fb->flags |= V4L2_FBUF_FLAG_LOCAL_ALPHA;
}
+ if (yi->track_osd)
+ fb->flags |= V4L2_FBUF_FLAG_OVERLAY;
break;
}
@@ -1285,6 +1288,7 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
(fb->flags & (V4L2_FBUF_FLAG_LOCAL_ALPHA|V4L2_FBUF_FLAG_LOCAL_INV_ALPHA)) != 0;
itv->osd_chroma_key_state = (fb->flags & V4L2_FBUF_FLAG_CHROMAKEY) != 0;
ivtv_set_osd_alpha(itv);
+ yi->track_osd = (fb->flags & V4L2_FBUF_FLAG_OVERLAY) != 0;
break;
}
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 65604dde9726..a329c4689dbf 100644
--- a/drivers/media/video/ivtv/ivtv-irq.c
+++ b/drivers/media/video/ivtv/ivtv-irq.c
@@ -384,6 +384,8 @@ static void ivtv_dma_enc_start_xfer(struct ivtv_stream *s)
ivtv_stream_sync_for_device(s);
write_reg(s->sg_handle, IVTV_REG_ENCDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x02, IVTV_REG_DMAXFER);
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+ add_timer(&itv->dma_timer);
}
static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
@@ -398,6 +400,8 @@ static void ivtv_dma_dec_start_xfer(struct ivtv_stream *s)
ivtv_stream_sync_for_device(s);
write_reg(s->sg_handle, IVTV_REG_DECDMAADDR);
write_reg_sync(read_reg(IVTV_REG_DMAXFER) | 0x01, IVTV_REG_DMAXFER);
+ itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
+ add_timer(&itv->dma_timer);
}
/* start the encoder DMA */
@@ -459,8 +463,6 @@ static void ivtv_dma_enc_start(struct ivtv_stream *s)
ivtv_dma_enc_start_xfer(s);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
- itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
- add_timer(&itv->dma_timer);
}
}
@@ -481,8 +483,6 @@ static void ivtv_dma_dec_start(struct ivtv_stream *s)
ivtv_dma_dec_start_xfer(s);
set_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = s->type;
- itv->dma_timer.expires = jiffies + msecs_to_jiffies(100);
- add_timer(&itv->dma_timer);
}
static void ivtv_irq_dma_read(struct ivtv *itv)
@@ -492,10 +492,11 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
int hw_stream_type = 0;
IVTV_DEBUG_HI_IRQ("DEC DMA READ\n");
- if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0) {
- del_timer(&itv->dma_timer);
+
+ del_timer(&itv->dma_timer);
+
+ if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags) && itv->cur_dma_stream < 0)
return;
- }
if (!test_bit(IVTV_F_I_UDMA, &itv->i_flags)) {
s = &itv->streams[itv->cur_dma_stream];
@@ -543,7 +544,6 @@ static void ivtv_irq_dma_read(struct ivtv *itv)
}
wake_up(&s->waitq);
}
- del_timer(&itv->dma_timer);
clear_bit(IVTV_F_I_UDMA, &itv->i_flags);
clear_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = -1;
@@ -557,10 +557,12 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
ivtv_api_get_data(&itv->enc_mbox, IVTV_MBOX_DMA_END, data);
IVTV_DEBUG_HI_IRQ("ENC DMA COMPLETE %x %d (%d)\n", data[0], data[1], itv->cur_dma_stream);
- if (itv->cur_dma_stream < 0) {
- del_timer(&itv->dma_timer);
+
+ del_timer(&itv->dma_timer);
+
+ if (itv->cur_dma_stream < 0)
return;
- }
+
s = &itv->streams[itv->cur_dma_stream];
ivtv_stream_sync_for_cpu(s);
@@ -585,7 +587,6 @@ static void ivtv_irq_enc_dma_complete(struct ivtv *itv)
ivtv_dma_enc_start_xfer(s);
return;
}
- del_timer(&itv->dma_timer);
clear_bit(IVTV_F_I_DMA, &itv->i_flags);
itv->cur_dma_stream = -1;
dma_post(s);
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index 39a216713244..3e1deec67a5e 100644
--- a/drivers/media/video/ivtv/ivtv-queue.c
+++ b/drivers/media/video/ivtv/ivtv-queue.c
@@ -51,7 +51,7 @@ void ivtv_queue_init(struct ivtv_queue *q)
void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_queue *q)
{
- unsigned long flags = 0;
+ unsigned long flags;
/* clear the buffer if it is going to be enqueued to the free queue */
if (q == &s->q_free) {
@@ -71,7 +71,7 @@ void ivtv_enqueue(struct ivtv_stream *s, struct ivtv_buffer *buf, struct ivtv_qu
struct ivtv_buffer *ivtv_dequeue(struct ivtv_stream *s, struct ivtv_queue *q)
{
struct ivtv_buffer *buf = NULL;
- unsigned long flags = 0;
+ unsigned long flags;
spin_lock_irqsave(&s->qlock, flags);
if (!list_empty(&q->list)) {
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index 85183480a225..393d917cd672 100644
--- a/drivers/media/video/ivtv/ivtv-yuv.c
+++ b/drivers/media/video/ivtv/ivtv-yuv.c
@@ -718,9 +718,11 @@ static u32 ivtv_yuv_window_setup(struct ivtv *itv, struct yuv_frame_info *f)
f->src_w -= (osd_scale * osd_crop) >> 16;
}
- /* The OSD can be moved. Track to it */
- f->dst_x += itv->yuv_info.osd_x_offset;
- f->dst_y += itv->yuv_info.osd_y_offset;
+ if (itv->yuv_info.track_osd) {
+ /* The OSD can be moved. Track to it */
+ f->dst_x += itv->yuv_info.osd_x_offset;
+ f->dst_y += itv->yuv_info.osd_y_offset;
+ }
/* Width & height for both src & dst must be even.
Same for coordinates. */
@@ -792,11 +794,19 @@ void ivtv_yuv_work_handler(struct ivtv *itv)
IVTV_DEBUG_YUV("Update yuv registers for frame %d\n", frame);
f = yi->new_frame_info[frame];
- /* Update the osd pan info */
- f.pan_x = yi->osd_x_pan;
- f.pan_y = yi->osd_y_pan;
- f.vis_w = yi->osd_vis_w;
- f.vis_h = yi->osd_vis_h;
+ if (yi->track_osd) {
+ /* Snapshot the osd pan info */
+ f.pan_x = yi->osd_x_pan;
+ f.pan_y = yi->osd_y_pan;
+ f.vis_w = yi->osd_vis_w;
+ f.vis_h = yi->osd_vis_h;
+ } else {
+ /* Not tracking the osd, so assume full screen */
+ f.pan_x = 0;
+ f.pan_y = 0;
+ f.vis_w = 720;
+ f.vis_h = yi->decode_height;
+ }
/* Calculate the display window coordinates. Exit if nothing left */
if (!(yuv_update = ivtv_yuv_window_setup(itv, &f)))
@@ -914,7 +924,7 @@ static void ivtv_yuv_init(struct ivtv *itv)
}
/* Get next available yuv buffer on PVR350 */
-void ivtv_yuv_next_free(struct ivtv *itv)
+static void ivtv_yuv_next_free(struct ivtv *itv)
{
int draw, display;
struct yuv_playback_info *yi = &itv->yuv_info;
@@ -937,7 +947,7 @@ void ivtv_yuv_next_free(struct ivtv *itv)
}
/* Set up frame according to ivtv_dma_frame parameters */
-void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+static void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
{
struct yuv_playback_info *yi = &itv->yuv_info;
u8 frame = yi->draw_frame;
@@ -965,12 +975,6 @@ void ivtv_yuv_setup_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
/* Are we going to offset the Y plane */
nf->offset_y = (nf->tru_h + nf->src_x < 512 - 16) ? 1 : 0;
- /* Snapshot the osd pan info */
- nf->pan_x = yi->osd_x_pan;
- nf->pan_y = yi->osd_y_pan;
- nf->vis_w = yi->osd_vis_w;
- nf->vis_h = yi->osd_vis_h;
-
nf->update = 0;
nf->interlaced_y = 0;
nf->interlaced_uv = 0;
@@ -1042,7 +1046,7 @@ void ivtv_yuv_frame_complete(struct ivtv *itv)
(itv->yuv_info.draw_frame + 1) % IVTV_YUV_BUFFERS);
}
-int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
+static int ivtv_yuv_udma_frame(struct ivtv *itv, struct ivtv_dma_frame *args)
{
DEFINE_WAIT(wait);
int rc = 0;
diff --git a/drivers/media/video/meye.c b/drivers/media/video/meye.c
index 3d51fa0a52b6..61c980193c10 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -789,7 +789,7 @@ static irqreturn_t meye_irq(int irq, void *dev_id)
{
u32 v;
int reqnr;
- static int sequence = 0;
+ static int sequence;
v = mchip_read(MCHIP_MM_INTA);
@@ -1239,6 +1239,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
c->default_value = 48;
c->flags = 0;
break;
+ case V4L2_CID_MEYE_SHARPNESS:
case V4L2_CID_SHARPNESS:
c->type = V4L2_CTRL_TYPE_INTEGER;
strcpy(c->name, "Sharpness");
@@ -1246,7 +1247,12 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
c->maximum = 63;
c->step = 1;
c->default_value = 32;
- c->flags = 0;
+
+ /* Continue to report legacy private SHARPNESS ctrl but
+ * say it is disabled in preference to ctrl in the spec
+ */
+ c->flags = (c->id == V4L2_CID_SHARPNESS) ? 0 :
+ V4L2_CTRL_FLAG_DISABLED;
break;
case V4L2_CID_PICTURE:
c->type = V4L2_CTRL_TYPE_INTEGER;
@@ -1312,6 +1318,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
meye.params.agc = c->value;
break;
case V4L2_CID_SHARPNESS:
+ case V4L2_CID_MEYE_SHARPNESS:
sony_pic_camera_command(
SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
meye.params.sharpness = c->value;
@@ -1356,6 +1363,7 @@ static int meye_do_ioctl(struct inode *inode, struct file *file,
c->value = meye.params.agc;
break;
case V4L2_CID_SHARPNESS:
+ case V4L2_CID_MEYE_SHARPNESS:
c->value = meye.params.sharpness;
break;
case V4L2_CID_PICTURE:
@@ -1753,7 +1761,9 @@ static const struct file_operations meye_fops = {
.release = meye_release,
.mmap = meye_mmap,
.ioctl = meye_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.poll = meye_poll,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 61ec794a737e..7f5568592793 100644
--- a/drivers/media/video/msp3400-kthreads.c
+++ b/drivers/media/video/msp3400-kthreads.c
@@ -833,11 +833,6 @@ static int msp34xxg_modus(struct i2c_client *client)
v4l_dbg(1, msp_debug, client, "selected radio modus\n");
return 0x0001;
}
-
- if (state->v4l2_std & V4L2_STD_PAL) {
- v4l_dbg(1, msp_debug, client, "selected PAL modus\n");
- return 0x7001;
- }
if (state->v4l2_std == V4L2_STD_NTSC_M_JP) {
v4l_dbg(1, msp_debug, client, "selected M (EIA-J) modus\n");
return 0x4001;
@@ -846,15 +841,15 @@ static int msp34xxg_modus(struct i2c_client *client)
v4l_dbg(1, msp_debug, client, "selected M (A2) modus\n");
return 0x0001;
}
+ if (state->v4l2_std == V4L2_STD_SECAM_L) {
+ v4l_dbg(1, msp_debug, client, "selected SECAM-L modus\n");
+ return 0x6001;
+ }
if (state->v4l2_std & V4L2_STD_MN) {
v4l_dbg(1, msp_debug, client, "selected M (BTSC) modus\n");
return 0x2001;
}
- if (state->v4l2_std & V4L2_STD_SECAM) {
- v4l_dbg(1, msp_debug, client, "selected SECAM modus\n");
- return 0x6001;
- }
- return 0x0001;
+ return 0x7001;
}
static void msp34xxg_set_source(struct i2c_client *client, u16 reg, int in)
diff --git a/drivers/media/video/mt20xx.c b/drivers/media/video/mt20xx.c
index 74fd6a01d4c4..fbcb28233737 100644
--- a/drivers/media/video/mt20xx.c
+++ b/drivers/media/video/mt20xx.c
@@ -10,12 +10,10 @@
#include "tuner-i2c.h"
#include "mt20xx.h"
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
-#define PREFIX "mt20xx"
-
/* ---------------------------------------------------------------------- */
static unsigned int optimize_vco = 1;
@@ -24,7 +22,7 @@ module_param(optimize_vco, int, 0644);
static unsigned int tv_antenna = 1;
module_param(tv_antenna, int, 0644);
-static unsigned int radio_antenna = 0;
+static unsigned int radio_antenna;
module_param(radio_antenna, int, 0644);
/* ---------------------------------------------------------------------- */
@@ -611,6 +609,7 @@ struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
priv->i2c_props.addr = i2c_addr;
priv->i2c_props.adap = i2c_adap;
+ priv->i2c_props.name = "mt20xx";
//priv->radio_if2 = 10700 * 1000; /* 10.7MHz - FM radio */
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
new file mode 100644
index 000000000000..2ea133e8a625
--- /dev/null
+++ b/drivers/media/video/mt9m001.c
@@ -0,0 +1,722 @@
+/*
+ * Driver for MT9M001 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/log2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+#include <asm/gpio.h>
+#endif
+
+/* mt9m001 i2c address 0x5d
+ * The platform has to define i2c_board_info
+ * and call i2c_register_board_info() */
+
+/* mt9m001 selected register addresses */
+#define MT9M001_CHIP_VERSION 0x00
+#define MT9M001_ROW_START 0x01
+#define MT9M001_COLUMN_START 0x02
+#define MT9M001_WINDOW_HEIGHT 0x03
+#define MT9M001_WINDOW_WIDTH 0x04
+#define MT9M001_HORIZONTAL_BLANKING 0x05
+#define MT9M001_VERTICAL_BLANKING 0x06
+#define MT9M001_OUTPUT_CONTROL 0x07
+#define MT9M001_SHUTTER_WIDTH 0x09
+#define MT9M001_FRAME_RESTART 0x0b
+#define MT9M001_SHUTTER_DELAY 0x0c
+#define MT9M001_RESET 0x0d
+#define MT9M001_READ_OPTIONS1 0x1e
+#define MT9M001_READ_OPTIONS2 0x20
+#define MT9M001_GLOBAL_GAIN 0x35
+#define MT9M001_CHIP_ENABLE 0xF1
+
+static const struct soc_camera_data_format mt9m001_colour_formats[] = {
+ /* Order important: first natively supported,
+ * second supported with a GPIO extender */
+ {
+ .name = "Bayer (sRGB) 10 bit",
+ .depth = 10,
+ .fourcc = V4L2_PIX_FMT_SBGGR16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }, {
+ .name = "Bayer (sRGB) 8 bit",
+ .depth = 8,
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }
+};
+
+static const struct soc_camera_data_format mt9m001_monochrome_formats[] = {
+ /* Order important - see above */
+ {
+ .name = "Monochrome 10 bit",
+ .depth = 10,
+ .fourcc = V4L2_PIX_FMT_Y16,
+ }, {
+ .name = "Monochrome 8 bit",
+ .depth = 8,
+ .fourcc = V4L2_PIX_FMT_GREY,
+ },
+};
+
+struct mt9m001 {
+ struct i2c_client *client;
+ struct soc_camera_device icd;
+ int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+ int switch_gpio;
+ unsigned char autoexposure;
+ unsigned char datawidth;
+};
+
+static int reg_read(struct soc_camera_device *icd, const u8 reg)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ struct i2c_client *client = mt9m001->client;
+ s32 data = i2c_smbus_read_word_data(client, reg);
+ return data < 0 ? data : swab16(data);
+}
+
+static int reg_write(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ return i2c_smbus_write_word_data(mt9m001->client, reg, swab16(data));
+}
+
+static int reg_set(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(icd, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(icd, reg, ret | data);
+}
+
+static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(icd, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(icd, reg, ret & ~data);
+}
+
+static int mt9m001_init(struct soc_camera_device *icd)
+{
+ int ret;
+
+ /* Disable chip, synchronous option update */
+ dev_dbg(icd->vdev->dev, "%s\n", __FUNCTION__);
+
+ ret = reg_write(icd, MT9M001_RESET, 1);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9M001_RESET, 0);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+
+ return ret >= 0 ? 0 : -EIO;
+}
+
+static int mt9m001_release(struct soc_camera_device *icd)
+{
+ /* Disable the chip */
+ reg_write(icd, MT9M001_OUTPUT_CONTROL, 0);
+ return 0;
+}
+
+static int mt9m001_start_capture(struct soc_camera_device *icd)
+{
+ /* Switch to master "normal" mode */
+ if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 2) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int mt9m001_stop_capture(struct soc_camera_device *icd)
+{
+ /* Stop sensor readout */
+ if (reg_write(icd, MT9M001_OUTPUT_CONTROL, 0) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int bus_switch_request(struct mt9m001 *mt9m001,
+ struct soc_camera_link *icl)
+{
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+ int ret;
+ unsigned int gpio = icl->gpio;
+
+ if (gpio_is_valid(gpio)) {
+ /* We have a data bus switch. */
+ ret = gpio_request(gpio, "mt9m001");
+ if (ret < 0) {
+ dev_err(&mt9m001->client->dev, "Cannot get GPIO %u\n",
+ gpio);
+ return ret;
+ }
+
+ ret = gpio_direction_output(gpio, 0);
+ if (ret < 0) {
+ dev_err(&mt9m001->client->dev,
+ "Cannot set GPIO %u to output\n", gpio);
+ gpio_free(gpio);
+ return ret;
+ }
+ }
+
+ mt9m001->switch_gpio = gpio;
+#else
+ mt9m001->switch_gpio = -EINVAL;
+#endif
+ return 0;
+}
+
+static void bus_switch_release(struct mt9m001 *mt9m001)
+{
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+ if (gpio_is_valid(mt9m001->switch_gpio))
+ gpio_free(mt9m001->switch_gpio);
+#endif
+}
+
+static int bus_switch_act(struct mt9m001 *mt9m001, int go8bit)
+{
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+ if (!gpio_is_valid(mt9m001->switch_gpio))
+ return -ENODEV;
+
+ gpio_set_value_cansleep(mt9m001->switch_gpio, go8bit);
+ return 0;
+#else
+ return -ENODEV;
+#endif
+}
+
+static int bus_switch_possible(struct mt9m001 *mt9m001)
+{
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+ return gpio_is_valid(mt9m001->switch_gpio);
+#else
+ return 0;
+#endif
+}
+
+static int mt9m001_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
+ int ret;
+
+ /* Flags validity verified in test_bus_param */
+
+ if ((mt9m001->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
+ (mt9m001->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
+ (mt9m001->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
+ /* Well, we actually only can do 10 or 8 bits... */
+ if (width_flag == SOCAM_DATAWIDTH_9)
+ return -EINVAL;
+ ret = bus_switch_act(mt9m001,
+ width_flag == SOCAM_DATAWIDTH_8);
+ if (ret < 0)
+ return ret;
+
+ mt9m001->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
+ }
+
+ return 0;
+}
+
+static unsigned long mt9m001_query_bus_param(struct soc_camera_device *icd)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ unsigned int width_flag = SOCAM_DATAWIDTH_10;
+
+ if (bus_switch_possible(mt9m001))
+ width_flag |= SOCAM_DATAWIDTH_8;
+
+ /* MT9M001 has all capture_format parameters fixed */
+ return SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_MASTER |
+ width_flag;
+}
+
+static int mt9m001_set_fmt_cap(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ int ret;
+ const u16 hblank = 9, vblank = 25;
+
+ /* Blanking and start values - default... */
+ ret = reg_write(icd, MT9M001_HORIZONTAL_BLANKING, hblank);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9M001_VERTICAL_BLANKING, vblank);
+
+ /* The caller provides a supported format, as verified per
+ * call to icd->try_fmt_cap() */
+ if (ret >= 0)
+ ret = reg_write(icd, MT9M001_COLUMN_START, rect->left);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9M001_ROW_START, rect->top);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9M001_WINDOW_WIDTH, rect->width - 1);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9M001_WINDOW_HEIGHT,
+ rect->height + icd->y_skip_top - 1);
+ if (ret >= 0 && mt9m001->autoexposure) {
+ ret = reg_write(icd, MT9M001_SHUTTER_WIDTH,
+ rect->height + icd->y_skip_top + vblank);
+ if (ret >= 0) {
+ const struct v4l2_queryctrl *qctrl =
+ soc_camera_find_qctrl(icd->ops,
+ V4L2_CID_EXPOSURE);
+ icd->exposure = (524 + (rect->height + icd->y_skip_top +
+ vblank - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
+ 1048 + qctrl->minimum;
+ }
+ }
+
+ return ret < 0 ? ret : 0;
+}
+
+static int mt9m001_try_fmt_cap(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ if (f->fmt.pix.height < 32 + icd->y_skip_top)
+ f->fmt.pix.height = 32 + icd->y_skip_top;
+ if (f->fmt.pix.height > 1024 + icd->y_skip_top)
+ f->fmt.pix.height = 1024 + icd->y_skip_top;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > 1280)
+ f->fmt.pix.width = 1280;
+ f->fmt.pix.width &= ~0x01; /* has to be even, unsure why was ~3 */
+
+ return 0;
+}
+
+static int mt9m001_get_chip_id(struct soc_camera_device *icd,
+ struct v4l2_chip_ident *id)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+
+ if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match_chip != mt9m001->client->addr)
+ return -ENODEV;
+
+ id->ident = mt9m001->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9m001_get_register(struct soc_camera_device *icd,
+ struct v4l2_register *reg)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+
+ if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match_chip != mt9m001->client->addr)
+ return -ENODEV;
+
+ reg->val = reg_read(icd, reg->reg);
+
+ if (reg->val > 0xffff)
+ return -EIO;
+
+ return 0;
+}
+
+static int mt9m001_set_register(struct soc_camera_device *icd,
+ struct v4l2_register *reg)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+
+ if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match_chip != mt9m001->client->addr)
+ return -ENODEV;
+
+ if (reg_write(icd, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+const struct v4l2_queryctrl mt9m001_controls[] = {
+ {
+ .id = V4L2_CID_VFLIP,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Flip Vertically",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 0,
+ }, {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Gain",
+ .minimum = 0,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 64,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 255,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ }
+};
+
+static int mt9m001_video_probe(struct soc_camera_device *);
+static void mt9m001_video_remove(struct soc_camera_device *);
+static int mt9m001_get_control(struct soc_camera_device *, struct v4l2_control *);
+static int mt9m001_set_control(struct soc_camera_device *, struct v4l2_control *);
+
+static struct soc_camera_ops mt9m001_ops = {
+ .owner = THIS_MODULE,
+ .probe = mt9m001_video_probe,
+ .remove = mt9m001_video_remove,
+ .init = mt9m001_init,
+ .release = mt9m001_release,
+ .start_capture = mt9m001_start_capture,
+ .stop_capture = mt9m001_stop_capture,
+ .set_fmt_cap = mt9m001_set_fmt_cap,
+ .try_fmt_cap = mt9m001_try_fmt_cap,
+ .set_bus_param = mt9m001_set_bus_param,
+ .query_bus_param = mt9m001_query_bus_param,
+ .controls = mt9m001_controls,
+ .num_controls = ARRAY_SIZE(mt9m001_controls),
+ .get_control = mt9m001_get_control,
+ .set_control = mt9m001_set_control,
+ .get_chip_id = mt9m001_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .get_register = mt9m001_get_register,
+ .set_register = mt9m001_set_register,
+#endif
+};
+
+static int mt9m001_get_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ data = reg_read(icd, MT9M001_READ_OPTIONS2);
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & 0x8000);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ ctrl->value = mt9m001->autoexposure;
+ break;
+ }
+ return 0;
+}
+
+static int mt9m001_set_control(struct soc_camera_device *icd, struct v4l2_control *ctrl)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ const struct v4l2_queryctrl *qctrl;
+ int data;
+
+ qctrl = soc_camera_find_qctrl(&mt9m001_ops, ctrl->id);
+
+ if (!qctrl)
+ return -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->value)
+ data = reg_set(icd, MT9M001_READ_OPTIONS2, 0x8000);
+ else
+ data = reg_clear(icd, MT9M001_READ_OPTIONS2, 0x8000);
+ if (data < 0)
+ return -EIO;
+ break;
+ case V4L2_CID_GAIN:
+ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+ return -EINVAL;
+ /* See Datasheet Table 7, Gain settings. */
+ if (ctrl->value <= qctrl->default_value) {
+ /* Pack it into 0..1 step 0.125, register values 0..8 */
+ unsigned long range = qctrl->default_value - qctrl->minimum;
+ data = ((ctrl->value - qctrl->minimum) * 8 + range / 2) / range;
+
+ dev_dbg(&icd->dev, "Setting gain %d\n", data);
+ data = reg_write(icd, MT9M001_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+ } else {
+ /* Pack it into 1.125..15 variable step, register values 9..67 */
+ /* We assume qctrl->maximum - qctrl->default_value - 1 > 0 */
+ unsigned long range = qctrl->maximum - qctrl->default_value - 1;
+ unsigned long gain = ((ctrl->value - qctrl->default_value - 1) *
+ 111 + range / 2) / range + 9;
+
+ if (gain <= 32)
+ data = gain;
+ else if (gain <= 64)
+ data = ((gain - 32) * 16 + 16) / 32 + 80;
+ else
+ data = ((gain - 64) * 7 + 28) / 56 + 96;
+
+ dev_dbg(&icd->dev, "Setting gain from %d to %d\n",
+ reg_read(icd, MT9M001_GLOBAL_GAIN), data);
+ data = reg_write(icd, MT9M001_GLOBAL_GAIN, data);
+ if (data < 0)
+ return -EIO;
+ }
+
+ /* Success */
+ icd->gain = ctrl->value;
+ break;
+ case V4L2_CID_EXPOSURE:
+ /* mt9m001 has maximum == default */
+ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+ return -EINVAL;
+ else {
+ unsigned long range = qctrl->maximum - qctrl->minimum;
+ unsigned long shutter = ((ctrl->value - qctrl->minimum) * 1048 +
+ range / 2) / range + 1;
+
+ dev_dbg(&icd->dev, "Setting shutter width from %d to %lu\n",
+ reg_read(icd, MT9M001_SHUTTER_WIDTH), shutter);
+ if (reg_write(icd, MT9M001_SHUTTER_WIDTH, shutter) < 0)
+ return -EIO;
+ icd->exposure = ctrl->value;
+ mt9m001->autoexposure = 0;
+ }
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ if (ctrl->value) {
+ const u16 vblank = 25;
+ if (reg_write(icd, MT9M001_SHUTTER_WIDTH, icd->height +
+ icd->y_skip_top + vblank) < 0)
+ return -EIO;
+ qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
+ icd->exposure = (524 + (icd->height + icd->y_skip_top + vblank - 1) *
+ (qctrl->maximum - qctrl->minimum)) /
+ 1048 + qctrl->minimum;
+ mt9m001->autoexposure = 1;
+ } else
+ mt9m001->autoexposure = 0;
+ break;
+ }
+ return 0;
+}
+
+/* Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one */
+static int mt9m001_video_probe(struct soc_camera_device *icd)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+ s32 data;
+ int ret;
+
+ /* We must have a parent by now. And it cannot be a wrong one.
+ * So this entire test is completely redundant. */
+ if (!icd->dev.parent ||
+ to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+ return -ENODEV;
+
+ /* Enable the chip */
+ data = reg_write(&mt9m001->icd, MT9M001_CHIP_ENABLE, 1);
+ dev_dbg(&icd->dev, "write: %d\n", data);
+
+ /* Read out the chip version register */
+ data = reg_read(icd, MT9M001_CHIP_VERSION);
+
+ /* must be 0x8411 or 0x8421 for colour sensor and 8431 for bw */
+ switch (data) {
+ case 0x8411:
+ case 0x8421:
+ mt9m001->model = V4L2_IDENT_MT9M001C12ST;
+ icd->formats = mt9m001_colour_formats;
+ if (mt9m001->client->dev.platform_data)
+ icd->num_formats = ARRAY_SIZE(mt9m001_colour_formats);
+ else
+ icd->num_formats = 1;
+ break;
+ case 0x8431:
+ mt9m001->model = V4L2_IDENT_MT9M001C12STM;
+ icd->formats = mt9m001_monochrome_formats;
+ if (mt9m001->client->dev.platform_data)
+ icd->num_formats = ARRAY_SIZE(mt9m001_monochrome_formats);
+ else
+ icd->num_formats = 1;
+ break;
+ default:
+ ret = -ENODEV;
+ dev_err(&icd->dev,
+ "No MT9M001 chip detected, register read %x\n", data);
+ goto ei2c;
+ }
+
+ dev_info(&icd->dev, "Detected a MT9M001 chip ID %x (%s)\n", data,
+ data == 0x8431 ? "C12STM" : "C12ST");
+
+ /* Now that we know the model, we can start video */
+ ret = soc_camera_video_start(icd);
+ if (ret)
+ goto eisis;
+
+ return 0;
+
+eisis:
+ei2c:
+ return ret;
+}
+
+static void mt9m001_video_remove(struct soc_camera_device *icd)
+{
+ struct mt9m001 *mt9m001 = container_of(icd, struct mt9m001, icd);
+
+ dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9m001->client->addr,
+ mt9m001->icd.dev.parent, mt9m001->icd.vdev);
+ soc_camera_video_stop(&mt9m001->icd);
+}
+
+static int mt9m001_probe(struct i2c_client *client)
+{
+ struct mt9m001 *mt9m001;
+ struct soc_camera_device *icd;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl = client->dev.platform_data;
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "MT9M001 driver needs platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9m001 = kzalloc(sizeof(struct mt9m001), GFP_KERNEL);
+ if (!mt9m001)
+ return -ENOMEM;
+
+ mt9m001->client = client;
+ i2c_set_clientdata(client, mt9m001);
+
+ /* Second stage probe - when a capture adapter is there */
+ icd = &mt9m001->icd;
+ icd->ops = &mt9m001_ops;
+ icd->control = &client->dev;
+ icd->x_min = 20;
+ icd->y_min = 12;
+ icd->x_current = 20;
+ icd->y_current = 12;
+ icd->width_min = 48;
+ icd->width_max = 1280;
+ icd->height_min = 32;
+ icd->height_max = 1024;
+ icd->y_skip_top = 1;
+ icd->iface = icl->bus_id;
+ /* Default datawidth - this is the only width this camera (normally)
+ * supports. It is only with extra logic that it can support
+ * other widths. Therefore it seems to be a sensible default. */
+ mt9m001->datawidth = 10;
+ /* Simulated autoexposure. If enabled, we calculate shutter width
+ * ourselves in the driver based on vertical blanking and frame width */
+ mt9m001->autoexposure = 1;
+
+ ret = bus_switch_request(mt9m001, icl);
+ if (ret)
+ goto eswinit;
+
+ ret = soc_camera_device_register(icd);
+ if (ret)
+ goto eisdr;
+
+ return 0;
+
+eisdr:
+ bus_switch_release(mt9m001);
+eswinit:
+ kfree(mt9m001);
+ return ret;
+}
+
+static int mt9m001_remove(struct i2c_client *client)
+{
+ struct mt9m001 *mt9m001 = i2c_get_clientdata(client);
+
+ soc_camera_device_unregister(&mt9m001->icd);
+ bus_switch_release(mt9m001);
+ kfree(mt9m001);
+
+ return 0;
+}
+
+static struct i2c_driver mt9m001_i2c_driver = {
+ .driver = {
+ .name = "mt9m001",
+ },
+ .probe = mt9m001_probe,
+ .remove = mt9m001_remove,
+};
+
+static int __init mt9m001_mod_init(void)
+{
+ return i2c_add_driver(&mt9m001_i2c_driver);
+}
+
+static void __exit mt9m001_mod_exit(void)
+{
+ i2c_del_driver(&mt9m001_i2c_driver);
+}
+
+module_init(mt9m001_mod_init);
+module_exit(mt9m001_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9M001 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mt9v022.c b/drivers/media/video/mt9v022.c
new file mode 100644
index 000000000000..d4b9e2744343
--- /dev/null
+++ b/drivers/media/video/mt9v022.c
@@ -0,0 +1,844 @@
+/*
+ * Driver for MT9V022 CMOS Image Sensor from Micron
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/videodev2.h>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include <linux/delay.h>
+#include <linux/log2.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-chip-ident.h>
+#include <media/soc_camera.h>
+
+#ifdef CONFIG_MT9M001_PCA9536_SWITCH
+#include <asm/gpio.h>
+#endif
+
+/* mt9v022 i2c address 0x48, 0x4c, 0x58, 0x5c
+ * The platform has to define i2c_board_info
+ * and call i2c_register_board_info() */
+
+static char *sensor_type;
+module_param(sensor_type, charp, S_IRUGO);
+MODULE_PARM_DESC(sensor_type, "Sensor type: \"colour\" or \"monochrome\"\n");
+
+/* mt9v022 selected register addresses */
+#define MT9V022_CHIP_VERSION 0x00
+#define MT9V022_COLUMN_START 0x01
+#define MT9V022_ROW_START 0x02
+#define MT9V022_WINDOW_HEIGHT 0x03
+#define MT9V022_WINDOW_WIDTH 0x04
+#define MT9V022_HORIZONTAL_BLANKING 0x05
+#define MT9V022_VERTICAL_BLANKING 0x06
+#define MT9V022_CHIP_CONTROL 0x07
+#define MT9V022_SHUTTER_WIDTH1 0x08
+#define MT9V022_SHUTTER_WIDTH2 0x09
+#define MT9V022_SHUTTER_WIDTH_CTRL 0x0a
+#define MT9V022_TOTAL_SHUTTER_WIDTH 0x0b
+#define MT9V022_RESET 0x0c
+#define MT9V022_READ_MODE 0x0d
+#define MT9V022_MONITOR_MODE 0x0e
+#define MT9V022_PIXEL_OPERATION_MODE 0x0f
+#define MT9V022_LED_OUT_CONTROL 0x1b
+#define MT9V022_ADC_MODE_CONTROL 0x1c
+#define MT9V022_ANALOG_GAIN 0x34
+#define MT9V022_BLACK_LEVEL_CALIB_CTRL 0x47
+#define MT9V022_PIXCLK_FV_LV 0x74
+#define MT9V022_DIGITAL_TEST_PATTERN 0x7f
+#define MT9V022_AEC_AGC_ENABLE 0xAF
+#define MT9V022_MAX_TOTAL_SHUTTER_WIDTH 0xBD
+
+/* Progressive scan, master, defaults */
+#define MT9V022_CHIP_CONTROL_DEFAULT 0x188
+
+static const struct soc_camera_data_format mt9v022_colour_formats[] = {
+ /* Order important: first natively supported,
+ * second supported with a GPIO extender */
+ {
+ .name = "Bayer (sRGB) 10 bit",
+ .depth = 10,
+ .fourcc = V4L2_PIX_FMT_SBGGR16,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }, {
+ .name = "Bayer (sRGB) 8 bit",
+ .depth = 8,
+ .fourcc = V4L2_PIX_FMT_SBGGR8,
+ .colorspace = V4L2_COLORSPACE_SRGB,
+ }
+};
+
+static const struct soc_camera_data_format mt9v022_monochrome_formats[] = {
+ /* Order important - see above */
+ {
+ .name = "Monochrome 10 bit",
+ .depth = 10,
+ .fourcc = V4L2_PIX_FMT_Y16,
+ }, {
+ .name = "Monochrome 8 bit",
+ .depth = 8,
+ .fourcc = V4L2_PIX_FMT_GREY,
+ },
+};
+
+struct mt9v022 {
+ struct i2c_client *client;
+ struct soc_camera_device icd;
+ int model; /* V4L2_IDENT_MT9M001* codes from v4l2-chip-ident.h */
+ int switch_gpio;
+ u16 chip_control;
+ unsigned char datawidth;
+};
+
+static int reg_read(struct soc_camera_device *icd, const u8 reg)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ struct i2c_client *client = mt9v022->client;
+ s32 data = i2c_smbus_read_word_data(client, reg);
+ return data < 0 ? data : swab16(data);
+}
+
+static int reg_write(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ return i2c_smbus_write_word_data(mt9v022->client, reg, swab16(data));
+}
+
+static int reg_set(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(icd, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(icd, reg, ret | data);
+}
+
+static int reg_clear(struct soc_camera_device *icd, const u8 reg,
+ const u16 data)
+{
+ int ret;
+
+ ret = reg_read(icd, reg);
+ if (ret < 0)
+ return ret;
+ return reg_write(icd, reg, ret & ~data);
+}
+
+static int mt9v022_init(struct soc_camera_device *icd)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ int ret;
+
+ /* Almost the default mode: master, parallel, simultaneous, and an
+ * undocumented bit 0x200, which is present in table 7, but not in 8,
+ * plus snapshot mode to disable scan for now */
+ mt9v022->chip_control |= 0x10;
+ ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+ if (ret >= 0)
+ reg_write(icd, MT9V022_READ_MODE, 0x300);
+
+ /* All defaults */
+ if (ret >= 0)
+ /* AEC, AGC on */
+ ret = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x3);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH, 480);
+ if (ret >= 0)
+ /* default - auto */
+ ret = reg_clear(icd, MT9V022_BLACK_LEVEL_CALIB_CTRL, 1);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9V022_DIGITAL_TEST_PATTERN, 0);
+
+ return ret >= 0 ? 0 : -EIO;
+}
+
+static int mt9v022_release(struct soc_camera_device *icd)
+{
+ /* Nothing? */
+ return 0;
+}
+
+static int mt9v022_start_capture(struct soc_camera_device *icd)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ /* Switch to master "normal" mode */
+ mt9v022->chip_control &= ~0x10;
+ if (reg_write(icd, MT9V022_CHIP_CONTROL,
+ mt9v022->chip_control) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int mt9v022_stop_capture(struct soc_camera_device *icd)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ /* Switch to snapshot mode */
+ mt9v022->chip_control |= 0x10;
+ if (reg_write(icd, MT9V022_CHIP_CONTROL,
+ mt9v022->chip_control) < 0)
+ return -EIO;
+ return 0;
+}
+
+static int bus_switch_request(struct mt9v022 *mt9v022, struct soc_camera_link *icl)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+ int ret;
+ unsigned int gpio = icl->gpio;
+
+ if (gpio_is_valid(gpio)) {
+ /* We have a data bus switch. */
+ ret = gpio_request(gpio, "mt9v022");
+ if (ret < 0) {
+ dev_err(&mt9v022->client->dev, "Cannot get GPIO %u\n", gpio);
+ return ret;
+ }
+
+ ret = gpio_direction_output(gpio, 0);
+ if (ret < 0) {
+ dev_err(&mt9v022->client->dev,
+ "Cannot set GPIO %u to output\n", gpio);
+ gpio_free(gpio);
+ return ret;
+ }
+ }
+
+ mt9v022->switch_gpio = gpio;
+#else
+ mt9v022->switch_gpio = -EINVAL;
+#endif
+ return 0;
+}
+
+static void bus_switch_release(struct mt9v022 *mt9v022)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+ if (gpio_is_valid(mt9v022->switch_gpio))
+ gpio_free(mt9v022->switch_gpio);
+#endif
+}
+
+static int bus_switch_act(struct mt9v022 *mt9v022, int go8bit)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+ if (!gpio_is_valid(mt9v022->switch_gpio))
+ return -ENODEV;
+
+ gpio_set_value_cansleep(mt9v022->switch_gpio, go8bit);
+ return 0;
+#else
+ return -ENODEV;
+#endif
+}
+
+static int bus_switch_possible(struct mt9v022 *mt9v022)
+{
+#ifdef CONFIG_MT9V022_PCA9536_SWITCH
+ return gpio_is_valid(mt9v022->switch_gpio);
+#else
+ return 0;
+#endif
+}
+
+static int mt9v022_set_bus_param(struct soc_camera_device *icd,
+ unsigned long flags)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ unsigned int width_flag = flags & SOCAM_DATAWIDTH_MASK;
+ int ret;
+ u16 pixclk = 0;
+
+ /* Only one width bit may be set */
+ if (!is_power_of_2(width_flag))
+ return -EINVAL;
+
+ if ((mt9v022->datawidth != 10 && (width_flag == SOCAM_DATAWIDTH_10)) ||
+ (mt9v022->datawidth != 9 && (width_flag == SOCAM_DATAWIDTH_9)) ||
+ (mt9v022->datawidth != 8 && (width_flag == SOCAM_DATAWIDTH_8))) {
+ /* Well, we actually only can do 10 or 8 bits... */
+ if (width_flag == SOCAM_DATAWIDTH_9)
+ return -EINVAL;
+
+ ret = bus_switch_act(mt9v022,
+ width_flag == SOCAM_DATAWIDTH_8);
+ if (ret < 0)
+ return ret;
+
+ mt9v022->datawidth = width_flag == SOCAM_DATAWIDTH_8 ? 8 : 10;
+ }
+
+ if (flags & SOCAM_PCLK_SAMPLE_RISING)
+ pixclk |= 0x10;
+
+ if (!(flags & SOCAM_HSYNC_ACTIVE_HIGH))
+ pixclk |= 0x1;
+
+ if (!(flags & SOCAM_VSYNC_ACTIVE_HIGH))
+ pixclk |= 0x2;
+
+ ret = reg_write(icd, MT9V022_PIXCLK_FV_LV, pixclk);
+ if (ret < 0)
+ return ret;
+
+ if (!(flags & SOCAM_MASTER))
+ mt9v022->chip_control &= ~0x8;
+
+ ret = reg_write(icd, MT9V022_CHIP_CONTROL, mt9v022->chip_control);
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&icd->dev, "Calculated pixclk 0x%x, chip control 0x%x\n",
+ pixclk, mt9v022->chip_control);
+
+ return 0;
+}
+
+static unsigned long mt9v022_query_bus_param(struct soc_camera_device *icd)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ unsigned int width_flag = SOCAM_DATAWIDTH_10;
+
+ if (bus_switch_possible(mt9v022))
+ width_flag |= SOCAM_DATAWIDTH_8;
+
+ return 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_MASTER | SOCAM_SLAVE |
+ width_flag;
+}
+
+static int mt9v022_set_fmt_cap(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ int ret;
+
+ /* The caller provides a supported format, as verified per call to
+ * icd->try_fmt_cap(), datawidth is from our supported format list */
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_GREY:
+ case V4L2_PIX_FMT_Y16:
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATM)
+ return -EINVAL;
+ break;
+ case V4L2_PIX_FMT_SBGGR8:
+ case V4L2_PIX_FMT_SBGGR16:
+ if (mt9v022->model != V4L2_IDENT_MT9V022IX7ATC)
+ return -EINVAL;
+ break;
+ case 0:
+ /* No format change, only geometry */
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ /* Like in example app. Contradicts the datasheet though */
+ ret = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+ if (ret >= 0) {
+ if (ret & 1) /* Autoexposure */
+ ret = reg_write(icd, MT9V022_MAX_TOTAL_SHUTTER_WIDTH,
+ rect->height + icd->y_skip_top + 43);
+ else
+ ret = reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH,
+ rect->height + icd->y_skip_top + 43);
+ }
+ /* Setup frame format: defaults apart from width and height */
+ if (ret >= 0)
+ ret = reg_write(icd, MT9V022_COLUMN_START, rect->left);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9V022_ROW_START, rect->top);
+ if (ret >= 0)
+ /* Default 94, Phytec driver says:
+ * "width + horizontal blank >= 660" */
+ ret = reg_write(icd, MT9V022_HORIZONTAL_BLANKING,
+ rect->width > 660 - 43 ? 43 :
+ 660 - rect->width);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9V022_VERTICAL_BLANKING, 45);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9V022_WINDOW_WIDTH, rect->width);
+ if (ret >= 0)
+ ret = reg_write(icd, MT9V022_WINDOW_HEIGHT,
+ rect->height + icd->y_skip_top);
+
+ if (ret < 0)
+ return ret;
+
+ dev_dbg(&icd->dev, "Frame %ux%u pixel\n", rect->width, rect->height);
+
+ return 0;
+}
+
+static int mt9v022_try_fmt_cap(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ if (f->fmt.pix.height < 32 + icd->y_skip_top)
+ f->fmt.pix.height = 32 + icd->y_skip_top;
+ if (f->fmt.pix.height > 480 + icd->y_skip_top)
+ f->fmt.pix.height = 480 + icd->y_skip_top;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > 752)
+ f->fmt.pix.width = 752;
+ f->fmt.pix.width &= ~0x03; /* ? */
+
+ return 0;
+}
+
+static int mt9v022_get_chip_id(struct soc_camera_device *icd,
+ struct v4l2_chip_ident *id)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+
+ if (id->match_type != V4L2_CHIP_MATCH_I2C_ADDR)
+ return -EINVAL;
+
+ if (id->match_chip != mt9v022->client->addr)
+ return -ENODEV;
+
+ id->ident = mt9v022->model;
+ id->revision = 0;
+
+ return 0;
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int mt9v022_get_register(struct soc_camera_device *icd,
+ struct v4l2_register *reg)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+
+ if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match_chip != mt9v022->client->addr)
+ return -ENODEV;
+
+ reg->val = reg_read(icd, reg->reg);
+
+ if (reg->val > 0xffff)
+ return -EIO;
+
+ return 0;
+}
+
+static int mt9v022_set_register(struct soc_camera_device *icd,
+ struct v4l2_register *reg)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+
+ if (reg->match_type != V4L2_CHIP_MATCH_I2C_ADDR || reg->reg > 0xff)
+ return -EINVAL;
+
+ if (reg->match_chip != mt9v022->client->addr)
+ return -ENODEV;
+
+ if (reg_write(icd, reg->reg, reg->val) < 0)
+ return -EIO;
+
+ return 0;
+}
+#endif
+
+const struct v4l2_queryctrl mt9v022_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,
+ }, {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Analog Gain",
+ .minimum = 64,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 64,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Exposure",
+ .minimum = 1,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 255,
+ .flags = V4L2_CTRL_FLAG_SLIDER,
+ }, {
+ .id = V4L2_CID_AUTOGAIN,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Gain",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ }, {
+ .id = V4L2_CID_EXPOSURE_AUTO,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Automatic Exposure",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ }
+};
+
+static int mt9v022_video_probe(struct soc_camera_device *);
+static void mt9v022_video_remove(struct soc_camera_device *);
+static int mt9v022_get_control(struct soc_camera_device *, struct v4l2_control *);
+static int mt9v022_set_control(struct soc_camera_device *, struct v4l2_control *);
+
+static struct soc_camera_ops mt9v022_ops = {
+ .owner = THIS_MODULE,
+ .probe = mt9v022_video_probe,
+ .remove = mt9v022_video_remove,
+ .init = mt9v022_init,
+ .release = mt9v022_release,
+ .start_capture = mt9v022_start_capture,
+ .stop_capture = mt9v022_stop_capture,
+ .set_fmt_cap = mt9v022_set_fmt_cap,
+ .try_fmt_cap = mt9v022_try_fmt_cap,
+ .set_bus_param = mt9v022_set_bus_param,
+ .query_bus_param = mt9v022_query_bus_param,
+ .controls = mt9v022_controls,
+ .num_controls = ARRAY_SIZE(mt9v022_controls),
+ .get_control = mt9v022_get_control,
+ .set_control = mt9v022_set_control,
+ .get_chip_id = mt9v022_get_chip_id,
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ .get_register = mt9v022_get_register,
+ .set_register = mt9v022_set_register,
+#endif
+};
+
+static int mt9v022_get_control(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ int data;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ data = reg_read(icd, MT9V022_READ_MODE);
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & 0x10);
+ break;
+ case V4L2_CID_HFLIP:
+ data = reg_read(icd, MT9V022_READ_MODE);
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & 0x20);
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ data = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & 0x1);
+ break;
+ case V4L2_CID_AUTOGAIN:
+ data = reg_read(icd, MT9V022_AEC_AGC_ENABLE);
+ if (data < 0)
+ return -EIO;
+ ctrl->value = !!(data & 0x2);
+ break;
+ }
+ return 0;
+}
+
+static int mt9v022_set_control(struct soc_camera_device *icd,
+ struct v4l2_control *ctrl)
+{
+ int data;
+ const struct v4l2_queryctrl *qctrl;
+
+ qctrl = soc_camera_find_qctrl(&mt9v022_ops, ctrl->id);
+
+ if (!qctrl)
+ return -EINVAL;
+
+ switch (ctrl->id) {
+ case V4L2_CID_VFLIP:
+ if (ctrl->value)
+ data = reg_set(icd, MT9V022_READ_MODE, 0x10);
+ else
+ data = reg_clear(icd, MT9V022_READ_MODE, 0x10);
+ if (data < 0)
+ return -EIO;
+ break;
+ case V4L2_CID_HFLIP:
+ if (ctrl->value)
+ data = reg_set(icd, MT9V022_READ_MODE, 0x20);
+ else
+ data = reg_clear(icd, MT9V022_READ_MODE, 0x20);
+ if (data < 0)
+ return -EIO;
+ break;
+ case V4L2_CID_GAIN:
+ /* mt9v022 has minimum == default */
+ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+ return -EINVAL;
+ else {
+ unsigned long range = qctrl->maximum - qctrl->minimum;
+ /* Datasheet says 16 to 64. autogain only works properly
+ * after setting gain to maximum 14. Larger values
+ * produce "white fly" noise effect. On the whole,
+ * manually setting analog gain does no good. */
+ unsigned long gain = ((ctrl->value - qctrl->minimum) *
+ 10 + range / 2) / range + 4;
+ if (gain >= 32)
+ gain &= ~1;
+ /* The user wants to set gain manually, hope, she
+ * knows, what she's doing... Switch AGC off. */
+
+ if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2) < 0)
+ return -EIO;
+
+ dev_info(&icd->dev, "Setting gain from %d to %lu\n",
+ reg_read(icd, MT9V022_ANALOG_GAIN), gain);
+ if (reg_write(icd, MT9V022_ANALOG_GAIN, gain) < 0)
+ return -EIO;
+ icd->gain = ctrl->value;
+ }
+ break;
+ case V4L2_CID_EXPOSURE:
+ /* mt9v022 has maximum == default */
+ if (ctrl->value > qctrl->maximum || ctrl->value < qctrl->minimum)
+ return -EINVAL;
+ else {
+ unsigned long range = qctrl->maximum - qctrl->minimum;
+ unsigned long shutter = ((ctrl->value - qctrl->minimum) *
+ 479 + range / 2) / range + 1;
+ /* The user wants to set shutter width manually, hope,
+ * she knows, what she's doing... Switch AEC off. */
+
+ if (reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1) < 0)
+ return -EIO;
+
+ dev_dbg(&icd->dev, "Shutter width from %d to %lu\n",
+ reg_read(icd, MT9V022_TOTAL_SHUTTER_WIDTH),
+ shutter);
+ if (reg_write(icd, MT9V022_TOTAL_SHUTTER_WIDTH,
+ shutter) < 0)
+ return -EIO;
+ icd->exposure = ctrl->value;
+ }
+ break;
+ case V4L2_CID_AUTOGAIN:
+ if (ctrl->value)
+ data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x2);
+ else
+ data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x2);
+ if (data < 0)
+ return -EIO;
+ break;
+ case V4L2_CID_EXPOSURE_AUTO:
+ if (ctrl->value)
+ data = reg_set(icd, MT9V022_AEC_AGC_ENABLE, 0x1);
+ else
+ data = reg_clear(icd, MT9V022_AEC_AGC_ENABLE, 0x1);
+ if (data < 0)
+ return -EIO;
+ break;
+ }
+ return 0;
+}
+
+/* Interface active, can use i2c. If it fails, it can indeed mean, that
+ * this wasn't our capture interface, so, we wait for the right one */
+static int mt9v022_video_probe(struct soc_camera_device *icd)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+ s32 data;
+ int ret;
+
+ if (!icd->dev.parent ||
+ to_soc_camera_host(icd->dev.parent)->nr != icd->iface)
+ return -ENODEV;
+
+ /* Read out the chip version register */
+ data = reg_read(icd, MT9V022_CHIP_VERSION);
+
+ /* must be 0x1311 or 0x1313 */
+ if (data != 0x1311 && data != 0x1313) {
+ ret = -ENODEV;
+ dev_info(&icd->dev, "No MT9V022 detected, ID register 0x%x\n",
+ data);
+ goto ei2c;
+ }
+
+ /* Soft reset */
+ ret = reg_write(icd, MT9V022_RESET, 1);
+ if (ret < 0)
+ goto ei2c;
+ /* 15 clock cycles */
+ udelay(200);
+ if (reg_read(icd, MT9V022_RESET)) {
+ dev_err(&icd->dev, "Resetting MT9V022 failed!\n");
+ goto ei2c;
+ }
+
+ /* Set monochrome or colour sensor type */
+ if (sensor_type && (!strcmp("colour", sensor_type) ||
+ !strcmp("color", sensor_type))) {
+ ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 4 | 0x11);
+ mt9v022->model = V4L2_IDENT_MT9V022IX7ATC;
+ icd->formats = mt9v022_colour_formats;
+ if (mt9v022->client->dev.platform_data)
+ icd->num_formats = ARRAY_SIZE(mt9v022_colour_formats);
+ else
+ icd->num_formats = 1;
+ } else {
+ ret = reg_write(icd, MT9V022_PIXEL_OPERATION_MODE, 0x11);
+ mt9v022->model = V4L2_IDENT_MT9V022IX7ATM;
+ icd->formats = mt9v022_monochrome_formats;
+ if (mt9v022->client->dev.platform_data)
+ icd->num_formats = ARRAY_SIZE(mt9v022_monochrome_formats);
+ else
+ icd->num_formats = 1;
+ }
+
+ if (ret >= 0)
+ ret = soc_camera_video_start(icd);
+ if (ret < 0)
+ goto eisis;
+
+ dev_info(&icd->dev, "Detected a MT9V022 chip ID %x, %s sensor\n",
+ data, mt9v022->model == V4L2_IDENT_MT9V022IX7ATM ?
+ "monochrome" : "colour");
+
+ return 0;
+
+eisis:
+ei2c:
+ return ret;
+}
+
+static void mt9v022_video_remove(struct soc_camera_device *icd)
+{
+ struct mt9v022 *mt9v022 = container_of(icd, struct mt9v022, icd);
+
+ dev_dbg(&icd->dev, "Video %x removed: %p, %p\n", mt9v022->client->addr,
+ mt9v022->icd.dev.parent, mt9v022->icd.vdev);
+ soc_camera_video_stop(&mt9v022->icd);
+}
+
+static int mt9v022_probe(struct i2c_client *client)
+{
+ struct mt9v022 *mt9v022;
+ struct soc_camera_device *icd;
+ struct i2c_adapter *adapter = to_i2c_adapter(client->dev.parent);
+ struct soc_camera_link *icl = client->dev.platform_data;
+ int ret;
+
+ if (!icl) {
+ dev_err(&client->dev, "MT9V022 driver needs platform data\n");
+ return -EINVAL;
+ }
+
+ if (!i2c_check_functionality(adapter, I2C_FUNC_SMBUS_WORD_DATA)) {
+ dev_warn(&adapter->dev,
+ "I2C-Adapter doesn't support I2C_FUNC_SMBUS_WORD\n");
+ return -EIO;
+ }
+
+ mt9v022 = kzalloc(sizeof(struct mt9v022), GFP_KERNEL);
+ if (!mt9v022)
+ return -ENOMEM;
+
+ mt9v022->chip_control = MT9V022_CHIP_CONTROL_DEFAULT;
+ mt9v022->client = client;
+ i2c_set_clientdata(client, mt9v022);
+
+ icd = &mt9v022->icd;
+ icd->ops = &mt9v022_ops;
+ icd->control = &client->dev;
+ icd->x_min = 1;
+ icd->y_min = 4;
+ icd->x_current = 1;
+ icd->y_current = 4;
+ icd->width_min = 48;
+ icd->width_max = 752;
+ icd->height_min = 32;
+ icd->height_max = 480;
+ icd->y_skip_top = 1;
+ icd->iface = icl->bus_id;
+ /* Default datawidth - this is the only width this camera (normally)
+ * supports. It is only with extra logic that it can support
+ * other widths. Therefore it seems to be a sensible default. */
+ mt9v022->datawidth = 10;
+
+ ret = bus_switch_request(mt9v022, icl);
+ if (ret)
+ goto eswinit;
+
+ ret = soc_camera_device_register(icd);
+ if (ret)
+ goto eisdr;
+
+ return 0;
+
+eisdr:
+ bus_switch_release(mt9v022);
+eswinit:
+ kfree(mt9v022);
+ return ret;
+}
+
+static int mt9v022_remove(struct i2c_client *client)
+{
+ struct mt9v022 *mt9v022 = i2c_get_clientdata(client);
+
+ soc_camera_device_unregister(&mt9v022->icd);
+ bus_switch_release(mt9v022);
+ kfree(mt9v022);
+
+ return 0;
+}
+
+static struct i2c_driver mt9v022_i2c_driver = {
+ .driver = {
+ .name = "mt9v022",
+ },
+ .probe = mt9v022_probe,
+ .remove = mt9v022_remove,
+};
+
+static int __init mt9v022_mod_init(void)
+{
+ return i2c_add_driver(&mt9v022_i2c_driver);
+}
+
+static void __exit mt9v022_mod_exit(void)
+{
+ i2c_del_driver(&mt9v022_i2c_driver);
+}
+
+module_init(mt9v022_mod_init);
+module_exit(mt9v022_mod_exit);
+
+MODULE_DESCRIPTION("Micron MT9V022 Camera driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/mxb.c b/drivers/media/video/mxb.c
index cb5a510f9251..f68e91fbe7fb 100644
--- a/drivers/media/video/mxb.c
+++ b/drivers/media/video/mxb.c
@@ -38,7 +38,7 @@
#define MXB_BOARD_CAN_DO_VBI(dev) (dev->revision != 0)
/* global variable */
-static int mxb_num = 0;
+static int mxb_num;
/* initial frequence the tuner will be tuned to.
in verden (lower saxony, germany) 4148 is a
@@ -47,7 +47,7 @@ static int freq = 4148;
module_param(freq, int, 0644);
MODULE_PARM_DESC(freq, "initial frequency the tuner will be tuned to while setup");
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
diff --git a/drivers/media/video/ov511.c b/drivers/media/video/ov511.c
index d55d5800efb4..7e69e4393fe9 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -4660,7 +4660,9 @@ static const struct file_operations ov511_fops = {
.read = ov51x_v4l1_read,
.mmap = ov51x_v4l1_mmap,
.ioctl = ov51x_v4l1_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 6820c2aabd30..51b1461d8fb6 100644
--- a/drivers/media/video/pms.c
+++ b/drivers/media/video/pms.c
@@ -57,11 +57,11 @@ struct i2c_info
u8 hits;
};
-static int i2c_count = 0;
+static int i2c_count;
static struct i2c_info i2cinfo[64];
static int decoder = PHILIPS2;
-static int standard = 0; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
+static int standard; /* 0 - auto 1 - ntsc 2 - pal 3 - secam */
/*
* I/O ports and Shared Memory
@@ -885,7 +885,9 @@ static const struct file_operations pms_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = pms_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.read = pms_read,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index 9d94aed2e12d..d0e6430aef5a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -23,6 +23,7 @@
#include "pvrusb2-ioread.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
+#include <linux/kthread.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
@@ -31,32 +32,65 @@
static void pvr2_context_destroy(struct pvr2_context *mp)
{
- pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr_main id=%p",mp);
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (destroy)",mp);
if (mp->hdw) pvr2_hdw_destroy(mp->hdw);
kfree(mp);
}
-static void pvr2_context_state_check(struct pvr2_context *mp)
+static void pvr2_context_notify(struct pvr2_context *mp)
{
- if (mp->init_flag) return;
-
- switch (pvr2_hdw_get_state(mp->hdw)) {
- case PVR2_STATE_WARM: break;
- case PVR2_STATE_ERROR: break;
- case PVR2_STATE_READY: break;
- case PVR2_STATE_RUN: break;
- default: return;
+ mp->notify_flag = !0;
+ wake_up(&mp->wait_data);
+}
+
+
+static int pvr2_context_thread(void *_mp)
+{
+ struct pvr2_channel *ch1,*ch2;
+ struct pvr2_context *mp = _mp;
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread start)",mp);
+
+ /* Finish hardware initialization */
+ if (pvr2_hdw_initialize(mp->hdw,
+ (void (*)(void *))pvr2_context_notify,mp)) {
+ mp->video_stream.stream =
+ pvr2_hdw_get_video_stream(mp->hdw);
+ /* Trigger interface initialization. By doing this here
+ initialization runs in our own safe and cozy thread
+ context. */
+ if (mp->setup_func) mp->setup_func(mp);
+ } else {
+ pvr2_trace(PVR2_TRACE_CTXT,
+ "pvr2_context %p (thread skipping setup)",mp);
+ /* Even though initialization did not succeed, we're still
+ going to enter the wait loop anyway. We need to do this
+ in order to await the expected disconnect (which we will
+ detect in the normal course of operation). */
}
- pvr2_context_enter(mp); do {
- mp->init_flag = !0;
- mp->video_stream.stream = pvr2_hdw_get_video_stream(mp->hdw);
- if (mp->setup_func) {
- mp->setup_func(mp);
+ /* Now just issue callbacks whenever hardware state changes or if
+ there is a disconnect. If there is a disconnect and there are
+ no channels left, then there's no reason to stick around anymore
+ so we'll self-destruct - tearing down the rest of this driver
+ instance along the way. */
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread enter loop)",mp);
+ while (!mp->disconnect_flag || mp->mc_first) {
+ if (mp->notify_flag) {
+ mp->notify_flag = 0;
+ pvr2_trace(PVR2_TRACE_CTXT,
+ "pvr2_context %p (thread notify)",mp);
+ for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
+ ch2 = ch1->mc_next;
+ if (ch1->check_func) ch1->check_func(ch1);
+ }
}
- } while (0); pvr2_context_exit(mp);
- }
+ wait_event_interruptible(mp->wait_data, mp->notify_flag);
+ }
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (thread end)",mp);
+ pvr2_context_destroy(mp);
+ return 0;
+}
struct pvr2_context *pvr2_context_create(
@@ -64,10 +98,12 @@ struct pvr2_context *pvr2_context_create(
const struct usb_device_id *devid,
void (*setup_func)(struct pvr2_context *))
{
+ struct task_struct *thread;
struct pvr2_context *mp = NULL;
mp = kzalloc(sizeof(*mp),GFP_KERNEL);
if (!mp) goto done;
- pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_main id=%p",mp);
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context %p (create)",mp);
+ init_waitqueue_head(&mp->wait_data);
mp->setup_func = setup_func;
mutex_init(&mp->mutex);
mp->hdw = pvr2_hdw_create(intf,devid);
@@ -76,58 +112,45 @@ struct pvr2_context *pvr2_context_create(
mp = NULL;
goto done;
}
- pvr2_hdw_set_state_callback(mp->hdw,
- (void (*)(void *))pvr2_context_state_check,
- mp);
- pvr2_context_state_check(mp);
+ thread = kthread_run(pvr2_context_thread, mp, "pvrusb2-context");
+ if (!thread) {
+ pvr2_context_destroy(mp);
+ mp = NULL;
+ goto done;
+ }
done:
return mp;
}
-void pvr2_context_enter(struct pvr2_context *mp)
+static void pvr2_context_enter(struct pvr2_context *mp)
{
mutex_lock(&mp->mutex);
- pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_enter(id=%p)",mp);
}
-void pvr2_context_exit(struct pvr2_context *mp)
+static void pvr2_context_exit(struct pvr2_context *mp)
{
int destroy_flag = 0;
if (!(mp->mc_first || !mp->disconnect_flag)) {
destroy_flag = !0;
}
- pvr2_trace(PVR2_TRACE_CREG,"pvr2_context_exit(id=%p) outside",mp);
mutex_unlock(&mp->mutex);
- if (destroy_flag) pvr2_context_destroy(mp);
-}
-
-
-static void pvr2_context_run_checks(struct pvr2_context *mp)
-{
- struct pvr2_channel *ch1,*ch2;
- for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
- ch2 = ch1->mc_next;
- if (ch1->check_func) {
- ch1->check_func(ch1);
- }
- }
+ if (destroy_flag) pvr2_context_notify(mp);
}
void pvr2_context_disconnect(struct pvr2_context *mp)
{
- pvr2_context_enter(mp); do {
- pvr2_hdw_disconnect(mp->hdw);
- mp->disconnect_flag = !0;
- pvr2_context_run_checks(mp);
- } while (0); pvr2_context_exit(mp);
+ pvr2_hdw_disconnect(mp->hdw);
+ mp->disconnect_flag = !0;
+ pvr2_context_notify(mp);
}
void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
{
+ pvr2_context_enter(mp);
cp->hdw = mp->hdw;
cp->mc_head = mp;
cp->mc_next = NULL;
@@ -138,6 +161,7 @@ void pvr2_channel_init(struct pvr2_channel *cp,struct pvr2_context *mp)
mp->mc_first = cp;
}
mp->mc_last = cp;
+ pvr2_context_exit(mp);
}
@@ -153,6 +177,7 @@ static void pvr2_channel_disclaim_stream(struct pvr2_channel *cp)
void pvr2_channel_done(struct pvr2_channel *cp)
{
struct pvr2_context *mp = cp->mc_head;
+ pvr2_context_enter(mp);
pvr2_channel_disclaim_stream(cp);
if (cp->mc_next) {
cp->mc_next->mc_prev = cp->mc_prev;
@@ -165,6 +190,7 @@ void pvr2_channel_done(struct pvr2_channel *cp)
mp->mc_first = cp->mc_next;
}
cp->hdw = NULL;
+ pvr2_context_exit(mp);
}
@@ -174,7 +200,7 @@ int pvr2_channel_claim_stream(struct pvr2_channel *cp,
int code = 0;
pvr2_context_enter(cp->mc_head); do {
if (sp == cp->stream) break;
- if (sp->user) {
+ if (sp && sp->user) {
code = -EBUSY;
break;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.h b/drivers/media/video/pvrusb2/pvrusb2-context.h
index a04187a93225..127ec53e0913 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.h
@@ -30,7 +30,6 @@ struct pvr2_stream; /* stream interface - defined elsewhere */
struct pvr2_context; /* All central state */
struct pvr2_channel; /* One I/O pathway to a user */
struct pvr2_context_stream; /* Wrapper for a stream */
-struct pvr2_crit_reg; /* Critical region pointer */
struct pvr2_ioread; /* Low level stream structure */
struct pvr2_context_stream {
@@ -44,8 +43,10 @@ struct pvr2_context {
struct pvr2_hdw *hdw;
struct pvr2_context_stream video_stream;
struct mutex mutex;
+ int notify_flag;
int disconnect_flag;
- int init_flag;
+
+ wait_queue_head_t wait_data;
/* Called after pvr2_context initialization is complete */
void (*setup_func)(struct pvr2_context *);
@@ -61,9 +62,6 @@ struct pvr2_channel {
void (*check_func)(struct pvr2_channel *);
};
-void pvr2_context_enter(struct pvr2_context *);
-void pvr2_context_exit(struct pvr2_context *);
-
struct pvr2_context *pvr2_context_create(struct usb_interface *intf,
const struct usb_device_id *devid,
void (*setup_func)(struct pvr2_context *));
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 5a3e8d21a38a..91a42f2473a7 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -30,6 +30,9 @@ static int pvr2_ctrl_range_check(struct pvr2_ctrl *cptr,int val)
{
if (cptr->info->check_value) {
if (!cptr->info->check_value(cptr,val)) return -ERANGE;
+ } else if (cptr->info->type == pvr2_ctl_enum) {
+ if (val < 0) return -ERANGE;
+ if (val >= cptr->info->def.type_enum.count) return -ERANGE;
} else {
int lim;
lim = cptr->info->def.type_int.min_value;
@@ -63,13 +66,10 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
if (cptr->info->set_value) {
if (cptr->info->type == pvr2_ctl_bitmask) {
mask &= cptr->info->def.type_bitmask.valid_bits;
- } else if (cptr->info->type == pvr2_ctl_int) {
+ } else if ((cptr->info->type == pvr2_ctl_int)||
+ (cptr->info->type == pvr2_ctl_enum)) {
ret = pvr2_ctrl_range_check(cptr,val);
if (ret < 0) break;
- } else if (cptr->info->type == pvr2_ctl_enum) {
- if (val >= cptr->info->def.type_enum.count) {
- break;
- }
} else if (cptr->info->type != pvr2_ctl_bool) {
break;
}
@@ -204,8 +204,7 @@ int pvr2_ctrl_get_valname(struct pvr2_ctrl *cptr,int val,
if (cptr->info->type == pvr2_ctl_enum) {
const char **names;
names = cptr->info->def.type_enum.value_names;
- if ((val >= 0) &&
- (val < cptr->info->def.type_enum.count)) {
+ if (pvr2_ctrl_range_check(cptr,val) == 0) {
if (names[val]) {
*blen = scnprintf(
bptr,bmax,"%s",
@@ -528,10 +527,8 @@ int pvr2_ctrl_sym_to_value(struct pvr2_ctrl *cptr,
ptr,len,valptr,
cptr->info->def.type_enum.value_names,
cptr->info->def.type_enum.count);
- if ((ret >= 0) &&
- ((*valptr < 0) ||
- (*valptr >= cptr->info->def.type_enum.count))) {
- ret = -ERANGE;
+ if (ret >= 0) {
+ ret = pvr2_ctrl_range_check(cptr,*valptr);
}
if (maskptr) *maskptr = ~0;
} else if (cptr->info->type == pvr2_ctl_bitmask) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index fca49d8a9311..11537ddf8aa3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debug.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-debug.h
@@ -39,7 +39,7 @@ extern int pvrusb2_debug;
#define PVR2_TRACE_EEPROM (1 << 10) /* eeprom parsing / report */
#define PVR2_TRACE_STRUCT (1 << 11) /* internal struct creation */
#define PVR2_TRACE_OPEN_CLOSE (1 << 12) /* application open / close */
-#define PVR2_TRACE_CREG (1 << 13) /* Main critical region entry / exit */
+#define PVR2_TRACE_CTXT (1 << 13) /* Main context tracking */
#define PVR2_TRACE_SYSFS (1 << 14) /* Sysfs driven I/O */
#define PVR2_TRACE_FIRMWARE (1 << 15) /* firmware upload actions */
#define PVR2_TRACE_CHIPS (1 << 16) /* chip broadcast operation */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index fe9991c10cf4..c33ba35a4ddf 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -56,7 +56,12 @@ static const struct pvr2_device_desc pvr2_device_29xxx = {
.fx2_firmware.lst = pvr2_fw1_names_29xxx,
.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_29xxx),
.flag_has_hauppauge_rom = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_fmradio = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
};
@@ -85,7 +90,12 @@ static const struct pvr2_device_desc pvr2_device_24xxx = {
.flag_has_wm8775 = !0,
.flag_has_hauppauge_rom = !0,
.flag_has_hauppauge_custom_ir = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_fmradio = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
};
@@ -105,6 +115,29 @@ static const struct pvr2_device_desc pvr2_device_gotview_2 = {
.client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
.flag_has_cx25840 = !0,
.default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
+ .signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
+};
+
+
+
+/*------------------------------------------------------------------------*/
+/* GOTVIEW USB2.0 DVD Deluxe */
+
+/* (same module list as gotview_2) */
+
+static const struct pvr2_device_desc pvr2_device_gotview_2d = {
+ .description = "Gotview USB 2.0 DVD Deluxe",
+ .shortname = "gv2d",
+ .client_modules.lst = pvr2_client_gotview_2,
+ .client_modules.cnt = ARRAY_SIZE(pvr2_client_gotview_2),
+ .flag_has_cx25840 = !0,
+ .default_tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_GOTVIEW,
};
@@ -126,7 +159,12 @@ static const struct pvr2_device_desc pvr2_device_onair_creator = {
.client_modules.lst = pvr2_client_onair_creator,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_creator),
.default_tuner_type = TUNER_LG_TDVS_H06XF,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+ .default_std_mask = V4L2_STD_NTSC_M,
};
#endif
@@ -147,8 +185,13 @@ static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
.shortname = "oa2",
.client_modules.lst = pvr2_client_onair_usb2,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_onair_usb2),
- .default_tuner_type = TUNER_PHILIPS_ATSC,
+ .default_tuner_type = TUNER_PHILIPS_FCV1236D,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+ .default_std_mask = V4L2_STD_NTSC_M,
};
#endif
@@ -210,8 +253,13 @@ static const struct pvr2_device_desc pvr2_device_75xxx = {
.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_75xxx),
.flag_has_cx25840 = !0,
.flag_has_hauppauge_rom = !0,
+ .flag_has_analogtuner = !0,
+ .flag_has_composite = !0,
+ .flag_has_svideo = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_HAUPPAUGE,
.default_std_mask = V4L2_STD_NTSC_M,
+ .led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
};
@@ -225,6 +273,8 @@ struct usb_device_id pvr2_device_table[] = {
.driver_info = (kernel_ulong_t)&pvr2_device_24xxx},
{ USB_DEVICE(0x1164, 0x0622),
.driver_info = (kernel_ulong_t)&pvr2_device_gotview_2},
+ { USB_DEVICE(0x1164, 0x0602),
+ .driver_info = (kernel_ulong_t)&pvr2_device_gotview_2d},
#ifdef CONFIG_VIDEO_PVRUSB2_ONAIR_CREATOR
{ USB_DEVICE(0x11ba, 0x1003),
.driver_info = (kernel_ulong_t)&pvr2_device_onair_creator},
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index 64b467f0637f..fb5f5d17e8cb 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -39,6 +39,13 @@ struct pvr2_string_table {
#define PVR2_ROUTING_SCHEME_HAUPPAUGE 0
#define PVR2_ROUTING_SCHEME_GOTVIEW 1
+#define PVR2_DIGITAL_SCHEME_NONE 0
+#define PVR2_DIGITAL_SCHEME_HAUPPAUGE 1
+#define PVR2_DIGITAL_SCHEME_ONAIR 2
+
+#define PVR2_LED_SCHEME_NONE 0
+#define PVR2_LED_SCHEME_HAUPPAUGE 1
+
/* This describes a particular hardware type (except for the USB device ID
which must live in a separate structure due to environmental
constraints). See the top of pvrusb2-hdw.c for where this is
@@ -58,40 +65,52 @@ struct pvr2_device_desc {
was initialized from internal ROM. */
struct pvr2_string_table fx2_firmware;
+ /* Initial standard bits to use for this device, if not zero.
+ Anything set here is also implied as an available standard.
+ Note: This is ignored if overridden on the module load line via
+ the video_std module option. */
+ v4l2_std_id default_std_mask;
+
+ /* V4L tuner type ID to use with this device (only used if the
+ driver could not discover the type any other way). */
+ int default_tuner_type;
+
/* Signal routing scheme used by device, contains one of
PVR2_ROUTING_SCHEME_XXX. Schemes have to be defined as we
encounter them. This is an arbitrary integer scheme id; its
meaning is contained entirely within the driver and is
interpreted by logic which must send commands to the chip-level
drivers (search for things which touch this field). */
- unsigned int signal_routing_scheme;
+ unsigned char signal_routing_scheme;
- /* V4L tuner type ID to use with this device (only used if the
- driver could not discover the type any other way). */
- int default_tuner_type;
+ /* Indicates scheme for controlling device's LED (if any). The
+ driver will turn on the LED when streaming is underway. This
+ contains one of PVR2_LED_SCHEME_XXX. */
+ unsigned char led_scheme;
- /* Initial standard bits to use for this device, if not zero.
- Anything set here is also implied as an available standard.
- Note: This is ignored if overridden on the module load line via
- the video_std module option. */
- v4l2_std_id default_std_mask;
+ /* Control scheme to use if there is a digital tuner. This
+ contains one of PVR2_DIGITAL_SCHEME_XXX. This is an arbitrary
+ integer scheme id; its meaning is contained entirely within the
+ driver and is interpreted by logic which must control the
+ streaming pathway (search for things which touch this field). */
+ unsigned char digital_control_scheme;
/* If set, we don't bother trying to load cx23416 firmware. */
- char flag_skip_cx23416_firmware;
+ int flag_skip_cx23416_firmware:1;
/* Device has a hauppauge eeprom which we can interrogate. */
- char flag_has_hauppauge_rom;
+ int flag_has_hauppauge_rom:1;
/* Device does not require a powerup command to be issued. */
- char flag_no_powerup;
+ int flag_no_powerup:1;
/* Device has a cx25840 - this enables special additional logic to
handle it. */
- char flag_has_cx25840;
+ int flag_has_cx25840:1;
/* Device has a wm8775 - this enables special additional logic to
ensure that it is found. */
- char flag_has_wm8775;
+ int flag_has_wm8775:1;
/* Device has IR hardware that can be faked into looking like a
normal Hauppauge i2c IR receiver. This is currently very
@@ -101,7 +120,15 @@ struct pvr2_device_desc {
to virtualize the presence of the non-existant IR receiver chip and
implement the virtual receiver in terms of appropriate FX2
commands. */
- char flag_has_hauppauge_custom_ir;
+ int flag_has_hauppauge_custom_ir:1;
+
+ /* These bits define which kinds of sources the device can handle.
+ Note: Digital tuner presence is inferred by the
+ digital_control_scheme enumeration. */
+ int flag_has_fmradio:1; /* Has FM radio receiver */
+ int flag_has_analogtuner:1; /* Has analog tuner */
+ int flag_has_composite:1; /* Has composite input */
+ int flag_has_svideo:1; /* Has s-video input */
};
extern struct usb_device_id pvr2_device_table[];
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 64062879981e..324d1bd8500d 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -480,10 +480,6 @@ int pvr2_encoder_start(struct pvr2_hdw *hdw)
/* unmask some interrupts */
pvr2_write_register(hdw, 0x0048, 0xbfffffff);
- /* change some GPIO data */
- pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000481);
- pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
-
pvr2_encoder_vcmd(hdw,CX2341X_ENC_MUTE_VIDEO,1,
hdw->input_val == PVR2_CVAL_INPUT_RADIO ? 1 : 0);
@@ -526,12 +522,6 @@ int pvr2_encoder_stop(struct pvr2_hdw *hdw)
break;
}
- /* change some GPIO data */
- /* Note: Bit d7 of dir appears to control the LED. So we shut it
- off here. */
- pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000401);
- pvr2_hdw_gpio_chg_out(hdw,0xffffffff,0x00000000);
-
return status;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
index ffbc6d096108..a866c949243c 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
@@ -49,6 +49,15 @@
#define FX2CMD_GET_EEPROM_ADDR 0xeb
#define FX2CMD_GET_IR_CODE 0xec
+#define FX2CMD_HCW_DEMOD_RESETIN 0xf0
+#define FX2CMD_HCW_DTV_STREAMING_ON 0xf1
+#define FX2CMD_HCW_DTV_STREAMING_OFF 0xf2
+
+#define FX2CMD_ONAIR_DTV_STREAMING_ON 0xa0
+#define FX2CMD_ONAIR_DTV_STREAMING_OFF 0xa1
+#define FX2CMD_ONAIR_DTV_POWER_ON 0xa2
+#define FX2CMD_ONAIR_DTV_POWER_OFF 0xa3
+
#endif /* _PVRUSB2_FX2_CMD_H_ */
/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
index d7a216b41b72..c725495826ce 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h
@@ -163,6 +163,11 @@ struct pvr2_decoder_ctrl {
#define FW1_STATE_RELOAD 3
#define FW1_STATE_OK 4
+/* What state the device is in if it is a hybrid */
+#define PVR2_PATHWAY_UNKNOWN 0
+#define PVR2_PATHWAY_ANALOG 1
+#define PVR2_PATHWAY_DIGITAL 2
+
typedef int (*pvr2_i2c_func)(struct pvr2_hdw *,u8,u8 *,u16,u8 *, u16);
#define PVR2_I2C_FUNC_CNT 128
@@ -182,7 +187,6 @@ struct pvr2_hdw {
struct workqueue_struct *workqueue;
struct work_struct workpoll; /* Update driver state */
struct work_struct worki2csync; /* Update i2c clients */
- struct work_struct workinit; /* Driver initialization sequence */
/* Video spigot */
struct pvr2_stream *vid_stream;
@@ -229,6 +233,7 @@ struct pvr2_hdw {
/* Bits of state that describe what is going on with various parts
of the driver. */
+ int state_pathway_ok; /* Pathway config is ok */
int state_encoder_ok; /* Encoder is operational */
int state_encoder_run; /* Encoder is running */
int state_encoder_config; /* Encoder is configured */
@@ -237,9 +242,9 @@ struct pvr2_hdw {
int state_usbstream_run; /* FX2 is streaming */
int state_decoder_quiescent; /* Decoder idle for > 50msec */
int state_pipeline_config; /* Pipeline is configured */
- int state_pipeline_req; /* Somebody wants to stream */
- int state_pipeline_pause; /* Pipeline must be paused */
- int state_pipeline_idle; /* Pipeline not running */
+ int state_pipeline_req; /* Somebody wants to stream */
+ int state_pipeline_pause; /* Pipeline must be paused */
+ int state_pipeline_idle; /* Pipeline not running */
/* This is the master state of the driver. It is the combined
result of other bits of state. Examining this will indicate the
@@ -247,6 +252,9 @@ struct pvr2_hdw {
PVR2_STATE_xxxx */
unsigned int master_state;
+ /* True if device led is currently on */
+ int led_on;
+
/* True if states must be re-evaluated */
int state_stale;
@@ -267,6 +275,7 @@ struct pvr2_hdw {
int flag_disconnected; /* flag_ok == 0 due to disconnect */
int flag_init_ok; /* true if structure is fully initialized */
int fw1_state; /* current situation with fw1 */
+ int pathway_state; /* one of PVR2_PATHWAY_xxx */
int flag_decoder_missed;/* We've noticed missing decoder */
int flag_tripped; /* Indicates overall failure to start */
@@ -323,6 +332,9 @@ struct pvr2_hdw {
int v4l_minor_number_vbi;
int v4l_minor_number_radio;
+ /* Bit mask of PVR2_CVAL_INPUT choices which are valid */
+ unsigned int input_avail_mask;
+
/* Location of eeprom or a negative number if none */
int eeprom_addr;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index d6955fa39598..7be32cc1d146 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -44,13 +44,13 @@
static struct pvr2_hdw *unit_pointers[PVR_NUM] = {[ 0 ... PVR_NUM-1 ] = NULL};
static DEFINE_MUTEX(pvr2_unit_mtx);
-static int ctlchg = 0;
+static int ctlchg;
static int initusbreset = 1;
-static int procreload = 0;
+static int procreload;
static int tuner[PVR_NUM] = { [0 ... PVR_NUM-1] = -1 };
static int tolerance[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
static int video_std[PVR_NUM] = { [0 ... PVR_NUM-1] = 0 };
-static int init_pause_msec = 0;
+static int init_pause_msec;
module_param(ctlchg, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(ctlchg, "0=optimize ctl change 1=always accept new ctl value");
@@ -183,6 +183,7 @@ static const char *control_values_srate[] = {
static const char *control_values_input[] = {
[PVR2_CVAL_INPUT_TV] = "television", /*xawtv needs this name*/
+ [PVR2_CVAL_INPUT_DTV] = "dtv",
[PVR2_CVAL_INPUT_RADIO] = "radio",
[PVR2_CVAL_INPUT_SVIDEO] = "s-video",
[PVR2_CVAL_INPUT_COMPOSITE] = "composite",
@@ -221,7 +222,6 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *);
static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *,unsigned long);
static void pvr2_hdw_worker_i2c(struct work_struct *work);
static void pvr2_hdw_worker_poll(struct work_struct *work);
-static void pvr2_hdw_worker_init(struct work_struct *work);
static int pvr2_hdw_wait(struct pvr2_hdw *,int state);
static int pvr2_hdw_untrip_unlocked(struct pvr2_hdw *);
static void pvr2_hdw_state_log_state(struct pvr2_hdw *);
@@ -368,6 +368,11 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
return 0;
}
+static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
+{
+ return ((1 << v) & cptr->hdw->input_avail_mask) != 0;
+}
+
static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
{
struct pvr2_hdw *hdw = cptr->hdw;
@@ -383,7 +388,8 @@ static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
hdw->freqSelector = 0;
hdw->freqDirty = !0;
- } else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
+ } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) ||
+ (hdw->input_val == PVR2_CVAL_INPUT_DTV)) {
hdw->freqSelector = 1;
hdw->freqDirty = !0;
}
@@ -804,6 +810,7 @@ static const struct pvr2_ctl_info control_defs[] = {
.name = "input",
.internal_id = PVR2_CID_INPUT,
.default_value = PVR2_CVAL_INPUT_TV,
+ .check_value = ctrl_check_input,
DEFREF(input),
DEFENUM(control_values_input),
},{
@@ -1496,7 +1503,7 @@ struct pvr2_std_hack {
default - which can always be overridden explicitly - and if the user
has otherwise named a default then that default will always be used in
place of this table. */
-const static struct pvr2_std_hack std_eeprom_maps[] = {
+static const struct pvr2_std_hack std_eeprom_maps[] = {
{ /* PAL(B/G) */
.pat = V4L2_STD_B|V4L2_STD_GH,
.std = V4L2_STD_PAL_B|V4L2_STD_PAL_B1|V4L2_STD_PAL_G,
@@ -1806,12 +1813,28 @@ static void pvr2_hdw_setup(struct pvr2_hdw *hdw)
}
-/* Create and return a structure for interacting with the underlying
- hardware */
+/* Perform second stage initialization. Set callback pointer first so that
+ we can avoid a possible initialization race (if the kernel thread runs
+ before the callback has been set). */
+int pvr2_hdw_initialize(struct pvr2_hdw *hdw,
+ void (*callback_func)(void *),
+ void *callback_data)
+{
+ LOCK_TAKE(hdw->big_lock); do {
+ hdw->state_data = callback_data;
+ hdw->state_func = callback_func;
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ pvr2_hdw_setup(hdw);
+ return hdw->flag_init_ok;
+}
+
+
+/* Create, set up, and return a structure for interacting with the
+ underlying hardware. */
struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
const struct usb_device_id *devid)
{
- unsigned int idx,cnt1,cnt2;
+ unsigned int idx,cnt1,cnt2,m;
struct pvr2_hdw *hdw;
int valid_std_mask;
struct pvr2_ctrl *cptr;
@@ -1842,6 +1865,25 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->tuner_signal_stale = !0;
cx2341x_fill_defaults(&hdw->enc_ctl_state);
+ /* Calculate which inputs are OK */
+ m = 0;
+ if (hdw_desc->flag_has_analogtuner) m |= 1 << PVR2_CVAL_INPUT_TV;
+ if (hdw_desc->digital_control_scheme != PVR2_DIGITAL_SCHEME_NONE) {
+ m |= 1 << PVR2_CVAL_INPUT_DTV;
+ }
+ if (hdw_desc->flag_has_svideo) m |= 1 << PVR2_CVAL_INPUT_SVIDEO;
+ if (hdw_desc->flag_has_composite) m |= 1 << PVR2_CVAL_INPUT_COMPOSITE;
+ if (hdw_desc->flag_has_fmradio) m |= 1 << PVR2_CVAL_INPUT_RADIO;
+ hdw->input_avail_mask = m;
+
+ /* If not a hybrid device, pathway_state never changes. So
+ initialize it here to what it should forever be. */
+ if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_DTV))) {
+ hdw->pathway_state = PVR2_PATHWAY_ANALOG;
+ } else if (!(hdw->input_avail_mask & (1 << PVR2_CVAL_INPUT_TV))) {
+ hdw->pathway_state = PVR2_PATHWAY_DIGITAL;
+ }
+
hdw->control_cnt = CTRLDEF_COUNT;
hdw->control_cnt += MPEGDEF_COUNT;
hdw->controls = kzalloc(sizeof(struct pvr2_ctrl) * hdw->control_cnt,
@@ -1859,6 +1901,15 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
cptr = hdw->controls + idx;
cptr->info = control_defs+idx;
}
+
+ /* Ensure that default input choice is a valid one. */
+ m = hdw->input_avail_mask;
+ if (m) for (idx = 0; idx < (sizeof(m) << 3); idx++) {
+ if (!((1 << idx) & m)) continue;
+ hdw->input_val = idx;
+ break;
+ }
+
/* Define and configure additional controls from cx2341x module. */
hdw->mpeg_ctrl_info = kzalloc(
sizeof(*(hdw->mpeg_ctrl_info)) * MPEGDEF_COUNT, GFP_KERNEL);
@@ -1982,7 +2033,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->workqueue = create_singlethread_workqueue(hdw->name);
INIT_WORK(&hdw->workpoll,pvr2_hdw_worker_poll);
INIT_WORK(&hdw->worki2csync,pvr2_hdw_worker_i2c);
- INIT_WORK(&hdw->workinit,pvr2_hdw_worker_init);
pvr2_trace(PVR2_TRACE_INIT,"Driver unit number is %d, name is %s",
hdw->unit_number,hdw->name);
@@ -2004,7 +2054,6 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
mutex_init(&hdw->ctl_lock_mutex);
mutex_init(&hdw->big_lock_mutex);
- queue_work(hdw->workqueue,&hdw->workinit);
return hdw;
fail:
if (hdw) {
@@ -2065,13 +2114,13 @@ void pvr2_hdw_destroy(struct pvr2_hdw *hdw)
{
if (!hdw) return;
pvr2_trace(PVR2_TRACE_INIT,"pvr2_hdw_destroy: hdw=%p",hdw);
- del_timer_sync(&hdw->quiescent_timer);
- del_timer_sync(&hdw->encoder_wait_timer);
if (hdw->workqueue) {
flush_workqueue(hdw->workqueue);
destroy_workqueue(hdw->workqueue);
hdw->workqueue = NULL;
}
+ del_timer_sync(&hdw->quiescent_timer);
+ del_timer_sync(&hdw->encoder_wait_timer);
if (hdw->fw_buffer) {
kfree(hdw->fw_buffer);
hdw->fw_buffer = NULL;
@@ -2353,6 +2402,18 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
}
}
+ if (hdw->input_dirty &&
+ (((hdw->input_val == PVR2_CVAL_INPUT_DTV) ?
+ PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG) !=
+ hdw->pathway_state)) {
+ /* Change of mode being asked for... */
+ hdw->state_pathway_ok = 0;
+ trace_stbit("state_pathway_ok",hdw->state_pathway_ok);
+ }
+ if (!hdw->state_pathway_ok) {
+ /* Can't commit anything until pathway is ok. */
+ return 0;
+ }
/* If any of the below has changed, then we can't do the update
while the pipeline is running. Pipeline must be paused first
and decoder -> encoder connection be made quiescent before we
@@ -2409,9 +2470,11 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
/* Now execute i2c core update */
pvr2_i2c_core_sync(hdw);
- if (hdw->state_encoder_run) {
- /* If encoder isn't running, then this will get worked out
- later when we start the encoder. */
+ if ((hdw->pathway_state == PVR2_PATHWAY_ANALOG) &&
+ hdw->state_encoder_run) {
+ /* If encoder isn't running or it can't be touched, then
+ this will get worked out later when we start the
+ encoder. */
if (pvr2_encoder_adjust(hdw) < 0) return !0;
}
@@ -2454,15 +2517,6 @@ static void pvr2_hdw_worker_poll(struct work_struct *work)
}
-static void pvr2_hdw_worker_init(struct work_struct *work)
-{
- struct pvr2_hdw *hdw = container_of(work,struct pvr2_hdw,workinit);
- LOCK_TAKE(hdw->big_lock); do {
- pvr2_hdw_setup(hdw);
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
{
return wait_event_interruptible(
@@ -2472,17 +2526,6 @@ static int pvr2_hdw_wait(struct pvr2_hdw *hdw,int state)
}
-void pvr2_hdw_set_state_callback(struct pvr2_hdw *hdw,
- void (*callback_func)(void *),
- void *callback_data)
-{
- LOCK_TAKE(hdw->big_lock); do {
- hdw->state_data = callback_data;
- hdw->state_func = callback_func;
- } while (0); LOCK_GIVE(hdw->big_lock);
-}
-
-
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *hdw)
{
@@ -3168,17 +3211,32 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
}
-int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
+static int pvr2_hdw_cmd_power_ctrl(struct pvr2_hdw *hdw, int onoff)
{
int status;
LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,"Requesting powerup");
- hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
- status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
+ if (onoff) {
+ pvr2_trace(PVR2_TRACE_INIT, "Requesting powerup");
+ hdw->cmd_buffer[0] = FX2CMD_POWER_ON;
+ } else {
+ pvr2_trace(PVR2_TRACE_INIT, "Requesting powerdown");
+ hdw->cmd_buffer[0] = FX2CMD_POWER_OFF;
+ }
+ status = pvr2_send_request(hdw, hdw->cmd_buffer, 1, NULL, 0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
}
+int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
+{
+ return pvr2_hdw_cmd_power_ctrl(hdw, 1);
+}
+
+int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
+{
+ return pvr2_hdw_cmd_power_ctrl(hdw, 0);
+}
+
int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
{
@@ -3201,19 +3259,185 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
}
-/* Stop / start video stream transport */
-static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
+static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
+{
+ int status;
+
+ LOCK_TAKE(hdw->ctl_lock); do {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Issuing fe demod wake command (%s)",
+ (onoff ? "on" : "off"));
+ hdw->flag_ok = !0;
+ hdw->cmd_buffer[0] = FX2CMD_HCW_DEMOD_RESETIN;
+ hdw->cmd_buffer[1] = onoff;
+ status = pvr2_send_request(hdw, hdw->cmd_buffer, 2, NULL, 0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
+
+ return status;
+}
+
+
+static int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff)
{
int status;
+
LOCK_TAKE(hdw->ctl_lock); do {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Issuing fe power command to CPLD (%s)",
+ (onoff ? "on" : "off"));
+ hdw->flag_ok = !0;
hdw->cmd_buffer[0] =
- (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
+ (onoff ? FX2CMD_ONAIR_DTV_POWER_ON :
+ FX2CMD_ONAIR_DTV_POWER_OFF);
+ status = pvr2_send_request(hdw, hdw->cmd_buffer, 1, NULL, 0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
+
+ return status;
+}
+
+
+static int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw,
+ int onoff)
+{
+ int status;
+ LOCK_TAKE(hdw->ctl_lock); do {
+ pvr2_trace(PVR2_TRACE_INIT,
+ "Issuing onair digital setup command (%s)",
+ (onoff ? "on" : "off"));
+ hdw->cmd_buffer[0] =
+ (onoff ? FX2CMD_ONAIR_DTV_STREAMING_ON :
+ FX2CMD_ONAIR_DTV_STREAMING_OFF);
+ status = pvr2_send_request(hdw, hdw->cmd_buffer, 1, NULL, 0);
+ } while (0); LOCK_GIVE(hdw->ctl_lock);
+ return status;
+}
+
+
+static void pvr2_hdw_cmd_modeswitch(struct pvr2_hdw *hdw,int digitalFl)
+{
+ int cmode;
+ /* Compare digital/analog desired setting with current setting. If
+ they don't match, fix it... */
+ cmode = (digitalFl ? PVR2_PATHWAY_DIGITAL : PVR2_PATHWAY_ANALOG);
+ if (cmode == hdw->pathway_state) {
+ /* They match; nothing to do */
+ return;
+ }
+
+ switch (hdw->hdw_desc->digital_control_scheme) {
+ case PVR2_DIGITAL_SCHEME_HAUPPAUGE:
+ pvr2_hdw_cmd_hcw_demod_reset(hdw,digitalFl);
+ if (cmode == PVR2_PATHWAY_ANALOG) {
+ /* If moving to analog mode, also force the decoder
+ to reset. If no decoder is attached, then it's
+ ok to ignore this because if/when the decoder
+ attaches, it will reset itself at that time. */
+ pvr2_hdw_cmd_decoder_reset(hdw);
+ }
+ break;
+ case PVR2_DIGITAL_SCHEME_ONAIR:
+ /* Supposedly we should always have the power on whether in
+ digital or analog mode. But for now do what appears to
+ work... */
+ if (digitalFl) pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,!0);
+ pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,digitalFl);
+ if (!digitalFl) pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,0);
+ break;
+ default: break;
+ }
+
+ pvr2_hdw_untrip_unlocked(hdw);
+ hdw->pathway_state = cmode;
+}
+
+
+void pvr2_led_ctrl_hauppauge(struct pvr2_hdw *hdw, int onoff)
+{
+ /* change some GPIO data
+ *
+ * note: bit d7 of dir appears to control the LED,
+ * so we shut it off here.
+ *
+ */
+ if (onoff) {
+ pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000481);
+ } else {
+ pvr2_hdw_gpio_chg_dir(hdw, 0xffffffff, 0x00000401);
+ }
+ pvr2_hdw_gpio_chg_out(hdw, 0xffffffff, 0x00000000);
+}
+
+
+typedef void (*led_method_func)(struct pvr2_hdw *,int);
+
+static led_method_func led_methods[] = {
+ [PVR2_LED_SCHEME_HAUPPAUGE] = pvr2_led_ctrl_hauppauge,
+};
+
+
+/* Toggle LED */
+static void pvr2_led_ctrl(struct pvr2_hdw *hdw,int onoff)
+{
+ unsigned int scheme_id;
+ led_method_func fp;
+
+ if ((!onoff) == (!hdw->led_on)) return;
+
+ hdw->led_on = onoff != 0;
+
+ scheme_id = hdw->hdw_desc->led_scheme;
+ if (scheme_id < ARRAY_SIZE(led_methods)) {
+ fp = led_methods[scheme_id];
+ } else {
+ fp = NULL;
+ }
+
+ if (fp) (*fp)(hdw,onoff);
+}
+
+
+/* Stop / start video stream transport */
+static int pvr2_hdw_cmd_usbstream(struct pvr2_hdw *hdw,int runFl)
+{
+ int status,cc;
+ if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+ hdw->hdw_desc->digital_control_scheme ==
+ PVR2_DIGITAL_SCHEME_HAUPPAUGE) {
+ cc = (runFl ?
+ FX2CMD_HCW_DTV_STREAMING_ON :
+ FX2CMD_HCW_DTV_STREAMING_OFF);
+ } else {
+ cc = (runFl ?
+ FX2CMD_STREAMING_ON :
+ FX2CMD_STREAMING_OFF);
+ }
+
+ LOCK_TAKE(hdw->ctl_lock); do {
+ hdw->cmd_buffer[0] = cc;
status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
} while (0); LOCK_GIVE(hdw->ctl_lock);
return status;
}
+/* Evaluate whether or not state_pathway_ok can change */
+static int state_eval_pathway_ok(struct pvr2_hdw *hdw)
+{
+ if (hdw->state_pathway_ok) {
+ /* Nothing to do if pathway is already ok */
+ return 0;
+ }
+ if (!hdw->state_pipeline_idle) {
+ /* Not allowed to change anything if pipeline is not idle */
+ return 0;
+ }
+ pvr2_hdw_cmd_modeswitch(hdw,hdw->input_val == PVR2_CVAL_INPUT_DTV);
+ hdw->state_pathway_ok = !0;
+ trace_stbit("state_pathway_ok",hdw->state_pathway_ok);
+ return !0;
+}
+
+
/* Evaluate whether or not state_encoder_ok can change */
static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
{
@@ -3223,6 +3447,7 @@ static int state_eval_encoder_ok(struct pvr2_hdw *hdw)
if (hdw->state_encoder_config) return 0;
if (hdw->state_decoder_run) return 0;
if (hdw->state_usbstream_run) return 0;
+ if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) return 0;
if (pvr2_upload_firmware2(hdw) < 0) {
hdw->flag_tripped = !0;
trace_stbit("flag_tripped",hdw->flag_tripped);
@@ -3248,7 +3473,9 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw)
/* paranoia - solve race if timer just completed */
del_timer_sync(&hdw->encoder_wait_timer);
} else {
- if (!hdw->state_encoder_ok ||
+ if (!hdw->state_pathway_ok ||
+ (hdw->pathway_state != PVR2_PATHWAY_ANALOG) ||
+ !hdw->state_encoder_ok ||
!hdw->state_pipeline_idle ||
hdw->state_pipeline_pause ||
!hdw->state_pipeline_req ||
@@ -3302,13 +3529,16 @@ static int state_eval_encoder_run(struct pvr2_hdw *hdw)
{
if (hdw->state_encoder_run) {
if (hdw->state_encoder_ok) {
- if (hdw->state_decoder_run) return 0;
+ if (hdw->state_decoder_run &&
+ hdw->state_pathway_ok) return 0;
if (pvr2_encoder_stop(hdw) < 0) return !0;
}
hdw->state_encoder_run = 0;
} else {
if (!hdw->state_encoder_ok) return 0;
if (!hdw->state_decoder_run) return 0;
+ if (!hdw->state_pathway_ok) return 0;
+ if (hdw->pathway_state != PVR2_PATHWAY_ANALOG) return 0;
if (pvr2_encoder_start(hdw) < 0) return !0;
hdw->state_encoder_run = !0;
}
@@ -3345,7 +3575,8 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
if (hdw->state_decoder_run) {
if (hdw->state_encoder_ok) {
if (hdw->state_pipeline_req &&
- !hdw->state_pipeline_pause) return 0;
+ !hdw->state_pipeline_pause &&
+ hdw->state_pathway_ok) return 0;
}
if (!hdw->flag_decoder_missed) {
pvr2_decoder_enable(hdw,0);
@@ -3378,7 +3609,9 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
hopefully further stabilize the encoder. */
return 0;
}
- if (!hdw->state_pipeline_req ||
+ if (!hdw->state_pathway_ok ||
+ (hdw->pathway_state != PVR2_PATHWAY_ANALOG) ||
+ !hdw->state_pipeline_req ||
hdw->state_pipeline_pause ||
!hdw->state_pipeline_config ||
!hdw->state_encoder_config ||
@@ -3399,16 +3632,25 @@ static int state_eval_decoder_run(struct pvr2_hdw *hdw)
static int state_eval_usbstream_run(struct pvr2_hdw *hdw)
{
if (hdw->state_usbstream_run) {
- if (hdw->state_encoder_ok) {
- if (hdw->state_encoder_run) return 0;
+ if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+ if (hdw->state_encoder_ok &&
+ hdw->state_encoder_run &&
+ hdw->state_pathway_ok) return 0;
+ } else {
+ if (hdw->state_pipeline_req &&
+ !hdw->state_pipeline_pause &&
+ hdw->state_pathway_ok) return 0;
}
pvr2_hdw_cmd_usbstream(hdw,0);
hdw->state_usbstream_run = 0;
} else {
- if (!hdw->state_encoder_ok ||
- !hdw->state_encoder_run ||
- !hdw->state_pipeline_req ||
- hdw->state_pipeline_pause) return 0;
+ if (!hdw->state_pipeline_req ||
+ hdw->state_pipeline_pause ||
+ !hdw->state_pathway_ok) return 0;
+ if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+ if (!hdw->state_encoder_ok ||
+ !hdw->state_encoder_run) return 0;
+ }
if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
hdw->state_usbstream_run = !0;
}
@@ -3454,7 +3696,8 @@ static int state_update_pipeline_state(struct pvr2_hdw *hdw)
typedef int (*state_eval_func)(struct pvr2_hdw *);
/* Set of functions to be run to evaluate various states in the driver. */
-const static state_eval_func eval_funcs[] = {
+static const state_eval_func eval_funcs[] = {
+ state_eval_pathway_ok,
state_eval_pipeline_config,
state_eval_encoder_ok,
state_eval_encoder_config,
@@ -3502,6 +3745,16 @@ static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
}
+static const char *pvr2_pathway_state_name(int id)
+{
+ switch (id) {
+ case PVR2_PATHWAY_ANALOG: return "analog";
+ case PVR2_PATHWAY_DIGITAL: return "digital";
+ default: return "unknown";
+ }
+}
+
+
static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
char *buf,unsigned int acnt)
{
@@ -3509,13 +3762,15 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
case 0:
return scnprintf(
buf,acnt,
- "driver:%s%s%s%s%s",
+ "driver:%s%s%s%s%s <mode=%s>",
(hdw->flag_ok ? " <ok>" : " <fail>"),
(hdw->flag_init_ok ? " <init>" : " <uninitialized>"),
(hdw->flag_disconnected ? " <disconnected>" :
" <connected>"),
(hdw->flag_tripped ? " <tripped>" : ""),
- (hdw->flag_decoder_missed ? " <no decoder>" : ""));
+ (hdw->flag_decoder_missed ? " <no decoder>" : ""),
+ pvr2_pathway_state_name(hdw->pathway_state));
+
case 1:
return scnprintf(
buf,acnt,
@@ -3528,7 +3783,7 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
case 2:
return scnprintf(
buf,acnt,
- "worker:%s%s%s%s%s%s",
+ "worker:%s%s%s%s%s%s%s",
(hdw->state_decoder_run ?
" <decode:run>" :
(hdw->state_decoder_quiescent ?
@@ -3544,7 +3799,9 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
(hdw->state_encoder_waitok ?
"" : " <encode:wait>")),
(hdw->state_usbstream_run ?
- " <usb:run>" : " <usb:stop>"));
+ " <usb:run>" : " <usb:stop>"),
+ (hdw->state_pathway_ok ?
+ " <pathway:ok>" : ""));
break;
case 3:
return scnprintf(
@@ -3597,6 +3854,7 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
unsigned int st;
int state_updated = 0;
int callback_flag = 0;
+ int analog_mode;
pvr2_trace(PVR2_TRACE_STBITS,
"Drive state check START");
@@ -3607,18 +3865,21 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
/* Process all state and get back over disposition */
state_updated = pvr2_hdw_state_update(hdw);
+ analog_mode = (hdw->pathway_state != PVR2_PATHWAY_DIGITAL);
+
/* Update master state based upon all other states. */
if (!hdw->flag_ok) {
st = PVR2_STATE_DEAD;
} else if (hdw->fw1_state != FW1_STATE_OK) {
st = PVR2_STATE_COLD;
- } else if (!hdw->state_encoder_ok) {
+ } else if (analog_mode && !hdw->state_encoder_ok) {
st = PVR2_STATE_WARM;
- } else if (hdw->flag_tripped || hdw->flag_decoder_missed) {
+ } else if (hdw->flag_tripped ||
+ (analog_mode && hdw->flag_decoder_missed)) {
st = PVR2_STATE_ERROR;
- } else if (hdw->state_encoder_run &&
- hdw->state_decoder_run &&
- hdw->state_usbstream_run) {
+ } else if (hdw->state_usbstream_run &&
+ (!analog_mode ||
+ (hdw->state_encoder_run && hdw->state_decoder_run))) {
st = PVR2_STATE_RUN;
} else {
st = PVR2_STATE_READY;
@@ -3628,6 +3889,7 @@ static int pvr2_hdw_state_eval(struct pvr2_hdw *hdw)
"Device state change from %s to %s",
pvr2_get_state_name(hdw->master_state),
pvr2_get_state_name(st));
+ pvr2_led_ctrl(hdw,st == PVR2_STATE_RUN);
hdw->master_state = st;
state_updated = !0;
callback_flag = !0;
@@ -3757,6 +4019,12 @@ int pvr2_hdw_gpio_chg_out(struct pvr2_hdw *hdw,u32 msk,u32 val)
}
+unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *hdw)
+{
+ return hdw->input_avail_mask;
+}
+
+
/* Find I2C address of eeprom */
static int pvr2_hdw_get_eeprom_addr(struct pvr2_hdw *hdw)
{
diff --git a/drivers/media/video/pvrusb2/pvrusb2-hdw.h b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
index 3ad7a13d6c39..a868e52a73a3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.h
@@ -40,9 +40,10 @@
/* Legal values for the INPUT state variable */
#define PVR2_CVAL_INPUT_TV 0
-#define PVR2_CVAL_INPUT_SVIDEO 1
+#define PVR2_CVAL_INPUT_DTV 1
#define PVR2_CVAL_INPUT_COMPOSITE 2
-#define PVR2_CVAL_INPUT_RADIO 3
+#define PVR2_CVAL_INPUT_SVIDEO 3
+#define PVR2_CVAL_INPUT_RADIO 4
enum pvr2_config {
pvr2_config_empty, /* No configuration */
@@ -100,14 +101,15 @@ struct pvr2_hdw;
struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
const struct usb_device_id *devid);
+/* Perform second stage initialization, passing in a notification callback
+ for when the master state changes. */
+int pvr2_hdw_initialize(struct pvr2_hdw *,
+ void (*callback_func)(void *),
+ void *callback_data);
+
/* Destroy hardware interaction structure */
void pvr2_hdw_destroy(struct pvr2_hdw *);
-/* Register a function to be called whenever the master state changes. */
-void pvr2_hdw_set_state_callback(struct pvr2_hdw *,
- void (*callback_func)(void *),
- void *callback_data);
-
/* Return true if in the ready (normal) state */
int pvr2_hdw_dev_ok(struct pvr2_hdw *);
@@ -146,6 +148,10 @@ struct pvr2_ctrl *pvr2_hdw_get_ctrl_nextv4l(struct pvr2_hdw *,
/* Commit all control changes made up to this point */
int pvr2_hdw_commit_ctl(struct pvr2_hdw *);
+/* Return a bit mask of valid input selections for this device. Mask bits
+ * will be according to PVR_CVAL_INPUT_xxxx definitions. */
+unsigned int pvr2_hdw_get_input_available(struct pvr2_hdw *);
+
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
@@ -250,6 +256,9 @@ int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *);
/* Execute simple reset command */
int pvr2_hdw_cmd_powerup(struct pvr2_hdw *);
+/* suspend */
+int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *);
+
/* Order decoder to reset */
int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
index 62867fa3517a..793c89a8d672 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-i2c-core.c
@@ -35,7 +35,7 @@
*/
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
module_param(i2c_scan, int, S_IRUGO|S_IWUSR);
MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index da309288daa4..fdc5a2b49ca8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-std.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-std.c
@@ -79,7 +79,7 @@ struct std_name {
#define TSTD_Nc (V4L2_STD_PAL_Nc)
#define TSTD_60 (V4L2_STD_PAL_60)
-#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_SECAM)
+#define CSTD_ALL (CSTD_PAL|CSTD_NTSC|CSTD_ATSC|CSTD_SECAM)
/* Mapping of standard bits to color system */
static const struct std_name std_groups[] = {
@@ -328,7 +328,7 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
struct v4l2_standard *stddefs;
if (pvrusb2_debug & PVR2_TRACE_STD) {
- char buf[50];
+ char buf[100];
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),id);
pvr2_trace(
PVR2_TRACE_STD,"Mapping standards mask=0x%x (%.*s)",
@@ -352,8 +352,11 @@ struct v4l2_standard *pvr2_std_create_enum(unsigned int *countptr,
if ((id & std_mixes[idx2]) == std_mixes[idx2]) std_cnt++;
}
+ /* Don't complain about ATSC standard values */
+ fmsk &= ~CSTD_ATSC;
+
if (fmsk) {
- char buf[50];
+ char buf[100];
bcnt = pvr2_std_id_to_str(buf,sizeof(buf),fmsk);
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
diff --git a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
index 7a1cd878e31a..4dd544ac85bf 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -288,6 +288,8 @@ static ssize_t store_val_norm(int id,struct device *class_dev,
struct pvr2_sysfs *sfp;
int ret;
sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+ pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_norm(cid=%d) \"%.*s\"",
+ sfp,id,(int)count,buf);
ret = store_val_any(id,0,sfp,buf,count);
if (!ret) ret = count;
return ret;
@@ -299,6 +301,8 @@ static ssize_t store_val_custom(int id,struct device *class_dev,
struct pvr2_sysfs *sfp;
int ret;
sfp = (struct pvr2_sysfs *)class_dev->driver_data;
+ pvr2_sysfs_trace("pvr2_sysfs(%p) store_val_custom(cid=%d) \"%.*s\"",
+ sfp,id,(int)count,buf);
ret = store_val_any(id,1,sfp,buf,count);
if (!ret) ret = count;
return ret;
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 8f0587ebd4bd..249d7488e482 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -67,6 +67,10 @@ struct pvr2_v4l2 {
struct v4l2_prio_state prio;
+ /* Map contiguous ordinal value to input id */
+ unsigned char *input_map;
+ unsigned int input_cnt;
+
/* streams - Note that these must be separately, individually,
* allocated pointers. This is because the v4l core is going to
* manage their deletion - separately, individually... */
@@ -259,14 +263,21 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
struct v4l2_input *vi = (struct v4l2_input *)arg;
struct v4l2_input tmp;
unsigned int cnt;
+ int val;
cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
memset(&tmp,0,sizeof(tmp));
tmp.index = vi->index;
ret = 0;
- switch (vi->index) {
+ if ((vi->index < 0) || (vi->index >= vp->input_cnt)) {
+ ret = -EINVAL;
+ break;
+ }
+ val = vp->input_map[vi->index];
+ switch (val) {
case PVR2_CVAL_INPUT_TV:
+ case PVR2_CVAL_INPUT_DTV:
case PVR2_CVAL_INPUT_RADIO:
tmp.type = V4L2_INPUT_TYPE_TUNER;
break;
@@ -281,7 +292,7 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
if (ret < 0) break;
cnt = 0;
- pvr2_ctrl_get_valname(cptr,vi->index,
+ pvr2_ctrl_get_valname(cptr,val,
tmp.name,sizeof(tmp.name)-1,&cnt);
tmp.name[cnt] = 0;
@@ -303,22 +314,33 @@ static int pvr2_v4l2_do_ioctl(struct inode *inode, struct file *file,
case VIDIOC_G_INPUT:
{
+ unsigned int idx;
struct pvr2_ctrl *cptr;
struct v4l2_input *vi = (struct v4l2_input *)arg;
int val;
cptr = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
val = 0;
ret = pvr2_ctrl_get_value(cptr,&val);
- vi->index = val;
+ vi->index = 0;
+ for (idx = 0; idx < vp->input_cnt; idx++) {
+ if (vp->input_map[idx] == val) {
+ vi->index = idx;
+ break;
+ }
+ }
break;
}
case VIDIOC_S_INPUT:
{
struct v4l2_input *vi = (struct v4l2_input *)arg;
+ if ((vi->index < 0) || (vi->index >= vp->input_cnt)) {
+ ret = -ERANGE;
+ break;
+ }
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
- vi->index);
+ vp->input_map[vi->index]);
break;
}
@@ -817,6 +839,10 @@ static void pvr2_v4l2_destroy_no_lock(struct pvr2_v4l2 *vp)
pvr2_v4l2_dev_destroy(vp->dev_radio);
vp->dev_radio = NULL;
}
+ if (vp->input_map) {
+ kfree(vp->input_map);
+ vp->input_map = NULL;
+ }
pvr2_trace(PVR2_TRACE_STRUCT,"Destroying pvr2_v4l2 id=%p",vp);
pvr2_channel_done(&vp->channel);
@@ -858,7 +884,6 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
{
struct pvr2_v4l2_fh *fhp = file->private_data;
struct pvr2_v4l2 *vp = fhp->vhead;
- struct pvr2_context *mp = fhp->vhead->channel.mc_head;
struct pvr2_hdw *hdw = fhp->channel.mc_head->hdw;
pvr2_trace(PVR2_TRACE_OPEN_CLOSE,"pvr2_v4l2_release");
@@ -875,42 +900,40 @@ static int pvr2_v4l2_release(struct inode *inode, struct file *file)
v4l2_prio_close(&vp->prio, &fhp->prio);
file->private_data = NULL;
- pvr2_context_enter(mp); do {
- /* Restore the previous input selection, if it makes sense
- to do so. */
- if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
- struct pvr2_ctrl *cp;
- int pval;
- cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
- pvr2_ctrl_get_value(cp,&pval);
- /* Only restore if we're still selecting the radio */
- if (pval == PVR2_CVAL_INPUT_RADIO) {
- pvr2_ctrl_set_value(cp,fhp->prev_input_val);
- pvr2_hdw_commit_ctl(hdw);
- }
+ /* Restore the previous input selection, if it makes sense
+ to do so. */
+ if (fhp->dev_info->v4l_type == VFL_TYPE_RADIO) {
+ struct pvr2_ctrl *cp;
+ int pval;
+ cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ pvr2_ctrl_get_value(cp,&pval);
+ /* Only restore if we're still selecting the radio */
+ if (pval == PVR2_CVAL_INPUT_RADIO) {
+ pvr2_ctrl_set_value(cp,fhp->prev_input_val);
+ pvr2_hdw_commit_ctl(hdw);
}
+ }
- if (fhp->vnext) {
- fhp->vnext->vprev = fhp->vprev;
- } else {
- vp->vlast = fhp->vprev;
- }
- if (fhp->vprev) {
- fhp->vprev->vnext = fhp->vnext;
- } else {
- vp->vfirst = fhp->vnext;
- }
- fhp->vnext = NULL;
- fhp->vprev = NULL;
- fhp->vhead = NULL;
- pvr2_channel_done(&fhp->channel);
- pvr2_trace(PVR2_TRACE_STRUCT,
- "Destroying pvr_v4l2_fh id=%p",fhp);
- kfree(fhp);
- if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
- pvr2_v4l2_destroy_no_lock(vp);
- }
- } while (0); pvr2_context_exit(mp);
+ if (fhp->vnext) {
+ fhp->vnext->vprev = fhp->vprev;
+ } else {
+ vp->vlast = fhp->vprev;
+ }
+ if (fhp->vprev) {
+ fhp->vprev->vnext = fhp->vnext;
+ } else {
+ vp->vfirst = fhp->vnext;
+ }
+ fhp->vnext = NULL;
+ fhp->vprev = NULL;
+ fhp->vhead = NULL;
+ pvr2_channel_done(&fhp->channel);
+ pvr2_trace(PVR2_TRACE_STRUCT,
+ "Destroying pvr_v4l2_fh id=%p",fhp);
+ kfree(fhp);
+ if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
+ pvr2_v4l2_destroy_no_lock(vp);
+ }
return 0;
}
@@ -943,32 +966,30 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
init_waitqueue_head(&fhp->wait_data);
fhp->dev_info = dip;
- pvr2_context_enter(vp->channel.mc_head); do {
- pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
- pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
+ pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr_v4l2_fh id=%p",fhp);
+ pvr2_channel_init(&fhp->channel,vp->channel.mc_head);
- fhp->vnext = NULL;
- fhp->vprev = vp->vlast;
- if (vp->vlast) {
- vp->vlast->vnext = fhp;
- } else {
- vp->vfirst = fhp;
- }
- vp->vlast = fhp;
- fhp->vhead = vp;
-
- /* Opening the /dev/radioX device implies a mode switch.
- So execute that here. Note that you can get the
- IDENTICAL effect merely by opening the normal video
- device and setting the input appropriately. */
- if (dip->v4l_type == VFL_TYPE_RADIO) {
- struct pvr2_ctrl *cp;
- cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
- pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
- pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
- pvr2_hdw_commit_ctl(hdw);
- }
- } while (0); pvr2_context_exit(vp->channel.mc_head);
+ fhp->vnext = NULL;
+ fhp->vprev = vp->vlast;
+ if (vp->vlast) {
+ vp->vlast->vnext = fhp;
+ } else {
+ vp->vfirst = fhp;
+ }
+ vp->vlast = fhp;
+ fhp->vhead = vp;
+
+ /* Opening the /dev/radioX device implies a mode switch.
+ So execute that here. Note that you can get the
+ IDENTICAL effect merely by opening the normal video
+ device and setting the input appropriately. */
+ if (dip->v4l_type == VFL_TYPE_RADIO) {
+ struct pvr2_ctrl *cp;
+ cp = pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT);
+ pvr2_ctrl_get_value(cp,&fhp->prev_input_val);
+ pvr2_ctrl_set_value(cp,PVR2_CVAL_INPUT_RADIO);
+ pvr2_hdw_commit_ctl(hdw);
+ }
fhp->file = file;
file->private_data = fhp;
@@ -1198,27 +1219,46 @@ static void pvr2_v4l2_dev_init(struct pvr2_v4l2_dev *dip,
struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
{
struct pvr2_v4l2 *vp;
+ struct pvr2_hdw *hdw;
+ unsigned int input_mask,input_cnt,idx;
vp = kzalloc(sizeof(*vp),GFP_KERNEL);
if (!vp) return vp;
- vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
- vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
- if (!(vp->dev_video && vp->dev_radio)) {
- kfree(vp->dev_video);
- kfree(vp->dev_radio);
- kfree(vp);
- return NULL;
- }
pvr2_channel_init(&vp->channel,mnp);
pvr2_trace(PVR2_TRACE_STRUCT,"Creating pvr2_v4l2 id=%p",vp);
vp->channel.check_func = pvr2_v4l2_internal_check;
+ hdw = vp->channel.mc_head->hdw;
+ input_mask = pvr2_hdw_get_input_available(hdw);
+ input_cnt = 0;
+ for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
+ if (input_mask & (1 << idx)) input_cnt++;
+ }
+ vp->input_cnt = input_cnt;
+ vp->input_map = kzalloc(input_cnt,GFP_KERNEL);
+ if (!vp->input_map) goto fail;
+ input_cnt = 0;
+ for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
+ if (!(input_mask & (1 << idx))) continue;
+ vp->input_map[input_cnt++] = idx;
+ }
+
/* register streams */
+ vp->dev_video = kzalloc(sizeof(*vp->dev_video),GFP_KERNEL);
+ if (!vp->dev_video) goto fail;
pvr2_v4l2_dev_init(vp->dev_video,vp,VFL_TYPE_GRABBER);
- pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
+ if (input_mask & (1 << PVR2_CVAL_INPUT_RADIO)) {
+ vp->dev_radio = kzalloc(sizeof(*vp->dev_radio),GFP_KERNEL);
+ if (!vp->dev_radio) goto fail;
+ pvr2_v4l2_dev_init(vp->dev_radio,vp,VFL_TYPE_RADIO);
+ }
return vp;
+ fail:
+ pvr2_trace(PVR2_TRACE_STRUCT,"Failure creating pvr2_v4l2 id=%p",vp);
+ pvr2_v4l2_destroy_no_lock(vp);
+ return 0;
}
/*
diff --git a/drivers/media/video/pwc/pwc-if.c b/drivers/media/video/pwc/pwc-if.c
index e0a453a6543d..d2941c5656ca 100644
--- a/drivers/media/video/pwc/pwc-if.c
+++ b/drivers/media/video/pwc/pwc-if.c
@@ -130,8 +130,8 @@ static int default_fbufs = 3; /* Default number of frame buffers */
#ifdef CONFIG_USB_PWC_DEBUG
int pwc_trace = PWC_DEBUG_LEVEL;
#endif
-static int power_save = 0;
-static int led_on = 100, led_off = 0; /* defaults to LED that is on while in use */
+static int power_save;
+static int led_on = 100, led_off; /* defaults to LED that is on while in use */
static int pwc_preferred_compression = 1; /* 0..3 = uncompressed..high */
static struct {
int type;
@@ -159,7 +159,9 @@ static const struct file_operations pwc_fops = {
.poll = pwc_video_poll,
.mmap = pwc_video_mmap,
.ioctl = pwc_video_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
static struct video_device pwc_template = {
@@ -786,8 +788,8 @@ static void pwc_isoc_handler(struct urb *urb)
} /* ..status == 0 */
else {
/* This is normally not interesting to the user, unless
- * you are really debugging something */
- static int iso_error = 0;
+ * you are really debugging something, default = 0 */
+ static int iso_error;
iso_error++;
if (iso_error < 20)
PWC_DEBUG_FLOW("Iso frame %d of USB has error %d\n", i, fst);
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
new file mode 100644
index 000000000000..bef3c9c7902a
--- /dev/null
+++ b/drivers/media/video/pxa_camera.c
@@ -0,0 +1,1000 @@
+/*
+ * V4L2 Driver for PXA camera host
+ *
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License 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/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/soc_camera.h>
+
+#include <linux/videodev2.h>
+
+#include <asm/dma.h>
+#include <asm/arch/pxa-regs.h>
+#include <asm/arch/camera.h>
+
+#define PXA_CAM_VERSION_CODE KERNEL_VERSION(0, 0, 5)
+#define PXA_CAM_DRV_NAME "pxa27x-camera"
+
+#define CICR0_SIM_MP (0 << 24)
+#define CICR0_SIM_SP (1 << 24)
+#define CICR0_SIM_MS (2 << 24)
+#define CICR0_SIM_EP (3 << 24)
+#define CICR0_SIM_ES (4 << 24)
+
+#define CICR1_DW_VAL(x) ((x) & CICR1_DW) /* Data bus width */
+#define CICR1_PPL_VAL(x) (((x) << 15) & CICR1_PPL) /* Pixels per line */
+
+#define CICR2_BLW_VAL(x) (((x) << 24) & CICR2_BLW) /* Beginning-of-line pixel clock wait count */
+#define CICR2_ELW_VAL(x) (((x) << 16) & CICR2_ELW) /* End-of-line pixel clock wait count */
+#define CICR2_HSW_VAL(x) (((x) << 10) & CICR2_HSW) /* Horizontal sync pulse width */
+#define CICR2_BFPW_VAL(x) (((x) << 3) & CICR2_BFPW) /* Beginning-of-frame pixel clock wait count */
+#define CICR2_FSW_VAL(x) (((x) << 0) & CICR2_FSW) /* Frame stabilization wait count */
+
+#define CICR3_BFW_VAL(x) (((x) << 24) & CICR3_BFW) /* Beginning-of-frame line clock wait count */
+#define CICR3_EFW_VAL(x) (((x) << 16) & CICR3_EFW) /* End-of-frame line clock wait count */
+#define CICR3_VSW_VAL(x) (((x) << 11) & CICR3_VSW) /* Vertical sync pulse width */
+#define CICR3_LPF_VAL(x) (((x) << 0) & CICR3_LPF) /* Lines per frame */
+
+#define CICR0_IRQ_MASK (CICR0_TOM | CICR0_RDAVM | CICR0_FEM | CICR0_EOLM | \
+ CICR0_PERRM | CICR0_QDM | CICR0_CDM | CICR0_SOFM | \
+ CICR0_EOFM | CICR0_FOM)
+
+static DEFINE_MUTEX(camera_lock);
+
+/*
+ * Structures
+ */
+
+/* buffer for one video frame */
+struct pxa_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
+ const struct soc_camera_data_format *fmt;
+
+ /* our descriptor list needed for the PXA DMA engine */
+ dma_addr_t sg_dma;
+ struct pxa_dma_desc *sg_cpu;
+ size_t sg_size;
+ int inwork;
+};
+
+struct pxa_framebuffer_queue {
+ dma_addr_t sg_last_dma;
+ struct pxa_dma_desc *sg_last_cpu;
+};
+
+struct pxa_camera_dev {
+ struct device *dev;
+ /* PXA27x is only supposed to handle one camera on its Quick Capture
+ * interface. If anyone ever builds hardware to enable more than
+ * one camera, they will have to modify this driver too */
+ struct soc_camera_device *icd;
+ struct clk *clk;
+
+ unsigned int irq;
+ void __iomem *base;
+ unsigned int dma_chan_y;
+
+ struct pxacamera_platform_data *pdata;
+ struct resource *res;
+ unsigned long platform_flags;
+ unsigned long platform_mclk_10khz;
+
+ struct list_head capture;
+
+ spinlock_t lock;
+
+ struct pxa_buffer *active;
+};
+
+static const char *pxa_cam_driver_description = "PXA_Camera";
+
+static unsigned int vid_limit = 16; /* Video memory limit, in Mb */
+
+/*
+ * Videobuf operations
+ */
+static int pxa_videobuf_setup(struct videobuf_queue *vq, unsigned int *count,
+ unsigned int *size)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+
+ dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+
+ *size = icd->width * icd->height * ((icd->current_fmt->depth + 7) >> 3);
+
+ if (0 == *count)
+ *count = 32;
+ while (*size * *count > vid_limit * 1024 * 1024)
+ (*count)--;
+
+ return 0;
+}
+
+static void free_buffer(struct videobuf_queue *vq, struct pxa_buffer *buf)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(&buf->vb);
+
+ BUG_ON(in_interrupt());
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ &buf->vb, buf->vb.baddr, buf->vb.bsize);
+
+ /* 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_dma_free(dma);
+
+ if (buf->sg_cpu)
+ dma_free_coherent(pcdev->dev, buf->sg_size, buf->sg_cpu,
+ buf->sg_dma);
+ buf->sg_cpu = NULL;
+
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int pxa_videobuf_prepare(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+ int i, ret;
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ vb, vb->baddr, vb->bsize);
+
+ /* Added list head initialization on alloc */
+ WARN_ON(!list_empty(&vb->queue));
+
+#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
+
+ BUG_ON(NULL == icd->current_fmt);
+
+ /* I think, in buf_prepare you only have to protect global data,
+ * the actual buffer is yours */
+ buf->inwork = 1;
+
+ if (buf->fmt != icd->current_fmt ||
+ vb->width != icd->width ||
+ vb->height != icd->height ||
+ vb->field != field) {
+ buf->fmt = icd->current_fmt;
+ vb->width = icd->width;
+ vb->height = icd->height;
+ vb->field = field;
+ vb->state = VIDEOBUF_NEEDS_INIT;
+ }
+
+ vb->size = vb->width * vb->height * ((buf->fmt->depth + 7) >> 3);
+ if (0 != vb->baddr && vb->bsize < vb->size) {
+ ret = -EINVAL;
+ goto out;
+ }
+
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ unsigned int size = vb->size;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+
+ ret = videobuf_iolock(vq, vb, NULL);
+ if (ret)
+ goto fail;
+
+ if (buf->sg_cpu)
+ dma_free_coherent(pcdev->dev, buf->sg_size, buf->sg_cpu,
+ buf->sg_dma);
+
+ buf->sg_size = (dma->sglen + 1) * sizeof(struct pxa_dma_desc);
+ buf->sg_cpu = dma_alloc_coherent(pcdev->dev, buf->sg_size,
+ &buf->sg_dma, GFP_KERNEL);
+ if (!buf->sg_cpu) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+
+ dev_dbg(&icd->dev, "nents=%d size: %d sg=0x%p\n",
+ dma->sglen, size, dma->sglist);
+ for (i = 0; i < dma->sglen; i++) {
+ struct scatterlist *sg = dma->sglist;
+ unsigned int dma_len = sg_dma_len(&sg[i]), xfer_len;
+
+ /* CIBR0 */
+ buf->sg_cpu[i].dsadr = pcdev->res->start + 0x28;
+ buf->sg_cpu[i].dtadr = sg_dma_address(&sg[i]);
+ /* PXA270 Developer's Manual 27.4.4.1:
+ * round up to 8 bytes */
+ xfer_len = (min(dma_len, size) + 7) & ~7;
+ if (xfer_len & 7)
+ dev_err(&icd->dev, "Unaligned buffer: "
+ "dma_len %u, size %u\n", dma_len, size);
+ buf->sg_cpu[i].dcmd = DCMD_FLOWSRC | DCMD_BURST8 |
+ DCMD_INCTRGADDR | xfer_len;
+ size -= dma_len;
+ buf->sg_cpu[i].ddadr = buf->sg_dma + (i + 1) *
+ sizeof(struct pxa_dma_desc);
+ }
+ buf->sg_cpu[dma->sglen - 1].ddadr = DDADR_STOP;
+ buf->sg_cpu[dma->sglen - 1].dcmd |= DCMD_ENDIRQEN;
+
+ vb->state = VIDEOBUF_PREPARED;
+ }
+
+ buf->inwork = 0;
+
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+out:
+ buf->inwork = 0;
+ return ret;
+}
+
+static void pxa_videobuf_queue(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct soc_camera_device *icd = vq->priv_data;
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+ struct pxa_buffer *active;
+ struct videobuf_dmabuf *dma = videobuf_to_dma(vb);
+ int nents = dma->sglen;
+ unsigned long flags;
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ vb, vb->baddr, vb->bsize);
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ list_add_tail(&vb->queue, &pcdev->capture);
+
+ vb->state = VIDEOBUF_ACTIVE;
+ active = pcdev->active;
+
+ if (!active) {
+ CIFR |= CIFR_RESET_F;
+ DDADR(pcdev->dma_chan_y) = buf->sg_dma;
+ DCSR(pcdev->dma_chan_y) = DCSR_RUN;
+ pcdev->active = buf;
+ CICR0 |= CICR0_ENB;
+ } else {
+ struct videobuf_dmabuf *active_dma =
+ videobuf_to_dma(&active->vb);
+ /* Stop DMA engine */
+ DCSR(pcdev->dma_chan_y) = 0;
+
+ /* Add the descriptors we just initialized to the currently
+ * running chain
+ */
+ active->sg_cpu[active_dma->sglen - 1].ddadr = buf->sg_dma;
+
+ /* Setup a dummy descriptor with the DMA engines current
+ * state
+ */
+ /* CIBR0 */
+ buf->sg_cpu[nents].dsadr = pcdev->res->start + 0x28;
+ buf->sg_cpu[nents].dtadr = DTADR(pcdev->dma_chan_y);
+ buf->sg_cpu[nents].dcmd = DCMD(pcdev->dma_chan_y);
+
+ if (DDADR(pcdev->dma_chan_y) == DDADR_STOP) {
+ /* The DMA engine is on the last descriptor, set the
+ * next descriptors address to the descriptors
+ * we just initialized
+ */
+ buf->sg_cpu[nents].ddadr = buf->sg_dma;
+ } else {
+ buf->sg_cpu[nents].ddadr = DDADR(pcdev->dma_chan_y);
+ }
+
+ /* The next descriptor is the dummy descriptor */
+ DDADR(pcdev->dma_chan_y) = buf->sg_dma + nents *
+ sizeof(struct pxa_dma_desc);
+
+#ifdef DEBUG
+ if (CISR & CISR_IFO_0) {
+ dev_warn(pcdev->dev, "FIFO overrun\n");
+ DDADR(pcdev->dma_chan_y) = pcdev->active->sg_dma;
+
+ CICR0 &= ~CICR0_ENB;
+ CIFR |= CIFR_RESET_F;
+ DCSR(pcdev->dma_chan_y) = DCSR_RUN;
+ CICR0 |= CICR0_ENB;
+ } else
+#endif
+ DCSR(pcdev->dma_chan_y) = DCSR_RUN;
+ }
+
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+
+}
+
+static void pxa_videobuf_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct pxa_buffer *buf = container_of(vb, struct pxa_buffer, vb);
+#ifdef DEBUG
+ struct soc_camera_device *icd = vq->priv_data;
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ vb, vb->baddr, vb->bsize);
+
+ switch (vb->state) {
+ case VIDEOBUF_ACTIVE:
+ dev_dbg(&icd->dev, "%s (active)\n", __FUNCTION__);
+ break;
+ case VIDEOBUF_QUEUED:
+ dev_dbg(&icd->dev, "%s (queued)\n", __FUNCTION__);
+ break;
+ case VIDEOBUF_PREPARED:
+ dev_dbg(&icd->dev, "%s (prepared)\n", __FUNCTION__);
+ break;
+ default:
+ dev_dbg(&icd->dev, "%s (unknown)\n", __FUNCTION__);
+ break;
+ }
+#endif
+
+ free_buffer(vq, buf);
+}
+
+static void pxa_camera_dma_irq_y(int channel, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ struct pxa_buffer *buf;
+ unsigned long flags;
+ unsigned int status;
+ struct videobuf_buffer *vb;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ status = DCSR(pcdev->dma_chan_y);
+ DCSR(pcdev->dma_chan_y) = status;
+
+ if (status & DCSR_BUSERR) {
+ dev_err(pcdev->dev, "DMA Bus Error IRQ!\n");
+ goto out;
+ }
+
+ if (!(status & DCSR_ENDINTR)) {
+ dev_err(pcdev->dev, "Unknown DMA IRQ source, "
+ "status: 0x%08x\n", status);
+ goto out;
+ }
+
+ if (!pcdev->active) {
+ dev_err(pcdev->dev, "DMA End IRQ with no active buffer!\n");
+ goto out;
+ }
+
+ vb = &pcdev->active->vb;
+ buf = container_of(vb, struct pxa_buffer, vb);
+ WARN_ON(buf->inwork || list_empty(&vb->queue));
+ dev_dbg(pcdev->dev, "%s (vb=0x%p) 0x%08lx %d\n", __FUNCTION__,
+ vb, vb->baddr, vb->bsize);
+
+ /* _init is used to debug races, see comment in pxa_camera_reqbufs() */
+ list_del_init(&vb->queue);
+ vb->state = VIDEOBUF_DONE;
+ do_gettimeofday(&vb->ts);
+ vb->field_count++;
+ wake_up(&vb->done);
+
+ if (list_empty(&pcdev->capture)) {
+ pcdev->active = NULL;
+ DCSR(pcdev->dma_chan_y) = 0;
+ CICR0 &= ~CICR0_ENB;
+ goto out;
+ }
+
+ pcdev->active = list_entry(pcdev->capture.next, struct pxa_buffer,
+ vb.queue);
+
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static struct videobuf_queue_ops pxa_videobuf_ops = {
+ .buf_setup = pxa_videobuf_setup,
+ .buf_prepare = pxa_videobuf_prepare,
+ .buf_queue = pxa_videobuf_queue,
+ .buf_release = pxa_videobuf_release,
+};
+
+static int mclk_get_divisor(struct pxa_camera_dev *pcdev)
+{
+ unsigned int mclk_10khz = pcdev->platform_mclk_10khz;
+ unsigned long div;
+ unsigned long lcdclk;
+
+ lcdclk = clk_get_rate(pcdev->clk) / 10000;
+
+ /* We verify platform_mclk_10khz != 0, so if anyone breaks it, here
+ * they get a nice Oops */
+ div = (lcdclk + 2 * mclk_10khz - 1) / (2 * mclk_10khz) - 1;
+
+ dev_dbg(pcdev->dev, "LCD clock %lukHz, target freq %dkHz, "
+ "divisor %lu\n", lcdclk * 10, mclk_10khz * 10, div);
+
+ return div;
+}
+
+static void pxa_camera_activate(struct pxa_camera_dev *pcdev)
+{
+ struct pxacamera_platform_data *pdata = pcdev->pdata;
+ u32 cicr4 = 0;
+
+ dev_dbg(pcdev->dev, "Registered platform device at %p data %p\n",
+ pcdev, pdata);
+
+ if (pdata && pdata->init) {
+ dev_dbg(pcdev->dev, "%s: Init gpios\n", __FUNCTION__);
+ pdata->init(pcdev->dev);
+ }
+
+ if (pdata && pdata->power) {
+ dev_dbg(pcdev->dev, "%s: Power on camera\n", __FUNCTION__);
+ pdata->power(pcdev->dev, 1);
+ }
+
+ if (pdata && pdata->reset) {
+ dev_dbg(pcdev->dev, "%s: Releasing camera reset\n",
+ __FUNCTION__);
+ pdata->reset(pcdev->dev, 1);
+ }
+
+ CICR0 = 0x3FF; /* disable all interrupts */
+
+ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+ cicr4 |= CICR4_PCLK_EN;
+ if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+ cicr4 |= CICR4_MCLK_EN;
+ if (pcdev->platform_flags & PXA_CAMERA_PCP)
+ cicr4 |= CICR4_PCP;
+ if (pcdev->platform_flags & PXA_CAMERA_HSP)
+ cicr4 |= CICR4_HSP;
+ if (pcdev->platform_flags & PXA_CAMERA_VSP)
+ cicr4 |= CICR4_VSP;
+
+ CICR4 = mclk_get_divisor(pcdev) | cicr4;
+
+ clk_enable(pcdev->clk);
+}
+
+static void pxa_camera_deactivate(struct pxa_camera_dev *pcdev)
+{
+ struct pxacamera_platform_data *board = pcdev->pdata;
+
+ clk_disable(pcdev->clk);
+
+ if (board && board->reset) {
+ dev_dbg(pcdev->dev, "%s: Asserting camera reset\n",
+ __FUNCTION__);
+ board->reset(pcdev->dev, 0);
+ }
+
+ if (board && board->power) {
+ dev_dbg(pcdev->dev, "%s: Power off camera\n", __FUNCTION__);
+ board->power(pcdev->dev, 0);
+ }
+}
+
+static irqreturn_t pxa_camera_irq(int irq, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ unsigned int status = CISR;
+
+ dev_dbg(pcdev->dev, "Camera interrupt status 0x%x\n", status);
+
+ CISR = status;
+
+ return IRQ_HANDLED;
+}
+
+/* The following two functions absolutely depend on the fact, that
+ * there can be only one camera on PXA quick capture interface */
+static int pxa_camera_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ int ret;
+
+ mutex_lock(&camera_lock);
+
+ if (pcdev->icd) {
+ ret = -EBUSY;
+ goto ebusy;
+ }
+
+ dev_info(&icd->dev, "PXA Camera driver attached to camera %d\n",
+ icd->devnum);
+
+ pxa_camera_activate(pcdev);
+ ret = icd->ops->init(icd);
+
+ if (!ret)
+ pcdev->icd = icd;
+
+ebusy:
+ mutex_unlock(&camera_lock);
+
+ return ret;
+}
+
+static void pxa_camera_remove_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+
+ BUG_ON(icd != pcdev->icd);
+
+ dev_info(&icd->dev, "PXA Camera driver detached from camera %d\n",
+ icd->devnum);
+
+ /* disable capture, disable interrupts */
+ CICR0 = 0x3ff;
+ /* Stop DMA engine */
+ DCSR(pcdev->dma_chan_y) = 0;
+
+ icd->ops->release(icd);
+
+ pxa_camera_deactivate(pcdev);
+
+ pcdev->icd = NULL;
+}
+
+static int test_platform_param(struct pxa_camera_dev *pcdev,
+ unsigned char buswidth, unsigned long *flags)
+{
+ /*
+ * Platform specified synchronization and pixel clock polarities are
+ * only a recommendation and are only used during probing. The PXA270
+ * quick capture interface supports both.
+ */
+ *flags = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+ SOCAM_MASTER : SOCAM_SLAVE) |
+ SOCAM_HSYNC_ACTIVE_HIGH |
+ SOCAM_HSYNC_ACTIVE_LOW |
+ SOCAM_VSYNC_ACTIVE_HIGH |
+ SOCAM_VSYNC_ACTIVE_LOW |
+ SOCAM_PCLK_SAMPLE_RISING |
+ SOCAM_PCLK_SAMPLE_FALLING;
+
+ /* If requested data width is supported by the platform, use it */
+ switch (buswidth) {
+ case 10:
+ if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_10))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_10;
+ break;
+ case 9:
+ if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_9))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_9;
+ break;
+ case 8:
+ if (!(pcdev->platform_flags & PXA_CAMERA_DATAWIDTH_8))
+ return -EINVAL;
+ *flags |= SOCAM_DATAWIDTH_8;
+ }
+
+ return 0;
+}
+
+static int pxa_camera_set_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ unsigned long dw, bpp, bus_flags, camera_flags, common_flags;
+ u32 cicr0, cicr4 = 0;
+ int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+
+ if (ret < 0)
+ return ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ common_flags = soc_camera_bus_param_compatible(camera_flags, bus_flags);
+ if (!common_flags)
+ return -EINVAL;
+
+ /* Make choises, based on platform preferences */
+ if ((common_flags & SOCAM_HSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_HSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & PXA_CAMERA_HSP)
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_HSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_VSYNC_ACTIVE_HIGH) &&
+ (common_flags & SOCAM_VSYNC_ACTIVE_LOW)) {
+ if (pcdev->platform_flags & PXA_CAMERA_VSP)
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_HIGH;
+ else
+ common_flags &= ~SOCAM_VSYNC_ACTIVE_LOW;
+ }
+
+ if ((common_flags & SOCAM_PCLK_SAMPLE_RISING) &&
+ (common_flags & SOCAM_PCLK_SAMPLE_FALLING)) {
+ if (pcdev->platform_flags & PXA_CAMERA_PCP)
+ common_flags &= ~SOCAM_PCLK_SAMPLE_RISING;
+ else
+ common_flags &= ~SOCAM_PCLK_SAMPLE_FALLING;
+ }
+
+ ret = icd->ops->set_bus_param(icd, common_flags);
+ if (ret < 0)
+ return ret;
+
+ /* Datawidth is now guaranteed to be equal to one of the three values.
+ * We fix bit-per-pixel equal to data-width... */
+ switch (common_flags & SOCAM_DATAWIDTH_MASK) {
+ case SOCAM_DATAWIDTH_10:
+ icd->buswidth = 10;
+ dw = 4;
+ bpp = 0x40;
+ break;
+ case SOCAM_DATAWIDTH_9:
+ icd->buswidth = 9;
+ dw = 3;
+ bpp = 0x20;
+ break;
+ default:
+ /* Actually it can only be 8 now,
+ * default is just to silence compiler warnings */
+ case SOCAM_DATAWIDTH_8:
+ icd->buswidth = 8;
+ dw = 2;
+ bpp = 0;
+ }
+
+ if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
+ cicr4 |= CICR4_PCLK_EN;
+ if (pcdev->platform_flags & PXA_CAMERA_MCLK_EN)
+ cicr4 |= CICR4_MCLK_EN;
+ if (common_flags & SOCAM_PCLK_SAMPLE_FALLING)
+ cicr4 |= CICR4_PCP;
+ if (common_flags & SOCAM_HSYNC_ACTIVE_LOW)
+ cicr4 |= CICR4_HSP;
+ if (common_flags & SOCAM_VSYNC_ACTIVE_LOW)
+ cicr4 |= CICR4_VSP;
+
+ cicr0 = CICR0;
+ if (cicr0 & CICR0_ENB)
+ CICR0 = cicr0 & ~CICR0_ENB;
+ CICR1 = CICR1_PPL_VAL(icd->width - 1) | bpp | dw;
+ CICR2 = 0;
+ CICR3 = CICR3_LPF_VAL(icd->height - 1) |
+ CICR3_BFW_VAL(min((unsigned short)255, icd->y_skip_top));
+ CICR4 = mclk_get_divisor(pcdev) | cicr4;
+
+ /* CIF interrupts are not used, only DMA */
+ CICR0 = (pcdev->platform_flags & PXA_CAMERA_MASTER ?
+ CICR0_SIM_MP : (CICR0_SL_CAP_EN | CICR0_SIM_SP)) |
+ CICR0_DMAEN | CICR0_IRQ_MASK | (cicr0 & CICR0_ENB);
+
+ return 0;
+}
+
+static int pxa_camera_try_bus_param(struct soc_camera_device *icd, __u32 pixfmt)
+{
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+ unsigned long bus_flags, camera_flags;
+ int ret = test_platform_param(pcdev, icd->buswidth, &bus_flags);
+
+ if (ret < 0)
+ return ret;
+
+ camera_flags = icd->ops->query_bus_param(icd);
+
+ return soc_camera_bus_param_compatible(camera_flags, bus_flags) ? 0 : -EINVAL;
+}
+
+static int pxa_camera_set_fmt_cap(struct soc_camera_device *icd,
+ __u32 pixfmt, struct v4l2_rect *rect)
+{
+ return icd->ops->set_fmt_cap(icd, pixfmt, rect);
+}
+
+static int pxa_camera_try_fmt_cap(struct soc_camera_device *icd,
+ struct v4l2_format *f)
+{
+ /* limit to pxa hardware capabilities */
+ if (f->fmt.pix.height < 32)
+ f->fmt.pix.height = 32;
+ if (f->fmt.pix.height > 2048)
+ f->fmt.pix.height = 2048;
+ if (f->fmt.pix.width < 48)
+ f->fmt.pix.width = 48;
+ if (f->fmt.pix.width > 2048)
+ f->fmt.pix.width = 2048;
+ f->fmt.pix.width &= ~0x01;
+
+ /* limit to sensor capabilities */
+ return icd->ops->try_fmt_cap(icd, f);
+}
+
+static int pxa_camera_reqbufs(struct soc_camera_file *icf,
+ 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 pxa_buffer *buf = container_of(icf->vb_vidq.bufs[i],
+ struct pxa_buffer, vb);
+ buf->inwork = 0;
+ INIT_LIST_HEAD(&buf->vb.queue);
+ }
+
+ return 0;
+}
+
+static unsigned int pxa_camera_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct pxa_buffer *buf;
+
+ buf = list_entry(icf->vb_vidq.stream.next, struct pxa_buffer,
+ 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 int pxa_camera_querycap(struct soc_camera_host *ici,
+ struct v4l2_capability *cap)
+{
+ /* cap->name is set by the firendly caller:-> */
+ strlcpy(cap->card, pxa_cam_driver_description, sizeof(cap->card));
+ cap->version = PXA_CAM_VERSION_CODE;
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE | V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static spinlock_t *pxa_camera_spinlock_alloc(struct soc_camera_file *icf)
+{
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icf->icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+
+ return &pcdev->lock;
+}
+
+static struct soc_camera_host_ops pxa_soc_camera_host_ops = {
+ .owner = THIS_MODULE,
+ .add = pxa_camera_add_device,
+ .remove = pxa_camera_remove_device,
+ .set_fmt_cap = pxa_camera_set_fmt_cap,
+ .try_fmt_cap = pxa_camera_try_fmt_cap,
+ .reqbufs = pxa_camera_reqbufs,
+ .poll = pxa_camera_poll,
+ .querycap = pxa_camera_querycap,
+ .try_bus_param = pxa_camera_try_bus_param,
+ .set_bus_param = pxa_camera_set_bus_param,
+ .spinlock_alloc = pxa_camera_spinlock_alloc,
+};
+
+/* Should be allocated dynamically too, but we have only one. */
+static struct soc_camera_host pxa_soc_camera_host = {
+ .drv_name = PXA_CAM_DRV_NAME,
+ .vbq_ops = &pxa_videobuf_ops,
+ .msize = sizeof(struct pxa_buffer),
+ .ops = &pxa_soc_camera_host_ops,
+};
+
+static int pxa_camera_probe(struct platform_device *pdev)
+{
+ struct pxa_camera_dev *pcdev;
+ struct resource *res;
+ 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 || !irq) {
+ 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 = clk_get(&pdev->dev, "CAMCLK");
+ if (IS_ERR(pcdev->clk)) {
+ err = PTR_ERR(pcdev->clk);
+ goto exit_kfree;
+ }
+
+ dev_set_drvdata(&pdev->dev, pcdev);
+ pcdev->res = res;
+
+ pcdev->pdata = pdev->dev.platform_data;
+ pcdev->platform_flags = pcdev->pdata->flags;
+ if (!(pcdev->platform_flags & (PXA_CAMERA_DATAWIDTH_8 |
+ PXA_CAMERA_DATAWIDTH_9 | PXA_CAMERA_DATAWIDTH_10))) {
+ /* Platform hasn't set available data widths. This is bad.
+ * Warn and use a default. */
+ dev_warn(&pdev->dev, "WARNING! Platform hasn't set available "
+ "data widths, using default 10 bit\n");
+ pcdev->platform_flags |= PXA_CAMERA_DATAWIDTH_10;
+ }
+ pcdev->platform_mclk_10khz = pcdev->pdata->mclk_10khz;
+ if (!pcdev->platform_mclk_10khz) {
+ dev_warn(&pdev->dev,
+ "mclk_10khz == 0! Please, fix your platform data. "
+ "Using default 20MHz\n");
+ pcdev->platform_mclk_10khz = 2000;
+ }
+
+ INIT_LIST_HEAD(&pcdev->capture);
+ spin_lock_init(&pcdev->lock);
+
+ /*
+ * Request the regions.
+ */
+ if (!request_mem_region(res->start, res->end - res->start + 1,
+ PXA_CAM_DRV_NAME)) {
+ err = -EBUSY;
+ goto exit_clk;
+ }
+
+ base = ioremap(res->start, res->end - res->start + 1);
+ if (!base) {
+ err = -ENOMEM;
+ goto exit_release;
+ }
+ pcdev->irq = irq;
+ pcdev->base = base;
+ pcdev->dev = &pdev->dev;
+
+ /* request dma */
+ pcdev->dma_chan_y = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
+ pxa_camera_dma_irq_y, pcdev);
+ if (pcdev->dma_chan_y < 0) {
+ dev_err(pcdev->dev, "Can't request DMA for Y\n");
+ err = -ENOMEM;
+ goto exit_iounmap;
+ }
+ dev_dbg(pcdev->dev, "got DMA channel %d\n", pcdev->dma_chan_y);
+
+ DRCMR68 = pcdev->dma_chan_y | DRCMR_MAPVLD;
+
+ /* request irq */
+ err = request_irq(pcdev->irq, pxa_camera_irq, 0, PXA_CAM_DRV_NAME,
+ pcdev);
+ if (err) {
+ dev_err(pcdev->dev, "Camera interrupt register failed \n");
+ goto exit_free_dma;
+ }
+
+ pxa_soc_camera_host.priv = pcdev;
+ pxa_soc_camera_host.dev.parent = &pdev->dev;
+ pxa_soc_camera_host.nr = pdev->id;
+ err = soc_camera_host_register(&pxa_soc_camera_host);
+ if (err)
+ goto exit_free_irq;
+
+ return 0;
+
+exit_free_irq:
+ free_irq(pcdev->irq, pcdev);
+exit_free_dma:
+ pxa_free_dma(pcdev->dma_chan_y);
+exit_iounmap:
+ iounmap(base);
+exit_release:
+ release_mem_region(res->start, res->end - res->start + 1);
+exit_clk:
+ clk_put(pcdev->clk);
+exit_kfree:
+ kfree(pcdev);
+exit:
+ return err;
+}
+
+static int __devexit pxa_camera_remove(struct platform_device *pdev)
+{
+ struct pxa_camera_dev *pcdev = platform_get_drvdata(pdev);
+ struct resource *res;
+
+ clk_put(pcdev->clk);
+
+ pxa_free_dma(pcdev->dma_chan_y);
+ free_irq(pcdev->irq, pcdev);
+
+ soc_camera_host_unregister(&pxa_soc_camera_host);
+
+ iounmap(pcdev->base);
+
+ res = pcdev->res;
+ release_mem_region(res->start, res->end - res->start + 1);
+
+ kfree(pcdev);
+
+ dev_info(&pdev->dev, "PXA Camera driver unloaded\n");
+
+ return 0;
+}
+
+static struct platform_driver pxa_camera_driver = {
+ .driver = {
+ .name = PXA_CAM_DRV_NAME,
+ },
+ .probe = pxa_camera_probe,
+ .remove = __exit_p(pxa_camera_remove),
+};
+
+
+static int __devinit pxa_camera_init(void)
+{
+ return platform_driver_register(&pxa_camera_driver);
+}
+
+static void __exit pxa_camera_exit(void)
+{
+ return platform_driver_unregister(&pxa_camera_driver);
+}
+
+module_init(pxa_camera_init);
+module_exit(pxa_camera_exit);
+
+MODULE_DESCRIPTION("PXA27x SoC Camera Host driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/saa5249.c b/drivers/media/video/saa5249.c
index f55d6e85f20f..ec8c65dc8408 100644
--- a/drivers/media/video/saa5249.c
+++ b/drivers/media/video/saa5249.c
@@ -701,7 +701,9 @@ static const struct file_operations saa_fops = {
.open = saa5249_open,
.release = saa5249_release,
.ioctl = saa5249_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/video/saa6588.c b/drivers/media/video/saa6588.c
index 72e344a12c79..716ee7f64df3 100644
--- a/drivers/media/video/saa6588.c
+++ b/drivers/media/video/saa6588.c
@@ -44,10 +44,10 @@ static unsigned short normal_i2c[] = {
I2C_CLIENT_INSMOD;
/* insmod options */
-static unsigned int debug = 0;
-static unsigned int xtal = 0;
-static unsigned int rbds = 0;
-static unsigned int plvl = 0;
+static unsigned int debug;
+static unsigned int xtal;
+static unsigned int rbds;
+static unsigned int plvl;
static unsigned int bufblocks = 100;
module_param(debug, int, 0644);
diff --git a/drivers/media/video/saa7110.c b/drivers/media/video/saa7110.c
index 1df2602cd184..4aa82b310708 100644
--- a/drivers/media/video/saa7110.c
+++ b/drivers/media/video/saa7110.c
@@ -46,7 +46,7 @@ MODULE_LICENSE("GPL");
#include <media/v4l2-common.h>
#include <linux/video_decoder.h>
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/saa7111.c b/drivers/media/video/saa7111.c
index a0772c53bb1f..96c3d4357722 100644
--- a/drivers/media/video/saa7111.c
+++ b/drivers/media/video/saa7111.c
@@ -55,7 +55,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(s) (s)->name
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/saa7114.c b/drivers/media/video/saa7114.c
index bf91a4faa706..e79075533beb 100644
--- a/drivers/media/video/saa7114.c
+++ b/drivers/media/video/saa7114.c
@@ -56,7 +56,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(x) (x)->name
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/saa7115.c b/drivers/media/video/saa7115.c
index 41e5e518a47e..416d05d4a969 100644
--- a/drivers/media/video/saa7115.c
+++ b/drivers/media/video/saa7115.c
@@ -57,7 +57,7 @@ MODULE_AUTHOR( "Maxim Yevtyushkin, Kevin Thayer, Chris Kennedy, "
"Hans Verkuil, Mauro Carvalho Chehab");
MODULE_LICENSE("GPL");
-static int debug = 0;
+static int debug;
module_param(debug, bool, 0644);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
@@ -957,7 +957,7 @@ static void saa711x_set_v4lstd(struct i2c_client *client, v4l2_std_id std)
if (std == V4L2_STD_PAL_M) {
reg |= 0x30;
- } else if (std == V4L2_STD_PAL_N) {
+ } else if (std == V4L2_STD_PAL_Nc) {
reg |= 0x20;
} else if (std == V4L2_STD_PAL_60) {
reg |= 0x10;
diff --git a/drivers/media/video/saa711x.c b/drivers/media/video/saa711x.c
index 80bf91187856..cedb988574bd 100644
--- a/drivers/media/video/saa711x.c
+++ b/drivers/media/video/saa711x.c
@@ -48,7 +48,7 @@ MODULE_LICENSE("GPL");
#include <linux/video_decoder.h>
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, " Set the default Debug level. Default: 0 (Off) - (0-1)");
diff --git a/drivers/media/video/saa7134/Kconfig b/drivers/media/video/saa7134/Kconfig
index 96bc3b1298a2..e086f14d5663 100644
--- a/drivers/media/video/saa7134/Kconfig
+++ b/drivers/media/video/saa7134/Kconfig
@@ -37,6 +37,7 @@ config VIDEO_SAA7134_DVB
select DVB_TDA826X if !DVB_FE_CUSTOMISE
select DVB_TDA827X if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
+ select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
---help---
This adds support for DVB cards based on the
Philips saa7134 chip.
diff --git a/drivers/media/video/saa7134/saa7134-alsa.c b/drivers/media/video/saa7134/saa7134-alsa.c
index 047add8f3010..048081be91fe 100644
--- a/drivers/media/video/saa7134/saa7134-alsa.c
+++ b/drivers/media/video/saa7134/saa7134-alsa.c
@@ -31,7 +31,7 @@
#include "saa7134.h"
#include "saa7134-reg.h"
-static unsigned int debug = 0;
+static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages [alsa]");
@@ -503,7 +503,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_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
+ videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
substream->runtime->dma_area = NULL;
}
@@ -519,12 +519,12 @@ static int snd_card_saa7134_hw_params(struct snd_pcm_substream * substream,
return err;
}
- if (0 != (err = videobuf_pci_dma_map(dev->pci, &dev->dmasound.dma))) {
+ if (0 != (err = videobuf_sg_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_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
+ videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
return err;
}
@@ -533,7 +533,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_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
+ videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
return err;
}
@@ -569,7 +569,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_pci_dma_unmap(dev->pci, &dev->dmasound.dma);
+ videobuf_sg_dma_unmap(&dev->pci->dev, &dev->dmasound.dma);
dsp_buffer_free(dev);
substream->runtime->dma_area = NULL;
}
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 6f5744286e8c..82fe19c3b1db 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -22,9 +22,12 @@
#include <linux/init.h>
#include <linux/module.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
#include "saa7134-reg.h"
#include "saa7134.h"
+#include "tuner-xc2028.h"
#include <media/v4l2-common.h>
#include <media/tveeprom.h>
@@ -2908,15 +2911,13 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_MD7134_BRIDGE_2] = {
- /* This card has two saa7134 chips on it,
- but only one of them is currently working.
- The programming for the primary decoder is
- in SAA7134_BOARD_MD7134 */
+ /* The second saa7134 on this card only serves as DVB-S host bridge */
.name = "Medion 7134 Bridge #2",
.audio_clock = 0x00187de7,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
},
[SAA7134_BOARD_FLYDVBT_HYBRID_CARDBUS] = {
.name = "LifeView FlyDVB-T Hybrid Cardbus/MSI TV @nywhere A/D NB",
@@ -3330,7 +3331,7 @@ struct saa7134_board saa7134_boards[] = {
/* Juan Pablo Sormani <sorman@gmail.com> */
.name = "Encore ENLTV-FM",
.audio_clock = 0x00200000,
- .tuner_type = TUNER_PHILIPS_ATSC,
+ .tuner_type = TUNER_PHILIPS_FCV1236D,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
@@ -3992,6 +3993,221 @@ struct saa7134_board saa7134_boards[] = {
.gpio = 0x6000,
},
},
+ [SAA7134_BOARD_PHILIPS_SNAKE] = {
+ .name = "NXP Snake DVB-S reference design",
+ .audio_clock = 0x00200000,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_CREATIX_CTX953] = {
+ .name = "Medion/Creatix CTX953 Hybrid",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 0,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 0,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_MSI_TVANYWHERE_AD11] = {
+ .name = "MSI TV@nywhere A/D v1.1",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 2,
+ .mpeg = SAA7134_MPEG_DVB,
+ .gpiomask = 0x0200000,
+ .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 = 0x0200000,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_CARDBUS_506] = {
+ .name = "AVerMedia Cardbus TV/Radio (E506R)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /*
+ TODO:
+ .mpeg = SAA7134_MPEG_DVB,
+ */
+
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE2,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_A16D] = {
+ .name = "AVerMedia Hybrid TV/Radio (A16D)",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE1,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = LINE1,
+ },
+ },
+ [SAA7134_BOARD_AVERMEDIA_M115] = {
+ .name = "Avermedia M115",
+ .audio_clock = 0x187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 3,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ },
+ [SAA7134_BOARD_VIDEOMATE_T750] = {
+ /* John Newbigin <jn@it.swin.edu.au> */
+ .name = "Compro VideoMate T750",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_XC2028,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .mpeg = SAA7134_MPEG_DVB,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 3,
+ .amux = TV,
+ .tv = 1,
+ }, {
+ .name = name_comp1,
+ .vmux = 1,
+ .amux = LINE2,
+ }, {
+ .name = name_svideo,
+ .vmux = 8,
+ .amux = LINE2,
+ } },
+ .radio = {
+ .name = name_radio,
+ .amux = TV,
+ }
+ },
+ [SAA7134_BOARD_AVERMEDIA_A700_PRO] = {
+ /* Matthias Schwarzott <zzam@gentoo.org> */
+ .name = "Avermedia DVB-S Pro A700",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* no DVB support for now */
+ /* .mpeg = SAA7134_MPEG_DVB, */
+ .inputs = { {
+ .name = name_comp,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ } },
+ },
+ [SAA7134_BOARD_AVERMEDIA_A700_HYBRID] = {
+ /* Matthias Schwarzott <zzam@gentoo.org> */
+ .name = "Avermedia DVB-S Hybrid+FM A700",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_ABSENT, /* TUNER_XC2028 */
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ /* no DVB support for now */
+ /* .mpeg = SAA7134_MPEG_DVB, */
+ .inputs = { {
+ .name = name_comp,
+ .vmux = 1,
+ .amux = LINE1,
+ }, {
+ .name = name_svideo,
+ .vmux = 6,
+ .amux = LINE1,
+ } },
+ },
};
const unsigned int saa7134_bcount = ARRAY_SIZE(saa7134_boards);
@@ -4224,6 +4440,18 @@ struct pci_device_id saa7134_pci_tbl[] = {
.driver_data = SAA7134_BOARD_MD2819,
},{
.vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa7a1,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A700_PRO,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa7a2,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A700_HYBRID,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7130,
.subvendor = 0x1461, /* Avermedia Technologies Inc */
.subdevice = 0x2115,
@@ -4942,7 +5170,43 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subvendor = 0x1822, /*Twinhan Technology Co. Ltd*/
.subdevice = 0x0022,
.driver_data = SAA7134_BOARD_TWINHAN_DTV_DVB_3056,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x16be,
+ .subdevice = 0x0010, /* Medion version CTX953_V.1.4.3 */
+ .driver_data = SAA7134_BOARD_CREATIX_CTX953,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1462, /* MSI */
+ .subdevice = 0x8625, /* TV@nywhere A/D v1.1 */
+ .driver_data = SAA7134_BOARD_MSI_TVANYWHERE_AD11,
},{
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf436,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_CARDBUS_506,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xf936,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_A16D,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x1461, /* Avermedia Technologies Inc */
+ .subdevice = 0xa836,
+ .driver_data = SAA7134_BOARD_AVERMEDIA_M115,
+ }, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = 0x185b,
+ .subdevice = 0xc900,
+ .driver_data = SAA7134_BOARD_VIDEOMATE_T750,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
@@ -4998,6 +5262,77 @@ static void board_flyvideo(struct saa7134_dev *dev)
dev->name, dev->name, dev->name);
}
+static int saa7134_xc2028_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ switch (command) {
+ case XC2028_TUNER_RESET:
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
+ mdelay(250);
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0);
+ mdelay(250);
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x06e20000, 0x06e20000);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x06a20000, 0x06a20000);
+ mdelay(250);
+ saa_andorl(SAA7133_ANALOG_IO_SELECT >> 2, 0x02, 0x02);
+ saa_andorl(SAA7134_ANALOG_IN_CTRL1 >> 2, 0x81, 0x81);
+ saa_andorl(SAA7134_AUDIO_CLOCK0 >> 2, 0x03187de7, 0x03187de7);
+ saa_andorl(SAA7134_AUDIO_PLL_CTRL >> 2, 0x03, 0x03);
+ saa_andorl(SAA7134_AUDIO_CLOCKS_PER_FIELD0 >> 2,
+ 0x0001e000, 0x0001e000);
+ return 0;
+ }
+ return -EINVAL;
+}
+
+
+static int saa7134_tda8290_callback(struct saa7134_dev *dev,
+ int command, int arg)
+{
+ u8 sync_control;
+
+ switch (command) {
+ case 0: /* switch LNA gain through GPIO 22*/
+ saa7134_set_gpio(dev, 22, arg) ;
+ break;
+ case 1: /* vsync output at GPIO22. 50 / 60Hz */
+ saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80);
+ saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03);
+ if (arg == 1)
+ sync_control = 11;
+ else
+ sync_control = 17;
+ saa_writeb(SAA7134_VGATE_START, sync_control);
+ saa_writeb(SAA7134_VGATE_STOP, sync_control + 1);
+ saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00);
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+int saa7134_tuner_callback(void *priv, int command, int arg)
+{
+ struct saa7134_dev *dev = priv;
+ if (dev != NULL) {
+ switch (dev->tuner_type) {
+ case TUNER_PHILIPS_TDA8290:
+ return saa7134_tda8290_callback(dev, command, arg);
+ case TUNER_XC2028:
+ return saa7134_xc2028_callback(dev, command, arg);
+ }
+ } else {
+ printk(KERN_ERR "saa7134: Error - device struct undefined.\n");
+ return -EINVAL;
+ }
+ return -EINVAL;
+}
+EXPORT_SYMBOL(saa7134_tuner_callback);
+
/* ----------------------------------------------------------- */
static void hauppauge_eeprom(struct saa7134_dev *dev, u8 *eeprom_data)
@@ -5067,6 +5402,7 @@ int saa7134_board_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_VIDEOMATE_DVBT_200:
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
+ case SAA7134_BOARD_VIDEOMATE_T750:
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
case SAA7134_BOARD_BEHOLD_409FM:
@@ -5133,11 +5469,18 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x08000000, 0x00000000);
break;
case SAA7134_BOARD_AVERMEDIA_CARDBUS:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ case SAA7134_BOARD_AVERMEDIA_M115:
case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ /* power-down tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0);
+ msleep(10);
/* power-up tuner chip */
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0xffffffff, 0xffffffff);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0xffffffff, 0xffffffff);
- msleep(1);
+ msleep(10);
break;
case SAA7134_BOARD_RTD_VFG7350:
@@ -5160,7 +5503,6 @@ int saa7134_board_init1(struct saa7134_dev *dev)
dev->has_remote = SAA7134_REMOTE_I2C;
break;
case SAA7134_BOARD_AVERMEDIA_A169_B:
- case SAA7134_BOARD_MD7134_BRIDGE_2:
printk("%s: %s: dual saa713x broadcast decoders\n"
"%s: Sorry, none of the inputs to this chip are supported yet.\n"
"%s: Dual decoder functionality is disabled for now, use the other chip.\n",
@@ -5172,6 +5514,15 @@ int saa7134_board_init1(struct saa7134_dev *dev)
saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x8c040007, 0x8c040007);
saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x0c0007cd, 0x0c0007cd);
break;
+ case SAA7134_BOARD_AVERMEDIA_A700_PRO:
+ case SAA7134_BOARD_AVERMEDIA_A700_HYBRID:
+ /* write windows gpio values */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x80040100, 0x80040100);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x80040100, 0x00040100);
+ printk("%s: %s: hybrid analog/dvb card\n"
+ "%s: Sorry, only the analog inputs are supported for now.\n",
+ dev->name, card(dev).name, dev->name);
+ break;
}
return 0;
}
@@ -5200,11 +5551,16 @@ int saa7134_board_init2(struct saa7134_dev *dev)
dev->tuner_type = saa7134_boards[dev->board].tuner_type;
if (TUNER_ABSENT != dev->tuner_type) {
- tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
- tun_setup.type = dev->tuner_type;
- tun_setup.addr = ADDR_UNSET;
+ tun_setup.mode_mask = T_RADIO |
+ T_ANALOG_TV |
+ T_DIGITAL_TV;
+ tun_setup.type = dev->tuner_type;
+ tun_setup.addr = ADDR_UNSET;
+ tun_setup.tuner_callback = saa7134_tuner_callback;
- saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR, &tun_setup);
+ saa7134_i2c_call_clients(dev,
+ TUNER_SET_TYPE_ADDR,
+ &tun_setup);
}
break;
case SAA7134_BOARD_MD7134:
@@ -5275,14 +5631,25 @@ int saa7134_board_init2(struct saa7134_dev *dev)
&tda9887_cfg);
}
- tun_setup.mode_mask = T_RADIO | T_ANALOG_TV | T_DIGITAL_TV;
+ tun_setup.mode_mask = T_RADIO |
+ T_ANALOG_TV |
+ T_DIGITAL_TV;
tun_setup.type = dev->tuner_type;
tun_setup.addr = ADDR_UNSET;
- saa7134_i2c_call_clients (dev, TUNER_SET_TYPE_ADDR,&tun_setup);
+ saa7134_i2c_call_clients(dev,
+ TUNER_SET_TYPE_ADDR, &tun_setup);
}
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
+ if (dev->autodetected && (dev->eedata[0x41] == 0x1c)) {
+ /* Reconfigure board as Snake reference design */
+ dev->board = SAA7134_BOARD_PHILIPS_SNAKE;
+ dev->tuner_type = saa7134_boards[dev->board].tuner_type;
+ printk(KERN_INFO "%s: Reconfigured board as %s\n",
+ dev->name, saa7134_boards[dev->board].name);
+ break;
+ }
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
case SAA7134_BOARD_ASUS_EUROPA2_HYBRID:
/* The Philips EUROPA based hybrid boards have the tuner connected through
@@ -5333,6 +5700,7 @@ int saa7134_board_init2(struct saa7134_dev *dev)
case SAA7134_BOARD_MEDION_MD8800_QUADRO:
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
+ case SAA7134_BOARD_CREATIX_CTX953:
/* this is a hybrid board, initialize to analog mode
* and configure firmware eeprom address
*/
@@ -5403,12 +5771,31 @@ int saa7134_board_init2(struct saa7134_dev *dev)
}
break;
}
+
+ if (dev->tuner_type == TUNER_XC2028) {
+ struct v4l2_priv_tun_config xc2028_cfg;
+ struct xc2028_ctrl ctl;
+
+ memset(&xc2028_cfg, 0, sizeof(ctl));
+ memset(&ctl, 0, sizeof(ctl));
+
+ ctl.fname = XC2028_DEFAULT_FIRMWARE;
+ ctl.max_len = 64;
+
+ switch (dev->board) {
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ ctl.demod = XC3028_FE_ZARLINK456;
+ break;
+ default:
+ ctl.demod = XC3028_FE_OREN538;
+ ctl.mts = 1;
+ }
+
+ xc2028_cfg.tuner = TUNER_XC2028;
+ xc2028_cfg.priv = &ctl;
+
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &xc2028_cfg);
+ }
+
return 0;
}
-
-/* ----------------------------------------------------------- */
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/drivers/media/video/saa7134/saa7134-core.c b/drivers/media/video/saa7134/saa7134-core.c
index 58ab163fdbd7..eec127864fe3 100644
--- a/drivers/media/video/saa7134/saa7134-core.c
+++ b/drivers/media/video/saa7134/saa7134-core.c
@@ -42,23 +42,23 @@ MODULE_LICENSE("GPL");
/* ------------------------------------------------------------------ */
-static unsigned int irq_debug = 0;
+static unsigned int irq_debug;
module_param(irq_debug, int, 0644);
MODULE_PARM_DESC(irq_debug,"enable debug messages [IRQ handler]");
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
module_param(core_debug, int, 0644);
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
-static unsigned int gpio_tracking = 0;
+static unsigned int gpio_tracking;
module_param(gpio_tracking, int, 0644);
MODULE_PARM_DESC(gpio_tracking,"enable debug messages [gpio]");
-static unsigned int alsa = 0;
+static unsigned int alsa;
module_param(alsa, int, 0644);
MODULE_PARM_DESC(alsa,"enable ALSA DMA sound [dmasound]");
-static unsigned int oss = 0;
+static unsigned int oss;
module_param(oss, int, 0644);
MODULE_PARM_DESC(oss,"enable OSS DMA sound [dmasound]");
@@ -142,39 +142,6 @@ void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value)
}
}
-int saa7134_tuner_callback(void *ptr, int command, int arg)
-{
- u8 sync_control;
- struct saa7134_dev *dev = ptr;
-
- switch (dev->tuner_type) {
- case TUNER_PHILIPS_TDA8290:
- switch (command) {
- case 0: /* switch LNA gain through GPIO 22*/
- saa7134_set_gpio(dev, 22, arg) ;
- break;
- case 1: /* vsync output at GPIO22. 50 / 60Hz */
- dprintk("setting GPIO22 to vsync %d\n", arg);
- saa_andorb(SAA7134_VIDEO_PORT_CTRL3, 0x80, 0x80);
- saa_andorb(SAA7134_VIDEO_PORT_CTRL6, 0x0f, 0x03);
- if (arg == 1)
- sync_control = 11;
- else
- sync_control = 17;
- saa_writeb(SAA7134_VGATE_START, sync_control);
- saa_writeb(SAA7134_VGATE_STOP, sync_control + 1);
- saa_andorb(SAA7134_MISC_VGATE_MSB, 0x03, 0x00);
- break;
- default:
- return -EINVAL;
- }
- break;
- default:
- return -ENODEV;
- }
- return 0;
-}
-
/* ------------------------------------------------------------------ */
@@ -897,6 +864,10 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
struct saa7134_dev *dev;
struct saa7134_mpeg_ops *mops;
int err;
+ int mask;
+
+ if (saa7134_devcount == SAA7134_MAXBOARDS)
+ return -ENOMEM;
dev = kzalloc(sizeof(*dev),GFP_KERNEL);
if (NULL == dev)
@@ -1094,6 +1065,11 @@ static int __devinit saa7134_initdev(struct pci_dev *pci_dev,
if (TUNER_ABSENT != dev->tuner_type)
saa7134_i2c_call_clients(dev, TUNER_SET_STANDBY, NULL);
+ if (card(dev).gpiomask != 0) {
+ mask = card(dev).gpiomask;
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, mask, mask);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, mask, 0);
+ }
return 0;
fail4:
diff --git a/drivers/media/video/saa7134/saa7134-dvb.c b/drivers/media/video/saa7134/saa7134-dvb.c
index ea2be9eceeb8..5c84f45ecbe2 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -33,30 +33,35 @@
#include "saa7134.h"
#include <media/v4l2-common.h>
#include "dvb-pll.h"
+#include <dvb_frontend.h>
#include "mt352.h"
#include "mt352_priv.h" /* FIXME */
#include "tda1004x.h"
#include "nxt200x.h"
+#include "tuner-xc2028.h"
#include "tda10086.h"
#include "tda826x.h"
#include "tda827x.h"
#include "isl6421.h"
+#include "isl6405.h"
+#include "lnbp21.h"
+#include "tuner-simple.h"
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
-static unsigned int antenna_pwr = 0;
+static unsigned int antenna_pwr;
module_param(antenna_pwr, int, 0444);
MODULE_PARM_DESC(antenna_pwr,"enable antenna power (Pinnacle 300i)");
-static int use_frontend = 0;
+static int use_frontend;
module_param(use_frontend, int, 0644);
MODULE_PARM_DESC(use_frontend,"for cards with multiple frontends (0: terrestrial, 1: satellite)");
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off module debugging (default:off).");
@@ -91,7 +96,7 @@ static int pinnacle_antenna_pwr(struct saa7134_dev *dev, int on)
saa_setl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 28));
udelay(10);
ok = saa_readl(SAA7134_GPIO_GPSTATUS0) & (1 << 27);
- dprintk("%s %s\n", __FUNCTION__, ok ? "on" : "off");
+ dprintk("%s %s\n", __func__, ok ? "on" : "off");
if (!ok)
saa_clearl(SAA7134_GPIO_GPSTATUS0 >> 2, (1 << 26));
@@ -111,7 +116,7 @@ static int mt352_pinnacle_init(struct dvb_frontend* fe)
static u8 irq_cfg [] = { INTERRUPT_EN_0, 0x00, 0x00, 0x00, 0x00 };
struct saa7134_dev *dev= fe->dvb->priv;
- dprintk("%s called\n", __FUNCTION__);
+ dprintk("%s called\n", __func__);
mt352_write(fe, clock_config, sizeof(clock_config));
udelay(200);
@@ -146,6 +151,26 @@ static int mt352_aver777_init(struct dvb_frontend* fe)
return 0;
}
+static int mt352_aver_a16d_init(struct dvb_frontend *fe)
+{
+ static u8 clock_config [] = { CLOCK_CTL, 0x38, 0x2d };
+ static u8 reset [] = { RESET, 0x80 };
+ static u8 adc_ctl_1_cfg [] = { ADC_CTL_1, 0x40 };
+ static u8 agc_cfg [] = { AGC_TARGET, 0x28, 0xa0 };
+ static u8 capt_range_cfg[] = { CAPT_RANGE, 0x33 };
+
+ mt352_write(fe, clock_config, sizeof(clock_config));
+ udelay(200);
+ mt352_write(fe, reset, sizeof(reset));
+ mt352_write(fe, adc_ctl_1_cfg, sizeof(adc_ctl_1_cfg));
+ mt352_write(fe, agc_cfg, sizeof(agc_cfg));
+ mt352_write(fe, capt_range_cfg, sizeof(capt_range_cfg));
+
+ return 0;
+}
+
+
+
static int mt352_pinnacle_tuner_set_params(struct dvb_frontend* fe,
struct dvb_frontend_parameters* params)
{
@@ -188,6 +213,16 @@ static struct mt352_config avermedia_777 = {
.demod_init = mt352_aver777_init,
};
+static struct mt352_config avermedia_16d = {
+ .demod_address = 0xf,
+ .demod_init = mt352_aver_a16d_init,
+};
+
+static struct mt352_config avermedia_e506r_mt352_dev = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+};
+
/* ==================================================================
* tda1004x based DVB-T cards, helper functions
*/
@@ -430,8 +465,6 @@ static struct tda1004x_config philips_europa_config = {
.request_firmware = philips_tda1004x_request_firmware
};
-/* ------------------------------------------------------------------ */
-
static struct tda1004x_config medion_cardbus = {
.demod_address = 0x08,
.invert = 1,
@@ -447,47 +480,6 @@ static struct tda1004x_config medion_cardbus = {
* tda 1004x based cards with philips silicon tuner
*/
-static void philips_tda827x_lna_gain(struct dvb_frontend *fe, int high)
-{
- struct saa7134_dev *dev = fe->dvb->priv;
- struct tda1004x_state *state = fe->demodulator_priv;
- u8 addr = state->config->i2c_gate;
- u8 config = state->config->tuner_config;
- u8 GP00_CF[] = {0x20, 0x01};
- u8 GP00_LEV[] = {0x22, 0x00};
-
- struct i2c_msg msg = {.addr = addr,.flags = 0,.buf = GP00_CF, .len = 2};
- if (config) {
- if (high) {
- dprintk("setting LNA to high gain\n");
- } else {
- dprintk("setting LNA to low gain\n");
- }
- }
- switch (config) {
- case 0: /* no LNA */
- break;
- case 1: /* switch is GPIO 0 of tda8290 */
- case 2:
- /* turn Vsync off */
- saa7134_set_gpio(dev, 22, 0);
- GP00_LEV[1] = high ? 0 : 1;
- if (i2c_transfer(&dev->i2c_adap, &msg, 1) != 1) {
- wprintk("could not access tda8290 at addr: 0x%02x\n",
- addr << 1);
- return;
- }
- msg.buf = GP00_LEV;
- if (config == 2)
- GP00_LEV[1] = high ? 1 : 0;
- i2c_transfer(&dev->i2c_adap, &msg, 1);
- break;
- case 3: /* switch with GPIO of saa713x */
- saa7134_set_gpio(dev, 22, high);
- break;
- }
-}
-
static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
{
struct tda1004x_state *state = fe->demodulator_priv;
@@ -510,8 +502,6 @@ static int tda8290_i2c_gate_ctrl( struct dvb_frontend* fe, int enable)
return 0;
}
-/* ------------------------------------------------------------------ */
-
static int philips_tda827x_tuner_init(struct dvb_frontend *fe)
{
struct saa7134_dev *dev = fe->dvb->priv;
@@ -546,28 +536,57 @@ static int philips_tda827x_tuner_sleep(struct dvb_frontend *fe)
return 0;
}
-static struct tda827x_config tda827x_cfg = {
- .lna_gain = philips_tda827x_lna_gain,
- .init = philips_tda827x_tuner_init,
- .sleep = philips_tda827x_tuner_sleep
-};
-
-static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *tda_conf)
+static void configure_tda827x_fe(struct saa7134_dev *dev, struct tda1004x_config *cdec_conf,
+ struct tda827x_config *tuner_conf)
{
- dev->dvb.frontend = dvb_attach(tda10046_attach, tda_conf, &dev->i2c_adap);
+ dev->dvb.frontend = dvb_attach(tda10046_attach, cdec_conf, &dev->i2c_adap);
if (dev->dvb.frontend) {
- if (tda_conf->i2c_gate)
+ if (cdec_conf->i2c_gate)
dev->dvb.frontend->ops.i2c_gate_ctrl = tda8290_i2c_gate_ctrl;
- if (dvb_attach(tda827x_attach, dev->dvb.frontend, tda_conf->tuner_address,
- &dev->i2c_adap,&tda827x_cfg) == NULL) {
+ if (dvb_attach(tda827x_attach, dev->dvb.frontend, cdec_conf->tuner_address,
+ &dev->i2c_adap, tuner_conf) == NULL) {
wprintk("no tda827x tuner found at addr: %02x\n",
- tda_conf->tuner_address);
+ cdec_conf->tuner_address);
}
}
}
/* ------------------------------------------------------------------ */
+static struct tda827x_config tda827x_cfg_0 = {
+ .tuner_callback = saa7134_tuner_callback,
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 0,
+ .switch_addr = 0
+};
+
+static struct tda827x_config tda827x_cfg_1 = {
+ .tuner_callback = saa7134_tuner_callback,
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 1,
+ .switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2 = {
+ .tuner_callback = saa7134_tuner_callback,
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 2,
+ .switch_addr = 0x4b
+};
+
+static struct tda827x_config tda827x_cfg_2_sw42 = {
+ .tuner_callback = saa7134_tuner_callback,
+ .init = philips_tda827x_tuner_init,
+ .sleep = philips_tda827x_tuner_sleep,
+ .config = 2,
+ .switch_addr = 0x42
+};
+
+/* ------------------------------------------------------------------ */
+
static struct tda1004x_config tda827x_lifeview_config = {
.demod_address = 0x08,
.invert = 1,
@@ -590,7 +609,6 @@ static struct tda1004x_config philips_tiger_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 0,
.antenna_switch= 1,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -605,7 +623,6 @@ static struct tda1004x_config cinergy_ht_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 0,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -619,7 +636,6 @@ static struct tda1004x_config cinergy_ht_pci_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x60,
- .tuner_config = 0,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -633,7 +649,6 @@ static struct tda1004x_config philips_tiger_s_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 2,
.antenna_switch= 1,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -648,7 +663,6 @@ static struct tda1004x_config pinnacle_pctv_310i_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 1,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -662,7 +676,6 @@ static struct tda1004x_config hauppauge_hvr_1110_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 1,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -676,7 +689,6 @@ static struct tda1004x_config asus_p7131_dual_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 0,
.antenna_switch= 2,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -715,7 +727,6 @@ static struct tda1004x_config md8800_dvbt_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x60,
- .tuner_config = 0,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -729,7 +740,6 @@ static struct tda1004x_config asus_p7131_4871_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 2,
.antenna_switch= 2,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -744,7 +754,6 @@ static struct tda1004x_config asus_p7131_hybrid_lna_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 2,
.antenna_switch= 2,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -759,7 +768,6 @@ static struct tda1004x_config kworld_dvb_t_210_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x61,
- .tuner_config = 2,
.antenna_switch= 1,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -774,7 +782,6 @@ static struct tda1004x_config avermedia_super_007_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x4b,
.tuner_address = 0x60,
- .tuner_config = 0,
.antenna_switch= 1,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -789,7 +796,6 @@ static struct tda1004x_config twinhan_dtv_dvb_3056_config = {
.if_freq = TDA10046_FREQ_045,
.i2c_gate = 0x42,
.tuner_address = 0x61,
- .tuner_config = 2,
.antenna_switch = 1,
.request_firmware = philips_tda1004x_request_firmware
};
@@ -817,9 +823,10 @@ static int ads_duo_tuner_sleep(struct dvb_frontend *fe)
}
static struct tda827x_config ads_duo_cfg = {
- .lna_gain = philips_tda827x_lna_gain,
+ .tuner_callback = saa7134_tuner_callback,
.init = ads_duo_tuner_init,
- .sleep = ads_duo_tuner_sleep
+ .sleep = ads_duo_tuner_sleep,
+ .config = 0
};
static struct tda1004x_config ads_tech_duo_config = {
@@ -844,6 +851,63 @@ static struct tda10086_config flydvbs = {
.diseqc_tone = 0,
};
+/* ------------------------------------------------------------------
+ * special case: lnb supply is connected to the gated i2c
+ */
+
+static int md8800_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ int res = -EIO;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dev->original_set_voltage)
+ res = dev->original_set_voltage(fe, voltage);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ return res;
+};
+
+static int md8800_set_high_voltage(struct dvb_frontend *fe, long arg)
+{
+ int res = -EIO;
+ struct saa7134_dev *dev = fe->dvb->priv;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dev->original_set_high_voltage)
+ res = dev->original_set_high_voltage(fe, arg);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ return res;
+};
+
+static int md8800_set_voltage2(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ u8 wbuf[2] = { 0x1f, 00 };
+ u8 rbuf;
+ struct i2c_msg msg[] = { { .addr = 0x08, .flags = 0, .buf = wbuf, .len = 1 },
+ { .addr = 0x08, .flags = I2C_M_RD, .buf = &rbuf, .len = 1 } };
+
+ if (i2c_transfer(&dev->i2c_adap, msg, 2) != 2)
+ return -EIO;
+ /* NOTE: this assumes that gpo1 is used, it might be bit 5 (gpo2) */
+ if (voltage == SEC_VOLTAGE_18)
+ wbuf[1] = rbuf | 0x10;
+ else
+ wbuf[1] = rbuf & 0xef;
+ msg[0].len = 2;
+ i2c_transfer(&dev->i2c_adap, msg, 1);
+ return 0;
+}
+
+static int md8800_set_high_voltage2(struct dvb_frontend *fe, long arg)
+{
+ struct saa7134_dev *dev = fe->dvb->priv;
+ wprintk("%s: sorry can't set high LNB supply voltage from here\n", __func__);
+ return -EIO;
+}
+
/* ==================================================================
* nxt200x based ATSC cards, helper functions
*/
@@ -863,12 +927,14 @@ static struct nxt200x_config kworldatsc110 = {
static int dvb_init(struct saa7134_dev *dev)
{
int ret;
+ int attach_xc3028 = 0;
+
/* init struct videobuf_dvb */
dev->ts.nr_bufs = 32;
dev->ts.nr_packets = 32*4;
dev->dvb.name = dev->name;
- videobuf_queue_pci_init(&dev->dvb.dvbq, &saa7134_ts_qops,
- dev->pci, &dev->slock,
+ videobuf_queue_sg_init(&dev->dvb.dvbq, &saa7134_ts_qops,
+ &dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
sizeof(struct saa7134_buf),
@@ -889,17 +955,25 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_777,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_PHILIPS_TD1316);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_TD1316);
}
break;
+ case SAA7134_BOARD_AVERMEDIA_A16D:
+ dprintk("avertv A16D dvb setup\n");
+ dev->dvb.frontend = dvb_attach(mt352_attach, &avermedia_16d,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
+ break;
case SAA7134_BOARD_MD7134:
dev->dvb.frontend = dvb_attach(tda10046_attach,
&medion_cardbus,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
- &dev->i2c_adap, DVB_PLL_FMD1216ME);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->i2c_adap, medion_cardbus.tuner_address,
+ TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
case SAA7134_BOARD_PHILIPS_TOUGH:
@@ -913,7 +987,7 @@ static int dvb_init(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_FLYDVBTDUO:
case SAA7134_BOARD_FLYDVBT_DUO_CARDBUS:
- configure_tda827x_fe(dev, &tda827x_lifeview_config);
+ configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
break;
case SAA7134_BOARD_PHILIPS_EUROPA:
case SAA7134_BOARD_VIDEOMATE_DVBT_300:
@@ -938,36 +1012,36 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_KWORLD_DVBT_210:
- configure_tda827x_fe(dev, &kworld_dvb_t_210_config);
+ configure_tda827x_fe(dev, &kworld_dvb_t_210_config, &tda827x_cfg_2);
break;
case SAA7134_BOARD_PHILIPS_TIGER:
- configure_tda827x_fe(dev, &philips_tiger_config);
+ configure_tda827x_fe(dev, &philips_tiger_config, &tda827x_cfg_0);
break;
case SAA7134_BOARD_PINNACLE_PCTV_310i:
- configure_tda827x_fe(dev, &pinnacle_pctv_310i_config);
+ configure_tda827x_fe(dev, &pinnacle_pctv_310i_config, &tda827x_cfg_1);
break;
case SAA7134_BOARD_HAUPPAUGE_HVR1110:
- configure_tda827x_fe(dev, &hauppauge_hvr_1110_config);
+ configure_tda827x_fe(dev, &hauppauge_hvr_1110_config, &tda827x_cfg_1);
break;
case SAA7134_BOARD_ASUSTeK_P7131_DUAL:
- configure_tda827x_fe(dev, &asus_p7131_dual_config);
+ configure_tda827x_fe(dev, &asus_p7131_dual_config, &tda827x_cfg_0);
break;
case SAA7134_BOARD_FLYDVBT_LR301:
- configure_tda827x_fe(dev, &tda827x_lifeview_config);
+ configure_tda827x_fe(dev, &tda827x_lifeview_config, &tda827x_cfg_0);
break;
case SAA7134_BOARD_FLYDVB_TRIO:
if(! use_frontend) { /* terrestrial */
- configure_tda827x_fe(dev, &lifeview_trio_config);
- } else { /* satellite */
+ configure_tda827x_fe(dev, &lifeview_trio_config, &tda827x_cfg_0);
+ } else { /* satellite */
dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs, &dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x63,
&dev->i2c_adap, 0) == NULL) {
- wprintk("%s: Lifeview Trio, No tda826x found!\n", __FUNCTION__);
+ wprintk("%s: Lifeview Trio, No tda826x found!\n", __func__);
}
if (dvb_attach(isl6421_attach, dev->dvb.frontend, &dev->i2c_adap,
0x08, 0, 0) == NULL) {
- wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __FUNCTION__);
+ wprintk("%s: Lifeview Trio, No ISL6421 found!\n", __func__);
}
}
}
@@ -979,18 +1053,56 @@ static int dvb_init(struct saa7134_dev *dev)
&dev->i2c_adap);
if (dev->dvb.frontend) {
if (dvb_attach(tda827x_attach,dev->dvb.frontend,
- ads_tech_duo_config.tuner_address,
- &dev->i2c_adap,&ads_duo_cfg) == NULL) {
+ ads_tech_duo_config.tuner_address, &dev->i2c_adap,
+ &ads_duo_cfg) == NULL) {
wprintk("no tda827x tuner found at addr: %02x\n",
ads_tech_duo_config.tuner_address);
}
}
break;
case SAA7134_BOARD_TEVION_DVBT_220RF:
- configure_tda827x_fe(dev, &tevion_dvbt220rf_config);
+ configure_tda827x_fe(dev, &tevion_dvbt220rf_config, &tda827x_cfg_0);
break;
case SAA7134_BOARD_MEDION_MD8800_QUADRO:
- configure_tda827x_fe(dev, &md8800_dvbt_config);
+ if (!use_frontend) { /* terrestrial */
+ configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+ } else { /* satellite */
+ dev->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ struct dvb_frontend *fe = dev->dvb.frontend;
+ u8 dev_id = dev->eedata[2];
+ u8 data = 0xc4;
+ struct i2c_msg msg = {.addr = 0x08, .flags = 0, .len = 1};
+
+ if (dvb_attach(tda826x_attach, dev->dvb.frontend,
+ 0x60, &dev->i2c_adap, 0) == NULL)
+ wprintk("%s: Medion Quadro, no tda826x "
+ "found !\n", __func__);
+ if (dev_id != 0x08) {
+ /* we need to open the i2c gate (we know it exists) */
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dvb_attach(isl6405_attach, fe,
+ &dev->i2c_adap, 0x08, 0, 0) == NULL)
+ wprintk("%s: Medion Quadro, no ISL6405 "
+ "found !\n", __func__);
+ if (dev_id == 0x07) {
+ /* fire up the 2nd section of the LNB supply since
+ we can't do this from the other section */
+ msg.buf = &data;
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ }
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ dev->original_set_voltage = fe->ops.set_voltage;
+ fe->ops.set_voltage = md8800_set_voltage;
+ dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+ } else {
+ fe->ops.set_voltage = md8800_set_voltage2;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage2;
+ }
+ }
+ }
break;
case SAA7134_BOARD_AVERMEDIA_AVERTVHD_A180:
dev->dvb.frontend = dvb_attach(nxt200x_attach, &avertvhda180,
@@ -1004,8 +1116,9 @@ static int dvb_init(struct saa7134_dev *dev)
dev->dvb.frontend = dvb_attach(nxt200x_attach, &kworldatsc110,
&dev->i2c_adap);
if (dev->dvb.frontend) {
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x61,
- NULL, DVB_PLL_TUV1236D);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->i2c_adap, 0x61,
+ TUNER_PHILIPS_TUV1236D);
}
break;
case SAA7134_BOARD_FLYDVBS_LR300:
@@ -1014,11 +1127,11 @@ static int dvb_init(struct saa7134_dev *dev)
if (dev->dvb.frontend) {
if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
&dev->i2c_adap, 0) == NULL) {
- wprintk("%s: No tda826x found!\n", __FUNCTION__);
+ wprintk("%s: No tda826x found!\n", __func__);
}
if (dvb_attach(isl6421_attach, dev->dvb.frontend,
&dev->i2c_adap, 0x08, 0, 0) == NULL) {
- wprintk("%s: No ISL6421 found!\n", __FUNCTION__);
+ wprintk("%s: No ISL6421 found!\n", __func__);
}
}
break;
@@ -1030,8 +1143,9 @@ static int dvb_init(struct saa7134_dev *dev)
dev->original_demod_sleep = dev->dvb.frontend->ops.sleep;
dev->dvb.frontend->ops.sleep = philips_europa_demod_sleep;
- dvb_attach(dvb_pll_attach, dev->dvb.frontend, medion_cardbus.tuner_address,
- &dev->i2c_adap, DVB_PLL_FMD1216ME);
+ dvb_attach(simple_tuner_attach, dev->dvb.frontend,
+ &dev->i2c_adap, medion_cardbus.tuner_address,
+ TUNER_PHILIPS_FMD1216ME_MK3);
}
break;
case SAA7134_BOARD_VIDEOMATE_DVBT_200A:
@@ -1044,31 +1158,99 @@ static int dvb_init(struct saa7134_dev *dev)
}
break;
case SAA7134_BOARD_CINERGY_HT_PCMCIA:
- configure_tda827x_fe(dev, &cinergy_ht_config);
+ configure_tda827x_fe(dev, &cinergy_ht_config, &tda827x_cfg_0);
break;
case SAA7134_BOARD_CINERGY_HT_PCI:
- configure_tda827x_fe(dev, &cinergy_ht_pci_config);
+ configure_tda827x_fe(dev, &cinergy_ht_pci_config, &tda827x_cfg_0);
break;
case SAA7134_BOARD_PHILIPS_TIGER_S:
- configure_tda827x_fe(dev, &philips_tiger_s_config);
+ configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
break;
case SAA7134_BOARD_ASUS_P7131_4871:
- configure_tda827x_fe(dev, &asus_p7131_4871_config);
+ configure_tda827x_fe(dev, &asus_p7131_4871_config, &tda827x_cfg_2);
break;
case SAA7134_BOARD_ASUSTeK_P7131_HYBRID_LNA:
- configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config);
+ configure_tda827x_fe(dev, &asus_p7131_hybrid_lna_config, &tda827x_cfg_2);
break;
case SAA7134_BOARD_AVERMEDIA_SUPER_007:
- configure_tda827x_fe(dev, &avermedia_super_007_config);
+ configure_tda827x_fe(dev, &avermedia_super_007_config, &tda827x_cfg_0);
break;
case SAA7134_BOARD_TWINHAN_DTV_DVB_3056:
- configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config);
+ configure_tda827x_fe(dev, &twinhan_dtv_dvb_3056_config, &tda827x_cfg_2_sw42);
+ break;
+ case SAA7134_BOARD_PHILIPS_SNAKE:
+ dev->dvb.frontend = dvb_attach(tda10086_attach, &flydvbs,
+ &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ if (dvb_attach(tda826x_attach, dev->dvb.frontend, 0x60,
+ &dev->i2c_adap, 0) == NULL)
+ wprintk("%s: No tda826x found!\n", __func__);
+ if (dvb_attach(lnbp21_attach, dev->dvb.frontend,
+ &dev->i2c_adap, 0, 0) == NULL)
+ wprintk("%s: No lnbp21 found!\n", __func__);
+ }
+ break;
+ case SAA7134_BOARD_CREATIX_CTX953:
+ configure_tda827x_fe(dev, &md8800_dvbt_config, &tda827x_cfg_0);
+ break;
+ case SAA7134_BOARD_MSI_TVANYWHERE_AD11:
+ configure_tda827x_fe(dev, &philips_tiger_s_config, &tda827x_cfg_2);
+ break;
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ dev->dvb.frontend = dvb_attach(mt352_attach,
+ &avermedia_e506r_mt352_dev,
+ &dev->i2c_adap);
+ attach_xc3028 = 1;
+ break;
+ case SAA7134_BOARD_MD7134_BRIDGE_2:
+ dev->dvb.frontend = dvb_attach(tda10086_attach,
+ &flydvbs, &dev->i2c_adap);
+ if (dev->dvb.frontend) {
+ struct dvb_frontend *fe;
+ if (dvb_attach(dvb_pll_attach, dev->dvb.frontend, 0x60,
+ &dev->i2c_adap, DVB_PLL_PHILIPS_SD1878_TDA8261) == NULL)
+ wprintk("%s: MD7134 DVB-S, no SD1878 "
+ "found !\n", __func__);
+ /* we need to open the i2c gate (we know it exists) */
+ fe = dev->dvb.frontend;
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ if (dvb_attach(isl6405_attach, fe,
+ &dev->i2c_adap, 0x08, 0, 0) == NULL)
+ wprintk("%s: MD7134 DVB-S, no ISL6405 "
+ "found !\n", __func__);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ dev->original_set_voltage = fe->ops.set_voltage;
+ fe->ops.set_voltage = md8800_set_voltage;
+ dev->original_set_high_voltage = fe->ops.enable_high_lnb_voltage;
+ fe->ops.enable_high_lnb_voltage = md8800_set_high_voltage;
+ }
break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
}
+ if (attach_xc3028) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_adap,
+ .i2c_addr = 0x61,
+ };
+
+ if (!dev->dvb.frontend)
+ return -1;
+
+ fe = dvb_attach(xc2028_attach, dev->dvb.frontend, &cfg);
+ if (!fe) {
+ printk(KERN_ERR "%s/2: xc3028 attach failed\n",
+ dev->name);
+ dvb_frontend_detach(dev->dvb.frontend);
+ dvb_unregister_frontend(dev->dvb.frontend);
+ dev->dvb.frontend = NULL;
+ return -1;
+ }
+ }
+
if (NULL == dev->dvb.frontend) {
printk(KERN_ERR "%s/dvb: frontend initialization failed\n", dev->name);
return -1;
@@ -1106,8 +1288,20 @@ static int dvb_fini(struct saa7134_dev *dev)
/* otherwise we don't detect the tuner on next insmod */
saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tda9887_cfg);
+ } else if (dev->board == SAA7134_BOARD_MEDION_MD8800_QUADRO) {
+ if ((dev->eedata[2] == 0x07) && use_frontend) {
+ /* turn off the 2nd lnb supply */
+ u8 data = 0x80;
+ struct i2c_msg msg = {.addr = 0x08, .buf = &data, .flags = 0, .len = 1};
+ struct dvb_frontend *fe;
+ fe = dev->dvb.frontend;
+ if (fe->ops.i2c_gate_ctrl) {
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ i2c_transfer(&dev->i2c_adap, &msg, 1);
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ }
}
-
videobuf_dvb_unregister(&dev->dvb);
return 0;
}
diff --git a/drivers/media/video/saa7134/saa7134-empress.c b/drivers/media/video/saa7134/saa7134-empress.c
index 3d2ec30de227..e002be568c21 100644
--- a/drivers/media/video/saa7134/saa7134-empress.c
+++ b/drivers/media/video/saa7134/saa7134-empress.c
@@ -40,7 +40,7 @@ static unsigned int empress_nr[] = {[0 ... (SAA7134_MAXBOARDS - 1)] = UNSET };
module_param_array(empress_nr, int, NULL, 0444);
MODULE_PARM_DESC(empress_nr,"ts device number");
-static unsigned int debug = 0;
+static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages");
@@ -427,8 +427,8 @@ static int empress_init(struct saa7134_dev *dev)
printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
dev->name,dev->empress_dev->minor & 0x1f);
- videobuf_queue_pci_init(&dev->empress_tsq, &saa7134_ts_qops,
- dev->pci, &dev->slock,
+ videobuf_queue_sg_init(&dev->empress_tsq, &saa7134_ts_qops,
+ &dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_ALTERNATE,
sizeof(struct saa7134_buf),
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index d3322c3018f2..ba71dd0040be 100644
--- a/drivers/media/video/saa7134/saa7134-i2c.c
+++ b/drivers/media/video/saa7134/saa7134-i2c.c
@@ -33,11 +33,11 @@
/* ----------------------------------------------------------- */
-static unsigned int i2c_debug = 0;
+static unsigned int i2c_debug;
module_param(i2c_debug, int, 0644);
MODULE_PARM_DESC(i2c_debug,"enable debug messages [i2c]");
-static unsigned int i2c_scan = 0;
+static unsigned int i2c_scan;
module_param(i2c_scan, int, 0444);
MODULE_PARM_DESC(i2c_scan,"scan i2c bus at insmod time");
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index b4188819782f..65f8e594d6fb 100644
--- a/drivers/media/video/saa7134/saa7134-input.c
+++ b/drivers/media/video/saa7134/saa7134-input.c
@@ -27,15 +27,15 @@
#include "saa7134-reg.h"
#include "saa7134.h"
-static unsigned int disable_ir = 0;
+static unsigned int disable_ir;
module_param(disable_ir, int, 0444);
MODULE_PARM_DESC(disable_ir,"disable infrared remote support");
-static unsigned int ir_debug = 0;
+static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
-static int pinnacle_remote = 0;
+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)");
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
index ac6431ba4fc3..86f5eefdb0f6 100644
--- a/drivers/media/video/saa7134/saa7134-reg.h
+++ b/drivers/media/video/saa7134/saa7134-reg.h
@@ -365,6 +365,9 @@
#define SAA7135_DSP_RWSTATE_RDB (1 << 1)
#define SAA7135_DSP_RWSTATE_WRR (1 << 0)
+#define SAA7135_DSP_RWCLEAR 0x586
+#define SAA7135_DSP_RWCLEAR_RERR 1
+
/* ------------------------------------------------------------------ */
/*
* Local variables:
diff --git a/drivers/media/video/saa7134/saa7134-ts.c b/drivers/media/video/saa7134/saa7134-ts.c
index f1b8fcaeb43a..eae72fd60cec 100644
--- a/drivers/media/video/saa7134/saa7134-ts.c
+++ b/drivers/media/video/saa7134/saa7134-ts.c
@@ -32,7 +32,7 @@
/* ------------------------------------------------------------------ */
-static unsigned int ts_debug = 0;
+static unsigned int ts_debug;
module_param(ts_debug, int, 0644);
MODULE_PARM_DESC(ts_debug,"enable debug messages [ts]");
diff --git a/drivers/media/video/saa7134/saa7134-tvaudio.c b/drivers/media/video/saa7134/saa7134-tvaudio.c
index 4e9810469ae3..232af598d947 100644
--- a/drivers/media/video/saa7134/saa7134-tvaudio.c
+++ b/drivers/media/video/saa7134/saa7134-tvaudio.c
@@ -35,18 +35,18 @@
/* ------------------------------------------------------------------ */
-static unsigned int audio_debug = 0;
+static unsigned int audio_debug;
module_param(audio_debug, int, 0644);
MODULE_PARM_DESC(audio_debug,"enable debug messages [tv audio]");
-static unsigned int audio_ddep = 0;
+static unsigned int audio_ddep;
module_param(audio_ddep, int, 0644);
MODULE_PARM_DESC(audio_ddep,"audio ddep overwrite");
static int audio_clock_override = UNSET;
module_param(audio_clock_override, int, 0644);
-static int audio_clock_tweak = 0;
+static int audio_clock_tweak;
module_param(audio_clock_tweak, int, 0644);
MODULE_PARM_DESC(audio_clock_tweak, "Audio clock tick fine tuning for cards with audio crystal that's slightly off (range [-1024 .. 1024])");
@@ -653,6 +653,17 @@ static char *stdres[0x20] = {
#define DSP_RETRY 32
#define DSP_DELAY 16
+#define SAA7135_DSP_RWCLEAR_RERR 1
+
+static inline int saa_dsp_reset_error_bit(struct saa7134_dev *dev)
+{
+ int state = saa_readb(SAA7135_DSP_RWSTATE);
+ if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
+ d2printk("%s: resetting error bit\n", dev->name);
+ saa_writeb(SAA7135_DSP_RWCLEAR, SAA7135_DSP_RWCLEAR_RERR);
+ }
+ return 0;
+}
static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit)
{
@@ -660,8 +671,8 @@ static inline int saa_dsp_wait_bit(struct saa7134_dev *dev, int bit)
state = saa_readb(SAA7135_DSP_RWSTATE);
if (unlikely(state & SAA7135_DSP_RWSTATE_ERR)) {
- printk("%s: dsp access error\n",dev->name);
- /* FIXME: send ack ... */
+ printk(KERN_WARNING "%s: dsp access error\n", dev->name);
+ saa_dsp_reset_error_bit(dev);
return -EIO;
}
while (0 == (state & bit)) {
diff --git a/drivers/media/video/saa7134/saa7134-vbi.c b/drivers/media/video/saa7134/saa7134-vbi.c
index f0d5ed9c2b06..cb0304298a96 100644
--- a/drivers/media/video/saa7134/saa7134-vbi.c
+++ b/drivers/media/video/saa7134/saa7134-vbi.c
@@ -31,7 +31,7 @@
/* ------------------------------------------------------------------ */
-static unsigned int vbi_debug = 0;
+static unsigned int vbi_debug;
module_param(vbi_debug, int, 0644);
MODULE_PARM_DESC(vbi_debug,"enable debug messages [vbi]");
diff --git a/drivers/media/video/saa7134/saa7134-video.c b/drivers/media/video/saa7134/saa7134-video.c
index 39c41ad97d0e..a0baf2d0ba7f 100644
--- a/drivers/media/video/saa7134/saa7134-video.c
+++ b/drivers/media/video/saa7134/saa7134-video.c
@@ -40,7 +40,7 @@
unsigned int video_debug;
static unsigned int gbuffers = 8;
-static unsigned int noninterlaced = 0;
+static unsigned int noninterlaced; /* 0 */
static unsigned int gbufsize = 720*576*4;
static unsigned int gbufsize_max = 720*576*4;
static char secam[] = "--";
@@ -626,13 +626,8 @@ void saa7134_set_tvnorm_hw(struct saa7134_dev *dev)
{
saa7134_set_decoder(dev);
- if (card_in(dev, dev->ctl_input).tv) {
- if ((card(dev).tuner_type == TUNER_PHILIPS_TDA8290)
- && ((card(dev).tuner_config == 1)
- || (card(dev).tuner_config == 2)))
- saa7134_set_gpio(dev, 22, 5);
+ if (card_in(dev, dev->ctl_input).tv)
saa7134_i2c_call_clients(dev, VIDIOC_S_STD, &dev->tvnorm->id);
- }
}
static void set_h_prescale(struct saa7134_dev *dev, int task, int prescale)
@@ -1350,14 +1345,14 @@ static int video_open(struct inode *inode, struct file *file)
fh->height = 576;
v4l2_prio_open(&dev->prio,&fh->prio);
- videobuf_queue_pci_init(&fh->cap, &video_qops,
- dev->pci, &dev->slock,
+ videobuf_queue_sg_init(&fh->cap, &video_qops,
+ &dev->pci->dev, &dev->slock,
V4L2_BUF_TYPE_VIDEO_CAPTURE,
V4L2_FIELD_INTERLACED,
sizeof(struct saa7134_buf),
fh);
- videobuf_queue_pci_init(&fh->vbi, &saa7134_vbi_qops,
- dev->pci, &dev->slock,
+ 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),
diff --git a/drivers/media/video/saa7134/saa7134.h b/drivers/media/video/saa7134/saa7134.h
index f940d0254798..924ffd13637e 100644
--- a/drivers/media/video/saa7134/saa7134.h
+++ b/drivers/media/video/saa7134/saa7134.h
@@ -253,7 +253,17 @@ struct saa7134_format {
#define SAA7134_BOARD_BEHOLD_607_9FM 129
#define SAA7134_BOARD_BEHOLD_M6 130
#define SAA7134_BOARD_TWINHAN_DTV_DVB_3056 131
-#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132
+#define SAA7134_BOARD_GENIUS_TVGO_A11MCE 132
+#define SAA7134_BOARD_PHILIPS_SNAKE 133
+#define SAA7134_BOARD_CREATIX_CTX953 134
+#define SAA7134_BOARD_MSI_TVANYWHERE_AD11 135
+#define SAA7134_BOARD_AVERMEDIA_CARDBUS_506 136
+#define SAA7134_BOARD_AVERMEDIA_A16D 137
+#define SAA7134_BOARD_AVERMEDIA_M115 138
+#define SAA7134_BOARD_VIDEOMATE_T750 139
+#define SAA7134_BOARD_AVERMEDIA_A700_PRO 140
+#define SAA7134_BOARD_AVERMEDIA_A700_HYBRID 141
+
#define SAA7134_MAXBOARDS 8
#define SAA7134_INPUT_MAX 8
@@ -380,9 +390,7 @@ struct saa7134_fh {
unsigned int radio;
enum v4l2_buf_type type;
unsigned int resources;
-#ifdef VIDIOC_G_PRIORITY
enum v4l2_priority prio;
-#endif
/* video overlay */
struct v4l2_window win;
@@ -454,9 +462,7 @@ struct saa7134_dev {
struct list_head devlist;
struct mutex lock;
spinlock_t slock;
-#ifdef VIDIOC_G_PRIORITY
struct v4l2_prio_state prio;
-#endif
/* workstruct for loading modules */
struct work_struct request_module_wk;
@@ -556,7 +562,9 @@ struct saa7134_dev {
#if defined(CONFIG_VIDEO_SAA7134_DVB) || defined(CONFIG_VIDEO_SAA7134_DVB_MODULE)
/* SAA7134_MPEG_DVB only */
struct videobuf_dvb dvb;
- int (*original_demod_sleep)(struct dvb_frontend* fe);
+ int (*original_demod_sleep)(struct dvb_frontend *fe);
+ int (*original_set_voltage)(struct dvb_frontend *fe, fe_sec_voltage_t voltage);
+ int (*original_set_high_voltage)(struct dvb_frontend *fe, long arg);
#endif
};
@@ -594,7 +602,6 @@ extern int saa7134_no_overlay;
void saa7134_track_gpio(struct saa7134_dev *dev, char *msg);
void saa7134_set_gpio(struct saa7134_dev *dev, int bit_no, int value);
-int saa7134_tuner_callback(void *ptr, int command, int arg);
#define SAA7134_PGTABLE_SIZE 4096
@@ -631,6 +638,7 @@ extern struct pci_device_id __devinitdata saa7134_pci_tbl[];
extern int saa7134_board_init1(struct saa7134_dev *dev);
extern int saa7134_board_init2(struct saa7134_dev *dev);
+int saa7134_tuner_callback(void *priv, int command, int arg);
/* ----------------------------------------------------------- */
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 41f70440fd3b..02fda4eecea3 100644
--- a/drivers/media/video/saa7185.c
+++ b/drivers/media/video/saa7185.c
@@ -52,7 +52,7 @@ MODULE_LICENSE("GPL");
#define I2C_NAME(s) (s)->name
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/se401.c b/drivers/media/video/se401.c
index d5d7d6cf734a..7b8cd30437c3 100644
--- a/drivers/media/video/se401.c
+++ b/drivers/media/video/se401.c
@@ -35,7 +35,7 @@ static const char version[] = "0.24";
#include <linux/usb.h>
#include "se401.h"
-static int flickerless=0;
+static int flickerless;
static int video_nr = -1;
static struct usb_device_id device_table [] = {
@@ -1224,7 +1224,9 @@ static const struct file_operations se401_fops = {
.read = se401_read,
.mmap = se401_mmap,
.ioctl = se401_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
static struct video_device se401_template = {
@@ -1279,7 +1281,7 @@ static int se401_init(struct usb_se401 *se401, int button)
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) {
+ if (!(cp[2] & SE401_FORMAT_BAYER)) {
err("Bayer format not supported!");
return 1;
}
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index c40ba3adab21..5748b1e1a128 100644
--- a/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/drivers/media/video/sn9c102/sn9c102_core.c
@@ -464,9 +464,9 @@ sn9c102_i2c_try_read(struct sn9c102_device* cam,
}
-int
-sn9c102_i2c_try_write(struct sn9c102_device* cam,
- const struct sn9c102_sensor* sensor, u8 address, u8 value)
+static int sn9c102_i2c_try_write(struct sn9c102_device* cam,
+ const struct sn9c102_sensor* sensor,
+ u8 address, u8 value)
{
return sn9c102_i2c_try_raw_write(cam, sensor, 3,
sensor->i2c_slave_id, address,
@@ -528,7 +528,7 @@ sn9c102_find_sof_header(struct sn9c102_device* cam, void* mem, size_t len)
/* Search for the SOF marker (fixed part) in the header */
for (j = 0, b=cam->sof.bytesread; j+b < sizeof(marker); j++) {
- if (unlikely(i+j) == len)
+ if (unlikely(i+j == len))
return NULL;
if (*(m+i+j) == marker[cam->sof.bytesread]) {
cam->sof.header[cam->sof.bytesread] = *(m+i+j);
@@ -3224,7 +3224,9 @@ static const struct file_operations sn9c102_fops = {
.open = sn9c102_open,
.release = sn9c102_release,
.ioctl = sn9c102_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.read = sn9c102_read,
.poll = sn9c102_poll,
.mmap = sn9c102_mmap,
@@ -3239,7 +3241,7 @@ sn9c102_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
{
struct usb_device *udev = interface_to_usbdev(intf);
struct sn9c102_device* cam;
- static unsigned int dev_nr = 0;
+ static unsigned int dev_nr;
unsigned int i;
int err = 0, r;
diff --git a/drivers/media/video/sn9c102/sn9c102_sensor.h b/drivers/media/video/sn9c102/sn9c102_sensor.h
index 2d7d786b8430..4af7382da5c5 100644
--- a/drivers/media/video/sn9c102/sn9c102_sensor.h
+++ b/drivers/media/video/sn9c102/sn9c102_sensor.h
@@ -85,9 +85,6 @@ sn9c102_attach_sensor(struct sn9c102_device* cam,
*/
/* The "try" I2C I/O versions are used when probing the sensor */
-extern int sn9c102_i2c_try_write(struct sn9c102_device*,
- const struct sn9c102_sensor*, u8 address,
- u8 value);
extern int sn9c102_i2c_try_read(struct sn9c102_device*,
const struct sn9c102_sensor*, u8 address);
@@ -126,7 +123,7 @@ extern int sn9c102_write_regs(struct sn9c102_device*, const u8 valreg[][2],
Register adresses must be < 256.
*/
#define sn9c102_write_const_regs(sn9c102_device, data...) \
- ({ const static u8 _valreg[][2] = {data}; \
+ ({ static const u8 _valreg[][2] = {data}; \
sn9c102_write_regs(sn9c102_device, _valreg, ARRAY_SIZE(_valreg)); })
/*****************************************************************************/
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
new file mode 100644
index 000000000000..1e921578804f
--- /dev/null
+++ b/drivers/media/video/soc_camera.c
@@ -0,0 +1,1033 @@
+/*
+ * camera image capture (abstract) bus driver
+ *
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This driver provides an interface between platform-specific camera
+ * busses and camera devices. It should be used if the camera is
+ * connected not over a "proper" bus like PCI or USB, but over a
+ * special bus, like, for example, the Quick Capture interface on PXA270
+ * SoCs. Later it should also be used for i.MX31 SoCs from Freescale.
+ * It can handle multiple cameras and / or multiple busses, which can
+ * be used, e.g., in stereo-vision applications.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/list.h>
+#include <linux/err.h>
+#include <linux/mutex.h>
+#include <linux/vmalloc.h>
+
+#include <media/v4l2-common.h>
+#include <media/v4l2-dev.h>
+#include <media/soc_camera.h>
+
+static LIST_HEAD(hosts);
+static LIST_HEAD(devices);
+static DEFINE_MUTEX(list_lock);
+static DEFINE_MUTEX(video_lock);
+
+const static struct soc_camera_data_format*
+format_by_fourcc(struct soc_camera_device *icd, unsigned int fourcc)
+{
+ unsigned int i;
+
+ for (i = 0; i < icd->num_formats; i++)
+ if (icd->formats[i].fourcc == fourcc)
+ return icd->formats + i;
+ return NULL;
+}
+
+static int soc_camera_try_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ enum v4l2_field field;
+ const struct soc_camera_data_format *fmt;
+ int ret;
+
+ WARN_ON(priv != file->private_data);
+
+ fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
+ if (!fmt) {
+ dev_dbg(&icd->dev, "invalid format 0x%08x\n",
+ f->fmt.pix.pixelformat);
+ return -EINVAL;
+ }
+
+ dev_dbg(&icd->dev, "fmt: 0x%08x\n", fmt->fourcc);
+
+ field = f->fmt.pix.field;
+
+ if (field == V4L2_FIELD_ANY) {
+ field = V4L2_FIELD_NONE;
+ } else if (V4L2_FIELD_NONE != field) {
+ dev_err(&icd->dev, "Field type invalid.\n");
+ return -EINVAL;
+ }
+
+ /* test physical bus parameters */
+ ret = ici->ops->try_bus_param(icd, f->fmt.pix.pixelformat);
+ if (ret)
+ return ret;
+
+ /* limit format to hardware capabilities */
+ ret = ici->ops->try_fmt_cap(icd, f);
+
+ /* calculate missing fields */
+ f->fmt.pix.field = field;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+
+ return ret;
+}
+
+static int soc_camera_enum_input(struct file *file, void *priv,
+ struct v4l2_input *inp)
+{
+ if (inp->index != 0)
+ return -EINVAL;
+
+ inp->type = V4L2_INPUT_TYPE_CAMERA;
+ inp->std = V4L2_STD_UNKNOWN;
+ strcpy(inp->name, "Camera");
+
+ return 0;
+}
+
+static int soc_camera_g_input(struct file *file, void *priv, unsigned int *i)
+{
+ *i = 0;
+
+ return 0;
+}
+
+static int soc_camera_s_input(struct file *file, void *priv, unsigned int i)
+{
+ if (i > 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int soc_camera_s_std(struct file *file, void *priv, v4l2_std_id *a)
+{
+ return 0;
+}
+
+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_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+
+ WARN_ON(priv != file->private_data);
+
+ dev_dbg(&icd->dev, "%s: %d\n", __FUNCTION__, p->memory);
+
+ ret = videobuf_reqbufs(&icf->vb_vidq, p);
+ if (ret < 0)
+ return ret;
+
+ return ici->ops->reqbufs(icf, p);
+
+ return ret;
+}
+
+static int soc_camera_querybuf(struct file *file, void *priv,
+ struct v4l2_buffer *p)
+{
+ struct soc_camera_file *icf = file->private_data;
+
+ WARN_ON(priv != file->private_data);
+
+ return videobuf_querybuf(&icf->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;
+
+ WARN_ON(priv != file->private_data);
+
+ return videobuf_qbuf(&icf->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;
+
+ WARN_ON(priv != file->private_data);
+
+ return videobuf_dqbuf(&icf->vb_vidq, p, file->f_flags & O_NONBLOCK);
+}
+
+static int soc_camera_open(struct inode *inode, struct file *file)
+{
+ struct video_device *vdev;
+ struct soc_camera_device *icd;
+ struct soc_camera_host *ici;
+ struct soc_camera_file *icf;
+ spinlock_t *lock;
+ int ret;
+
+ icf = vmalloc(sizeof(*icf));
+ if (!icf)
+ return -ENOMEM;
+
+ /* Protect against icd->remove() until we module_get() both drivers. */
+ mutex_lock(&video_lock);
+
+ vdev = video_devdata(file);
+ icd = container_of(vdev->dev, struct soc_camera_device, dev);
+ ici = to_soc_camera_host(icd->dev.parent);
+
+ if (!try_module_get(icd->ops->owner)) {
+ dev_err(&icd->dev, "Couldn't lock sensor driver.\n");
+ ret = -EINVAL;
+ goto emgd;
+ }
+
+ if (!try_module_get(ici->ops->owner)) {
+ dev_err(&icd->dev, "Couldn't lock capture bus driver.\n");
+ ret = -EINVAL;
+ goto emgi;
+ }
+
+ icf->icd = icd;
+
+ icf->lock = ici->ops->spinlock_alloc(icf);
+ if (!icf->lock) {
+ ret = -ENOMEM;
+ goto esla;
+ }
+
+ icd->use_count++;
+
+ /* Now we really have to activate the camera */
+ if (icd->use_count == 1) {
+ ret = ici->ops->add(icd);
+ if (ret < 0) {
+ dev_err(&icd->dev, "Couldn't activate the camera: %d\n", ret);
+ icd->use_count--;
+ goto eiciadd;
+ }
+ }
+
+ mutex_unlock(&video_lock);
+
+ file->private_data = icf;
+ dev_dbg(&icd->dev, "camera device open\n");
+
+ /* We must pass NULL as dev pointer, then all pci_* dma operations
+ * transform to normal dma_* ones. */
+ videobuf_queue_sg_init(&icf->vb_vidq, ici->vbq_ops, NULL, icf->lock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE, V4L2_FIELD_NONE,
+ ici->msize, icd);
+
+ return 0;
+
+ /* All errors are entered with the video_lock held */
+eiciadd:
+ lock = icf->lock;
+ icf->lock = NULL;
+ if (ici->ops->spinlock_free)
+ ici->ops->spinlock_free(lock);
+esla:
+ module_put(ici->ops->owner);
+emgi:
+ module_put(icd->ops->owner);
+emgd:
+ mutex_unlock(&video_lock);
+ vfree(icf);
+ return ret;
+}
+
+static int soc_camera_close(struct inode *inode, struct file *file)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ struct video_device *vdev = icd->vdev;
+ spinlock_t *lock = icf->lock;
+
+ mutex_lock(&video_lock);
+ icd->use_count--;
+ if (!icd->use_count)
+ ici->ops->remove(icd);
+ icf->lock = NULL;
+ if (ici->ops->spinlock_free)
+ ici->ops->spinlock_free(lock);
+ module_put(icd->ops->owner);
+ module_put(ici->ops->owner);
+ mutex_unlock(&video_lock);
+
+ vfree(icf);
+
+ dev_dbg(vdev->dev, "camera device close\n");
+
+ return 0;
+}
+
+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 video_device *vdev = icd->vdev;
+ int err = -EINVAL;
+
+ dev_err(vdev->dev, "camera device read not implemented\n");
+
+ return err;
+}
+
+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;
+ int err;
+
+ dev_dbg(&icd->dev, "mmap called, vma=0x%08lx\n", (unsigned long)vma);
+
+ err = videobuf_mmap_mapper(&icf->vb_vidq, vma);
+
+ dev_dbg(&icd->dev, "vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end - (unsigned long)vma->vm_start,
+ err);
+
+ return err;
+}
+
+static unsigned int soc_camera_poll(struct file *file, poll_table *pt)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+
+ if (list_empty(&icf->vb_vidq.stream)) {
+ dev_err(&icd->dev, "Trying to poll with no queued buffers!\n");
+ return POLLERR;
+ }
+
+ return ici->ops->poll(file, pt);
+}
+
+
+static struct file_operations soc_camera_fops = {
+ .owner = THIS_MODULE,
+ .open = soc_camera_open,
+ .release = soc_camera_close,
+ .ioctl = video_ioctl2,
+ .read = soc_camera_read,
+ .mmap = soc_camera_mmap,
+ .poll = soc_camera_poll,
+ .llseek = no_llseek,
+};
+
+
+static int soc_camera_s_fmt_cap(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ int ret;
+ struct v4l2_rect rect;
+ const static struct soc_camera_data_format *data_fmt;
+
+ WARN_ON(priv != file->private_data);
+
+ data_fmt = format_by_fourcc(icd, f->fmt.pix.pixelformat);
+ if (!data_fmt)
+ return -EINVAL;
+
+ /* buswidth may be further adjusted by the ici */
+ icd->buswidth = data_fmt->depth;
+
+ ret = soc_camera_try_fmt_cap(file, icf, f);
+ if (ret < 0)
+ return ret;
+
+ rect.left = icd->x_current;
+ rect.top = icd->y_current;
+ rect.width = f->fmt.pix.width;
+ rect.height = f->fmt.pix.height;
+ ret = ici->ops->set_fmt_cap(icd, f->fmt.pix.pixelformat, &rect);
+ if (ret < 0)
+ return ret;
+
+ icd->current_fmt = data_fmt;
+ icd->width = rect.width;
+ icd->height = rect.height;
+ icf->vb_vidq.field = f->fmt.pix.field;
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != f->type)
+ dev_warn(&icd->dev, "Attention! Wrong buf-type %d\n",
+ f->type);
+
+ dev_dbg(&icd->dev, "set width: %d height: %d\n",
+ icd->width, icd->height);
+
+ /* set physical bus parameters */
+ return ici->ops->set_bus_param(icd, f->fmt.pix.pixelformat);
+}
+
+static int soc_camera_enum_fmt_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;
+ const struct soc_camera_data_format *format;
+
+ WARN_ON(priv != file->private_data);
+
+ if (f->index >= icd->num_formats)
+ return -EINVAL;
+
+ format = &icd->formats[f->index];
+
+ strlcpy(f->description, format->name, sizeof(f->description));
+ f->pixelformat = format->fourcc;
+ return 0;
+}
+
+static int soc_camera_g_fmt_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;
+
+ WARN_ON(priv != file->private_data);
+
+ f->fmt.pix.width = icd->width;
+ f->fmt.pix.height = icd->height;
+ f->fmt.pix.field = icf->vb_vidq.field;
+ f->fmt.pix.pixelformat = icd->current_fmt->fourcc;
+ f->fmt.pix.bytesperline =
+ (f->fmt.pix.width * icd->current_fmt->depth) >> 3;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.height * f->fmt.pix.bytesperline;
+ dev_dbg(&icd->dev, "current_fmt->fourcc: 0x%08x\n",
+ icd->current_fmt->fourcc);
+ return 0;
+}
+
+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_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+
+ WARN_ON(priv != file->private_data);
+
+ strlcpy(cap->driver, ici->drv_name, sizeof(cap->driver));
+ return ici->ops->querycap(ici, cap);
+}
+
+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;
+
+ WARN_ON(priv != file->private_data);
+
+ dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ icd->ops->start_capture(icd);
+
+ /* This calls buf_queue from host driver's videobuf_queue_ops */
+ return videobuf_streamon(&icf->vb_vidq);
+}
+
+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;
+
+ WARN_ON(priv != file->private_data);
+
+ dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+
+ if (i != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ /* This calls buf_release from host driver's videobuf_queue_ops for all
+ * remaining buffers. When the last buffer is freed, stop capture */
+ videobuf_streamoff(&icf->vb_vidq);
+
+ icd->ops->stop_capture(icd);
+
+ 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;
+ int i;
+
+ WARN_ON(priv != file->private_data);
+
+ if (!qc->id)
+ return -EINVAL;
+
+ for (i = 0; i < icd->ops->num_controls; i++)
+ if (qc->id == icd->ops->controls[i].id) {
+ memcpy(qc, &(icd->ops->controls[i]),
+ sizeof(*qc));
+ return 0;
+ }
+
+ return -EINVAL;
+}
+
+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;
+
+ WARN_ON(priv != file->private_data);
+
+ switch (ctrl->id) {
+ case V4L2_CID_GAIN:
+ if (icd->gain == (unsigned short)~0)
+ return -EINVAL;
+ ctrl->value = icd->gain;
+ return 0;
+ case V4L2_CID_EXPOSURE:
+ if (icd->exposure == (unsigned short)~0)
+ return -EINVAL;
+ ctrl->value = icd->exposure;
+ return 0;
+ }
+
+ if (icd->ops->get_control)
+ return icd->ops->get_control(icd, ctrl);
+ return -EINVAL;
+}
+
+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;
+
+ WARN_ON(priv != file->private_data);
+
+ if (icd->ops->set_control)
+ return icd->ops->set_control(icd, ctrl);
+ return -EINVAL;
+}
+
+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;
+
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->bounds.left = icd->x_min;
+ a->bounds.top = icd->y_min;
+ a->bounds.width = icd->width_max;
+ a->bounds.height = icd->height_max;
+ a->defrect.left = icd->x_min;
+ a->defrect.top = icd->y_min;
+ a->defrect.width = 640;
+ a->defrect.height = 480;
+ a->pixelaspect.numerator = 1;
+ a->pixelaspect.denominator = 1;
+
+ return 0;
+}
+
+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;
+
+ a->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ a->c.left = icd->x_current;
+ a->c.top = icd->y_current;
+ a->c.width = icd->width;
+ a->c.height = icd->height;
+
+ return 0;
+}
+
+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_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ int ret;
+
+ if (a->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ ret = ici->ops->set_fmt_cap(icd, 0, &a->c);
+ if (!ret) {
+ icd->width = a->c.width;
+ icd->height = a->c.height;
+ icd->x_current = a->c.left;
+ icd->y_current = a->c.top;
+ }
+
+ return ret;
+}
+
+static int soc_camera_g_chip_ident(struct file *file, void *fh,
+ struct v4l2_chip_ident *id)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+
+ if (!icd->ops->get_chip_id)
+ return -EINVAL;
+
+ return icd->ops->get_chip_id(icd, id);
+}
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+static int soc_camera_g_register(struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+
+ if (!icd->ops->get_register)
+ return -EINVAL;
+
+ return icd->ops->get_register(icd, reg);
+}
+
+static int soc_camera_s_register(struct file *file, void *fh,
+ struct v4l2_register *reg)
+{
+ struct soc_camera_file *icf = file->private_data;
+ struct soc_camera_device *icd = icf->icd;
+
+ if (!icd->ops->set_register)
+ return -EINVAL;
+
+ return icd->ops->set_register(icd, reg);
+}
+#endif
+
+static int device_register_link(struct soc_camera_device *icd)
+{
+ int ret = device_register(&icd->dev);
+
+ if (ret < 0) {
+ /* Prevent calling device_unregister() */
+ icd->dev.parent = NULL;
+ dev_err(&icd->dev, "Cannot register device: %d\n", ret);
+ /* Even if probe() was unsuccessful for all registered drivers,
+ * device_register() returns 0, and we add the link, just to
+ * document this camera's control device */
+ } else if (icd->control)
+ /* Have to sysfs_remove_link() before device_unregister()? */
+ if (sysfs_create_link(&icd->dev.kobj, &icd->control->kobj,
+ "control"))
+ dev_warn(&icd->dev,
+ "Failed creating the control symlink\n");
+ return ret;
+}
+
+/* So far this function cannot fail */
+static void scan_add_host(struct soc_camera_host *ici)
+{
+ struct soc_camera_device *icd;
+
+ mutex_lock(&list_lock);
+
+ list_for_each_entry(icd, &devices, list) {
+ if (icd->iface == ici->nr) {
+ icd->dev.parent = &ici->dev;
+ device_register_link(icd);
+ }
+ }
+
+ mutex_unlock(&list_lock);
+}
+
+/* return: 0 if no match found or a match found and
+ * device_register() successful, error code otherwise */
+static int scan_add_device(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici;
+ int ret = 0;
+
+ mutex_lock(&list_lock);
+
+ list_add_tail(&icd->list, &devices);
+
+ /* Watch out for class_for_each_device / class_find_device API by
+ * Dave Young <hidave.darkstar@gmail.com> */
+ list_for_each_entry(ici, &hosts, list) {
+ if (icd->iface == ici->nr) {
+ ret = 1;
+ icd->dev.parent = &ici->dev;
+ break;
+ }
+ }
+
+ mutex_unlock(&list_lock);
+
+ if (ret)
+ ret = device_register_link(icd);
+
+ return ret;
+}
+
+static int soc_camera_probe(struct device *dev)
+{
+ struct soc_camera_device *icd = to_soc_camera_dev(dev);
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ int ret;
+
+ if (!icd->ops->probe)
+ return -ENODEV;
+
+ /* We only call ->add() here to activate and probe the camera.
+ * We shall ->remove() and deactivate it immediately afterwards. */
+ ret = ici->ops->add(icd);
+ if (ret < 0)
+ return ret;
+
+ ret = icd->ops->probe(icd);
+ if (ret >= 0) {
+ const struct v4l2_queryctrl *qctrl;
+
+ qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_GAIN);
+ icd->gain = qctrl ? qctrl->default_value : (unsigned short)~0;
+ qctrl = soc_camera_find_qctrl(icd->ops, V4L2_CID_EXPOSURE);
+ icd->exposure = qctrl ? qctrl->default_value :
+ (unsigned short)~0;
+ }
+ ici->ops->remove(icd);
+
+ return ret;
+}
+
+/* This is called on device_unregister, which only means we have to disconnect
+ * from the host, but not remove ourselves from the device list */
+static int soc_camera_remove(struct device *dev)
+{
+ struct soc_camera_device *icd = to_soc_camera_dev(dev);
+
+ if (icd->ops->remove)
+ icd->ops->remove(icd);
+
+ return 0;
+}
+
+static struct bus_type soc_camera_bus_type = {
+ .name = "soc-camera",
+ .probe = soc_camera_probe,
+ .remove = soc_camera_remove,
+};
+
+static struct device_driver ic_drv = {
+ .name = "camera",
+ .bus = &soc_camera_bus_type,
+ .owner = THIS_MODULE,
+};
+
+/*
+ * Image capture host - this is a host device, not a bus device, so,
+ * no bus reference, no probing.
+ */
+static struct class soc_camera_host_class = {
+ .owner = THIS_MODULE,
+ .name = "camera_host",
+};
+
+static void dummy_release(struct device *dev)
+{
+}
+
+static spinlock_t *spinlock_alloc(struct soc_camera_file *icf)
+{
+ spinlock_t *lock = kmalloc(sizeof(spinlock_t), GFP_KERNEL);
+
+ if (lock)
+ spin_lock_init(lock);
+
+ return lock;
+}
+
+static void spinlock_free(spinlock_t *lock)
+{
+ kfree(lock);
+}
+
+int soc_camera_host_register(struct soc_camera_host *ici)
+{
+ int ret;
+ struct soc_camera_host *ix;
+
+ if (!ici->vbq_ops || !ici->ops->add || !ici->ops->remove)
+ return -EINVAL;
+
+ /* Number might be equal to the platform device ID */
+ sprintf(ici->dev.bus_id, "camera_host%d", ici->nr);
+ ici->dev.class = &soc_camera_host_class;
+
+ mutex_lock(&list_lock);
+ list_for_each_entry(ix, &hosts, list) {
+ if (ix->nr == ici->nr) {
+ mutex_unlock(&list_lock);
+ return -EBUSY;
+ }
+ }
+
+ list_add_tail(&ici->list, &hosts);
+ mutex_unlock(&list_lock);
+
+ ici->dev.release = dummy_release;
+
+ ret = device_register(&ici->dev);
+
+ if (ret)
+ goto edevr;
+
+ if (!ici->ops->spinlock_alloc) {
+ ici->ops->spinlock_alloc = spinlock_alloc;
+ ici->ops->spinlock_free = spinlock_free;
+ }
+
+ scan_add_host(ici);
+
+ return 0;
+
+edevr:
+ mutex_lock(&list_lock);
+ list_del(&ici->list);
+ mutex_unlock(&list_lock);
+
+ return ret;
+}
+EXPORT_SYMBOL(soc_camera_host_register);
+
+/* Unregister all clients! */
+void soc_camera_host_unregister(struct soc_camera_host *ici)
+{
+ struct soc_camera_device *icd;
+
+ mutex_lock(&list_lock);
+
+ list_del(&ici->list);
+
+ list_for_each_entry(icd, &devices, list) {
+ if (icd->dev.parent == &ici->dev) {
+ device_unregister(&icd->dev);
+ /* Not before device_unregister(), .remove
+ * needs parent to call ici->ops->remove() */
+ icd->dev.parent = NULL;
+ memset(&icd->dev.kobj, 0, sizeof(icd->dev.kobj));
+ }
+ }
+
+ mutex_unlock(&list_lock);
+
+ device_unregister(&ici->dev);
+}
+EXPORT_SYMBOL(soc_camera_host_unregister);
+
+/* Image capture device */
+int soc_camera_device_register(struct soc_camera_device *icd)
+{
+ struct soc_camera_device *ix;
+ int num = -1, i;
+
+ if (!icd)
+ return -EINVAL;
+
+ for (i = 0; i < 256 && num < 0; i++) {
+ num = i;
+ list_for_each_entry(ix, &devices, list) {
+ if (ix->iface == icd->iface && ix->devnum == i) {
+ num = -1;
+ break;
+ }
+ }
+ }
+
+ if (num < 0)
+ /* ok, we have 256 cameras on this host...
+ * man, stay reasonable... */
+ return -ENOMEM;
+
+ icd->devnum = num;
+ icd->dev.bus = &soc_camera_bus_type;
+ snprintf(icd->dev.bus_id, sizeof(icd->dev.bus_id),
+ "%u-%u", icd->iface, icd->devnum);
+
+ icd->dev.release = dummy_release;
+
+ return scan_add_device(icd);
+}
+EXPORT_SYMBOL(soc_camera_device_register);
+
+void soc_camera_device_unregister(struct soc_camera_device *icd)
+{
+ mutex_lock(&list_lock);
+ list_del(&icd->list);
+
+ /* The bus->remove will be eventually called */
+ if (icd->dev.parent)
+ device_unregister(&icd->dev);
+ mutex_unlock(&list_lock);
+}
+EXPORT_SYMBOL(soc_camera_device_unregister);
+
+int soc_camera_video_start(struct soc_camera_device *icd)
+{
+ struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
+ int err = -ENOMEM;
+ struct video_device *vdev;
+
+ if (!icd->dev.parent)
+ return -ENODEV;
+
+ vdev = video_device_alloc();
+ if (!vdev)
+ goto evidallocd;
+ dev_dbg(&ici->dev, "Allocated video_device %p\n", vdev);
+
+ strlcpy(vdev->name, ici->drv_name, sizeof(vdev->name));
+ /* Maybe better &ici->dev */
+ vdev->dev = &icd->dev;
+ vdev->type = VID_TYPE_CAPTURE;
+ vdev->current_norm = V4L2_STD_UNKNOWN;
+ vdev->fops = &soc_camera_fops;
+ vdev->release = video_device_release;
+ vdev->minor = -1;
+ vdev->tvnorms = V4L2_STD_UNKNOWN,
+ vdev->vidioc_querycap = soc_camera_querycap;
+ vdev->vidioc_g_fmt_cap = soc_camera_g_fmt_cap;
+ vdev->vidioc_enum_fmt_cap = soc_camera_enum_fmt_cap;
+ vdev->vidioc_s_fmt_cap = soc_camera_s_fmt_cap;
+ vdev->vidioc_enum_input = soc_camera_enum_input;
+ vdev->vidioc_g_input = soc_camera_g_input;
+ vdev->vidioc_s_input = soc_camera_s_input;
+ vdev->vidioc_s_std = soc_camera_s_std;
+ vdev->vidioc_reqbufs = soc_camera_reqbufs;
+ vdev->vidioc_try_fmt_cap = soc_camera_try_fmt_cap;
+ vdev->vidioc_querybuf = soc_camera_querybuf;
+ vdev->vidioc_qbuf = soc_camera_qbuf;
+ vdev->vidioc_dqbuf = soc_camera_dqbuf;
+ vdev->vidioc_streamon = soc_camera_streamon;
+ vdev->vidioc_streamoff = soc_camera_streamoff;
+ vdev->vidioc_queryctrl = soc_camera_queryctrl;
+ vdev->vidioc_g_ctrl = soc_camera_g_ctrl;
+ vdev->vidioc_s_ctrl = soc_camera_s_ctrl;
+ vdev->vidioc_cropcap = soc_camera_cropcap;
+ vdev->vidioc_g_crop = soc_camera_g_crop;
+ vdev->vidioc_s_crop = soc_camera_s_crop;
+ vdev->vidioc_g_chip_ident = soc_camera_g_chip_ident;
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ vdev->vidioc_g_register = soc_camera_g_register;
+ vdev->vidioc_s_register = soc_camera_s_register;
+#endif
+
+ icd->current_fmt = &icd->formats[0];
+
+ err = video_register_device(vdev, VFL_TYPE_GRABBER, vdev->minor);
+ if (err < 0) {
+ dev_err(vdev->dev, "video_register_device failed\n");
+ goto evidregd;
+ }
+ icd->vdev = vdev;
+
+ return 0;
+
+evidregd:
+ video_device_release(vdev);
+evidallocd:
+ return err;
+}
+EXPORT_SYMBOL(soc_camera_video_start);
+
+void soc_camera_video_stop(struct soc_camera_device *icd)
+{
+ struct video_device *vdev = icd->vdev;
+
+ dev_dbg(&icd->dev, "%s\n", __FUNCTION__);
+
+ if (!icd->dev.parent || !vdev)
+ return;
+
+ mutex_lock(&video_lock);
+ video_unregister_device(vdev);
+ icd->vdev = NULL;
+ mutex_unlock(&video_lock);
+}
+EXPORT_SYMBOL(soc_camera_video_stop);
+
+static int __init soc_camera_init(void)
+{
+ int ret = bus_register(&soc_camera_bus_type);
+ if (ret)
+ return ret;
+ ret = driver_register(&ic_drv);
+ if (ret)
+ goto edrvr;
+ ret = class_register(&soc_camera_host_class);
+ if (ret)
+ goto eclr;
+
+ return 0;
+
+eclr:
+ driver_unregister(&ic_drv);
+edrvr:
+ bus_unregister(&soc_camera_bus_type);
+ return ret;
+}
+
+static void __exit soc_camera_exit(void)
+{
+ class_unregister(&soc_camera_host_class);
+ driver_unregister(&ic_drv);
+ bus_unregister(&soc_camera_bus_type);
+}
+
+module_init(soc_camera_init);
+module_exit(soc_camera_exit);
+
+MODULE_DESCRIPTION("Image capture bus driver");
+MODULE_AUTHOR("Guennadi Liakhovetski <kernel@pengutronix.de>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/stk-webcam.c b/drivers/media/video/stk-webcam.c
index ceba45ad0294..d2bf54194b63 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -1465,7 +1465,7 @@ static void stk_camera_disconnect(struct usb_interface *interface)
}
#ifdef CONFIG_PM
-int stk_camera_suspend(struct usb_interface *intf, pm_message_t message)
+static int stk_camera_suspend(struct usb_interface *intf, pm_message_t message)
{
struct stk_camera *dev = usb_get_intfdata(intf);
if (is_streaming(dev)) {
@@ -1476,7 +1476,7 @@ int stk_camera_suspend(struct usb_interface *intf, pm_message_t message)
return 0;
}
-int stk_camera_resume(struct usb_interface *intf)
+static int stk_camera_resume(struct usb_interface *intf)
{
struct stk_camera *dev = usb_get_intfdata(intf);
if (!is_initialised(dev))
diff --git a/drivers/media/video/stradis.c b/drivers/media/video/stradis.c
index 3fb85af5d1f2..c109511f21ea 100644
--- a/drivers/media/video/stradis.c
+++ b/drivers/media/video/stradis.c
@@ -58,7 +58,7 @@
static struct saa7146 saa7146s[SAA7146_MAX];
-static int saa_num = 0; /* number of SAA7146s in use */
+static int saa_num; /* number of SAA7146s in use */
static int video_nr = -1;
module_param(video_nr, int, 0);
@@ -248,7 +248,7 @@ static void I2CBusScan(struct saa7146 *saa)
attach_inform(saa, i);
}
-static int debiwait_maxwait = 0;
+static int debiwait_maxwait;
static int wait_for_debi_done(struct saa7146 *saa)
{
@@ -1906,7 +1906,9 @@ static const struct file_operations saa_fops = {
.open = saa_open,
.release = saa_release,
.ioctl = saa_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.read = saa_read,
.llseek = no_llseek,
.write = saa_write,
diff --git a/drivers/media/video/stv680.c b/drivers/media/video/stv680.c
index afc32aa56fde..78730294454e 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -72,10 +72,13 @@
#include "stv680.h"
static int video_nr = -1;
-static int swapRGB = 0; /* default for auto sleect */
-static int swapRGB_on = 0; /* default to allow auto select; -1=swap never, +1= swap always */
-static unsigned int debug = 0;
+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 { \
@@ -1391,7 +1394,9 @@ static const struct file_operations stv680_fops = {
.read = stv680_read,
.mmap = stv680_mmap,
.ioctl = stv680_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
static struct video_device stv680_template = {
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 55bc89a6f069..89afb19c9468 100644
--- a/drivers/media/video/tda8290.c
+++ b/drivers/media/video/tda8290.c
@@ -32,8 +32,6 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
-#define PREFIX "tda8290"
-
/* ---------------------------------------------------------------------- */
struct tda8290_priv {
@@ -174,7 +172,7 @@ static void tda8290_set_params(struct dvb_frontend *fe,
set_audio(fe, params);
if (priv->cfg.config)
- tuner_dbg("tda827xa config is 0x%02x\n", *priv->cfg.config);
+ tuner_dbg("tda827xa config is 0x%02x\n", priv->cfg.config);
tuner_i2c_xfer_send(&priv->i2c_props, easy_mode, 2);
tuner_i2c_xfer_send(&priv->i2c_props, agc_out_on, 2);
tuner_i2c_xfer_send(&priv->i2c_props, soft_reset, 2);
@@ -444,8 +442,7 @@ static void tda8290_init_if(struct dvb_frontend *fe)
unsigned char set_GP00_CF[] = { 0x20, 0x01 };
unsigned char set_GP01_CF[] = { 0x20, 0x0B };
- if ((priv->cfg.config) &&
- ((*priv->cfg.config == 1) || (*priv->cfg.config == 2)))
+ if ((priv->cfg.config == 1) || (priv->cfg.config == 2))
tuner_i2c_xfer_send(&priv->i2c_props, set_GP00_CF, 2);
else
tuner_i2c_xfer_send(&priv->i2c_props, set_GP01_CF, 2);
@@ -590,8 +587,8 @@ static int tda829x_find_tuner(struct dvb_frontend *fe)
else
priv->ver |= TDA8275A;
- tda827x_attach(fe, priv->tda827x_addr,
- priv->i2c_props.adap, &priv->cfg);
+ tda827x_attach(fe, priv->tda827x_addr, priv->i2c_props.adap, &priv->cfg);
+ priv->cfg.switch_addr = priv->i2c_props.addr;
}
if (fe->ops.tuner_ops.init)
fe->ops.tuner_ops.init(fe);
@@ -674,6 +671,7 @@ struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
priv->i2c_props.addr = i2c_addr;
priv->i2c_props.adap = i2c_adap;
+ priv->i2c_props.name = "tda829x";
if (cfg) {
priv->cfg.config = cfg->lna_cfg;
priv->cfg.tuner_callback = cfg->tuner_callback;
diff --git a/drivers/media/video/tda8290.h b/drivers/media/video/tda8290.h
index dc8ef310b7b2..9dd8b73eb8c6 100644
--- a/drivers/media/video/tda8290.h
+++ b/drivers/media/video/tda8290.h
@@ -21,7 +21,7 @@
#include "dvb_frontend.h"
struct tda829x_config {
- unsigned int *lna_cfg;
+ unsigned int lna_cfg;
int (*tuner_callback) (void *dev, int command, int arg);
unsigned int probe_tuner:1;
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index bdca5d278978..269761ce84a5 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -31,7 +31,7 @@
#include "tda9840.h"
-static int debug = 0; /* insmod parameter */
+static int debug; /* insmod parameter */
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
#define dprintk(args...) \
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 106c93b8203f..a0545ba957b0 100644
--- a/drivers/media/video/tda9887.c
+++ b/drivers/media/video/tda9887.c
@@ -25,10 +25,12 @@ static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
-#define PREFIX "tda9887"
+static DEFINE_MUTEX(tda9887_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
struct tda9887_priv {
struct tuner_i2c_props i2c_props;
+ struct list_head hybrid_tuner_instance_list;
unsigned char data[4];
unsigned int config;
@@ -644,7 +646,15 @@ static int tda9887_set_config(struct dvb_frontend *fe, void *priv_cfg)
static void tda9887_release(struct dvb_frontend *fe)
{
- kfree(fe->analog_demod_priv);
+ struct tda9887_priv *priv = fe->analog_demod_priv;
+
+ mutex_lock(&tda9887_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&tda9887_list_mutex);
+
fe->analog_demod_priv = NULL;
}
@@ -665,17 +675,29 @@ struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
u8 i2c_addr)
{
struct tda9887_priv *priv = NULL;
+ int instance;
- priv = kzalloc(sizeof(struct tda9887_priv), GFP_KERNEL);
- if (priv == NULL)
- return NULL;
- fe->analog_demod_priv = priv;
+ mutex_lock(&tda9887_list_mutex);
- priv->i2c_props.addr = i2c_addr;
- priv->i2c_props.adap = i2c_adap;
- priv->mode = T_STANDBY;
+ instance = hybrid_tuner_request_state(struct tda9887_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c_adap, i2c_addr, "tda9887");
+ switch (instance) {
+ case 0:
+ mutex_unlock(&tda9887_list_mutex);
+ return NULL;
+ break;
+ case 1:
+ fe->analog_demod_priv = priv;
+ priv->mode = T_STANDBY;
+ tuner_info("tda988[5/6/7] found\n");
+ break;
+ default:
+ fe->analog_demod_priv = priv;
+ break;
+ }
- tuner_info("tda988[5/6/7] found\n");
+ mutex_unlock(&tda9887_list_mutex);
memcpy(&fe->ops.analog_ops, &tda9887_ops,
sizeof(struct analog_demod_ops));
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
index 5326eeceaacd..bd5ad549c1df 100644
--- a/drivers/media/video/tea5761.c
+++ b/drivers/media/video/tea5761.c
@@ -14,12 +14,10 @@
#include "tuner-i2c.h"
#include "tea5761.h"
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
-#define PREFIX "tea5761"
-
struct tea5761_priv {
struct tuner_i2c_props i2c_props;
@@ -131,7 +129,7 @@ static void tea5761_status_dump(unsigned char *buffer)
frq = 1000 * (div * 32768 / 1000 + FREQ_OFFSET + 225) / 4; /* Freq in KHz */
- printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
+ printk(KERN_INFO "tea5761: Frequency %d.%03d KHz (divider = 0x%04x)\n",
frq / 1000, frq % 1000, div);
}
@@ -302,6 +300,7 @@ struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
priv->i2c_props.addr = i2c_addr;
priv->i2c_props.adap = i2c_adap;
+ priv->i2c_props.name = "tea5761";
memcpy(&fe->ops.tuner_ops, &tea5761_tuner_ops,
sizeof(struct dvb_tuner_ops));
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index e1b48d87e7b7..833f2768958d 100644
--- a/drivers/media/video/tea5767.c
+++ b/drivers/media/video/tea5767.c
@@ -16,12 +16,10 @@
#include "tuner-i2c.h"
#include "tea5767.h"
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
-#define PREFIX "tea5767"
-
/*****************************************************************************/
struct tea5767_priv {
@@ -137,14 +135,14 @@ static void tea5767_status_dump(struct tea5767_priv *priv,
unsigned int div, frq;
if (TEA5767_READY_FLAG_MASK & buffer[0])
- printk(PREFIX "Ready Flag ON\n");
+ tuner_info("Ready Flag ON\n");
else
- printk(PREFIX "Ready Flag OFF\n");
+ tuner_info("Ready Flag OFF\n");
if (TEA5767_BAND_LIMIT_MASK & buffer[0])
- printk(PREFIX "Tuner at band limit\n");
+ tuner_info("Tuner at band limit\n");
else
- printk(PREFIX "Tuner not at band limit\n");
+ tuner_info("Tuner not at band limit\n");
div = ((buffer[0] & 0x3f) << 8) | buffer[1];
@@ -166,23 +164,23 @@ static void tea5767_status_dump(struct tea5767_priv *priv,
buffer[0] = (div >> 8) & 0x3f;
buffer[1] = div & 0xff;
- printk(PREFIX "Frequency %d.%03d KHz (divider = 0x%04x)\n",
- frq / 1000, frq % 1000, div);
+ tuner_info("Frequency %d.%03d KHz (divider = 0x%04x)\n",
+ frq / 1000, frq % 1000, div);
if (TEA5767_STEREO_MASK & buffer[2])
- printk(PREFIX "Stereo\n");
+ tuner_info("Stereo\n");
else
- printk(PREFIX "Mono\n");
+ tuner_info("Mono\n");
- printk(PREFIX "IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK);
+ tuner_info("IF Counter = %d\n", buffer[2] & TEA5767_IF_CNTR_MASK);
- printk(PREFIX "ADC Level = %d\n",
- (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4);
+ tuner_info("ADC Level = %d\n",
+ (buffer[3] & TEA5767_ADC_LEVEL_MASK) >> 4);
- printk(PREFIX "Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK));
+ tuner_info("Chip ID = %d\n", (buffer[3] & TEA5767_CHIP_ID_MASK));
- printk(PREFIX "Reserved = 0x%02x\n",
- (buffer[4] & TEA5767_RESERVED_MASK));
+ tuner_info("Reserved = 0x%02x\n",
+ (buffer[4] & TEA5767_RESERVED_MASK));
}
/* Freq should be specifyed at 62.5 Hz */
@@ -456,6 +454,8 @@ struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
priv->i2c_props.addr = i2c_addr;
priv->i2c_props.adap = i2c_adap;
+ priv->i2c_props.name = "tea5767";
+
priv->ctrl.xtal_freq = TEA5767_HIGH_LO_32768;
priv->ctrl.port1 = 1;
priv->ctrl.port2 = 1;
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index df2fad9f391e..f22620e1872e 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -33,7 +33,7 @@
#include "tea6415c.h"
-static int debug = 0; /* insmod parameter */
+static int debug; /* insmod parameter */
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
#define dprintk(args...) \
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 4ff6c63f7237..dc0f0405f4c9 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -33,7 +33,7 @@
#include "tea6420.h"
-static int debug = 0; /* insmod parameter */
+static int debug; /* insmod parameter */
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off device debugging (default:off).");
#define dprintk(args...) \
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 78a09a2a4857..225e8f8df1a5 100644
--- a/drivers/media/video/tuner-core.c
+++ b/drivers/media/video/tuner-core.c
@@ -68,9 +68,9 @@ static unsigned short normal_i2c[] = {
I2C_CLIENT_INSMOD;
/* insmod options used at init time => read/only */
-static unsigned int addr = 0;
-static unsigned int no_autodetect = 0;
-static unsigned int show_i2c = 0;
+static unsigned int addr;
+static unsigned int no_autodetect;
+static unsigned int show_i2c;
/* insmod options used at runtime => read/write */
static int tuner_debug;
@@ -313,24 +313,14 @@ static void tuner_i2c_address_check(struct tuner *t)
tuner_warn("output to v4l-dvb-maintainer@linuxtv.org\n");
tuner_warn("Please use subject line: \"obsolete tuner i2c address.\"\n");
tuner_warn("driver: %s, addr: 0x%02x, type: %d (%s)\n",
- t->i2c->adapter->name, t->i2c->addr, t->type,
- tuners[t->type].name);
+ t->i2c->adapter->name, t->i2c->addr, t->type, t->i2c->name);
tuner_warn("====================== WARNING! ======================\n");
}
-static void attach_simple_tuner(struct tuner *t)
-{
- struct simple_tuner_config cfg = {
- .type = t->type,
- .tun = &tuners[t->type]
- };
- simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
-}
-
static void attach_tda829x(struct tuner *t)
{
struct tda829x_config cfg = {
- .lna_cfg = &t->config,
+ .lna_cfg = t->config,
.tuner_callback = t->tuner_callback,
};
tda829x_attach(&t->fe, t->i2c->adapter, t->i2c->addr, &cfg);
@@ -352,11 +342,6 @@ static void set_type(struct i2c_client *c, unsigned int type,
return;
}
- if (type >= tuner_count) {
- tuner_warn ("tuner 0x%02x: Tuner count greater than %d\n",c->addr,tuner_count);
- return;
- }
-
t->type = type;
t->config = new_config;
if (tuner_callback != NULL) {
@@ -409,7 +394,12 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0x54;
i2c_master_send(c, buffer, 4);
- attach_simple_tuner(t);
+ if (simple_tuner_attach(&t->fe, t->i2c->adapter, t->i2c->addr,
+ t->type) == NULL) {
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+ return;
+ }
break;
case TUNER_PHILIPS_TD1316:
buffer[0] = 0x0b;
@@ -417,14 +407,18 @@ static void set_type(struct i2c_client *c, unsigned int type,
buffer[2] = 0x86;
buffer[3] = 0xa4;
i2c_master_send(c,buffer,4);
- attach_simple_tuner(t);
+ if (simple_tuner_attach(&t->fe, t->i2c->adapter,
+ t->i2c->addr, t->type) == NULL) {
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+ return;
+ }
break;
case TUNER_XC2028:
{
struct xc2028_config cfg = {
.i2c_adap = t->i2c->adapter,
.i2c_addr = t->i2c->addr,
- .video_dev = c->adapter->algo_data,
.callback = t->tuner_callback,
};
if (!xc2028_attach(&t->fe, &cfg)) {
@@ -455,7 +449,12 @@ static void set_type(struct i2c_client *c, unsigned int type,
}
break;
default:
- attach_simple_tuner(t);
+ if (simple_tuner_attach(&t->fe, t->i2c->adapter,
+ t->i2c->addr, t->type) == NULL) {
+ t->type = TUNER_ABSENT;
+ t->mode_mask = T_UNINITIALIZED;
+ return;
+ }
break;
}
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
index de52e8ffd347..3ad6c8e0b04c 100644
--- a/drivers/media/video/tuner-i2c.h
+++ b/drivers/media/video/tuner-i2c.h
@@ -26,6 +26,10 @@
struct tuner_i2c_props {
u8 addr;
struct i2c_adapter *adap;
+
+ /* used for tuner instance management */
+ int count;
+ char *name;
};
static inline int tuner_i2c_xfer_send(struct tuner_i2c_props *props, char *buf, int len)
@@ -59,29 +63,111 @@ static inline int tuner_i2c_xfer_send_recv(struct tuner_i2c_props *props,
return (ret == 2) ? ilen : ret;
}
-#define tuner_warn(fmt, arg...) do { \
- printk(KERN_WARNING "%s %d-%04x: " fmt, PREFIX, \
- i2c_adapter_id(priv->i2c_props.adap), \
- priv->i2c_props.addr, ##arg); \
+/* Callers must declare as a global for the module:
+ *
+ * static LIST_HEAD(hybrid_tuner_instance_list);
+ *
+ * hybrid_tuner_instance_list should be the third argument
+ * passed into hybrid_tuner_request_state().
+ *
+ * state structure must contain the following:
+ *
+ * struct list_head hybrid_tuner_instance_list;
+ * struct tuner_i2c_props i2c_props;
+ *
+ * hybrid_tuner_instance_list (both within state structure and globally)
+ * is only required if the driver is using hybrid_tuner_request_state
+ * and hybrid_tuner_release_state to manage state sharing between
+ * multiple instances of hybrid tuners.
+ */
+
+#define tuner_printk(kernlvl, i2cprops, fmt, arg...) do { \
+ printk(kernlvl "%s %d-%04x: " fmt, i2cprops.name, \
+ i2cprops.adap ? \
+ i2c_adapter_id(i2cprops.adap) : -1, \
+ i2cprops.addr, ##arg); \
} while (0)
-#define tuner_info(fmt, arg...) do { \
- printk(KERN_INFO "%s %d-%04x: " fmt, PREFIX, \
- i2c_adapter_id(priv->i2c_props.adap), \
- priv->i2c_props.addr , ##arg); \
+/* TO DO: convert all callers of these macros to pass in
+ * struct tuner_i2c_props, then remove the macro wrappers */
+
+#define __tuner_warn(i2cprops, fmt, arg...) do { \
+ tuner_printk(KERN_WARNING, i2cprops, fmt, ##arg); \
} while (0)
-#define tuner_err(fmt, arg...) do { \
- printk(KERN_ERR "%s %d-%04x: " fmt, PREFIX, \
- i2c_adapter_id(priv->i2c_props.adap), \
- priv->i2c_props.addr , ##arg); \
+#define __tuner_info(i2cprops, fmt, arg...) do { \
+ tuner_printk(KERN_INFO, i2cprops, fmt, ##arg); \
} while (0)
-#define tuner_dbg(fmt, arg...) do { \
+#define __tuner_err(i2cprops, fmt, arg...) do { \
+ tuner_printk(KERN_ERR, i2cprops, fmt, ##arg); \
+ } while (0)
+
+#define __tuner_dbg(i2cprops, fmt, arg...) do { \
if ((debug)) \
- printk(KERN_DEBUG "%s %d-%04x: " fmt, PREFIX, \
- i2c_adapter_id(priv->i2c_props.adap), \
- priv->i2c_props.addr , ##arg); \
+ tuner_printk(KERN_DEBUG, i2cprops, fmt, ##arg); \
} while (0)
+#define tuner_warn(fmt, arg...) __tuner_warn(priv->i2c_props, fmt, ##arg)
+#define tuner_info(fmt, arg...) __tuner_info(priv->i2c_props, fmt, ##arg)
+#define tuner_err(fmt, arg...) __tuner_err(priv->i2c_props, fmt, ##arg)
+#define tuner_dbg(fmt, arg...) __tuner_dbg(priv->i2c_props, fmt, ##arg)
+
+/****************************************************************************/
+
+/* The return value of hybrid_tuner_request_state indicates the number of
+ * instances using this tuner object.
+ *
+ * 0 - no instances, indicates an error - kzalloc must have failed
+ *
+ * 1 - one instance, indicates that the tuner object was created successfully
+ *
+ * 2 (or more) instances, indicates that an existing tuner object was found
+ */
+
+#define hybrid_tuner_request_state(type, state, list, i2cadap, i2caddr, devname)\
+({ \
+ int __ret = 0; \
+ list_for_each_entry(state, &list, hybrid_tuner_instance_list) { \
+ if (((i2cadap) && (state->i2c_props.adap)) && \
+ ((i2c_adapter_id(state->i2c_props.adap) == \
+ i2c_adapter_id(i2cadap)) && \
+ (i2caddr == state->i2c_props.addr))) { \
+ __tuner_info(state->i2c_props, \
+ "attaching existing instance\n"); \
+ state->i2c_props.count++; \
+ __ret = state->i2c_props.count; \
+ break; \
+ } \
+ } \
+ if (0 == __ret) { \
+ state = kzalloc(sizeof(type), GFP_KERNEL); \
+ if (NULL == state) \
+ goto __fail; \
+ state->i2c_props.addr = i2caddr; \
+ state->i2c_props.adap = i2cadap; \
+ state->i2c_props.name = devname; \
+ __tuner_info(state->i2c_props, \
+ "creating new instance\n"); \
+ list_add_tail(&state->hybrid_tuner_instance_list, &list);\
+ state->i2c_props.count++; \
+ __ret = state->i2c_props.count; \
+ } \
+__fail: \
+ __ret; \
+})
+
+#define hybrid_tuner_release_state(state) \
+({ \
+ int __ret; \
+ state->i2c_props.count--; \
+ __ret = state->i2c_props.count; \
+ if (!state->i2c_props.count) { \
+ __tuner_info(state->i2c_props, "destroying instance\n");\
+ list_del(&state->hybrid_tuner_instance_list); \
+ kfree(state); \
+ } \
+ __ret; \
+})
+
#endif /* __TUNER_I2C_H__ */
diff --git a/drivers/media/video/tuner-simple.c b/drivers/media/video/tuner-simple.c
index c1db576696c6..8d6d2c803f92 100644
--- a/drivers/media/video/tuner-simple.c
+++ b/drivers/media/video/tuner-simple.c
@@ -13,15 +13,25 @@
#include "tuner-i2c.h"
#include "tuner-simple.h"
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
-#define PREFIX "tuner-simple"
+#define TUNER_SIMPLE_MAX 64
+static unsigned int simple_devcount;
-static int offset = 0;
+static int offset;
module_param(offset, int, 0664);
-MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
+MODULE_PARM_DESC(offset, "Allows to specify an offset for tuner");
+
+static unsigned int atv_input[TUNER_SIMPLE_MAX] = \
+ { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
+static unsigned int dtv_input[TUNER_SIMPLE_MAX] = \
+ { [0 ... (TUNER_SIMPLE_MAX-1)] = 0 };
+module_param_array(atv_input, int, NULL, 0644);
+module_param_array(dtv_input, int, NULL, 0644);
+MODULE_PARM_DESC(atv_input, "specify atv rf input, 0 for autoselect");
+MODULE_PARM_DESC(dtv_input, "specify dtv rf input, 0 for autoselect");
/* ---------------------------------------------------------------------- */
@@ -36,8 +46,8 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
*/
#define TEMIC_SET_PAL_I 0x05
#define TEMIC_SET_PAL_DK 0x09
-#define TEMIC_SET_PAL_L 0x0a // SECAM ?
-#define TEMIC_SET_PAL_L2 0x0b // change IF !
+#define TEMIC_SET_PAL_L 0x0a /* SECAM ? */
+#define TEMIC_SET_PAL_L2 0x0b /* change IF ! */
#define TEMIC_SET_PAL_BG 0x0c
/* tv tuner system standard selection for Philips FQ1216ME
@@ -90,14 +100,21 @@ MODULE_PARM_DESC(offset,"Allows to specify an offset for tuner");
#define TUNER_PLL_LOCKED 0x40
#define TUNER_STEREO_MK3 0x04
+static DEFINE_MUTEX(tuner_simple_list_mutex);
+static LIST_HEAD(hybrid_tuner_instance_list);
+
struct tuner_simple_priv {
+ unsigned int nr;
u16 last_div;
+
struct tuner_i2c_props i2c_props;
+ struct list_head hybrid_tuner_instance_list;
unsigned int type;
struct tunertype *tun;
u32 frequency;
+ u32 bandwidth;
};
/* ---------------------------------------------------------------------- */
@@ -107,7 +124,7 @@ static int tuner_read_status(struct dvb_frontend *fe)
struct tuner_simple_priv *priv = fe->tuner_priv;
unsigned char byte;
- if (1 != tuner_i2c_xfer_recv(&priv->i2c_props,&byte,1))
+ if (1 != tuner_i2c_xfer_recv(&priv->i2c_props, &byte, 1))
return 0;
return byte;
@@ -121,13 +138,13 @@ static inline int tuner_signal(const int status)
static inline int tuner_stereo(const int type, const int status)
{
switch (type) {
- case TUNER_PHILIPS_FM1216ME_MK3:
- case TUNER_PHILIPS_FM1236_MK3:
- case TUNER_PHILIPS_FM1256_IH3:
- case TUNER_LG_NTSC_TAPE:
- return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
- default:
- return status & TUNER_STEREO;
+ case TUNER_PHILIPS_FM1216ME_MK3:
+ case TUNER_PHILIPS_FM1236_MK3:
+ case TUNER_PHILIPS_FM1256_IH3:
+ case TUNER_LG_NTSC_TAPE:
+ return ((status & TUNER_SIGNAL) == TUNER_STEREO_MK3);
+ default:
+ return status & TUNER_STEREO;
}
}
@@ -145,7 +162,12 @@ static inline int tuner_afcstatus(const int status)
static int simple_get_status(struct dvb_frontend *fe, u32 *status)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
- int tuner_status = tuner_read_status(fe);
+ int tuner_status;
+
+ if (priv->i2c_props.adap == NULL)
+ return -EINVAL;
+
+ tuner_status = tuner_read_status(fe);
*status = 0;
@@ -162,7 +184,12 @@ static int simple_get_status(struct dvb_frontend *fe, u32 *status)
static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
{
struct tuner_simple_priv *priv = fe->tuner_priv;
- int signal = tuner_signal(tuner_read_status(fe));
+ int signal;
+
+ if (priv->i2c_props.adap == NULL)
+ return -EINVAL;
+
+ signal = tuner_signal(tuner_read_status(fe));
*strength = signal;
@@ -173,174 +200,378 @@ static int simple_get_rf_strength(struct dvb_frontend *fe, u16 *strength)
/* ---------------------------------------------------------------------- */
-static int simple_set_tv_freq(struct dvb_frontend *fe,
- struct analog_parameters *params)
+static inline char *tuner_param_name(enum param_type type)
{
- struct tuner_simple_priv *priv = fe->tuner_priv;
- u8 config, cb, tuneraddr;
- u16 div;
- struct tunertype *tun;
- u8 buffer[4];
- int rc, IFPCoff, i, j;
- enum param_type desired_type;
- struct tuner_params *t_params;
+ char *name;
- tun = priv->tun;
+ switch (type) {
+ case TUNER_PARAM_TYPE_RADIO:
+ name = "radio";
+ break;
+ case TUNER_PARAM_TYPE_PAL:
+ name = "pal";
+ break;
+ case TUNER_PARAM_TYPE_SECAM:
+ name = "secam";
+ break;
+ case TUNER_PARAM_TYPE_NTSC:
+ name = "ntsc";
+ break;
+ case TUNER_PARAM_TYPE_DIGITAL:
+ name = "digital";
+ break;
+ default:
+ name = "unknown";
+ break;
+ }
+ return name;
+}
- /* IFPCoff = Video Intermediate Frequency - Vif:
- 940 =16*58.75 NTSC/J (Japan)
- 732 =16*45.75 M/N STD
- 704 =16*44 ATSC (at DVB code)
- 632 =16*39.50 I U.K.
- 622.4=16*38.90 B/G D/K I, L STD
- 592 =16*37.00 D China
- 590 =16.36.875 B Australia
- 543.2=16*33.95 L' STD
- 171.2=16*10.70 FM Radio (at set_radio_freq)
- */
+static struct tuner_params *simple_tuner_params(struct dvb_frontend *fe,
+ enum param_type desired_type)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ struct tunertype *tun = priv->tun;
+ int i;
- if (params->std == V4L2_STD_NTSC_M_JP) {
- IFPCoff = 940;
- desired_type = TUNER_PARAM_TYPE_NTSC;
- } else if ((params->std & V4L2_STD_MN) &&
- !(params->std & ~V4L2_STD_MN)) {
- IFPCoff = 732;
- desired_type = TUNER_PARAM_TYPE_NTSC;
- } else if (params->std == V4L2_STD_SECAM_LC) {
- IFPCoff = 543;
- desired_type = TUNER_PARAM_TYPE_SECAM;
- } else {
- IFPCoff = 623;
- desired_type = TUNER_PARAM_TYPE_PAL;
- }
+ for (i = 0; i < tun->count; i++)
+ if (desired_type == tun->params[i].type)
+ break;
- for (j = 0; j < tun->count-1; j++) {
- if (desired_type != tun->params[j].type)
- continue;
- break;
- }
- /* use default tuner_t_params if desired_type not available */
- if (desired_type != tun->params[j].type) {
- tuner_dbg("IFPCoff = %d: tuner_t_params undefined for tuner %d\n",
- IFPCoff, priv->type);
- j = 0;
+ /* use default tuner params if desired_type not available */
+ if (i == tun->count) {
+ tuner_dbg("desired params (%s) undefined for tuner %d\n",
+ tuner_param_name(desired_type), priv->type);
+ i = 0;
}
- t_params = &tun->params[j];
+
+ tuner_dbg("using tuner params #%d (%s)\n", i,
+ tuner_param_name(tun->params[i].type));
+
+ return &tun->params[i];
+}
+
+static int simple_config_lookup(struct dvb_frontend *fe,
+ struct tuner_params *t_params,
+ int *frequency, u8 *config, u8 *cb)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int i;
for (i = 0; i < t_params->count; i++) {
- if (params->frequency > t_params->ranges[i].limit)
+ if (*frequency > t_params->ranges[i].limit)
continue;
break;
}
if (i == t_params->count) {
- tuner_dbg("TV frequency out of range (%d > %d)",
- params->frequency, t_params->ranges[i - 1].limit);
- params->frequency = t_params->ranges[--i].limit;
+ tuner_dbg("frequency out of range (%d > %d)\n",
+ *frequency, t_params->ranges[i - 1].limit);
+ *frequency = t_params->ranges[--i].limit;
}
- config = t_params->ranges[i].config;
- cb = t_params->ranges[i].cb;
- /* i == 0 -> VHF_LO
- * i == 1 -> VHF_HI
- * i == 2 -> UHF */
- tuner_dbg("tv: param %d, range %d\n",j,i);
+ *config = t_params->ranges[i].config;
+ *cb = t_params->ranges[i].cb;
+
+ tuner_dbg("freq = %d.%02d (%d), range = %d, "
+ "config = 0x%02x, cb = 0x%02x\n",
+ *frequency / 16, *frequency % 16 * 100 / 16, *frequency,
+ i, *config, *cb);
+
+ return i;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void simple_set_rf_input(struct dvb_frontend *fe,
+ u8 *config, u8 *cb, unsigned int rf)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
- div=params->frequency + IFPCoff + offset;
+ switch (priv->type) {
+ case TUNER_PHILIPS_TUV1236D:
+ switch (rf) {
+ case 1:
+ *cb |= 0x08;
+ break;
+ default:
+ *cb &= ~0x08;
+ break;
+ }
+ break;
+ case TUNER_PHILIPS_FCV1236D:
+ switch (rf) {
+ case 1:
+ *cb |= 0x01;
+ break;
+ default:
+ *cb &= ~0x01;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
- tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, Offset=%d.%02d MHz, div=%0d\n",
- params->frequency / 16, params->frequency % 16 * 100 / 16,
- IFPCoff / 16, IFPCoff % 16 * 100 / 16,
- offset / 16, offset % 16 * 100 / 16,
- div);
+static int simple_std_setup(struct dvb_frontend *fe,
+ struct analog_parameters *params,
+ u8 *config, u8 *cb)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ u8 tuneraddr;
+ int rc;
/* tv norm specific stuff for multi-norm tuners */
switch (priv->type) {
- case TUNER_PHILIPS_SECAM: // FI1216MF
+ case TUNER_PHILIPS_SECAM: /* FI1216MF */
/* 0x01 -> ??? no change ??? */
/* 0x02 -> PAL BDGHI / SECAM L */
/* 0x04 -> ??? PAL others / SECAM others ??? */
- cb &= ~0x03;
- if (params->std & V4L2_STD_SECAM_L) //also valid for V4L2_STD_SECAM
- cb |= PHILIPS_MF_SET_STD_L;
+ *cb &= ~0x03;
+ if (params->std & V4L2_STD_SECAM_L)
+ /* also valid for V4L2_STD_SECAM */
+ *cb |= PHILIPS_MF_SET_STD_L;
else if (params->std & V4L2_STD_SECAM_LC)
- cb |= PHILIPS_MF_SET_STD_LC;
+ *cb |= PHILIPS_MF_SET_STD_LC;
else /* V4L2_STD_B|V4L2_STD_GH */
- cb |= PHILIPS_MF_SET_STD_BG;
+ *cb |= PHILIPS_MF_SET_STD_BG;
break;
case TUNER_TEMIC_4046FM5:
- cb &= ~0x0f;
+ *cb &= ~0x0f;
if (params->std & V4L2_STD_PAL_BG) {
- cb |= TEMIC_SET_PAL_BG;
+ *cb |= TEMIC_SET_PAL_BG;
} else if (params->std & V4L2_STD_PAL_I) {
- cb |= TEMIC_SET_PAL_I;
+ *cb |= TEMIC_SET_PAL_I;
} else if (params->std & V4L2_STD_PAL_DK) {
- cb |= TEMIC_SET_PAL_DK;
+ *cb |= TEMIC_SET_PAL_DK;
} else if (params->std & V4L2_STD_SECAM_L) {
- cb |= TEMIC_SET_PAL_L;
+ *cb |= TEMIC_SET_PAL_L;
}
break;
case TUNER_PHILIPS_FQ1216ME:
- cb &= ~0x0f;
+ *cb &= ~0x0f;
if (params->std & (V4L2_STD_PAL_BG|V4L2_STD_PAL_DK)) {
- cb |= PHILIPS_SET_PAL_BGDK;
+ *cb |= PHILIPS_SET_PAL_BGDK;
} else if (params->std & V4L2_STD_PAL_I) {
- cb |= PHILIPS_SET_PAL_I;
+ *cb |= PHILIPS_SET_PAL_I;
} else if (params->std & V4L2_STD_SECAM_L) {
- cb |= PHILIPS_SET_PAL_L;
+ *cb |= PHILIPS_SET_PAL_L;
}
break;
- case TUNER_PHILIPS_ATSC:
+ case TUNER_PHILIPS_FCV1236D:
/* 0x00 -> ATSC antenna input 1 */
/* 0x01 -> ATSC antenna input 2 */
/* 0x02 -> NTSC antenna input 1 */
/* 0x03 -> NTSC antenna input 2 */
- cb &= ~0x03;
+ *cb &= ~0x03;
if (!(params->std & V4L2_STD_ATSC))
- cb |= 2;
- /* FIXME: input */
+ *cb |= 2;
break;
case TUNER_MICROTUNE_4042FI5:
/* Set the charge pump for fast tuning */
- config |= TUNER_CHARGE_PUMP;
+ *config |= TUNER_CHARGE_PUMP;
break;
case TUNER_PHILIPS_TUV1236D:
+ {
/* 0x40 -> ATSC antenna input 1 */
/* 0x48 -> ATSC antenna input 2 */
/* 0x00 -> NTSC antenna input 1 */
/* 0x08 -> NTSC antenna input 2 */
- buffer[0] = 0x14;
- buffer[1] = 0x00;
- buffer[2] = 0x17;
- buffer[3] = 0x00;
- cb &= ~0x40;
+ u8 buffer[4] = { 0x14, 0x00, 0x17, 0x00};
+ *cb &= ~0x40;
if (params->std & V4L2_STD_ATSC) {
- cb |= 0x40;
+ *cb |= 0x40;
buffer[1] = 0x04;
}
/* set to the correct mode (analog or digital) */
tuneraddr = priv->i2c_props.addr;
priv->i2c_props.addr = 0x0a;
- if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[0],2)))
- tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
- if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,&buffer[2],2)))
- tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2);
+ if (2 != rc)
+ tuner_warn("i2c i/o error: rc == %d "
+ "(should be 2)\n", rc);
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2);
+ if (2 != rc)
+ tuner_warn("i2c i/o error: rc == %d "
+ "(should be 2)\n", rc);
priv->i2c_props.addr = tuneraddr;
- /* FIXME: input */
break;
}
+ }
+ if (atv_input[priv->nr])
+ simple_set_rf_input(fe, config, cb, atv_input[priv->nr]);
+
+ return 0;
+}
+
+static int simple_post_tune(struct dvb_frontend *fe, u8 *buffer,
+ u16 div, u8 config, u8 cb)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ int rc;
+
+ switch (priv->type) {
+ case TUNER_LG_TDVS_H06XF:
+ /* Set the Auxiliary Byte. */
+ buffer[0] = buffer[2];
+ buffer[0] &= ~0x20;
+ buffer[0] |= 0x18;
+ buffer[1] = 0x20;
+ tuner_dbg("tv 0x%02x 0x%02x\n", buffer[0], buffer[1]);
+
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 2);
+ if (2 != rc)
+ tuner_warn("i2c i/o error: rc == %d "
+ "(should be 2)\n", rc);
+ break;
+ case TUNER_MICROTUNE_4042FI5:
+ {
+ /* FIXME - this may also work for other tuners */
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
+ u8 status_byte = 0;
+
+ /* Wait until the PLL locks */
+ for (;;) {
+ if (time_after(jiffies, timeout))
+ return 0;
+ rc = tuner_i2c_xfer_recv(&priv->i2c_props,
+ &status_byte, 1);
+ if (1 != rc) {
+ tuner_warn("i2c i/o read error: rc == %d "
+ "(should be 1)\n", rc);
+ break;
+ }
+ if (status_byte & TUNER_PLL_LOCKED)
+ break;
+ udelay(10);
+ }
+
+ /* Set the charge pump for optimized phase noise figure */
+ config &= ~TUNER_CHARGE_PUMP;
+ buffer[0] = (div>>8) & 0x7f;
+ buffer[1] = div & 0xff;
+ buffer[2] = config;
+ buffer[3] = cb;
+ tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
+ buffer[0], buffer[1], buffer[2], buffer[3]);
+
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+ if (4 != rc)
+ tuner_warn("i2c i/o error: rc == %d "
+ "(should be 4)\n", rc);
+ break;
+ }
+ }
+
+ return 0;
+}
+
+static int simple_radio_bandswitch(struct dvb_frontend *fe, u8 *buffer)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+
+ switch (priv->type) {
+ case TUNER_TENA_9533_DI:
+ case TUNER_YMEC_TVF_5533MF:
+ tuner_dbg("This tuner doesn't have FM. "
+ "Most cards have a TEA5767 for FM\n");
+ return 0;
+ case TUNER_PHILIPS_FM1216ME_MK3:
+ case TUNER_PHILIPS_FM1236_MK3:
+ case TUNER_PHILIPS_FMD1216ME_MK3:
+ case TUNER_LG_NTSC_TAPE:
+ case TUNER_PHILIPS_FM1256_IH3:
+ buffer[3] = 0x19;
+ break;
+ case TUNER_TNF_5335MF:
+ buffer[3] = 0x11;
+ break;
+ case TUNER_LG_PAL_FM:
+ buffer[3] = 0xa5;
+ break;
+ case TUNER_THOMSON_DTT761X:
+ buffer[3] = 0x39;
+ break;
+ case TUNER_MICROTUNE_4049FM5:
+ default:
+ buffer[3] = 0xa4;
+ break;
+ }
+
+ return 0;
+}
+
+/* ---------------------------------------------------------------------- */
+
+static int simple_set_tv_freq(struct dvb_frontend *fe,
+ struct analog_parameters *params)
+{
+ 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
+ 704 =16*44 ATSC (at DVB code)
+ 632 =16*39.50 I U.K.
+ 622.4=16*38.90 B/G D/K I, L STD
+ 592 =16*37.00 D China
+ 590 =16.36.875 B Australia
+ 543.2=16*33.95 L' STD
+ 171.2=16*10.70 FM Radio (at set_radio_freq)
+ */
+
+ if (params->std == V4L2_STD_NTSC_M_JP) {
+ IFPCoff = 940;
+ desired_type = TUNER_PARAM_TYPE_NTSC;
+ } else if ((params->std & V4L2_STD_MN) &&
+ !(params->std & ~V4L2_STD_MN)) {
+ IFPCoff = 732;
+ desired_type = TUNER_PARAM_TYPE_NTSC;
+ } else if (params->std == V4L2_STD_SECAM_LC) {
+ IFPCoff = 543;
+ desired_type = TUNER_PARAM_TYPE_SECAM;
+ } else {
+ IFPCoff = 623;
+ desired_type = TUNER_PARAM_TYPE_PAL;
+ }
+
+ t_params = simple_tuner_params(fe, desired_type);
+
+ i = simple_config_lookup(fe, t_params, &params->frequency,
+ &config, &cb);
+
+ div = params->frequency + IFPCoff + offset;
+
+ tuner_dbg("Freq= %d.%02d MHz, V_IF=%d.%02d MHz, "
+ "Offset=%d.%02d MHz, div=%0d\n",
+ params->frequency / 16, params->frequency % 16 * 100 / 16,
+ IFPCoff / 16, IFPCoff % 16 * 100 / 16,
+ offset / 16, offset % 16 * 100 / 16, div);
+
+ /* tv norm specific stuff for multi-norm tuners */
+ simple_std_setup(fe, params, &config, &cb);
if (t_params->cb_first_if_lower_freq && div < priv->last_div) {
buffer[0] = config;
@@ -357,8 +588,10 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
if (t_params->has_tda9887) {
struct v4l2_priv_tun_config tda9887_cfg;
int config = 0;
- int is_secam_l = (params->std & (V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC)) &&
- !(params->std & ~(V4L2_STD_SECAM_L | V4L2_STD_SECAM_LC));
+ int is_secam_l = (params->std & (V4L2_STD_SECAM_L |
+ V4L2_STD_SECAM_LC)) &&
+ !(params->std & ~(V4L2_STD_SECAM_L |
+ V4L2_STD_SECAM_LC));
tda9887_cfg.tuner = TUNER_TDA9887;
tda9887_cfg.priv = &config;
@@ -368,8 +601,7 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
config |= TDA9887_PORT1_ACTIVE;
if (t_params->port2_active ^ t_params->port2_invert_for_secam_lc)
config |= TDA9887_PORT2_ACTIVE;
- }
- else {
+ } else {
if (t_params->port1_active)
config |= TDA9887_PORT1_ACTIVE;
if (t_params->port2_active)
@@ -384,8 +616,7 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
config |= TDA9887_TOP(t_params->default_top_secam_mid);
else if (t_params->default_top_secam_high)
config |= TDA9887_TOP(t_params->default_top_secam_high);
- }
- else {
+ } else {
if (i == 0 && t_params->default_top_low)
config |= TDA9887_TOP(t_params->default_top_low);
else if (i == 1 && t_params->default_top_mid)
@@ -399,56 +630,14 @@ static int simple_set_tv_freq(struct dvb_frontend *fe,
&tda9887_cfg);
}
tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0],buffer[1],buffer[2],buffer[3]);
-
- if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
- tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
-
- switch (priv->type) {
- case TUNER_LG_TDVS_H06XF:
- /* Set the Auxiliary Byte. */
- buffer[0] = buffer[2];
- buffer[0] &= ~0x20;
- buffer[0] |= 0x18;
- buffer[1] = 0x20;
- tuner_dbg("tv 0x%02x 0x%02x\n",buffer[0],buffer[1]);
-
- if (2 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,2)))
- tuner_warn("i2c i/o error: rc == %d (should be 2)\n",rc);
- break;
- case TUNER_MICROTUNE_4042FI5:
- {
- // FIXME - this may also work for other tuners
- unsigned long timeout = jiffies + msecs_to_jiffies(1);
- u8 status_byte = 0;
+ buffer[0], buffer[1], buffer[2], buffer[3]);
- /* Wait until the PLL locks */
- for (;;) {
- if (time_after(jiffies,timeout))
- return 0;
- if (1 != (rc = tuner_i2c_xfer_recv(&priv->i2c_props,&status_byte,1))) {
- tuner_warn("i2c i/o read error: rc == %d (should be 1)\n",rc);
- break;
- }
- if (status_byte & TUNER_PLL_LOCKED)
- break;
- udelay(10);
- }
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+ if (4 != rc)
+ tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
- /* Set the charge pump for optimized phase noise figure */
- config &= ~TUNER_CHARGE_PUMP;
- buffer[0] = (div>>8) & 0x7f;
- buffer[1] = div & 0xff;
- buffer[2] = config;
- buffer[3] = cb;
- tuner_dbg("tv 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0],buffer[1],buffer[2],buffer[3]);
+ simple_post_tune(fe, &buffer[0], div, config, cb);
- if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
- tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
- break;
- }
- }
return 0;
}
@@ -483,37 +672,13 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
freq += (unsigned int)(41.3*16000);
break;
default:
- tuner_warn("Unsupported radio_if value %d\n", t_params->radio_if);
+ tuner_warn("Unsupported radio_if value %d\n",
+ t_params->radio_if);
return 0;
}
/* Bandswitch byte */
- switch (priv->type) {
- case TUNER_TENA_9533_DI:
- case TUNER_YMEC_TVF_5533MF:
- tuner_dbg("This tuner doesn't have FM. Most cards have a TEA5767 for FM\n");
- return 0;
- case TUNER_PHILIPS_FM1216ME_MK3:
- case TUNER_PHILIPS_FM1236_MK3:
- case TUNER_PHILIPS_FMD1216ME_MK3:
- case TUNER_LG_NTSC_TAPE:
- case TUNER_PHILIPS_FM1256_IH3:
- buffer[3] = 0x19;
- break;
- case TUNER_TNF_5335MF:
- buffer[3] = 0x11;
- break;
- case TUNER_LG_PAL_FM:
- buffer[3] = 0xa5;
- break;
- case TUNER_THOMSON_DTT761X:
- buffer[3] = 0x39;
- break;
- case TUNER_MICROTUNE_4049FM5:
- default:
- buffer[3] = 0xa4;
- break;
- }
+ simple_radio_bandswitch(fe, &buffer[0]);
buffer[2] = (t_params->ranges[0].config & ~TUNER_RATIO_MASK) |
TUNER_RATIO_SELECT_50; /* 50 kHz step */
@@ -534,7 +699,7 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
}
tuner_dbg("radio 0x%02x 0x%02x 0x%02x 0x%02x\n",
- buffer[0],buffer[1],buffer[2],buffer[3]);
+ buffer[0], buffer[1], buffer[2], buffer[3]);
priv->last_div = div;
if (t_params->has_tda9887) {
@@ -544,9 +709,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
tda9887_cfg.tuner = TUNER_TDA9887;
tda9887_cfg.priv = &config;
- if (t_params->port1_active && !t_params->port1_fm_high_sensitivity)
+ if (t_params->port1_active &&
+ !t_params->port1_fm_high_sensitivity)
config |= TDA9887_PORT1_ACTIVE;
- if (t_params->port2_active && !t_params->port2_fm_high_sensitivity)
+ if (t_params->port2_active &&
+ !t_params->port2_fm_high_sensitivity)
config |= TDA9887_PORT2_ACTIVE;
if (t_params->intercarrier_mode)
config |= TDA9887_INTERCARRIER;
@@ -557,10 +724,11 @@ static int simple_set_radio_freq(struct dvb_frontend *fe,
if (t_params->radio_if == 2)
config |= TDA9887_RIF_41_3;
i2c_clients_command(priv->i2c_props.adap, TUNER_SET_CONFIG,
- &tda9887_cfg);
+ &tda9887_cfg);
}
- if (4 != (rc = tuner_i2c_xfer_send(&priv->i2c_props,buffer,4)))
- tuner_warn("i2c i/o error: rc == %d (should be 4)\n",rc);
+ rc = tuner_i2c_xfer_send(&priv->i2c_props, buffer, 4);
+ if (4 != rc)
+ tuner_warn("i2c i/o error: rc == %d (should be 4)\n", rc);
return 0;
}
@@ -571,6 +739,9 @@ static int simple_set_params(struct dvb_frontend *fe,
struct tuner_simple_priv *priv = fe->tuner_priv;
int ret = -EINVAL;
+ if (priv->i2c_props.adap == NULL)
+ return -EINVAL;
+
switch (params->mode) {
case V4L2_TUNER_RADIO:
ret = simple_set_radio_freq(fe, params);
@@ -582,14 +753,210 @@ static int simple_set_params(struct dvb_frontend *fe,
priv->frequency = params->frequency * 62500;
break;
}
+ priv->bandwidth = 0;
return ret;
}
+static void simple_set_dvb(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+
+ switch (priv->type) {
+ case TUNER_PHILIPS_FMD1216ME_MK3:
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ &&
+ params->frequency >= 158870000)
+ buf[3] |= 0x08;
+ break;
+ case TUNER_PHILIPS_TD1316:
+ /* determine band */
+ buf[3] |= (params->frequency < 161000000) ? 1 :
+ (params->frequency < 444000000) ? 2 : 4;
+
+ /* setup PLL filter */
+ if (params->u.ofdm.bandwidth == BANDWIDTH_8_MHZ)
+ buf[3] |= 1 << 3;
+ break;
+ case TUNER_PHILIPS_TUV1236D:
+ case TUNER_PHILIPS_FCV1236D:
+ {
+ unsigned int new_rf;
+
+ if (dtv_input[priv->nr])
+ new_rf = dtv_input[priv->nr];
+ else
+ switch (params->u.vsb.modulation) {
+ case QAM_64:
+ case QAM_256:
+ new_rf = 1;
+ break;
+ case VSB_8:
+ default:
+ new_rf = 0;
+ break;
+ }
+ simple_set_rf_input(fe, &buf[2], &buf[3], new_rf);
+ break;
+ }
+ default:
+ break;
+ }
+}
+
+static u32 simple_dvb_configure(struct dvb_frontend *fe, u8 *buf,
+ const struct dvb_frontend_parameters *params)
+{
+ /* This function returns the tuned frequency on success, 0 on error */
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ struct tunertype *tun = priv->tun;
+ static struct tuner_params *t_params;
+ u8 config, cb;
+ u32 div;
+ int ret, frequency = params->frequency / 62500;
+
+ t_params = simple_tuner_params(fe, TUNER_PARAM_TYPE_DIGITAL);
+ ret = simple_config_lookup(fe, t_params, &frequency, &config, &cb);
+ if (ret < 0)
+ return 0; /* failure */
+
+ div = ((frequency + t_params->iffreq) * 62500 + offset +
+ tun->stepsize/2) / tun->stepsize;
+
+ buf[0] = div >> 8;
+ buf[1] = div & 0xff;
+ buf[2] = config;
+ buf[3] = cb;
+
+ simple_set_dvb(fe, buf, params);
+
+ tuner_dbg("%s: div=%d | buf=0x%02x,0x%02x,0x%02x,0x%02x\n",
+ tun->name, div, buf[0], buf[1], buf[2], buf[3]);
+
+ /* calculate the frequency we set it to */
+ return (div * tun->stepsize) - t_params->iffreq;
+}
+
+static int simple_dvb_calc_regs(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ u8 *buf, int buf_len)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ u32 frequency;
+
+ if (buf_len < 5)
+ return -EINVAL;
+
+ frequency = simple_dvb_configure(fe, buf+1, params);
+ if (frequency == 0)
+ return -EINVAL;
+
+ buf[0] = priv->i2c_props.addr;
+
+ priv->frequency = frequency;
+ priv->bandwidth = (fe->ops.info.type == FE_OFDM) ?
+ params->u.ofdm.bandwidth : 0;
+
+ return 5;
+}
+
+static int simple_dvb_set_params(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ u32 prev_freq, prev_bw;
+ int ret;
+ u8 buf[5];
+
+ if (priv->i2c_props.adap == NULL)
+ return -EINVAL;
+
+ prev_freq = priv->frequency;
+ prev_bw = priv->bandwidth;
+
+ ret = simple_dvb_calc_regs(fe, params, buf, 5);
+ if (ret != 5)
+ goto fail;
+
+ /* put analog demod in standby when tuning digital */
+ if (fe->ops.analog_ops.standby)
+ fe->ops.analog_ops.standby(fe);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ /* buf[0] contains the i2c address, but *
+ * we already have it in i2c_props.addr */
+ ret = tuner_i2c_xfer_send(&priv->i2c_props, buf+1, 4);
+ if (ret != 4)
+ goto fail;
+
+ return 0;
+fail:
+ /* calc_regs sets frequency and bandwidth. if we failed, unset them */
+ priv->frequency = prev_freq;
+ priv->bandwidth = prev_bw;
+
+ return ret;
+}
+
+static int simple_init(struct dvb_frontend *fe)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+
+ if (priv->i2c_props.adap == NULL)
+ return -EINVAL;
+
+ if (priv->tun->initdata) {
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = tuner_i2c_xfer_send(&priv->i2c_props,
+ priv->tun->initdata + 1,
+ priv->tun->initdata[0]);
+ if (ret != priv->tun->initdata[0])
+ return ret;
+ }
+
+ return 0;
+}
+
+static int simple_sleep(struct dvb_frontend *fe)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+
+ if (priv->i2c_props.adap == NULL)
+ return -EINVAL;
+
+ if (priv->tun->sleepdata) {
+ int ret;
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ ret = tuner_i2c_xfer_send(&priv->i2c_props,
+ priv->tun->sleepdata + 1,
+ priv->tun->sleepdata[0]);
+ if (ret != priv->tun->sleepdata[0])
+ return ret;
+ }
+
+ return 0;
+}
static int simple_release(struct dvb_frontend *fe)
{
- kfree(fe->tuner_priv);
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+
+ mutex_lock(&tuner_simple_list_mutex);
+
+ if (priv)
+ hybrid_tuner_release_state(priv);
+
+ mutex_unlock(&tuner_simple_list_mutex);
+
fe->tuner_priv = NULL;
return 0;
@@ -602,10 +969,22 @@ static int simple_get_frequency(struct dvb_frontend *fe, u32 *frequency)
return 0;
}
+static int simple_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ struct tuner_simple_priv *priv = fe->tuner_priv;
+ *bandwidth = priv->bandwidth;
+ return 0;
+}
+
static struct dvb_tuner_ops simple_tuner_ops = {
+ .init = simple_init,
+ .sleep = simple_sleep,
.set_analog_params = simple_set_params,
+ .set_params = simple_dvb_set_params,
+ .calc_regs = simple_dvb_calc_regs,
.release = simple_release,
.get_frequency = simple_get_frequency,
+ .get_bandwidth = simple_get_bandwidth,
.get_status = simple_get_status,
.get_rf_strength = simple_get_rf_strength,
};
@@ -613,30 +992,92 @@ static struct dvb_tuner_ops simple_tuner_ops = {
struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr,
- struct simple_tuner_config *cfg)
+ unsigned int type)
{
struct tuner_simple_priv *priv = NULL;
+ int instance;
- priv = kzalloc(sizeof(struct tuner_simple_priv), GFP_KERNEL);
- if (priv == NULL)
+ if (type >= tuner_count) {
+ printk(KERN_WARNING "%s: invalid tuner type: %d (max: %d)\n",
+ __FUNCTION__, type, tuner_count-1);
return NULL;
- fe->tuner_priv = priv;
+ }
- priv->i2c_props.addr = i2c_addr;
- priv->i2c_props.adap = i2c_adap;
- priv->type = cfg->type;
- priv->tun = cfg->tun;
+ /* If i2c_adap is set, check that the tuner is at the correct address.
+ * Otherwise, if i2c_adap is NULL, the tuner will be programmed directly
+ * by the digital demod via calc_regs.
+ */
+ if (i2c_adap != NULL) {
+ u8 b[1];
+ struct i2c_msg msg = {
+ .addr = i2c_addr, .flags = I2C_M_RD,
+ .buf = b, .len = 1,
+ };
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ if (1 != i2c_transfer(i2c_adap, &msg, 1))
+ tuner_warn("unable to probe %s, proceeding anyway.",
+ tuners[type].name);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
- memcpy(&fe->ops.tuner_ops, &simple_tuner_ops, sizeof(struct dvb_tuner_ops));
+ mutex_lock(&tuner_simple_list_mutex);
- tuner_info("type set to %d (%s)\n", cfg->type, cfg->tun->name);
+ instance = hybrid_tuner_request_state(struct tuner_simple_priv, priv,
+ hybrid_tuner_instance_list,
+ i2c_adap, i2c_addr,
+ "tuner-simple");
+ switch (instance) {
+ case 0:
+ mutex_unlock(&tuner_simple_list_mutex);
+ return NULL;
+ break;
+ case 1:
+ fe->tuner_priv = priv;
- strlcpy(fe->ops.tuner_ops.info.name, cfg->tun->name, sizeof(fe->ops.tuner_ops.info.name));
+ priv->type = type;
+ priv->tun = &tuners[type];
+ priv->nr = simple_devcount++;
+ break;
+ default:
+ fe->tuner_priv = priv;
+ break;
+ }
- return fe;
-}
+ mutex_unlock(&tuner_simple_list_mutex);
+
+ memcpy(&fe->ops.tuner_ops, &simple_tuner_ops,
+ sizeof(struct dvb_tuner_ops));
+
+ tuner_info("type set to %d (%s)\n", type, priv->tun->name);
+
+ if ((debug) || ((atv_input[priv->nr] > 0) ||
+ (dtv_input[priv->nr] > 0))) {
+ if (0 == atv_input[priv->nr])
+ tuner_info("tuner %d atv rf input will be "
+ "autoselected\n", priv->nr);
+ else
+ tuner_info("tuner %d atv rf input will be "
+ "set to input %d (insmod option)\n",
+ priv->nr, atv_input[priv->nr]);
+ if (0 == dtv_input[priv->nr])
+ tuner_info("tuner %d dtv rf input will be "
+ "autoselected\n", priv->nr);
+ else
+ tuner_info("tuner %d dtv rf input will be "
+ "set to input %d (insmod option)\n",
+ priv->nr, dtv_input[priv->nr]);
+ }
+ strlcpy(fe->ops.tuner_ops.info.name, priv->tun->name,
+ sizeof(fe->ops.tuner_ops.info.name));
+ return fe;
+}
EXPORT_SYMBOL_GPL(simple_tuner_attach);
MODULE_DESCRIPTION("Simple 4-control-bytes style tuner driver");
diff --git a/drivers/media/video/tuner-simple.h b/drivers/media/video/tuner-simple.h
index 9089939a8c02..bf425f325f87 100644
--- a/drivers/media/video/tuner-simple.h
+++ b/drivers/media/video/tuner-simple.h
@@ -20,23 +20,16 @@
#include <linux/i2c.h>
#include "dvb_frontend.h"
-struct simple_tuner_config
-{
- /* chip type */
- unsigned int type;
- struct tunertype *tun;
-};
-
#if defined(CONFIG_TUNER_SIMPLE) || (defined(CONFIG_TUNER_SIMPLE_MODULE) && defined(MODULE))
extern struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr,
- struct simple_tuner_config *cfg);
+ unsigned int type);
#else
static inline struct dvb_frontend *simple_tuner_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr,
- struct simple_tuner_config *cfg)
+ unsigned int type)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
return NULL;
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 883047f9c28c..10dddca8b5d1 100644
--- a/drivers/media/video/tuner-types.c
+++ b/drivers/media/video/tuner-types.c
@@ -35,6 +35,27 @@
* based on the video standard in use.
*/
+/* The following was taken from dvb-pll.c: */
+
+/* Set AGC TOP value to 103 dBuV:
+ * 0x80 = Control Byte
+ * 0x40 = 250 uA charge pump (irrelevant)
+ * 0x18 = Aux Byte to follow
+ * 0x06 = 64.5 kHz divider (irrelevant)
+ * 0x01 = Disable Vt (aka sleep)
+ *
+ * 0x00 = AGC Time constant 2s Iagc = 300 nA (vs 0x80 = 9 nA)
+ * 0x50 = AGC Take over point = 103 dBuV
+ */
+static u8 tua603x_agc103[] = { 2, 0x80|0x40|0x18|0x06|0x01, 0x00|0x50 };
+
+/* 0x04 = 166.67 kHz divider
+ *
+ * 0x80 = AGC Time constant 50ms Iagc = 9 uA
+ * 0x20 = AGC Take over point = 112 dBuV
+ */
+static u8 tua603x_agc112[] = { 2, 0x80|0x40|0x18|0x04|0x01, 0x80|0x20 };
+
/* 0-9 */
/* ------------ TUNER_TEMIC_PAL - TEMIC PAL ------------ */
@@ -594,19 +615,31 @@ static struct tuner_params tuner_philips_pal_mk_params[] = {
},
};
-/* ---- TUNER_PHILIPS_ATSC - Philips FCV1236D (ATSC/NTSC) ---- */
+/* ---- TUNER_PHILIPS_FCV1236D - Philips FCV1236D (ATSC/NTSC) ---- */
-static struct tuner_range tuner_philips_fcv1236d_ranges[] = {
- { 16 * 157.25 /*MHz*/, 0x8e, 0xa0, },
- { 16 * 451.25 /*MHz*/, 0x8e, 0x90, },
+static struct tuner_range tuner_philips_fcv1236d_ntsc_ranges[] = {
+ { 16 * 157.25 /*MHz*/, 0x8e, 0xa2, },
+ { 16 * 451.25 /*MHz*/, 0x8e, 0x92, },
+ { 16 * 999.99 , 0x8e, 0x32, },
+};
+
+static struct tuner_range tuner_philips_fcv1236d_atsc_ranges[] = {
+ { 16 * 159.00 /*MHz*/, 0x8e, 0xa0, },
+ { 16 * 453.00 /*MHz*/, 0x8e, 0x90, },
{ 16 * 999.99 , 0x8e, 0x30, },
};
static struct tuner_params tuner_philips_fcv1236d_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
- .ranges = tuner_philips_fcv1236d_ranges,
- .count = ARRAY_SIZE(tuner_philips_fcv1236d_ranges),
+ .ranges = tuner_philips_fcv1236d_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fcv1236d_ntsc_ranges),
+ },
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_philips_fcv1236d_atsc_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fcv1236d_atsc_ranges),
+ .iffreq = 16 * 44.00,
},
};
@@ -701,12 +734,24 @@ static struct tuner_range tuner_microtune_4042fi5_ntsc_ranges[] = {
{ 16 * 999.99 , 0x8e, 0x31, },
};
+static struct tuner_range tuner_microtune_4042fi5_atsc_ranges[] = {
+ { 16 * 162.00 /*MHz*/, 0x8e, 0xa1, },
+ { 16 * 457.00 /*MHz*/, 0x8e, 0x91, },
+ { 16 * 999.99 , 0x8e, 0x31, },
+};
+
static struct tuner_params tuner_microtune_4042fi5_params[] = {
{
.type = TUNER_PARAM_TYPE_NTSC,
.ranges = tuner_microtune_4042fi5_ntsc_ranges,
.count = ARRAY_SIZE(tuner_microtune_4042fi5_ntsc_ranges),
},
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_microtune_4042fi5_atsc_ranges,
+ .count = ARRAY_SIZE(tuner_microtune_4042fi5_atsc_ranges),
+ .iffreq = 16 * 44.00 /*MHz*/,
+ },
};
/* 50-59 */
@@ -740,6 +785,7 @@ static struct tuner_params tuner_philips_fm1256_ih3_params[] = {
/* ------------ TUNER_THOMSON_DTT7610 - THOMSON ATSC ------------ */
+/* single range used for both ntsc and atsc */
static struct tuner_range tuner_thomson_dtt7610_ntsc_ranges[] = {
{ 16 * 157.25 /*MHz*/, 0x8e, 0x39, },
{ 16 * 454.00 /*MHz*/, 0x8e, 0x3a, },
@@ -752,6 +798,12 @@ static struct tuner_params tuner_thomson_dtt7610_params[] = {
.ranges = tuner_thomson_dtt7610_ntsc_ranges,
.count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
},
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_thomson_dtt7610_ntsc_ranges,
+ .count = ARRAY_SIZE(tuner_thomson_dtt7610_ntsc_ranges),
+ .iffreq = 16 * 44.00 /*MHz*/,
+ },
};
/* ------------ TUNER_PHILIPS_FQ1286 - Philips NTSC ------------ */
@@ -855,6 +907,11 @@ static struct tuner_range tuner_thomson_dtt761x_ntsc_ranges[] = {
{ 16 * 999.99 , 0x8e, 0x3c, },
};
+static struct tuner_range tuner_thomson_dtt761x_atsc_ranges[] = {
+ { 16 * 147.00 /*MHz*/, 0x8e, 0x39, },
+ { 16 * 417.00 /*MHz*/, 0x8e, 0x3a, },
+ { 16 * 999.99 , 0x8e, 0x3c, },
+};
static struct tuner_params tuner_thomson_dtt761x_params[] = {
{
@@ -865,6 +922,12 @@ static struct tuner_params tuner_thomson_dtt761x_params[] = {
.fm_gain_normal = 1,
.radio_if = 2, /* 41.3 MHz */
},
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_thomson_dtt761x_atsc_ranges,
+ .count = ARRAY_SIZE(tuner_thomson_dtt761x_atsc_ranges),
+ .iffreq = 16 * 44.00, /*MHz*/
+ },
};
/* ------------ TUNER_TENA_9533_DI - Philips PAL ------------ */
@@ -891,6 +954,15 @@ static struct tuner_range tuner_philips_fmd1216me_mk3_pal_ranges[] = {
{ 16 * 999.99 , 0x86, 0x54, },
};
+static struct tuner_range tuner_philips_fmd1216me_mk3_dvb_ranges[] = {
+ { 16 * 143.87 /*MHz*/, 0xbc, 0x41 },
+ { 16 * 158.87 /*MHz*/, 0xf4, 0x41 },
+ { 16 * 329.87 /*MHz*/, 0xbc, 0x42 },
+ { 16 * 441.87 /*MHz*/, 0xf4, 0x42 },
+ { 16 * 625.87 /*MHz*/, 0xbc, 0x44 },
+ { 16 * 803.87 /*MHz*/, 0xf4, 0x44 },
+ { 16 * 999.99 , 0xfc, 0x44 },
+};
static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
{
@@ -904,6 +976,12 @@ static struct tuner_params tuner_philips_fmd1216me_mk3_params[] = {
.port2_invert_for_secam_lc = 1,
.port1_set_for_fm_mono = 1,
},
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_philips_fmd1216me_mk3_dvb_ranges,
+ .count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_dvb_ranges),
+ .iffreq = 16 * 36.125, /*MHz*/
+ },
};
@@ -915,6 +993,11 @@ static struct tuner_range tuner_tua6034_ntsc_ranges[] = {
{ 16 * 999.99 , 0x8e, 0x04 },
};
+static struct tuner_range tuner_tua6034_atsc_ranges[] = {
+ { 16 * 165.00 /*MHz*/, 0xce, 0x01 },
+ { 16 * 450.00 /*MHz*/, 0xce, 0x02 },
+ { 16 * 999.99 , 0xce, 0x04 },
+};
static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
{
@@ -922,6 +1005,12 @@ static struct tuner_params tuner_lg_tdvs_h06xf_params[] = {
.ranges = tuner_tua6034_ntsc_ranges,
.count = ARRAY_SIZE(tuner_tua6034_ntsc_ranges),
},
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_tua6034_atsc_ranges,
+ .count = ARRAY_SIZE(tuner_tua6034_atsc_ranges),
+ .iffreq = 16 * 44.00,
+ },
};
/* ------------ TUNER_YMEC_TVF66T5_B_DFF - Philips PAL ------------ */
@@ -974,12 +1063,30 @@ static struct tuner_range tuner_philips_td1316_pal_ranges[] = {
{ 16 * 999.99 , 0xc8, 0xa4, },
};
+static struct tuner_range tuner_philips_td1316_dvb_ranges[] = {
+ { 16 * 93.834 /*MHz*/, 0xca, 0x60, },
+ { 16 * 123.834 /*MHz*/, 0xca, 0xa0, },
+ { 16 * 163.834 /*MHz*/, 0xca, 0xc0, },
+ { 16 * 253.834 /*MHz*/, 0xca, 0x60, },
+ { 16 * 383.834 /*MHz*/, 0xca, 0xa0, },
+ { 16 * 443.834 /*MHz*/, 0xca, 0xc0, },
+ { 16 * 583.834 /*MHz*/, 0xca, 0x60, },
+ { 16 * 793.834 /*MHz*/, 0xca, 0xa0, },
+ { 16 * 999.999 , 0xca, 0xe0, },
+};
+
static struct tuner_params tuner_philips_td1316_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
.ranges = tuner_philips_td1316_pal_ranges,
.count = ARRAY_SIZE(tuner_philips_td1316_pal_ranges),
},
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_philips_td1316_dvb_ranges,
+ .count = ARRAY_SIZE(tuner_philips_td1316_dvb_ranges),
+ .iffreq = 16 * 36.166667 /*MHz*/,
+ },
};
/* ------------ TUNER_PHILIPS_TUV1236D - Philips ATSC ------------ */
@@ -990,6 +1097,11 @@ static struct tuner_range tuner_tuv1236d_ntsc_ranges[] = {
{ 16 * 999.99 , 0xce, 0x04, },
};
+static struct tuner_range tuner_tuv1236d_atsc_ranges[] = {
+ { 16 * 157.25 /*MHz*/, 0xc6, 0x41, },
+ { 16 * 454.00 /*MHz*/, 0xc6, 0x42, },
+ { 16 * 999.99 , 0xc6, 0x44, },
+};
static struct tuner_params tuner_tuv1236d_params[] = {
{
@@ -997,6 +1109,12 @@ static struct tuner_params tuner_tuv1236d_params[] = {
.ranges = tuner_tuv1236d_ntsc_ranges,
.count = ARRAY_SIZE(tuner_tuv1236d_ntsc_ranges),
},
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_tuv1236d_atsc_ranges,
+ .count = ARRAY_SIZE(tuner_tuv1236d_atsc_ranges),
+ .iffreq = 16 * 44.00,
+ },
};
/* ------------ TUNER_TNF_xxx5 - Texas Instruments--------- */
@@ -1050,17 +1168,30 @@ static struct tuner_params tuner_samsung_tcpn_2121p30a_params[] = {
/* ------------ TUNER_THOMSON_FE6600 - DViCO Hybrid PAL ------------ */
-static struct tuner_range tuner_thomson_fe6600_ranges[] = {
+static struct tuner_range tuner_thomson_fe6600_pal_ranges[] = {
{ 16 * 160.00 /*MHz*/, 0xfe, 0x11, },
{ 16 * 442.00 /*MHz*/, 0xf6, 0x12, },
{ 16 * 999.99 , 0xf6, 0x18, },
};
+static struct tuner_range tuner_thomson_fe6600_dvb_ranges[] = {
+ { 16 * 250.00 /*MHz*/, 0xb4, 0x12, },
+ { 16 * 455.00 /*MHz*/, 0xfe, 0x11, },
+ { 16 * 775.50 /*MHz*/, 0xbc, 0x18, },
+ { 16 * 999.99 , 0xf4, 0x18, },
+};
+
static struct tuner_params tuner_thomson_fe6600_params[] = {
{
.type = TUNER_PARAM_TYPE_PAL,
- .ranges = tuner_thomson_fe6600_ranges,
- .count = ARRAY_SIZE(tuner_thomson_fe6600_ranges),
+ .ranges = tuner_thomson_fe6600_pal_ranges,
+ .count = ARRAY_SIZE(tuner_thomson_fe6600_pal_ranges),
+ },
+ {
+ .type = TUNER_PARAM_TYPE_DIGITAL,
+ .ranges = tuner_thomson_fe6600_dvb_ranges,
+ .count = ARRAY_SIZE(tuner_thomson_fe6600_dvb_ranges),
+ .iffreq = 16 * 36.125 /*MHz*/,
},
};
@@ -1303,10 +1434,13 @@ struct tunertype tuners[] = {
.params = tuner_philips_pal_mk_params,
.count = ARRAY_SIZE(tuner_philips_pal_mk_params),
},
- [TUNER_PHILIPS_ATSC] = { /* Philips ATSC */
+ [TUNER_PHILIPS_FCV1236D] = { /* Philips ATSC */
.name = "Philips FCV1236D ATSC/NTSC dual in",
.params = tuner_philips_fcv1236d_params,
.count = ARRAY_SIZE(tuner_philips_fcv1236d_params),
+ .min = 16 * 53.00,
+ .max = 16 * 803.00,
+ .stepsize = 62500,
},
[TUNER_PHILIPS_FM1236_MK3] = { /* Philips NTSC */
.name = "Philips NTSC MK3 (FM1236MK3 or FM1236/F)",
@@ -1342,6 +1476,9 @@ struct tunertype tuners[] = {
.name = "Microtune 4042 FI5 ATSC/NTSC dual in",
.params = tuner_microtune_4042fi5_params,
.count = ARRAY_SIZE(tuner_microtune_4042fi5_params),
+ .min = 16 * 57.00,
+ .max = 16 * 858.00,
+ .stepsize = 62500,
},
/* 50-59 */
@@ -1359,6 +1496,9 @@ struct tunertype tuners[] = {
.name = "Thomson DTT 7610 (ATSC/NTSC)",
.params = tuner_thomson_dtt7610_params,
.count = ARRAY_SIZE(tuner_thomson_dtt7610_params),
+ .min = 16 * 44.00,
+ .max = 16 * 958.00,
+ .stepsize = 62500,
},
[TUNER_PHILIPS_FQ1286] = { /* Philips NTSC */
.name = "Philips FQ1286",
@@ -1400,6 +1540,10 @@ struct tunertype tuners[] = {
.name = "Thomson DTT 761X (ATSC/NTSC)",
.params = tuner_thomson_dtt761x_params,
.count = ARRAY_SIZE(tuner_thomson_dtt761x_params),
+ .min = 16 * 57.00,
+ .max = 16 * 863.00,
+ .stepsize = 62500,
+ .initdata = tua603x_agc103,
},
[TUNER_TENA_9533_DI] = { /* Philips PAL */
.name = "Tena TNF9533-D/IF/TNF9533-B/DF",
@@ -1414,11 +1558,20 @@ struct tunertype tuners[] = {
.name = "Philips FMD1216ME MK3 Hybrid Tuner",
.params = tuner_philips_fmd1216me_mk3_params,
.count = ARRAY_SIZE(tuner_philips_fmd1216me_mk3_params),
+ .min = 16 * 50.87,
+ .max = 16 * 858.00,
+ .stepsize = 166667,
+ .initdata = tua603x_agc112,
+ .sleepdata = (u8[]){ 4, 0x9c, 0x60, 0x85, 0x54 },
},
[TUNER_LG_TDVS_H06XF] = { /* LGINNOTEK ATSC */
.name = "LG TDVS-H06xF", /* H061F, H062F & H064F */
.params = tuner_lg_tdvs_h06xf_params,
.count = ARRAY_SIZE(tuner_lg_tdvs_h06xf_params),
+ .min = 16 * 54.00,
+ .max = 16 * 863.00,
+ .stepsize = 62500,
+ .initdata = tua603x_agc103,
},
[TUNER_YMEC_TVF66T5_B_DFF] = { /* Philips PAL */
.name = "Ymec TVF66T5-B/DFF",
@@ -1434,11 +1587,17 @@ struct tunertype tuners[] = {
.name = "Philips TD1316 Hybrid Tuner",
.params = tuner_philips_td1316_params,
.count = ARRAY_SIZE(tuner_philips_td1316_params),
+ .min = 16 * 87.00,
+ .max = 16 * 895.00,
+ .stepsize = 166667,
},
[TUNER_PHILIPS_TUV1236D] = { /* Philips ATSC */
.name = "Philips TUV1236D ATSC/NTSC dual in",
.params = tuner_tuv1236d_params,
.count = ARRAY_SIZE(tuner_tuv1236d_params),
+ .min = 16 * 54.00,
+ .max = 16 * 864.00,
+ .stepsize = 62500,
},
[TUNER_TNF_5335MF] = { /* Tenna PAL/NTSC */
.name = "Tena TNF 5335 and similar models",
@@ -1460,6 +1619,9 @@ struct tunertype tuners[] = {
.name = "Thomson FE6600",
.params = tuner_thomson_fe6600_params,
.count = ARRAY_SIZE(tuner_thomson_fe6600_params),
+ .min = 16 * 44.25,
+ .max = 16 * 858.00,
+ .stepsize = 166667,
},
[TUNER_SAMSUNG_TCPG_6121P30A] = { /* Samsung PAL */
.name = "Samsung TCPG 6121P30A",
@@ -1480,5 +1642,11 @@ struct tunertype tuners[] = {
/* see xc5000.c for details */
},
};
+EXPORT_SYMBOL(tuners);
unsigned const int tuner_count = ARRAY_SIZE(tuners);
+EXPORT_SYMBOL(tuner_count);
+
+MODULE_DESCRIPTION("Simple tuner device type database");
+MODULE_AUTHOR("Ralph Metzler, Gerd Knorr, Gunther Mayer");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index 50cf876f020f..098a9956a2bc 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -23,8 +23,6 @@
#include "dvb_frontend.h"
-#define PREFIX "xc2028"
-
static int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "enable verbose debug messages");
@@ -43,6 +41,11 @@ MODULE_PARM_DESC(audio_std,
"NICAM/A\n"
"NICAM/B\n");
+static char firmware_name[FIRMWARE_NAME_MAX];
+module_param_string(firmware_name, firmware_name, sizeof(firmware_name), 0);
+MODULE_PARM_DESC(firmware_name, "Firmware file name. Allows overriding the "
+ "default firmware name\n");
+
static LIST_HEAD(xc2028_list);
static DEFINE_MUTEX(xc2028_list_mutex);
@@ -145,7 +148,7 @@ static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
}
#define dump_firm_type(t) dump_firm_type_and_int_freq(t, 0)
-void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
+static void dump_firm_type_and_int_freq(unsigned int type, u16 int_freq)
{
if (type & BASE)
printk("BASE ");
@@ -255,19 +258,24 @@ static int load_all_firmwares(struct dvb_frontend *fe)
int rc = 0;
int n, n_array;
char name[33];
+ char *fname;
tuner_dbg("%s called\n", __FUNCTION__);
- tuner_dbg("Reading firmware %s\n", priv->ctrl.fname);
- rc = request_firmware(&fw, priv->ctrl.fname,
- &priv->i2c_props.adap->dev);
+ if (!firmware_name[0])
+ fname = priv->ctrl.fname;
+ else
+ fname = firmware_name;
+
+ tuner_dbg("Reading firmware %s\n", fname);
+ rc = request_firmware(&fw, fname, &priv->i2c_props.adap->dev);
if (rc < 0) {
if (rc == -ENOENT)
tuner_err("Error: firmware %s not found.\n",
- priv->ctrl.fname);
+ fname);
else
tuner_err("Error %d while requesting firmware %s \n",
- rc, priv->ctrl.fname);
+ rc, fname);
return rc;
}
@@ -276,7 +284,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
if (fw->size < sizeof(name) - 1 + 2 + 2) {
tuner_err("Error: firmware file %s has invalid size!\n",
- priv->ctrl.fname);
+ fname);
goto corrupt;
}
@@ -291,7 +299,7 @@ static int load_all_firmwares(struct dvb_frontend *fe)
p += 2;
tuner_info("Loading %d firmware images from %s, type: %s, ver %d.%d\n",
- n_array, priv->ctrl.fname, name,
+ n_array, fname, name,
priv->firm_version >> 8, priv->firm_version & 0xff);
priv->firm = kzalloc(sizeof(*priv->firm) * n_array, GFP_KERNEL);
@@ -906,9 +914,11 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
if (rc < 0)
goto ret;
- rc = priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
- if (rc < 0)
- goto ret;
+ /* Return code shouldn't be checked.
+ The reset CLK is needed only with tm6000.
+ Driver should work fine even if this fails.
+ */
+ priv->tuner_callback(priv->video_dev, XC2028_RESET_CLK, 1);
msleep(10);
@@ -1153,23 +1163,29 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
void *video_dev;
if (debug)
- printk(KERN_DEBUG PREFIX ": Xcv2028/3028 init called!\n");
+ printk(KERN_DEBUG "xc2028: Xcv2028/3028 init called!\n");
- if (NULL == cfg || NULL == cfg->video_dev)
+ if (NULL == cfg)
return NULL;
if (!fe) {
- printk(KERN_ERR PREFIX ": No frontend!\n");
+ printk(KERN_ERR "xc2028: No frontend!\n");
return NULL;
}
- video_dev = cfg->video_dev;
+ video_dev = cfg->i2c_adap->algo_data;
+
+ if (debug)
+ printk(KERN_DEBUG "xc2028: video_dev =%p\n", video_dev);
mutex_lock(&xc2028_list_mutex);
list_for_each_entry(priv, &xc2028_list, xc2028_list) {
- if (priv->video_dev == cfg->video_dev) {
+ if (&priv->i2c_props.adap->dev == &cfg->i2c_adap->dev) {
video_dev = NULL;
+ if (debug)
+ printk(KERN_DEBUG "xc2028: reusing device\n");
+
break;
}
}
@@ -1183,6 +1199,8 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
priv->i2c_props.addr = cfg->i2c_addr;
priv->i2c_props.adap = cfg->i2c_adap;
+ priv->i2c_props.name = "xc2028";
+
priv->video_dev = video_dev;
priv->tuner_callback = cfg->callback;
priv->ctrl.max_len = 13;
@@ -1195,6 +1213,9 @@ struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
fe->tuner_priv = priv;
priv->count++;
+ if (debug)
+ printk(KERN_DEBUG "xc2028: usage count is %i\n", priv->count);
+
memcpy(&fe->ops.tuner_ops, &xc2028_dvb_tuner_ops,
sizeof(xc2028_dvb_tuner_ops));
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 01ebcec040c4..f29a2cd0f2f2 100644
--- a/drivers/media/video/tvaudio.c
+++ b/drivers/media/video/tvaudio.c
@@ -38,7 +38,7 @@
/* ---------------------------------------------------------------------- */
/* insmod args */
-static int debug = 0; /* insmod parameter */
+static int debug; /* insmod parameter */
module_param(debug, int, 0644);
MODULE_DESCRIPTION("device driver for various i2c TV sound decoder / audiomux chips");
@@ -1235,11 +1235,11 @@ static int tda9850 = 1;
static int tda9855 = 1;
static int tda9873 = 1;
static int tda9874a = 1;
-static int tea6300 = 0; /* address clash with msp34xx */
-static int tea6320 = 0; /* address clash with msp34xx */
+static int tea6300; /* default 0 - address clash with msp34xx */
+static int tea6320; /* default 0 - address clash with msp34xx */
static int tea6420 = 1;
static int pic16c54 = 1;
-static int ta8874z = 0; /* address clash with tda9840 */
+static int ta8874z; /* default 0 - address clash with tda9840 */
module_param(tda8425, int, 0444);
module_param(tda9840, int, 0444);
diff --git a/drivers/media/video/tveeprom.c b/drivers/media/video/tveeprom.c
index dc0da44a5af6..3cf8a8e801e5 100644
--- a/drivers/media/video/tveeprom.c
+++ b/drivers/media/video/tveeprom.c
@@ -745,109 +745,6 @@ int tveeprom_read(struct i2c_client *c, unsigned char *eedata, int len)
}
EXPORT_SYMBOL(tveeprom_read);
-/* ----------------------------------------------------------------------- */
-/* needed for ivtv.sf.net at the moment. Should go away in the long */
-/* run, just call the exported tveeprom_* directly, there is no point in */
-/* using the indirect way via i2c_driver->command() */
-
-static unsigned short normal_i2c[] = {
- 0xa0 >> 1,
- I2C_CLIENT_END,
-};
-
-I2C_CLIENT_INSMOD;
-
-static struct i2c_driver i2c_driver_tveeprom;
-
-static int
-tveeprom_command(struct i2c_client *client,
- unsigned int cmd,
- void *arg)
-{
- struct tveeprom eeprom;
- u32 *eeprom_props = arg;
- u8 *buf;
-
- switch (cmd) {
- case 0:
- buf = kzalloc(256, GFP_KERNEL);
- tveeprom_read(client, buf, 256);
- tveeprom_hauppauge_analog(client, &eeprom, buf);
- kfree(buf);
- eeprom_props[0] = eeprom.tuner_type;
- eeprom_props[1] = eeprom.tuner_formats;
- eeprom_props[2] = eeprom.model;
- eeprom_props[3] = eeprom.revision;
- eeprom_props[4] = eeprom.has_radio;
- break;
- default:
- return -EINVAL;
- }
- return 0;
-}
-
-static int
-tveeprom_detect_client(struct i2c_adapter *adapter,
- int address,
- int kind)
-{
- struct i2c_client *client;
-
- client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (NULL == client)
- return -ENOMEM;
- client->addr = address;
- client->adapter = adapter;
- client->driver = &i2c_driver_tveeprom;
- snprintf(client->name, sizeof(client->name), "tveeprom");
- i2c_attach_client(client);
-
- return 0;
-}
-
-static int
-tveeprom_attach_adapter(struct i2c_adapter *adapter)
-{
- if (adapter->class & I2C_CLASS_TV_ANALOG)
- return i2c_probe(adapter, &addr_data, tveeprom_detect_client);
- return 0;
-}
-
-static int
-tveeprom_detach_client(struct i2c_client *client)
-{
- int err;
-
- err = i2c_detach_client(client);
- if (err < 0)
- return err;
- kfree(client);
- return 0;
-}
-
-static struct i2c_driver i2c_driver_tveeprom = {
- .driver = {
- .name = "tveeprom",
- },
- .id = I2C_DRIVERID_TVEEPROM,
- .attach_adapter = tveeprom_attach_adapter,
- .detach_client = tveeprom_detach_client,
- .command = tveeprom_command,
-};
-
-static int __init tveeprom_init(void)
-{
- return i2c_add_driver(&i2c_driver_tveeprom);
-}
-
-static void __exit tveeprom_exit(void)
-{
- i2c_del_driver(&i2c_driver_tveeprom);
-}
-
-module_init(tveeprom_init);
-module_exit(tveeprom_exit);
-
/*
* Local variables:
* c-basic-offset: 8
diff --git a/drivers/media/video/tvp5150.c b/drivers/media/video/tvp5150.c
index b6e24e714a23..6a3af1005f03 100644
--- a/drivers/media/video/tvp5150.c
+++ b/drivers/media/video/tvp5150.c
@@ -27,7 +27,7 @@ static unsigned short normal_i2c[] = {
I2C_CLIENT_INSMOD;
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/usbvideo/ibmcam.c b/drivers/media/video/usbvideo/ibmcam.c
index 14db95e10cfe..84ee6b1d9fd2 100644
--- a/drivers/media/video/usbvideo/ibmcam.c
+++ b/drivers/media/video/usbvideo/ibmcam.c
@@ -121,7 +121,7 @@ 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 = 0;
+static int init_model3_input;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level: 0-9 (default=0)");
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 719b17ce83f8..97479609f97d 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -61,7 +61,7 @@ static int debug;
}
#else
#define DEBUG(n, arg...)
-static const int debug = 0;
+static const int debug;
#endif
diff --git a/drivers/media/video/usbvideo/quickcam_messenger.c b/drivers/media/video/usbvideo/quickcam_messenger.c
index a2acba0bcc47..e0ee6d8f2565 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -50,7 +50,7 @@ static int debug;
}
#else
#define DEBUG(n, arg...)
-static const int debug = 0;
+static const int debug;
#endif
#define DRIVER_VERSION "v0.01"
diff --git a/drivers/media/video/usbvideo/ultracam.c b/drivers/media/video/usbvideo/ultracam.c
index 95453c108d40..9544e644bf0d 100644
--- a/drivers/media/video/usbvideo/ultracam.c
+++ b/drivers/media/video/usbvideo/ultracam.c
@@ -28,9 +28,9 @@ typedef struct {
static struct usbvideo *cams = NULL;
-static int debug = 0;
+static int debug;
-static int flags = 0; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
+static int flags; /* FLAGS_DISPLAY_HINTS | FLAGS_OVERLAY_STATS; */
static const int min_canvasWidth = 8;
static const int min_canvasHeight = 4;
diff --git a/drivers/media/video/usbvideo/usbvideo.c b/drivers/media/video/usbvideo/usbvideo.c
index 5d363be7bc73..300188097de6 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -522,7 +522,7 @@ 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 = 0;
+ static int num_pass;
if (uvd == NULL) {
err("%s: uvd == NULL", __FUNCTION__);
@@ -946,7 +946,9 @@ static const struct file_operations usbvideo_fops = {
.read = usbvideo_v4l_read,
.mmap = usbvideo_v4l_mmap,
.ioctl = usbvideo_v4l_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
static const struct video_device usbvideo_template = {
@@ -1035,10 +1037,10 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
__FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
}
if (uvd->dev == NULL) {
- err("%s: uvd->dev == NULL", __FUNCTION__);
+ err("%s: uvd->dev == NULL", __func__);
return -EINVAL;
}
- uvd->vdev.dev=&(uvd->dev->dev);
+ uvd->vdev.dev = &uvd->dev->dev;
if (video_register_device(&uvd->vdev, VFL_TYPE_GRABBER, video_nr) == -1) {
err("%s: video_register_device failed", __FUNCTION__);
return -EPIPE;
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index da1ba0211108..4d4795ae3bc7 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -1066,7 +1066,9 @@ static const struct file_operations vicam_fops = {
.read = vicam_read,
.mmap = vicam_mmap,
.ioctl = vicam_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
};
diff --git a/drivers/media/video/usbvision/usbvision-core.c b/drivers/media/video/usbvision/usbvision-core.c
index 56775ab8b75d..a9c5e5adba3a 100644
--- a/drivers/media/video/usbvision/usbvision-core.c
+++ b/drivers/media/video/usbvision/usbvision-core.c
@@ -53,19 +53,21 @@
#include "usbvision.h"
-static unsigned int core_debug = 0;
+static unsigned int core_debug;
module_param(core_debug,int,0644);
MODULE_PARM_DESC(core_debug,"enable debug messages [core]");
-static unsigned int force_testpattern = 0;
+static unsigned int force_testpattern;
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
+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 SwitchSVideoInput = 0; // To help people with Black and White output with using s-video input. Some cables and input device are wired differently.
+/* 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)");
@@ -82,8 +84,10 @@ MODULE_PARM_DESC(adjust_Y_Offset, "adjust Y offset display [core]");
#ifdef USBVISION_DEBUG
- #define PDEBUG(level, fmt, args...) \
- if (core_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+ #define PDEBUG(level, fmt, args...) { \
+ if (core_debug & (level)) \
+ info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+ }
#else
#define PDEBUG(level, fmt, args...) do {} while(0)
#endif
@@ -384,7 +388,7 @@ int usbvision_scratch_alloc(struct usb_usbvision *usbvision)
scratch_reset(usbvision);
if(usbvision->scratch == NULL) {
err("%s: unable to allocate %d bytes for scratch",
- __FUNCTION__, scratch_buf_size);
+ __func__, scratch_buf_size);
return -ENOMEM;
}
return 0;
@@ -418,7 +422,7 @@ static void usbvision_testpattern(struct usb_usbvision *usbvision,
unsigned char *f;
int num_cell = 0;
int scan_length = 0;
- static int num_pass = 0;
+ static int num_pass;
if (usbvision == NULL) {
printk(KERN_ERR "%s: usbvision == NULL\n", proc);
@@ -493,7 +497,8 @@ 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) {
- err("%s: unable to allocate %d for compr. frame buffer", __FUNCTION__, IFB_size);
+ err("%s: unable to allocate %d for compr. frame buffer",
+ __func__, IFB_size);
return -ENOMEM;
}
return 0;
@@ -1430,7 +1435,7 @@ static int usbvision_compress_isochronous(struct usb_usbvision *usbvision,
}
#if ENABLE_HEXDUMP
if (totlen > 0) {
- static int foo = 0;
+ static int foo;
if (foo < 1) {
printk(KERN_DEBUG "+%d.\n", usbvision->scratchlen);
usbvision_hexdump(data0, (totlen > 64) ? 64 : totlen);
@@ -1516,7 +1521,7 @@ static void usbvision_isocIrq(struct urb *urb)
if(errCode) {
err("%s: usb_submit_urb failed: error %d",
- __FUNCTION__, errCode);
+ __func__, errCode);
}
return;
@@ -1547,7 +1552,7 @@ int usbvision_read_reg(struct usb_usbvision *usbvision, unsigned char reg)
0, (__u16) reg, buffer, 1, HZ);
if (errCode < 0) {
- err("%s: failed: error %d", __FUNCTION__, errCode);
+ err("%s: failed: error %d", __func__, errCode);
return errCode;
}
return buffer[0];
@@ -1575,7 +1580,7 @@ int usbvision_write_reg(struct usb_usbvision *usbvision, unsigned char reg,
USB_RECIP_ENDPOINT, 0, (__u16) reg, &value, 1, HZ);
if (errCode < 0) {
- err("%s: failed: error %d", __FUNCTION__, errCode);
+ err("%s: failed: error %d", __func__, errCode);
}
return errCode;
}
@@ -1851,7 +1856,7 @@ int usbvision_set_output(struct usb_usbvision *usbvision, int width,
0, (__u16) USBVISION_LXSIZE_O, value, 4, HZ);
if (errCode < 0) {
- err("%s failed: error %d", __FUNCTION__, errCode);
+ err("%s failed: error %d", __func__, errCode);
return errCode;
}
usbvision->curwidth = usbvision->stretch_width * UsbWidth;
@@ -2237,7 +2242,7 @@ static int usbvision_set_dram_settings(struct usb_usbvision *usbvision)
(__u16) USBVISION_DRM_PRM1, value, 8, HZ);
if (rc < 0) {
- err("%sERROR=%d", __FUNCTION__, rc);
+ err("%sERROR=%d", __func__, rc);
return rc;
}
@@ -2486,7 +2491,7 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
urb = usb_alloc_urb(USBVISION_URB_FRAMES, GFP_KERNEL);
if (urb == NULL) {
- err("%s: usb_alloc_urb() failed", __FUNCTION__);
+ err("%s: usb_alloc_urb() failed", __func__);
return -ENOMEM;
}
usbvision->sbuf[bufIdx].urb = urb;
@@ -2520,13 +2525,13 @@ int usbvision_init_isoc(struct usb_usbvision *usbvision)
GFP_KERNEL);
if (errCode) {
err("%s: usb_submit_urb(%d) failed: error %d",
- __FUNCTION__, bufIdx, errCode);
+ __func__, bufIdx, errCode);
}
}
usbvision->streaming = Stream_Idle;
PDEBUG(DBG_ISOC, "%s: streaming=1 usbvision->video_endp=$%02x",
- __FUNCTION__,
+ __func__,
usbvision->video_endp);
return 0;
}
@@ -2560,7 +2565,7 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
}
- PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __FUNCTION__);
+ PDEBUG(DBG_ISOC, "%s: streaming=Stream_Off\n", __func__);
usbvision->streaming = Stream_Off;
if (!usbvision->remove_pending) {
@@ -2571,7 +2576,7 @@ void usbvision_stop_isoc(struct usb_usbvision *usbvision)
usbvision->ifaceAlt);
if (errCode < 0) {
err("%s: usb_set_interface() failed: error %d",
- __FUNCTION__, errCode);
+ __func__, errCode);
usbvision->last_error = errCode;
}
regValue = (16-usbvision_read_reg(usbvision, USBVISION_ALTER_REG)) & 0x0F;
diff --git a/drivers/media/video/usbvision/usbvision-i2c.c b/drivers/media/video/usbvision/usbvision-i2c.c
index aabc42cae9c7..e2274d77ea29 100644
--- a/drivers/media/video/usbvision/usbvision-i2c.c
+++ b/drivers/media/video/usbvision/usbvision-i2c.c
@@ -40,13 +40,15 @@
#define DBG_I2C 1<<0
-static int i2c_debug = 0;
+static int i2c_debug;
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...) \
- if (i2c_debug & (level)) info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ , ## args)
+#define PDEBUG(level, fmt, args...) { \
+ if (i2c_debug & (level)) \
+ info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+ }
static int usbvision_i2c_write(struct usb_usbvision *usbvision, unsigned char addr, char *buf,
short len);
diff --git a/drivers/media/video/usbvision/usbvision-video.c b/drivers/media/video/usbvision/usbvision-video.c
index df52f8a60215..d97261ab430f 100644
--- a/drivers/media/video/usbvision/usbvision-video.c
+++ b/drivers/media/video/usbvision/usbvision-video.c
@@ -97,10 +97,10 @@ USBVISION_DRIVER_VERSION_PATCHLEVEL)
#ifdef USBVISION_DEBUG
- #define PDEBUG(level, fmt, args...) \
+ #define PDEBUG(level, fmt, args...) { \
if (video_debug & (level)) \
- info("[%s:%d] " fmt, __PRETTY_FUNCTION__, __LINE__ ,\
- ## args)
+ info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
+ }
#else
#define PDEBUG(level, fmt, args...) do {} while(0)
#endif
@@ -115,7 +115,7 @@ USBVISION_DRIVER_VERSION_PATCHLEVEL)
/* sequential number of usbvision device */
-static int usbvision_nr = 0;
+static int usbvision_nr;
static struct usbvision_v4l2_format_st usbvision_v4l2_format[] = {
{ 1, 1, 8, V4L2_PIX_FMT_GREY , "GREY" },
@@ -135,7 +135,7 @@ static void usbvision_release(struct usb_usbvision *usbvision);
/* Set the default format for ISOC endpoint */
static int isocMode = ISOC_MODE_COMPRESS;
/* Set the default Debug Mode of the device driver */
-static int video_debug = 0;
+static int video_debug;
/* Set the default device to power on at startup */
static int PowerOnAtOpen = 1;
/* Sequential Number of Video Device */
@@ -343,7 +343,7 @@ static void usbvision_create_sysfs(struct video_device *vdev)
return;
} while (0);
- err("%s error: %d\n", __FUNCTION__, res);
+ err("%s error: %d\n", __func__, res);
}
static void usbvision_remove_sysfs(struct video_device *vdev)
@@ -490,7 +490,7 @@ static int usbvision_v4l2_close(struct inode *inode, struct file *file)
mutex_unlock(&usbvision->lock);
if (usbvision->remove_pending) {
- printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
+ printk(KERN_INFO "%s: Final disconnect\n", __func__);
usbvision_release(usbvision);
}
@@ -522,7 +522,7 @@ static int vidioc_g_register (struct file *file, void *priv,
errCode = usbvision_read_reg(usbvision, reg->reg&0xff);
if (errCode < 0) {
err("%s: VIDIOC_DBG_G_REGISTER failed: error %d",
- __FUNCTION__, errCode);
+ __func__, errCode);
return errCode;
}
reg->val = errCode;
@@ -543,7 +543,7 @@ static int vidioc_s_register (struct file *file, void *priv,
errCode = usbvision_write_reg(usbvision, reg->reg&0xff, reg->val);
if (errCode < 0) {
err("%s: VIDIOC_DBG_S_REGISTER failed: error %d",
- __FUNCTION__, errCode);
+ __func__, errCode);
return errCode;
}
return 0;
@@ -1102,7 +1102,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
int ret,i;
struct usbvision_frame *frame;
- PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __FUNCTION__,
+ PDEBUG(DBG_IO, "%s: %ld bytes, noblock=%d", __func__,
(unsigned long)count, noblock);
if (!USBVISION_IS_OPERATIONAL(usbvision) || (buf == NULL))
@@ -1171,7 +1171,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
}
PDEBUG(DBG_IO, "%s: frmx=%d, bytes_read=%ld, scanlength=%ld",
- __FUNCTION__,
+ __func__,
frame->index, frame->bytes_read, frame->scanlength);
/* copy bytes to user space; we allow for partials reads */
@@ -1184,7 +1184,7 @@ static ssize_t usbvision_v4l2_read(struct file *file, char __user *buf,
frame->bytes_read += count;
PDEBUG(DBG_IO, "%s: {copy} count used=%ld, new bytes_read=%ld",
- __FUNCTION__,
+ __func__,
(unsigned long)count, frame->bytes_read);
/* For now, forget the frame if it has not been read in one shot. */
@@ -1269,12 +1269,12 @@ static int usbvision_radio_open(struct inode *inode, struct file *file)
(struct usb_usbvision *) video_get_drvdata(dev);
int errCode = 0;
- PDEBUG(DBG_IO, "%s:", __FUNCTION__);
+ PDEBUG(DBG_IO, "%s:", __func__);
mutex_lock(&usbvision->lock);
if (usbvision->user) {
- err("%s: Someone tried to open an already opened USBVision Radio!", __FUNCTION__);
+ err("%s: Someone tried to open an already opened USBVision Radio!", __func__);
errCode = -EBUSY;
}
else {
@@ -1342,7 +1342,7 @@ static int usbvision_radio_close(struct inode *inode, struct file *file)
mutex_unlock(&usbvision->lock);
if (usbvision->remove_pending) {
- printk(KERN_INFO "%s: Final disconnect\n", __FUNCTION__);
+ printk(KERN_INFO "%s: Final disconnect\n", __func__);
usbvision_release(usbvision);
}
@@ -1507,7 +1507,7 @@ static struct video_device *usbvision_vdev_init(struct usb_usbvision *usbvision,
struct video_device *vdev;
if (usb_dev == NULL) {
- err("%s: usbvision->dev is not set", __FUNCTION__);
+ err("%s: usbvision->dev is not set", __func__);
return NULL;
}
@@ -1759,7 +1759,7 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
PDEBUG(DBG_PROBE, "model out of bounds %d",model);
return -ENODEV;
}
- printk(KERN_INFO "%s: %s found\n", __FUNCTION__,
+ printk(KERN_INFO "%s: %s found\n", __func__,
usbvision_device_data[model].ModelString);
if (usbvision_device_data[model].Interface >= 0) {
@@ -1771,20 +1771,20 @@ static int __devinit usbvision_probe(struct usb_interface *intf,
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
err("%s: interface %d. has non-ISO endpoint!",
- __FUNCTION__, ifnum);
+ __func__, ifnum);
err("%s: Endpoint attributes %d",
- __FUNCTION__, endpoint->bmAttributes);
+ __func__, endpoint->bmAttributes);
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) ==
USB_DIR_OUT) {
err("%s: interface %d. has ISO OUT endpoint!",
- __FUNCTION__, ifnum);
+ __func__, ifnum);
return -ENODEV;
}
if ((usbvision = usbvision_alloc(dev)) == NULL) {
- err("%s: couldn't allocate USBVision struct", __FUNCTION__);
+ err("%s: couldn't allocate USBVision struct", __func__);
return -ENOMEM;
}
@@ -1868,7 +1868,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
PDEBUG(DBG_PROBE, "");
if (usbvision == NULL) {
- err("%s: usb_get_intfdata() failed", __FUNCTION__);
+ err("%s: usb_get_intfdata() failed", __func__);
return;
}
usb_set_intfdata (intf, NULL);
@@ -1891,7 +1891,7 @@ static void __devexit usbvision_disconnect(struct usb_interface *intf)
if (usbvision->user) {
printk(KERN_INFO "%s: In use, disconnect pending\n",
- __FUNCTION__);
+ __func__);
wake_up_interruptible(&usbvision->wait_frame);
wake_up_interruptible(&usbvision->wait_stream);
} else {
diff --git a/drivers/media/video/v4l1-compat.c b/drivers/media/video/v4l1-compat.c
index 50e1ff9f2be5..a0f6c60279ec 100644
--- a/drivers/media/video/v4l1-compat.c
+++ b/drivers/media/video/v4l1-compat.c
@@ -39,15 +39,18 @@
#include <linux/kmod.h>
#endif
-static unsigned int debug = 0;
+static unsigned int debug;
module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug,"enable debug messages");
+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...) if (debug) \
- printk(KERN_DEBUG "v4l1-compat: " fmt , ## arg)
+#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
@@ -69,14 +72,12 @@ get_v4l_control(struct inode *inode,
qctrl2.id = cid;
err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2);
if (err < 0)
- dprintk("VIDIOC_QUERYCTRL: %d\n",err);
- if (err == 0 &&
- !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED))
- {
+ dprintk("VIDIOC_QUERYCTRL: %d\n", err);
+ if (err == 0 && !(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED)) {
ctrl2.id = qctrl2.id;
err = drv(inode, file, VIDIOC_G_CTRL, &ctrl2);
if (err < 0) {
- dprintk("VIDIOC_G_CTRL: %d\n",err);
+ dprintk("VIDIOC_G_CTRL: %d\n", err);
return 0;
}
return ((ctrl2.value - qctrl2.minimum) * 65535
@@ -100,11 +101,10 @@ set_v4l_control(struct inode *inode,
qctrl2.id = cid;
err = drv(inode, file, VIDIOC_QUERYCTRL, &qctrl2);
if (err < 0)
- dprintk("VIDIOC_QUERYCTRL: %d\n",err);
+ dprintk("VIDIOC_QUERYCTRL: %d\n", err);
if (err == 0 &&
!(qctrl2.flags & V4L2_CTRL_FLAG_DISABLED) &&
- !(qctrl2.flags & V4L2_CTRL_FLAG_GRABBED))
- {
+ !(qctrl2.flags & V4L2_CTRL_FLAG_GRABBED)) {
if (value < 0)
value = 0;
if (value > 65535)
@@ -119,14 +119,14 @@ set_v4l_control(struct inode *inode,
ctrl2.value += qctrl2.minimum;
err = drv(inode, file, VIDIOC_S_CTRL, &ctrl2);
if (err < 0)
- dprintk("VIDIOC_S_CTRL: %d\n",err);
+ dprintk("VIDIOC_S_CTRL: %d\n", err);
}
return 0;
}
/* ----------------------------------------------------------------- */
-const static unsigned int palette2pixelformat[] = {
+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,
@@ -157,8 +157,7 @@ static unsigned int __attribute_const__
pixelformat_to_palette(unsigned int pixelformat)
{
int palette = 0;
- switch (pixelformat)
- {
+ switch (pixelformat) {
case V4L2_PIX_FMT_GREY:
palette = VIDEO_PALETTE_GREY;
break;
@@ -200,14 +199,13 @@ pixelformat_to_palette(unsigned int pixelformat)
/* ----------------------------------------------------------------- */
-static int poll_one(struct file *file)
+static int poll_one(struct file *file, struct poll_wqueues *pwq)
{
int retval = 1;
poll_table *table;
- struct poll_wqueues pwq;
- poll_initwait(&pwq);
- table = &pwq.pt;
+ poll_initwait(pwq);
+ table = &pwq->pt;
for (;;) {
int mask;
set_current_state(TASK_INTERRUPTIBLE);
@@ -222,878 +220,1073 @@ static int poll_one(struct file *file)
schedule();
}
set_current_state(TASK_RUNNING);
- poll_freewait(&pwq);
+ poll_freewait(pwq);
return retval;
}
-static int count_inputs(struct inode *inode,
- struct file *file,
- v4l2_kioctl drv)
+static int count_inputs(
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
{
struct v4l2_input input2;
int i;
for (i = 0;; i++) {
- memset(&input2,0,sizeof(input2));
+ memset(&input2, 0, sizeof(input2));
input2.index = i;
- if (0 != drv(inode,file,VIDIOC_ENUMINPUT, &input2))
+ if (0 != drv(inode, file, VIDIOC_ENUMINPUT, &input2))
break;
}
return i;
}
-static int check_size(struct inode *inode,
- struct file *file,
- v4l2_kioctl drv,
- int *maxw, int *maxh)
+static int check_size(
+ struct inode *inode,
+ 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));
+ memset(&desc2, 0, sizeof(desc2));
+ memset(&fmt2, 0, sizeof(fmt2));
desc2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- if (0 != drv(inode,file,VIDIOC_ENUM_FMT, &desc2))
+ if (0 != drv(inode, 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(inode,file,VIDIOC_TRY_FMT, &fmt2))
+ if (0 != drv(inode, file, VIDIOC_TRY_FMT, &fmt2))
goto done;
*maxw = fmt2.fmt.pix.width;
*maxh = fmt2.fmt.pix.height;
- done:
+done:
return 0;
}
/* ----------------------------------------------------------------- */
-/*
- * This function is exported.
- */
-int
-v4l_compat_translate_ioctl(struct inode *inode,
- struct file *file,
- int cmd,
- void *arg,
- v4l2_kioctl drv)
+static noinline int v4l1_compat_get_capabilities(
+ struct video_capability *cap,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
{
- struct v4l2_capability *cap2 = NULL;
- struct v4l2_format *fmt2 = NULL;
- enum v4l2_buf_type captype = V4L2_BUF_TYPE_VIDEO_CAPTURE;
-
- struct v4l2_framebuffer fbuf2;
- struct v4l2_input input2;
- struct v4l2_tuner tun2;
- struct v4l2_standard std2;
- struct v4l2_frequency freq2;
- struct v4l2_audio aud2;
- struct v4l2_queryctrl qctrl2;
- struct v4l2_buffer buf2;
- v4l2_std_id sid;
- int i, err = 0;
-
- switch (cmd) {
- case VIDIOCGCAP: /* capability */
- {
- struct video_capability *cap = arg;
-
- cap2 = kzalloc(sizeof(*cap2), GFP_KERNEL);
- if (!cap2) {
- err = -ENOMEM;
- break;
- }
- memset(cap, 0, sizeof(*cap));
- memset(&fbuf2, 0, sizeof(fbuf2));
+ int 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(inode, file, VIDIOC_QUERYCAP, cap2);
+ err = drv(inode, file, VIDIOC_QUERYCAP, cap2);
+ if (err < 0) {
+ dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n", err);
+ goto done;
+ }
+ if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) {
+ err = drv(inode, file, VIDIOC_G_FBUF, &fbuf);
if (err < 0) {
- dprintk("VIDIOCGCAP / VIDIOC_QUERYCAP: %d\n",err);
- break;
+ dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n", err);
+ memset(&fbuf, 0, sizeof(fbuf));
}
- if (cap2->capabilities & V4L2_CAP_VIDEO_OVERLAY) {
- err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
- if (err < 0) {
- dprintk("VIDIOCGCAP / VIDIOC_G_FBUF: %d\n",err);
- memset(&fbuf2, 0, sizeof(fbuf2));
- }
- 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 (fbuf2.capability & V4L2_FBUF_CAP_LIST_CLIPPING)
- cap->type |= VID_TYPE_CLIPPING;
-
- cap->channels = count_inputs(inode,file,drv);
- check_size(inode,file,drv,
- &cap->maxwidth,&cap->maxheight);
- cap->audios = 0; /* FIXME */
- cap->minwidth = 48; /* FIXME */
- cap->minheight = 32; /* FIXME */
- break;
+ err = 0;
}
- case VIDIOCGFBUF: /* get frame buffer */
- {
- struct video_buffer *buffer = arg;
- memset(buffer, 0, sizeof(*buffer));
- memset(&fbuf2, 0, sizeof(fbuf2));
+ 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(inode, file, drv);
+ check_size(inode, file, drv,
+ &cap->maxwidth, &cap->maxheight);
+ cap->audios = 0; /* FIXME */
+ cap->minwidth = 48; /* FIXME */
+ cap->minheight = 32; /* FIXME */
+
+done:
+ kfree(cap2);
+ return err;
+}
- err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
- if (err < 0) {
- dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\n",err);
- break;
- }
- buffer->base = fbuf2.base;
- buffer->height = fbuf2.fmt.height;
- buffer->width = fbuf2.fmt.width;
+static noinline int v4l1_compat_get_frame_buffer(
+ struct video_buffer *buffer,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_framebuffer fbuf;
- switch (fbuf2.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 (fbuf2.fmt.bytesperline) {
- buffer->bytesperline = fbuf2.fmt.bytesperline;
- if (!buffer->depth && buffer->width)
- buffer->depth = ((fbuf2.fmt.bytesperline<<3)
- + (buffer->width-1) )
- /buffer->width;
- } else {
- buffer->bytesperline =
- (buffer->width * buffer->depth + 7) & 7;
- buffer->bytesperline >>= 3;
- }
+ memset(buffer, 0, sizeof(*buffer));
+ memset(&fbuf, 0, sizeof(fbuf));
+
+ err = drv(inode, file, VIDIOC_G_FBUF, &fbuf);
+ if (err < 0) {
+ dprintk("VIDIOCGFBUF / VIDIOC_G_FBUF: %d\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;
}
- case VIDIOCSFBUF: /* set frame buffer */
- {
- struct video_buffer *buffer = arg;
-
- memset(&fbuf2, 0, sizeof(fbuf2));
- fbuf2.base = buffer->base;
- fbuf2.fmt.height = buffer->height;
- fbuf2.fmt.width = buffer->width;
- switch (buffer->depth) {
- case 8:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB332;
- break;
- case 15:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB555;
- break;
- case 16:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_RGB565;
- break;
- case 24:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_BGR24;
- break;
- case 32:
- fbuf2.fmt.pixelformat = V4L2_PIX_FMT_BGR32;
- break;
- }
- fbuf2.fmt.bytesperline = buffer->bytesperline;
- err = drv(inode, file, VIDIOC_S_FBUF, &fbuf2);
- if (err < 0)
- dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n",err);
+ 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 int v4l1_compat_set_frame_buffer(
+ struct video_buffer *buffer,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int 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;
}
- case VIDIOCGWIN: /* get window or capture dimensions */
- {
- struct video_window *win = arg;
+ fbuf.fmt.bytesperline = buffer->bytesperline;
+ err = drv(inode, file, VIDIOC_S_FBUF, &fbuf);
+ if (err < 0)
+ dprintk("VIDIOCSFBUF / VIDIOC_S_FBUF: %d\n", err);
+ return err;
+}
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- break;
- }
- memset(win,0,sizeof(*win));
+static noinline int v4l1_compat_get_win_cap_dimensions(
+ struct video_window *win,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_format *fmt;
- fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
- err = drv(inode, file, VIDIOC_G_FMT, fmt2);
- if (err < 0)
- dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\n",err);
- if (err == 0) {
- win->x = fmt2->fmt.win.w.left;
- win->y = fmt2->fmt.win.w.top;
- win->width = fmt2->fmt.win.w.width;
- win->height = fmt2->fmt.win.w.height;
- win->chromakey = fmt2->fmt.win.chromakey;
- win->clips = NULL;
- win->clipcount = 0;
- break;
- }
+ fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
+ if (!fmt) {
+ err = -ENOMEM;
+ return err;
+ }
+ memset(win, 0, sizeof(*win));
- fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\n",err);
- break;
- }
- win->x = 0;
- win->y = 0;
- win->width = fmt2->fmt.pix.width;
- win->height = fmt2->fmt.pix.height;
- win->chromakey = 0;
+ fmt->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
+ err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ if (err < 0)
+ dprintk("VIDIOCGWIN / VIDIOC_G_WIN: %d\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;
- break;
+ goto done;
}
- case VIDIOCSWIN: /* set window and/or capture dimensions */
- {
- struct video_window *win = arg;
- int err1,err2;
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- break;
- }
- fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- drv(inode, file, VIDIOC_STREAMOFF, &fmt2->type);
- err1 = drv(inode, file, VIDIOC_G_FMT, fmt2);
- if (err1 < 0)
- dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\n",err);
- if (err1 == 0) {
- fmt2->fmt.pix.width = win->width;
- fmt2->fmt.pix.height = win->height;
- fmt2->fmt.pix.field = V4L2_FIELD_ANY;
- fmt2->fmt.pix.bytesperline = 0;
- err = drv(inode, file, VIDIOC_S_FMT, fmt2);
- if (err < 0)
- dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n",
- err);
- win->width = fmt2->fmt.pix.width;
- win->height = fmt2->fmt.pix.height;
- }
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ if (err < 0) {
+ dprintk("VIDIOCGWIN / VIDIOC_G_FMT: %d\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;
+}
- memset(fmt2,0,sizeof(*fmt2));
- fmt2->type = V4L2_BUF_TYPE_VIDEO_OVERLAY;
- fmt2->fmt.win.w.left = win->x;
- fmt2->fmt.win.w.top = win->y;
- fmt2->fmt.win.w.width = win->width;
- fmt2->fmt.win.w.height = win->height;
- fmt2->fmt.win.chromakey = win->chromakey;
- fmt2->fmt.win.clips = (void __user *)win->clips;
- fmt2->fmt.win.clipcount = win->clipcount;
- err2 = drv(inode, file, VIDIOC_S_FMT, fmt2);
- if (err2 < 0)
- dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n",err);
-
- if (err1 != 0 && err2 != 0)
- err = err1;
- break;
+static noinline int v4l1_compat_set_win_cap_dimensions(
+ struct video_window *win,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err, err1, err2;
+ struct v4l2_format *fmt;
+
+ fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
+ if (!fmt) {
+ err = -ENOMEM;
+ return err;
}
- case VIDIOCCAPTURE: /* turn on/off preview */
- {
- int *on = arg;
-
- if (0 == *on) {
- /* dirty hack time. But v4l1 has no STREAMOFF
- * equivalent in the API, and this one at
- * least comes close ... */
- drv(inode, file, VIDIOC_STREAMOFF, &captype);
- }
- err = drv(inode, file, VIDIOC_OVERLAY, arg);
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ drv(inode, file, VIDIOC_STREAMOFF, &fmt->type);
+ err1 = drv(inode, file, VIDIOC_G_FMT, fmt);
+ if (err1 < 0)
+ dprintk("VIDIOCSWIN / VIDIOC_G_FMT: %d\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(inode, file, VIDIOC_S_FMT, fmt);
if (err < 0)
- dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n",err);
- break;
+ dprintk("VIDIOCSWIN / VIDIOC_S_FMT #1: %d\n",
+ err);
+ win->width = fmt->fmt.pix.width;
+ win->height = fmt->fmt.pix.height;
}
- case VIDIOCGCHAN: /* get input information */
- {
- struct video_channel *chan = arg;
- memset(&input2,0,sizeof(input2));
- input2.index = chan->channel;
- err = drv(inode, file, VIDIOC_ENUMINPUT, &input2);
- if (err < 0) {
- dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: "
- "channel=%d err=%d\n",chan->channel,err);
- break;
- }
- 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;
- err = drv(inode, file, VIDIOC_G_STD, &sid);
- if (err < 0)
- dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %d\n",err);
- if (err == 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;
- }
- break;
- }
- case VIDIOCSCHAN: /* set input */
- {
- struct video_channel *chan = arg;
+ 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(inode, file, VIDIOC_S_FMT, fmt);
+ if (err2 < 0)
+ dprintk("VIDIOCSWIN / VIDIOC_S_FMT #2: %d\n", err2);
+
+ if (err1 != 0 && err2 != 0)
+ err = err1;
+ else
+ err = 0;
+ kfree(fmt);
+ return err;
+}
- sid = 0;
- err = drv(inode, file, VIDIOC_S_INPUT, &chan->channel);
- if (err < 0)
- dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\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;
- }
- if (0 != sid) {
- err = drv(inode, file, VIDIOC_S_STD, &sid);
- if (err < 0)
- dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n",err);
- }
- break;
+static noinline int v4l1_compat_turn_preview_on_off(
+ int *on,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int 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(inode, file, VIDIOC_STREAMOFF, &captype);
}
- case VIDIOCGPICT: /* get tone controls & partial capture format */
- {
- struct video_picture *pict = arg;
-
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- break;
- }
+ err = drv(inode, file, VIDIOC_OVERLAY, on);
+ if (err < 0)
+ dprintk("VIDIOCCAPTURE / VIDIOC_PREVIEW: %d\n", err);
+ return err;
+}
- pict->brightness = get_v4l_control(inode, file,
- V4L2_CID_BRIGHTNESS,drv);
- pict->hue = get_v4l_control(inode, file,
- V4L2_CID_HUE, drv);
- pict->contrast = get_v4l_control(inode, file,
- V4L2_CID_CONTRAST, drv);
- pict->colour = get_v4l_control(inode, file,
- V4L2_CID_SATURATION, drv);
- pict->whiteness = get_v4l_control(inode, file,
- V4L2_CID_WHITENESS, drv);
-
- fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n",err);
- break;
- }
+static noinline int v4l1_compat_get_input_info(
+ struct video_channel *chan,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_input input2;
+ v4l2_std_id sid;
- pict->depth = ((fmt2->fmt.pix.bytesperline<<3)
- + (fmt2->fmt.pix.width-1) )
- /fmt2->fmt.pix.width;
- pict->palette = pixelformat_to_palette(
- fmt2->fmt.pix.pixelformat);
+ memset(&input2, 0, sizeof(input2));
+ input2.index = chan->channel;
+ err = drv(inode, file, VIDIOC_ENUMINPUT, &input2);
+ if (err < 0) {
+ dprintk("VIDIOCGCHAN / VIDIOC_ENUMINPUT: "
+ "channel=%d err=%d\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;
}
- case VIDIOCSPICT: /* set tone controls & partial capture format */
- {
- struct video_picture *pict = arg;
- int mem_err = 0, ovl_err = 0;
+ chan->norm = 0;
+ err = drv(inode, file, VIDIOC_G_STD, &sid);
+ if (err < 0)
+ dprintk("VIDIOCGCHAN / VIDIOC_G_STD: %d\n", err);
+ if (err == 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;
+ }
+done:
+ return err;
+}
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- break;
- }
- memset(&fbuf2, 0, sizeof(fbuf2));
-
- set_v4l_control(inode, file,
- V4L2_CID_BRIGHTNESS, pict->brightness, drv);
- set_v4l_control(inode, file,
- V4L2_CID_HUE, pict->hue, drv);
- set_v4l_control(inode, file,
- V4L2_CID_CONTRAST, pict->contrast, drv);
- set_v4l_control(inode, file,
- V4L2_CID_SATURATION, pict->colour, drv);
- set_v4l_control(inode, 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.
- */
-
- fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt2);
- /* 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: %d\n",err);
- mem_err = -1000; /* didn't even try */
- } else if (fmt2->fmt.pix.pixelformat !=
- palette_to_pixelformat(pict->palette)) {
- fmt2->fmt.pix.pixelformat = palette_to_pixelformat(
- pict->palette);
- mem_err = drv(inode, file, VIDIOC_S_FMT, fmt2);
- if (mem_err < 0)
- dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n",
- mem_err);
- }
+static noinline int v4l1_compat_set_input(
+ struct video_channel *chan,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ v4l2_std_id sid = 0;
- err = drv(inode, file, VIDIOC_G_FBUF, &fbuf2);
- /* 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: %d\n",err);
- ovl_err = -1000; /* didn't even try */
- } else if (fbuf2.fmt.pixelformat !=
- palette_to_pixelformat(pict->palette)) {
- fbuf2.fmt.pixelformat = palette_to_pixelformat(
- pict->palette);
- ovl_err = drv(inode, file, VIDIOC_S_FBUF, &fbuf2);
- 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;
+ err = drv(inode, file, VIDIOC_S_INPUT, &chan->channel);
+ if (err < 0)
+ dprintk("VIDIOCSCHAN / VIDIOC_S_INPUT: %d\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 VIDIOCGTUNER: /* get tuner information */
- {
- struct video_tuner *tun = arg;
-
- memset(&tun2,0,sizeof(tun2));
- err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
- if (err < 0) {
- dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %d\n",err);
- break;
- }
- 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(inode, 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;
- }
-
- err = drv(inode, file, VIDIOC_G_STD, &sid);
+ if (0 != sid) {
+ err = drv(inode, file, VIDIOC_S_STD, &sid);
if (err < 0)
- dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n",err);
- if (err == 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;
- break;
+ dprintk("VIDIOCSCHAN / VIDIOC_S_STD: %d\n", err);
}
- case VIDIOCSTUNER: /* select a tuner input */
- {
- struct video_tuner *tun = arg;
- struct v4l2_tuner t;
- memset(&t,0,sizeof(t));
-
- t.index=tun->tuner;
+ return err;
+}
- err = drv(inode, file, VIDIOC_S_INPUT, &t);
- if (err < 0)
- dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n",err);
+static noinline int v4l1_compat_get_picture(
+ struct video_picture *pict,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_format *fmt;
- break;
+ fmt = kzalloc(sizeof(*fmt), GFP_KERNEL);
+ if (!fmt) {
+ err = -ENOMEM;
+ return err;
}
- case VIDIOCGFREQ: /* get frequency */
- {
- unsigned long *freq = arg;
- memset(&freq2,0,sizeof(freq2));
- freq2.tuner = 0;
- err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
- if (err < 0)
- dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n",err);
- if (0 == err)
- *freq = freq2.frequency;
- break;
+ pict->brightness = get_v4l_control(inode, file,
+ V4L2_CID_BRIGHTNESS, drv);
+ pict->hue = get_v4l_control(inode, file,
+ V4L2_CID_HUE, drv);
+ pict->contrast = get_v4l_control(inode, file,
+ V4L2_CID_CONTRAST, drv);
+ pict->colour = get_v4l_control(inode, file,
+ V4L2_CID_SATURATION, drv);
+ pict->whiteness = get_v4l_control(inode, file,
+ V4L2_CID_WHITENESS, drv);
+
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ if (err < 0) {
+ dprintk("VIDIOCGPICT / VIDIOC_G_FMT: %d\n", err);
+ goto done;
}
- case VIDIOCSFREQ: /* set frequency */
- {
- unsigned long *freq = arg;
- memset(&freq2,0,sizeof(freq2));
- drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
- freq2.frequency = *freq;
- err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2);
- if (err < 0)
- dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %d\n",err);
- break;
+ 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 int v4l1_compat_set_picture(
+ struct video_picture *pict,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int 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(inode, file,
+ V4L2_CID_BRIGHTNESS, pict->brightness, drv);
+ set_v4l_control(inode, file,
+ V4L2_CID_HUE, pict->hue, drv);
+ set_v4l_control(inode, file,
+ V4L2_CID_CONTRAST, pict->contrast, drv);
+ set_v4l_control(inode, file,
+ V4L2_CID_SATURATION, pict->colour, drv);
+ set_v4l_control(inode, 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(inode, 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: %d\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(inode, file, VIDIOC_S_FMT, fmt);
+ if (mem_err < 0)
+ dprintk("VIDIOCSPICT / VIDIOC_S_FMT: %d\n",
+ mem_err);
}
- case VIDIOCGAUDIO: /* get audio properties/controls */
- {
- struct video_audio *aud = arg;
- memset(&aud2,0,sizeof(aud2));
- err = drv(inode, file, VIDIOC_G_AUDIO, &aud2);
- if (err < 0) {
- dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %d\n",err);
- break;
- }
- 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(inode, file, V4L2_CID_AUDIO_VOLUME, drv);
- if (i >= 0) {
- aud->volume = i;
- aud->flags |= VIDEO_AUDIO_VOLUME;
- }
- i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv);
- if (i >= 0) {
- aud->bass = i;
- aud->flags |= VIDEO_AUDIO_BASS;
- }
- i = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv);
- if (i >= 0) {
- aud->treble = i;
- aud->flags |= VIDEO_AUDIO_TREBLE;
- }
- i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv);
- if (i >= 0) {
- aud->balance = i;
- aud->flags |= VIDEO_AUDIO_BALANCE;
- }
- i = get_v4l_control(inode, 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(inode, 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(inode, file, VIDIOC_G_TUNER, &tun2);
- if (err < 0) {
- dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n",err);
+ err = drv(inode, 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: %d\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(inode, 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 int v4l1_compat_get_tuner(
+ struct video_tuner *tun,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err, i;
+ struct v4l2_tuner tun2;
+ struct v4l2_standard std2;
+ v4l2_std_id sid;
+
+ memset(&tun2, 0, sizeof(tun2));
+ err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
+ if (err < 0) {
+ dprintk("VIDIOCGTUNER / VIDIOC_G_TUNER: %d\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(inode, 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;
+ }
- 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;
- break;
+ err = drv(inode, file, VIDIOC_G_STD, &sid);
+ if (err < 0)
+ dprintk("VIDIOCGTUNER / VIDIOC_G_STD: %d\n", err);
+ if (err == 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;
}
- case VIDIOCSAUDIO: /* set audio controls */
- {
- struct video_audio *aud = arg;
- memset(&aud2,0,sizeof(aud2));
- memset(&tun2,0,sizeof(tun2));
+ 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;
+}
- aud2.index = aud->audio;
- err = drv(inode, file, VIDIOC_S_AUDIO, &aud2);
- if (err < 0) {
- dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %d\n",err);
- break;
- }
+static noinline int v4l1_compat_select_tuner(
+ struct video_tuner *tun,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_tuner t;/*84 bytes on x86_64*/
+ memset(&t, 0, sizeof(t));
- set_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME,
- aud->volume, drv);
- set_v4l_control(inode, file, V4L2_CID_AUDIO_BASS,
- aud->bass, drv);
- set_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE,
- aud->treble, drv);
- set_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE,
- aud->balance, drv);
- set_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE,
- !!(aud->flags & VIDEO_AUDIO_MUTE), drv);
-
- err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
- if (err < 0)
- dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %d\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(inode, file, VIDIOC_S_TUNER, &tun2);
- if (err < 0)
- dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %d\n",err);
- }
+ t.index = tun->tuner;
+
+ err = drv(inode, file, VIDIOC_S_INPUT, &t);
+ if (err < 0)
+ dprintk("VIDIOCSTUNER / VIDIOC_S_INPUT: %d\n", err);
+ return err;
+}
+
+static noinline int v4l1_compat_get_frequency(
+ unsigned long *freq,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_frequency freq2;
+ memset(&freq2, 0, sizeof(freq2));
+
+ freq2.tuner = 0;
+ err = drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
+ if (err < 0)
+ dprintk("VIDIOCGFREQ / VIDIOC_G_FREQUENCY: %d\n", err);
+ if (0 == err)
+ *freq = freq2.frequency;
+ return err;
+}
+
+static noinline int v4l1_compat_set_frequency(
+ unsigned long *freq,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_frequency freq2;
+ memset(&freq2, 0, sizeof(freq2));
+
+ drv(inode, file, VIDIOC_G_FREQUENCY, &freq2);
+ freq2.frequency = *freq;
+ err = drv(inode, file, VIDIOC_S_FREQUENCY, &freq2);
+ if (err < 0)
+ dprintk("VIDIOCSFREQ / VIDIOC_S_FREQUENCY: %d\n", err);
+ return err;
+}
+
+static noinline int v4l1_compat_get_audio(
+ struct video_audio *aud,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err, i;
+ struct v4l2_queryctrl qctrl2;
+ struct v4l2_audio aud2;
+ struct v4l2_tuner tun2;
+ memset(&aud2, 0, sizeof(aud2));
+
+ err = drv(inode, file, VIDIOC_G_AUDIO, &aud2);
+ if (err < 0) {
+ dprintk("VIDIOCGAUDIO / VIDIOC_G_AUDIO: %d\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(inode, file, V4L2_CID_AUDIO_VOLUME, drv);
+ if (i >= 0) {
+ aud->volume = i;
+ aud->flags |= VIDEO_AUDIO_VOLUME;
+ }
+ i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BASS, drv);
+ if (i >= 0) {
+ aud->bass = i;
+ aud->flags |= VIDEO_AUDIO_BASS;
+ }
+ i = get_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE, drv);
+ if (i >= 0) {
+ aud->treble = i;
+ aud->flags |= VIDEO_AUDIO_TREBLE;
+ }
+ i = get_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE, drv);
+ if (i >= 0) {
+ aud->balance = i;
+ aud->flags |= VIDEO_AUDIO_BALANCE;
+ }
+ i = get_v4l_control(inode, 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(inode, 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(inode, file, VIDIOC_G_TUNER, &tun2);
+ if (err < 0) {
+ dprintk("VIDIOCGAUDIO / VIDIOC_G_TUNER: %d\n", err);
err = 0;
- break;
+ goto done;
}
- case VIDIOCMCAPTURE: /* capture a frame */
- {
- struct video_mmap *mm = arg;
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- break;
- }
- memset(&buf2,0,sizeof(buf2));
+ 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;
+}
- fmt2->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_G_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\n",err);
+static noinline int v4l1_compat_set_audio(
+ struct video_audio *aud,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int 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(inode, file, VIDIOC_S_AUDIO, &aud2);
+ if (err < 0) {
+ dprintk("VIDIOCSAUDIO / VIDIOC_S_AUDIO: %d\n", err);
+ goto done;
+ }
+
+ set_v4l_control(inode, file, V4L2_CID_AUDIO_VOLUME,
+ aud->volume, drv);
+ set_v4l_control(inode, file, V4L2_CID_AUDIO_BASS,
+ aud->bass, drv);
+ set_v4l_control(inode, file, V4L2_CID_AUDIO_TREBLE,
+ aud->treble, drv);
+ set_v4l_control(inode, file, V4L2_CID_AUDIO_BALANCE,
+ aud->balance, drv);
+ set_v4l_control(inode, file, V4L2_CID_AUDIO_MUTE,
+ !!(aud->flags & VIDEO_AUDIO_MUTE), drv);
+
+ err = drv(inode, file, VIDIOC_G_TUNER, &tun2);
+ if (err < 0)
+ dprintk("VIDIOCSAUDIO / VIDIOC_G_TUNER: %d\n", err);
+ if (err == 0) {
+ switch (aud->mode) {
+ default:
+ case VIDEO_SOUND_MONO:
+ case VIDEO_SOUND_LANG1:
+ tun2.audmode = V4L2_TUNER_MODE_MONO;
break;
- }
- if (mm->width != fmt2->fmt.pix.width ||
- mm->height != fmt2->fmt.pix.height ||
- palette_to_pixelformat(mm->format) !=
- fmt2->fmt.pix.pixelformat)
- {/* New capture format... */
- fmt2->fmt.pix.width = mm->width;
- fmt2->fmt.pix.height = mm->height;
- fmt2->fmt.pix.pixelformat =
- palette_to_pixelformat(mm->format);
- fmt2->fmt.pix.field = V4L2_FIELD_ANY;
- fmt2->fmt.pix.bytesperline = 0;
- err = drv(inode, file, VIDIOC_S_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n",err);
- break;
- }
- }
- buf2.index = mm->frame;
- buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n",err);
+ case VIDEO_SOUND_STEREO:
+ tun2.audmode = V4L2_TUNER_MODE_STEREO;
break;
- }
- err = drv(inode, file, VIDIOC_QBUF, &buf2);
- if (err < 0) {
- dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n",err);
+ case VIDEO_SOUND_LANG2:
+ tun2.audmode = V4L2_TUNER_MODE_LANG2;
break;
}
- err = drv(inode, file, VIDIOC_STREAMON, &captype);
+ err = drv(inode, file, VIDIOC_S_TUNER, &tun2);
if (err < 0)
- dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n",err);
- break;
+ dprintk("VIDIOCSAUDIO / VIDIOC_S_TUNER: %d\n", err);
}
- case VIDIOCSYNC: /* wait for a frame */
- {
- int *i = arg;
+ err = 0;
+done:
+ return err;
+}
- memset(&buf2,0,sizeof(buf2));
- buf2.index = *i;
- buf2.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
- if (err < 0) {
- /* No such buffer */
- dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n",err);
- break;
- }
- if (!(buf2.flags & V4L2_BUF_FLAG_MAPPED)) {
- /* Buffer is not mapped */
- err = -EINVAL;
- break;
- }
+static noinline int v4l1_compat_capture_frame(
+ struct video_mmap *mm,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int 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));
- /* make sure capture actually runs so we don't block forever */
- err = drv(inode, file, VIDIOC_STREAMON, &captype);
+ fmt->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = drv(inode, file, VIDIOC_G_FMT, fmt);
+ if (err < 0) {
+ dprintk("VIDIOCMCAPTURE / VIDIOC_G_FMT: %d\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(inode, file, VIDIOC_S_FMT, fmt);
if (err < 0) {
- dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %d\n",err);
- break;
+ dprintk("VIDIOCMCAPTURE / VIDIOC_S_FMT: %d\n", err);
+ goto done;
}
+ }
+ buf.index = mm->frame;
+ buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ err = drv(inode, file, VIDIOC_QUERYBUF, &buf);
+ if (err < 0) {
+ dprintk("VIDIOCMCAPTURE / VIDIOC_QUERYBUF: %d\n", err);
+ goto done;
+ }
+ err = drv(inode, file, VIDIOC_QBUF, &buf);
+ if (err < 0) {
+ dprintk("VIDIOCMCAPTURE / VIDIOC_QBUF: %d\n", err);
+ goto done;
+ }
+ err = drv(inode, file, VIDIOC_STREAMON, &captype);
+ if (err < 0)
+ dprintk("VIDIOCMCAPTURE / VIDIOC_STREAMON: %d\n", err);
+done:
+ kfree(fmt);
+ return err;
+}
- /* Loop as long as the buffer is queued, but not done */
- while ((buf2.flags &
- (V4L2_BUF_FLAG_QUEUED | V4L2_BUF_FLAG_DONE))
- == V4L2_BUF_FLAG_QUEUED)
- {
- err = poll_one(file);
- if (err < 0 || /* error or sleep was interrupted */
- err == 0) /* timeout? Shouldn't occur. */
- break;
- err = drv(inode, file, VIDIOC_QUERYBUF, &buf2);
- if (err < 0)
- dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n",err);
- }
- if (!(buf2.flags & V4L2_BUF_FLAG_DONE)) /* not done */
- break;
- do {
- err = drv(inode, file, VIDIOC_DQBUF, &buf2);
- if (err < 0)
- dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %d\n",err);
- } while (err == 0 && buf2.index != *i);
- break;
+static noinline int v4l1_compat_sync(
+ int *i,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int 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(inode, file, VIDIOC_QUERYBUF, &buf);
+ if (err < 0) {
+ /* No such buffer */
+ dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err);
+ goto done;
+ }
+ if (!(buf.flags & V4L2_BUF_FLAG_MAPPED)) {
+ /* Buffer is not mapped */
+ err = -EINVAL;
+ goto done;
}
- case VIDIOCGVBIFMT: /* query VBI data capture format */
- {
- struct vbi_format *fmt = arg;
+ /* make sure capture actually runs so we don't block forever */
+ err = drv(inode, file, VIDIOC_STREAMON, &captype);
+ if (err < 0) {
+ dprintk("VIDIOCSYNC / VIDIOC_STREAMON: %d\n", err);
+ goto done;
+ }
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
+ 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;
- }
- fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ err = drv(inode, file, VIDIOC_QUERYBUF, &buf);
+ if (err < 0)
+ dprintk("VIDIOCSYNC / VIDIOC_QUERYBUF: %d\n", err);
+ }
+ kfree(pwq);
+ if (!(buf.flags & V4L2_BUF_FLAG_DONE)) /* not done */
+ goto done;
+ do {
+ err = drv(inode, file, VIDIOC_DQBUF, &buf);
+ if (err < 0)
+ dprintk("VIDIOCSYNC / VIDIOC_DQBUF: %d\n", err);
+ } while (err == 0 && buf.index != *i);
+done:
+ return err;
+}
- err = drv(inode, file, VIDIOC_G_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\n", err);
- break;
- }
- if (fmt2->fmt.vbi.sample_format != V4L2_PIX_FMT_GREY) {
- err = -EINVAL;
- break;
- }
- 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;
- break;
+static noinline int v4l1_compat_get_vbi_format(
+ struct vbi_format *fmt,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_format *fmt2;
+
+ fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
+ if (!fmt2) {
+ err = -ENOMEM;
+ return err;
}
- case VIDIOCSVBIFMT:
- {
- struct vbi_format *fmt = arg;
+ fmt2->type = V4L2_BUF_TYPE_VBI_CAPTURE;
- if (VIDEO_PALETTE_RAW != fmt->sample_format) {
- err = -EINVAL;
- break;
- }
+ err = drv(inode, file, VIDIOC_G_FMT, fmt2);
+ if (err < 0) {
+ dprintk("VIDIOCGVBIFMT / VIDIOC_G_FMT: %d\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;
+}
- fmt2 = kzalloc(sizeof(*fmt2), GFP_KERNEL);
- if (!fmt2) {
- err = -ENOMEM;
- break;
- }
- 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(inode, file, VIDIOC_TRY_FMT, fmt2);
- if (err < 0) {
- dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\n", err);
- break;
- }
+static noinline int v4l1_compat_set_vbi_format(
+ struct vbi_format *fmt,
+ struct inode *inode,
+ struct file *file,
+ v4l2_kioctl drv)
+{
+ int err;
+ struct v4l2_format *fmt2 = NULL;
- 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;
- break;
- }
- err = drv(inode, file, VIDIOC_S_FMT, fmt2);
- if (err < 0)
- dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err);
- break;
+ 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(inode, file, VIDIOC_TRY_FMT, fmt2);
+ if (err < 0) {
+ dprintk("VIDIOCSVBIFMT / VIDIOC_TRY_FMT: %d\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(inode, file, VIDIOC_S_FMT, fmt2);
+ if (err < 0)
+ dprintk("VIDIOCSVBIFMT / VIDIOC_S_FMT: %d\n", err);
+done:
+ kfree(fmt2);
+ return err;
+}
+
+/*
+ * This function is exported.
+ */
+int
+v4l_compat_translate_ioctl(struct inode *inode,
+ struct file *file,
+ int cmd,
+ void *arg,
+ v4l2_kioctl drv)
+{
+ int err;
+
+ switch (cmd) {
+ case VIDIOCGCAP: /* capability */
+ err = v4l1_compat_get_capabilities(arg, inode, file, drv);
+ break;
+ case VIDIOCGFBUF: /* get frame buffer */
+ err = v4l1_compat_get_frame_buffer(arg, inode, file, drv);
+ break;
+ case VIDIOCSFBUF: /* set frame buffer */
+ err = v4l1_compat_set_frame_buffer(arg, inode, file, drv);
+ break;
+ case VIDIOCGWIN: /* get window or capture dimensions */
+ err = v4l1_compat_get_win_cap_dimensions(arg, inode, file, drv);
+ break;
+ case VIDIOCSWIN: /* set window and/or capture dimensions */
+ err = v4l1_compat_set_win_cap_dimensions(arg, inode, file, drv);
+ break;
+ case VIDIOCCAPTURE: /* turn on/off preview */
+ err = v4l1_compat_turn_preview_on_off(arg, inode, file, drv);
+ break;
+ case VIDIOCGCHAN: /* get input information */
+ err = v4l1_compat_get_input_info(arg, inode, file, drv);
+ break;
+ case VIDIOCSCHAN: /* set input */
+ err = v4l1_compat_set_input(arg, inode, file, drv);
+ break;
+ case VIDIOCGPICT: /* get tone controls & partial capture format */
+ err = v4l1_compat_get_picture(arg, inode, file, drv);
+ break;
+ case VIDIOCSPICT: /* set tone controls & partial capture format */
+ err = v4l1_compat_set_picture(arg, inode, file, drv);
+ break;
+ case VIDIOCGTUNER: /* get tuner information */
+ err = v4l1_compat_get_tuner(arg, inode, file, drv);
+ break;
+ case VIDIOCSTUNER: /* select a tuner input */
+ err = v4l1_compat_select_tuner(arg, inode, file, drv);
+ break;
+ case VIDIOCGFREQ: /* get frequency */
+ err = v4l1_compat_get_frequency(arg, inode, file, drv);
+ break;
+ case VIDIOCSFREQ: /* set frequency */
+ err = v4l1_compat_set_frequency(arg, inode, file, drv);
+ break;
+ case VIDIOCGAUDIO: /* get audio properties/controls */
+ err = v4l1_compat_get_audio(arg, inode, file, drv);
+ break;
+ case VIDIOCSAUDIO: /* set audio controls */
+ err = v4l1_compat_set_audio(arg, inode, file, drv);
+ break;
+ case VIDIOCMCAPTURE: /* capture a frame */
+ err = v4l1_compat_capture_frame(arg, inode, file, drv);
+ break;
+ case VIDIOCSYNC: /* wait for a frame */
+ err = v4l1_compat_sync(arg, inode, file, drv);
+ break;
+ case VIDIOCGVBIFMT: /* query VBI data capture format */
+ err = v4l1_compat_get_vbi_format(arg, inode, file, drv);
+ break;
+ case VIDIOCSVBIFMT:
+ err = v4l1_compat_set_vbi_format(arg, inode, file, drv);
+ break;
default:
err = -ENOIOCTLCMD;
break;
}
- kfree(cap2);
- kfree(fmt2);
return err;
}
-
EXPORT_SYMBOL(v4l_compat_translate_ioctl);
/*
diff --git a/drivers/media/video/videobuf-core.c b/drivers/media/video/videobuf-core.c
index eab79ffdf56a..0e252cd29eff 100644
--- a/drivers/media/video/videobuf-core.c
+++ b/drivers/media/video/videobuf-core.c
@@ -64,32 +64,25 @@ void *videobuf_alloc(struct videobuf_queue *q)
return vb;
}
+#define WAITON_CONDITION (vb->state != VIDEOBUF_ACTIVE &&\
+ vb->state != VIDEOBUF_QUEUED)
int videobuf_waiton(struct videobuf_buffer *vb, int non_blocking, int intr)
{
- int retval = 0;
- DECLARE_WAITQUEUE(wait, current);
-
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
- add_wait_queue(&vb->done, &wait);
- while (vb->state == VIDEOBUF_ACTIVE || vb->state == VIDEOBUF_QUEUED) {
- if (non_blocking) {
- retval = -EAGAIN;
- break;
- }
- set_current_state(intr ? TASK_INTERRUPTIBLE
- : TASK_UNINTERRUPTIBLE);
- if (vb->state == VIDEOBUF_ACTIVE ||
- vb->state == VIDEOBUF_QUEUED)
- schedule();
- set_current_state(TASK_RUNNING);
- if (intr && signal_pending(current)) {
- dprintk(1, "buffer waiton: -EINTR\n");
- retval = -EINTR;
- break;
- }
+
+ if (non_blocking) {
+ if (WAITON_CONDITION)
+ return 0;
+ else
+ return -EAGAIN;
}
- remove_wait_queue(&vb->done, &wait);
- return retval;
+
+ if (intr)
+ return wait_event_interruptible(vb->done, WAITON_CONDITION);
+ else
+ wait_event(vb->done, WAITON_CONDITION);
+
+ return 0;
}
int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
@@ -98,29 +91,21 @@ int videobuf_iolock(struct videobuf_queue *q, struct videobuf_buffer *vb,
MAGIC_CHECK(vb->magic, MAGIC_BUFFER);
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- /* This is required to avoid OOPS on some cases,
- since mmap_mapper() method should be called before _iolock.
- On some cases, the mmap_mapper() is called only after scheduling.
- */
- if (vb->memory == V4L2_MEMORY_MMAP) {
- wait_event_timeout(vb->done, q->is_mmapped,
- msecs_to_jiffies(100));
- if (!q->is_mmapped) {
- printk(KERN_ERR
- "Error: mmap_mapper() never called!\n");
- return -EINVAL;
- }
- }
-
return CALL(q, iolock, q, vb, fbuf);
}
/* --------------------------------------------------------------------- */
+static int videobuf_mmap_setup_default(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ return 0;
+}
+
void videobuf_queue_core_init(struct videobuf_queue *q,
struct videobuf_queue_ops *ops,
- void *dev,
+ struct device *dev,
spinlock_t *irqlock,
enum v4l2_buf_type type,
enum v4l2_field field,
@@ -138,6 +123,9 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
q->priv_data = priv;
q->int_ops = int_ops;
+ if (!q->int_ops->mmap_setup)
+ q->int_ops->mmap_setup = videobuf_mmap_setup_default;
+
/* All buffer operations are mandatory */
BUG_ON(!q->ops->buf_setup);
BUG_ON(!q->ops->buf_prepare);
@@ -148,6 +136,7 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
BUG_ON(!q->int_ops);
mutex_init(&q->vb_lock);
+ init_waitqueue_head(&q->wait);
INIT_LIST_HEAD(&q->stream);
}
@@ -195,6 +184,10 @@ void videobuf_queue_cancel(struct videobuf_queue *q)
unsigned long flags = 0;
int i;
+ q->streaming = 0;
+ q->reading = 0;
+ wake_up_interruptible_sync(&q->wait);
+
/* remove queued buffers from list */
if (q->irqlock)
spin_lock_irqsave(q->irqlock, flags);
@@ -204,6 +197,7 @@ void videobuf_queue_cancel(struct videobuf_queue *q)
if (q->bufs[i]->state == VIDEOBUF_QUEUED) {
list_del(&q->bufs[i]->queue);
q->bufs[i]->state = VIDEOBUF_ERROR;
+ wake_up_all(&q->bufs[i]->done);
}
}
if (q->irqlock)
@@ -309,8 +303,6 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
rc = CALL(q, mmap_free, q);
- q->is_mmapped = 0;
-
if (rc < 0)
return rc;
@@ -362,6 +354,9 @@ static int __videobuf_mmap_setup(struct videobuf_queue *q,
switch (memory) {
case V4L2_MEMORY_MMAP:
q->bufs[i]->boff = bsize * i;
+ err = q->int_ops->mmap_setup(q, q->bufs[i]);
+ if (err)
+ break;
break;
case V4L2_MEMORY_USERPTR:
case V4L2_MEMORY_OVERLAY:
@@ -571,6 +566,7 @@ int videobuf_qbuf(struct videobuf_queue *q,
}
dprintk(1, "qbuf: succeded\n");
retval = 0;
+ wake_up_interruptible_sync(&q->wait);
done:
mutex_unlock(&q->vb_lock);
@@ -581,35 +577,88 @@ int videobuf_qbuf(struct videobuf_queue *q,
return retval;
}
-int videobuf_dqbuf(struct videobuf_queue *q,
- struct v4l2_buffer *b, int nonblocking)
+
+/* Locking: Caller holds q->vb_lock */
+static int stream_next_buffer_check_queue(struct videobuf_queue *q, int noblock)
{
- struct videobuf_buffer *buf;
int retval;
- MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
-
- mutex_lock(&q->vb_lock);
- retval = -EBUSY;
- if (q->reading) {
- dprintk(1, "dqbuf: Reading running...\n");
- goto done;
- }
- retval = -EINVAL;
- if (b->type != q->type) {
- dprintk(1, "dqbuf: Wrong type.\n");
+checks:
+ if (!q->streaming) {
+ dprintk(1, "next_buffer: Not streaming\n");
+ retval = -EINVAL;
goto done;
}
+
if (list_empty(&q->stream)) {
- dprintk(1, "dqbuf: stream running\n");
- goto done;
+ if (noblock) {
+ retval = -EAGAIN;
+ dprintk(2, "next_buffer: no buffers to dequeue\n");
+ goto done;
+ } else {
+ dprintk(2, "next_buffer: waiting on buffer\n");
+
+ /* Drop lock to avoid deadlock with qbuf */
+ mutex_unlock(&q->vb_lock);
+
+ /* 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);
+
+ if (retval)
+ goto done;
+
+ goto checks;
+ }
}
+
+ retval = 0;
+
+done:
+ return retval;
+}
+
+
+/* Locking: Caller holds q->vb_lock */
+static int stream_next_buffer(struct videobuf_queue *q,
+ struct videobuf_buffer **vb, int nonblocking)
+{
+ int retval;
+ struct videobuf_buffer *buf = NULL;
+
+ retval = stream_next_buffer_check_queue(q, nonblocking);
+ if (retval)
+ goto done;
+
buf = list_entry(q->stream.next, struct videobuf_buffer, stream);
retval = videobuf_waiton(buf, nonblocking, 1);
+ if (retval < 0)
+ goto done;
+
+ *vb = buf;
+done:
+ return retval;
+}
+
+int videobuf_dqbuf(struct videobuf_queue *q,
+ struct v4l2_buffer *b, int nonblocking)
+{
+ struct videobuf_buffer *buf = NULL;
+ int retval;
+
+ MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
+
+ mutex_lock(&q->vb_lock);
+
+ retval = stream_next_buffer(q, &buf, nonblocking);
if (retval < 0) {
- dprintk(1, "dqbuf: waiton returned %d\n", retval);
+ dprintk(1, "dqbuf: next_buffer error: %i\n", retval);
goto done;
}
+
switch (buf->state) {
case VIDEOBUF_ERROR:
dprintk(1, "dqbuf: state is error\n");
@@ -658,6 +707,7 @@ int videobuf_streamon(struct videobuf_queue *q)
if (q->irqlock)
spin_unlock_irqrestore(q->irqlock, flags);
+ wake_up_interruptible_sync(&q->wait);
done:
mutex_unlock(&q->vb_lock);
return retval;
@@ -670,7 +720,6 @@ static int __videobuf_streamoff(struct videobuf_queue *q)
return -EINVAL;
videobuf_queue_cancel(q);
- q->streaming = 0;
return 0;
}
@@ -740,14 +789,13 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
{
enum v4l2_field field;
unsigned long flags = 0;
- unsigned size, nbufs;
+ unsigned size = 0, nbufs = 1;
int retval;
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
mutex_lock(&q->vb_lock);
- nbufs = 1; size = 0;
q->ops->buf_setup(q, &nbufs, &size);
if (NULL == q->read_buf &&
@@ -874,7 +922,6 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
q->bufs[i] = NULL;
}
q->read_buf = NULL;
- q->reading = 0;
}
@@ -1032,7 +1079,6 @@ int videobuf_mmap_mapper(struct videobuf_queue *q,
mutex_lock(&q->vb_lock);
retval = CALL(q, mmap_mapper, q, vma);
- q->is_mmapped = 1;
mutex_unlock(&q->vb_lock);
return retval;
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 53fed4b74ce9..e6ce99ff7fd1 100644
--- a/drivers/media/video/videobuf-dma-sg.c
+++ b/drivers/media/video/videobuf-dma-sg.c
@@ -1,5 +1,5 @@
/*
- * helper functions for PCI DMA video4linux capture buffers
+ * helper functions for SG DMA video4linux capture buffers
*
* The functions expect the hardware being able to scatter gatter
* (i.e. the buffers are not linear in physical memory, but fragmented
@@ -24,7 +24,7 @@
#include <linux/slab.h>
#include <linux/interrupt.h>
-#include <linux/pci.h>
+#include <linux/dma-mapping.h>
#include <linux/vmalloc.h>
#include <linux/pagemap.h>
#include <linux/scatterlist.h>
@@ -39,10 +39,10 @@
#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
-MODULE_DESCRIPTION("helper module to manage video4linux pci dma sg buffers");
+MODULE_DESCRIPTION("helper module to manage video4linux dma sg buffers");
MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
MODULE_LICENSE("GPL");
@@ -119,10 +119,10 @@ videobuf_pages_to_sg(struct page **pages, int nr_pages, int offset)
struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf)
{
- struct videbuf_pci_sg_memory *mem=buf->priv;
- BUG_ON (!mem);
+ struct videobuf_dma_sg_memory *mem = buf->priv;
+ BUG_ON(!mem);
- MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+ MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
return &mem->dma;
}
@@ -141,9 +141,14 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
dma->direction = direction;
switch (dma->direction) {
- case PCI_DMA_FROMDEVICE: rw = READ; break;
- case PCI_DMA_TODEVICE: rw = WRITE; break;
- default: BUG();
+ case DMA_FROM_DEVICE:
+ rw = READ;
+ break;
+ case DMA_TO_DEVICE:
+ rw = WRITE;
+ break;
+ default:
+ BUG();
}
first = (data & PAGE_MASK) >> PAGE_SHIFT;
@@ -216,10 +221,8 @@ int videobuf_dma_init_overlay(struct videobuf_dmabuf *dma, int direction,
return 0;
}
-int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
+int videobuf_dma_map(struct videobuf_queue* q, struct videobuf_dmabuf *dma)
{
- void *dev=q->dev;
-
MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
BUG_ON(0 == dma->nr_pages);
@@ -245,7 +248,7 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
return -ENOMEM;
}
if (!dma->bus_addr) {
- dma->sglen = pci_map_sg(dev,dma->sglist,
+ dma->sglen = dma_map_sg(q->dev, dma->sglist,
dma->nr_pages, dma->direction);
if (0 == dma->sglen) {
printk(KERN_WARNING
@@ -259,26 +262,22 @@ int videobuf_dma_map(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
return 0;
}
-int videobuf_dma_sync(struct videobuf_queue *q,struct videobuf_dmabuf *dma)
+int videobuf_dma_sync(struct videobuf_queue *q, struct videobuf_dmabuf *dma)
{
- void *dev=q->dev;
-
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
BUG_ON(!dma->sglen);
- pci_dma_sync_sg_for_cpu (dev,dma->sglist,dma->nr_pages,dma->direction);
+ dma_sync_sg_for_cpu(q->dev, dma->sglist, dma->nr_pages, dma->direction);
return 0;
}
int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma)
{
- void *dev=q->dev;
-
- MAGIC_CHECK(dma->magic,MAGIC_DMABUF);
+ MAGIC_CHECK(dma->magic, MAGIC_DMABUF);
if (!dma->sglen)
return 0;
- pci_unmap_sg (dev,dma->sglist,dma->nr_pages,dma->direction);
+ dma_unmap_sg(q->dev, dma->sglist, dma->nr_pages, dma->direction);
kfree(dma->sglist);
dma->sglist = NULL;
@@ -306,28 +305,28 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
if (dma->bus_addr) {
dma->bus_addr = 0;
}
- dma->direction = PCI_DMA_NONE;
+ dma->direction = DMA_NONE;
return 0;
}
/* --------------------------------------------------------------------- */
-int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma)
{
struct videobuf_queue q;
- q.dev=pci;
+ q.dev = dev;
- return (videobuf_dma_map(&q,dma));
+ return videobuf_dma_map(&q, dma);
}
-int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma)
+int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma)
{
struct videobuf_queue q;
- q.dev=pci;
+ q.dev = dev;
- return (videobuf_dma_unmap(&q,dma));
+ return videobuf_dma_unmap(&q, dma);
}
/* --------------------------------------------------------------------- */
@@ -347,7 +346,7 @@ videobuf_vm_close(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
struct videobuf_queue *q = map->q;
- struct videbuf_pci_sg_memory *mem;
+ struct videobuf_dma_sg_memory *mem;
int i;
dprintk(2,"vm_close %p [count=%d,vma=%08lx-%08lx]\n",map,
@@ -409,18 +408,18 @@ static struct vm_operations_struct videobuf_vm_ops =
};
/* ---------------------------------------------------------------------
- * PCI handlers for the generic methods
+ * SG handlers for the generic methods
*/
/* Allocated area consists on 3 parts:
struct video_buffer
struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
- struct videobuf_pci_sg_memory
+ struct videobuf_dma_sg_memory
*/
static void *__videobuf_alloc(size_t size)
{
- struct videbuf_pci_sg_memory *mem;
+ struct videobuf_dma_sg_memory *mem;
struct videobuf_buffer *vb;
vb = kzalloc(size+sizeof(*mem),GFP_KERNEL);
@@ -443,10 +442,10 @@ static int __videobuf_iolock (struct videobuf_queue* q,
{
int err,pages;
dma_addr_t bus;
- struct videbuf_pci_sg_memory *mem=vb->priv;
+ struct videobuf_dma_sg_memory *mem = vb->priv;
BUG_ON(!mem);
- MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
+ MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
switch (vb->memory) {
case V4L2_MEMORY_MMAP:
@@ -455,14 +454,14 @@ static int __videobuf_iolock (struct videobuf_queue* q,
/* no userspace addr -- kernel bounce buffer */
pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
err = videobuf_dma_init_kernel( &mem->dma,
- PCI_DMA_FROMDEVICE,
+ DMA_FROM_DEVICE,
pages );
if (0 != err)
return err;
} else if (vb->memory == V4L2_MEMORY_USERPTR) {
/* dma directly to userspace */
err = videobuf_dma_init_user( &mem->dma,
- PCI_DMA_FROMDEVICE,
+ DMA_FROM_DEVICE,
vb->baddr,vb->bsize );
if (0 != err)
return err;
@@ -473,7 +472,7 @@ static int __videobuf_iolock (struct videobuf_queue* q,
locking inversion, so don't take it here */
err = videobuf_dma_init_user_locked(&mem->dma,
- PCI_DMA_FROMDEVICE,
+ DMA_FROM_DEVICE,
vb->baddr, vb->bsize);
if (0 != err)
return err;
@@ -490,7 +489,7 @@ static int __videobuf_iolock (struct videobuf_queue* q,
*/
bus = (dma_addr_t)(unsigned long)fbuf->base + vb->boff;
pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
- err = videobuf_dma_init_overlay(&mem->dma,PCI_DMA_FROMDEVICE,
+ err = videobuf_dma_init_overlay(&mem->dma, DMA_FROM_DEVICE,
bus, pages);
if (0 != err)
return err;
@@ -498,7 +497,7 @@ static int __videobuf_iolock (struct videobuf_queue* q,
default:
BUG();
}
- err = videobuf_dma_map(q,&mem->dma);
+ err = videobuf_dma_map(q, &mem->dma);
if (0 != err)
return err;
@@ -508,8 +507,8 @@ static int __videobuf_iolock (struct videobuf_queue* q,
static int __videobuf_sync(struct videobuf_queue *q,
struct videobuf_buffer *buf)
{
- struct videbuf_pci_sg_memory *mem=buf->priv;
- BUG_ON (!mem);
+ struct videobuf_dma_sg_memory *mem = buf->priv;
+ BUG_ON(!mem);
MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
return videobuf_dma_sync(q,&mem->dma);
@@ -532,7 +531,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct vm_area_struct *vma)
{
- struct videbuf_pci_sg_memory *mem;
+ struct videobuf_dma_sg_memory *mem;
struct videobuf_mapping *map;
unsigned int first,last,size,i;
int retval;
@@ -547,12 +546,20 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
goto done;
}
+ /* 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
+ */
+
/* look for first buffer to map */
for (first = 0; first < VIDEO_MAX_FRAME; first++) {
if (NULL == q->bufs[first])
continue;
mem=q->bufs[first]->priv;
- BUG_ON (!mem);
+ BUG_ON(!mem);
MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
if (V4L2_MEMORY_MMAP != q->bufs[first]->memory)
@@ -591,10 +598,16 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
map = kmalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
if (NULL == map)
goto done;
- for (size = 0, i = first; i <= last; size += q->bufs[i++]->bsize) {
+
+ size = 0;
+ for (i = first; i <= last; i++) {
+ if (NULL == q->bufs[i])
+ continue;
q->bufs[i]->map = map;
q->bufs[i]->baddr = vma->vm_start + size;
+ size += q->bufs[i]->bsize;
}
+
map->count = 1;
map->start = vma->vm_start;
map->end = vma->vm_end;
@@ -615,8 +628,8 @@ static int __videobuf_copy_to_user ( struct videobuf_queue *q,
char __user *data, size_t count,
int nonblocking )
{
- struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
- BUG_ON (!mem);
+ struct videobuf_dma_sg_memory *mem = q->read_buf->priv;
+ BUG_ON(!mem);
MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
/* copy to userspace */
@@ -634,8 +647,8 @@ static int __videobuf_copy_stream ( struct videobuf_queue *q,
int vbihack, int nonblocking )
{
unsigned int *fc;
- struct videbuf_pci_sg_memory *mem=q->read_buf->priv;
- BUG_ON (!mem);
+ struct videobuf_dma_sg_memory *mem = q->read_buf->priv;
+ BUG_ON(!mem);
MAGIC_CHECK(mem->magic,MAGIC_SG_MEM);
if (vbihack) {
@@ -658,7 +671,7 @@ static int __videobuf_copy_stream ( struct videobuf_queue *q,
return count;
}
-static struct videobuf_qtype_ops pci_ops = {
+static struct videobuf_qtype_ops sg_ops = {
.magic = MAGIC_QTYPE_OPS,
.alloc = __videobuf_alloc,
@@ -670,21 +683,21 @@ static struct videobuf_qtype_ops pci_ops = {
.copy_stream = __videobuf_copy_stream,
};
-void *videobuf_pci_alloc (size_t size)
+void *videobuf_sg_alloc(size_t size)
{
struct videobuf_queue q;
/* Required to make generic handler to call __videobuf_alloc */
- q.int_ops=&pci_ops;
+ q.int_ops = &sg_ops;
- q.msize=size;
+ q.msize = size;
- return videobuf_alloc (&q);
+ return videobuf_alloc(&q);
}
-void videobuf_queue_pci_init(struct videobuf_queue* q,
+void videobuf_queue_sg_init(struct videobuf_queue* q,
struct videobuf_queue_ops *ops,
- void *dev,
+ struct device *dev,
spinlock_t *irqlock,
enum v4l2_buf_type type,
enum v4l2_field field,
@@ -692,7 +705,7 @@ void videobuf_queue_pci_init(struct videobuf_queue* q,
void *priv)
{
videobuf_queue_core_init(q, ops, dev, irqlock, type, field, msize,
- priv, &pci_ops);
+ priv, &sg_ops);
}
/* --------------------------------------------------------------------- */
@@ -709,11 +722,11 @@ EXPORT_SYMBOL_GPL(videobuf_dma_sync);
EXPORT_SYMBOL_GPL(videobuf_dma_unmap);
EXPORT_SYMBOL_GPL(videobuf_dma_free);
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_map);
-EXPORT_SYMBOL_GPL(videobuf_pci_dma_unmap);
-EXPORT_SYMBOL_GPL(videobuf_pci_alloc);
+EXPORT_SYMBOL_GPL(videobuf_sg_dma_map);
+EXPORT_SYMBOL_GPL(videobuf_sg_dma_unmap);
+EXPORT_SYMBOL_GPL(videobuf_sg_alloc);
-EXPORT_SYMBOL_GPL(videobuf_queue_pci_init);
+EXPORT_SYMBOL_GPL(videobuf_queue_sg_init);
/*
* Local variables:
diff --git a/drivers/media/video/videobuf-dvb.c b/drivers/media/video/videobuf-dvb.c
index b73aba65d21d..4ba8b7db7fda 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -30,7 +30,7 @@
MODULE_AUTHOR("Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]");
MODULE_LICENSE("GPL");
-static unsigned int debug = 0;
+static unsigned int debug;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug,"enable debug messages");
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 5266ecc91dab..0bd447d9abe9 100644
--- a/drivers/media/video/videobuf-vmalloc.c
+++ b/drivers/media/video/videobuf-vmalloc.c
@@ -33,7 +33,7 @@
#define MAGIC_CHECK(is,should) if (unlikely((is) != (should))) \
{ printk(KERN_ERR "magic mismatch: %x (expected %x)\n",is,should); BUG(); }
-static int debug = 0;
+static int debug;
module_param(debug, int, 0644);
MODULE_DESCRIPTION("helper module to manage video4linux vmalloc buffers");
@@ -78,8 +78,6 @@ videobuf_vm_close(struct vm_area_struct *vma)
if (q->bufs[i]->map != map)
continue;
- q->ops->buf_release(q,q->bufs[i]);
-
q->bufs[i]->map = NULL;
q->bufs[i]->baddr = 0;
}
@@ -102,7 +100,7 @@ static struct vm_operations_struct videobuf_vm_ops =
/* Allocated area consists on 3 parts:
struct video_buffer
struct <driver>_buffer (cx88_buffer, saa7134_buf, ...)
- struct videobuf_pci_sg_memory
+ struct videobuf_dma_sg_memory
*/
static void *__videobuf_alloc(size_t size)
@@ -153,21 +151,26 @@ static int __videobuf_iolock (struct videobuf_queue* q,
(unsigned long)mem->vmalloc,
pages << PAGE_SHIFT);
- /* It seems that some kernel versions need to do remap *after*
- the mmap() call
- */
- if (mem->vma) {
- int retval=remap_vmalloc_range(mem->vma, mem->vmalloc,0);
- kfree(mem->vma);
- mem->vma=NULL;
- if (retval<0) {
- dprintk(1,"mmap app bug: remap_vmalloc_range area %p error %d\n",
- mem->vmalloc,retval);
- return retval;
+ return 0;
+}
+
+static int __videobuf_mmap_setup(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ int retval = 0;
+ BUG_ON(vb->memory != V4L2_MEMORY_MMAP);
+ if (vb->state == VIDEOBUF_NEEDS_INIT) {
+ /* bsize == size since the buffer needs to be large enough to
+ * hold an entire frame, not the case in the read case for
+ * example*/
+ vb->size = vb->bsize;
+ retval = __videobuf_iolock(q, vb, NULL);
+ if (!retval) {
+ /* Don't IOLOCK later */
+ vb->state = VIDEOBUF_IDLE;
}
}
-
- return 0;
+ return retval;
}
static int __videobuf_sync(struct videobuf_queue *q,
@@ -240,15 +243,8 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
/* Try to remap memory */
retval=remap_vmalloc_range(vma, mem->vmalloc,0);
if (retval<0) {
- dprintk(1,"mmap: postponing remap_vmalloc_range\n");
-
- mem->vma=kmalloc(sizeof(*vma),GFP_KERNEL);
- if (!mem->vma) {
- kfree(map);
- q->bufs[first]->map=NULL;
- return -ENOMEM;
- }
- memcpy(mem->vma,vma,sizeof(*vma));
+ dprintk(1, "mmap: failed to remap_vmalloc_range\n");
+ return -EINVAL;
}
dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
@@ -316,6 +312,7 @@ static struct videobuf_qtype_ops qops = {
.alloc = __videobuf_alloc,
.iolock = __videobuf_iolock,
.sync = __videobuf_sync,
+ .mmap_setup = __videobuf_mmap_setup,
.mmap_free = __videobuf_mmap_free,
.mmap_mapper = __videobuf_mmap_mapper,
.video_copy_to_user = __videobuf_copy_to_user,
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
index 87951ec8254f..b30b6b2a9a85 100644
--- a/drivers/media/video/videocodec.c
+++ b/drivers/media/video/videocodec.c
@@ -44,7 +44,7 @@
#include "videocodec.h"
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-4)");
@@ -325,7 +325,7 @@ videocodec_unregister (const struct videocodec *codec)
/* ============ */
static char *videocodec_buf = NULL;
-static int videocodec_bufsize = 0;
+static int videocodec_bufsize;
static int
videocodec_build_table (void)
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 5bb75294b5aa..d545c98dd5e7 100644
--- a/drivers/media/video/vino.c
+++ b/drivers/media/video/vino.c
@@ -333,7 +333,7 @@ struct vino_settings {
*
* Use non-zero value to enable conversion.
*/
-static int vino_pixel_conversion = 0;
+static int vino_pixel_conversion;
module_param_named(pixelconv, vino_pixel_conversion, int, 0);
@@ -4370,8 +4370,8 @@ static int vino_ioctl(struct inode *inode, struct file *file,
/* Initialization and cleanup */
-// __initdata
-static int vino_init_stage = 0;
+/* __initdata */
+static int vino_init_stage;
static const struct file_operations vino_fops = {
.owner = THIS_MODULE,
@@ -4385,8 +4385,8 @@ static const struct file_operations vino_fops = {
static struct video_device v4l_device_template = {
.name = "NOT SET",
- //.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE |
- // VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY
+ /*.type = VID_TYPE_CAPTURE | VID_TYPE_SUBCAPTURE | */
+ /* VID_TYPE_CLIPPING | VID_TYPE_SCALES, VID_TYPE_OVERLAY */
.fops = &vino_fops,
.minor = -1,
};
diff --git a/drivers/media/video/vivi.c b/drivers/media/video/vivi.c
index 1db067c02815..8353deb8a1d4 100644
--- a/drivers/media/video/vivi.c
+++ b/drivers/media/video/vivi.c
@@ -146,8 +146,6 @@ struct vivi_buffer {
struct vivi_dmaqueue {
struct list_head active;
- struct list_head queued;
- struct timer_list timeout;
/* thread for generating video stream*/
struct task_struct *kthread;
@@ -162,8 +160,8 @@ static LIST_HEAD(vivi_devlist);
struct vivi_dev {
struct list_head vivi_devlist;
- struct mutex lock;
spinlock_t slock;
+ struct mutex mutex;
int users;
@@ -322,24 +320,26 @@ static void gen_line(char *basep, int inipos, int wmax,
end:
return;
}
+
static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
{
int h , pos = 0;
int hmax = buf->vb.height;
int wmax = buf->vb.width;
struct timeval ts;
- char *tmpbuf = kmalloc(wmax * 2, GFP_KERNEL);
+ char *tmpbuf = kmalloc(wmax * 2, GFP_ATOMIC);
void *vbuf = videobuf_to_vmalloc(&buf->vb);
if (!tmpbuf)
return;
+ if (!vbuf)
+ return;
+
for (h = 0; h < hmax; h++) {
gen_line(tmpbuf, 0, wmax, hmax, h, dev->mv_count,
dev->timestr);
- /* FIXME: replacing to __copy_to_user */
- if (copy_to_user(vbuf + pos, tmpbuf, wmax * 2) != 0)
- dprintk(dev, 2, "vivifill copy_to_user failed.\n");
+ memcpy(vbuf + pos, tmpbuf, wmax * 2);
pos += wmax*2;
}
@@ -372,67 +372,58 @@ static void vivi_fillbuff(struct vivi_dev *dev, struct vivi_buffer *buf)
dev->timestr, (unsigned long)tmpbuf, pos);
/* Advice that buffer was filled */
- buf->vb.state = VIDEOBUF_DONE;
buf->vb.field_count++;
do_gettimeofday(&ts);
buf->vb.ts = ts;
-
- list_del(&buf->vb.queue);
- wake_up(&buf->vb.done);
+ buf->vb.state = VIDEOBUF_DONE;
}
-static int restart_video_queue(struct vivi_dmaqueue *dma_q);
-
-static void vivi_thread_tick(struct vivi_dmaqueue *dma_q)
+static void vivi_thread_tick(struct vivi_fh *fh)
{
- struct vivi_buffer *buf;
- struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+ struct vivi_buffer *buf;
+ struct vivi_dev *dev = fh->dev;
+ struct vivi_dmaqueue *dma_q = &dev->vidq;
- int bc;
+ unsigned long flags = 0;
- spin_lock(&dev->slock);
- /* Announces videobuf that all went ok */
- for (bc = 0;; bc++) {
- if (list_empty(&dma_q->active)) {
- dprintk(dev, 1, "No active queue to serve\n");
- break;
- }
+ dprintk(dev, 1, "Thread tick\n");
- buf = list_entry(dma_q->active.next,
- struct vivi_buffer, vb.queue);
+ spin_lock_irqsave(&dev->slock, flags);
+ if (list_empty(&dma_q->active)) {
+ dprintk(dev, 1, "No active queue to serve\n");
+ goto unlock;
+ }
- /* Nobody is waiting something to be done, just return */
- if (!waitqueue_active(&buf->vb.done)) {
- mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
- spin_unlock(&dev->slock);
- return;
- }
+ buf = list_entry(dma_q->active.next,
+ struct vivi_buffer, vb.queue);
- do_gettimeofday(&buf->vb.ts);
- dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+ /* Nobody is waiting on this buffer, return */
+ if (!waitqueue_active(&buf->vb.done))
+ goto unlock;
- /* Fill buffer */
- vivi_fillbuff(dev, buf);
+ list_del(&buf->vb.queue);
- if (list_empty(&dma_q->active)) {
- del_timer(&dma_q->timeout);
- } else {
- mod_timer(&dma_q->timeout, jiffies + BUFFER_TIMEOUT);
- }
- }
- if (bc != 1)
- dprintk(dev, 1, "%s: %d buffers handled (should be 1)\n",
- __FUNCTION__, bc);
- spin_unlock(&dev->slock);
+ do_gettimeofday(&buf->vb.ts);
+
+ /* Fill buffer */
+ vivi_fillbuff(dev, buf);
+ dprintk(dev, 1, "filled buffer %p\n", buf);
+
+ wake_up(&buf->vb.done);
+ dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+unlock:
+ spin_unlock_irqrestore(&dev->slock, flags);
+ return;
}
#define frames_to_ms(frames) \
((frames * WAKE_NUMERATOR * 1000) / WAKE_DENOMINATOR)
-static void vivi_sleep(struct vivi_dmaqueue *dma_q)
+static void vivi_sleep(struct vivi_fh *fh)
{
- struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
- int timeout, running_time;
+ struct vivi_dev *dev = fh->dev;
+ struct vivi_dmaqueue *dma_q = &dev->vidq;
+ int timeout;
DECLARE_WAITQUEUE(wait, current);
dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
@@ -442,37 +433,10 @@ static void vivi_sleep(struct vivi_dmaqueue *dma_q)
if (kthread_should_stop())
goto stop_task;
- running_time = jiffies - dma_q->ini_jiffies;
- dma_q->frame++;
-
/* Calculate time to wake up */
- timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame)) - running_time;
-
- if (timeout > msecs_to_jiffies(frames_to_ms(2)) || timeout <= 0) {
- int old = dma_q->frame;
- int nframes;
-
- dma_q->frame = (jiffies_to_msecs(running_time) /
- frames_to_ms(1)) + 1;
-
- timeout = msecs_to_jiffies(frames_to_ms(dma_q->frame))
- - running_time;
+ timeout = msecs_to_jiffies(frames_to_ms(1));
- if (unlikely (timeout <= 0))
- timeout = 1;
-
- nframes = (dma_q->frame > old)?
- dma_q->frame - old : old - dma_q->frame;
-
- dprintk(dev, 1, "%ld: %s %d frames. "
- "Current frame is %d. Will sleep for %d jiffies\n",
- jiffies,
- (dma_q->frame > old)? "Underrun, losed" : "Overrun of",
- nframes, dma_q->frame, timeout);
- } else
- dprintk(dev, 1, "will sleep for %d jiffies\n", timeout);
-
- vivi_thread_tick(dma_q);
+ vivi_thread_tick(fh);
schedule_timeout_interruptible(timeout);
@@ -483,16 +447,15 @@ stop_task:
static int vivi_thread(void *data)
{
- struct vivi_dmaqueue *dma_q = data;
- struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+ struct vivi_fh *fh = data;
+ struct vivi_dev *dev = fh->dev;
dprintk(dev, 1, "thread started\n");
- mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
set_freezable();
for (;;) {
- vivi_sleep(dma_q);
+ vivi_sleep(fh);
if (kthread_should_stop())
break;
@@ -501,16 +464,17 @@ static int vivi_thread(void *data)
return 0;
}
-static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
+static int vivi_start_thread(struct vivi_fh *fh)
{
- struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
+ struct vivi_dev *dev = fh->dev;
+ struct vivi_dmaqueue *dma_q = &dev->vidq;
dma_q->frame = 0;
dma_q->ini_jiffies = jiffies;
dprintk(dev, 1, "%s\n", __FUNCTION__);
- dma_q->kthread = kthread_run(vivi_thread, dma_q, "vivi");
+ dma_q->kthread = kthread_run(vivi_thread, fh, "vivi");
if (IS_ERR(dma_q->kthread)) {
printk(KERN_ERR "vivi: kernel_thread() failed\n");
@@ -535,91 +499,6 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
}
}
-static int restart_video_queue(struct vivi_dmaqueue *dma_q)
-{
- struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
- struct vivi_buffer *buf, *prev;
-
- dprintk(dev, 1, "%s dma_q=0x%08lx\n", __FUNCTION__,
- (unsigned long)dma_q);
-
- if (!list_empty(&dma_q->active)) {
- buf = list_entry(dma_q->active.next,
- struct vivi_buffer, vb.queue);
- dprintk(dev, 2, "restart_queue [%p/%d]: restart dma\n",
- buf, buf->vb.i);
-
- dprintk(dev, 1, "Restarting video dma\n");
- vivi_stop_thread(dma_q);
-
- /* cancel all outstanding capture / vbi requests */
- list_for_each_entry_safe(buf, prev, &dma_q->active, vb.queue) {
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- }
- mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
-
- return 0;
- }
-
- prev = NULL;
- for (;;) {
- if (list_empty(&dma_q->queued))
- return 0;
- buf = list_entry(dma_q->queued.next,
- struct vivi_buffer, vb.queue);
- if (NULL == prev) {
- list_del(&buf->vb.queue);
- list_add_tail(&buf->vb.queue, &dma_q->active);
-
- dprintk(dev, 1, "Restarting video dma\n");
- vivi_stop_thread(dma_q);
- vivi_start_thread(dma_q);
-
- buf->vb.state = VIDEOBUF_ACTIVE;
- mod_timer(&dma_q->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(dev, 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, &dma_q->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- dprintk(dev, 2,
- "[%p/%d] restart_queue - move to active\n",
- buf, buf->vb.i);
- } else {
- return 0;
- }
- prev = buf;
- }
-}
-
-static void vivi_vid_timeout(unsigned long data)
-{
- struct vivi_dev *dev = (struct vivi_dev *)data;
- struct vivi_dmaqueue *vidq = &dev->vidq;
- struct vivi_buffer *buf;
-
- spin_lock(&dev->slock);
-
- while (!list_empty(&vidq->active)) {
- buf = list_entry(vidq->active.next,
- struct vivi_buffer, vb.queue);
- list_del(&buf->vb.queue);
- buf->vb.state = VIDEOBUF_ERROR;
- wake_up(&buf->vb.done);
- printk(KERN_INFO "vivi/0: [%p/%d] timeout\n", buf, buf->vb.i);
- }
- restart_video_queue(vidq);
-
- spin_unlock(&dev->slock);
-}
-
/* ------------------------------------------------------------------
Videobuf operations
------------------------------------------------------------------*/
@@ -648,13 +527,13 @@ static void free_buffer(struct videobuf_queue *vq, struct vivi_buffer *buf)
struct vivi_fh *fh = vq->priv_data;
struct vivi_dev *dev = fh->dev;
- dprintk(dev, 1, "%s\n", __FUNCTION__);
+ dprintk(dev, 1, "%s, state: %i\n", __FUNCTION__, buf->vb.state);
if (in_interrupt())
BUG();
- videobuf_waiton(&buf->vb, 0, 0);
videobuf_vmalloc_free(&buf->vb);
+ dprintk(dev, 1, "free_buffer: freed");
buf->vb.state = VIDEOBUF_NEEDS_INIT;
}
@@ -667,28 +546,25 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct vivi_fh *fh = vq->priv_data;
struct vivi_dev *dev = fh->dev;
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
- int rc, init_buffer = 0;
+ int rc;
dprintk(dev, 1, "%s, field=%d\n", __FUNCTION__, field);
BUG_ON(NULL == fh->fmt);
+
if (fh->width < 48 || fh->width > norm_maxw() ||
fh->height < 32 || fh->height > norm_maxh())
return -EINVAL;
+
buf->vb.size = fh->width*fh->height*2;
if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
return -EINVAL;
- if (buf->fmt != fh->fmt ||
- buf->vb.width != fh->width ||
- buf->vb.height != fh->height ||
- buf->vb.field != field) {
- buf->fmt = fh->fmt;
- buf->vb.width = fh->width;
- buf->vb.height = fh->height;
- buf->vb.field = field;
- init_buffer = 1;
- }
+ /* These properties only change when queue is idle, see s_fmt */
+ buf->fmt = fh->fmt;
+ buf->vb.width = fh->width;
+ buf->vb.height = fh->height;
+ buf->vb.field = field;
if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
rc = videobuf_iolock(vq, &buf->vb, NULL);
@@ -711,45 +587,12 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
struct vivi_fh *fh = vq->priv_data;
struct vivi_dev *dev = fh->dev;
- struct vivi_dmaqueue *vidq = &dev->vidq;
- struct vivi_buffer *prev;
-
- if (!list_empty(&vidq->queued)) {
- dprintk(dev, 1, "adding vb queue=0x%08lx\n",
- (unsigned long)&buf->vb.queue);
- list_add_tail(&buf->vb.queue, &vidq->queued);
- buf->vb.state = VIDEOBUF_QUEUED;
- dprintk(dev, 2, "[%p/%d] buffer_queue - append to queued\n",
- buf, buf->vb.i);
- } else if (list_empty(&vidq->active)) {
- list_add_tail(&buf->vb.queue, &vidq->active);
-
- buf->vb.state = VIDEOBUF_ACTIVE;
- mod_timer(&vidq->timeout, jiffies+BUFFER_TIMEOUT);
- dprintk(dev, 2, "[%p/%d] buffer_queue - first active\n",
- buf, buf->vb.i);
-
- vivi_start_thread(vidq);
- } else {
- prev = list_entry(vidq->active.prev,
- struct vivi_buffer, vb.queue);
- if (prev->vb.width == buf->vb.width &&
- prev->vb.height == buf->vb.height &&
- prev->fmt == buf->fmt) {
- list_add_tail(&buf->vb.queue, &vidq->active);
- buf->vb.state = VIDEOBUF_ACTIVE;
- dprintk(dev, 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(dev, 2,
- "[%p/%d] buffer_queue - first queued\n",
- buf, buf->vb.i);
- }
- }
+ struct vivi_dmaqueue *vidq = &dev->vidq;
+
+ dprintk(dev, 1, "%s\n", __FUNCTION__);
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
}
static void buffer_release(struct videobuf_queue *vq,
@@ -758,12 +601,9 @@ static void buffer_release(struct videobuf_queue *vq,
struct vivi_buffer *buf = container_of(vb, struct vivi_buffer, vb);
struct vivi_fh *fh = vq->priv_data;
struct vivi_dev *dev = (struct vivi_dev *)fh->dev;
- struct vivi_dmaqueue *vidq = &dev->vidq;
dprintk(dev, 1, "%s\n", __FUNCTION__);
- vivi_stop_thread(vidq);
-
free_buffer(vq, buf);
}
@@ -869,17 +709,31 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
struct v4l2_format *f)
{
struct vivi_fh *fh = priv;
+ struct videobuf_queue *q = &fh->vb_vidq;
+
int ret = vidioc_try_fmt_cap(file, fh, f);
if (ret < 0)
return (ret);
+ mutex_lock(&q->vb_lock);
+
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ dprintk(fh->dev, 1, "%s queue busy\n", __FUNCTION__);
+ ret = -EBUSY;
+ goto out;
+ }
+
fh->fmt = &format;
fh->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height;
fh->vb_vidq.field = f->fmt.pix.field;
fh->type = f->type;
- return (0);
+ ret = 0;
+out:
+ mutex_unlock(&q->vb_lock);
+
+ return (ret);
}
static int vidioc_reqbufs(struct file *file, void *priv,
@@ -1036,6 +890,7 @@ static int vivi_open(struct inode *inode, struct file *file)
struct vivi_dev *dev;
struct vivi_fh *fh;
int i;
+ int retval = 0;
printk(KERN_DEBUG "vivi: open called (minor=%d)\n", minor);
@@ -1045,9 +900,15 @@ static int vivi_open(struct inode *inode, struct file *file)
return -ENODEV;
found:
- /* If more than one user, mutex should be added */
+ mutex_lock(&dev->mutex);
dev->users++;
+ if (dev->users > 1) {
+ dev->users--;
+ retval = -EBUSY;
+ goto unlock;
+ }
+
dprintk(dev, 1, "open minor=%d type=%s users=%d\n", minor,
v4l2_type_names[V4L2_BUF_TYPE_VIDEO_CAPTURE], dev->users);
@@ -1055,8 +916,13 @@ found:
fh = kzalloc(sizeof(*fh), GFP_KERNEL);
if (NULL == fh) {
dev->users--;
- return -ENOMEM;
+ retval = -ENOMEM;
+ goto unlock;
}
+unlock:
+ mutex_unlock(&dev->mutex);
+ if (retval)
+ return retval;
file->private_data = fh;
fh->dev = dev;
@@ -1084,6 +950,8 @@ found:
NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
sizeof(struct vivi_buffer), fh);
+ vivi_start_thread(fh);
+
return 0;
}
@@ -1128,7 +996,9 @@ static int vivi_close(struct inode *inode, struct file *file)
kfree(fh);
+ mutex_lock(&dev->mutex);
dev->users--;
+ mutex_unlock(&dev->mutex);
dprintk(dev, 1, "close called (minor=%d, users=%d)\n",
minor, dev->users);
@@ -1182,6 +1052,7 @@ static const struct file_operations vivi_fops = {
.read = vivi_read,
.poll = vivi_poll,
.ioctl = video_ioctl2, /* V4L2 ioctl handler */
+ .compat_ioctl = v4l_compat_ioctl32,
.mmap = vivi_mmap,
.llseek = no_llseek,
};
@@ -1236,16 +1107,11 @@ static int __init vivi_init(void)
/* init video dma queues */
INIT_LIST_HEAD(&dev->vidq.active);
- INIT_LIST_HEAD(&dev->vidq.queued);
init_waitqueue_head(&dev->vidq.wq);
/* initialize locks */
- mutex_init(&dev->lock);
spin_lock_init(&dev->slock);
-
- dev->vidq.timeout.function = vivi_vid_timeout;
- dev->vidq.timeout.data = (unsigned long)dev;
- init_timer(&dev->vidq.timeout);
+ mutex_init(&dev->mutex);
vfd = video_device_alloc();
if (NULL == vfd)
diff --git a/drivers/media/video/vpx3220.c b/drivers/media/video/vpx3220.c
index a9133858e913..35293029da02 100644
--- a/drivers/media/video/vpx3220.c
+++ b/drivers/media/video/vpx3220.c
@@ -40,7 +40,7 @@
#define I2C_VPX3220 0x86
#define VPX3220_DEBUG KERN_DEBUG "vpx3220: "
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-1)");
diff --git a/drivers/media/video/w9966.c b/drivers/media/video/w9966.c
index 08aaae07c7e0..cdb396d9203c 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -61,7 +61,7 @@
#include <media/v4l2-common.h>
#include <linux/parport.h>
-//#define DEBUG // Undef me for production
+/*#define DEBUG*/ /* Undef me for production */
#ifdef DEBUG
#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __FUNCTION__ , ##a)
@@ -134,7 +134,7 @@ MODULE_PARM_DESC(pardev, "pardev: where to search for\n\
\tEg: >pardev=parport3,aggressive,parport2,parport1< would assign\n\
\tcam 1 to parport3 and search every parport for cam 2 etc...");
-static int parmode = 0;
+static int parmode;
module_param(parmode, int, 0);
MODULE_PARM_DESC(parmode, "parmode: transfer mode (0=auto, 1=ecp, 2=epp");
@@ -188,7 +188,9 @@ static const struct file_operations w9966_fops = {
.open = video_exclusive_open,
.release = video_exclusive_release,
.ioctl = w9966_v4l_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.read = w9966_v4l_read,
.llseek = no_llseek,
};
diff --git a/drivers/media/video/w9968cf.c b/drivers/media/video/w9968cf.c
index 2ae1430f5f7d..840522442d07 100644
--- a/drivers/media/video/w9968cf.c
+++ b/drivers/media/video/w9968cf.c
@@ -3461,7 +3461,9 @@ static const struct file_operations w9968cf_fops = {
.release = w9968cf_release,
.read = w9968cf_read,
.ioctl = w9968cf_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.mmap = w9968cf_mmap,
.llseek = no_llseek,
};
@@ -3481,7 +3483,7 @@ w9968cf_usb_probe(struct usb_interface* intf, const struct usb_device_id* id)
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 dev_nr; /* 0 - we are handling device number n */
if (le16_to_cpu(udev->descriptor.idVendor) == winbond_id_table[0].idVendor &&
le16_to_cpu(udev->descriptor.idProduct) == winbond_id_table[0].idProduct)
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 2c5665c82442..363dd2b9475c 100644
--- a/drivers/media/video/zc0301/zc0301_core.c
+++ b/drivers/media/video/zc0301/zc0301_core.c
@@ -1925,7 +1925,9 @@ static const struct file_operations zc0301_fops = {
.open = zc0301_open,
.release = zc0301_release,
.ioctl = zc0301_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.read = zc0301_read,
.poll = zc0301_poll,
.mmap = zc0301_mmap,
@@ -1939,7 +1941,7 @@ 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 = 0;
+ static unsigned int dev_nr;
unsigned int i;
int err = 0;
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 690281bb59ee..006d48847e24 100644
--- a/drivers/media/video/zoran_card.c
+++ b/drivers/media/video/zoran_card.c
@@ -83,7 +83,7 @@ MODULE_PARM_DESC(decoder, "i2c TV decoder");
or set in in a VIDIOCSFBUF ioctl
*/
-static unsigned long vidmem = 0; /* Video memory base address */
+static unsigned long vidmem; /* default = 0 - Video memory base address */
module_param(vidmem, ulong, 0444);
MODULE_PARM_DESC(vidmem, "Default video memory base address");
@@ -91,7 +91,7 @@ MODULE_PARM_DESC(vidmem, "Default video memory base address");
Default input and video norm at startup of the driver.
*/
-static unsigned int default_input = 0; /* 0=Composite, 1=S-Video */
+static unsigned int default_input; /* default 0 = Composite, 1 = S-Video */
module_param(default_input, uint, 0444);
MODULE_PARM_DESC(default_input,
"Default input (0=Composite, 1=S-Video, 2=Internal)");
@@ -101,7 +101,7 @@ module_param(default_mux, int, 0644);
MODULE_PARM_DESC(default_mux,
"Default 6 Eyes mux setting (Input selection)");
-static int default_norm = 0; /* 0=PAL, 1=NTSC 2=SECAM */
+static int default_norm; /* default 0 = PAL, 1 = NTSC 2 = SECAM */
module_param(default_norm, int, 0444);
MODULE_PARM_DESC(default_norm, "Default norm (0=PAL, 1=NTSC, 2=SECAM)");
diff --git a/drivers/media/video/zoran_card.h b/drivers/media/video/zoran_card.h
index 8444ca0a5f3f..1b5c4171cf9c 100644
--- a/drivers/media/video/zoran_card.h
+++ b/drivers/media/video/zoran_card.h
@@ -50,4 +50,6 @@ extern int zoran_check_jpg_settings(struct zoran *zr,
extern void zoran_open_init_params(struct zoran *zr);
extern void zoran_vdev_release(struct video_device *vdev);
+void zr36016_write(struct videocodec *codec, u16 reg, u32 val);
+
#endif /* __ZORAN_CARD_H__ */
diff --git a/drivers/media/video/zoran_device.c b/drivers/media/video/zoran_device.c
index f97c20692057..7b60533efe45 100644
--- a/drivers/media/video/zoran_device.c
+++ b/drivers/media/video/zoran_device.c
@@ -60,7 +60,8 @@
extern const struct zoran_format zoran_formats[];
-static int lml33dpath = 0; /* 1 will use digital path in capture
+static int lml33dpath; /* default = 0
+ * 1 will use digital path in capture
* mode instead of analog. It can be
* used for picture adjustments using
* tool like xawtv while watching image
@@ -927,11 +928,6 @@ count_reset_interrupt (struct zoran *zr)
return isr;
}
-/* hack */
-extern void zr36016_write (struct videocodec *codec,
- u16 reg,
- u32 val);
-
void
jpeg_start (struct zoran *zr)
{
@@ -987,7 +983,7 @@ void
zr36057_enable_jpg (struct zoran *zr,
enum zoran_codec_mode mode)
{
- static int zero = 0;
+ static int zero;
static int one = 1;
struct vfe_settings cap;
int field_size =
@@ -1726,7 +1722,7 @@ decoder_command (struct zoran *zr,
return -EIO;
if (zr->card.type == LML33 &&
- (cmd == DECODER_SET_NORM || DECODER_SET_INPUT)) {
+ (cmd == DECODER_SET_NORM || cmd == DECODER_SET_INPUT)) {
int res;
// Bt819 needs to reset its FIFO buffer using #FRST pin and
diff --git a/drivers/media/video/zoran_driver.c b/drivers/media/video/zoran_driver.c
index fea4946ee713..8c0a379071e5 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -205,7 +205,7 @@ extern int jpg_nbufs;
extern int jpg_bufsize;
extern int pass_through;
-static int lock_norm = 0; /* 1=Don't change TV standard (norm) */
+static int lock_norm; /* 0 = default 1 = Don't change TV standard (norm) */
module_param(lock_norm, int, 0644);
MODULE_PARM_DESC(lock_norm, "Prevent norm changes (1 = ignore, >1 = fail)");
@@ -4644,7 +4644,9 @@ static const struct file_operations zoran_fops = {
.open = zoran_open,
.release = zoran_close,
.ioctl = zoran_ioctl,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.llseek = no_llseek,
.read = zoran_read,
.write = zoran_write,
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index dd084555da8f..00d132bcd1e4 100644
--- a/drivers/media/video/zr36016.c
+++ b/drivers/media/video/zr36016.c
@@ -55,11 +55,10 @@
#define MAX_CODECS 20
/* amount of chips attached via this driver */
-static int zr36016_codecs = 0;
+static int zr36016_codecs;
/* debugging is available via module parameter */
-
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-4)");
diff --git a/drivers/media/video/zr36050.c b/drivers/media/video/zr36050.c
index faae4ec3ea0b..cf8b271a1c8f 100644
--- a/drivers/media/video/zr36050.c
+++ b/drivers/media/video/zr36050.c
@@ -52,11 +52,10 @@
#define MAX_CODECS 20
/* amount of chips attached via this driver */
-static int zr36050_codecs = 0;
+static int zr36050_codecs;
/* debugging is available via module parameter */
-
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-4)");
diff --git a/drivers/media/video/zr36060.c b/drivers/media/video/zr36060.c
index 7849b65969d0..8e74054d5ef1 100644
--- a/drivers/media/video/zr36060.c
+++ b/drivers/media/video/zr36060.c
@@ -52,14 +52,14 @@
#define MAX_CODECS 20
/* amount of chips attached via this driver */
-static int zr36060_codecs = 0;
+static int zr36060_codecs;
-static int low_bitrate = 0;
+static int low_bitrate;
module_param(low_bitrate, bool, 0);
MODULE_PARM_DESC(low_bitrate, "Buz compatibility option, halves bitrate");
/* debugging is available via module parameter */
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-4)");
diff --git a/drivers/media/video/zr364xx.c b/drivers/media/video/zr364xx.c
index 04949c823654..a0e49dc66301 100644
--- a/drivers/media/video/zr364xx.c
+++ b/drivers/media/video/zr364xx.c
@@ -62,8 +62,8 @@
/* Module parameters */
-static int debug = 0;
-static int mode = 0;
+static int debug;
+static int mode;
/* Module parameters interface */
diff --git a/include/asm-arm/arch-pxa/camera.h b/include/asm-arm/arch-pxa/camera.h
new file mode 100644
index 000000000000..39516ced8b1f
--- /dev/null
+++ b/include/asm-arm/arch-pxa/camera.h
@@ -0,0 +1,48 @@
+/*
+ camera.h - PXA camera driver header file
+
+ Copyright (C) 2003, Intel Corporation
+ Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License 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 __ASM_ARCH_CAMERA_H_
+#define __ASM_ARCH_CAMERA_H_
+
+#define PXA_CAMERA_MASTER 1
+#define PXA_CAMERA_DATAWIDTH_4 2
+#define PXA_CAMERA_DATAWIDTH_5 4
+#define PXA_CAMERA_DATAWIDTH_8 8
+#define PXA_CAMERA_DATAWIDTH_9 0x10
+#define PXA_CAMERA_DATAWIDTH_10 0x20
+#define PXA_CAMERA_PCLK_EN 0x40
+#define PXA_CAMERA_MCLK_EN 0x80
+#define PXA_CAMERA_PCP 0x100
+#define PXA_CAMERA_HSP 0x200
+#define PXA_CAMERA_VSP 0x400
+
+struct pxacamera_platform_data {
+ int (*init)(struct device *);
+ int (*power)(struct device *, int);
+ int (*reset)(struct device *, int);
+
+ unsigned long flags;
+ unsigned long mclk_10khz;
+};
+
+extern void pxa_set_camera_info(struct pxacamera_platform_data *);
+
+#endif /* __ASM_ARCH_CAMERA_H_ */
diff --git a/include/asm-arm/arch-pxa/pxa-regs.h b/include/asm-arm/arch-pxa/pxa-regs.h
index 2357a73340d4..87bfd7fce103 100644
--- a/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/include/asm-arm/arch-pxa/pxa-regs.h
@@ -46,13 +46,13 @@
#define PCMCIA1AttrSp PCMCIAAttrSp /* PCMCIA 1 Attribute Space [byte] */
#define PCMCIA1MemSp PCMCIAMemSp /* PCMCIA 1 Memory Space [byte] */
-#define _PCMCIA(Nb) /* PCMCIA [0..1] */ \
- (0x20000000 + (Nb)*PCMCIASp)
+#define _PCMCIA(Nb) /* PCMCIA [0..1] */ \
+ (0x20000000 + (Nb)*PCMCIASp)
#define _PCMCIAIO(Nb) _PCMCIA (Nb) /* PCMCIA I/O [0..1] */
-#define _PCMCIAAttr(Nb) /* PCMCIA Attribute [0..1] */ \
- (_PCMCIA (Nb) + 2*PCMCIAPrtSp)
-#define _PCMCIAMem(Nb) /* PCMCIA Memory [0..1] */ \
- (_PCMCIA (Nb) + 3*PCMCIAPrtSp)
+#define _PCMCIAAttr(Nb) /* PCMCIA Attribute [0..1] */ \
+ (_PCMCIA (Nb) + 2*PCMCIAPrtSp)
+#define _PCMCIAMem(Nb) /* PCMCIA Memory [0..1] */ \
+ (_PCMCIA (Nb) + 3*PCMCIAPrtSp)
#define _PCMCIA0 _PCMCIA (0) /* PCMCIA 0 */
#define _PCMCIA0IO _PCMCIAIO (0) /* PCMCIA 0 I/O */
@@ -1248,19 +1248,26 @@
#define GPIO10_RTCCLK 10 /* real time clock (1 Hz) */
#define GPIO11_3_6MHz 11 /* 3.6 MHz oscillator out */
#define GPIO12_32KHz 12 /* 32 kHz out */
+#define GPIO12_CIF_DD7 12 /* Capture Interface D7 (PXA27x) */
#define GPIO13_MBGNT 13 /* memory controller grant */
#define GPIO14_MBREQ 14 /* alternate bus master request */
#define GPIO15_nCS_1 15 /* chip select 1 */
#define GPIO16_PWM0 16 /* PWM0 output */
#define GPIO17_PWM1 17 /* PWM1 output */
+#define GPIO17_CIF_DD6 17 /* Capture Interface D6 (PXA27x) */
#define GPIO18_RDY 18 /* Ext. Bus Ready */
#define GPIO19_DREQ1 19 /* External DMA Request */
#define GPIO20_DREQ0 20 /* External DMA Request */
#define GPIO23_SCLK 23 /* SSP clock */
+#define GPIO23_CIF_MCLK 23 /* Capture Interface MCLK (PXA27x) */
#define GPIO24_SFRM 24 /* SSP Frame */
+#define GPIO24_CIF_FV 24 /* Capture Interface FV (PXA27x) */
#define GPIO25_STXD 25 /* SSP transmit */
+#define GPIO25_CIF_LV 25 /* Capture Interface LV (PXA27x) */
#define GPIO26_SRXD 26 /* SSP receive */
+#define GPIO26_CIF_PCLK 26 /* Capture Interface PCLK (PXA27x) */
#define GPIO27_SEXTCLK 27 /* SSP ext_clk */
+#define GPIO27_CIF_DD0 27 /* Capture Interface D0 (PXA27x) */
#define GPIO28_BITCLK 28 /* AC97/I2S bit_clk */
#define GPIO29_SDATA_IN 29 /* AC97 Sdata_in0 / I2S Sdata_in */
#define GPIO30_SDATA_OUT 30 /* AC97/I2S Sdata_out */
@@ -1281,28 +1288,40 @@
#define GPIO41_FFRTS 41 /* FFUART request to send */
#define GPIO42_BTRXD 42 /* BTUART receive data */
#define GPIO42_HWRXD 42 /* HWUART receive data */
+#define GPIO42_CIF_MCLK 42 /* Capture interface MCLK (PXA27x) */
#define GPIO43_BTTXD 43 /* BTUART transmit data */
#define GPIO43_HWTXD 43 /* HWUART transmit data */
+#define GPIO43_CIF_FV 43 /* Capture interface FV (PXA27x) */
#define GPIO44_BTCTS 44 /* BTUART clear to send */
#define GPIO44_HWCTS 44 /* HWUART clear to send */
+#define GPIO44_CIF_LV 44 /* Capture interface LV (PXA27x) */
#define GPIO45_BTRTS 45 /* BTUART request to send */
#define GPIO45_HWRTS 45 /* HWUART request to send */
#define GPIO45_AC97_SYSCLK 45 /* AC97 System Clock */
+#define GPIO45_CIF_PCLK 45 /* Capture interface PCLK (PXA27x) */
#define GPIO46_ICPRXD 46 /* ICP receive data */
#define GPIO46_STRXD 46 /* STD_UART receive data */
#define GPIO47_ICPTXD 47 /* ICP transmit data */
#define GPIO47_STTXD 47 /* STD_UART transmit data */
+#define GPIO47_CIF_DD0 47 /* Capture interface D0 (PXA27x) */
#define GPIO48_nPOE 48 /* Output Enable for Card Space */
+#define GPIO48_CIF_DD5 48 /* Capture interface D5 (PXA27x) */
#define GPIO49_nPWE 49 /* Write Enable for Card Space */
#define GPIO50_nPIOR 50 /* I/O Read for Card Space */
+#define GPIO50_CIF_DD3 50 /* Capture interface D3 (PXA27x) */
#define GPIO51_nPIOW 51 /* I/O Write for Card Space */
+#define GPIO51_CIF_DD2 51 /* Capture interface D2 (PXA27x) */
#define GPIO52_nPCE_1 52 /* Card Enable for Card Space */
+#define GPIO52_CIF_DD4 52 /* Capture interface D4 (PXA27x) */
#define GPIO53_nPCE_2 53 /* Card Enable for Card Space */
#define GPIO53_MMCCLK 53 /* MMC Clock */
+#define GPIO53_CIF_MCLK 53 /* Capture interface MCLK (PXA27x) */
#define GPIO54_MMCCLK 54 /* MMC Clock */
#define GPIO54_pSKTSEL 54 /* Socket Select for Card Space */
#define GPIO54_nPCE_2 54 /* Card Enable for Card Space (PXA27x) */
+#define GPIO54_CIF_PCLK 54 /* Capture interface PCLK (PXA27x) */
#define GPIO55_nPREG 55 /* Card Address bit 26 */
+#define GPIO55_CIF_DD1 55 /* Capture interface D1 (PXA27x) */
#define GPIO56_nPWAIT 56 /* Wait signal for Card Space */
#define GPIO57_nIOIS16 57 /* Bus Width select for I/O Card Space */
#define GPIO58_LDD_0 58 /* LCD data pin 0 */
@@ -1337,11 +1356,28 @@
#define GPIO79_nCS_3 79 /* chip select 3 */
#define GPIO80_nCS_4 80 /* chip select 4 */
#define GPIO81_NSCLK 81 /* NSSP clock */
+#define GPIO81_CIF_DD0 81 /* Capture Interface D0 (PXA27x) */
#define GPIO82_NSFRM 82 /* NSSP Frame */
+#define GPIO82_CIF_DD5 82 /* Capture Interface D5 (PXA27x) */
#define GPIO83_NSTXD 83 /* NSSP transmit */
+#define GPIO83_CIF_DD4 83 /* Capture Interface D4 (PXA27x) */
#define GPIO84_NSRXD 84 /* NSSP receive */
+#define GPIO84_CIF_FV 84 /* Capture Interface FV (PXA27x) */
#define GPIO85_nPCE_1 85 /* Card Enable for Card Space (PXA27x) */
+#define GPIO85_CIF_LV 85 /* Capture Interface LV (PXA27x) */
+#define GPIO90_CIF_DD4 90 /* Capture Interface DD4 (PXA27x) */
+#define GPIO91_CIF_DD5 91 /* Capture Interface DD5 (PXA27x) */
#define GPIO92_MMCDAT0 92 /* MMC DAT0 (PXA27x) */
+#define GPIO93_CIF_DD6 93 /* Capture interface D6 (PXA27x) */
+#define GPIO94_CIF_DD5 94 /* Capture interface D5 (PXA27x) */
+#define GPIO95_CIF_DD4 95 /* Capture interface D4 (PXA27x) */
+#define GPIO98_CIF_DD0 98 /* Capture interface D0 (PXA27x) */
+#define GPIO103_CIF_DD3 103 /* Capture interface D3 (PXA27x) */
+#define GPIO104_CIF_DD2 104 /* Capture interface D2 (PXA27x) */
+#define GPIO105_CIF_DD1 105 /* Capture interface D1 (PXA27x) */
+#define GPIO106_CIF_DD9 106 /* Capture interface D9 (PXA27x) */
+#define GPIO107_CIF_DD8 107 /* Capture interface D8 (PXA27x) */
+#define GPIO108_CIF_DD7 108 /* Capture interface D7 (PXA27x) */
#define GPIO102_nPCE_1 102 /* PCMCIA (PXA27x) */
#define GPIO109_MMCDAT1 109 /* MMC DAT1 (PXA27x) */
#define GPIO110_MMCDAT2 110 /* MMC DAT2 (PXA27x) */
@@ -1351,6 +1387,9 @@
#define GPIO112_MMCCMD 112 /* MMC CMD (PXA27x) */
#define GPIO113_I2S_SYSCLK 113 /* I2S System Clock (PXA27x) */
#define GPIO113_AC97_RESET_N 113 /* AC97 NRESET on (PXA27x) */
+#define GPIO114_CIF_DD1 114 /* Capture interface D1 (PXA27x) */
+#define GPIO115_CIF_DD3 115 /* Capture interface D3 (PXA27x) */
+#define GPIO116_CIF_DD2 116 /* Capture interface D2 (PXA27x) */
/* GPIO alternate function mode & direction */
@@ -1376,19 +1415,26 @@
#define GPIO10_RTCCLK_MD (10 | GPIO_ALT_FN_1_OUT)
#define GPIO11_3_6MHz_MD (11 | GPIO_ALT_FN_1_OUT)
#define GPIO12_32KHz_MD (12 | GPIO_ALT_FN_1_OUT)
+#define GPIO12_CIF_DD7_MD (12 | GPIO_ALT_FN_2_IN)
#define GPIO13_MBGNT_MD (13 | GPIO_ALT_FN_2_OUT)
#define GPIO14_MBREQ_MD (14 | GPIO_ALT_FN_1_IN)
#define GPIO15_nCS_1_MD (15 | GPIO_ALT_FN_2_OUT)
#define GPIO16_PWM0_MD (16 | GPIO_ALT_FN_2_OUT)
#define GPIO17_PWM1_MD (17 | GPIO_ALT_FN_2_OUT)
+#define GPIO17_CIF_DD6_MD (17 | GPIO_ALT_FN_2_IN)
#define GPIO18_RDY_MD (18 | GPIO_ALT_FN_1_IN)
#define GPIO19_DREQ1_MD (19 | GPIO_ALT_FN_1_IN)
#define GPIO20_DREQ0_MD (20 | GPIO_ALT_FN_1_IN)
+#define GPIO23_CIF_MCLK_MD (23 | GPIO_ALT_FN_1_OUT)
#define GPIO23_SCLK_MD (23 | GPIO_ALT_FN_2_OUT)
+#define GPIO24_CIF_FV_MD (24 | GPIO_ALT_FN_1_OUT)
#define GPIO24_SFRM_MD (24 | GPIO_ALT_FN_2_OUT)
+#define GPIO25_CIF_LV_MD (25 | GPIO_ALT_FN_1_OUT)
#define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT)
#define GPIO26_SRXD_MD (26 | GPIO_ALT_FN_1_IN)
+#define GPIO26_CIF_PCLK_MD (26 | GPIO_ALT_FN_2_IN)
#define GPIO27_SEXTCLK_MD (27 | GPIO_ALT_FN_1_IN)
+#define GPIO27_CIF_DD0_MD (27 | GPIO_ALT_FN_3_IN)
#define GPIO28_BITCLK_AC97_MD (28 | GPIO_ALT_FN_1_IN)
#define GPIO28_BITCLK_IN_I2S_MD (28 | GPIO_ALT_FN_2_IN)
#define GPIO28_BITCLK_OUT_I2S_MD (28 | GPIO_ALT_FN_1_OUT)
@@ -1413,34 +1459,46 @@
#define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT)
#define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT)
#define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN)
+#define GPIO42_CIF_MCLK_MD (42 | GPIO_ALT_FN_3_OUT)
#define GPIO42_HWRXD_MD (42 | GPIO_ALT_FN_3_IN)
#define GPIO43_BTTXD_MD (43 | GPIO_ALT_FN_2_OUT)
+#define GPIO43_CIF_FV_MD (43 | GPIO_ALT_FN_3_OUT)
#define GPIO43_HWTXD_MD (43 | GPIO_ALT_FN_3_OUT)
#define GPIO44_BTCTS_MD (44 | GPIO_ALT_FN_1_IN)
#define GPIO44_HWCTS_MD (44 | GPIO_ALT_FN_3_IN)
+#define GPIO44_CIF_LV_MD (44 | GPIO_ALT_FN_3_OUT)
#define GPIO45_BTRTS_MD (45 | GPIO_ALT_FN_2_OUT)
#define GPIO45_HWRTS_MD (45 | GPIO_ALT_FN_3_OUT)
#define GPIO45_SYSCLK_AC97_MD (45 | GPIO_ALT_FN_1_OUT)
+#define GPIO45_CIF_PCLK_MD (45 | GPIO_ALT_FN_3_IN)
#define GPIO46_ICPRXD_MD (46 | GPIO_ALT_FN_1_IN)
#define GPIO46_STRXD_MD (46 | GPIO_ALT_FN_2_IN)
#define GPIO47_ICPTXD_MD (47 | GPIO_ALT_FN_2_OUT)
#define GPIO47_STTXD_MD (47 | GPIO_ALT_FN_1_OUT)
+#define GPIO47_CIF_DD0_MD (47 | GPIO_ALT_FN_1_IN)
#define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT)
+#define GPIO48_CIF_DD5_MD (48 | GPIO_ALT_FN_1_IN)
#define GPIO48_HWTXD_MD (48 | GPIO_ALT_FN_1_OUT)
#define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT)
#define GPIO49_HWRXD_MD (49 | GPIO_ALT_FN_1_IN)
#define GPIO49_nPWE_MD (49 | GPIO_ALT_FN_2_OUT)
#define GPIO50_nPIOR_MD (50 | GPIO_ALT_FN_2_OUT)
+#define GPIO50_CIF_DD3_MD (50 | GPIO_ALT_FN_1_IN)
#define GPIO50_HWCTS_MD (50 | GPIO_ALT_FN_1_IN)
#define GPIO51_HWRTS_MD (51 | GPIO_ALT_FN_1_OUT)
#define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT)
+#define GPIO51_CIF_DD2_MD (51 | GPIO_ALT_FN_1_IN)
#define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT)
+#define GPIO52_CIF_DD4_MD (52 | GPIO_ALT_FN_1_IN)
#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT)
#define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT)
+#define GPIO53_CIF_MCLK_MD (53 | GPIO_ALT_FN_2_OUT)
#define GPIO54_MMCCLK_MD (54 | GPIO_ALT_FN_1_OUT)
#define GPIO54_nPCE_2_MD (54 | GPIO_ALT_FN_2_OUT)
#define GPIO54_pSKTSEL_MD (54 | GPIO_ALT_FN_2_OUT)
+#define GPIO54_CIF_PCLK_MD (54 | GPIO_ALT_FN_3_IN)
#define GPIO55_nPREG_MD (55 | GPIO_ALT_FN_2_OUT)
+#define GPIO55_CIF_DD1_MD (55 | GPIO_ALT_FN_1_IN)
#define GPIO56_nPWAIT_MD (56 | GPIO_ALT_FN_1_IN)
#define GPIO57_nIOIS16_MD (57 | GPIO_ALT_FN_1_IN)
#define GPIO58_LDD_0_MD (58 | GPIO_ALT_FN_2_OUT)
@@ -1477,16 +1535,33 @@
#define GPIO80_nCS_4_MD (80 | GPIO_ALT_FN_2_OUT)
#define GPIO81_NSSP_CLK_OUT (81 | GPIO_ALT_FN_1_OUT)
#define GPIO81_NSSP_CLK_IN (81 | GPIO_ALT_FN_1_IN)
+#define GPIO81_CIF_DD0_MD (81 | GPIO_ALT_FN_2_IN)
#define GPIO82_NSSP_FRM_OUT (82 | GPIO_ALT_FN_1_OUT)
#define GPIO82_NSSP_FRM_IN (82 | GPIO_ALT_FN_1_IN)
+#define GPIO82_CIF_DD5_MD (82 | GPIO_ALT_FN_3_IN)
#define GPIO83_NSSP_TX (83 | GPIO_ALT_FN_1_OUT)
#define GPIO83_NSSP_RX (83 | GPIO_ALT_FN_2_IN)
+#define GPIO83_CIF_DD4_MD (83 | GPIO_ALT_FN_3_IN)
#define GPIO84_NSSP_TX (84 | GPIO_ALT_FN_1_OUT)
#define GPIO84_NSSP_RX (84 | GPIO_ALT_FN_2_IN)
+#define GPIO84_CIF_FV_MD (84 | GPIO_ALT_FN_3_OUT)
#define GPIO85_nPCE_1_MD (85 | GPIO_ALT_FN_1_OUT)
+#define GPIO85_CIF_LV_MD (85 | GPIO_ALT_FN_3_OUT)
+#define GPIO90_CIF_DD4_MD (90 | GPIO_ALT_FN_3_IN)
+#define GPIO91_CIF_DD5_MD (91 | GPIO_ALT_FN_3_IN)
#define GPIO92_MMCDAT0_MD (92 | GPIO_ALT_FN_1_OUT)
+#define GPIO93_CIF_DD6_MD (93 | GPIO_ALT_FN_2_IN)
+#define GPIO94_CIF_DD5_MD (94 | GPIO_ALT_FN_2_IN)
+#define GPIO95_CIF_DD4_MD (95 | GPIO_ALT_FN_2_IN)
+#define GPIO98_CIF_DD0_MD (98 | GPIO_ALT_FN_2_IN)
#define GPIO102_nPCE_1_MD (102 | GPIO_ALT_FN_1_OUT)
+#define GPIO103_CIF_DD3_MD (103 | GPIO_ALT_FN_1_IN)
#define GPIO104_pSKTSEL_MD (104 | GPIO_ALT_FN_1_OUT)
+#define GPIO104_CIF_DD2_MD (104 | GPIO_ALT_FN_1_IN)
+#define GPIO105_CIF_DD1_MD (105 | GPIO_ALT_FN_1_IN)
+#define GPIO106_CIF_DD9_MD (106 | GPIO_ALT_FN_1_IN)
+#define GPIO107_CIF_DD8_MD (107 | GPIO_ALT_FN_1_IN)
+#define GPIO108_CIF_DD7_MD (108 | GPIO_ALT_FN_1_IN)
#define GPIO109_MMCDAT1_MD (109 | GPIO_ALT_FN_1_OUT)
#define GPIO110_MMCDAT2_MD (110 | GPIO_ALT_FN_1_OUT)
#define GPIO110_MMCCS0_MD (110 | GPIO_ALT_FN_1_OUT)
@@ -1715,7 +1790,7 @@
#define LCCR0_Color (LCCR0_CMS*0) /* Color display */
#define LCCR0_Mono (LCCR0_CMS*1) /* Monochrome display */
#define LCCR0_SDS (1 << 2) /* Single/Dual Panel Display */
- /* Select */
+ /* Select */
#define LCCR0_Sngl (LCCR0_SDS*0) /* Single panel display */
#define LCCR0_Dual (LCCR0_SDS*1) /* Dual panel display */
@@ -1727,11 +1802,11 @@
#define LCCR0_Pas (LCCR0_PAS*0) /* Passive display (STN) */
#define LCCR0_Act (LCCR0_PAS*1) /* Active display (TFT) */
#define LCCR0_DPD (1 << 9) /* Double Pixel Data (monochrome */
- /* display mode) */
+ /* display mode) */
#define LCCR0_4PixMono (LCCR0_DPD*0) /* 4-Pixel/clock Monochrome */
- /* display */
+ /* display */
#define LCCR0_8PixMono (LCCR0_DPD*1) /* 8-Pixel/clock Monochrome */
- /* display */
+ /* display */
#define LCCR0_DIS (1 << 10) /* LCD Disable */
#define LCCR0_QDM (1 << 11) /* LCD Quick Disable mask */
#define LCCR0_PDD (0xff << 12) /* Palette DMA request delay */
@@ -1746,47 +1821,47 @@
#define LCCR1_PPL Fld (10, 0) /* Pixels Per Line - 1 */
#define LCCR1_DisWdth(Pixel) /* Display Width [1..800 pix.] */ \
- (((Pixel) - 1) << FShft (LCCR1_PPL))
+ (((Pixel) - 1) << FShft (LCCR1_PPL))
#define LCCR1_HSW Fld (6, 10) /* Horizontal Synchronization */
#define LCCR1_HorSnchWdth(Tpix) /* Horizontal Synchronization */ \
- /* pulse Width [1..64 Tpix] */ \
- (((Tpix) - 1) << FShft (LCCR1_HSW))
+ /* pulse Width [1..64 Tpix] */ \
+ (((Tpix) - 1) << FShft (LCCR1_HSW))
#define LCCR1_ELW Fld (8, 16) /* End-of-Line pixel clock Wait */
- /* count - 1 [Tpix] */
+ /* count - 1 [Tpix] */
#define LCCR1_EndLnDel(Tpix) /* End-of-Line Delay */ \
- /* [1..256 Tpix] */ \
- (((Tpix) - 1) << FShft (LCCR1_ELW))
+ /* [1..256 Tpix] */ \
+ (((Tpix) - 1) << FShft (LCCR1_ELW))
#define LCCR1_BLW Fld (8, 24) /* Beginning-of-Line pixel clock */
- /* Wait count - 1 [Tpix] */
+ /* Wait count - 1 [Tpix] */
#define LCCR1_BegLnDel(Tpix) /* Beginning-of-Line Delay */ \
- /* [1..256 Tpix] */ \
- (((Tpix) - 1) << FShft (LCCR1_BLW))
+ /* [1..256 Tpix] */ \
+ (((Tpix) - 1) << FShft (LCCR1_BLW))
#define LCCR2_LPP Fld (10, 0) /* Line Per Panel - 1 */
#define LCCR2_DisHght(Line) /* Display Height [1..1024 lines] */ \
- (((Line) - 1) << FShft (LCCR2_LPP))
+ (((Line) - 1) << FShft (LCCR2_LPP))
#define LCCR2_VSW Fld (6, 10) /* Vertical Synchronization pulse */
- /* Width - 1 [Tln] (L_FCLK) */
+ /* Width - 1 [Tln] (L_FCLK) */
#define LCCR2_VrtSnchWdth(Tln) /* Vertical Synchronization pulse */ \
- /* Width [1..64 Tln] */ \
- (((Tln) - 1) << FShft (LCCR2_VSW))
+ /* Width [1..64 Tln] */ \
+ (((Tln) - 1) << FShft (LCCR2_VSW))
#define LCCR2_EFW Fld (8, 16) /* End-of-Frame line clock Wait */
- /* count [Tln] */
+ /* count [Tln] */
#define LCCR2_EndFrmDel(Tln) /* End-of-Frame Delay */ \
- /* [0..255 Tln] */ \
- ((Tln) << FShft (LCCR2_EFW))
+ /* [0..255 Tln] */ \
+ ((Tln) << FShft (LCCR2_EFW))
#define LCCR2_BFW Fld (8, 24) /* Beginning-of-Frame line clock */
- /* Wait count [Tln] */
+ /* Wait count [Tln] */
#define LCCR2_BegFrmDel(Tln) /* Beginning-of-Frame Delay */ \
- /* [0..255 Tln] */ \
- ((Tln) << FShft (LCCR2_BFW))
+ /* [0..255 Tln] */ \
+ ((Tln) << FShft (LCCR2_BFW))
#if 0
#define LCCR3_PCD (0xff) /* Pixel clock divisor */
@@ -1803,7 +1878,7 @@
#define LCCR3_PixFlEdg (LCCR3_PCP*1) /* Pixel clock Falling-Edge */
#define LCCR3_OEP (1 << 23) /* Output Enable Polarity (L_BIAS, */
- /* active display mode) */
+ /* active display mode) */
#define LCCR3_OutEnH (LCCR3_OEP*0) /* Output Enable active High */
#define LCCR3_OutEnL (LCCR3_OEP*1) /* Output Enable active Low */
@@ -1816,25 +1891,25 @@
#define LCCR3_PCD Fld (8, 0) /* Pixel Clock Divisor */
#define LCCR3_PixClkDiv(Div) /* Pixel Clock Divisor */ \
- (((Div) << FShft (LCCR3_PCD)))
+ (((Div) << FShft (LCCR3_PCD)))
#define LCCR3_BPP Fld (3, 24) /* Bit Per Pixel */
#define LCCR3_Bpp(Bpp) /* Bit Per Pixel */ \
- (((Bpp) << FShft (LCCR3_BPP)))
+ (((Bpp) << FShft (LCCR3_BPP)))
#define LCCR3_ACB Fld (8, 8) /* AC Bias */
#define LCCR3_Acb(Acb) /* BAC Bias */ \
- (((Acb) << FShft (LCCR3_ACB)))
+ (((Acb) << FShft (LCCR3_ACB)))
#define LCCR3_HorSnchH (LCCR3_HSP*0) /* Horizontal Synchronization */
- /* pulse active High */
+ /* pulse active High */
#define LCCR3_HorSnchL (LCCR3_HSP*1) /* Horizontal Synchronization */
#define LCCR3_VrtSnchH (LCCR3_VSP*0) /* Vertical Synchronization pulse */
- /* active High */
+ /* active High */
#define LCCR3_VrtSnchL (LCCR3_VSP*1) /* Vertical Synchronization pulse */
- /* active Low */
+ /* active Low */
#define LCSR_LDD (1 << 0) /* LCD Disable Done */
#define LCSR_SOF (1 << 1) /* Start of frame */
diff --git a/include/linux/dvb/dmx.h b/include/linux/dvb/dmx.h
index c6a2353c4e68..402fb7a8d922 100644
--- a/include/linux/dvb/dmx.h
+++ b/include/linux/dvb/dmx.h
@@ -39,9 +39,10 @@ typedef enum
DMX_OUT_DECODER, /* Streaming directly to decoder. */
DMX_OUT_TAP, /* Output going to a memory buffer */
/* (to be retrieved via the read command).*/
- DMX_OUT_TS_TAP /* Output multiplexed into a new TS */
+ DMX_OUT_TS_TAP, /* Output multiplexed into a new TS */
/* (to be retrieved by reading from the */
/* logical DVR device). */
+ DMX_OUT_TSDEMUX_TAP /* Like TS_TAP but retrieved from the DMX device */
} dmx_output_t;
diff --git a/include/linux/meye.h b/include/linux/meye.h
index 39fd9c8ddd4b..12010ace1f04 100644
--- a/include/linux/meye.h
+++ b/include/linux/meye.h
@@ -58,7 +58,7 @@ struct meye_params {
/* V4L2 private controls */
#define V4L2_CID_AGC V4L2_CID_PRIVATE_BASE
-#define V4L2_CID_SHARPNESS (V4L2_CID_PRIVATE_BASE + 1)
+#define V4L2_CID_MEYE_SHARPNESS (V4L2_CID_PRIVATE_BASE + 1)
#define V4L2_CID_PICTURE (V4L2_CID_PRIVATE_BASE + 2)
#define V4L2_CID_JPEGQUAL (V4L2_CID_PRIVATE_BASE + 3)
#define V4L2_CID_FRAMERATE (V4L2_CID_PRIVATE_BASE + 4)
diff --git a/include/linux/videodev2.h b/include/linux/videodev2.h
index 17a80177a674..c1411189ba6c 100644
--- a/include/linux/videodev2.h
+++ b/include/linux/videodev2.h
@@ -282,6 +282,7 @@ struct v4l2_pix_format
#define V4L2_PIX_FMT_BGR32 v4l2_fourcc('B','G','R','4') /* 32 BGR-8-8-8-8 */
#define V4L2_PIX_FMT_RGB32 v4l2_fourcc('R','G','B','4') /* 32 RGB-8-8-8-8 */
#define V4L2_PIX_FMT_GREY v4l2_fourcc('G','R','E','Y') /* 8 Greyscale */
+#define V4L2_PIX_FMT_Y16 v4l2_fourcc('Y','1','6',' ') /* 16 Greyscale */
#define V4L2_PIX_FMT_PAL8 v4l2_fourcc('P','A','L','8') /* 8 8-bit palette */
#define V4L2_PIX_FMT_YVU410 v4l2_fourcc('Y','V','U','9') /* 9 YVU 4:1:0 */
#define V4L2_PIX_FMT_YVU420 v4l2_fourcc('Y','V','1','2') /* 12 YVU 4:2:0 */
@@ -308,6 +309,7 @@ struct v4l2_pix_format
/* see http://www.siliconimaging.com/RGB%20Bayer.htm */
#define V4L2_PIX_FMT_SBGGR8 v4l2_fourcc('B','A','8','1') /* 8 BGBG.. GRGR.. */
+#define V4L2_PIX_FMT_SBGGR16 v4l2_fourcc('B','Y','R','2') /* 16 BGBG.. GRGR.. */
/* compressed formats */
#define V4L2_PIX_FMT_MJPEG v4l2_fourcc('M','J','P','G') /* Motion-JPEG */
@@ -793,6 +795,7 @@ struct v4l2_ext_controls
/* Values for ctrl_class field */
#define V4L2_CTRL_CLASS_USER 0x00980000 /* Old-style 'user' controls */
#define V4L2_CTRL_CLASS_MPEG 0x00990000 /* MPEG-compression controls */
+#define V4L2_CTRL_CLASS_CAMERA 0x009a0000 /* Camera class controls */
#define V4L2_CTRL_ID_MASK (0x0fffffff)
#define V4L2_CTRL_ID2CLASS(id) ((id) & 0x0fff0000UL)
@@ -849,21 +852,37 @@ struct v4l2_querymenu
#define V4L2_CID_AUDIO_TREBLE (V4L2_CID_BASE+8)
#define V4L2_CID_AUDIO_MUTE (V4L2_CID_BASE+9)
#define V4L2_CID_AUDIO_LOUDNESS (V4L2_CID_BASE+10)
-#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11)
+#define V4L2_CID_BLACK_LEVEL (V4L2_CID_BASE+11) /* Deprecated */
#define V4L2_CID_AUTO_WHITE_BALANCE (V4L2_CID_BASE+12)
#define V4L2_CID_DO_WHITE_BALANCE (V4L2_CID_BASE+13)
#define V4L2_CID_RED_BALANCE (V4L2_CID_BASE+14)
#define V4L2_CID_BLUE_BALANCE (V4L2_CID_BASE+15)
#define V4L2_CID_GAMMA (V4L2_CID_BASE+16)
-#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* ? Not sure */
+#define V4L2_CID_WHITENESS (V4L2_CID_GAMMA) /* Deprecated */
#define V4L2_CID_EXPOSURE (V4L2_CID_BASE+17)
#define V4L2_CID_AUTOGAIN (V4L2_CID_BASE+18)
#define V4L2_CID_GAIN (V4L2_CID_BASE+19)
#define V4L2_CID_HFLIP (V4L2_CID_BASE+20)
#define V4L2_CID_VFLIP (V4L2_CID_BASE+21)
-#define V4L2_CID_HCENTER (V4L2_CID_BASE+22)
-#define V4L2_CID_VCENTER (V4L2_CID_BASE+23)
-#define V4L2_CID_LASTP1 (V4L2_CID_BASE+24) /* last CID + 1 */
+
+/* Deprecated, use V4L2_CID_PAN_RESET and V4L2_CID_TILT_RESET */
+#define V4L2_CID_HCENTER_DEPRECATED (V4L2_CID_BASE+22)
+#define V4L2_CID_VCENTER_DEPRECATED (V4L2_CID_BASE+23)
+
+#define V4L2_CID_POWER_LINE_FREQUENCY (V4L2_CID_BASE+24)
+enum v4l2_power_line_frequency {
+ V4L2_CID_POWER_LINE_FREQUENCY_DISABLED = 0,
+ V4L2_CID_POWER_LINE_FREQUENCY_50HZ = 1,
+ V4L2_CID_POWER_LINE_FREQUENCY_60HZ = 2,
+};
+#define V4L2_CID_HUE_AUTO (V4L2_CID_BASE+25)
+#define V4L2_CID_WHITE_BALANCE_TEMPERATURE (V4L2_CID_BASE+26)
+#define V4L2_CID_SHARPNESS (V4L2_CID_BASE+27)
+#define V4L2_CID_BACKLIGHT_COMPENSATION (V4L2_CID_BASE+28)
+#define V4L2_CID_CHROMA_AGC (V4L2_CID_BASE+29)
+#define V4L2_CID_COLOR_KILLER (V4L2_CID_BASE+30)
+/* last CID + 1 */
+#define V4L2_CID_LASTP1 (V4L2_CID_BASE+31)
/* MPEG-class control IDs defined by V4L2 */
#define V4L2_CID_MPEG_BASE (V4L2_CTRL_CLASS_MPEG | 0x900)
@@ -1051,6 +1070,32 @@ enum v4l2_mpeg_cx2341x_video_median_filter_type {
#define V4L2_CID_MPEG_CX2341X_VIDEO_CHROMA_MEDIAN_FILTER_TOP (V4L2_CID_MPEG_CX2341X_BASE+10)
#define V4L2_CID_MPEG_CX2341X_STREAM_INSERT_NAV_PACKETS (V4L2_CID_MPEG_CX2341X_BASE+11)
+/* Camera class control IDs */
+#define V4L2_CID_CAMERA_CLASS_BASE (V4L2_CTRL_CLASS_CAMERA | 0x900)
+#define V4L2_CID_CAMERA_CLASS (V4L2_CTRL_CLASS_CAMERA | 1)
+
+#define V4L2_CID_EXPOSURE_AUTO (V4L2_CID_CAMERA_CLASS_BASE+1)
+enum v4l2_exposure_auto_type {
+ V4L2_EXPOSURE_AUTO = 0,
+ V4L2_EXPOSURE_MANUAL = 1,
+ V4L2_EXPOSURE_SHUTTER_PRIORITY = 2,
+ V4L2_EXPOSURE_APERTURE_PRIORITY = 3
+};
+#define V4L2_CID_EXPOSURE_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+2)
+#define V4L2_CID_EXPOSURE_AUTO_PRIORITY (V4L2_CID_CAMERA_CLASS_BASE+3)
+
+#define V4L2_CID_PAN_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+4)
+#define V4L2_CID_TILT_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+5)
+#define V4L2_CID_PAN_RESET (V4L2_CID_CAMERA_CLASS_BASE+6)
+#define V4L2_CID_TILT_RESET (V4L2_CID_CAMERA_CLASS_BASE+7)
+
+#define V4L2_CID_PAN_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+8)
+#define V4L2_CID_TILT_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+9)
+
+#define V4L2_CID_FOCUS_ABSOLUTE (V4L2_CID_CAMERA_CLASS_BASE+10)
+#define V4L2_CID_FOCUS_RELATIVE (V4L2_CID_CAMERA_CLASS_BASE+11)
+#define V4L2_CID_FOCUS_AUTO (V4L2_CID_CAMERA_CLASS_BASE+12)
+
/*
* T U N I N G
*/
diff --git a/include/media/ir-common.h b/include/media/ir-common.h
index a4274203f252..75a3482866fe 100644
--- a/include/media/ir-common.h
+++ b/include/media/ir-common.h
@@ -107,6 +107,7 @@ extern IR_KEYTAB_TYPE ir_codes_avermedia[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_avermedia_dvbt[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_apac_viewcomp[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_pixelview[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_pixelview_new[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_nebula[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_dntv_live_dvb_t[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_iodata_bctv7e[IR_KEYTAB_SIZE];
@@ -143,6 +144,7 @@ extern IR_KEYTAB_TYPE ir_codes_fusionhdtv_mce[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_behold[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_pinnacle_pctv_hd[IR_KEYTAB_SIZE];
extern IR_KEYTAB_TYPE ir_codes_genius_tvgo_a11mce[IR_KEYTAB_SIZE];
+extern IR_KEYTAB_TYPE ir_codes_powercolor_real_angel[IR_KEYTAB_SIZE];
#endif
diff --git a/include/media/soc_camera.h b/include/media/soc_camera.h
new file mode 100644
index 000000000000..6a8c8be7a1ae
--- /dev/null
+++ b/include/media/soc_camera.h
@@ -0,0 +1,179 @@
+/*
+ * camera image capture (abstract) bus driver header
+ *
+ * Copyright (C) 2006, Sascha Hauer, Pengutronix
+ * Copyright (C) 2008, Guennadi Liakhovetski <kernel@pengutronix.de>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef SOC_CAMERA_H
+#define SOC_CAMERA_H
+
+#include <linux/videodev2.h>
+#include <media/videobuf-dma-sg.h>
+
+struct soc_camera_device {
+ struct list_head list;
+ struct device dev;
+ struct device *control;
+ unsigned short width; /* Current window */
+ unsigned short height; /* sizes */
+ unsigned short x_min; /* Camera capabilities */
+ unsigned short y_min;
+ unsigned short x_current; /* Current window location */
+ unsigned short y_current;
+ unsigned short width_min;
+ unsigned short width_max;
+ unsigned short height_min;
+ unsigned short height_max;
+ unsigned short y_skip_top; /* Lines to skip at the top */
+ unsigned short gain;
+ unsigned short exposure;
+ unsigned char iface; /* Host number */
+ unsigned char devnum; /* Device number per host */
+ unsigned char buswidth; /* See comment in .c */
+ struct soc_camera_ops *ops;
+ struct video_device *vdev;
+ const struct soc_camera_data_format *current_fmt;
+ const struct soc_camera_data_format *formats;
+ int num_formats;
+ struct module *owner;
+ /* soc_camera.c private count. Only accessed with video_lock held */
+ int use_count;
+};
+
+struct soc_camera_file {
+ struct soc_camera_device *icd;
+ struct videobuf_queue vb_vidq;
+ spinlock_t *lock;
+};
+
+struct soc_camera_host {
+ struct list_head list;
+ struct device dev;
+ unsigned char nr; /* Host number */
+ size_t msize;
+ struct videobuf_queue_ops *vbq_ops;
+ void *priv;
+ char *drv_name;
+ struct soc_camera_host_ops *ops;
+};
+
+struct soc_camera_host_ops {
+ struct module *owner;
+ int (*add)(struct soc_camera_device *);
+ void (*remove)(struct soc_camera_device *);
+ int (*set_fmt_cap)(struct soc_camera_device *, __u32,
+ struct v4l2_rect *);
+ int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+ int (*reqbufs)(struct soc_camera_file *, struct v4l2_requestbuffers *);
+ int (*querycap)(struct soc_camera_host *, struct v4l2_capability *);
+ int (*try_bus_param)(struct soc_camera_device *, __u32);
+ int (*set_bus_param)(struct soc_camera_device *, __u32);
+ unsigned int (*poll)(struct file *, poll_table *);
+ spinlock_t* (*spinlock_alloc)(struct soc_camera_file *);
+ void (*spinlock_free)(spinlock_t *);
+};
+
+struct soc_camera_link {
+ /* Camera bus id, used to match a camera and a bus */
+ int bus_id;
+ /* GPIO number to switch between 8 and 10 bit modes */
+ unsigned int gpio;
+};
+
+static inline struct soc_camera_device *to_soc_camera_dev(struct device *dev)
+{
+ return container_of(dev, struct soc_camera_device, dev);
+}
+
+static inline struct soc_camera_host *to_soc_camera_host(struct device *dev)
+{
+ return container_of(dev, struct soc_camera_host, dev);
+}
+
+extern int soc_camera_host_register(struct soc_camera_host *ici);
+extern void soc_camera_host_unregister(struct soc_camera_host *ici);
+extern int soc_camera_device_register(struct soc_camera_device *icd);
+extern void soc_camera_device_unregister(struct soc_camera_device *icd);
+
+extern int soc_camera_video_start(struct soc_camera_device *icd);
+extern void soc_camera_video_stop(struct soc_camera_device *icd);
+
+struct soc_camera_data_format {
+ char *name;
+ unsigned int depth;
+ __u32 fourcc;
+ enum v4l2_colorspace colorspace;
+};
+
+struct soc_camera_ops {
+ struct module *owner;
+ int (*probe)(struct soc_camera_device *);
+ void (*remove)(struct soc_camera_device *);
+ int (*init)(struct soc_camera_device *);
+ int (*release)(struct soc_camera_device *);
+ int (*start_capture)(struct soc_camera_device *);
+ int (*stop_capture)(struct soc_camera_device *);
+ int (*set_fmt_cap)(struct soc_camera_device *, __u32,
+ struct v4l2_rect *);
+ int (*try_fmt_cap)(struct soc_camera_device *, struct v4l2_format *);
+ unsigned long (*query_bus_param)(struct soc_camera_device *);
+ int (*set_bus_param)(struct soc_camera_device *, unsigned long);
+ int (*get_chip_id)(struct soc_camera_device *,
+ struct v4l2_chip_ident *);
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ int (*get_register)(struct soc_camera_device *, struct v4l2_register *);
+ int (*set_register)(struct soc_camera_device *, struct v4l2_register *);
+#endif
+ int (*get_control)(struct soc_camera_device *, struct v4l2_control *);
+ int (*set_control)(struct soc_camera_device *, struct v4l2_control *);
+ const struct v4l2_queryctrl *controls;
+ int num_controls;
+};
+
+static inline struct v4l2_queryctrl const *soc_camera_find_qctrl(
+ struct soc_camera_ops *ops, int id)
+{
+ int i;
+
+ for (i = 0; i < ops->num_controls; i++)
+ if (ops->controls[i].id == id)
+ return &ops->controls[i];
+
+ return NULL;
+}
+
+#define SOCAM_MASTER (1 << 0)
+#define SOCAM_SLAVE (1 << 1)
+#define SOCAM_HSYNC_ACTIVE_HIGH (1 << 2)
+#define SOCAM_HSYNC_ACTIVE_LOW (1 << 3)
+#define SOCAM_VSYNC_ACTIVE_HIGH (1 << 4)
+#define SOCAM_VSYNC_ACTIVE_LOW (1 << 5)
+#define SOCAM_DATAWIDTH_8 (1 << 6)
+#define SOCAM_DATAWIDTH_9 (1 << 7)
+#define SOCAM_DATAWIDTH_10 (1 << 8)
+#define SOCAM_PCLK_SAMPLE_RISING (1 << 9)
+#define SOCAM_PCLK_SAMPLE_FALLING (1 << 10)
+
+#define SOCAM_DATAWIDTH_MASK (SOCAM_DATAWIDTH_8 | SOCAM_DATAWIDTH_9 | \
+ SOCAM_DATAWIDTH_10)
+
+static inline unsigned long soc_camera_bus_param_compatible(
+ unsigned long camera_flags, unsigned long bus_flags)
+{
+ unsigned long common_flags, hsync, vsync, pclk;
+
+ common_flags = camera_flags & bus_flags;
+
+ hsync = common_flags & (SOCAM_HSYNC_ACTIVE_HIGH | SOCAM_HSYNC_ACTIVE_LOW);
+ vsync = common_flags & (SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_VSYNC_ACTIVE_LOW);
+ pclk = common_flags & (SOCAM_PCLK_SAMPLE_RISING | SOCAM_PCLK_SAMPLE_FALLING);
+
+ return (!hsync || !vsync || !pclk) ? 0 : common_flags;
+}
+
+#endif
diff --git a/include/media/tuner-types.h b/include/media/tuner-types.h
index b201371416a0..ab03c5344209 100644
--- a/include/media/tuner-types.h
+++ b/include/media/tuner-types.h
@@ -6,10 +6,11 @@
#define __TUNER_TYPES_H__
enum param_type {
- TUNER_PARAM_TYPE_RADIO, \
- TUNER_PARAM_TYPE_PAL, \
- TUNER_PARAM_TYPE_SECAM, \
- TUNER_PARAM_TYPE_NTSC
+ TUNER_PARAM_TYPE_RADIO,
+ TUNER_PARAM_TYPE_PAL,
+ TUNER_PARAM_TYPE_SECAM,
+ TUNER_PARAM_TYPE_NTSC,
+ TUNER_PARAM_TYPE_DIGITAL,
};
struct tuner_range {
@@ -105,6 +106,7 @@ struct tuner_params {
the SECAM-L/L' standards. Range: -16:+15 */
signed int default_top_secam_high:5;
+ u16 iffreq;
unsigned int count;
struct tuner_range *ranges;
@@ -114,6 +116,13 @@ struct tunertype {
char *name;
unsigned int count;
struct tuner_params *params;
+
+ u16 min;
+ u16 max;
+ u32 stepsize;
+
+ u8 *initdata;
+ u8 *sleepdata;
};
extern struct tunertype tuners[];
diff --git a/include/media/tuner.h b/include/media/tuner.h
index 1bf24a6ed8f1..77068fcc86bd 100644
--- a/include/media/tuner.h
+++ b/include/media/tuner.h
@@ -78,7 +78,7 @@
#define TUNER_HITACHI_NTSC 40
#define TUNER_PHILIPS_PAL_MK 41
-#define TUNER_PHILIPS_ATSC 42
+#define TUNER_PHILIPS_FCV1236D 42
#define TUNER_PHILIPS_FM1236_MK3 43
#define TUNER_PHILIPS_4IN1 44 /* ATI TV Wonder Pro - Conexant */
diff --git a/include/media/v4l2-chip-ident.h b/include/media/v4l2-chip-ident.h
index 032bb75f69c2..0ea0bd85c036 100644
--- a/include/media/v4l2-chip-ident.h
+++ b/include/media/v4l2-chip-ident.h
@@ -153,6 +153,12 @@ enum {
V4L2_IDENT_MSP4428G = 44287,
V4L2_IDENT_MSP4448G = 44487,
V4L2_IDENT_MSP4458G = 44587,
+
+ /* Micron CMOS sensor chips: 45000-45099 */
+ V4L2_IDENT_MT9M001C12ST = 45000,
+ V4L2_IDENT_MT9M001C12STM = 45005,
+ V4L2_IDENT_MT9V022IX7ATC = 45010, /* No way to detect "normal" I77ATx */
+ V4L2_IDENT_MT9V022IX7ATM = 45015, /* and "lead free" IA7ATx chips */
};
#endif
diff --git a/include/media/videobuf-core.h b/include/media/videobuf-core.h
index 99033945cdee..53caa3102146 100644
--- a/include/media/videobuf-core.h
+++ b/include/media/videobuf-core.h
@@ -144,6 +144,8 @@ struct videobuf_qtype_ops {
int vbihack,
int nonblocking);
int (*mmap_free) (struct videobuf_queue *q);
+ int (*mmap_setup) (struct videobuf_queue *q,
+ struct videobuf_buffer *vb);
int (*mmap_mapper) (struct videobuf_queue *q,
struct vm_area_struct *vma);
};
@@ -151,7 +153,9 @@ struct videobuf_qtype_ops {
struct videobuf_queue {
struct mutex vb_lock;
spinlock_t *irqlock;
- void *dev; /* on pci, points to struct pci_dev */
+ struct device *dev;
+
+ wait_queue_head_t wait; /* wait if queue is empty */
enum v4l2_buf_type type;
unsigned int inputs; /* for V4L2_BUF_FLAG_INPUT */
@@ -164,7 +168,6 @@ struct videobuf_queue {
unsigned int streaming:1;
unsigned int reading:1;
- unsigned int is_mmapped:1;
/* capture via mmap() + ioctl(QBUF/DQBUF) */
struct list_head stream;
@@ -185,7 +188,7 @@ void *videobuf_alloc(struct videobuf_queue* q);
void videobuf_queue_core_init(struct videobuf_queue *q,
struct videobuf_queue_ops *ops,
- void *dev,
+ struct device *dev,
spinlock_t *irqlock,
enum v4l2_buf_type type,
enum v4l2_field field,
diff --git a/include/media/videobuf-dma-sg.h b/include/media/videobuf-dma-sg.h
index 38105031db23..b6ab08045de6 100644
--- a/include/media/videobuf-dma-sg.h
+++ b/include/media/videobuf-dma-sg.h
@@ -1,5 +1,5 @@
/*
- * helper functions for PCI DMA video4linux capture buffers
+ * helper functions for SG DMA video4linux capture buffers
*
* The functions expect the hardware being able to scatter gatter
* (i.e. the buffers are not linear in physical memory, but fragmented
@@ -81,7 +81,7 @@ struct videobuf_dmabuf {
int direction;
};
-struct videbuf_pci_sg_memory
+struct videobuf_dma_sg_memory
{
u32 magic;
@@ -103,11 +103,11 @@ int videobuf_dma_sync(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
int videobuf_dma_unmap(struct videobuf_queue* q,struct videobuf_dmabuf *dma);
struct videobuf_dmabuf *videobuf_to_dma (struct videobuf_buffer *buf);
-void *videobuf_pci_alloc (size_t size);
+void *videobuf_sg_alloc(size_t size);
-void videobuf_queue_pci_init(struct videobuf_queue* q,
+void videobuf_queue_sg_init(struct videobuf_queue* q,
struct videobuf_queue_ops *ops,
- void *dev,
+ struct device *dev,
spinlock_t *irqlock,
enum v4l2_buf_type type,
enum v4l2_field field,
@@ -117,6 +117,6 @@ void videobuf_queue_pci_init(struct videobuf_queue* q,
/*FIXME: these variants are used only on *-alsa code, where videobuf is
* used without queue
*/
-int videobuf_pci_dma_map(struct pci_dev *pci,struct videobuf_dmabuf *dma);
-int videobuf_pci_dma_unmap(struct pci_dev *pci,struct videobuf_dmabuf *dma);
+int videobuf_sg_dma_map(struct device *dev, struct videobuf_dmabuf *dma);
+int videobuf_sg_dma_unmap(struct device *dev, struct videobuf_dmabuf *dma);