summaryrefslogtreecommitdiffstats
path: root/drivers/media/video
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/media/video')
-rw-r--r--drivers/media/video/Kconfig56
-rw-r--r--drivers/media/video/Makefile12
-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/au0828/Kconfig12
-rw-r--r--drivers/media/video/au0828/Makefile9
-rw-r--r--drivers/media/video/au0828/au0828-cards.c182
-rw-r--r--drivers/media/video/au0828/au0828-cards.h25
-rw-r--r--drivers/media/video/au0828/au0828-core.c270
-rw-r--r--drivers/media/video/au0828/au0828-dvb.c373
-rw-r--r--drivers/media/video/au0828/au0828-i2c.c385
-rw-r--r--drivers/media/video/au0828/au0828-reg.h38
-rw-r--r--drivers/media/video/au0828/au0828.h128
-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.c36
-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.c13
-rw-r--r--drivers/media/video/cafe_ccic.c4
-rw-r--r--drivers/media/video/cpia.c2
-rw-r--r--drivers/media/video/cpia.h4
-rw-r--r--drivers/media/video/cpia2/cpia2_core.c16
-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/cpia_usb.c2
-rw-r--r--drivers/media/video/cx23885/Kconfig2
-rw-r--r--drivers/media/video/cx23885/Makefile2
-rw-r--r--drivers/media/video/cx23885/cx23885-417.c1764
-rw-r--r--drivers/media/video/cx23885/cx23885-cards.c116
-rw-r--r--drivers/media/video/cx23885/cx23885-core.c310
-rw-r--r--drivers/media/video/cx23885/cx23885-dvb.c172
-rw-r--r--drivers/media/video/cx23885/cx23885-i2c.c46
-rw-r--r--drivers/media/video/cx23885/cx23885-video.c58
-rw-r--r--drivers/media/video/cx23885/cx23885.h27
-rw-r--r--drivers/media/video/cx25840/cx25840-core.c97
-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.c14
-rw-r--r--drivers/media/video/cx88/cx88-blackbird.c18
-rw-r--r--drivers/media/video/cx88/cx88-cards.c585
-rw-r--r--drivers/media/video/cx88/cx88-core.c17
-rw-r--r--drivers/media/video/cx88/cx88-dvb.c260
-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.c20
-rw-r--r--drivers/media/video/cx88/cx88-tvaudio.c30
-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/Kconfig14
-rw-r--r--drivers/media/video/em28xx/Makefile1
-rw-r--r--drivers/media/video/em28xx/em28xx-audio.c2
-rw-r--r--drivers/media/video/em28xx/em28xx-cards.c207
-rw-r--r--drivers/media/video/em28xx/em28xx-core.c776
-rw-r--r--drivers/media/video/em28xx/em28xx-dvb.c474
-rw-r--r--drivers/media/video/em28xx/em28xx-i2c.c160
-rw-r--r--drivers/media/video/em28xx/em28xx-input.c26
-rw-r--r--drivers/media/video/em28xx/em28xx-reg.h88
-rw-r--r--drivers/media/video/em28xx/em28xx-video.c1078
-rw-r--r--drivers/media/video/em28xx/em28xx.h318
-rw-r--r--drivers/media/video/et61x251/et61x251.h6
-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.c28
-rw-r--r--drivers/media/video/ivtv/Kconfig1
-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.c46
-rw-r--r--drivers/media/video/ivtv/ivtv-driver.h2
-rw-r--r--drivers/media/video/ivtv/ivtv-fileops.c6
-rw-r--r--drivers/media/video/ivtv/ivtv-i2c.c12
-rw-r--r--drivers/media/video/ivtv/ivtv-ioctl.c42
-rw-r--r--drivers/media/video/ivtv/ivtv-irq.c25
-rw-r--r--drivers/media/video/ivtv/ivtv-mailbox.c11
-rw-r--r--drivers/media/video/ivtv/ivtv-queue.c4
-rw-r--r--drivers/media/video/ivtv/ivtv-streams.c3
-rw-r--r--drivers/media/video/ivtv/ivtv-yuv.c38
-rw-r--r--drivers/media/video/meye.c1361
-rw-r--r--drivers/media/video/msp3400-driver.c4
-rw-r--r--drivers/media/video/msp3400-kthreads.c15
-rw-r--r--drivers/media/video/mt20xx.c7
-rw-r--r--drivers/media/video/mt20xx.h2
-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.c4
-rw-r--r--drivers/media/video/ov511.h2
-rw-r--r--drivers/media/video/ovcamchip/ovcamchip_priv.h4
-rw-r--r--drivers/media/video/pms.c6
-rw-r--r--drivers/media/video/pvrusb2/Kconfig24
-rw-r--r--drivers/media/video/pvrusb2/Makefile6
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.c306
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-context.h16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-ctrl.c19
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c4
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debug.h2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-debugifc.c24
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.c270
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-devattr.h72
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-dvb.c425
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-dvb.h41
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-encoder.c19
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h43
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw-internal.h26
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.c903
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-hdw.h39
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-i2c-core.c2
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.c30
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-io.h12
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-main.c16
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-std.c9
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-sysfs.c53
-rw-r--r--drivers/media/video/pvrusb2/pvrusb2-v4l2.c195
-rw-r--r--drivers/media/video/pwc/pwc-if.c16
-rw-r--r--drivers/media/video/pwc/pwc-v4l.c4
-rw-r--r--drivers/media/video/pxa_camera.c1206
-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.c16
-rw-r--r--drivers/media/video/saa7134/saa7134-cards.c507
-rw-r--r--drivers/media/video/saa7134/saa7134-core.c52
-rw-r--r--drivers/media/video/saa7134/saa7134-dvb.c434
-rw-r--r--drivers/media/video/saa7134/saa7134-empress.c10
-rw-r--r--drivers/media/video/saa7134/saa7134-i2c.c6
-rw-r--r--drivers/media/video/saa7134/saa7134-input.c19
-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/saa717x.c1516
-rw-r--r--drivers/media/video/saa7185.c2
-rw-r--r--drivers/media/video/se401.c12
-rw-r--r--drivers/media/video/sn9c102/sn9c102.h6
-rw-r--r--drivers/media/video/sn9c102/sn9c102_core.c12
-rw-r--r--drivers/media/video/sn9c102/sn9c102_sensor.h3
-rw-r--r--drivers/media/video/soc_camera.c1031
-rw-r--r--drivers/media/video/stk-webcam.c6
-rw-r--r--drivers/media/video/stradis.c6
-rw-r--r--drivers/media/video/stv680.c13
-rw-r--r--drivers/media/video/tcm825x.c2
-rw-r--r--drivers/media/video/tda8290.c18
-rw-r--r--drivers/media/video/tda8290.h6
-rw-r--r--drivers/media/video/tda9840.c4
-rw-r--r--drivers/media/video/tda9887.c42
-rw-r--r--drivers/media/video/tda9887.h2
-rw-r--r--drivers/media/video/tea5761.c22
-rw-r--r--drivers/media/video/tea5761.h4
-rw-r--r--drivers/media/video/tea5767.c39
-rw-r--r--drivers/media/video/tea5767.h4
-rw-r--r--drivers/media/video/tea6415c.c4
-rw-r--r--drivers/media/video/tea6420.c4
-rw-r--r--drivers/media/video/tuner-core.c55
-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.h13
-rw-r--r--drivers/media/video/tuner-types.c188
-rw-r--r--drivers/media/video/tuner-xc2028-types.h23
-rw-r--r--drivers/media/video/tuner-xc2028.c165
-rw-r--r--drivers/media/video/tuner-xc2028.h6
-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.c64
-rw-r--r--drivers/media/video/usbvideo/konicawc.c4
-rw-r--r--drivers/media/video/usbvideo/quickcam_messenger.c4
-rw-r--r--drivers/media/video/usbvideo/ultracam.c4
-rw-r--r--drivers/media/video/usbvideo/usbvideo.c148
-rw-r--r--drivers/media/video/usbvideo/vicam.c4
-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.c1735
-rw-r--r--drivers/media/video/videobuf-core.c209
-rw-r--r--drivers/media/video/videobuf-dma-sg.c156
-rw-r--r--drivers/media/video/videobuf-dvb.c18
-rw-r--r--drivers/media/video/videobuf-vmalloc.c211
-rw-r--r--drivers/media/video/videocodec.c115
-rw-r--r--drivers/media/video/videodev.c74
-rw-r--r--drivers/media/video/vino.c10
-rw-r--r--drivers/media/video/vivi.c350
-rw-r--r--drivers/media/video/vpx3220.c2
-rw-r--r--drivers/media/video/w9966.c8
-rw-r--r--drivers/media/video/w9968cf.c4
-rw-r--r--drivers/media/video/w9968cf.h6
-rw-r--r--drivers/media/video/zc0301/zc0301.h6
-rw-r--r--drivers/media/video/zc0301/zc0301_core.c4
-rw-r--r--drivers/media/video/zoran.h16
-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.c26
-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
215 files changed, 18949 insertions, 5281 deletions
diff --git a/drivers/media/video/Kconfig b/drivers/media/video/Kconfig
index 1832966f53f..fe9a4cc1414 100644
--- a/drivers/media/video/Kconfig
+++ b/drivers/media/video/Kconfig
@@ -270,6 +270,15 @@ config VIDEO_SAA711X
To compile this driver as a module, choose M here: the
module will be called saa7115.
+config VIDEO_SAA717X
+ tristate "Philips SAA7171/3/4 audio/video decoders"
+ depends on VIDEO_V4L2 && I2C
+ ---help---
+ Support for the Philips SAA7171/3/4 audio/video decoders.
+
+ To compile this driver as a module, choose M here: the
+ module will be called saa717x.
+
config VIDEO_SAA7191
tristate "Philips SAA7191 video decoder"
depends on VIDEO_V4L1 && I2C
@@ -689,6 +698,8 @@ source "drivers/media/video/cx88/Kconfig"
source "drivers/media/video/cx23885/Kconfig"
+source "drivers/media/video/au0828/Kconfig"
+
source "drivers/media/video/ivtv/Kconfig"
config VIDEO_M32R_AR
@@ -836,4 +847,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 3f209b32eea..be14227f372 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
@@ -38,6 +38,7 @@ obj-$(CONFIG_VIDEO_SAA7110) += saa7110.o
obj-$(CONFIG_VIDEO_SAA7111) += saa7111.o
obj-$(CONFIG_VIDEO_SAA7114) += saa7114.o
obj-$(CONFIG_VIDEO_SAA711X) += saa7115.o
+obj-$(CONFIG_VIDEO_SAA717X) += saa717x.o
obj-$(CONFIG_VIDEO_SAA7127) += saa7127.o
obj-$(CONFIG_VIDEO_SAA7185) += saa7185.o
obj-$(CONFIG_VIDEO_SAA7191) += saa7191.o
@@ -87,6 +88,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 +138,12 @@ 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
+
+obj-$(CONFIG_VIDEO_AU0828) += au0828/
+
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 fea2e723e34..f794f2dbfb3 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 10d4d89623f..8ee07a68f70 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 c94a4d0f280..8c7d1958856 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/au0828/Kconfig b/drivers/media/video/au0828/Kconfig
new file mode 100644
index 00000000000..c97c4bd2484
--- /dev/null
+++ b/drivers/media/video/au0828/Kconfig
@@ -0,0 +1,12 @@
+
+config VIDEO_AU0828
+ tristate "Auvitek AU0828 support"
+ depends on VIDEO_DEV && I2C && INPUT
+ select I2C_ALGOBIT
+ select DVB_AU8522 if !DVB_FE_CUSTOMIZE
+ select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ ---help---
+ This is a video4linux driver for Auvitek's USB device.
+
+ To compile this driver as a module, choose M here: the
+ module will be called au0828
diff --git a/drivers/media/video/au0828/Makefile b/drivers/media/video/au0828/Makefile
new file mode 100644
index 00000000000..9f4f572c89c
--- /dev/null
+++ b/drivers/media/video/au0828/Makefile
@@ -0,0 +1,9 @@
+au0828-objs := au0828-core.o au0828-i2c.o au0828-cards.o au0828-dvb.o
+
+obj-$(CONFIG_VIDEO_AU0828) += au0828.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
+
+EXTRA_CFLAGS += $(extra-cflags-y) $(extra-cflags-m)
diff --git a/drivers/media/video/au0828/au0828-cards.c b/drivers/media/video/au0828/au0828-cards.c
new file mode 100644
index 00000000000..8ca91f81427
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-cards.c
@@ -0,0 +1,182 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include "au0828.h"
+#include "au0828-cards.h"
+
+struct au0828_board au0828_boards[] = {
+ [AU0828_BOARD_UNKNOWN] = {
+ .name = "Unknown board",
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR850] = {
+ .name = "Hauppauge HVR850",
+ },
+ [AU0828_BOARD_HAUPPAUGE_HVR950Q] = {
+ .name = "Hauppauge HVR950Q",
+ },
+ [AU0828_BOARD_DVICO_FUSIONHDTV7] = {
+ .name = "DViCO FusionHDTV USB",
+ },
+};
+const unsigned int au0828_bcount = ARRAY_SIZE(au0828_boards);
+
+/* Tuner callback function for au0828 boards. Currently only needed
+ * for HVR1500Q, which has an xc5000 tuner.
+ */
+int au0828_tuner_callback(void *priv, int command, int arg)
+{
+ struct au0828_dev *dev = priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ switch (dev->board) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ if (command == 0) {
+ /* Tuner Reset Command from xc5000 */
+ /* Drive the tuner into reset and out */
+ au0828_clear(dev, REG_001, 2);
+ mdelay(200);
+ au0828_set(dev, REG_001, 2);
+ mdelay(50);
+ return 0;
+ } else {
+ printk(KERN_ERR
+ "%s(): Unknown command.\n", __func__);
+ return -EINVAL;
+ }
+ break;
+ }
+
+ return 0; /* Should never be here */
+}
+
+static void hauppauge_eeprom(struct au0828_dev *dev, u8 *eeprom_data)
+{
+ struct tveeprom tv;
+
+ tveeprom_hauppauge_analog(&dev->i2c_client, &tv, eeprom_data);
+
+ /* Make sure we support the board model */
+ switch (tv.model) {
+ case 72001: /* WinTV-HVR950q (Retail, IR, ATSC/QAM and basic analog video */
+ case 72301: /* WinTV-HVR850 (Retail, IR, ATSC and basic analog video */
+ break;
+ default:
+ printk(KERN_WARNING "%s: warning: "
+ "unknown hauppauge model #%d\n", __func__, tv.model);
+ break;
+ }
+
+ printk(KERN_INFO "%s: hauppauge eeprom: model=%d\n",
+ __func__, tv.model);
+}
+
+void au0828_card_setup(struct au0828_dev *dev)
+{
+ static u8 eeprom[256];
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (dev->i2c_rc == 0) {
+ dev->i2c_client.addr = 0xa0 >> 1;
+ tveeprom_read(&dev->i2c_client, eeprom, sizeof(eeprom));
+ }
+
+ switch (dev->board) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ if (dev->i2c_rc == 0)
+ hauppauge_eeprom(dev, eeprom+0xa0);
+ break;
+ }
+}
+
+/*
+ * The bridge has between 8 and 12 gpios.
+ * Regs 1 and 0 deal with output enables.
+ * Regs 3 and 2 deal with direction.
+ */
+void au0828_gpio_setup(struct au0828_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ switch (dev->board) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ /* GPIO's
+ * 4 - CS5340
+ * 5 - AU8522 Demodulator
+ * 6 - eeprom W/P
+ * 9 - XC5000 Tuner
+ */
+
+ /* Into reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0x88 | 0x20);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_000, 0x0);
+ msleep(100);
+
+ /* Out of reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_001, 0x02);
+ au0828_write(dev, REG_002, 0x88 | 0x20);
+ au0828_write(dev, REG_000, 0x88 | 0x20 | 0x40);
+ msleep(250);
+ break;
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ /* GPIO's
+ * 6 - ?
+ * 8 - AU8522 Demodulator
+ * 9 - XC5000 Tuner
+ */
+
+ /* Into reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0xa0);
+ au0828_write(dev, REG_001, 0x0);
+ au0828_write(dev, REG_000, 0x0);
+ msleep(100);
+
+ /* Out of reset */
+ au0828_write(dev, REG_003, 0x02);
+ au0828_write(dev, REG_002, 0xa0);
+ au0828_write(dev, REG_001, 0x02);
+ au0828_write(dev, REG_000, 0xa0);
+ msleep(250);
+ break;
+ }
+}
+
+/* table of devices that work with this driver */
+struct usb_device_id au0828_usb_id_table [] = {
+ { USB_DEVICE(0x2040, 0x7200),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR950Q },
+ { USB_DEVICE(0x2040, 0x7240),
+ .driver_info = AU0828_BOARD_HAUPPAUGE_HVR850 },
+ { USB_DEVICE(0x0fe9, 0xd620),
+ .driver_info = AU0828_BOARD_DVICO_FUSIONHDTV7 },
+ { },
+};
+
+MODULE_DEVICE_TABLE(usb, au0828_usb_id_table);
diff --git a/drivers/media/video/au0828/au0828-cards.h b/drivers/media/video/au0828/au0828-cards.h
new file mode 100644
index 00000000000..e26f54a961d
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-cards.h
@@ -0,0 +1,25 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#define AU0828_BOARD_UNKNOWN 0
+#define AU0828_BOARD_HAUPPAUGE_HVR950Q 1
+#define AU0828_BOARD_HAUPPAUGE_HVR850 2
+#define AU0828_BOARD_DVICO_FUSIONHDTV7 3
diff --git a/drivers/media/video/au0828/au0828-core.c b/drivers/media/video/au0828/au0828-core.c
new file mode 100644
index 00000000000..e65d5642cb1
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-core.c
@@ -0,0 +1,270 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/videodev2.h>
+#include <media/v4l2-common.h>
+#include <linux/mutex.h>
+
+#include "au0828.h"
+
+/*
+ * 1 = General debug messages
+ * 2 = USB handling
+ * 4 = I2C related
+ * 8 = Bridge related
+ */
+unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages");
+
+unsigned int usb_debug;
+module_param(usb_debug, int, 0644);
+MODULE_PARM_DESC(usb_debug, "enable usb debug messages");
+
+unsigned int bridge_debug;
+module_param(bridge_debug, int, 0644);
+MODULE_PARM_DESC(bridge_debug, "enable bridge debug messages");
+
+#define _AU0828_BULKPIPE 0x03
+#define _BULKPIPESIZE 0xffff
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size);
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size);
+
+/* USB Direction */
+#define CMD_REQUEST_IN 0x00
+#define CMD_REQUEST_OUT 0x01
+
+u32 au0828_readreg(struct au0828_dev *dev, u16 reg)
+{
+ recv_control_msg(dev, CMD_REQUEST_IN, 0, reg, dev->ctrlmsg, 1);
+ dprintk(8, "%s(0x%x) = 0x%x\n", __func__, reg, dev->ctrlmsg[0]);
+ return dev->ctrlmsg[0];
+}
+
+u32 au0828_writereg(struct au0828_dev *dev, u16 reg, u32 val)
+{
+ dprintk(8, "%s(0x%x, 0x%x)\n", __func__, reg, val);
+ return send_control_msg(dev, CMD_REQUEST_OUT, val, reg,
+ dev->ctrlmsg, 0);
+}
+
+static void cmd_msg_dump(struct au0828_dev *dev)
+{
+ int i;
+
+ for (i = 0; i < sizeof(dev->ctrlmsg); i += 16)
+ dprintk(2, "%s() %02x %02x %02x %02x %02x %02x %02x %02x "
+ "%02x %02x %02x %02x %02x %02x %02x %02x\n",
+ __func__,
+ dev->ctrlmsg[i+0], dev->ctrlmsg[i+1],
+ dev->ctrlmsg[i+2], dev->ctrlmsg[i+3],
+ dev->ctrlmsg[i+4], dev->ctrlmsg[i+5],
+ dev->ctrlmsg[i+6], dev->ctrlmsg[i+7],
+ dev->ctrlmsg[i+8], dev->ctrlmsg[i+9],
+ dev->ctrlmsg[i+10], dev->ctrlmsg[i+11],
+ dev->ctrlmsg[i+12], dev->ctrlmsg[i+13],
+ dev->ctrlmsg[i+14], dev->ctrlmsg[i+15]);
+}
+
+static int send_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size)
+{
+ int status = -ENODEV;
+ mutex_lock(&dev->mutex);
+ if (dev->usbdev) {
+
+ /* cp must be memory that has been allocated by kmalloc */
+ status = usb_control_msg(dev->usbdev,
+ usb_sndctrlpipe(dev->usbdev, 0),
+ request,
+ USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ cp, size, 1000);
+
+ status = min(status, 0);
+
+ if (status < 0) {
+ printk(KERN_ERR "%s() Failed sending control message, error %d.\n",
+ __func__, status);
+ }
+
+ }
+ mutex_unlock(&dev->mutex);
+ return status;
+}
+
+static int recv_control_msg(struct au0828_dev *dev, u16 request, u32 value,
+ u16 index, unsigned char *cp, u16 size)
+{
+ int status = -ENODEV;
+ mutex_lock(&dev->mutex);
+ if (dev->usbdev) {
+
+ memset(dev->ctrlmsg, 0, sizeof(dev->ctrlmsg));
+
+ /* cp must be memory that has been allocated by kmalloc */
+ status = usb_control_msg(dev->usbdev,
+ usb_rcvctrlpipe(dev->usbdev, 0),
+ request,
+ USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
+ value, index,
+ cp, size, 1000);
+
+ status = min(status, 0);
+
+ if (status < 0) {
+ printk(KERN_ERR "%s() Failed receiving control message, error %d.\n",
+ __func__, status);
+ } else
+ cmd_msg_dump(dev);
+ }
+ mutex_unlock(&dev->mutex);
+ return status;
+}
+
+static void au0828_usb_disconnect(struct usb_interface *interface)
+{
+ struct au0828_dev *dev = usb_get_intfdata(interface);
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Digital TV */
+ au0828_dvb_unregister(dev);
+
+ /* I2C */
+ au0828_i2c_unregister(dev);
+
+ usb_set_intfdata(interface, NULL);
+
+ mutex_lock(&dev->mutex);
+ dev->usbdev = NULL;
+ mutex_unlock(&dev->mutex);
+
+ kfree(dev);
+
+}
+
+static int au0828_usb_probe(struct usb_interface *interface,
+ const struct usb_device_id *id)
+{
+ int ifnum;
+ struct au0828_dev *dev;
+ struct usb_device *usbdev = interface_to_usbdev(interface);
+
+ ifnum = interface->altsetting->desc.bInterfaceNumber;
+
+ if (ifnum != 0)
+ return -ENODEV;
+
+ dprintk(1, "%s() vendor id 0x%x device id 0x%x ifnum:%d\n", __func__,
+ le16_to_cpu(usbdev->descriptor.idVendor),
+ le16_to_cpu(usbdev->descriptor.idProduct),
+ ifnum);
+
+ dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+ if (dev == NULL) {
+ printk(KERN_ERR "%s() Unable to allocate memory\n", __func__);
+ return -ENOMEM;
+ }
+
+ mutex_init(&dev->mutex);
+ mutex_init(&dev->dvb.lock);
+ dev->usbdev = usbdev;
+ dev->board = id->driver_info;
+
+ usb_set_intfdata(interface, dev);
+
+ /* Power Up the bridge */
+ au0828_write(dev, REG_600, 1 << 4);
+
+ /* Bring up the GPIO's and supporting devices */
+ au0828_gpio_setup(dev);
+
+ /* I2C */
+ au0828_i2c_register(dev);
+
+ /* Setup */
+ au0828_card_setup(dev);
+
+ /* Digital TV */
+ au0828_dvb_register(dev);
+
+ printk(KERN_INFO "Registered device AU0828 [%s]\n",
+ au0828_boards[dev->board].name == NULL ? "Unset" :
+ au0828_boards[dev->board].name);
+
+ return 0;
+}
+
+static struct usb_driver au0828_usb_driver = {
+ .name = DRIVER_NAME,
+ .probe = au0828_usb_probe,
+ .disconnect = au0828_usb_disconnect,
+ .id_table = au0828_usb_id_table,
+};
+
+static int __init au0828_init(void)
+{
+ int ret;
+
+ if (debug)
+ printk(KERN_INFO "%s() Debugging is enabled\n", __func__);
+
+ if (usb_debug) {
+ printk(KERN_INFO "%s() USB Debugging is enabled\n", __func__);
+ debug |= 2;
+ }
+
+ if (i2c_debug) {
+ printk(KERN_INFO "%s() I2C Debugging is enabled\n", __func__);
+ debug |= 4;
+ }
+
+ if (bridge_debug) {
+ printk(KERN_INFO "%s() Bridge Debugging is enabled\n",
+ __func__);
+ debug |= 8;
+ }
+
+ printk(KERN_INFO "au0828 driver loaded\n");
+
+ ret = usb_register(&au0828_usb_driver);
+ if (ret)
+ printk(KERN_ERR "usb_register failed, error = %d\n", ret);
+
+ return ret;
+}
+
+static void __exit au0828_exit(void)
+{
+ usb_deregister(&au0828_usb_driver);
+}
+
+module_init(au0828_init);
+module_exit(au0828_exit);
+
+MODULE_DESCRIPTION("Driver for Auvitek AU0828 based products");
+MODULE_AUTHOR("Steven Toth <stoth@hauppauge.com>");
+MODULE_LICENSE("GPL");
diff --git a/drivers/media/video/au0828/au0828-dvb.c b/drivers/media/video/au0828/au0828-dvb.c
new file mode 100644
index 00000000000..85d0ae9a322
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-dvb.c
@@ -0,0 +1,373 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/device.h>
+#include <linux/suspend.h>
+#include <media/v4l2-common.h>
+
+#include "au0828.h"
+#include "au8522.h"
+#include "xc5000.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define _AU0828_BULKPIPE 0x83
+#define _BULKPIPESIZE 0xe522
+
+static struct au8522_config hauppauge_hvr950q_config = {
+ .demod_address = 0x8e >> 1,
+ .status_mode = AU8522_DEMODLOCKING,
+};
+
+static struct xc5000_config hauppauge_hvr950q_tunerconfig = {
+ .i2c_address = 0x61,
+ .if_khz = 6000,
+ .tuner_callback = au0828_tuner_callback
+};
+
+/*-------------------------------------------------------------------*/
+static void urb_completion(struct urb *purb)
+{
+ u8 *ptr;
+ struct au0828_dev *dev = purb->context;
+ int ptype = usb_pipetype(purb->pipe);
+
+ dprintk(2, "%s()\n", __func__);
+
+ if (!dev)
+ return;
+
+ if (dev->urb_streaming == 0)
+ return;
+
+ if (ptype != PIPE_BULK) {
+ printk(KERN_ERR "%s() Unsupported URB type %d\n",
+ __func__, ptype);
+ return;
+ }
+
+ ptr = (u8 *)purb->transfer_buffer;
+
+ /* Feed the transport payload into the kernel demux */
+ dvb_dmx_swfilter_packets(&dev->dvb.demux,
+ purb->transfer_buffer, purb->actual_length / 188);
+
+ /* Clean the buffer before we requeue */
+ memset(purb->transfer_buffer, 0, URB_BUFSIZE);
+
+ /* Requeue URB */
+ usb_submit_urb(purb, GFP_ATOMIC);
+}
+
+static int stop_urb_transfer(struct au0828_dev *dev)
+{
+ int i;
+
+ dprintk(2, "%s()\n", __func__);
+
+ for (i = 0; i < URB_COUNT; i++) {
+ usb_kill_urb(dev->urbs[i]);
+ kfree(dev->urbs[i]->transfer_buffer);
+ usb_free_urb(dev->urbs[i]);
+ }
+
+ dev->urb_streaming = 0;
+
+ return 0;
+}
+
+static int start_urb_transfer(struct au0828_dev *dev)
+{
+ struct urb *purb;
+ int i, ret = -ENOMEM;
+
+ dprintk(2, "%s()\n", __func__);
+
+ if (dev->urb_streaming) {
+ dprintk(2, "%s: iso xfer already running!\n", __func__);
+ return 0;
+ }
+
+ for (i = 0; i < URB_COUNT; i++) {
+
+ dev->urbs[i] = usb_alloc_urb(0, GFP_KERNEL);
+ if (!dev->urbs[i])
+ goto err;
+
+ purb = dev->urbs[i];
+
+ purb->transfer_buffer = kzalloc(URB_BUFSIZE, GFP_KERNEL);
+ if (!purb->transfer_buffer) {
+ usb_free_urb(purb);
+ dev->urbs[i] = 0;
+ goto err;
+ }
+
+ purb->status = -EINPROGRESS;
+ usb_fill_bulk_urb(purb,
+ dev->usbdev,
+ usb_rcvbulkpipe(dev->usbdev, _AU0828_BULKPIPE),
+ purb->transfer_buffer,
+ URB_BUFSIZE,
+ urb_completion,
+ dev);
+
+ }
+
+ for (i = 0; i < URB_COUNT; i++) {
+ ret = usb_submit_urb(dev->urbs[i], GFP_ATOMIC);
+ if (ret != 0) {
+ stop_urb_transfer(dev);
+ printk(KERN_ERR "%s: failed urb submission, "
+ "err = %d\n", __func__, ret);
+ return ret;
+ }
+ }
+
+ dev->urb_streaming = 1;
+ ret = 0;
+
+err:
+ return ret;
+}
+
+static int au0828_dvb_start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret = 0;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ if (dvb) {
+ mutex_lock(&dvb->lock);
+ if (dvb->feeding++ == 0) {
+ /* Start transport */
+ au0828_write(dev, 0x608, 0x90);
+ au0828_write(dev, 0x609, 0x72);
+ au0828_write(dev, 0x60a, 0x71);
+ au0828_write(dev, 0x60b, 0x01);
+ ret = start_urb_transfer(dev);
+ }
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
+static int au0828_dvb_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct au0828_dev *dev = (struct au0828_dev *) demux->priv;
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret = 0;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (dvb) {
+ mutex_lock(&dvb->lock);
+ if (--dvb->feeding == 0) {
+ /* Stop transport */
+ au0828_write(dev, 0x608, 0x00);
+ au0828_write(dev, 0x609, 0x00);
+ au0828_write(dev, 0x60a, 0x00);
+ au0828_write(dev, 0x60b, 0x00);
+ ret = stop_urb_transfer(dev);
+ }
+ mutex_unlock(&dvb->lock);
+ }
+
+ return ret;
+}
+
+int dvb_register(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+ int result;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* register adapter */
+ result = dvb_register_adapter(&dvb->adapter, DRIVER_NAME, THIS_MODULE,
+ &dev->usbdev->dev, adapter_nr);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_register_adapter failed "
+ "(errno = %d)\n", DRIVER_NAME, result);
+ goto fail_adapter;
+ }
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_register_frontend failed "
+ "(errno = %d)\n", DRIVER_NAME, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dev;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = au0828_dvb_start_feed;
+ dvb->demux.stop_feed = au0828_dvb_stop_feed;
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_dmx_init failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+ if (result < 0) {
+ printk(KERN_ERR "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_ERR "%s: add_frontend failed "
+ "(DMX_FRONTEND_0, errno = %d)\n", DRIVER_NAME, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ printk(KERN_ERR "%s: add_frontend failed "
+ "(DMX_MEMORY_FE, errno = %d)\n", DRIVER_NAME, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_ERR "%s: connect_frontend failed (errno = %d)\n",
+ DRIVER_NAME, result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+ return 0;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+ return result;
+}
+
+void au0828_dvb_unregister(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (dvb->frontend == NULL)
+ return;
+
+ dvb_net_release(&dvb->net);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+}
+
+/* All the DVB attach calls go here, this function get's modified
+ * for each new card. No other function in this file needs
+ * to change.
+ */
+int au0828_dvb_register(struct au0828_dev *dev)
+{
+ struct au0828_dvb *dvb = &dev->dvb;
+ int ret;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* init frontend */
+ switch (dev->board) {
+ case AU0828_BOARD_HAUPPAUGE_HVR850:
+ case AU0828_BOARD_HAUPPAUGE_HVR950Q:
+ case AU0828_BOARD_DVICO_FUSIONHDTV7:
+ dvb->frontend = dvb_attach(au8522_attach,
+ &hauppauge_hvr950q_config,
+ &dev->i2c_adap);
+ if (dvb->frontend != NULL) {
+ hauppauge_hvr950q_tunerconfig.priv = dev;
+ dvb_attach(xc5000_attach, dvb->frontend,
+ &dev->i2c_adap,
+ &hauppauge_hvr950q_tunerconfig);
+ }
+ break;
+ default:
+ printk(KERN_WARNING "The frontend of your DVB/ATSC card "
+ "isn't supported yet\n");
+ break;
+ }
+ if (NULL == dvb->frontend) {
+ printk(KERN_ERR "%s() Frontend initialization failed\n",
+ __func__);
+ return -1;
+ }
+
+ /* Put the analog decoder in standby to keep it quiet */
+ au0828_call_i2c_clients(dev, TUNER_SET_STANDBY, NULL);
+
+ if (dvb->frontend->ops.analog_ops.standby)
+ dvb->frontend->ops.analog_ops.standby(dvb->frontend);
+
+ /* register everything */
+ ret = dvb_register(dev);
+ if (ret < 0) {
+ if (dvb->frontend->ops.release)
+ dvb->frontend->ops.release(dvb->frontend);
+ return ret;
+ }
+
+ return 0;
+}
diff --git a/drivers/media/video/au0828/au0828-i2c.c b/drivers/media/video/au0828/au0828-i2c.c
new file mode 100644
index 00000000000..94c8b74a665
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-i2c.c
@@ -0,0 +1,385 @@
+/*
+ * Driver for the Auvitek AU0828 USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/delay.h>
+#include <linux/io.h>
+
+#include "au0828.h"
+
+#include <media/v4l2-common.h>
+
+unsigned int i2c_debug;
+module_param(i2c_debug, int, 0444);
+MODULE_PARM_DESC(i2c_debug, "enable debug messages [i2c]");
+
+unsigned int i2c_scan;
+module_param(i2c_scan, int, 0444);
+MODULE_PARM_DESC(i2c_scan, "scan i2c bus at insmod time");
+
+#define I2C_WAIT_DELAY 512
+#define I2C_WAIT_RETRY 64
+
+static inline int i2c_slave_did_write_ack(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x08 ? 0 : 1;
+}
+
+static inline int i2c_slave_did_read_ack(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x02 ? 0 : 1;
+}
+
+static int i2c_wait_read_ack(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_slave_did_read_ack(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_read_busy(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x01 ? 0 : 1;
+}
+
+static int i2c_wait_read_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_is_read_busy(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_write_done(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x04 ? 1 : 0;
+}
+
+static int i2c_wait_write_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (i2c_is_write_done(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+static inline int i2c_is_busy(struct i2c_adapter *i2c_adap)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ return au0828_read(dev, REG_201) & 0x10 ? 1 : 0;
+}
+
+static int i2c_wait_done(struct i2c_adapter *i2c_adap)
+{
+ int count;
+
+ for (count = 0; count < I2C_WAIT_RETRY; count++) {
+ if (!i2c_is_busy(i2c_adap))
+ break;
+ udelay(I2C_WAIT_DELAY);
+ }
+
+ if (I2C_WAIT_RETRY == count)
+ return 0;
+
+ return 1;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int joined_rlen)
+{
+ int i, strobe = 0;
+ struct au0828_dev *dev = i2c_adap->algo_data;
+
+ dprintk(4, "%s()\n", __func__);
+
+ au0828_write(dev, REG_2FF, 0x01);
+ au0828_write(dev, REG_202, 0x07);
+
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, REG_203, msg->addr << 1);
+
+ dprintk(4, "SEND: %02x\n", msg->addr);
+
+ for (i = 0; i < msg->len;) {
+
+ dprintk(4, " %02x\n", msg->buf[i]);
+
+ au0828_write(dev, REG_205, msg->buf[i]);
+
+ strobe++;
+ i++;
+
+ if ((strobe >= 4) || (i >= msg->len)) {
+
+ /* Strobe the byte into the bus */
+ if (i < msg->len)
+ au0828_write(dev, REG_200, 0x41);
+ else
+ au0828_write(dev, REG_200, 0x01);
+
+ /* Reset strobe trigger */
+ strobe = 0;
+
+ if (!i2c_wait_write_done(i2c_adap))
+ return -EIO;
+
+ }
+
+ }
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+
+ dprintk(4, "\n");
+
+ return msg->len;
+}
+
+/* FIXME: Implement join handling correctly */
+static int i2c_readbytes(struct i2c_adapter *i2c_adap,
+ const struct i2c_msg *msg, int joined)
+{
+ struct au0828_dev *dev = i2c_adap->algo_data;
+ int i;
+
+ dprintk(4, "%s()\n", __func__);
+
+ au0828_write(dev, REG_2FF, 0x01);
+ au0828_write(dev, REG_202, 0x07);
+
+ /* Hardware needs 8 bit addresses */
+ au0828_write(dev, REG_203, msg->addr << 1);
+
+ dprintk(4, " RECV:\n");
+
+ /* Deal with i2c_scan */
+ if (msg->len == 0) {
+ au0828_write(dev, REG_200, 0x20);
+ if (i2c_wait_read_ack(i2c_adap))
+ return -EIO;
+ return 0;
+ }
+
+ for (i = 0; i < msg->len;) {
+
+ i++;
+
+ if (i < msg->len)
+ au0828_write(dev, REG_200, 0x60);
+ else
+ au0828_write(dev, REG_200, 0x20);
+
+ if (!i2c_wait_read_done(i2c_adap))
+ return -EIO;
+
+ msg->buf[i-1] = au0828_read(dev, REG_209) & 0xff;
+
+ dprintk(4, " %02x\n", msg->buf[i-1]);
+ }
+ if (!i2c_wait_done(i2c_adap))
+ return -EIO;
+
+ dprintk(4, "\n");
+
+ return msg->len;
+}
+
+static int i2c_xfer(struct i2c_adapter *i2c_adap,
+ struct i2c_msg *msgs, int num)
+{
+ int i, retval = 0;
+
+ dprintk(4, "%s(num = %d)\n", __func__, num);
+
+ for (i = 0; i < num; i++) {
+ dprintk(4, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
+ __func__, num, msgs[i].addr, msgs[i].len);
+ if (msgs[i].flags & I2C_M_RD) {
+ /* read */
+ retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
+ } else if (i + 1 < num && (msgs[i + 1].flags & I2C_M_RD) &&
+ msgs[i].addr == msgs[i + 1].addr) {
+ /* write then read from same address */
+ retval = i2c_sendbytes(i2c_adap, &msgs[i],
+ msgs[i + 1].len);
+ if (retval < 0)
+ goto err;
+ i++;
+ retval = i2c_readbytes(i2c_adap, &msgs[i], 1);
+ } else {
+ /* write */
+ retval = i2c_sendbytes(i2c_adap, &msgs[i], 0);
+ }
+ if (retval < 0)
+ goto err;
+ }
+ return num;
+
+err:
+ return retval;
+}
+
+static int attach_inform(struct i2c_client *client)
+{
+ dprintk(1, "%s i2c attach [addr=0x%x,client=%s]\n",
+ client->driver->driver.name, client->addr, client->name);
+
+ if (!client->driver->command)
+ return 0;
+
+ return 0;
+}
+
+static int detach_inform(struct i2c_client *client)
+{
+ dprintk(1, "i2c detach [client=%s]\n", client->name);
+
+ return 0;
+}
+
+void au0828_call_i2c_clients(struct au0828_dev *dev,
+ unsigned int cmd, void *arg)
+{
+ if (dev->i2c_rc != 0)
+ return;
+
+ i2c_clients_command(&dev->i2c_adap, cmd, arg);
+}
+
+static u32 au0828_functionality(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_SMBUS_EMUL | I2C_FUNC_I2C;
+}
+
+static struct i2c_algorithm au0828_i2c_algo_template = {
+ .master_xfer = i2c_xfer,
+ .functionality = au0828_functionality,
+};
+
+/* ----------------------------------------------------------------------- */
+
+static struct i2c_adapter au0828_i2c_adap_template = {
+ .name = DRIVER_NAME,
+ .owner = THIS_MODULE,
+ .id = I2C_HW_B_AU0828,
+ .algo = &au0828_i2c_algo_template,
+ .class = I2C_CLASS_TV_ANALOG,
+ .client_register = attach_inform,
+ .client_unregister = detach_inform,
+};
+
+static struct i2c_client au0828_i2c_client_template = {
+ .name = "au0828 internal",
+};
+
+static char *i2c_devs[128] = {
+ [0x8e >> 1] = "au8522",
+ [0xa0 >> 1] = "eeprom",
+ [0xc2 >> 1] = "tuner/xc5000",
+};
+
+static void do_i2c_scan(char *name, struct i2c_client *c)
+{
+ unsigned char buf;
+ int i, rc;
+
+ for (i = 0; i < 128; i++) {
+ c->addr = i;
+ rc = i2c_master_recv(c, &buf, 0);
+ if (rc < 0)
+ continue;
+ printk(KERN_INFO "%s: i2c scan: found device @ 0x%x [%s]\n",
+ name, i << 1, i2c_devs[i] ? i2c_devs[i] : "???");
+ }
+}
+
+/* init + register i2c algo-bit adapter */
+int au0828_i2c_register(struct au0828_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ memcpy(&dev->i2c_adap, &au0828_i2c_adap_template,
+ sizeof(dev->i2c_adap));
+ memcpy(&dev->i2c_algo, &au0828_i2c_algo_template,
+ sizeof(dev->i2c_algo));
+ memcpy(&dev->i2c_client, &au0828_i2c_client_template,
+ sizeof(dev->i2c_client));
+
+ dev->i2c_adap.dev.parent = &dev->usbdev->dev;
+
+ strlcpy(dev->i2c_adap.name, DRIVER_NAME,
+ sizeof(dev->i2c_adap.name));
+
+ dev->i2c_algo.data = dev;
+ dev->i2c_adap.algo_data = dev;
+ i2c_set_adapdata(&dev->i2c_adap, dev);
+ i2c_add_adapter(&dev->i2c_adap);
+
+ dev->i2c_client.adapter = &dev->i2c_adap;
+
+ if (0 == dev->i2c_rc) {
+ printk(KERN_INFO "%s: i2c bus registered\n", DRIVER_NAME);
+ if (i2c_scan)
+ do_i2c_scan(DRIVER_NAME, &dev->i2c_client);
+ } else
+ printk(KERN_INFO "%s: i2c bus register FAILED\n", DRIVER_NAME);
+
+ return dev->i2c_rc;
+}
+
+int au0828_i2c_unregister(struct au0828_dev *dev)
+{
+ i2c_del_adapter(&dev->i2c_adap);
+ return 0;
+}
+
diff --git a/drivers/media/video/au0828/au0828-reg.h b/drivers/media/video/au0828/au0828-reg.h
new file mode 100644
index 00000000000..39827550891
--- /dev/null
+++ b/drivers/media/video/au0828/au0828-reg.h
@@ -0,0 +1,38 @@
+/*
+ * Driver for the Auvitek USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* We'll start to rename these registers once we have a better
+ * understanding of their meaning.
+ */
+#define REG_000 0x000
+#define REG_001 0x001
+#define REG_002 0x002
+#define REG_003 0x003
+
+#define REG_200 0x200
+#define REG_201 0x201
+#define REG_202 0x202
+#define REG_203 0x203
+#define REG_205 0x205
+#define REG_209 0x209
+#define REG_2FF 0x2ff
+
+#define REG_600 0x600
diff --git a/drivers/media/video/au0828/au0828.h b/drivers/media/video/au0828/au0828.h
new file mode 100644
index 00000000000..0200b9fc5dc
--- /dev/null
+++ b/drivers/media/video/au0828/au0828.h
@@ -0,0 +1,128 @@
+/*
+ * Driver for the Auvitek AU0828 USB bridge
+ *
+ * Copyright (c) 2008 Steven Toth <stoth@hauppauge.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/usb.h>
+#include <linux/i2c.h>
+#include <linux/i2c-algo-bit.h>
+#include <media/tveeprom.h>
+
+/* DVB */
+#include "demux.h"
+#include "dmxdev.h"
+#include "dvb_demux.h"
+#include "dvb_frontend.h"
+#include "dvb_net.h"
+#include "dvbdev.h"
+
+#include "au0828-reg.h"
+#include "au0828-cards.h"
+
+#define DRIVER_NAME "au0828"
+#define URB_COUNT 16
+#define URB_BUFSIZE (0xe522)
+
+struct au0828_board {
+ char *name;
+};
+
+struct au0828_dvb {
+ struct mutex lock;
+ struct dvb_adapter adapter;
+ struct dvb_frontend *frontend;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net net;
+ int feeding;
+};
+
+struct au0828_dev {
+ struct mutex mutex;
+ struct usb_device *usbdev;
+ int board;
+ u8 ctrlmsg[64];
+
+ /* I2C */
+ struct i2c_adapter i2c_adap;
+ struct i2c_algo_bit_data i2c_algo;
+ struct i2c_client i2c_client;
+ u32 i2c_rc;
+
+ /* Digital */
+ struct au0828_dvb dvb;
+
+ /* USB / URB Related */
+ int urb_streaming;
+ struct urb *urbs[URB_COUNT];
+
+};
+
+struct au0828_buff {
+ struct au0828_dev *dev;
+ struct urb *purb;
+ struct list_head buff_list;
+};
+
+/* ----------------------------------------------------------- */
+#define au0828_read(dev, reg) au0828_readreg(dev, reg)
+#define au0828_write(dev, reg, value) au0828_writereg(dev, reg, value)
+#define au0828_andor(dev, reg, mask, value) \
+ au0828_writereg(dev, reg, \
+ (au0828_readreg(dev, reg) & ~(mask)) | ((value) & (mask)))
+
+#define au0828_set(dev, reg, bit) au0828_andor(dev, (reg), (bit), (bit))
+#define au0828_clear(dev, reg, bit) au0828_andor(dev, (reg), (bit), 0)
+
+/* ----------------------------------------------------------- */
+/* au0828-core.c */
+extern u32 au0828_read(struct au0828_dev *dev, u16 reg);
+extern u32 au0828_write(struct au0828_dev *dev, u16 reg, u32 val);
+extern unsigned int debug;
+extern unsigned int usb_debug;
+extern unsigned int bridge_debug;
+
+/* ----------------------------------------------------------- */
+/* au0828-cards.c */
+extern struct au0828_board au0828_boards[];
+extern struct usb_device_id au0828_usb_id_table[];
+extern const unsigned int au0828_bcount;
+extern void au0828_gpio_setup(struct au0828_dev *dev);
+extern int au0828_tuner_callback(void *priv, int command, int arg);
+extern void au0828_card_setup(struct au0828_dev *dev);
+
+/* ----------------------------------------------------------- */
+/* au0828-i2c.c */
+extern int au0828_i2c_register(struct au0828_dev *dev);
+extern int au0828_i2c_unregister(struct au0828_dev *dev);
+extern void au0828_call_i2c_clients(struct au0828_dev *dev,
+ unsigned int cmd, void *arg);
+extern unsigned int i2c_debug;
+
+/* ----------------------------------------------------------- */
+/* au0828-dvb.c */
+extern int au0828_dvb_register(struct au0828_dev *dev);
+extern void au0828_dvb_unregister(struct au0828_dev *dev);
+
+#define dprintk(level, fmt, arg...)\
+ do { if (debug & level)\
+ printk(KERN_DEBUG DRIVER_NAME "/0: " fmt, ## arg);\
+ } while (0)
diff --git a/drivers/media/video/bt819.c b/drivers/media/video/bt819.c
index e663cc045c4..8bfd5c75cb3 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 7dee2e3235a..98ee2d8feb3 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 7374c02dd18..f20a01cfc73 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 fcf8f2d208a..2ca3e9cfb2b 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),
@@ -3457,6 +3463,9 @@ static int radio_release(struct inode *inode, struct file *file)
struct bttv *btv = fh->btv;
struct rds_command cmd;
+ file->private_data = NULL;
+ kfree(fh);
+
btv->radio_user--;
bttv_call_i2c_clients(btv, RDS_CMD_CLOSE, &cmd);
@@ -3510,7 +3519,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 +3527,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 +3551,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 fc9ecb21eec..a38af98f4ca 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 75fa82c7c73..bfdbc469e30 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 bf4c339a520..f2393202904 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 1305d315cfc..03816b73f84 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 032265383df..b364adaae78 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 cf1546b5a7f..fe1e67bb1ca 100644
--- a/drivers/media/video/c-qcam.c
+++ b/drivers/media/video/c-qcam.c
@@ -36,6 +36,7 @@
#include <linux/videodev.h>
#include <media/v4l2-common.h>
#include <linux/mutex.h>
+#include <linux/jiffies.h>
#include <asm/uaccess.h>
@@ -69,7 +70,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)
@@ -95,7 +96,8 @@ static unsigned int qcam_await_ready1(struct qcam_device *qcam,
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
+ for (oldjiffies = jiffies;
+ time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
if (qcam_ready1(qcam) == value)
return 0;
@@ -120,7 +122,8 @@ static unsigned int qcam_await_ready2(struct qcam_device *qcam, int value)
unsigned long oldjiffies = jiffies;
unsigned int i;
- for (oldjiffies = jiffies; (jiffies - oldjiffies) < msecs_to_jiffies(40); )
+ for (oldjiffies = jiffies;
+ time_before(jiffies, oldjiffies + msecs_to_jiffies(40)); )
if (qcam_ready2(qcam) == value)
return 0;
@@ -689,7 +692,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 +746,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 7ae499c9c54..5195b1f3378 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 7c630f5ee72..2a81376ef50 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/cpia.h b/drivers/media/video/cpia.h
index 78392fb6f94..5096058bf57 100644
--- a/drivers/media/video/cpia.h
+++ b/drivers/media/video/cpia.h
@@ -412,11 +412,11 @@ void cpia_unregister_camera(struct cam_data *cam);
/* ErrorCode */
#define ERROR_FLICKER_BELOW_MIN_EXP 0x01 /*flicker exposure got below minimum exposure */
#define ALOG(fmt,args...) printk(fmt, ##args)
-#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __FUNCTION__ , __LINE__ , ##args)
+#define LOG(fmt,args...) ALOG(KERN_INFO __FILE__ ":%s(%d):" fmt, __func__ , __LINE__ , ##args)
#ifdef _CPIA_DEBUG_
#define ADBG(fmt,args...) printk(fmt, jiffies, ##args)
-#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __FUNCTION__, __LINE__ , ##args)
+#define DBG(fmt,args...) ADBG(KERN_DEBUG __FILE__" (%ld):%s(%d):" fmt, __func__, __LINE__ , ##args)
#else
#define DBG(fmn,args...) do {} while(0)
#endif
diff --git a/drivers/media/video/cpia2/cpia2_core.c b/drivers/media/video/cpia2/cpia2_core.c
index a76bd786cf1..c8b9fdb700f 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 */
/******************************************************************************
@@ -570,7 +570,7 @@ int cpia2_send_command(struct camera_data *cam, struct cpia2_command *cmd)
block_name[block_index]);
break;
default:
- LOG("%s: invalid request mode\n",__FUNCTION__);
+ LOG("%s: invalid request mode\n",__func__);
return -EINVAL;
}
@@ -952,7 +952,7 @@ static int set_default_user_mode(struct camera_data *cam)
frame_rate = CPIA2_VP_FRAMERATE_30;
break;
default:
- LOG("%s: Invalid sensor flag value 0x%0X\n",__FUNCTION__,
+ LOG("%s: Invalid sensor flag value 0x%0X\n",__func__,
cam->params.version.sensor_flags);
return -EINVAL;
}
@@ -2356,12 +2356,12 @@ long cpia2_read(struct camera_data *cam,
}
if (!buf) {
- ERR("%s: buffer NULL\n",__FUNCTION__);
+ ERR("%s: buffer NULL\n",__func__);
return -EINVAL;
}
if (!cam) {
- ERR("%s: Internal error, camera_data NULL!\n",__FUNCTION__);
+ ERR("%s: Internal error, camera_data NULL!\n",__func__);
return -EINVAL;
}
@@ -2370,7 +2370,7 @@ long cpia2_read(struct camera_data *cam,
return -ERESTARTSYS;
if (!cam->present) {
- LOG("%s: camera removed\n",__FUNCTION__);
+ LOG("%s: camera removed\n",__func__);
mutex_unlock(&cam->busy_lock);
return 0; /* EOF */
}
@@ -2434,7 +2434,7 @@ unsigned int cpia2_poll(struct camera_data *cam, struct file *filp,
unsigned int status=0;
if(!cam) {
- ERR("%s: Internal error, camera_data not found!\n",__FUNCTION__);
+ ERR("%s: Internal error, camera_data not found!\n",__func__);
return POLLERR;
}
diff --git a/drivers/media/video/cpia2/cpia2_usb.c b/drivers/media/video/cpia2/cpia2_usb.c
index d8e929863a8..a4574740350 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 e378abec806..7ce2789fa97 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/cpia_usb.c b/drivers/media/video/cpia_usb.c
index 9da4726eb9b..ef1f8939998 100644
--- a/drivers/media/video/cpia_usb.c
+++ b/drivers/media/video/cpia_usb.c
@@ -170,7 +170,7 @@ static void cpia_usb_complete(struct urb *urb)
/* resubmit */
urb->dev = ucpia->dev;
if ((i = usb_submit_urb(urb, GFP_ATOMIC)) != 0)
- printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __FUNCTION__, i);
+ printk(KERN_ERR "%s: usb_submit_urb ret %d\n", __func__, i);
}
static int cpia_usb_open(void *privdata)
diff --git a/drivers/media/video/cx23885/Kconfig b/drivers/media/video/cx23885/Kconfig
index 1fd326fe411..ca5fbce3a90 100644
--- a/drivers/media/video/cx23885/Kconfig
+++ b/drivers/media/video/cx23885/Kconfig
@@ -8,6 +8,7 @@ config VIDEO_CX23885
select VIDEO_TVEEPROM
select VIDEO_IR
select VIDEOBUF_DVB
+ select VIDEO_CX25840
select DVB_TUNER_MT2131 if !DVB_FE_CUSTOMISE
select DVB_S5H1409 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
@@ -16,6 +17,7 @@ config VIDEO_CX23885
select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
select DVB_TUNER_XC5000 if !DVB_FE_CUSTOMIZE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
---help---
This is a video4linux driver for Conexant 23885 based
TV cards.
diff --git a/drivers/media/video/cx23885/Makefile b/drivers/media/video/cx23885/Makefile
index 32c90be5060..d7b0721af06 100644
--- a/drivers/media/video/cx23885/Makefile
+++ b/drivers/media/video/cx23885/Makefile
@@ -1,4 +1,4 @@
-cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o
+cx23885-objs := cx23885-cards.o cx23885-video.o cx23885-vbi.o cx23885-core.o cx23885-i2c.o cx23885-dvb.o cx23885-417.o
obj-$(CONFIG_VIDEO_CX23885) += cx23885.o
diff --git a/drivers/media/video/cx23885/cx23885-417.c b/drivers/media/video/cx23885/cx23885-417.c
new file mode 100644
index 00000000000..acdd3b6b3e7
--- /dev/null
+++ b/drivers/media/video/cx23885/cx23885-417.c
@@ -0,0 +1,1764 @@
+/*
+ *
+ * Support for a cx23417 mpeg encoder via cx23885 host port.
+ *
+ * (c) 2004 Jelle Foks <jelle@foks.8m.com>
+ * (c) 2004 Gerd Knorr <kraxel@bytesex.org>
+ * (c) 2008 Steven Toth <stoth@hauppauge.com>
+ * - CX23885/7/8 support
+ *
+ * Includes parts from the ivtv driver( http://ivtv.sourceforge.net/),
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/init.h>
+#include <linux/fs.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/firmware.h>
+#include <media/v4l2-common.h>
+#include <media/cx2341x.h>
+
+#include "cx23885.h"
+#include "media/cx2341x.h"
+
+#define CX23885_FIRM_IMAGE_SIZE 376836
+#define CX23885_FIRM_IMAGE_NAME "v4l-cx23885-enc.fw"
+
+static unsigned int mpegbufs = 32;
+module_param(mpegbufs, int, 0644);
+MODULE_PARM_DESC(mpegbufs, "number of mpeg buffers, range 2-32");
+static unsigned int mpeglines = 32;
+module_param(mpeglines, int, 0644);
+MODULE_PARM_DESC(mpeglines, "number of lines in an MPEG buffer, range 2-32");
+static unsigned int mpeglinesize = 512;
+module_param(mpeglinesize, int, 0644);
+MODULE_PARM_DESC(mpeglinesize,
+ "number of bytes in each line of an MPEG buffer, range 512-1024");
+
+static unsigned int v4l_debug;
+module_param(v4l_debug, int, 0644);
+MODULE_PARM_DESC(v4l_debug, "enable V4L debug messages");
+
+#define dprintk(level, fmt, arg...)\
+ do { if (v4l_debug >= level) \
+ printk(KERN_DEBUG "%s: " fmt, dev->name , ## arg);\
+ } while (0)
+
+static struct cx23885_tvnorm cx23885_tvnorms[] = {
+ {
+ .name = "NTSC-M",
+ .id = V4L2_STD_NTSC_M,
+ }, {
+ .name = "NTSC-JP",
+ .id = V4L2_STD_NTSC_M_JP,
+ }, {
+ .name = "PAL-BG",
+ .id = V4L2_STD_PAL_BG,
+ }, {
+ .name = "PAL-DK",
+ .id = V4L2_STD_PAL_DK,
+ }, {
+ .name = "PAL-I",
+ .id = V4L2_STD_PAL_I,
+ }, {
+ .name = "PAL-M",
+ .id = V4L2_STD_PAL_M,
+ }, {
+ .name = "PAL-N",
+ .id = V4L2_STD_PAL_N,
+ }, {
+ .name = "PAL-Nc",
+ .id = V4L2_STD_PAL_Nc,
+ }, {
+ .name = "PAL-60",
+ .id = V4L2_STD_PAL_60,
+ }, {
+ .name = "SECAM-L",
+ .id = V4L2_STD_SECAM_L,
+ }, {
+ .name = "SECAM-DK",
+ .id = V4L2_STD_SECAM_DK,
+ }
+};
+
+/* ------------------------------------------------------------------ */
+enum cx23885_capture_type {
+ CX23885_MPEG_CAPTURE,
+ CX23885_RAW_CAPTURE,
+ CX23885_RAW_PASSTHRU_CAPTURE
+};
+enum cx23885_capture_bits {
+ CX23885_RAW_BITS_NONE = 0x00,
+ CX23885_RAW_BITS_YUV_CAPTURE = 0x01,
+ CX23885_RAW_BITS_PCM_CAPTURE = 0x02,
+ CX23885_RAW_BITS_VBI_CAPTURE = 0x04,
+ CX23885_RAW_BITS_PASSTHRU_CAPTURE = 0x08,
+ CX23885_RAW_BITS_TO_HOST_CAPTURE = 0x10
+};
+enum cx23885_capture_end {
+ CX23885_END_AT_GOP, /* stop at the end of gop, generate irq */
+ CX23885_END_NOW, /* stop immediately, no irq */
+};
+enum cx23885_framerate {
+ CX23885_FRAMERATE_NTSC_30, /* NTSC: 30fps */
+ CX23885_FRAMERATE_PAL_25 /* PAL: 25fps */
+};
+enum cx23885_stream_port {
+ CX23885_OUTPUT_PORT_MEMORY,
+ CX23885_OUTPUT_PORT_STREAMING,
+ CX23885_OUTPUT_PORT_SERIAL
+};
+enum cx23885_data_xfer_status {
+ CX23885_MORE_BUFFERS_FOLLOW,
+ CX23885_LAST_BUFFER,
+};
+enum cx23885_picture_mask {
+ CX23885_PICTURE_MASK_NONE,
+ CX23885_PICTURE_MASK_I_FRAMES,
+ CX23885_PICTURE_MASK_I_P_FRAMES = 0x3,
+ CX23885_PICTURE_MASK_ALL_FRAMES = 0x7,
+};
+enum cx23885_vbi_mode_bits {
+ CX23885_VBI_BITS_SLICED,
+ CX23885_VBI_BITS_RAW,
+};
+enum cx23885_vbi_insertion_bits {
+ CX23885_VBI_BITS_INSERT_IN_XTENSION_USR_DATA,
+ CX23885_VBI_BITS_INSERT_IN_PRIVATE_PACKETS = 0x1 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM = 0x2 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM_USR_DATA = 0x4 << 1,
+ CX23885_VBI_BITS_SEPARATE_STREAM_PRV_DATA = 0x5 << 1,
+};
+enum cx23885_dma_unit {
+ CX23885_DMA_BYTES,
+ CX23885_DMA_FRAMES,
+};
+enum cx23885_dma_transfer_status_bits {
+ CX23885_DMA_TRANSFER_BITS_DONE = 0x01,
+ CX23885_DMA_TRANSFER_BITS_ERROR = 0x04,
+ CX23885_DMA_TRANSFER_BITS_LL_ERROR = 0x10,
+};
+enum cx23885_pause {
+ CX23885_PAUSE_ENCODING,
+ CX23885_RESUME_ENCODING,
+};
+enum cx23885_copyright {
+ CX23885_COPYRIGHT_OFF,
+ CX23885_COPYRIGHT_ON,
+};
+enum cx23885_notification_type {
+ CX23885_NOTIFICATION_REFRESH,
+};
+enum cx23885_notification_status {
+ CX23885_NOTIFICATION_OFF,
+ CX23885_NOTIFICATION_ON,
+};
+enum cx23885_notification_mailbox {
+ CX23885_NOTIFICATION_NO_MAILBOX = -1,
+};
+enum cx23885_field1_lines {
+ CX23885_FIELD1_SAA7114 = 0x00EF, /* 239 */
+ CX23885_FIELD1_SAA7115 = 0x00F0, /* 240 */
+ CX23885_FIELD1_MICRONAS = 0x0105, /* 261 */
+};
+enum cx23885_field2_lines {
+ CX23885_FIELD2_SAA7114 = 0x00EF, /* 239 */
+ CX23885_FIELD2_SAA7115 = 0x00F0, /* 240 */
+ CX23885_FIELD2_MICRONAS = 0x0106, /* 262 */
+};
+enum cx23885_custom_data_type {
+ CX23885_CUSTOM_EXTENSION_USR_DATA,
+ CX23885_CUSTOM_PRIVATE_PACKET,
+};
+enum cx23885_mute {
+ CX23885_UNMUTE,
+ CX23885_MUTE,
+};
+enum cx23885_mute_video_mask {
+ CX23885_MUTE_VIDEO_V_MASK = 0x0000FF00,
+ CX23885_MUTE_VIDEO_U_MASK = 0x00FF0000,
+ CX23885_MUTE_VIDEO_Y_MASK = 0xFF000000,
+};
+enum cx23885_mute_video_shift {
+ CX23885_MUTE_VIDEO_V_SHIFT = 8,
+ CX23885_MUTE_VIDEO_U_SHIFT = 16,
+ CX23885_MUTE_VIDEO_Y_SHIFT = 24,
+};
+
+/* defines below are from ivtv-driver.h */
+#define IVTV_CMD_HW_BLOCKS_RST 0xFFFFFFFF
+
+/* Firmware API commands */
+#define IVTV_API_STD_TIMEOUT 500
+
+/* Registers */
+/* IVTV_REG_OFFSET */
+#define IVTV_REG_ENC_SDRAM_REFRESH (0x07F8)
+#define IVTV_REG_ENC_SDRAM_PRECHARGE (0x07FC)
+#define IVTV_REG_SPU (0x9050)
+#define IVTV_REG_HW_BLOCKS (0x9054)
+#define IVTV_REG_VPU (0x9058)
+#define IVTV_REG_APU (0xA064)
+
+/**** Bit definitions for MC417_RWD and MC417_OEN registers ***
+ bits 31-16
++-----------+
+| Reserved |
++-----------+
+ bit 15 bit 14 bit 13 bit 12 bit 11 bit 10 bit 9 bit 8
++-------+-------+-------+-------+-------+-------+-------+-------+
+| MIWR# | MIRD# | MICS# |MIRDY# |MIADDR3|MIADDR2|MIADDR1|MIADDR0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+ bit 7 bit 6 bit 5 bit 4 bit 3 bit 2 bit 1 bit 0
++-------+-------+-------+-------+-------+-------+-------+-------+
+|MIDATA7|MIDATA6|MIDATA5|MIDATA4|MIDATA3|MIDATA2|MIDATA1|MIDATA0|
++-------+-------+-------+-------+-------+-------+-------+-------+
+***/
+#define MC417_MIWR 0x8000
+#define MC417_MIRD 0x4000
+#define MC417_MICS 0x2000
+#define MC417_MIRDY 0x1000
+#define MC417_MIADDR 0x0F00
+#define MC417_MIDATA 0x00FF
+
+/* MIADDR* nibble definitions */
+#define MCI_MEMORY_DATA_BYTE0 0x000
+#define MCI_MEMORY_DATA_BYTE1 0x100
+#define MCI_MEMORY_DATA_BYTE2 0x200
+#define MCI_MEMORY_DATA_BYTE3 0x300
+#define MCI_MEMORY_ADDRESS_BYTE2 0x400
+#define MCI_MEMORY_ADDRESS_BYTE1 0x500
+#define MCI_MEMORY_ADDRESS_BYTE0 0x600
+#define MCI_REGISTER_DATA_BYTE0 0x800
+#define MCI_REGISTER_DATA_BYTE1 0x900
+#define MCI_REGISTER_DATA_BYTE2 0xA00
+#define MCI_REGISTER_DATA_BYTE3 0xB00
+#define MCI_REGISTER_ADDRESS_BYTE0 0xC00
+#define MCI_REGISTER_ADDRESS_BYTE1 0xD00
+#define MCI_REGISTER_MODE 0xE00
+
+/* Read and write modes */
+#define MCI_MODE_REGISTER_READ 0
+#define MCI_MODE_REGISTER_WRITE 1
+#define MCI_MODE_MEMORY_READ 0
+#define MCI_MODE_MEMORY_WRITE 0x40
+
+/*** Bit definitions for MC417_CTL register ****
+ bits 31-6 bits 5-4 bit 3 bits 2-1 Bit 0
++--------+-------------+--------+--------------+------------+
+|Reserved|MC417_SPD_CTL|Reserved|MC417_GPIO_SEL|UART_GPIO_EN|
++--------+-------------+--------+--------------+------------+
+***/
+#define MC417_SPD_CTL(x) (((x) << 4) & 0x00000030)
+#define MC417_GPIO_SEL(x) (((x) << 1) & 0x00000006)
+#define MC417_UART_GPIO_EN 0x00000001
+
+/* Values for speed control */
+#define MC417_SPD_CTL_SLOW 0x1
+#define MC417_SPD_CTL_MEDIUM 0x0
+#define MC417_SPD_CTL_FAST 0x3 /* b'1x, but we use b'11 */
+
+/* Values for GPIO select */
+#define MC417_GPIO_SEL_GPIO3 0x3
+#define MC417_GPIO_SEL_GPIO2 0x2
+#define MC417_GPIO_SEL_GPIO1 0x1
+#define MC417_GPIO_SEL_GPIO0 0x0
+
+void cx23885_mc417_init(struct cx23885_dev *dev)
+{
+ u32 regval;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Configure MC417_CTL register to defaults. */
+ regval = MC417_SPD_CTL(MC417_SPD_CTL_FAST) |
+ MC417_GPIO_SEL(MC417_GPIO_SEL_GPIO3) |
+ MC417_UART_GPIO_EN;
+ cx_write(MC417_CTL, regval);
+
+ /* Configure MC417_OEN to defaults. */
+ regval = MC417_MIRDY;
+ cx_write(MC417_OEN, regval);
+
+ /* Configure MC417_RWD to defaults. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS;
+ cx_write(MC417_RWD, regval);
+}
+
+static int mc417_wait_ready(struct cx23885_dev *dev)
+{
+ u32 mi_ready;
+ unsigned long timeout = jiffies + msecs_to_jiffies(1);
+
+ for (;;) {
+ mi_ready = cx_read(MC417_RWD) & MC417_MIRDY;
+ if (mi_ready != 0)
+ return 0;
+ if (time_after(jiffies, timeout))
+ return -1;
+ udelay(1);
+ }
+}
+
+static int mc417_register_write(struct cx23885_dev *dev, u16 address, u32 value)
+{
+ u32 regval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0 |
+ (value & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+
+ /* Transition CS/WR to effect write transaction across bus. */
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1 |
+ ((value >> 8) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2 |
+ ((value >> 16) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3 |
+ ((value >> 24) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Indicate that this is a write. */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+ MCI_MODE_REGISTER_WRITE;
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ return mc417_wait_ready(dev);
+}
+
+static int mc417_register_read(struct cx23885_dev *dev, u16 address, u32 *value)
+{
+ int retval;
+ u32 regval;
+ u32 tempval;
+ u32 dataval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE0 |
+ ((address & 0x00FF));
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Indicate that this is a register read. */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_MODE |
+ MCI_MODE_REGISTER_READ;
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ retval = mc417_wait_ready(dev);
+
+ /* switch the DAT0-7 GPIO[10:3] to input mode */
+ cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+ /* Read data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+
+ /* Transition RD to effect read transaction across bus.
+ * Transtion 0x5000 -> 0x9000 correct (RD/RDY -> WR/RDY)?
+ * Should it be 0x9000 -> 0xF000 (also why is RDY being set, its
+ * input only...)
+ */
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+
+ /* Collect byte */
+ tempval = cx_read(MC417_RWD);
+ dataval = tempval & 0x000000FF;
+
+ /* Bring CS and RD high. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 8);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 16);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_REGISTER_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 24);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ *value = dataval;
+
+ return retval;
+}
+
+int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value)
+{
+ u32 regval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0 |
+ (value & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+
+ /* Transition CS/WR to effect write transaction across bus. */
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1 |
+ ((value >> 8) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2 |
+ ((value >> 16) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3 |
+ ((value >> 24) & 0x000000FF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+ MCI_MODE_MEMORY_WRITE | ((address >> 16) & 0x3F);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ return mc417_wait_ready(dev);
+}
+
+int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value)
+{
+ int retval;
+ u32 regval;
+ u32 tempval;
+ u32 dataval;
+
+ /* Enable MC417 GPIO outputs except for MC417_MIRDY,
+ * which is an input.
+ */
+ cx_write(MC417_OEN, MC417_MIRDY);
+
+ /* Write address byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE2 |
+ MCI_MODE_MEMORY_READ | ((address >> 16) & 0x3F);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE1 |
+ ((address >> 8) & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Write address byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_ADDRESS_BYTE0 |
+ (address & 0xFF);
+ cx_write(MC417_RWD, regval);
+ regval |= MC417_MICS | MC417_MIWR;
+ cx_write(MC417_RWD, regval);
+
+ /* Wait for the trans to complete (MC417_MIRDY asserted). */
+ retval = mc417_wait_ready(dev);
+
+ /* switch the DAT0-7 GPIO[10:3] to input mode */
+ cx_write(MC417_OEN, MC417_MIRDY | MC417_MIDATA);
+
+ /* Read data byte 3 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+
+ /* Transition RD to effect read transaction across bus. */
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE3;
+ cx_write(MC417_RWD, regval);
+
+ /* Collect byte */
+ tempval = cx_read(MC417_RWD);
+ dataval = ((tempval & 0x000000FF) << 24);
+
+ /* Bring CS and RD high. */
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 2 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE2;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 16);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 1 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE1;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= ((tempval & 0x000000FF) << 8);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ /* Read data byte 0 */
+ regval = MC417_MIRD | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+ regval = MC417_MIWR | MC417_MIRDY | MCI_MEMORY_DATA_BYTE0;
+ cx_write(MC417_RWD, regval);
+ tempval = cx_read(MC417_RWD);
+ dataval |= (tempval & 0x000000FF);
+ regval = MC417_MIWR | MC417_MIRD | MC417_MICS | MC417_MIRDY;
+ cx_write(MC417_RWD, regval);
+
+ *value = dataval;
+
+ return retval;
+}
+
+/* ------------------------------------------------------------------ */
+
+/* MPEG encoder API */
+char *cmd_to_str(int cmd)
+{
+ switch (cmd) {
+ case CX2341X_ENC_PING_FW:
+ return "PING_FW";
+ case CX2341X_ENC_START_CAPTURE:
+ return "START_CAPTURE";
+ case CX2341X_ENC_STOP_CAPTURE:
+ return "STOP_CAPTURE";
+ case CX2341X_ENC_SET_AUDIO_ID:
+ return "SET_AUDIO_ID";
+ case CX2341X_ENC_SET_VIDEO_ID:
+ return "SET_VIDEO_ID";
+ case CX2341X_ENC_SET_PCR_ID:
+ return "SET_PCR_PID";
+ case CX2341X_ENC_SET_FRAME_RATE:
+ return "SET_FRAME_RATE";
+ case CX2341X_ENC_SET_FRAME_SIZE:
+ return "SET_FRAME_SIZE";
+ case CX2341X_ENC_SET_BIT_RATE:
+ return "SET_BIT_RATE";
+ case CX2341X_ENC_SET_GOP_PROPERTIES:
+ return "SET_GOP_PROPERTIES";
+ case CX2341X_ENC_SET_ASPECT_RATIO:
+ return "SET_ASPECT_RATIO";
+ case CX2341X_ENC_SET_DNR_FILTER_MODE:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_DNR_FILTER_PROPS:
+ return "SET_DNR_FILTER_PROPS";
+ case CX2341X_ENC_SET_CORING_LEVELS:
+ return "SET_CORING_LEVELS";
+ case CX2341X_ENC_SET_SPATIAL_FILTER_TYPE:
+ return "SET_SPATIAL_FILTER_TYPE";
+ case CX2341X_ENC_SET_VBI_LINE:
+ return "SET_VBI_LINE";
+ case CX2341X_ENC_SET_STREAM_TYPE:
+ return "SET_STREAM_TYPE";
+ case CX2341X_ENC_SET_OUTPUT_PORT:
+ return "SET_OUTPUT_PORT";
+ case CX2341X_ENC_SET_AUDIO_PROPERTIES:
+ return "SET_AUDIO_PROPERTIES";
+ case CX2341X_ENC_HALT_FW:
+ return "HALT_FW";
+ case CX2341X_ENC_GET_VERSION:
+ return "GET_VERSION";
+ case CX2341X_ENC_SET_GOP_CLOSURE:
+ return "SET_GOP_CLOSURE";
+ case CX2341X_ENC_GET_SEQ_END:
+ return "GET_SEQ_END";
+ case CX2341X_ENC_SET_PGM_INDEX_INFO:
+ return "SET_PGM_INDEX_INFO";
+ case CX2341X_ENC_SET_VBI_CONFIG:
+ return "SET_VBI_CONFIG";
+ case CX2341X_ENC_SET_DMA_BLOCK_SIZE:
+ return "SET_DMA_BLOCK_SIZE";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_10:
+ return "GET_PREV_DMA_INFO_MB_10";
+ case CX2341X_ENC_GET_PREV_DMA_INFO_MB_9:
+ return "GET_PREV_DMA_INFO_MB_9";
+ case CX2341X_ENC_SCHED_DMA_TO_HOST:
+ return "SCHED_DMA_TO_HOST";
+ case CX2341X_ENC_INITIALIZE_INPUT:
+ return "INITIALIZE_INPUT";
+ case CX2341X_ENC_SET_FRAME_DROP_RATE:
+ return "SET_FRAME_DROP_RATE";
+ case CX2341X_ENC_PAUSE_ENCODER:
+ return "PAUSE_ENCODER";
+ case CX2341X_ENC_REFRESH_INPUT:
+ return "REFRESH_INPUT";
+ case CX2341X_ENC_SET_COPYRIGHT:
+ return "SET_COPYRIGHT";
+ case CX2341X_ENC_SET_EVENT_NOTIFICATION:
+ return "SET_EVENT_NOTIFICATION";
+ case CX2341X_ENC_SET_NUM_VSYNC_LINES:
+ return "SET_NUM_VSYNC_LINES";
+ case CX2341X_ENC_SET_PLACEHOLDER:
+ return "SET_PLACEHOLDER";
+ case CX2341X_ENC_MUTE_VIDEO:
+ return "MUTE_VIDEO";
+ case CX2341X_ENC_MUTE_AUDIO:
+ return "MUTE_AUDIO";
+ case CX2341X_ENC_MISC:
+ return "MISC";
+ default:
+ return "UNKNOWN";
+ }
+}
+
+static int cx23885_mbox_func(void *priv,
+ u32 command,
+ int in,
+ int out,
+ u32 data[CX2341X_MBOX_MAX_DATA])
+{
+ struct cx23885_dev *dev = priv;
+ unsigned long timeout;
+ u32 value, flag, retval = 0;
+ int i;
+
+ dprintk(3, "%s: command(0x%X) = %s\n", __func__, command,
+ cmd_to_str(command));
+
+ /* this may not be 100% safe if we can't read any memory location
+ without side effects */
+ mc417_memory_read(dev, dev->cx23417_mailbox - 4, &value);
+ if (value != 0x12345678) {
+ printk(KERN_ERR
+ "Firmware and/or mailbox pointer not initialized "
+ "or corrupted, signature = 0x%x, cmd = %s\n", value,
+ cmd_to_str(command));
+ return -1;
+ }
+
+ /* This read looks at 32 bits, but flag is only 8 bits.
+ * Seems we also bail if CMD or TIMEOUT bytes are set???
+ */
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (flag) {
+ printk(KERN_ERR "ERROR: Mailbox appears to be in use "
+ "(%x), cmd = %s\n", flag, cmd_to_str(command));
+ return -1;
+ }
+
+ flag |= 1; /* tell 'em we're working on it */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* write command + args + fill remaining with zeros */
+ /* command code */
+ mc417_memory_write(dev, dev->cx23417_mailbox + 1, command);
+ mc417_memory_write(dev, dev->cx23417_mailbox + 3,
+ IVTV_API_STD_TIMEOUT); /* timeout */
+ for (i = 0; i < in; i++) {
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, data[i]);
+ dprintk(3, "API Input %d = %d\n", i, data[i]);
+ }
+ for (; i < CX2341X_MBOX_MAX_DATA; i++)
+ mc417_memory_write(dev, dev->cx23417_mailbox + 4 + i, 0);
+
+ flag |= 3; /* tell 'em we're done writing */
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ /* wait for firmware to handle the API command */
+ timeout = jiffies + msecs_to_jiffies(10);
+ for (;;) {
+ mc417_memory_read(dev, dev->cx23417_mailbox, &flag);
+ if (0 != (flag & 4))
+ break;
+ if (time_after(jiffies, timeout)) {
+ printk(KERN_ERR "ERROR: API Mailbox timeout\n");
+ return -1;
+ }
+ udelay(10);
+ }
+
+ /* read output values */
+ for (i = 0; i < out; i++) {
+ mc417_memory_read(dev, dev->cx23417_mailbox + 4 + i, data + i);
+ dprintk(3, "API Output %d = %d\n", i, data[i]);
+ }
+
+ mc417_memory_read(dev, dev->cx23417_mailbox + 2, &retval);
+ dprintk(3, "API result = %d\n", retval);
+
+ flag = 0;
+ mc417_memory_write(dev, dev->cx23417_mailbox, flag);
+
+ return retval;
+}
+
+/* We don't need to call the API often, so using just one
+ * mailbox will probably suffice
+ */
+static int cx23885_api_cmd(struct cx23885_dev *dev,
+ u32 command,
+ u32 inputcnt,
+ u32 outputcnt,
+ ...)
+{
+ u32 data[CX2341X_MBOX_MAX_DATA];
+ va_list vargs;
+ int i, err;
+
+ dprintk(3, "%s() cmds = 0x%08x\n", __func__, command);
+
+ va_start(vargs, outputcnt);
+ for (i = 0; i < inputcnt; i++)
+ data[i] = va_arg(vargs, int);
+
+ err = cx23885_mbox_func(dev, command, inputcnt, outputcnt, data);
+ for (i = 0; i < outputcnt; i++) {
+ int *vptr = va_arg(vargs, int *);
+ *vptr = data[i];
+ }
+ va_end(vargs);
+
+ return err;
+}
+
+static int cx23885_find_mailbox(struct cx23885_dev *dev)
+{
+ u32 signature[4] = {
+ 0x12345678, 0x34567812, 0x56781234, 0x78123456
+ };
+ int signaturecnt = 0;
+ u32 value;
+ int i;
+
+ dprintk(2, "%s()\n", __func__);
+
+ for (i = 0; i < CX23885_FIRM_IMAGE_SIZE; i++) {
+ mc417_memory_read(dev, i, &value);
+ if (value == signature[signaturecnt])
+ signaturecnt++;
+ else
+ signaturecnt = 0;
+ if (4 == signaturecnt) {
+ dprintk(1, "Mailbox signature found at 0x%x\n", i+1);
+ return i+1;
+ }
+ }
+ printk(KERN_ERR "Mailbox signature values not found!\n");
+ return -1;
+}
+
+static int cx23885_load_firmware(struct cx23885_dev *dev)
+{
+ static const unsigned char magic[8] = {
+ 0xa7, 0x0d, 0x00, 0x00, 0x66, 0xbb, 0x55, 0xaa
+ };
+ const struct firmware *firmware;
+ int i, retval = 0;
+ u32 value = 0;
+ u32 gpio_output = 0;
+ u32 checksum = 0;
+ u32 *dataptr;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Save GPIO settings before reset of APU */
+ retval |= mc417_memory_read(dev, 0x9020, &gpio_output);
+ retval |= mc417_memory_read(dev, 0x900C, &value);
+
+ retval = mc417_register_write(dev,
+ IVTV_REG_VPU, 0xFFFFFFED);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_HW_BLOCKS, IVTV_CMD_HW_BLOCKS_RST);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_REFRESH, 0x80000800);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_ENC_SDRAM_PRECHARGE, 0x1A);
+ retval |= mc417_register_write(dev,
+ IVTV_REG_APU, 0);
+
+ if (retval != 0) {
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return -1;
+ }
+
+ retval = request_firmware(&firmware, CX23885_FIRM_IMAGE_NAME,
+ &dev->pci->dev);
+
+ if (retval != 0) {
+ printk(KERN_ERR
+ "ERROR: Hotplug firmware request failed (%s).\n",
+ CX2341X_FIRM_ENC_FILENAME);
+ printk(KERN_ERR "Please fix your hotplug setup, the board will "
+ "not work without firmware loaded!\n");
+ return -1;
+ }
+
+ if (firmware->size != CX23885_FIRM_IMAGE_SIZE) {
+ printk(KERN_ERR "ERROR: Firmware size mismatch "
+ "(have %zd, expected %d)\n",
+ firmware->size, CX23885_FIRM_IMAGE_SIZE);
+ release_firmware(firmware);
+ return -1;
+ }
+
+ if (0 != memcmp(firmware->data, magic, 8)) {
+ printk(KERN_ERR
+ "ERROR: Firmware magic mismatch, wrong file?\n");
+ release_firmware(firmware);
+ return -1;
+ }
+
+ /* transfer to the chip */
+ dprintk(2, "Loading firmware ...\n");
+ dataptr = (u32 *)firmware->data;
+ for (i = 0; i < (firmware->size >> 2); i++) {
+ value = *dataptr;
+ checksum += ~value;
+ if (mc417_memory_write(dev, i, value) != 0) {
+ printk(KERN_ERR "ERROR: Loading firmware failed!\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ dataptr++;
+ }
+
+ /* read back to verify with the checksum */
+ dprintk(1, "Verifying firmware ...\n");
+ for (i--; i >= 0; i--) {
+ if (mc417_memory_read(dev, i, &value) != 0) {
+ printk(KERN_ERR "ERROR: Reading firmware failed!\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ checksum -= ~value;
+ }
+ if (checksum) {
+ printk(KERN_ERR
+ "ERROR: Firmware load failed (checksum mismatch).\n");
+ release_firmware(firmware);
+ return -1;
+ }
+ release_firmware(firmware);
+ dprintk(1, "Firmware upload successful.\n");
+
+ retval |= mc417_register_write(dev, IVTV_REG_HW_BLOCKS,
+ IVTV_CMD_HW_BLOCKS_RST);
+
+ /* Restore GPIO settings, make sure EIO14 is enabled as an output. */
+ dprintk(2, "%s: GPIO output EIO 0-15 was = 0x%x\n",
+ __func__, gpio_output);
+ /* Power-up seems to have GPIOs AFU. This was causing digital side
+ * to fail at power-up. Seems GPIOs should be set to 0x10ff0411 at
+ * power-up.
+ * gpio_output |= (1<<14);
+ */
+ /* Note: GPIO14 is specific to the HVR1800 here */
+ gpio_output = 0x10ff0411 | (1<<14);
+ retval |= mc417_register_write(dev, 0x9020, gpio_output | (1<<14));
+ dprintk(2, "%s: GPIO output EIO 0-15 now = 0x%x\n",
+ __func__, gpio_output);
+
+ dprintk(1, "%s: GPIO value EIO 0-15 was = 0x%x\n",
+ __func__, value);
+ value |= (1<<14);
+ dprintk(1, "%s: GPIO value EIO 0-15 now = 0x%x\n",
+ __func__, value);
+ retval |= mc417_register_write(dev, 0x900C, value);
+
+ retval |= mc417_register_read(dev, IVTV_REG_VPU, &value);
+ retval |= mc417_register_write(dev, IVTV_REG_VPU, value & 0xFFFFFFE8);
+
+ if (retval < 0)
+ printk(KERN_ERR "%s: Error with mc417_register_write\n",
+ __func__);
+ return 0;
+}
+
+void cx23885_417_check_encoder(struct cx23885_dev *dev)
+{
+ u32 status, seq;
+
+ status = seq = 0;
+ cx23885_api_cmd(dev, CX2341X_ENC_GET_SEQ_END, 0, 2, &status, &seq);
+ dprintk(1, "%s() status = %d, seq = %d\n", __func__, status, seq);
+}
+
+static void cx23885_codec_settings(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ /* assign frame size */
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_FRAME_SIZE, 2, 0,
+ dev->ts1.height, dev->ts1.width);
+
+ dev->mpeg_params.width = dev->ts1.width;
+ dev->mpeg_params.height = dev->ts1.height;
+ dev->mpeg_params.is_50hz =
+ (dev->encodernorm.id & V4L2_STD_625_50) != 0;
+
+ cx2341x_update(dev, cx23885_mbox_func, NULL, &dev->mpeg_params);
+
+ cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 3, 1);
+ cx23885_api_cmd(dev, CX2341X_ENC_MISC, 2, 0, 4, 1);
+}
+
+static int cx23885_initialize_codec(struct cx23885_dev *dev)
+{
+ int version;
+ int retval;
+ u32 i, data[7];
+
+ dprintk(1, "%s()\n", __func__);
+
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0); /* ping */
+ if (retval < 0) {
+ dprintk(2, "%s() PING OK\n", __func__);
+ retval = cx23885_load_firmware(dev);
+ if (retval < 0) {
+ printk(KERN_ERR "%s() f/w load failed\n", __func__);
+ return retval;
+ }
+ dev->cx23417_mailbox = cx23885_find_mailbox(dev);
+ if (dev->cx23417_mailbox < 0) {
+ printk(KERN_ERR "%s() mailbox < 0, error\n",
+ __func__);
+ return -1;
+ }
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_PING_FW, 0, 0);
+ if (retval < 0) {
+ printk(KERN_ERR
+ "ERROR: cx23417 firmware ping failed!\n");
+ return -1;
+ }
+ retval = cx23885_api_cmd(dev, CX2341X_ENC_GET_VERSION, 0, 1,
+ &version);
+ if (retval < 0) {
+ printk(KERN_ERR "ERROR: cx23417 firmware get encoder :"
+ "version failed!\n");
+ return -1;
+ }
+ dprintk(1, "cx23417 firmware version is 0x%08x\n", version);
+ msleep(200);
+ }
+
+ cx23885_codec_settings(dev);
+ msleep(60);
+
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_NUM_VSYNC_LINES, 2, 0,
+ CX23885_FIELD1_SAA7115, CX23885_FIELD2_SAA7115);
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_PLACEHOLDER, 12, 0,
+ CX23885_CUSTOM_EXTENSION_USR_DATA, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0);
+
+ /* Setup to capture VBI */
+ data[0] = 0x0001BD00;
+ data[1] = 1; /* frames per interrupt */
+ data[2] = 4; /* total bufs */
+ data[3] = 0x91559155; /* start codes */
+ data[4] = 0x206080C0; /* stop codes */
+ data[5] = 6; /* lines */
+ data[6] = 64; /* BPL */
+
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_CONFIG, 7, 0, data[0], data[1],
+ data[2], data[3], data[4], data[5], data[6]);
+
+ for (i = 2; i <= 24; i++) {
+ int valid;
+
+ valid = ((i >= 19) && (i <= 21));
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0, i,
+ valid, 0 , 0, 0);
+ cx23885_api_cmd(dev, CX2341X_ENC_SET_VBI_LINE, 5, 0,
+ i | 0x80000000, valid, 0, 0, 0);
+ }
+
+ cx23885_api_cmd(dev, CX2341X_ENC_MUTE_AUDIO, 1, 0, CX23885_UNMUTE);
+ msleep(60);
+
+ /* initialize the video input */
+ cx23885_api_cmd(dev, CX2341X_ENC_INITIALIZE_INPUT, 0, 0);
+ msleep(60);
+
+ /* Enable VIP style pixel invalidation so we work with scaled mode */
+ mc417_memory_write(dev, 2120, 0x00000080);
+
+ /* start capturing to the host interface */
+ cx23885_api_cmd(dev, CX2341X_ENC_START_CAPTURE, 2, 0,
+ CX23885_MPEG_CAPTURE, CX23885_RAW_BITS_NONE);
+ msleep(10);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+static int bb_buf_setup(struct videobuf_queue *q,
+ unsigned int *count, unsigned int *size)
+{
+ struct cx23885_fh *fh = q->priv_data;
+
+ fh->dev->ts1.ts_packet_size = mpeglinesize;
+ fh->dev->ts1.ts_packet_count = mpeglines;
+
+ *size = fh->dev->ts1.ts_packet_size * fh->dev->ts1.ts_packet_count;
+ *count = mpegbufs;
+
+ return 0;
+}
+
+static int bb_buf_prepare(struct videobuf_queue *q,
+ struct videobuf_buffer *vb, enum v4l2_field field)
+{
+ struct cx23885_fh *fh = q->priv_data;
+ return cx23885_buf_prepare(q, &fh->dev->ts1,
+ (struct cx23885_buffer *)vb,
+ field);
+}
+
+static void bb_buf_queue(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ struct cx23885_fh *fh = q->priv_data;
+ cx23885_buf_queue(&fh->dev->ts1, (struct cx23885_buffer *)vb);
+}
+
+static void bb_buf_release(struct videobuf_queue *q,
+ struct videobuf_buffer *vb)
+{
+ cx23885_free_buffer(q, (struct cx23885_buffer *)vb);
+}
+
+static struct videobuf_queue_ops cx23885_qops = {
+ .buf_setup = bb_buf_setup,
+ .buf_prepare = bb_buf_prepare,
+ .buf_queue = bb_buf_queue,
+ .buf_release = bb_buf_release,
+};
+
+/* ------------------------------------------------------------------ */
+
+static const u32 *ctrl_classes[] = {
+ cx2341x_mpeg_ctrls,
+ NULL
+};
+
+static int cx23885_queryctrl(struct cx23885_dev *dev,
+ struct v4l2_queryctrl *qctrl)
+{
+ qctrl->id = v4l2_ctrl_next(ctrl_classes, qctrl->id);
+ if (qctrl->id == 0)
+ return -EINVAL;
+
+ /* MPEG V4L2 controls */
+ if (cx2341x_ctrl_query(&dev->mpeg_params, qctrl))
+ qctrl->flags |= V4L2_CTRL_FLAG_DISABLED;
+
+ return 0;
+}
+
+static int cx23885_querymenu(struct cx23885_dev *dev,
+ struct v4l2_querymenu *qmenu)
+{
+ struct v4l2_queryctrl qctrl;
+
+ qctrl.id = qmenu->id;
+ cx23885_queryctrl(dev, &qctrl);
+ return v4l2_ctrl_query_menu(qmenu, &qctrl,
+ cx2341x_ctrl_get_menu(qmenu->id));
+}
+
+int cx23885_do_ioctl(struct inode *inode, struct file *file, int radio,
+ struct cx23885_dev *dev, unsigned int cmd, void *arg,
+ v4l2_kioctl driver_ioctl)
+{
+ int err;
+
+ switch (cmd) {
+ /* ---------- tv norms ---------- */
+ case VIDIOC_ENUMSTD:
+ {
+ struct v4l2_standard *e = arg;
+ unsigned int i;
+
+ i = e->index;
+ if (i >= ARRAY_SIZE(cx23885_tvnorms))
+ return -EINVAL;
+ err = v4l2_video_std_construct(e,
+ cx23885_tvnorms[e->index].id,
+ cx23885_tvnorms[e->index].name);
+ e->index = i;
+ if (err < 0)
+ return err;
+ return 0;
+ }
+ case VIDIOC_G_STD:
+ {
+ v4l2_std_id *id = arg;
+
+ *id = dev->encodernorm.id;
+ return 0;
+ }
+ case VIDIOC_S_STD:
+ {
+ v4l2_std_id *id = arg;
+ unsigned int i;
+
+ for (i = 0; i < ARRAY_SIZE(cx23885_tvnorms); i++)
+ if (*id & cx23885_tvnorms[i].id)
+ break;
+ if (i == ARRAY_SIZE(cx23885_tvnorms))
+ return -EINVAL;
+ dev->encodernorm = cx23885_tvnorms[i];
+
+ return 0;
+ }
+
+ /* ------ input switching ---------- */
+ case VIDIOC_ENUMINPUT:
+ {
+ struct cx23885_input *input;
+ struct v4l2_input *i = arg;
+ unsigned int n;
+
+ n = i->index;
+ if (n >= 4)
+ return -EINVAL;
+ input = &cx23885_boards[dev->board].input[n];
+ if (input->type == 0)
+ return -EINVAL;
+ memset(i, 0, sizeof(*i));
+ i->index = n;
+ /* FIXME
+ * strcpy(i->name, input->name); */
+ strcpy(i->name, "unset");
+ if (input->type == CX23885_VMUX_TELEVISION ||
+ input->type == CX23885_VMUX_CABLE)
+ i->type = V4L2_INPUT_TYPE_TUNER;
+ else
+ i->type = V4L2_INPUT_TYPE_CAMERA;
+
+ for (n = 0; n < ARRAY_SIZE(cx23885_tvnorms); n++)
+ i->std |= cx23885_tvnorms[n].id;
+ return 0;
+ }
+ case VIDIOC_G_INPUT:
+ {
+ unsigned int *i = arg;
+
+ *i = dev->input;
+ return 0;
+ }
+ case VIDIOC_S_INPUT:
+ {
+ unsigned int *i = arg;
+
+ if (*i >= 4)
+ return -EINVAL;
+
+ return 0;
+ }
+
+ /* --- tuner ioctls ------------------------------------------ */
+ case VIDIOC_G_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (0 != t->index)
+ return -EINVAL;
+ memset(t, 0, sizeof(*t));
+ strcpy(t->name, "Television");
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_TUNER, t);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_G_TUNER, t);
+
+ dprintk(1, "VIDIOC_G_TUNER: tuner type %d\n", t->type);
+
+ return 0;
+ }
+ case VIDIOC_S_TUNER:
+ {
+ struct v4l2_tuner *t = arg;
+
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+
+ /* Update the A/V core */
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_TUNER, t);
+
+ return 0;
+ }
+ case VIDIOC_G_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ memset(f, 0, sizeof(*f));
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ f->type = V4L2_TUNER_ANALOG_TV;
+ f->frequency = dev->freq;
+
+ /* Assumption that tuner is always on bus 1 */
+ cx23885_call_i2c_clients(&dev->i2c_bus[1],
+ VIDIOC_G_FREQUENCY, f);
+
+ return 0;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ struct v4l2_frequency *f = arg;
+
+ dprintk(1, "VIDIOC_S_FREQUENCY: dev type %d, f\n",
+ dev->tuner_type);
+ dprintk(1, "VIDIOC_S_FREQUENCY: f tuner %d, f type %d\n",
+ f->tuner, f->type);
+ if (UNSET == dev->tuner_type)
+ return -EINVAL;
+ if (f->tuner != 0)
+ return -EINVAL;
+ if (f->type != V4L2_TUNER_ANALOG_TV)
+ return -EINVAL;
+ dev->freq = f->frequency;
+
+ /* Assumption that tuner is always on bus 1 */
+ cx23885_call_i2c_clients(&dev->i2c_bus[1],
+ VIDIOC_S_FREQUENCY, f);
+ return 0;
+ }
+ case VIDIOC_S_CTRL:
+ {
+ /* Update the A/V core */
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_CTRL, arg);
+ return 0;
+ }
+ default:
+ /* Convert V4L ioctl to V4L2 and call mpeg_do_ioctl
+ * (driver_ioctl) */
+ return v4l_compat_translate_ioctl(inode, file, cmd, arg,
+ driver_ioctl);
+ }
+
+ return 0;
+}
+
+static int mpeg_do_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, void *arg)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+ struct cx23885_tsport *tsport = &dev->ts1;
+
+ if (v4l_debug > 1)
+ v4l_print_ioctl(dev->name, cmd);
+
+ switch (cmd) {
+
+ /* --- capabilities ------------------------------------------ */
+ case VIDIOC_QUERYCAP:
+ {
+ struct v4l2_capability *cap = arg;
+
+ memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, dev->name);
+ strlcpy(cap->card, cx23885_boards[tsport->dev->board].name,
+ sizeof(cap->card));
+ sprintf(cap->bus_info, "PCI:%s", pci_name(dev->pci));
+ cap->version = CX23885_VERSION_CODE;
+ cap->capabilities =
+ V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_READWRITE |
+ V4L2_CAP_STREAMING |
+ 0;
+ if (UNSET != dev->tuner_type)
+ cap->capabilities |= V4L2_CAP_TUNER;
+
+ return 0;
+ }
+
+ /* --- capture ioctls ---------------------------------------- */
+ case VIDIOC_ENUM_FMT:
+ {
+ struct v4l2_fmtdesc *f = arg;
+ int index;
+
+ index = f->index;
+ if (index != 0)
+ return -EINVAL;
+
+ memset(f, 0, sizeof(*f));
+ f->index = index;
+ strlcpy(f->description, "MPEG", sizeof(f->description));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->pixelformat = V4L2_PIX_FMT_MPEG;
+ return 0;
+ }
+ case VIDIOC_G_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ memset(f, 0, sizeof(*f));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.width = dev->ts1.width;
+ f->fmt.pix.height = dev->ts1.height;
+ f->fmt.pix.field = fh->mpegq.field;
+ dprintk(1, "VIDIOC_G_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ return 0;
+ }
+ case VIDIOC_TRY_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.sizeimage =
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_TRY_FMT: w: %d, h: %d, f: %d\n",
+ dev->ts1.width, dev->ts1.height, fh->mpegq.field);
+ return 0;
+ }
+ case VIDIOC_S_FMT:
+ {
+ struct v4l2_format *f = arg;
+
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MPEG;
+ f->fmt.pix.bytesperline = 0;
+ f->fmt.pix.sizeimage =
+ dev->ts1.ts_packet_size * dev->ts1.ts_packet_count;
+ f->fmt.pix.colorspace = 0;
+ dprintk(1, "VIDIOC_S_FMT: w: %d, h: %d, f: %d\n",
+ f->fmt.pix.width, f->fmt.pix.height, f->fmt.pix.field);
+ return 0;
+ }
+
+ /* --- streaming capture ------------------------------------- */
+ case VIDIOC_REQBUFS:
+ return videobuf_reqbufs(&fh->mpegq, arg);
+
+ case VIDIOC_QUERYBUF:
+ return videobuf_querybuf(&fh->mpegq, arg);
+
+ case VIDIOC_QBUF:
+ return videobuf_qbuf(&fh->mpegq, arg);
+
+ case VIDIOC_DQBUF:
+ return videobuf_dqbuf(&fh->mpegq, arg,
+ file->f_flags & O_NONBLOCK);
+
+ case VIDIOC_STREAMON:
+ return videobuf_streamon(&fh->mpegq);
+
+ case VIDIOC_STREAMOFF:
+ return videobuf_streamoff(&fh->mpegq);
+
+ case VIDIOC_G_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *f = arg;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ return cx2341x_ext_ctrls(&dev->mpeg_params, 0, f, cmd);
+ }
+ case VIDIOC_S_EXT_CTRLS:
+ case VIDIOC_TRY_EXT_CTRLS:
+ {
+ struct v4l2_ext_controls *f = arg;
+ struct cx2341x_mpeg_params p;
+ int err;
+
+ if (f->ctrl_class != V4L2_CTRL_CLASS_MPEG)
+ return -EINVAL;
+ p = dev->mpeg_params;
+ err = cx2341x_ext_ctrls(&p, 0, f, cmd);
+ if (err == 0 && cmd == VIDIOC_S_EXT_CTRLS) {
+ err = cx2341x_update(dev, cx23885_mbox_func,
+ &dev->mpeg_params, &p);
+ dev->mpeg_params = p;
+ }
+ return err;
+ }
+ case VIDIOC_S_FREQUENCY:
+ {
+ cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+ CX23885_RAW_BITS_NONE);
+ cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
+ mpeg_do_ioctl);
+ cx23885_initialize_codec(dev);
+
+ return 0;
+ }
+ case VIDIOC_LOG_STATUS:
+ {
+ char name[32 + 2];
+
+ snprintf(name, sizeof(name), "%s/2", dev->name);
+ printk(KERN_INFO
+ "%s/2: ============ START LOG STATUS ============\n",
+ dev->name);
+ cx23885_call_i2c_clients(&dev->i2c_bus[0], VIDIOC_LOG_STATUS,
+ NULL);
+ cx23885_call_i2c_clients(&dev->i2c_bus[1], VIDIOC_LOG_STATUS,
+ NULL);
+ cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_LOG_STATUS,
+ NULL);
+ cx2341x_log_status(&dev->mpeg_params, name);
+ printk(KERN_INFO
+ "%s/2: ============= END LOG STATUS =============\n",
+ dev->name);
+ return 0;
+ }
+ case VIDIOC_QUERYMENU:
+ return cx23885_querymenu(dev, arg);
+ case VIDIOC_QUERYCTRL:
+ {
+ struct v4l2_queryctrl *c = arg;
+
+ return cx23885_queryctrl(dev, c);
+ }
+
+ default:
+ return cx23885_do_ioctl(inode, file, 0, dev, cmd, arg,
+ mpeg_do_ioctl);
+ }
+ return 0;
+}
+
+static int mpeg_ioctl(struct inode *inode, struct file *file,
+ unsigned int cmd, unsigned long arg)
+{
+ return video_usercopy(inode, file, cmd, arg, mpeg_do_ioctl);
+}
+
+static int mpeg_open(struct inode *inode, struct file *file)
+{
+ int minor = iminor(inode);
+ struct cx23885_dev *h, *dev = NULL;
+ struct list_head *list;
+ struct cx23885_fh *fh;
+
+ dprintk(2, "%s()\n", __func__);
+
+ list_for_each(list, &cx23885_devlist) {
+ h = list_entry(list, struct cx23885_dev, devlist);
+ if (h->v4l_device->minor == minor) {
+ dev = h;
+ break;
+ }
+ }
+
+ if (dev == NULL)
+ return -ENODEV;
+
+ /* allocate + initialize per filehandle data */
+ fh = kzalloc(sizeof(*fh), GFP_KERNEL);
+ if (NULL == fh)
+ return -ENOMEM;
+
+ file->private_data = fh;
+ fh->dev = dev;
+
+ videobuf_queue_sg_init(&fh->mpegq, &cx23885_qops,
+ &dev->pci->dev, &dev->ts1.slock,
+ V4L2_BUF_TYPE_VIDEO_CAPTURE,
+ V4L2_FIELD_INTERLACED,
+ sizeof(struct cx23885_buffer),
+ fh);
+
+ return 0;
+}
+
+static int mpeg_release(struct inode *inode, struct file *file)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* FIXME: Review this crap */
+ /* Shut device down on last close */
+ if (atomic_cmpxchg(&fh->v4l_reading, 1, 0) == 1) {
+ if (atomic_dec_return(&dev->v4l_reader_count) == 0) {
+ /* stop mpeg capture */
+ cx23885_api_cmd(fh->dev, CX2341X_ENC_STOP_CAPTURE, 3, 0,
+ CX23885_END_NOW, CX23885_MPEG_CAPTURE,
+ CX23885_RAW_BITS_NONE);
+
+ msleep(500);
+ cx23885_417_check_encoder(dev);
+
+ cx23885_cancel_buffers(&fh->dev->ts1);
+ }
+ }
+
+ if (fh->mpegq.streaming)
+ videobuf_streamoff(&fh->mpegq);
+ if (fh->mpegq.reading)
+ videobuf_read_stop(&fh->mpegq);
+
+ videobuf_mmap_free(&fh->mpegq);
+ file->private_data = NULL;
+ kfree(fh);
+
+ return 0;
+}
+
+static ssize_t mpeg_read(struct file *file, char __user *data,
+ size_t count, loff_t *ppos)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ /* Deal w/ A/V decoder * and mpeg encoder sync issues. */
+ /* Start mpeg encoder on first read. */
+ if (atomic_cmpxchg(&fh->v4l_reading, 0, 1) == 0) {
+ if (atomic_inc_return(&dev->v4l_reader_count) == 1) {
+ if (cx23885_initialize_codec(dev) < 0)
+ return -EINVAL;
+ }
+ }
+
+ return videobuf_read_stream(&fh->mpegq, data, count, ppos, 0,
+ file->f_flags & O_NONBLOCK);
+}
+
+static unsigned int mpeg_poll(struct file *file,
+ struct poll_table_struct *wait)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s\n", __func__);
+
+ return videobuf_poll_stream(file, &fh->mpegq, wait);
+}
+
+static int mpeg_mmap(struct file *file, struct vm_area_struct *vma)
+{
+ struct cx23885_fh *fh = file->private_data;
+ struct cx23885_dev *dev = fh->dev;
+
+ dprintk(2, "%s()\n", __func__);
+
+ return videobuf_mmap_mapper(&fh->mpegq, vma);
+}
+
+static struct file_operations mpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = mpeg_open,
+ .release = mpeg_release,
+ .read = mpeg_read,
+ .poll = mpeg_poll,
+ .mmap = mpeg_mmap,
+ .ioctl = mpeg_ioctl,
+ .llseek = no_llseek,
+};
+
+static struct video_device cx23885_mpeg_template = {
+ .name = "cx23885",
+ .type = VID_TYPE_CAPTURE |
+ VID_TYPE_TUNER |
+ VID_TYPE_SCALES |
+ VID_TYPE_MPEG_ENCODER,
+ .fops = &mpeg_fops,
+ .minor = -1,
+};
+
+void cx23885_417_unregister(struct cx23885_dev *dev)
+{
+ dprintk(1, "%s()\n", __func__);
+
+ if (dev->v4l_device) {
+ if (-1 != dev->v4l_device->minor)
+ video_unregister_device(dev->v4l_device);
+ else
+ video_device_release(dev->v4l_device);
+ dev->v4l_device = NULL;
+ }
+}
+
+static struct video_device *cx23885_video_dev_alloc(
+ struct cx23885_tsport *tsport,
+ struct pci_dev *pci,
+ struct video_device *template,
+ char *type)
+{
+ struct video_device *vfd;
+ struct cx23885_dev *dev = tsport->dev;
+
+ dprintk(1, "%s()\n", __func__);
+
+ vfd = video_device_alloc();
+ if (NULL == vfd)
+ return NULL;
+ *vfd = *template;
+ vfd->minor = -1;
+ snprintf(vfd->name, sizeof(vfd->name), "%s %s (%s)", dev->name,
+ type, cx23885_boards[tsport->dev->board].name);
+ vfd->dev = &pci->dev;
+ vfd->release = video_device_release;
+ return vfd;
+}
+
+int cx23885_417_register(struct cx23885_dev *dev)
+{
+ /* FIXME: Port1 hardcoded here */
+ int err = -ENODEV;
+ struct cx23885_tsport *tsport = &dev->ts1;
+
+ dprintk(1, "%s()\n", __func__);
+
+ if (cx23885_boards[dev->board].portb != CX23885_MPEG_ENCODER)
+ return err;
+
+ /* Set default TV standard */
+ dev->encodernorm = cx23885_tvnorms[0];
+
+ if (dev->encodernorm.id & V4L2_STD_525_60)
+ tsport->height = 480;
+ else
+ tsport->height = 576;
+
+ tsport->width = 720;
+ cx2341x_fill_defaults(&dev->mpeg_params);
+
+ dev->mpeg_params.port = CX2341X_PORT_SERIAL;
+
+ /* Allocate and initialize V4L video device */
+ dev->v4l_device = cx23885_video_dev_alloc(tsport,
+ dev->pci, &cx23885_mpeg_template, "mpeg");
+ err = video_register_device(dev->v4l_device,
+ VFL_TYPE_GRABBER, -1);
+ if (err < 0) {
+ printk(KERN_INFO "%s: can't register mpeg device\n", dev->name);
+ return err;
+ }
+
+ /* Initialize MC417 registers */
+ cx23885_mc417_init(dev);
+
+ printk(KERN_INFO "%s: registered device video%d [mpeg]\n",
+ dev->name, dev->v4l_device->minor & 0x1f);
+
+ return 0;
+}
diff --git a/drivers/media/video/cx23885/cx23885-cards.c b/drivers/media/video/cx23885/cx23885-cards.c
index dfa269838e0..6ebf58724a0 100644
--- a/drivers/media/video/cx23885/cx23885-cards.c
+++ b/drivers/media/video/cx23885/cx23885-cards.c
@@ -73,6 +73,7 @@ struct cx23885_board cx23885_boards[] = {
[CX23885_BOARD_HAUPPAUGE_HVR1800] = {
.name = "Hauppauge WinTV-HVR1800",
.porta = CX23885_ANALOG_VIDEO,
+ .portb = CX23885_MPEG_ENCODER,
.portc = CX23885_MPEG_DVB,
.tuner_type = TUNER_PHILIPS_TDA8290,
.tuner_addr = 0x42, /* 0x84 >> 1 */
@@ -130,6 +131,18 @@ struct cx23885_board cx23885_boards[] = {
.name = "Hauppauge WinTV-HVR1500",
.portc = CX23885_MPEG_DVB,
},
+ [CX23885_BOARD_HAUPPAUGE_HVR1200] = {
+ .name = "Hauppauge WinTV-HVR1200",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1700] = {
+ .name = "Hauppauge WinTV-HVR1700",
+ .portc = CX23885_MPEG_DVB,
+ },
+ [CX23885_BOARD_HAUPPAUGE_HVR1400] = {
+ .name = "Hauppauge WinTV-HVR1400",
+ .portc = CX23885_MPEG_DVB,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -181,6 +194,18 @@ struct cx23885_subid cx23885_subids[] = {
.subvendor = 0x0070,
.subdevice = 0x7717,
.card = CX23885_BOARD_HAUPPAUGE_HVR1500,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x71d1,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1200,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8101,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1700,
+ }, {
+ .subvendor = 0x0070,
+ .subdevice = 0x8010,
+ .card = CX23885_BOARD_HAUPPAUGE_HVR1400,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -235,6 +260,12 @@ static void hauppauge_eeprom(struct cx23885_dev *dev, u8 *eeprom_data)
case 79561: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
case 79571: /* WinTV-HVR1250 (PCIe, OEM, No IR, full height, ATSC and Basic analog */
case 79671: /* WinTV-HVR1250 (PCIe, OEM, No IR, half height, ATSC and Basic analog */
+ case 80019:
+ /* WinTV-HVR1400 (Express Card, Retail, IR,
+ * DVB-T and Basic analog */
+ case 81519:
+ /* WinTV-HVR1700 (PCIe, Retail, No IR, half height,
+ * DVB-T and MPEG2 HW Encoder */
break;
default:
printk("%s: warning: unknown hauppauge model #%d\n", dev->name, tv.model);
@@ -264,7 +295,7 @@ int cx23885_tuner_callback(void *priv, int command, int arg)
}
else {
printk(KERN_ERR
- "%s(): Unknow command.\n", __FUNCTION__);
+ "%s(): Unknow command.\n", __func__);
return -EINVAL;
}
break;
@@ -306,6 +337,10 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
/* GPIO-15-18 cx23417 READY, CS, RD, WR */
/* GPIO-19 IR_RX */
+ /* CX23417 GPIO's */
+ /* EIO15 Zilog Reset */
+ /* EIO14 S5H1409/CX24227 Reset */
+
/* Force the TDA8295A into reset and back */
cx_set(GP0_IO, 0x00040004);
mdelay(20);
@@ -314,6 +349,50 @@ void cx23885_gpio_setup(struct cx23885_dev *dev)
cx_set(GP0_IO, 0x00040004);
mdelay(20);
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ /* GPIO-0 tda10048 demodulator reset */
+ /* GPIO-2 tda18271 tuner reset */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ /* GPIO-0 TDA10048 demodulator reset */
+ /* GPIO-2 TDA8295A Reset */
+ /* GPIO-3-10 cx23417 data0-7 */
+ /* GPIO-11-14 cx23417 addr0-3 */
+ /* GPIO-15-18 cx23417 READY, CS, RD, WR */
+
+ /* The following GPIO's are on the interna AVCore (cx25840) */
+ /* GPIO-19 IR_RX */
+ /* GPIO-20 IR_TX 416/DVBT Select */
+ /* GPIO-21 IIS DAT */
+ /* GPIO-22 IIS WCLK */
+ /* GPIO-23 IIS BCLK */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ /* GPIO-0 Dibcom7000p demodulator reset */
+ /* GPIO-2 xc3028L tuner reset */
+ /* GPIO-13 LED */
+
+ /* Put the parts into reset and back */
+ cx_set(GP0_IO, 0x00050000);
+ mdelay(20);
+ cx_clear(GP0_IO, 0x00000005);
+ mdelay(20);
+ cx_set(GP0_IO, 0x00050005);
+ break;
}
}
@@ -324,6 +403,8 @@ int cx23885_ir_init(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
/* FIXME: Implement me */
break;
}
@@ -348,11 +429,14 @@ void cx23885_card_setup(struct cx23885_dev *dev)
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0x80);
break;
case CX23885_BOARD_HAUPPAUGE_HVR1800:
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
if (dev->i2c_bus[0].i2c_rc == 0)
hauppauge_eeprom(dev, eeprom+0xc0);
break;
@@ -364,17 +448,45 @@ void cx23885_card_setup(struct cx23885_dev *dev)
ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ /* Defaults for VID B - Analog encoder */
+ /* DREQ_POL, SMODE, PUNC_CLK, MCLK_POL Serial bus + punc clk */
+ ts1->gen_ctrl_val = 0x10e;
+ ts1->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts1->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+
+ /* APB_TSVALERR_POL (active low)*/
+ ts1->vld_misc_val = 0x2000;
+ ts1->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4 | 0xc);
+
+ /* Defaults for VID C */
+ ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
+ ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
+ ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
+ break;
case CX23885_BOARD_HAUPPAUGE_HVR1250:
case CX23885_BOARD_HAUPPAUGE_HVR1500:
case CX23885_BOARD_HAUPPAUGE_HVR1500Q:
- case CX23885_BOARD_HAUPPAUGE_HVR1800:
case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
default:
ts2->gen_ctrl_val = 0xc; /* Serial bus + punctured clock */
ts2->ts_clk_en_val = 0x1; /* Enable TS_CLK */
ts2->src_sel_val = CX23885_SRC_SEL_PARALLEL_MPEG_VIDEO;
}
+ /* Certain boards support analog, or require the avcore to be
+ * loaded, ensure this happens.
+ */
+ switch (dev->board) {
+ case CX23885_BOARD_HAUPPAUGE_HVR1800:
+ case CX23885_BOARD_HAUPPAUGE_HVR1800lp:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ request_module("cx25840");
+ break;
+ }
}
/* ------------------------------------------------------------------ */
diff --git a/drivers/media/video/cx23885/cx23885-core.c b/drivers/media/video/cx23885/cx23885-core.c
index 7f10b273598..f24abcd06de 100644
--- a/drivers/media/video/cx23885/cx23885-core.c
+++ b/drivers/media/video/cx23885/cx23885-core.c
@@ -190,25 +190,25 @@ static struct sram_channel cx23887_sram_channels[] = {
static int cx23885_risc_decode(u32 risc)
{
static char *instr[16] = {
- [ RISC_SYNC >> 28 ] = "sync",
- [ RISC_WRITE >> 28 ] = "write",
- [ RISC_WRITEC >> 28 ] = "writec",
- [ RISC_READ >> 28 ] = "read",
- [ RISC_READC >> 28 ] = "readc",
- [ RISC_JUMP >> 28 ] = "jump",
- [ RISC_SKIP >> 28 ] = "skip",
- [ RISC_WRITERM >> 28 ] = "writerm",
- [ RISC_WRITECM >> 28 ] = "writecm",
- [ RISC_WRITECR >> 28 ] = "writecr",
+ [RISC_SYNC >> 28] = "sync",
+ [RISC_WRITE >> 28] = "write",
+ [RISC_WRITEC >> 28] = "writec",
+ [RISC_READ >> 28] = "read",
+ [RISC_READC >> 28] = "readc",
+ [RISC_JUMP >> 28] = "jump",
+ [RISC_SKIP >> 28] = "skip",
+ [RISC_WRITERM >> 28] = "writerm",
+ [RISC_WRITECM >> 28] = "writecm",
+ [RISC_WRITECR >> 28] = "writecr",
};
static int incr[16] = {
- [ RISC_WRITE >> 28 ] = 3,
- [ RISC_JUMP >> 28 ] = 3,
- [ RISC_SKIP >> 28 ] = 1,
- [ RISC_SYNC >> 28 ] = 1,
- [ RISC_WRITERM >> 28 ] = 3,
- [ RISC_WRITECM >> 28 ] = 3,
- [ RISC_WRITECR >> 28 ] = 4,
+ [RISC_WRITE >> 28] = 3,
+ [RISC_JUMP >> 28] = 3,
+ [RISC_SKIP >> 28] = 1,
+ [RISC_SYNC >> 28] = 1,
+ [RISC_WRITERM >> 28] = 3,
+ [RISC_WRITECM >> 28] = 3,
+ [RISC_WRITECR >> 28] = 4,
};
static char *bits[] = {
"12", "13", "14", "resync",
@@ -260,7 +260,7 @@ void cx23885_wakeup(struct cx23885_tsport *port,
}
if (bc != 1)
printk("%s: %d buffers handled (should be 1)\n",
- __FUNCTION__, bc);
+ __func__, bc);
}
int cx23885_sram_channel_setup(struct cx23885_dev *dev,
@@ -272,7 +272,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
if (ch->cmds_start == 0)
{
- dprintk(1, "%s() Erasing channel [%s]\n", __FUNCTION__,
+ dprintk(1, "%s() Erasing channel [%s]\n", __func__,
ch->name);
cx_write(ch->ptr1_reg, 0);
cx_write(ch->ptr2_reg, 0);
@@ -280,7 +280,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
cx_write(ch->cnt1_reg, 0);
return 0;
} else {
- dprintk(1, "%s() Configuring channel [%s]\n", __FUNCTION__,
+ dprintk(1, "%s() Configuring channel [%s]\n", __func__,
ch->name);
}
@@ -297,7 +297,7 @@ int cx23885_sram_channel_setup(struct cx23885_dev *dev,
/* write CDT */
for (i = 0; i < lines; i++) {
- dprintk(2, "%s() 0x%08x <- 0x%08x\n", __FUNCTION__, cdt + 16*i,
+ dprintk(2, "%s() 0x%08x <- 0x%08x\n", __func__, cdt + 16*i,
ch->fifo_start + bpl*i);
cx_write(cdt + 16*i, ch->fifo_start + bpl*i);
cx_write(cdt + 16*i + 4, 0);
@@ -449,7 +449,7 @@ static void cx23885_shutdown(struct cx23885_dev *dev)
static void cx23885_reset(struct cx23885_dev *dev)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
cx23885_shutdown(dev);
@@ -482,7 +482,7 @@ static void cx23885_reset(struct cx23885_dev *dev)
static int cx23885_pci_quirks(struct cx23885_dev *dev)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
/* The cx23885 bridge has a weird bug which causes NMI to be asserted
* when DMA begins if RDR_TLCTL0 bit4 is not cleared. It does not
@@ -513,11 +513,13 @@ int cx23885_risc_stopper(struct pci_dev *pci, struct btcx_riscmem *risc,
static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *port, int portno)
{
- dprintk(1, "%s(portno=%d)\n", __FUNCTION__, portno);
+ dprintk(1, "%s(portno=%d)\n", __func__, portno);
/* Transport bus init dma queue - Common settings */
port->dma_ctl_val = 0x11; /* Enable RISC controller and Fifo */
port->ts_int_msk_val = 0x1111; /* TS port bits for RISC */
+ port->vld_misc_val = 0x0;
+ port->hw_sop_ctrl_val = (0x47 << 16 | 188 << 4);
spin_lock_init(&port->slock);
port->dev = dev;
@@ -544,7 +546,7 @@ static int cx23885_init_tsport(struct cx23885_dev *dev, struct cx23885_tsport *p
port->reg_ts_clk_en = VID_B_TS_CLK_EN;
port->reg_src_sel = VID_B_SRC_SEL;
port->reg_ts_int_msk = VID_B_INT_MSK;
- port->reg_ts_int_stat = VID_B_INT_STAT;
+ port->reg_ts_int_stat = VID_B_INT_STAT;
port->sram_chno = SRAM_CH03; /* VID_B */
port->pci_irqmask = 0x02; /* VID_B bit1 */
break;
@@ -604,14 +606,14 @@ static void cx23885_dev_checkrevision(struct cx23885_dev *dev)
break;
default:
printk(KERN_ERR "%s() New hardware revision found 0x%x\n",
- __FUNCTION__, dev->hwrevision);
+ __func__, dev->hwrevision);
}
if (dev->hwrevision)
printk(KERN_INFO "%s() Hardware revision = 0x%02x\n",
- __FUNCTION__, dev->hwrevision);
+ __func__, dev->hwrevision);
else
printk(KERN_ERR "%s() Hardware revision unknown 0x%x\n",
- __FUNCTION__, dev->hwrevision);
+ __func__, dev->hwrevision);
}
static int cx23885_dev_setup(struct cx23885_dev *dev)
@@ -644,7 +646,7 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
BUG();
dprintk(1, "%s() Memory configured for PCIe bridge type %d\n",
- __FUNCTION__, dev->bridge);
+ __func__, dev->bridge);
/* board config */
dev->board = UNSET;
@@ -697,10 +699,12 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dev->i2c_bus[2].reg_wdata = I2C3_WDATA;
dev->i2c_bus[2].i2c_period = (0x07 << 24); /* 1.95MHz */
- if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ if ((cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) ||
+ (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER))
cx23885_init_tsport(dev, &dev->ts1, 1);
- if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+ if ((cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) ||
+ (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER))
cx23885_init_tsport(dev, &dev->ts2, 2);
if (get_resources(dev) < 0) {
@@ -734,9 +738,9 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
dev->radio_addr = cx23885_boards[dev->board].radio_addr;
dprintk(1, "%s() tuner_type = 0x%x tuner_addr = 0x%x\n",
- __FUNCTION__, dev->tuner_type, dev->tuner_addr);
+ __func__, dev->tuner_type, dev->tuner_addr);
dprintk(1, "%s() radio_type = 0x%x radio_addr = 0x%x\n",
- __FUNCTION__, dev->radio_type, dev->radio_addr);
+ __func__, dev->radio_type, dev->radio_addr);
/* init hardware */
cx23885_reset(dev);
@@ -744,28 +748,43 @@ static int cx23885_dev_setup(struct cx23885_dev *dev)
cx23885_i2c_register(&dev->i2c_bus[0]);
cx23885_i2c_register(&dev->i2c_bus[1]);
cx23885_i2c_register(&dev->i2c_bus[2]);
- cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
cx23885_card_setup(dev);
+ cx23885_call_i2c_clients (&dev->i2c_bus[0], TUNER_SET_STANDBY, NULL);
cx23885_ir_init(dev);
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO) {
if (cx23885_video_register(dev) < 0) {
printk(KERN_ERR "%s() Failed to register analog "
- "video adapters on VID_A\n", __FUNCTION__);
+ "video adapters on VID_A\n", __func__);
}
}
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB) {
if (cx23885_dvb_register(&dev->ts1) < 0) {
printk(KERN_ERR "%s() Failed to register dvb adapters on VID_B\n",
- __FUNCTION__);
+ __func__);
+ }
+ } else
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER) {
+ if (cx23885_417_register(dev) < 0) {
+ printk(KERN_ERR
+ "%s() Failed to register 417 on VID_B\n",
+ __func__);
}
}
if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB) {
if (cx23885_dvb_register(&dev->ts2) < 0) {
- printk(KERN_ERR "%s() Failed to register dvb adapters on VID_C\n",
- __FUNCTION__);
+ printk(KERN_ERR
+ "%s() Failed to register dvb on VID_C\n",
+ __func__);
+ }
+ } else
+ if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER) {
+ if (cx23885_417_register(dev) < 0) {
+ printk(KERN_ERR
+ "%s() Failed to register 417 on VID_C\n",
+ __func__);
}
}
@@ -785,12 +804,18 @@ static void cx23885_dev_unregister(struct cx23885_dev *dev)
if (cx23885_boards[dev->board].porta == CX23885_ANALOG_VIDEO)
cx23885_video_unregister(dev);
- if(cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
cx23885_dvb_unregister(&dev->ts1);
- if(cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ cx23885_417_unregister(dev);
+
+ if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
cx23885_dvb_unregister(&dev->ts2);
+ if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
+ cx23885_417_unregister(dev);
+
cx23885_i2c_unregister(&dev->i2c_bus[2]);
cx23885_i2c_unregister(&dev->i2c_bus[1]);
cx23885_i2c_unregister(&dev->i2c_bus[0]);
@@ -952,7 +977,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;
}
@@ -960,50 +985,50 @@ static void cx23885_tsport_reg_dump(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
- dprintk(1, "%s() Register Dump\n", __FUNCTION__);
- dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() Register Dump\n", __func__);
+ dprintk(1, "%s() DEV_CNTRL2 0x%08X\n", __func__,
cx_read(DEV_CNTRL2));
- dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() PCI_INT_MSK 0x%08X\n", __func__,
cx_read(PCI_INT_MSK));
- dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() AUD_INT_INT_MSK 0x%08X\n", __func__,
cx_read(AUDIO_INT_INT_MSK));
- dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() AUD_INT_DMA_CTL 0x%08X\n", __func__,
cx_read(AUD_INT_DMA_CTL));
- dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() AUD_EXT_INT_MSK 0x%08X\n", __func__,
cx_read(AUDIO_EXT_INT_MSK));
- dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() AUD_EXT_DMA_CTL 0x%08X\n", __func__,
cx_read(AUD_EXT_DMA_CTL));
- dprintk(1, "%s() PAD_CTRL 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() PAD_CTRL 0x%08X\n", __func__,
cx_read(PAD_CTRL));
- dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() ALT_PIN_OUT_SEL 0x%08X\n", __func__,
cx_read(ALT_PIN_OUT_SEL));
- dprintk(1, "%s() GPIO2 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() GPIO2 0x%08X\n", __func__,
cx_read(GPIO2));
- dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __FUNCTION__,
+ dprintk(1, "%s() gpcnt(0x%08X) 0x%08X\n", __func__,
port->reg_gpcnt, cx_read(port->reg_gpcnt));
- dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() gpcnt_ctl(0x%08X) 0x%08x\n", __func__,
port->reg_gpcnt_ctl, cx_read(port->reg_gpcnt_ctl));
- dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() dma_ctl(0x%08X) 0x%08x\n", __func__,
port->reg_dma_ctl, cx_read(port->reg_dma_ctl));
- dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() src_sel(0x%08X) 0x%08x\n", __func__,
port->reg_src_sel, cx_read(port->reg_src_sel));
- dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() lngth(0x%08X) 0x%08x\n", __func__,
port->reg_lngth, cx_read(port->reg_lngth));
- dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() hw_sop_ctrl(0x%08X) 0x%08x\n", __func__,
port->reg_hw_sop_ctrl, cx_read(port->reg_hw_sop_ctrl));
- dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() gen_ctrl(0x%08X) 0x%08x\n", __func__,
port->reg_gen_ctrl, cx_read(port->reg_gen_ctrl));
- dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() bd_pkt_status(0x%08X) 0x%08x\n", __func__,
port->reg_bd_pkt_status, cx_read(port->reg_bd_pkt_status));
- dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() sop_status(0x%08X) 0x%08x\n", __func__,
port->reg_sop_status, cx_read(port->reg_sop_status));
- dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() fifo_ovfl_stat(0x%08X) 0x%08x\n", __func__,
port->reg_fifo_ovfl_stat, cx_read(port->reg_fifo_ovfl_stat));
- dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() vld_misc(0x%08X) 0x%08x\n", __func__,
port->reg_vld_misc, cx_read(port->reg_vld_misc));
- dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() ts_clk_en(0x%08X) 0x%08x\n", __func__,
port->reg_ts_clk_en, cx_read(port->reg_ts_clk_en));
- dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __FUNCTION__,
+ dprintk(1, "%s() ts_int_msk(0x%08X) 0x%08x\n", __func__,
port->reg_ts_int_msk, cx_read(port->reg_ts_int_msk));
}
@@ -1012,8 +1037,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
struct cx23885_buffer *buf)
{
struct cx23885_dev *dev = port->dev;
+ u32 reg;
- dprintk(1, "%s() w: %d, h: %d, f: %d\n", __FUNCTION__,
+ dprintk(1, "%s() w: %d, h: %d, f: %d\n", __func__,
buf->vb.width, buf->vb.height, buf->vb.field);
/* setup fifo + format */
@@ -1031,21 +1057,24 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
if ( (!(cx23885_boards[dev->board].portb & CX23885_MPEG_DVB)) &&
(!(cx23885_boards[dev->board].portc & CX23885_MPEG_DVB)) ) {
printk( "%s() Failed. Unsupported value in .portb/c (0x%08x)/(0x%08x)\n",
- __FUNCTION__,
+ __func__,
cx23885_boards[dev->board].portb,
cx23885_boards[dev->board].portc );
return -EINVAL;
}
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ cx23885_av_clk(dev, 0);
+
udelay(100);
/* If the port supports SRC SELECT, configure it */
if(port->reg_src_sel)
cx_write(port->reg_src_sel, port->src_sel_val);
- cx_write(port->reg_hw_sop_ctrl, 0x47 << 16 | 188 << 4);
+ cx_write(port->reg_hw_sop_ctrl, port->hw_sop_ctrl_val);
cx_write(port->reg_ts_clk_en, port->ts_clk_en_val);
- cx_write(port->reg_vld_misc, 0x00);
+ cx_write(port->reg_vld_misc, port->vld_misc_val);
cx_write(port->reg_gen_ctrl, port->gen_ctrl_val);
udelay(100);
@@ -1054,11 +1083,26 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
cx_write(port->reg_gpcnt_ctl, 3);
q->count = 1;
+ if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) {
+
+ reg = cx_read(PAD_CTRL);
+ reg = reg & ~0x1; /* Clear TS1_OE */
+
+ /* FIXME, bit 2 writing here is questionable */
+ /* set TS1_SOP_OE and TS1_OE_HI */
+ reg = reg | 0xa;
+ cx_write(PAD_CTRL, reg);
+
+ /* FIXME and these two registers should be documented. */
+ cx_write(CLK_DELAY, cx_read(CLK_DELAY) | 0x80000011);
+ cx_write(ALT_PIN_OUT_SEL, 0x10100045);
+ }
+
switch(dev->bridge) {
case CX23885_BRIDGE_885:
case CX23885_BRIDGE_887:
/* enable irqs */
- dprintk(1, "%s() enabling TS int's and DMA\n", __FUNCTION__ );
+ dprintk(1, "%s() enabling TS int's and DMA\n", __func__ );
cx_set(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_set(port->reg_dma_ctl, port->dma_ctl_val);
cx_set(PCI_INT_MSK, dev->pci_irqmask | port->pci_irqmask);
@@ -1069,6 +1113,9 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
cx_set(DEV_CNTRL2, (1<<5)); /* Enable RISC controller */
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ cx23885_av_clk(dev, 1);
+
if (debug > 4)
cx23885_tsport_reg_dump(port);
@@ -1078,12 +1125,32 @@ static int cx23885_start_dma(struct cx23885_tsport *port,
static int cx23885_stop_dma(struct cx23885_tsport *port)
{
struct cx23885_dev *dev = port->dev;
- dprintk(1, "%s()\n", __FUNCTION__);
+ u32 reg;
+
+ dprintk(1, "%s()\n", __func__);
/* Stop interrupts and DMA */
cx_clear(port->reg_ts_int_msk, port->ts_int_msk_val);
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+ if (cx23885_boards[dev->board].portb & CX23885_MPEG_ENCODER) {
+
+ reg = cx_read(PAD_CTRL);
+
+ /* Set TS1_OE */
+ reg = reg | 0x1;
+
+ /* clear TS1_SOP_OE and TS1_OE_HI */
+ reg = reg & ~0xa;
+ cx_write(PAD_CTRL, reg);
+ cx_write(port->reg_src_sel, 0);
+ cx_write(port->reg_gen_ctrl, 8);
+
+ }
+
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ cx23885_av_clk(dev, 0);
+
return 0;
}
@@ -1093,13 +1160,13 @@ int cx23885_restart_queue(struct cx23885_tsport *port,
struct cx23885_dev *dev = port->dev;
struct cx23885_buffer *buf;
- dprintk(5, "%s()\n", __FUNCTION__);
+ dprintk(5, "%s()\n", __func__);
if (list_empty(&q->active))
{
struct cx23885_buffer *prev;
prev = NULL;
- dprintk(5, "%s() queue is empty\n", __FUNCTION__);
+ dprintk(5, "%s() queue is empty\n", __func__);
for (;;) {
if (list_empty(&q->queued))
@@ -1154,7 +1221,7 @@ int cx23885_buf_prepare(struct videobuf_queue *q, struct cx23885_tsport *port,
int size = port->ts_packet_size * port->ts_packet_count;
int rc;
- dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+ dprintk(1, "%s: %p\n", __func__, buf);
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
@@ -1197,7 +1264,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
buf->count = cx88q->count++;
mod_timer(&cx88q->timeout, jiffies + BUFFER_TIMEOUT);
dprintk(1, "[%p/%d] %s - first active\n",
- buf, buf->vb.i, __FUNCTION__);
+ buf, buf->vb.i, __func__);
} else {
dprintk( 1, "queue is not empty - append to active\n" );
prev = list_entry(cx88q->active.prev, struct cx23885_buffer,
@@ -1208,7 +1275,7 @@ void cx23885_buf_queue(struct cx23885_tsport *port, struct cx23885_buffer *buf)
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
prev->risc.jmp[2] = cpu_to_le32(0); /* 64 bit bits 63-32 */
dprintk( 1, "[%p/%d] %s - append to active\n",
- buf, buf->vb.i, __FUNCTION__);
+ buf, buf->vb.i, __func__);
}
}
@@ -1239,13 +1306,23 @@ static void do_cancel_buffers(struct cx23885_tsport *port, char *reason,
spin_unlock_irqrestore(&port->slock, flags);
}
+void cx23885_cancel_buffers(struct cx23885_tsport *port)
+{
+ struct cx23885_dev *dev = port->dev;
+ struct cx23885_dmaqueue *q = &port->mpegq;
+
+ dprintk(1, "%s()\n", __FUNCTION__);
+ del_timer_sync(&q->timeout);
+ cx23885_stop_dma(port);
+ do_cancel_buffers(port, "cancel", 0);
+}
static void cx23885_timeout(unsigned long data)
{
struct cx23885_tsport *port = (struct cx23885_tsport *)data;
struct cx23885_dev *dev = port->dev;
- dprintk(1, "%s()\n",__FUNCTION__);
+ dprintk(1, "%s()\n",__func__);
if (debug > 5)
cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
@@ -1254,16 +1331,77 @@ static void cx23885_timeout(unsigned long data)
do_cancel_buffers(port, "timeout", 1);
}
+int cx23885_irq_417(struct cx23885_dev *dev, u32 status)
+{
+ /* FIXME: port1 assumption here. */
+ struct cx23885_tsport *port = &dev->ts1;
+ int count = 0;
+ int handled = 0;
+
+ if (status == 0)
+ return handled;
+
+ count = cx_read(port->reg_gpcnt);
+ dprintk(7, "status: 0x%08x mask: 0x%08x count: 0x%x\n",
+ status, cx_read(port->reg_ts_int_msk), count);
+
+ if ((status & VID_B_MSK_BAD_PKT) ||
+ (status & VID_B_MSK_OPC_ERR) ||
+ (status & VID_B_MSK_VBI_OPC_ERR) ||
+ (status & VID_B_MSK_SYNC) ||
+ (status & VID_B_MSK_VBI_SYNC) ||
+ (status & VID_B_MSK_OF) ||
+ (status & VID_B_MSK_VBI_OF)) {
+ printk(KERN_ERR "%s: V4L mpeg risc op code error, status "
+ "= 0x%x\n", dev->name, status);
+ if (status & VID_B_MSK_BAD_PKT)
+ dprintk(1, " VID_B_MSK_BAD_PKT\n");
+ if (status & VID_B_MSK_OPC_ERR)
+ dprintk(1, " VID_B_MSK_OPC_ERR\n");
+ if (status & VID_B_MSK_VBI_OPC_ERR)
+ dprintk(1, " VID_B_MSK_VBI_OPC_ERR\n");
+ if (status & VID_B_MSK_SYNC)
+ dprintk(1, " VID_B_MSK_SYNC\n");
+ if (status & VID_B_MSK_VBI_SYNC)
+ dprintk(1, " VID_B_MSK_VBI_SYNC\n");
+ if (status & VID_B_MSK_OF)
+ dprintk(1, " VID_B_MSK_OF\n");
+ if (status & VID_B_MSK_VBI_OF)
+ dprintk(1, " VID_B_MSK_VBI_OF\n");
+
+ cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
+ cx23885_sram_channel_dump(dev,
+ &dev->sram_channels[port->sram_chno]);
+ cx23885_417_check_encoder(dev);
+ } else if (status & VID_B_MSK_RISCI1) {
+ dprintk(7, " VID_B_MSK_RISCI1\n");
+ spin_lock(&port->slock);
+ cx23885_wakeup(port, &port->mpegq, count);
+ spin_unlock(&port->slock);
+ } else if (status & VID_B_MSK_RISCI2) {
+ dprintk(7, " VID_B_MSK_RISCI2\n");
+ spin_lock(&port->slock);
+ cx23885_restart_queue(port, &port->mpegq);
+ spin_unlock(&port->slock);
+ }
+ if (status) {
+ cx_write(port->reg_ts_int_stat, status);
+ handled = 1;
+ }
+
+ return handled;
+}
+
static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
{
struct cx23885_dev *dev = port->dev;
int handled = 0;
u32 count;
- if ( (status & VID_BC_MSK_OPC_ERR) ||
- (status & VID_BC_MSK_BAD_PKT) ||
- (status & VID_BC_MSK_SYNC) ||
- (status & VID_BC_MSK_OF))
+ if ((status & VID_BC_MSK_OPC_ERR) ||
+ (status & VID_BC_MSK_BAD_PKT) ||
+ (status & VID_BC_MSK_SYNC) ||
+ (status & VID_BC_MSK_OF))
{
if (status & VID_BC_MSK_OPC_ERR)
dprintk(7, " (VID_BC_MSK_OPC_ERR 0x%08x)\n", VID_BC_MSK_OPC_ERR);
@@ -1277,7 +1415,8 @@ static int cx23885_irq_ts(struct cx23885_tsport *port, u32 status)
printk(KERN_ERR "%s: mpeg risc op code error\n", dev->name);
cx_clear(port->reg_dma_ctl, port->dma_ctl_val);
- cx23885_sram_channel_dump(dev, &dev->sram_channels[ port->sram_chno ]);
+ cx23885_sram_channel_dump(dev,
+ &dev->sram_channels[port->sram_chno]);
} else if (status & VID_BC_MSK_RISCI1) {
@@ -1378,11 +1517,17 @@ static irqreturn_t cx23885_irq(int irq, void *dev_id)
if (ts1_status) {
if (cx23885_boards[dev->board].portb == CX23885_MPEG_DVB)
handled += cx23885_irq_ts(ts1, ts1_status);
+ else
+ if (cx23885_boards[dev->board].portb == CX23885_MPEG_ENCODER)
+ handled += cx23885_irq_417(dev, ts1_status);
}
if (ts2_status) {
if (cx23885_boards[dev->board].portc == CX23885_MPEG_DVB)
handled += cx23885_irq_ts(ts2, ts2_status);
+ else
+ if (cx23885_boards[dev->board].portc == CX23885_MPEG_ENCODER)
+ handled += cx23885_irq_417(dev, ts2_status);
}
if (vida_status)
@@ -1422,7 +1567,8 @@ static int __devinit cx23885_initdev(struct pci_dev *pci_dev,
printk(KERN_INFO "%s/0: found at %s, rev: %d, irq: %d, "
"latency: %d, mmio: 0x%llx\n", dev->name,
pci_name(pci_dev), dev->pci_rev, pci_dev->irq,
- dev->pci_lat, (unsigned long long)pci_resource_start(pci_dev,0));
+ dev->pci_lat,
+ (unsigned long long)pci_resource_start(pci_dev, 0));
pci_set_master(pci_dev);
if (!pci_dma_supported(pci_dev, 0xffffffff)) {
diff --git a/drivers/media/video/cx23885/cx23885-dvb.c b/drivers/media/video/cx23885/cx23885-dvb.c
index ed465c007ce..870d6e197d6 100644
--- a/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/drivers/media/video/cx23885/cx23885-dvb.c
@@ -36,9 +36,12 @@
#include "tda18271.h"
#include "lgdt330x.h"
#include "xc5000.h"
+#include "tda10048.h"
#include "dvb-pll.h"
#include "tuner-xc2028.h"
-#include "tuner-xc2028-types.h"
+#include "tuner-simple.h"
+#include "dib7000p.h"
+#include "dibx000_common.h"
static unsigned int debug;
@@ -53,6 +56,8 @@ static unsigned int alt_tuner;
module_param(alt_tuner, int, 0644);
MODULE_PARM_DESC(alt_tuner, "Enable alternate tuner configuration");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
/* ------------------------------------------------------------------ */
static int dvb_buf_setup(struct videobuf_queue *q,
@@ -104,6 +109,13 @@ static struct s5h1409_config hauppauge_generic_config = {
.mpeg_timing = S5H1409_MPEGTIMING_CONTINOUS_NONINVERTING_CLOCK,
};
+static struct tda10048_config hauppauge_hvr1200_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_SERIAL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON
+};
+
static struct s5h1409_config hauppauge_ezqam_config = {
.demod_address = 0x32 >> 1,
.output_mode = S5H1409_SERIAL_OUTPUT,
@@ -164,8 +176,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 = {
@@ -173,6 +187,96 @@ static struct tda18271_config hauppauge_tda18271_config = {
.gate = TDA18271_GATE_ANALOG,
};
+static struct tda18271_config hauppauge_hvr1200_tuner_config = {
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+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.000000
+ * With external clock = 30.000000 */
+struct dibx000_bandwidth_config xc3028_bw_config = {
+ 60000, /* internal */
+ 30000, /* sampling */
+ 1, /* pll_cfg: prediv */
+ 8, /* pll_cfg: ratio */
+ 3, /* pll_cfg: range */
+ 1, /* pll_cfg: reset */
+ 0, /* pll_cfg: bypass */
+ 0, /* misc: refdiv */
+ 0, /* misc: bypclk_div */
+ 1, /* misc: IO_CLK_en_core */
+ 1, /* misc: ADClkSrc */
+ 0, /* misc: 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 hauppauge_hvr1400_dib7000_config = {
+ .output_mpeg2_in_188_bytes = 1,
+ .hostbus_diversity = 1,
+ .tuner_is_baseband = 0,
+ .update_lna = NULL,
+
+ .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,
+
+ .pwm_freq_div = 0,
+ .agc_control = NULL,
+ .spur_protect = 0,
+
+ .output_mode = OUTMODE_MPEG2_SERIAL,
+};
+
static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
{
struct cx23885_tsport *port = ptr;
@@ -182,7 +286,7 @@ static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
case XC2028_TUNER_RESET:
/* Send the tuner in then out of reset */
/* GPIO-2 xc3028 tuner */
- dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __FUNCTION__, arg);
+ dprintk(1, "%s: XC2028_TUNER_RESET %d\n", __func__, arg);
cx_set(GP0_IO, 0x00040000);
cx_clear(GP0_IO, 0x00000004);
@@ -192,10 +296,10 @@ static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
msleep(5);
break;
case XC2028_RESET_CLK:
- dprintk(1, "%s: XC2028_RESET_CLK %d\n", __FUNCTION__, arg);
+ dprintk(1, "%s: XC2028_RESET_CLK %d\n", __func__, arg);
break;
default:
- dprintk(1, "%s: unknown command %d, arg %d\n", __FUNCTION__,
+ dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
command, arg);
return -EINVAL;
}
@@ -271,8 +375,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,13 +402,52 @@ 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 = {
.fname = "xc3028-v27.fw",
.max_len = 64,
- .scode_table = OREN538,
+ .scode_table = XC3028_FE_OREN538,
+ };
+
+ fe = dvb_attach(xc2028_attach,
+ port->dvb.frontend, &cfg);
+ if (fe != NULL && fe->ops.tuner_ops.set_config != NULL)
+ fe->ops.tuner_ops.set_config(fe, &ctl);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1200:
+ case CX23885_BOARD_HAUPPAUGE_HVR1700:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(tda10048_attach,
+ &hauppauge_hvr1200_config,
+ &i2c_bus->i2c_adap);
+ if (port->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, port->dvb.frontend,
+ &dev->i2c_bus[1].i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, port->dvb.frontend,
+ 0x60, &dev->i2c_bus[1].i2c_adap,
+ &hauppauge_hvr1200_tuner_config);
+ }
+ break;
+ case CX23885_BOARD_HAUPPAUGE_HVR1400:
+ i2c_bus = &dev->i2c_bus[0];
+ port->dvb.frontend = dvb_attach(dib7000p_attach,
+ &i2c_bus->i2c_adap,
+ 0x12, &hauppauge_hvr1400_dib7000_config);
+ if (port->dvb.frontend != NULL) {
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg = {
+ .i2c_adap = &dev->i2c_bus[1].i2c_adap,
+ .i2c_addr = 0x64,
+ .callback = cx23885_hvr1500_xc3028_callback,
+ };
+ static struct xc2028_ctrl ctl = {
+ .fname = "xc3028L-v36.fw",
+ .max_len = 64,
+ .demod = 5000,
+ .d2633 = 1
};
fe = dvb_attach(xc2028_attach,
@@ -330,7 +474,7 @@ static int dvb_register(struct cx23885_tsport *port)
/* register everything */
return videobuf_dvb_register(&port->dvb, THIS_MODULE, port,
- &dev->pci->dev);
+ &dev->pci->dev, adapter_nr);
}
int cx23885_dvb_register(struct cx23885_tsport *port)
@@ -338,7 +482,7 @@ int cx23885_dvb_register(struct cx23885_tsport *port)
struct cx23885_dev *dev = port->dev;
int err;
- dprintk(1, "%s\n", __FUNCTION__);
+ dprintk(1, "%s\n", __func__);
dprintk(1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
dev->board,
dev->name,
@@ -349,12 +493,12 @@ 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);
if (err != 0)
- printk("%s() dvb_register failed err = %d\n", __FUNCTION__, err);
+ printk("%s() dvb_register failed err = %d\n", __func__, err);
return err;
}
diff --git a/drivers/media/video/cx23885/cx23885-i2c.c b/drivers/media/video/cx23885/cx23885-i2c.c
index 92fe0bd37c8..c6bb0a05bc1 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");
@@ -87,10 +87,10 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
int retval, cnt;
if (joined_rlen)
- dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __FUNCTION__,
+ dprintk(1, "%s(msg->wlen=%d, nextmsg->rlen=%d)\n", __func__,
msg->len, joined_rlen);
else
- dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+ dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
/* Deal with i2c probe functions with zero payload */
if (msg->len == 0) {
@@ -101,7 +101,7 @@ static int i2c_sendbytes(struct i2c_adapter *i2c_adap,
if (!i2c_slave_did_ack(i2c_adap))
return -EIO;
- dprintk(1, "%s() returns 0\n", __FUNCTION__);
+ dprintk(1, "%s() returns 0\n", __func__);
return 0;
}
@@ -176,7 +176,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
if (i2c_debug && !joined)
- dprintk(1, "%s(msg->len=%d)\n", __FUNCTION__, msg->len);
+ dprintk(1, "%s(msg->len=%d)\n", __func__, msg->len);
/* Deal with i2c probe functions with zero payload */
if (msg->len == 0) {
@@ -188,7 +188,7 @@ static int i2c_readbytes(struct i2c_adapter *i2c_adap,
return -EIO;
- dprintk(1, "%s() returns 0\n", __FUNCTION__);
+ dprintk(1, "%s() returns 0\n", __func__);
return 0;
}
@@ -238,11 +238,11 @@ static int i2c_xfer(struct i2c_adapter *i2c_adap,
struct cx23885_dev *dev = bus->dev;
int i, retval = 0;
- dprintk(1, "%s(num = %d)\n", __FUNCTION__, num);
+ dprintk(1, "%s(num = %d)\n", __func__, num);
for (i = 0 ; i < num; i++) {
dprintk(1, "%s(num = %d) addr = 0x%02x len = 0x%x\n",
- __FUNCTION__, num, msgs[i].addr, msgs[i].len);
+ __func__, num, msgs[i].addr, msgs[i].len);
if (msgs[i].flags & I2C_M_RD) {
/* read */
retval = i2c_readbytes(i2c_adap, &msgs[i], 0);
@@ -353,6 +353,8 @@ static struct i2c_client cx23885_i2c_client_template = {
};
static char *i2c_devs[128] = {
+ [0x10 >> 1] = "tda10048",
+ [0x12 >> 1] = "dib7000pc",
[ 0x1c >> 1 ] = "lgdt3303",
[ 0x86 >> 1 ] = "tda9887",
[ 0x32 >> 1 ] = "cx24227",
@@ -360,7 +362,8 @@ static char *i2c_devs[128] = {
[ 0x84 >> 1 ] = "tda8295",
[ 0xa0 >> 1 ] = "eeprom",
[ 0xc0 >> 1 ] = "tuner/mt2131/tda8275",
- [ 0xc2 >> 1 ] = "tuner/mt2131/tda8275/xc5000",
+ [0xc2 >> 1] = "tuner/mt2131/tda8275/xc5000/xc3028",
+ [0xc8 >> 1] = "tuner/xc3028L",
};
static void do_i2c_scan(char *name, struct i2c_client *c)
@@ -383,7 +386,7 @@ int cx23885_i2c_register(struct cx23885_i2c *bus)
{
struct cx23885_dev *dev = bus->dev;
- dprintk(1, "%s(bus = %d)\n", __FUNCTION__, bus->nr);
+ dprintk(1, "%s(bus = %d)\n", __func__, bus->nr);
memcpy(&bus->i2c_adap, &cx23885_i2c_adap_template,
sizeof(bus->i2c_adap));
@@ -420,6 +423,29 @@ int cx23885_i2c_unregister(struct cx23885_i2c *bus)
return 0;
}
+void cx23885_av_clk(struct cx23885_dev *dev, int enable)
+{
+ /* write 0 to bus 2 addr 0x144 via i2x_xfer() */
+ char buffer[3];
+ struct i2c_msg msg;
+ dprintk(1, "%s(enabled = %d)\n", __func__, enable);
+
+ /* Register 0x144 */
+ buffer[0] = 0x01;
+ buffer[1] = 0x44;
+ if (enable == 1)
+ buffer[2] = 0x05;
+ else
+ buffer[2] = 0x00;
+
+ msg.addr = 0x44;
+ msg.flags = I2C_M_TEN;
+ msg.len = 3;
+ msg.buf = buffer;
+
+ i2c_xfer(&dev->i2c_bus[2].i2c_adap, &msg, 1);
+}
+
/* ----------------------------------------------------------------------- */
/*
diff --git a/drivers/media/video/cx23885/cx23885-video.c b/drivers/media/video/cx23885/cx23885-video.c
index d3c4d2c5cbe..84652210a28 100644
--- a/drivers/media/video/cx23885/cx23885-video.c
+++ b/drivers/media/video/cx23885/cx23885-video.c
@@ -141,7 +141,7 @@ static struct cx23885_fmt *format_by_fourcc(unsigned int fourcc)
if (formats[i].fourcc == fourcc)
return formats+i;
- printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __FUNCTION__, fourcc);
+ printk(KERN_ERR "%s(0x%08x) NOT FOUND\n", __func__, fourcc);
return NULL;
}
@@ -292,13 +292,13 @@ void cx23885_video_wakeup(struct cx23885_dev *dev,
}
if (bc != 1)
printk(KERN_ERR "%s: %d buffers handled (should be 1)\n",
- __FUNCTION__, bc);
+ __func__, bc);
}
int cx23885_set_tvnorm(struct cx23885_dev *dev, v4l2_std_id norm)
{
dprintk(1, "%s(norm = 0x%08x) name: [%s]\n",
- __FUNCTION__,
+ __func__,
(unsigned int)norm,
v4l2_norm_to_name(norm));
@@ -319,7 +319,7 @@ struct video_device *cx23885_vdev_init(struct cx23885_dev *dev,
char *type)
{
struct video_device *vfd;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
vfd = video_device_alloc();
if (NULL == vfd)
@@ -358,7 +358,7 @@ EXPORT_SYMBOL(cx23885_ctrl_query);
static int res_get(struct cx23885_dev *dev, struct cx23885_fh *fh,
unsigned int bit)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
if (fh->resources & bit)
/* have it already allocated */
return 1;
@@ -392,7 +392,7 @@ static void res_free(struct cx23885_dev *dev, struct cx23885_fh *fh,
unsigned int bits)
{
BUG_ON((fh->resources & bits) != bits);
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
mutex_lock(&dev->lock);
fh->resources &= ~bits;
@@ -407,7 +407,7 @@ int cx23885_video_mux(struct cx23885_dev *dev, unsigned int input)
memset(&route, 0, sizeof(route));
dprintk(1, "%s() video_mux: %d [vmux=%d, gpio=0x%x,0x%x,0x%x,0x%x]\n",
- __FUNCTION__,
+ __func__,
input, INPUT(input)->vmux,
INPUT(input)->gpio0, INPUT(input)->gpio1,
INPUT(input)->gpio2, INPUT(input)->gpio3);
@@ -427,7 +427,7 @@ EXPORT_SYMBOL(cx23885_video_mux);
int cx23885_set_scale(struct cx23885_dev *dev, unsigned int width,
unsigned int height, enum v4l2_field field)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
return 0;
}
@@ -435,7 +435,7 @@ static int cx23885_start_video_dma(struct cx23885_dev *dev,
struct cx23885_dmaqueue *q,
struct cx23885_buffer *buf)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
/* setup fifo + format */
cx23885_sram_channel_setup(dev, &dev->sram_channels[SRAM_CH01],
@@ -463,7 +463,7 @@ static int cx23885_restart_video_queue(struct cx23885_dev *dev,
{
struct cx23885_buffer *buf, *prev;
struct list_head *item;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
if (!list_empty(&q->active)) {
buf = list_entry(q->active.next, struct cx23885_buffer,
@@ -579,13 +579,13 @@ static int buffer_prepare(struct videobuf_queue *q, struct videobuf_buffer *vb,
if (dev->tvnorm & V4L2_STD_NTSC) {
/* cx25840 transmits NTSC bottom field first */
dprintk(1, "%s() Creating NTSC risc\n",
- __FUNCTION__);
+ __func__);
line0_offset = buf->bpl;
line1_offset = 0;
} else {
/* All other formats are top field first */
dprintk(1, "%s() Creating PAL/SECAM risc\n",
- __FUNCTION__);
+ __func__);
line0_offset = 0;
line1_offset = buf->bpl;
}
@@ -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),
@@ -885,7 +885,7 @@ static int video_mmap(struct file *file, struct vm_area_struct *vma)
int cx23885_get_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
{
- dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __FUNCTION__);
+ dprintk(1, "%s() calling cx25840(VIDIOC_G_CTRL)\n", __func__);
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_G_CTRL, ctl);
return 0;
}
@@ -894,7 +894,7 @@ EXPORT_SYMBOL(cx23885_get_control);
int cx23885_set_control(struct cx23885_dev *dev, struct v4l2_control *ctl)
{
dprintk(1, "%s() calling cx25840(VIDIOC_S_CTRL)"
- " (disabled - no action)\n", __FUNCTION__);
+ " (disabled - no action)\n", __func__);
return 0;
}
EXPORT_SYMBOL(cx23885_set_control);
@@ -990,7 +990,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
int err;
- dprintk(2, "%s()\n", __FUNCTION__);
+ dprintk(2, "%s()\n", __func__);
err = vidioc_try_fmt_cap(file, priv, f);
if (0 != err)
@@ -999,7 +999,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
fh->width = f->fmt.pix.width;
fh->height = f->fmt.pix.height;
fh->vidq.field = f->fmt.pix.field;
- dprintk(2, "%s() width=%d height=%d field=%d\n", __FUNCTION__,
+ dprintk(2, "%s() width=%d height=%d field=%d\n", __func__,
fh->width, fh->height, fh->vidq.field);
cx23885_call_i2c_clients(&dev->i2c_bus[2], VIDIOC_S_FMT, f);
return 0;
@@ -1101,7 +1101,7 @@ static int vidioc_streamon(struct file *file, void *priv,
{
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = fh->dev;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
if (unlikely(fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE))
return -EINVAL;
@@ -1118,7 +1118,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
struct cx23885_fh *fh = priv;
struct cx23885_dev *dev = fh->dev;
int err, res;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
return -EINVAL;
@@ -1136,7 +1136,7 @@ static int vidioc_streamoff(struct file *file, void *priv, enum v4l2_buf_type i)
static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *tvnorms)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
mutex_lock(&dev->lock);
cx23885_set_tvnorm(dev, *tvnorms);
@@ -1159,7 +1159,7 @@ int cx23885_enum_input(struct cx23885_dev *dev, struct v4l2_input *i)
[CX23885_VMUX_DEBUG] = "for debug only",
};
unsigned int n;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
n = i->index;
if (n >= 4)
@@ -1184,7 +1184,7 @@ static int vidioc_enum_input(struct file *file, void *priv,
struct v4l2_input *i)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
return cx23885_enum_input(dev, i);
}
@@ -1193,7 +1193,7 @@ static int vidioc_g_input(struct file *file, void *priv, unsigned int *i)
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
*i = dev->input;
- dprintk(1, "%s() returns %d\n", __FUNCTION__, *i);
+ dprintk(1, "%s() returns %d\n", __func__, *i);
return 0;
}
@@ -1201,10 +1201,10 @@ static int vidioc_s_input(struct file *file, void *priv, unsigned int i)
{
struct cx23885_dev *dev = ((struct cx23885_fh *)priv)->dev;
- dprintk(1, "%s(%d)\n", __FUNCTION__, i);
+ dprintk(1, "%s(%d)\n", __func__, i);
if (i >= 4) {
- dprintk(1, "%s() -EINVAL\n", __FUNCTION__);
+ dprintk(1, "%s() -EINVAL\n", __func__);
return -EINVAL;
}
@@ -1389,7 +1389,7 @@ int cx23885_video_irq(struct cx23885_dev *dev, u32 status)
return handled;
cx_write(VID_A_INT_STAT, status);
- dprintk(2, "%s() status = 0x%08x\n", __FUNCTION__, status);
+ dprintk(2, "%s() status = 0x%08x\n", __func__, status);
/* risc op code error */
if (status & (1 << 16)) {
printk(KERN_WARNING "%s/0: video risc op code error\n",
@@ -1487,7 +1487,7 @@ static const struct file_operations radio_fops = {
void cx23885_video_unregister(struct cx23885_dev *dev)
{
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
cx_clear(PCI_INT_MSK, 1);
if (dev->video_dev) {
@@ -1505,7 +1505,7 @@ int cx23885_video_register(struct cx23885_dev *dev)
{
int err;
- dprintk(1, "%s()\n", __FUNCTION__);
+ dprintk(1, "%s()\n", __func__);
spin_lock_init(&dev->slock);
/* Initialize VBI template */
diff --git a/drivers/media/video/cx23885/cx23885.h b/drivers/media/video/cx23885/cx23885.h
index 7cb2179f262..32af87f25e7 100644
--- a/drivers/media/video/cx23885/cx23885.h
+++ b/drivers/media/video/cx23885/cx23885.h
@@ -32,6 +32,7 @@
#include "btcx-risc.h"
#include "cx23885-reg.h"
+#include "media/cx2341x.h"
#include <linux/version.h>
#include <linux/mutex.h>
@@ -59,6 +60,9 @@
#define CX23885_BOARD_DVICO_FUSIONHDTV_5_EXP 4
#define CX23885_BOARD_HAUPPAUGE_HVR1500Q 5
#define CX23885_BOARD_HAUPPAUGE_HVR1500 6
+#define CX23885_BOARD_HAUPPAUGE_HVR1200 7
+#define CX23885_BOARD_HAUPPAUGE_HVR1700 8
+#define CX23885_BOARD_HAUPPAUGE_HVR1400 9
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
@@ -154,6 +158,7 @@ typedef enum {
CX23885_MPEG_UNDEFINED = 0,
CX23885_MPEG_DVB,
CX23885_ANALOG_VIDEO,
+ CX23885_MPEG_ENCODER,
} port_t;
struct cx23885_board {
@@ -252,6 +257,8 @@ struct cx23885_tsport {
u32 gen_ctrl_val;
u32 ts_clk_en_val;
u32 src_sel_val;
+ u32 vld_misc_val;
+ u32 hw_sop_ctrl_val;
};
struct cx23885_dev {
@@ -312,6 +319,14 @@ struct cx23885_dev {
struct cx23885_dmaqueue vidq;
struct cx23885_dmaqueue vbiq;
spinlock_t slock;
+
+ /* MPEG Encoder ONLY settings */
+ u32 cx23417_mailbox;
+ struct cx2341x_mpeg_params mpeg_params;
+ struct video_device *v4l_device;
+ atomic_t v4l_reader_count;
+ struct cx23885_tvnorm encodernorm;
+
};
extern struct list_head cx23885_devlist;
@@ -431,6 +446,18 @@ extern int cx23885_i2c_register(struct cx23885_i2c *bus);
extern int cx23885_i2c_unregister(struct cx23885_i2c *bus);
extern void cx23885_call_i2c_clients(struct cx23885_i2c *bus, unsigned int cmd,
void *arg);
+extern void cx23885_av_clk(struct cx23885_dev *dev, int enable);
+
+/* ----------------------------------------------------------- */
+/* cx23885-417.c */
+extern int cx23885_417_register(struct cx23885_dev *dev);
+extern void cx23885_417_unregister(struct cx23885_dev *dev);
+extern int cx23885_irq_417(struct cx23885_dev *dev, u32 status);
+extern void cx23885_417_check_encoder(struct cx23885_dev *dev);
+extern void cx23885_mc417_init(struct cx23885_dev *dev);
+extern int mc417_memory_read(struct cx23885_dev *dev, u32 address, u32 *value);
+extern int mc417_memory_write(struct cx23885_dev *dev, u32 address, u32 value);
+
/* ----------------------------------------------------------- */
/* tv norms */
diff --git a/drivers/media/video/cx25840/cx25840-core.c b/drivers/media/video/cx25840/cx25840-core.c
index 756a1eeb274..7fde678b2c4 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;
@@ -1291,6 +1268,12 @@ static int cx25840_probe(struct i2c_client *client)
state->id = id;
state->rev = device_id;
+ if (state->is_cx23885) {
+ /* Drive GPIO2 direction and values */
+ cx25840_write(client, 0x160, 0x1d);
+ cx25840_write(client, 0x164, 0x00);
+ }
+
return 0;
}
diff --git a/drivers/media/video/cx25840/cx25840-core.h b/drivers/media/video/cx25840/cx25840-core.h
index 95093edc918..8bf797f48b0 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 1ddf724a2c7..620d295947a 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 6828f59b9d8..c754b9d1336 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 49d3813a9b4..bcf6d9ba063 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 316b106c351..e976fc6bef7 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;
@@ -494,7 +494,7 @@ static snd_pcm_uframes_t snd_cx88_pointer(struct snd_pcm_substream *substream)
count = atomic_read(&chip->count);
-// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __FUNCTION__,
+// dprintk(2, "%s - count %d (+%u), period %d, frame %lu\n", __func__,
// count, new, count & (runtime->periods-1),
// runtime->period_size * (count & (runtime->periods-1)));
return runtime->period_size * (count & (runtime->periods-1));
@@ -690,10 +690,8 @@ MODULE_DEVICE_TABLE(pci, cx88_audio_pci_tbl);
static int snd_cx88_free(snd_cx88_card_t *chip)
{
- if (chip->irq >= 0){
- synchronize_irq(chip->irq);
+ if (chip->irq >= 0)
free_irq(chip->irq, chip);
- }
cx88_core_put(chip->core,chip->pci);
diff --git a/drivers/media/video/cx88/cx88-blackbird.c b/drivers/media/video/cx88/cx88-blackbird.c
index a99e9d5950a..61c4f72644b 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]");
@@ -314,7 +314,7 @@ static int blackbird_mbox_func(void *priv, u32 command, int in, int out, u32 dat
u32 value, flag, retval;
int i;
- dprintk(1,"%s: 0x%X\n", __FUNCTION__, command);
+ dprintk(1,"%s: 0x%X\n", __func__, command);
/* this may not be 100% safe if we can't read any memory location
without side effects */
@@ -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,
@@ -1055,7 +1055,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
dev = cx8802_get_device(inode);
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
if (dev == NULL)
return -ENODEV;
@@ -1065,7 +1065,7 @@ static int mpeg_open(struct inode *inode, struct file *file)
if (drv) {
err = drv->request_acquire(drv);
if(err != 0) {
- dprintk(1,"%s: Unable to acquire hardware, %d\n", __FUNCTION__, err);
+ dprintk(1,"%s: Unable to acquire hardware, %d\n", __func__, err);
return err;
}
}
@@ -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),
@@ -1284,7 +1284,7 @@ static int cx8802_blackbird_probe(struct cx8802_driver *drv)
struct cx8802_dev *dev = core->dvbdev;
int err;
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
core->boardnr,
core->name,
diff --git a/drivers/media/video/cx88/cx88-cards.c b/drivers/media/video/cx88/cx88-cards.c
index 8c9a8adf52d..620159d0550 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 */
@@ -1354,6 +1364,10 @@ static const struct cx88_board cx88_boards[] = {
}},
/* fixme: Add radio support */
.mpeg = CX88_MPEG_DVB | CX88_MPEG_BLACKBIRD,
+ .radio = {
+ .type = CX88_RADIO,
+ .gpio0 = 0xe780,
+ },
},
[CX88_BOARD_ADSTECH_PTV_390] = {
.name = "ADS Tech Instant Video PCI",
@@ -1401,6 +1415,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 +1858,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 +1971,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 +2020,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 +2073,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 +2124,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 +2132,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 +2229,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 +2316,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 +2356,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 +2391,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 +2479,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 +2533,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 +2555,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 +2687,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 +2697,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 +2715,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 01e2ac98970..c4d1aff1fdb 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;
}
@@ -548,7 +548,7 @@ void cx88_wakeup(struct cx88_core *core,
mod_timer(&q->timeout, jiffies+BUFFER_TIMEOUT);
}
if (bc != 1)
- printk("%s: %d buffers handled (should be 1)\n",__FUNCTION__,bc);
+ printk("%s: %d buffers handled (should be 1)\n",__func__,bc);
}
void cx88_shutdown(struct cx88_core *core)
@@ -577,7 +577,7 @@ void cx88_shutdown(struct cx88_core *core)
int cx88_reset(struct cx88_core *core)
{
- dprintk(1,"%s\n",__FUNCTION__);
+ dprintk(1,"%s\n",__func__);
cx88_shutdown(core);
/* clear irq status */
@@ -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 f7b41eb1bb5..f1251b844e0 100644
--- a/drivers/media/video/cx88/cx88-dvb.c
+++ b/drivers/media/video/cx88/cx88-dvb.c
@@ -45,16 +45,20 @@
#include "nxt200x.h"
#include "cx24123.h"
#include "isl6421.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]");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
#define dprintk(level,fmt, arg...) if (debug >= level) \
printk(KERN_DEBUG "%s/2-dvb: " fmt, core->name, ## arg)
@@ -235,6 +239,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,
};
@@ -266,7 +283,7 @@ static int lgdt330x_pll_rf_set(struct dvb_frontend* fe, int index)
struct cx8802_dev *dev= fe->dvb->priv;
struct cx88_core *core = dev->core;
- dprintk(1, "%s: index = %d\n", __FUNCTION__, index);
+ dprintk(1, "%s: index = %d\n", __func__, index);
if (index == 0)
cx_clear(MO_GP0_IO, 8);
else
@@ -357,6 +374,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", __func__, 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", __func__, arg);
+ break;
+ default:
+ dprintk(1, "%s: unknown command %d, arg %d\n", __func__,
+ 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 +434,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 +544,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 +613,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 +626,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 +675,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 +695,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 +715,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 +737,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 +750,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 +798,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 = XC3028_FE_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 */
@@ -675,7 +863,8 @@ static int dvb_register(struct cx8802_dev *dev)
cx88_call_i2c_clients (dev->core, TUNER_SET_STANDBY, NULL);
/* register everything */
- return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+ return videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev,
+ &dev->pci->dev, adapter_nr);
}
/* ----------------------------------------------------------- */
@@ -685,7 +874,7 @@ static int cx8802_dvb_advise_acquire(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
int err = 0;
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -708,7 +897,7 @@ static int cx8802_dvb_advise_release(struct cx8802_driver *drv)
{
struct cx88_core *core = drv->core;
int err = 0;
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
switch (core->boardnr) {
case CX88_BOARD_HAUPPAUGE_HVR1300:
@@ -726,7 +915,7 @@ static int cx8802_dvb_probe(struct cx8802_driver *drv)
struct cx8802_dev *dev = drv->core->dvbdev;
int err;
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
dprintk( 1, " ->being probed by Card=%d Name=%s, PCI %02x:%02x\n",
core->boardnr,
core->name,
@@ -744,8 +933,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),
@@ -764,7 +953,8 @@ static int cx8802_dvb_remove(struct cx8802_driver *drv)
struct cx8802_dev *dev = drv->core->dvbdev;
/* dvb */
- videobuf_dvb_unregister(&dev->dvb);
+ if (dev->dvb.frontend)
+ videobuf_dvb_unregister(&dev->dvb);
vp3054_i2c_remove(dev);
diff --git a/drivers/media/video/cx88/cx88-i2c.c b/drivers/media/video/cx88/cx88-i2c.c
index 566b26af523..c6b44732a08 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 bb0911b4d2f..53526d997a4 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 e357f415db0..a6b061c2644 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]");
@@ -146,7 +146,7 @@ static int cx8802_start_dma(struct cx8802_dev *dev,
cx_write(TS_GEN_CNTRL, 0x06); /* punctured clock TS & posedge driven */
udelay(100);
} else {
- printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __FUNCTION__,
+ printk( "%s() Failed. Unsupported value in .mpeg (0x%08x)\n", __func__,
core->board.mpeg );
return -EINVAL;
}
@@ -247,7 +247,7 @@ int cx8802_buf_prepare(struct videobuf_queue *q, struct cx8802_dev *dev,
struct videobuf_dmabuf *dma=videobuf_to_dma(&buf->vb);
int rc;
- dprintk(1, "%s: %p\n", __FUNCTION__, buf);
+ dprintk(1, "%s: %p\n", __func__, buf);
if (0 != buf->vb.baddr && buf->vb.bsize < size)
return -EINVAL;
@@ -289,7 +289,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
buf->count = cx88q->count++;
mod_timer(&cx88q->timeout, jiffies+BUFFER_TIMEOUT);
dprintk(1,"[%p/%d] %s - first active\n",
- buf, buf->vb.i, __FUNCTION__);
+ buf, buf->vb.i, __func__);
} else {
dprintk( 1, "queue is not empty - append to active\n" );
@@ -299,7 +299,7 @@ void cx8802_buf_queue(struct cx8802_dev *dev, struct cx88_buffer *buf)
buf->count = cx88q->count++;
prev->risc.jmp[1] = cpu_to_le32(buf->risc.dma);
dprintk( 1, "[%p/%d] %s - append to active\n",
- buf, buf->vb.i, __FUNCTION__);
+ buf, buf->vb.i, __func__);
}
}
@@ -342,7 +342,7 @@ static void cx8802_timeout(unsigned long data)
{
struct cx8802_dev *dev = (struct cx8802_dev*)data;
- dprintk(1, "%s\n",__FUNCTION__);
+ dprintk(1, "%s\n",__func__);
if (debug)
cx88_sram_channel_dump(dev->core, &cx88_sram_channels[SRAM_CH28]);
@@ -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);
@@ -623,7 +625,7 @@ static int cx8802_request_acquire(struct cx8802_driver *drv)
}
mutex_unlock(&drv->core->lock);
- mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+ mpeg_dbg(1,"%s() Post acquire GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
}
return 0;
@@ -639,7 +641,7 @@ static int cx8802_request_release(struct cx8802_driver *drv)
{
drv->advise_release(drv);
core->active_type_id = CX88_BOARD_NONE;
- mpeg_dbg(1,"%s() Post release GPIO=%x\n", __FUNCTION__, cx_read(MO_GP0_IO));
+ mpeg_dbg(1,"%s() Post release GPIO=%x\n", __func__, cx_read(MO_GP0_IO));
}
mutex_unlock(&drv->core->lock);
@@ -813,7 +815,7 @@ static void __devexit cx8802_remove(struct pci_dev *pci_dev)
dev = pci_get_drvdata(pci_dev);
- dprintk( 1, "%s\n", __FUNCTION__);
+ dprintk( 1, "%s\n", __func__);
if (!list_empty(&dev->drvlist)) {
struct cx8802_driver *drv, *tmp;
diff --git a/drivers/media/video/cx88/cx88-tvaudio.c b/drivers/media/video/cx88/cx88-tvaudio.c
index 76e5c78d8ae..3a1977f41e2 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)");
@@ -265,12 +265,12 @@ static void set_audio_standard_BTSC(struct cx88_core *core, unsigned int sap,
mode |= EN_FMRADIO_EN_RDS;
if (sap) {
- dprintk("%s SAP (status: unknown)\n", __FUNCTION__);
+ dprintk("%s SAP (status: unknown)\n", __func__);
set_audio_start(core, SEL_SAP);
set_audio_registers(core, btsc_sap);
set_audio_finish(core, mode);
} else {
- dprintk("%s (status: known-good)\n", __FUNCTION__);
+ dprintk("%s (status: known-good)\n", __func__);
set_audio_start(core, SEL_BTSC);
set_audio_registers(core, btsc);
set_audio_finish(core, mode);
@@ -351,16 +351,16 @@ static void set_audio_standard_NICAM(struct cx88_core *core, u32 mode)
set_audio_start(core,SEL_NICAM);
switch (core->tvaudio) {
case WW_L:
- dprintk("%s SECAM-L NICAM (status: devel)\n", __FUNCTION__);
+ dprintk("%s SECAM-L NICAM (status: devel)\n", __func__);
set_audio_registers(core, nicam_l);
break;
case WW_I:
- dprintk("%s PAL-I NICAM (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-I NICAM (status: known-good)\n", __func__);
set_audio_registers(core, nicam_bgdki_common);
set_audio_registers(core, nicam_i);
break;
default:
- dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-BGDK NICAM (status: known-good)\n", __func__);
set_audio_registers(core, nicam_bgdki_common);
set_audio_registers(core, nicam_default);
break;
@@ -600,28 +600,28 @@ static void set_audio_standard_A2(struct cx88_core *core, u32 mode)
set_audio_start(core, SEL_A2);
switch (core->tvaudio) {
case WW_BG:
- dprintk("%s PAL-BG A1/2 (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-BG A1/2 (status: known-good)\n", __func__);
set_audio_registers(core, a2_bgdk_common);
set_audio_registers(core, a2_bg);
set_audio_registers(core, a2_deemph50);
break;
case WW_DK:
- dprintk("%s PAL-DK A1/2 (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-DK A1/2 (status: known-good)\n", __func__);
set_audio_registers(core, a2_bgdk_common);
set_audio_registers(core, a2_dk);
set_audio_registers(core, a2_deemph50);
break;
case WW_I:
- dprintk("%s PAL-I A1 (status: known-good)\n", __FUNCTION__);
+ dprintk("%s PAL-I A1 (status: known-good)\n", __func__);
set_audio_registers(core, a1_i);
set_audio_registers(core, a2_deemph50);
break;
case WW_L:
- dprintk("%s AM-L (status: devel)\n", __FUNCTION__);
+ dprintk("%s AM-L (status: devel)\n", __func__);
set_audio_registers(core, am_l);
break;
default:
- dprintk("%s Warning: wrong value\n", __FUNCTION__);
+ dprintk("%s Warning: wrong value\n", __func__);
return;
break;
};
@@ -637,7 +637,7 @@ static void set_audio_standard_EIAJ(struct cx88_core *core)
{ /* end of list */ },
};
- dprintk("%s (status: unknown)\n", __FUNCTION__);
+ dprintk("%s (status: unknown)\n", __func__);
set_audio_start(core, SEL_EIAJ);
set_audio_registers(core, eiaj);
@@ -691,7 +691,7 @@ static void set_audio_standard_FM(struct cx88_core *core,
{ /* end of list */ },
};
- dprintk("%s (status: unknown)\n", __FUNCTION__);
+ dprintk("%s (status: unknown)\n", __func__);
set_audio_start(core, SEL_FMRADIO);
switch (deemph) {
diff --git a/drivers/media/video/cx88/cx88-vbi.c b/drivers/media/video/cx88/cx88-vbi.c
index d96ecfcf393..0943060682b 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 227179620d1..eea23f95edb 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 37e6d2e4002..14ac173f407 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 d14d803566a..cbd92635993 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 a5731f90be0..8d1f8ee2a53 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 9ceb6b2f394..88d6df71d05 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/Kconfig b/drivers/media/video/em28xx/Kconfig
index 0f7a0bd86ff..9caffed2b6b 100644
--- a/drivers/media/video/em28xx/Kconfig
+++ b/drivers/media/video/em28xx/Kconfig
@@ -1,11 +1,13 @@
config VIDEO_EM28XX
- tristate "Empia EM2800/2820/2840 USB video capture support"
+ tristate "Empia EM28xx USB video capture support"
depends on VIDEO_DEV && I2C && INPUT
select VIDEO_TUNER
select VIDEO_TVEEPROM
select VIDEO_IR
+ select VIDEOBUF_VMALLOC
select VIDEO_SAA711X if VIDEO_HELPER_CHIPS_AUTO
select VIDEO_TVP5150 if VIDEO_HELPER_CHIPS_AUTO
+ select VIDEO_MSP3400 if VIDEO_HELPER_CHIPS_AUTO
---help---
This is a video4linux driver for Empia 28xx based TV cards.
@@ -27,3 +29,13 @@ config VIDEO_EM28XX_ALSA
To compile this driver as a module, choose M here: the
module will be called em28xx-alsa
+config VIDEO_EM28XX_DVB
+ tristate "DVB/ATSC Support for em28xx based TV cards"
+ depends on VIDEO_EM28XX && DVB_CORE
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_ZL10353 if !DVB_FE_CUSTOMISE
+ select VIDEOBUF_DVB
+ select FW_LOADER
+ ---help---
+ This adds support for DVB cards based on the
+ Empiatech em28xx chips.
diff --git a/drivers/media/video/em28xx/Makefile b/drivers/media/video/em28xx/Makefile
index 0924550992d..3d1c3cc337f 100644
--- a/drivers/media/video/em28xx/Makefile
+++ b/drivers/media/video/em28xx/Makefile
@@ -5,6 +5,7 @@ em28xx-alsa-objs := em28xx-audio.o
obj-$(CONFIG_VIDEO_EM28XX) += em28xx.o
obj-$(CONFIG_VIDEO_EM28XX_ALSA) += em28xx-alsa.o
+obj-$(CONFIG_VIDEO_EM28XX_DVB) += em28xx-dvb.o
EXTRA_CFLAGS += -Idrivers/media/video
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
diff --git a/drivers/media/video/em28xx/em28xx-audio.c b/drivers/media/video/em28xx/em28xx-audio.c
index 8c67f678266..92b2a6db4fd 100644
--- a/drivers/media/video/em28xx/em28xx-audio.c
+++ b/drivers/media/video/em28xx/em28xx-audio.c
@@ -51,7 +51,7 @@ MODULE_PARM_DESC(debug, "activates debug info");
#define dprintk(fmt, arg...) do { \
if (debug) \
printk(KERN_INFO "em28xx-audio %s: " fmt, \
- __FUNCTION__, ##arg); \
+ __func__, ##arg); \
} while (0)
static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX;
diff --git a/drivers/media/video/em28xx/em28xx-cards.c b/drivers/media/video/em28xx/em28xx-cards.c
index aae7753fef1..50ccf377120 100644
--- a/drivers/media/video/em28xx/em28xx-cards.c
+++ b/drivers/media/video/em28xx/em28xx-cards.c
@@ -36,7 +36,6 @@
#include <media/v4l2-common.h>
#include "em28xx.h"
-#include "tuner-xc2028.h"
static int tuner = -1;
module_param(tuner, int, 0444);
@@ -52,26 +51,6 @@ struct em28xx_hash_table {
unsigned int tuner;
};
-/* Boards supported by driver */
-
-#define EM2800_BOARD_UNKNOWN 0
-#define EM2820_BOARD_UNKNOWN 1
-#define EM2820_BOARD_TERRATEC_CINERGY_250 2
-#define EM2820_BOARD_PINNACLE_USB_2 3
-#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
-#define EM2820_BOARD_MSI_VOX_USB_2 5
-#define EM2800_BOARD_TERRATEC_CINERGY_200 6
-#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
-#define EM2800_BOARD_KWORLD_USB2800 8
-#define EM2820_BOARD_PINNACLE_DVC_90 9
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
-#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
-#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
-#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
-#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
-#define EM2800_BOARD_VGEAR_POCKETTV 15
-#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16
-
struct em28xx_board em28xx_boards[] = {
[EM2800_BOARD_UNKNOWN] = {
.name = "Unknown EM2800 video grabber",
@@ -200,6 +179,7 @@ struct em28xx_board em28xx_boards[] = {
.tuner_type = TUNER_XC2028,
.mts_firmware = 1,
.has_12mhz_i2s = 1,
+ .has_dvb = 1,
.decoder = EM28XX_TVP5150,
.input = { {
.type = EM28XX_VMUX_TELEVISION,
@@ -214,9 +194,6 @@ struct em28xx_board em28xx_boards[] = {
.vmux = TVP5150_SVIDEO,
.amux = 1,
} },
-
- /* gpio's 4, 1, 0 */
- .analog_gpio = 0x003d2d,
},
[EM2880_BOARD_TERRATEC_HYBRID_XS] = {
.name = "Terratec Hybrid XS",
@@ -331,7 +308,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 = { {
@@ -453,7 +430,36 @@ struct usb_device_id em28xx_id_table [] = {
};
MODULE_DEVICE_TABLE(usb, em28xx_id_table);
-/* EEPROM hash table for devices with generic USB IDs */
+/*
+ * Reset sequences for analog/digital modes
+ */
+
+/* Board Hauppauge WinTV HVR 900 analog */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_analog[] = {
+ {EM28XX_R08_GPIO, 0x2d, ~EM_GPIO_4, 10},
+ {0x05, 0xff, 0x10, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 digital */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_digital[] = {
+ {EM28XX_R08_GPIO, 0x2e, ~EM_GPIO_4, 10},
+ {EM2880_R04_GPO, 0x04, 0x0f, 10},
+ {EM2880_R04_GPO, 0x0c, 0x0f, 10},
+ { -1, -1, -1, -1},
+};
+
+/* Board Hauppauge WinTV HVR 900 tuner_callback */
+static struct em28xx_reg_seq hauppauge_wintv_hvr_900_tuner_callback[] = {
+ {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ {EM28XX_R08_GPIO, 0, EM_GPIO_4, 10},
+ {EM28XX_R08_GPIO, EM_GPIO_4, EM_GPIO_4, 10},
+ { -1, -1, -1, -1},
+};
+
+/*
+ * EEPROM hash table for devices with generic USB IDs
+ */
static struct em28xx_hash_table em28xx_eeprom_hash [] = {
/* P/N: SA 60002070465 Tuner: TVF7533-MF */
{0x6ce05a8f, EM2820_BOARD_PROLINK_PLAYTV_USB2, TUNER_YMEC_TVF_5533MF},
@@ -465,79 +471,113 @@ static struct em28xx_hash_table em28xx_i2c_hash[] = {
{0xf51200e3, EM2800_BOARD_VGEAR_POCKETTV, TUNER_LG_PAL_NEW_TAPC},
};
+int em28xx_tuner_callback(void *ptr, int command, int arg)
+{
+ int rc = 0;
+ struct em28xx *dev = ptr;
+
+ if (dev->tuner_type != TUNER_XC2028)
+ return 0;
+
+ if (command != XC2028_TUNER_RESET)
+ return 0;
+
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_gpio_set(dev, dev->tun_analog_gpio);
+ else
+ rc = em28xx_gpio_set(dev, dev->tun_digital_gpio);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(em28xx_tuner_callback);
+
+static void em28xx_set_model(struct em28xx *dev)
+{
+ dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
+ dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
+ dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
+ dev->decoder = em28xx_boards[dev->model].decoder;
+ dev->video_inputs = em28xx_boards[dev->model].vchannels;
+ dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
+ dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
+ dev->has_dvb = em28xx_boards[dev->model].has_dvb;
+}
+
/* Since em28xx_pre_card_setup() requires a proper dev->model,
* this won't work for boards with generic PCI IDs
*/
void em28xx_pre_card_setup(struct em28xx *dev)
{
+ int rc;
+
+ rc = em28xx_read_reg(dev, EM2880_R04_GPO);
+ if (rc >= 0)
+ dev->reg_gpo = rc;
+
+ dev->wait_after_write = 5;
+ rc = em28xx_read_reg(dev, EM28XX_R0A_CHIPID);
+ if (rc > 0) {
+ switch (rc) {
+ case CHIP_ID_EM2883:
+ em28xx_info("chip ID is em2882/em2883\n");
+ dev->wait_after_write = 0;
+ break;
+ default:
+ em28xx_info("em28xx chip ID = %d\n", rc);
+ }
+ }
+ em28xx_set_model(dev);
+
/* request some modules */
switch (dev->model) {
case EM2880_BOARD_TERRATEC_PRODIGY_XS:
case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
- case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
case EM2880_BOARD_TERRATEC_HYBRID_XS:
- em28xx_write_regs(dev, XCLK_REG, "\x27", 1);
- em28xx_write_regs(dev, I2C_CLK_REG, "\x40", 1);
- em28xx_write_regs(dev, 0x08, "\xff", 1);
- em28xx_write_regs(dev, 0x04, "\x00", 1);
- msleep(100);
- em28xx_write_regs(dev, 0x04, "\x08", 1);
- msleep(100);
- em28xx_write_regs(dev, 0x08, "\xff", 1);
- msleep(50);
- em28xx_write_regs(dev, 0x08, "\x2d", 1);
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ em28xx_write_regs(dev, EM28XX_R0F_XCLK, "\x27", 1);
+ em28xx_write_regs(dev, EM28XX_R06_I2C_CLK, "\x40", 1);
msleep(50);
- em28xx_write_regs(dev, 0x08, "\x3d", 1);
+
+ /* Sets GPO/GPIO sequences for this device */
+ dev->analog_gpio = hauppauge_wintv_hvr_900_analog;
+ dev->digital_gpio = hauppauge_wintv_hvr_900_digital;
+ dev->tun_analog_gpio = hauppauge_wintv_hvr_900_tuner_callback;
+ dev->tun_digital_gpio = hauppauge_wintv_hvr_900_tuner_callback;
+
break;
}
+
+ em28xx_gpio_set(dev, dev->tun_analog_gpio);
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+
+ /* Unlock device */
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
}
-static int em28xx_tuner_callback(void *ptr, int command, int arg)
+static void em28xx_setup_xc3028(struct em28xx *dev, struct xc2028_ctrl *ctl)
{
- int rc = 0;
- struct em28xx *dev = ptr;
+ memset(ctl, 0, sizeof(*ctl));
- if (dev->tuner_type != TUNER_XC2028)
- return 0;
-
- switch (command) {
- case XC2028_TUNER_RESET:
- {
- /* GPIO and initialization codes for analog TV and radio
- This code should be complemented for DTV, since reset
- codes are different.
- */
-
- dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
- dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
-
- if (dev->analog_gpio) {
- char gpio0 = dev->analog_gpio & 0xff;
- char gpio1 = (dev->analog_gpio >> 8) & 0xff;
- char gpio4 = dev->analog_gpio >> 24;
-
- if (gpio4) {
- dev->em28xx_write_regs(dev, 0x04, &gpio4, 1);
- msleep(140);
- }
-
- msleep(6);
- dev->em28xx_write_regs(dev, 0x08, &gpio0, 1);
- msleep(10);
- dev->em28xx_write_regs(dev, 0x08, &gpio1, 1);
- msleep(5);
- }
+ ctl->fname = XC2028_DEFAULT_FIRMWARE;
+ ctl->max_len = 64;
+ ctl->mts = em28xx_boards[dev->model].mts_firmware;
+ switch (dev->model) {
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ ctl->demod = XC3028_FE_ZARLINK456;
break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ /* FIXME: Better to specify the needed IF */
+ ctl->demod = XC3028_FE_DEFAULT;
+ break;
+ default:
+ ctl->demod = XC3028_FE_OREN538;
}
- }
- return rc;
}
static void em28xx_config_tuner(struct em28xx *dev)
{
struct v4l2_priv_tun_config xc2028_cfg;
- struct xc2028_ctrl ctl;
struct tuner_setup tun_setup;
struct v4l2_frequency f;
@@ -552,11 +592,9 @@ static void em28xx_config_tuner(struct em28xx *dev)
em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
if (dev->tuner_type == TUNER_XC2028) {
- memset(&ctl, 0, sizeof(ctl));
+ struct xc2028_ctrl ctl;
- ctl.fname = XC2028_DEFAULT_FIRMWARE;
- ctl.max_len = 64;
- ctl.mts = em28xx_boards[dev->model].mts_firmware;
+ em28xx_setup_xc3028(dev, &ctl);
xc2028_cfg.tuner = TUNER_XC2028;
xc2028_cfg.priv = &ctl;
@@ -654,19 +692,6 @@ static int em28xx_hint_board(struct em28xx *dev)
return -1;
}
-
-static void em28xx_set_model(struct em28xx *dev)
-{
- dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
- dev->has_msp34xx = em28xx_boards[dev->model].has_msp34xx;
- dev->tda9887_conf = em28xx_boards[dev->model].tda9887_conf;
- dev->decoder = em28xx_boards[dev->model].decoder;
- dev->video_inputs = em28xx_boards[dev->model].vchannels;
- dev->analog_gpio = em28xx_boards[dev->model].analog_gpio;
- dev->has_12mhz_i2s = em28xx_boards[dev->model].has_12mhz_i2s;
- dev->max_range_640_480 = em28xx_boards[dev->model].max_range_640_480;
-}
-
/* ----------------------------------------------------------------------- */
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir)
{
diff --git a/drivers/media/video/em28xx/em28xx-core.c b/drivers/media/video/em28xx/em28xx-core.c
index c1caaa855b9..f8c41d8c74c 100644
--- a/drivers/media/video/em28xx/em28xx-core.c
+++ b/drivers/media/video/em28xx/em28xx-core.c
@@ -31,104 +31,33 @@
/* #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]");
#define em28xx_coredbg(fmt, arg...) do {\
if (core_debug) \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ dev->name, __func__ , ##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]");
#define em28xx_regdbg(fmt, arg...) do {\
if (reg_debug) \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
-
-static unsigned int isoc_debug = 0;
-module_param(isoc_debug,int,0644);
-MODULE_PARM_DESC(isoc_debug,"enable debug messages [isoc transfers]");
-
-#define em28xx_isocdbg(fmt, arg...) do {\
- if (isoc_debug) \
- printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ dev->name, __func__ , ##arg); } while (0)
static int alt = EM28XX_PINOUT;
module_param(alt, int, 0644);
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
-
-/*
- * em28xx_request_buffers()
- * allocate a number of buffers
- */
-u32 em28xx_request_buffers(struct em28xx *dev, u32 count)
-{
- const size_t imagesize = PAGE_ALIGN(dev->frame_size); /*needs to be page aligned cause the buffers can be mapped individually! */
- void *buff = NULL;
- u32 i;
- em28xx_coredbg("requested %i buffers with size %zi\n",
- count, imagesize);
- if (count > EM28XX_NUM_FRAMES)
- count = EM28XX_NUM_FRAMES;
-
- dev->num_frames = count;
- while (dev->num_frames > 0) {
- if ((buff = vmalloc_32(dev->num_frames * imagesize))) {
- memset(buff, 0, dev->num_frames * imagesize);
- break;
- }
- dev->num_frames--;
- }
-
- for (i = 0; i < dev->num_frames; i++) {
- dev->frame[i].bufmem = buff + i * imagesize;
- dev->frame[i].buf.index = i;
- dev->frame[i].buf.m.offset = i * imagesize;
- dev->frame[i].buf.length = dev->frame_size;
- dev->frame[i].buf.type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- dev->frame[i].buf.sequence = 0;
- dev->frame[i].buf.field = V4L2_FIELD_NONE;
- dev->frame[i].buf.memory = V4L2_MEMORY_MMAP;
- dev->frame[i].buf.flags = 0;
- }
- return dev->num_frames;
-}
-
-/*
- * em28xx_queue_unusedframes()
- * add all frames that are not currently in use to the inbuffer queue
- */
-void em28xx_queue_unusedframes(struct em28xx *dev)
-{
- unsigned long lock_flags;
- u32 i;
-
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].state == F_UNUSED) {
- dev->frame[i].state = F_QUEUED;
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_add_tail(&dev->frame[i].frame, &dev->inqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
- }
-}
-
-/*
- * em28xx_release_buffers()
- * free frame buffers
- */
-void em28xx_release_buffers(struct em28xx *dev)
-{
- if (dev->num_frames) {
- vfree(dev->frame[0].bufmem);
- dev->num_frames = 0;
- }
-}
+/* FIXME */
+#define em28xx_isocdbg(fmt, arg...) do {\
+ if (core_debug) \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); } while (0)
/*
* em28xx_read_reg_req()
@@ -148,11 +77,11 @@ int em28xx_read_reg_req_len(struct em28xx *dev, u8 req, u16 reg,
USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, reg, buf, len, HZ);
- if (reg_debug){
+ if (reg_debug) {
printk(ret < 0 ? " failed!\n" : "%02x values: ", ret);
- for (byte = 0; byte < len; byte++) {
+ for (byte = 0; byte < len; byte++)
printk(" %02x", (unsigned char)buf[byte]);
- }
+
printk("\n");
}
@@ -205,7 +134,10 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
unsigned char *bufs;
if (dev->state & DEV_DISCONNECTED)
- return(-ENODEV);
+ return -ENODEV;
+
+ if (len < 1)
+ return -EINVAL;
bufs = kmalloc(len, GFP_KERNEL);
@@ -214,8 +146,8 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
if (reg_debug) {
int i;
for (i = 0; i < len; ++i)
- printk (" %02x", (unsigned char)buf[i]);
- printk ("\n");
+ printk(" %02x", (unsigned char)buf[i]);
+ printk("\n");
}
if (!bufs)
@@ -224,14 +156,32 @@ int em28xx_write_regs_req(struct em28xx *dev, u8 req, u16 reg, char *buf,
ret = usb_control_msg(dev->udev, usb_sndctrlpipe(dev->udev, 0), req,
USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
0x0000, reg, bufs, len, HZ);
- msleep(5); /* FIXME: magic number */
+ if (dev->wait_after_write)
+ msleep(dev->wait_after_write);
+
kfree(bufs);
return ret;
}
int em28xx_write_regs(struct em28xx *dev, u16 reg, char *buf, int len)
{
- return em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+ int rc;
+
+ rc = em28xx_write_regs_req(dev, USB_REQ_GET_STATUS, reg, buf, len);
+
+ /* Stores GPO/GPIO values at the cache, if changed
+ Only write values should be stored, since input on a GPIO
+ register will return the input bits.
+ Not sure what happens on reading GPO register.
+ */
+ if (rc >= 0) {
+ if (reg == EM2880_R04_GPO)
+ dev->reg_gpo = buf[0];
+ else if (reg == EM28XX_R08_GPIO)
+ dev->reg_gpio = buf[0];
+ }
+
+ return rc;
}
/*
@@ -244,9 +194,20 @@ static int em28xx_write_reg_bits(struct em28xx *dev, u16 reg, u8 val,
{
int oldval;
u8 newval;
- if ((oldval = em28xx_read_reg(dev, reg)) < 0)
+
+ /* Uses cache for gpo/gpio registers */
+ if (reg == EM2880_R04_GPO)
+ oldval = dev->reg_gpo;
+ else if (reg == EM28XX_R08_GPIO)
+ oldval = dev->reg_gpio;
+ else
+ oldval = em28xx_read_reg(dev, reg);
+
+ if (oldval < 0)
return oldval;
+
newval = (((u8) oldval) & ~bitmask) | (val & bitmask);
+
return em28xx_write_regs(dev, reg, &newval, 1);
}
@@ -258,20 +219,26 @@ static int em28xx_write_ac97(struct em28xx *dev, u8 reg, u8 *val)
{
int ret, i;
u8 addr = reg & 0x7f;
- if ((ret = em28xx_write_regs(dev, AC97LSB_REG, val, 2)) < 0)
+
+ ret = em28xx_write_regs(dev, EM28XX_R40_AC97LSB, val, 2);
+ if (ret < 0)
return ret;
- if ((ret = em28xx_write_regs(dev, AC97ADDR_REG, &addr, 1)) < 0)
+
+ ret = em28xx_write_regs(dev, EM28XX_R42_AC97ADDR, &addr, 1);
+ if (ret < 0)
return ret;
/* Wait up to 50 ms for AC97 command to complete */
for (i = 0; i < 10; i++) {
- if ((ret = em28xx_read_reg(dev, AC97BUSY_REG)) < 0)
+ ret = em28xx_read_reg(dev, EM28XX_R43_AC97BUSY);
+ if (ret < 0)
return ret;
+
if (!(ret & 0x01))
return 0;
msleep(5);
}
- em28xx_warn ("AC97 command still being executed: not handled properly!\n");
+ em28xx_warn("AC97 command still being executed: not handled properly!\n");
return 0;
}
@@ -289,7 +256,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
else
input = EM2800_AUDIO_SRC_TUNER;
- ret = em28xx_write_regs(dev, EM2800_AUDIOSRC_REG, &input, 1);
+ ret = em28xx_write_regs(dev, EM2800_R08_AUDIOSRC, &input, 1);
if (ret < 0)
return ret;
}
@@ -315,7 +282,7 @@ static int em28xx_set_audio_source(struct em28xx *dev)
}
}
- ret = em28xx_write_reg_bits(dev, AUDIOSRC_REG, input, 0xc0);
+ ret = em28xx_write_reg_bits(dev, EM28XX_R0E_AUDIOSRC, input, 0xc0);
if (ret < 0)
return ret;
msleep(5);
@@ -323,11 +290,11 @@ static int em28xx_set_audio_source(struct em28xx *dev)
/* Sets AC97 mixer registers
This is seems to be needed, even for non-ac97 configs
*/
- ret = em28xx_write_ac97(dev, VIDEO_AC97, video);
+ ret = em28xx_write_ac97(dev, EM28XX_R14_VIDEO_AC97, video);
if (ret < 0)
return ret;
- ret = em28xx_write_ac97(dev, LINE_IN_AC97, line);
+ ret = em28xx_write_ac97(dev, EM28XX_R10_LINE_IN_AC97, line);
return ret;
}
@@ -343,7 +310,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
/* Mute */
s[1] |= 0x80;
- ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+ ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
if (ret < 0)
return ret;
@@ -354,7 +321,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
if (!dev->mute)
xclk |= 0x80;
- ret = em28xx_write_reg_bits(dev, XCLK_REG, xclk, 0xa7);
+ ret = em28xx_write_reg_bits(dev, EM28XX_R0F_XCLK, xclk, 0xa7);
if (ret < 0)
return ret;
msleep(10);
@@ -365,7 +332,7 @@ int em28xx_audio_analog_set(struct em28xx *dev)
/* Unmute device */
if (!dev->mute)
s[1] &= ~0x80;
- ret = em28xx_write_ac97(dev, MASTER_AC97, s);
+ ret = em28xx_write_ac97(dev, EM28XX_R02_MASTER_AC97, s);
return ret;
}
@@ -373,50 +340,68 @@ EXPORT_SYMBOL_GPL(em28xx_audio_analog_set);
int em28xx_colorlevels_set_default(struct em28xx *dev)
{
- em28xx_write_regs(dev, YGAIN_REG, "\x10", 1); /* contrast */
- em28xx_write_regs(dev, YOFFSET_REG, "\x00", 1); /* brightness */
- em28xx_write_regs(dev, UVGAIN_REG, "\x10", 1); /* saturation */
- em28xx_write_regs(dev, UOFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, VOFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, SHARPNESS_REG, "\x00", 1);
-
- em28xx_write_regs(dev, GAMMA_REG, "\x20", 1);
- em28xx_write_regs(dev, RGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, GGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, BGAIN_REG, "\x20", 1);
- em28xx_write_regs(dev, ROFFSET_REG, "\x00", 1);
- em28xx_write_regs(dev, GOFFSET_REG, "\x00", 1);
- return em28xx_write_regs(dev, BOFFSET_REG, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R20_YGAIN, "\x10", 1); /* contrast */
+ em28xx_write_regs(dev, EM28XX_R21_YOFFSET, "\x00", 1); /* brightness */
+ em28xx_write_regs(dev, EM28XX_R22_UVGAIN, "\x10", 1); /* saturation */
+ em28xx_write_regs(dev, EM28XX_R23_UOFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R24_VOFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R25_SHARPNESS, "\x00", 1);
+
+ em28xx_write_regs(dev, EM28XX_R14_GAMMA, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R15_RGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R16_GGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R17_BGAIN, "\x20", 1);
+ em28xx_write_regs(dev, EM28XX_R18_ROFFSET, "\x00", 1);
+ em28xx_write_regs(dev, EM28XX_R19_GOFFSET, "\x00", 1);
+ return em28xx_write_regs(dev, EM28XX_R1A_BOFFSET, "\x00", 1);
}
int em28xx_capture_start(struct em28xx *dev, int start)
{
- int ret;
+ int rc;
/* FIXME: which is the best order? */
/* video registers are sampled by VREF */
- if ((ret = em28xx_write_reg_bits(dev, USBSUSP_REG, start ? 0x10 : 0x00,
- 0x10)) < 0)
- return ret;
+ rc = em28xx_write_reg_bits(dev, EM28XX_R0C_USBSUSP,
+ start ? 0x10 : 0x00, 0x10);
+ if (rc < 0)
+ return rc;
+
+ if (!start) {
+ /* disable video capture */
+ rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x27", 1);
+ return rc;
+ }
+
/* enable video capture */
- return em28xx_write_regs(dev, VINENABLE_REG, start ? "\x67" : "\x27", 1);
+ rc = em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x67", 1);
+ else
+ rc = em28xx_write_regs(dev, EM28XX_R12_VINENABLE, "\x37", 1);
+
+ msleep(6);
+
+ return rc;
}
int em28xx_outfmt_set_yuv422(struct em28xx *dev)
{
- em28xx_write_regs(dev, OUTFMT_REG, "\x34", 1);
- em28xx_write_regs(dev, VINMODE_REG, "\x10", 1);
- return em28xx_write_regs(dev, VINCTRL_REG, "\x11", 1);
+ em28xx_write_regs(dev, EM28XX_R27_OUTFMT, "\x34", 1);
+ em28xx_write_regs(dev, EM28XX_R10_VINMODE, "\x10", 1);
+ return em28xx_write_regs(dev, EM28XX_R11_VINCTRL, "\x11", 1);
}
static int em28xx_accumulator_set(struct em28xx *dev, u8 xmin, u8 xmax,
u8 ymin, u8 ymax)
{
- em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n", xmin, ymin, xmax, ymax);
+ em28xx_coredbg("em28xx Scale: (%d,%d)-(%d,%d)\n",
+ xmin, ymin, xmax, ymax);
- em28xx_write_regs(dev, XMIN_REG, &xmin, 1);
- em28xx_write_regs(dev, XMAX_REG, &xmax, 1);
- em28xx_write_regs(dev, YMIN_REG, &ymin, 1);
- return em28xx_write_regs(dev, YMAX_REG, &ymax, 1);
+ em28xx_write_regs(dev, EM28XX_R28_XMIN, &xmin, 1);
+ em28xx_write_regs(dev, EM28XX_R29_XMAX, &xmax, 1);
+ em28xx_write_regs(dev, EM28XX_R2A_YMIN, &ymin, 1);
+ return em28xx_write_regs(dev, EM28XX_R2B_YMAX, &ymax, 1);
}
static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
@@ -426,34 +411,36 @@ static int em28xx_capture_area_set(struct em28xx *dev, u8 hstart, u8 vstart,
u8 cheight = height;
u8 overflow = (height >> 7 & 0x02) | (width >> 8 & 0x01);
- em28xx_coredbg("em28xx Area Set: (%d,%d)\n", (width | (overflow & 2) << 7),
+ em28xx_coredbg("em28xx Area Set: (%d,%d)\n",
+ (width | (overflow & 2) << 7),
(height | (overflow & 1) << 8));
- em28xx_write_regs(dev, HSTART_REG, &hstart, 1);
- em28xx_write_regs(dev, VSTART_REG, &vstart, 1);
- em28xx_write_regs(dev, CWIDTH_REG, &cwidth, 1);
- em28xx_write_regs(dev, CHEIGHT_REG, &cheight, 1);
- return em28xx_write_regs(dev, OFLOW_REG, &overflow, 1);
+ em28xx_write_regs(dev, EM28XX_R1C_HSTART, &hstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1D_VSTART, &vstart, 1);
+ em28xx_write_regs(dev, EM28XX_R1E_CWIDTH, &cwidth, 1);
+ em28xx_write_regs(dev, EM28XX_R1F_CHEIGHT, &cheight, 1);
+ return em28xx_write_regs(dev, EM28XX_R1B_OFLOW, &overflow, 1);
}
static int em28xx_scaler_set(struct em28xx *dev, u16 h, u16 v)
{
u8 mode;
/* the em2800 scaler only supports scaling down to 50% */
- if(dev->is_em2800)
+ if (dev->is_em2800)
mode = (v ? 0x20 : 0x00) | (h ? 0x10 : 0x00);
else {
u8 buf[2];
buf[0] = h;
buf[1] = h >> 8;
- em28xx_write_regs(dev, HSCALELOW_REG, (char *)buf, 2);
+ em28xx_write_regs(dev, EM28XX_R30_HSCALELOW, (char *)buf, 2);
buf[0] = v;
buf[1] = v >> 8;
- em28xx_write_regs(dev, VSCALELOW_REG, (char *)buf, 2);
- /* it seems that both H and V scalers must be active to work correctly */
+ em28xx_write_regs(dev, EM28XX_R32_VSCALELOW, (char *)buf, 2);
+ /* it seems that both H and V scalers must be active
+ to work correctly */
mode = (h || v)? 0x30: 0x00;
}
- return em28xx_write_reg_bits(dev, COMPR_REG, mode, 0x30);
+ return em28xx_write_reg_bits(dev, EM28XX_R26_COMPR, mode, 0x30);
}
/* FIXME: this only function read values from dev */
@@ -469,376 +456,271 @@ int em28xx_resolution_set(struct em28xx *dev)
return em28xx_scaler_set(dev, dev->hscale, dev->vscale);
}
-
-/******************* isoc transfer handling ****************************/
-
-#ifdef ENABLE_DEBUG_ISOC_FRAMES
-static void em28xx_isoc_dump(struct urb *urb)
+int em28xx_set_alternate(struct em28xx *dev)
{
- int len = 0;
- int ntrans = 0;
+ int errCode, prev_alt = dev->alt;
int i;
+ unsigned int min_pkt_size = dev->width * 2 + 4;
- printk(KERN_DEBUG "isocIrq: sf=%d np=%d ec=%x\n",
- urb->start_frame, urb->number_of_packets,
- urb->error_count);
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned char *buf =
- urb->transfer_buffer +
- urb->iso_frame_desc[i].offset;
- int alen = urb->iso_frame_desc[i].actual_length;
- if (alen > 0) {
- if (buf[0] == 0x88) {
- ntrans++;
- len += alen;
- } else if (buf[0] == 0x22) {
- printk(KERN_DEBUG
- "= l=%d nt=%d bpp=%d\n",
- len - 4 * ntrans, ntrans,
- ntrans == 0 ? 0 : len / ntrans);
- ntrans = 1;
- len = alen;
- } else
- printk(KERN_DEBUG "!\n");
+ /* When image size is bigger than a certain value,
+ the frame size should be increased, otherwise, only
+ green screen will be received.
+ */
+ if (dev->width * 2 * dev->height > 720 * 240 * 2)
+ min_pkt_size *= 2;
+
+ 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;
+ /* 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",
+ min_pkt_size, dev->alt);
+ dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
+ em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
+ dev->alt, dev->max_pkt_size);
+ errCode = usb_set_interface(dev->udev, 0, dev->alt);
+ if (errCode < 0) {
+ em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
+ dev->alt, errCode);
+ return errCode;
}
- printk(KERN_DEBUG " n=%d s=%d al=%d %x\n", i,
- urb->iso_frame_desc[i].status,
- urb->iso_frame_desc[i].actual_length,
- (unsigned int)
- *((unsigned char *)(urb->transfer_buffer +
- urb->iso_frame_desc[i].
- offset)));
}
+ return 0;
}
-#endif
-static inline int em28xx_isoc_video(struct em28xx *dev,struct em28xx_frame_t **f,
- unsigned long *lock_flags, unsigned char buf)
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
{
- if (!(buf & 0x01)) {
- if ((*f)->state == F_GRABBING) {
- /*previous frame is incomplete */
- if ((*f)->fieldbytesused < dev->field_size) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("dropping incomplete bottom field (%i missing bytes)",
- dev->field_size-(*f)->fieldbytesused);
- } else {
- (*f)->state = F_DONE;
- (*f)->buf.bytesused = dev->frame_size;
- }
- }
- if ((*f)->state == F_DONE || (*f)->state == F_ERROR) {
- /* move current frame to outqueue and get next free buffer from inqueue */
- spin_lock_irqsave(&dev-> queue_lock, *lock_flags);
- list_move_tail(&(*f)->frame, &dev->outqueue);
- if (!list_empty(&dev->inqueue))
- (*f) = list_entry(dev-> inqueue.next,
- struct em28xx_frame_t,frame);
- else
- (*f) = NULL;
- spin_unlock_irqrestore(&dev->queue_lock,*lock_flags);
- }
- if (!(*f)) {
- em28xx_isocdbg ("new frame but no buffer is free");
- return -1;
- }
- do_gettimeofday(&(*f)->buf.timestamp);
- (*f)->buf.sequence = ++dev->frame_count;
- (*f)->buf.field = V4L2_FIELD_INTERLACED;
- (*f)->state = F_GRABBING;
- (*f)->buf.bytesused = 0;
- (*f)->top_field = 1;
- (*f)->fieldbytesused = 0;
- } else {
- /* acquiring bottom field */
- if ((*f)->state == F_GRABBING) {
- if (!(*f)->top_field) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("unexpected begin of bottom field; discarding it");
- } else if ((*f)-> fieldbytesused < dev->field_size - 172) {
- (*f)->state = F_ERROR;
- em28xx_isocdbg ("dropping incomplete top field (%i missing bytes)",
- dev->field_size-(*f)->fieldbytesused);
- } else {
- (*f)->top_field = 0;
- (*f)->fieldbytesused = 0;
- }
+ int rc = 0;
+
+ if (!gpio)
+ return rc;
+
+ dev->em28xx_write_regs_req(dev, 0x00, 0x48, "\x00", 1);
+ if (dev->mode == EM28XX_ANALOG_MODE)
+ dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x67", 1);
+ else
+ dev->em28xx_write_regs_req(dev, 0x00, 0x12, "\x37", 1);
+ msleep(6);
+
+ /* Send GPIO reset sequences specified at board entry */
+ while (gpio->sleep >= 0) {
+ if (gpio->reg >= 0) {
+ rc = em28xx_write_reg_bits(dev,
+ gpio->reg,
+ gpio->val,
+ gpio->mask);
+ if (rc < 0)
+ return rc;
}
+ if (gpio->sleep > 0)
+ msleep(gpio->sleep);
+
+ gpio++;
}
- return (0);
+ return rc;
}
-static inline void em28xx_isoc_video_copy(struct em28xx *dev,
- struct em28xx_frame_t **f, unsigned char *buf, int len)
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
{
- void *fieldstart, *startwrite, *startread;
- int linesdone, currlinedone, offset, lencopy,remain;
+ if (dev->mode == set_mode)
+ return 0;
- if(dev->frame_size != (*f)->buf.length){
- em28xx_err("frame_size %i and buf.length %i are different!!!\n",dev->frame_size,(*f)->buf.length);
- return;
+ if (set_mode == EM28XX_MODE_UNDEFINED) {
+ dev->mode = set_mode;
+ return 0;
}
- if ((*f)->fieldbytesused + len > dev->field_size)
- len =dev->field_size - (*f)->fieldbytesused;
-
- if (buf[0] != 0x88 && buf[0] != 0x22) {
- em28xx_isocdbg("frame is not complete\n");
- startread = buf;
- len+=4;
- } else
- startread = buf + 4;
-
- remain = len;
+ dev->mode = set_mode;
- if ((*f)->top_field)
- fieldstart = (*f)->bufmem;
+ if (dev->mode == EM28XX_DIGITAL_MODE)
+ return em28xx_gpio_set(dev, dev->digital_gpio);
else
- fieldstart = (*f)->bufmem + dev->bytesperline;
-
- linesdone = (*f)->fieldbytesused / dev->bytesperline;
- currlinedone = (*f)->fieldbytesused % dev->bytesperline;
- offset = linesdone * dev->bytesperline * 2 + currlinedone;
- startwrite = fieldstart + offset;
- lencopy = dev->bytesperline - currlinedone;
- lencopy = lencopy > remain ? remain : lencopy;
-
- memcpy(startwrite, startread, lencopy);
- remain -= lencopy;
-
- while (remain > 0) {
- startwrite += lencopy + dev->bytesperline;
- startread += lencopy;
- if (dev->bytesperline > remain)
- lencopy = remain;
- else
- lencopy = dev->bytesperline;
-
- memcpy(startwrite, startread, lencopy);
- remain -= lencopy;
- }
-
- (*f)->fieldbytesused += len;
+ return em28xx_gpio_set(dev, dev->analog_gpio);
}
+EXPORT_SYMBOL_GPL(em28xx_set_mode);
+
+/* ------------------------------------------------------------------
+ URB control
+ ------------------------------------------------------------------*/
/*
- * em28xx_isoIrq()
- * handles the incoming isoc urbs and fills the frames from our inqueue
+ * IRQ callback, called by URB callback
*/
-static void em28xx_isocIrq(struct urb *urb)
+static void em28xx_irq_callback(struct urb *urb)
{
- struct em28xx *dev = urb->context;
- int i, status;
- struct em28xx_frame_t **f;
- unsigned long lock_flags;
-
- if (!dev)
- return;
-#ifdef ENABLE_DEBUG_ISOC_FRAMES
- if (isoc_debug>1)
- em28xx_isoc_dump(urb);
-#endif
-
- if (urb->status == -ENOENT)
- return;
-
- f = &dev->frame_current;
-
- if (dev->stream == STREAM_INTERRUPT) {
- dev->stream = STREAM_OFF;
- if ((*f))
- (*f)->state = F_QUEUED;
- em28xx_isocdbg("stream interrupted");
- wake_up_interruptible(&dev->wait_stream);
- }
-
- if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
- return;
-
- if (dev->stream == STREAM_ON && !list_empty(&dev->inqueue)) {
- if (!(*f))
- (*f) = list_entry(dev->inqueue.next,
- struct em28xx_frame_t, frame);
-
- for (i = 0; i < urb->number_of_packets; i++) {
- unsigned char *buf = urb->transfer_buffer +
- urb->iso_frame_desc[i].offset;
- int len = urb->iso_frame_desc[i].actual_length - 4;
-
- if (urb->iso_frame_desc[i].status) {
- em28xx_isocdbg("data error: [%d] len=%d, status=%d", i,
- urb->iso_frame_desc[i].actual_length,
- urb->iso_frame_desc[i].status);
- if (urb->iso_frame_desc[i].status != -EPROTO)
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length <= 0) {
- em28xx_isocdbg("packet %d is empty",i);
- continue;
- }
- if (urb->iso_frame_desc[i].actual_length >
- urb->iso_frame_desc[i].length) {
- em28xx_isocdbg("packet bigger than packet size");
- continue;
- }
- /*new frame */
- if (buf[0] == 0x22 && buf[1] == 0x5a) {
- em28xx_isocdbg("Video frame, length=%i!",len);
-
- if (em28xx_isoc_video(dev,f,&lock_flags,buf[2]))
- break;
- } else if (buf[0]==0x33 && buf[1]==0x95 && buf[2]==0x00) {
- em28xx_isocdbg("VBI HEADER!!!");
- }
+ struct em28xx_dmaqueue *dma_q = urb->context;
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ int rc, i;
- /* actual copying */
- if ((*f)->state == F_GRABBING) {
- em28xx_isoc_video_copy(dev,f,buf, len);
- }
- }
- }
+ /* Copy data from URB */
+ spin_lock(&dev->slock);
+ rc = dev->isoc_ctl.isoc_copy(dev, urb);
+ spin_unlock(&dev->slock);
+ /* Reset urb buffers */
for (i = 0; i < urb->number_of_packets; i++) {
urb->iso_frame_desc[i].status = 0;
urb->iso_frame_desc[i].actual_length = 0;
}
-
urb->status = 0;
- if ((status = usb_submit_urb(urb, GFP_ATOMIC))) {
- em28xx_errdev("resubmit of urb failed (error=%i)\n", status);
- dev->state |= DEV_MISCONFIGURED;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ em28xx_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
}
- wake_up_interruptible(&dev->wait_frame);
- return;
}
/*
- * em28xx_uninit_isoc()
- * deallocates the buffers and urbs allocated during em28xx_init_iosc()
+ * Stop and Deallocate URBs
*/
void em28xx_uninit_isoc(struct em28xx *dev)
{
+ struct urb *urb;
int i;
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- if (dev->urb[i]) {
- usb_kill_urb(dev->urb[i]);
- if (dev->transfer_buffer[i]) {
+ em28xx_isocdbg("em28xx: called em28xx_uninit_isoc\n");
+
+ dev->isoc_ctl.nfields = -1;
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = dev->isoc_ctl.urb[i];
+ if (urb) {
+ usb_kill_urb(urb);
+ usb_unlink_urb(urb);
+ if (dev->isoc_ctl.transfer_buffer[i]) {
usb_buffer_free(dev->udev,
- dev->urb[i]->transfer_buffer_length,
- dev->transfer_buffer[i],
- dev->urb[i]->transfer_dma);
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
}
- usb_free_urb(dev->urb[i]);
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[i] = NULL;
}
- dev->urb[i] = NULL;
- dev->transfer_buffer[i] = NULL;
+ dev->isoc_ctl.transfer_buffer[i] = NULL;
}
+
+ kfree(dev->isoc_ctl.urb);
+ kfree(dev->isoc_ctl.transfer_buffer);
+
+ dev->isoc_ctl.urb = NULL;
+ dev->isoc_ctl.transfer_buffer = NULL;
+ dev->isoc_ctl.num_bufs = 0;
+
em28xx_capture_start(dev, 0);
}
+EXPORT_SYMBOL_GPL(em28xx_uninit_isoc);
/*
- * em28xx_init_isoc()
- * allocates transfer buffers and submits the urbs for isoc transfer
+ * Allocate URBs and start IRQ
*/
-int em28xx_init_isoc(struct em28xx *dev)
+int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb))
{
- /* change interface to 3 which allows the biggest packet sizes */
- int i, errCode;
- int sb_size;
-
- em28xx_set_alternate(dev);
- sb_size = EM28XX_NUM_PACKETS * dev->max_pkt_size;
-
- /* reset streaming vars */
- dev->frame_current = NULL;
- dev->frame_count = 0;
-
- /* allocate urbs */
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- struct urb *urb;
- int j;
- /* allocate transfer buffer */
- urb = usb_alloc_urb(EM28XX_NUM_PACKETS, GFP_KERNEL);
- if (!urb){
- em28xx_errdev("cannot alloc urb %i\n", i);
+ struct em28xx_dmaqueue *dma_q = &dev->vidq;
+ int i;
+ int sb_size, pipe;
+ struct urb *urb;
+ int j, k;
+ int rc;
+
+ em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
+
+ /* De-allocates all pending stuff */
+ em28xx_uninit_isoc(dev);
+
+ dev->isoc_ctl.isoc_copy = isoc_copy;
+ dev->isoc_ctl.num_bufs = num_bufs;
+
+ dev->isoc_ctl.urb = kzalloc(sizeof(void *)*num_bufs, GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ em28xx_errdev("cannot alloc memory for usb buffers\n");
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.transfer_buffer = kzalloc(sizeof(void *)*num_bufs,
+ GFP_KERNEL);
+ if (!dev->isoc_ctl.urb) {
+ em28xx_errdev("cannot allocate memory for usbtransfer\n");
+ kfree(dev->isoc_ctl.urb);
+ return -ENOMEM;
+ }
+
+ dev->isoc_ctl.max_pkt_size = max_pkt_size;
+ dev->isoc_ctl.buf = NULL;
+
+ sb_size = max_packets * dev->isoc_ctl.max_pkt_size;
+
+ /* allocate urbs and transfer buffers */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ urb = usb_alloc_urb(max_packets, GFP_KERNEL);
+ if (!urb) {
+ em28xx_err("cannot alloc isoc_ctl.urb %i\n", i);
em28xx_uninit_isoc(dev);
return -ENOMEM;
}
- dev->transfer_buffer[i] = usb_buffer_alloc(dev->udev, sb_size,
- GFP_KERNEL,
- &urb->transfer_dma);
- if (!dev->transfer_buffer[i]) {
- em28xx_errdev
- ("unable to allocate %i bytes for transfer buffer %i\n",
- sb_size, i);
+ dev->isoc_ctl.urb[i] = urb;
+
+ dev->isoc_ctl.transfer_buffer[i] = usb_buffer_alloc(dev->udev,
+ sb_size, GFP_KERNEL, &urb->transfer_dma);
+ if (!dev->isoc_ctl.transfer_buffer[i]) {
+ em28xx_err("unable to allocate %i bytes for transfer"
+ " buffer %i%s\n",
+ sb_size, i,
+ in_interrupt()?" while in int":"");
em28xx_uninit_isoc(dev);
- usb_free_urb(urb);
return -ENOMEM;
}
- memset(dev->transfer_buffer[i], 0, sb_size);
- urb->dev = dev->udev;
- urb->context = dev;
- urb->pipe = usb_rcvisocpipe(dev->udev, 0x82);
- urb->transfer_flags = URB_ISO_ASAP | URB_NO_TRANSFER_DMA_MAP;
- urb->interval = 1;
- urb->transfer_buffer = dev->transfer_buffer[i];
- urb->complete = em28xx_isocIrq;
- urb->number_of_packets = EM28XX_NUM_PACKETS;
- urb->transfer_buffer_length = sb_size;
- for (j = 0; j < EM28XX_NUM_PACKETS; j++) {
- urb->iso_frame_desc[j].offset = j * dev->max_pkt_size;
- urb->iso_frame_desc[j].length = dev->max_pkt_size;
+ memset(dev->isoc_ctl.transfer_buffer[i], 0, sb_size);
+
+ /* FIXME: this is a hack - should be
+ 'desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK'
+ should also be using 'desc.bInterval'
+ */
+ pipe = usb_rcvisocpipe(dev->udev,
+ dev->mode == EM28XX_ANALOG_MODE ? 0x82 : 0x84);
+
+ usb_fill_int_urb(urb, dev->udev, pipe,
+ dev->isoc_ctl.transfer_buffer[i], sb_size,
+ em28xx_irq_callback, dma_q, 1);
+
+ urb->number_of_packets = max_packets;
+ urb->transfer_flags = URB_ISO_ASAP;
+
+ k = 0;
+ for (j = 0; j < max_packets; j++) {
+ urb->iso_frame_desc[j].offset = k;
+ urb->iso_frame_desc[j].length =
+ dev->isoc_ctl.max_pkt_size;
+ k += dev->isoc_ctl.max_pkt_size;
}
- dev->urb[i] = urb;
}
- /* submit urbs */
- em28xx_coredbg("Submitting %d urbs of %d packets (%d each)\n",
- EM28XX_NUM_BUFS, EM28XX_NUM_PACKETS, dev->max_pkt_size);
- for (i = 0; i < EM28XX_NUM_BUFS; i++) {
- errCode = usb_submit_urb(dev->urb[i], GFP_KERNEL);
- if (errCode) {
- em28xx_errdev("submit of urb %i failed (error=%i)\n", i,
- errCode);
- em28xx_uninit_isoc(dev);
- return errCode;
- }
- }
-
- return 0;
-}
-
-int em28xx_set_alternate(struct em28xx *dev)
-{
- int errCode, prev_alt = dev->alt;
- int i;
- unsigned int min_pkt_size = dev->bytesperline+4;
-
- /* When image size is bigger than a ceirtain 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;
+ init_waitqueue_head(&dma_q->wq);
- for (i = 0; i < dev->num_alt; i++)
- if (dev->alt_max_pkt_size[i] >= min_pkt_size)
- break;
- dev->alt = i;
+ em28xx_capture_start(dev, 1);
- if (dev->alt != prev_alt) {
- em28xx_coredbg("minimum isoc packet size: %u (alt=%d)\n",
- min_pkt_size, dev->alt);
- dev->max_pkt_size = dev->alt_max_pkt_size[dev->alt];
- em28xx_coredbg("setting alternate %d with wMaxPacketSize=%u\n",
- dev->alt, dev->max_pkt_size);
- errCode = usb_set_interface(dev->udev, 0, dev->alt);
- if (errCode < 0) {
- em28xx_errdev ("cannot change alternate number to %d (error=%i)\n",
- dev->alt, errCode);
- return errCode;
+ /* submit urbs and enables IRQ */
+ for (i = 0; i < dev->isoc_ctl.num_bufs; i++) {
+ rc = usb_submit_urb(dev->isoc_ctl.urb[i], GFP_ATOMIC);
+ if (rc) {
+ em28xx_err("submit of urb %i failed (error=%i)\n", i,
+ rc);
+ em28xx_uninit_isoc(dev);
+ return rc;
}
}
+
return 0;
}
+EXPORT_SYMBOL_GPL(em28xx_init_isoc);
diff --git a/drivers/media/video/em28xx/em28xx-dvb.c b/drivers/media/video/em28xx/em28xx-dvb.c
new file mode 100644
index 00000000000..7df81575b7f
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-dvb.c
@@ -0,0 +1,474 @@
+/*
+ DVB device driver for em28xx
+
+ (c) 2008 Mauro Carvalho Chehab <mchehab@infradead.org>
+
+ (c) 2008 Devin Heitmueller <devin.heitmueller@gmail.com>
+ - Fixes for the driver to properly work with HVR-950
+
+ (c) 2008 Aidan Thornton <makosoft@googlemail.com>
+
+ Based on cx88-dvb, saa7134-dvb and videobuf-dvb originally written by:
+ (c) 2004, 2005 Chris Pascoe <c.pascoe@itee.uq.edu.au>
+ (c) 2004 Gerd Knorr <kraxel@bytesex.org> [SuSE Labs]
+
+ This program is free software; you can redistribute it and/or modify
+ it under the terms of the GNU General Public License as published by
+ the Free Software Foundation; either version 2 of the License.
+ */
+
+#include <linux/kernel.h>
+#include <linux/usb.h>
+
+#include "em28xx.h"
+#include <media/v4l2-common.h>
+#include <media/videobuf-vmalloc.h>
+
+#include "lgdt330x.h"
+#include "zl10353.h"
+
+MODULE_DESCRIPTION("driver for em28xx based DVB cards");
+MODULE_AUTHOR("Mauro Carvalho Chehab <mchehab@infradead.org>");
+MODULE_LICENSE("GPL");
+
+static unsigned int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debug messages [dvb]");
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+#define dprintk(level, fmt, arg...) do { \
+if (debug >= level) \
+ printk(KERN_DEBUG "%s/2-dvb: " fmt, dev->name, ## arg); \
+} while (0)
+
+#define EM28XX_DVB_NUM_BUFS 5
+#define EM28XX_DVB_MAX_PACKETSIZE 564
+#define EM28XX_DVB_MAX_PACKETS 64
+
+struct em28xx_dvb {
+ struct dvb_frontend *frontend;
+
+ /* feed count management */
+ struct mutex lock;
+ int nfeeds;
+
+ /* general boilerplate stuff */
+ struct dvb_adapter adapter;
+ struct dvb_demux demux;
+ struct dmxdev dmxdev;
+ struct dmx_frontend fe_hw;
+ struct dmx_frontend fe_mem;
+ struct dvb_net net;
+};
+
+
+static inline void print_err_status(struct em28xx *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ dprintk(1, "URB status %d [%s].\n", status, errmsg);
+ } else {
+ dprintk(1, "URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+static inline int dvb_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+ int i;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ dvb_dmx_swfilter(&dev->dvb->demux, urb->transfer_buffer +
+ urb->iso_frame_desc[i].offset,
+ urb->iso_frame_desc[i].actual_length);
+ }
+
+ return 0;
+}
+
+static int start_streaming(struct em28xx_dvb *dvb)
+{
+ int rc;
+ struct em28xx *dev = dvb->adapter.priv;
+
+ usb_set_interface(dev->udev, 0, 1);
+ rc = em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ if (rc < 0)
+ return rc;
+
+ return em28xx_init_isoc(dev, EM28XX_DVB_MAX_PACKETS,
+ EM28XX_DVB_NUM_BUFS, EM28XX_DVB_MAX_PACKETSIZE,
+ dvb_isoc_copy);
+}
+
+static int stop_streaming(struct em28xx_dvb *dvb)
+{
+ struct em28xx *dev = dvb->adapter.priv;
+
+ em28xx_uninit_isoc(dev);
+
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+
+ return 0;
+}
+
+static int start_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct em28xx_dvb *dvb = demux->priv;
+ int rc, ret;
+
+ if (!demux->dmx.frontend)
+ return -EINVAL;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds++;
+ rc = dvb->nfeeds;
+
+ if (dvb->nfeeds == 1) {
+ ret = start_streaming(dvb);
+ if (ret < 0)
+ rc = ret;
+ }
+
+ mutex_unlock(&dvb->lock);
+ return rc;
+}
+
+static int stop_feed(struct dvb_demux_feed *feed)
+{
+ struct dvb_demux *demux = feed->demux;
+ struct em28xx_dvb *dvb = demux->priv;
+ int err = 0;
+
+ mutex_lock(&dvb->lock);
+ dvb->nfeeds--;
+
+ if (0 == dvb->nfeeds)
+ err = stop_streaming(dvb);
+
+ mutex_unlock(&dvb->lock);
+ return err;
+}
+
+
+
+/* ------------------------------------------------------------------ */
+static int em28xx_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct em28xx *dev = fe->dvb->priv;
+
+ if (acquire)
+ return em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ else
+ return em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+}
+
+/* ------------------------------------------------------------------ */
+
+static struct lgdt330x_config em2880_lgdt3303_dev = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+};
+
+static struct zl10353_config em28xx_zl10353_with_xc3028 = {
+ .demod_address = (0x1e >> 1),
+ .no_tuner = 1,
+ .parallel_ts = 1,
+ .if2 = 45600,
+};
+
+/* ------------------------------------------------------------------ */
+
+static int attach_xc3028(u8 addr, struct em28xx *dev)
+{
+ struct dvb_frontend *fe;
+ struct xc2028_config cfg;
+
+ memset(&cfg, 0, sizeof(cfg));
+ cfg.i2c_adap = &dev->i2c_adap;
+ cfg.i2c_addr = addr;
+ cfg.callback = em28xx_tuner_callback;
+
+ if (!dev->dvb->frontend) {
+ printk(KERN_ERR "%s/2: dvb frontend not attached. "
+ "Can't attach xc3028\n",
+ dev->name);
+ return -EINVAL;
+ }
+
+ 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 -EINVAL;
+ }
+
+ printk(KERN_INFO "%s/2: xc3028 attached\n", dev->name);
+
+ return 0;
+}
+
+/* ------------------------------------------------------------------ */
+
+int register_dvb(struct em28xx_dvb *dvb,
+ struct module *module,
+ struct em28xx *dev,
+ struct device *device)
+{
+ int result;
+
+ mutex_init(&dvb->lock);
+
+ /* register adapter */
+ result = dvb_register_adapter(&dvb->adapter, dev->name, module, device,
+ adapter_nr);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_adapter;
+ }
+
+ /* Ensure all frontends negotiate bus access */
+ dvb->frontend->ops.ts_bus_ctrl = em28xx_dvb_bus_ctrl;
+
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_register_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_frontend;
+ }
+
+ /* register demux stuff */
+ dvb->demux.dmx.capabilities =
+ DMX_TS_FILTERING | DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ dvb->demux.priv = dvb;
+ dvb->demux.filternum = 256;
+ dvb->demux.feednum = 256;
+ dvb->demux.start_feed = start_feed;
+ dvb->demux.stop_feed = stop_feed;
+
+ result = dvb_dmx_init(&dvb->demux);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmx_init failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_dmx;
+ }
+
+ dvb->dmxdev.filternum = 256;
+ dvb->dmxdev.demux = &dvb->demux.dmx;
+ dvb->dmxdev.capabilities = 0;
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: dvb_dmxdev_init failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_dmxdev;
+ }
+
+ dvb->fe_hw.source = DMX_FRONTEND_0;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_FRONTEND_0, errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_hw;
+ }
+
+ dvb->fe_mem.source = DMX_MEMORY_FE;
+ result = dvb->demux.dmx.add_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: add_frontend failed (DMX_MEMORY_FE, errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_mem;
+ }
+
+ result = dvb->demux.dmx.connect_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ if (result < 0) {
+ printk(KERN_WARNING "%s: connect_frontend failed (errno = %d)\n",
+ dev->name, result);
+ goto fail_fe_conn;
+ }
+
+ /* register network adapter */
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+ return 0;
+
+fail_fe_conn:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+fail_fe_mem:
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+fail_fe_hw:
+ dvb_dmxdev_release(&dvb->dmxdev);
+fail_dmxdev:
+ dvb_dmx_release(&dvb->demux);
+fail_dmx:
+ dvb_unregister_frontend(dvb->frontend);
+fail_frontend:
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+fail_adapter:
+ return result;
+}
+
+static void unregister_dvb(struct em28xx_dvb *dvb)
+{
+ dvb_net_release(&dvb->net);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_mem);
+ dvb->demux.dmx.remove_frontend(&dvb->demux.dmx, &dvb->fe_hw);
+ dvb_dmxdev_release(&dvb->dmxdev);
+ dvb_dmx_release(&dvb->demux);
+ dvb_unregister_frontend(dvb->frontend);
+ dvb_frontend_detach(dvb->frontend);
+ dvb_unregister_adapter(&dvb->adapter);
+}
+
+
+static int dvb_init(struct em28xx *dev)
+{
+ int result = 0;
+ struct em28xx_dvb *dvb;
+
+ dvb = kzalloc(sizeof(struct em28xx_dvb), GFP_KERNEL);
+
+ if (dvb == NULL) {
+ printk(KERN_INFO "em28xx_dvb: memory allocation failed\n");
+ return -ENOMEM;
+ }
+ dev->dvb = dvb;
+
+ em28xx_set_mode(dev, EM28XX_DIGITAL_MODE);
+ /* init frontend */
+ switch (dev->model) {
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950:
+ dvb->frontend = dvb_attach(lgdt330x_attach,
+ &em2880_lgdt3303_dev,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ case EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900:
+ dvb->frontend = dvb_attach(zl10353_attach,
+ &em28xx_zl10353_with_xc3028,
+ &dev->i2c_adap);
+ if (attach_xc3028(0x61, dev) < 0) {
+ result = -EINVAL;
+ goto out_free;
+ }
+ break;
+ default:
+ printk(KERN_ERR "%s/2: The frontend of your DVB/ATSC card"
+ " isn't supported yet\n",
+ dev->name);
+ break;
+ }
+ if (NULL == dvb->frontend) {
+ printk(KERN_ERR
+ "%s/2: frontend initialization failed\n",
+ dev->name);
+ result = -EINVAL;
+ goto out_free;
+ }
+
+ /* register everything */
+ result = register_dvb(dvb, THIS_MODULE, dev, &dev->udev->dev);
+
+ if (result < 0)
+ goto out_free;
+
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ printk(KERN_INFO "Successfully loaded em28xx-dvb\n");
+ return 0;
+
+out_free:
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+ kfree(dvb);
+ dev->dvb = NULL;
+ return result;
+}
+
+static int dvb_fini(struct em28xx *dev)
+{
+ if (dev->dvb) {
+ unregister_dvb(dev->dvb);
+ dev->dvb = NULL;
+ }
+
+ return 0;
+}
+
+static struct em28xx_ops dvb_ops = {
+ .id = EM28XX_DVB,
+ .name = "Em28xx dvb Extension",
+ .init = dvb_init,
+ .fini = dvb_fini,
+};
+
+static int __init em28xx_dvb_register(void)
+{
+ return em28xx_register_extension(&dvb_ops);
+}
+
+static void __exit em28xx_dvb_unregister(void)
+{
+ em28xx_unregister_extension(&dvb_ops);
+}
+
+module_init(em28xx_dvb_register);
+module_exit(em28xx_dvb_unregister);
diff --git a/drivers/media/video/em28xx/em28xx-i2c.c b/drivers/media/video/em28xx/em28xx-i2c.c
index cacd04d46e9..6a78fd294ca 100644
--- a/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/drivers/media/video/em28xx/em28xx-i2c.c
@@ -33,19 +33,29 @@
/* ----------------------------------------------------------- */
-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]");
-#define dprintk1(lvl,fmt, args...) if (i2c_debug>=lvl) do {\
- printk(fmt, ##args); } while (0)
-#define dprintk2(lvl,fmt, args...) if (i2c_debug>=lvl) do{ \
- printk(KERN_DEBUG "%s at %s: " fmt, \
- dev->name, __FUNCTION__ , ##args); } while (0)
+
+#define dprintk1(lvl, fmt, args...) \
+do { \
+ if (i2c_debug >= lvl) { \
+ printk(fmt, ##args); \
+ } \
+} while (0)
+
+#define dprintk2(lvl, fmt, args...) \
+do { \
+ if (i2c_debug >= lvl) { \
+ printk(KERN_DEBUG "%s at %s: " fmt, \
+ dev->name, __func__ , ##args); \
+ } \
+} while (0)
/*
* em2800_i2c_send_max4()
@@ -235,16 +245,16 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
return 0;
for (i = 0; i < num; i++) {
addr = msgs[i].addr << 1;
- dprintk2(2,"%s %s addr=%x len=%d:",
+ dprintk2(2, "%s %s addr=%x len=%d:",
(msgs[i].flags & I2C_M_RD) ? "read" : "write",
i == num - 1 ? "stop" : "nonstop", addr, msgs[i].len);
- if (!msgs[i].len) { /* no len: check only for device presence */
+ if (!msgs[i].len) { /* no len: check only for device presence */
if (dev->is_em2800)
rc = em2800_i2c_check_for_device(dev, addr);
else
rc = em28xx_i2c_check_for_device(dev, addr);
if (rc < 0) {
- dprintk2(2," no device\n");
+ dprintk2(2, " no device\n");
return rc;
}
@@ -258,14 +268,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
rc = em28xx_i2c_recv_bytes(dev, addr,
msgs[i].buf,
msgs[i].len);
- if (i2c_debug>=2) {
- for (byte = 0; byte < msgs[i].len; byte++) {
+ if (i2c_debug >= 2) {
+ for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
- }
}
} else {
/* write bytes */
- if (i2c_debug>=2) {
+ if (i2c_debug >= 2) {
for (byte = 0; byte < msgs[i].len; byte++)
printk(" %02x", msgs[i].buf[byte]);
}
@@ -281,13 +290,13 @@ static int em28xx_i2c_xfer(struct i2c_adapter *i2c_adap,
}
if (rc < 0)
goto err;
- if (i2c_debug>=2)
+ if (i2c_debug >= 2)
printk("\n");
}
return num;
- err:
- dprintk2(2," ERROR: %i\n", rc);
+err:
+ dprintk2(2, " ERROR: %i\n", rc);
return rc;
}
@@ -330,7 +339,9 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
return -1;
buf = 0;
- if (1 != (err = i2c_master_send(&dev->i2c_client, &buf, 1))) {
+
+ err = i2c_master_send(&dev->i2c_client, &buf, 1);
+ if (err != 1) {
printk(KERN_INFO "%s: Huh, no eeprom present (err=%d)?\n",
dev->name, err);
return -1;
@@ -403,8 +414,10 @@ static int em28xx_i2c_eeprom(struct em28xx *dev, unsigned char *eedata, int len)
break;
}
printk(KERN_INFO "Table at 0x%02x, strings=0x%04x, 0x%04x, 0x%04x\n",
- em_eeprom->string_idx_table,em_eeprom->string1,
- em_eeprom->string2,em_eeprom->string3);
+ em_eeprom->string_idx_table,
+ em_eeprom->string1,
+ em_eeprom->string2,
+ em_eeprom->string3);
return 0;
}
@@ -430,58 +443,61 @@ static int attach_inform(struct i2c_client *client)
struct em28xx *dev = client->adapter->algo_data;
switch (client->addr << 1) {
- case 0x86:
- case 0x84:
- case 0x96:
- case 0x94:
- {
- struct v4l2_priv_tun_config tda9887_cfg;
-
- struct tuner_setup tun_setup;
-
- tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
- tun_setup.type = TUNER_TDA9887;
- tun_setup.addr = client->addr;
-
- em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR, &tun_setup);
-
- tda9887_cfg.tuner = TUNER_TDA9887;
- tda9887_cfg.priv = &dev->tda9887_conf;
- em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
- &tda9887_cfg);
- break;
- }
- case 0x42:
- dprintk1(1,"attach_inform: saa7114 detected.\n");
- break;
- case 0x4a:
- dprintk1(1,"attach_inform: saa7113 detected.\n");
- break;
- case 0xa0:
- dprintk1(1,"attach_inform: eeprom detected.\n");
- break;
- case 0x60:
- case 0x8e:
- {
- struct IR_i2c *ir = i2c_get_clientdata(client);
- dprintk1(1,"attach_inform: IR detected (%s).\n",ir->phys);
- em28xx_set_ir(dev,ir);
- break;
- }
- case 0x80:
- case 0x88:
- dprintk1(1,"attach_inform: msp34xx detected.\n");
- break;
- case 0xb8:
- case 0xba:
- dprintk1(1,"attach_inform: tvp5150 detected.\n");
- break;
-
- default:
- if (!dev->tuner_addr)
- dev->tuner_addr = client->addr;
-
- dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+ case 0x86:
+ case 0x84:
+ case 0x96:
+ case 0x94:
+ {
+ struct v4l2_priv_tun_config tda9887_cfg;
+
+ struct tuner_setup tun_setup;
+
+ tun_setup.mode_mask = T_ANALOG_TV | T_RADIO;
+ tun_setup.type = TUNER_TDA9887;
+ tun_setup.addr = client->addr;
+
+ em28xx_i2c_call_clients(dev, TUNER_SET_TYPE_ADDR,
+ &tun_setup);
+
+ tda9887_cfg.tuner = TUNER_TDA9887;
+ tda9887_cfg.priv = &dev->tda9887_conf;
+ em28xx_i2c_call_clients(dev, TUNER_SET_CONFIG,
+ &tda9887_cfg);
+ break;
+ }
+ case 0x42:
+ dprintk1(1, "attach_inform: saa7114 detected.\n");
+ break;
+ case 0x4a:
+ dprintk1(1, "attach_inform: saa7113 detected.\n");
+ break;
+ case 0xa0:
+ dprintk1(1, "attach_inform: eeprom detected.\n");
+ break;
+ case 0x60:
+ case 0x8e:
+ {
+ struct IR_i2c *ir = i2c_get_clientdata(client);
+ dprintk1(1, "attach_inform: IR detected (%s).\n",
+ ir->phys);
+ em28xx_set_ir(dev, ir);
+ break;
+ }
+ case 0x80:
+ case 0x88:
+ dprintk1(1, "attach_inform: msp34xx detected.\n");
+ break;
+ case 0xb8:
+ case 0xba:
+ dprintk1(1, "attach_inform: tvp5150 detected.\n");
+ break;
+
+ default:
+ if (!dev->tuner_addr)
+ dev->tuner_addr = client->addr;
+
+ dprintk1(1, "attach inform: detected I2C address %x\n",
+ client->addr << 1);
}
diff --git a/drivers/media/video/em28xx/em28xx-input.c b/drivers/media/video/em28xx/em28xx-input.c
index 10da2fd8d98..bb5807159b8 100644
--- a/drivers/media/video/em28xx/em28xx-input.c
+++ b/drivers/media/video/em28xx/em28xx-input.c
@@ -32,10 +32,12 @@
static unsigned int ir_debug;
module_param(ir_debug, int, 0644);
-MODULE_PARM_DESC(ir_debug,"enable debug messages [IR]");
+MODULE_PARM_DESC(ir_debug, "enable debug messages [IR]");
-#define dprintk(fmt, arg...) if (ir_debug) \
- printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg)
+#define dprintk(fmt, arg...) \
+ if (ir_debug) { \
+ printk(KERN_DEBUG "%s/ir: " fmt, ir->c.name , ## arg); \
+ }
/* ----------------------------------------------------------------------- */
@@ -44,7 +46,7 @@ int em28xx_get_key_terratec(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char b;
/* poll IR chip */
- if (1 != i2c_master_recv(&ir->c,&b,1)) {
+ if (1 != i2c_master_recv(&ir->c, &b, 1)) {
dprintk("read error\n");
return -EIO;
}
@@ -74,24 +76,25 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
unsigned char code;
/* poll IR chip */
- if (2 != i2c_master_recv(&ir->c,buf,2))
+ if (2 != i2c_master_recv(&ir->c, buf, 2))
return -EIO;
/* Does eliminate repeated parity code */
- if (buf[1]==0xff)
+ if (buf[1] == 0xff)
return 0;
- ir->old=buf[1];
+ ir->old = buf[1];
/* Rearranges bits to the right order */
- code= ((buf[0]&0x01)<<5) | /* 0010 0000 */
+ code = ((buf[0]&0x01)<<5) | /* 0010 0000 */
((buf[0]&0x02)<<3) | /* 0001 0000 */
((buf[0]&0x04)<<1) | /* 0000 1000 */
((buf[0]&0x08)>>1) | /* 0000 0100 */
((buf[0]&0x10)>>3) | /* 0000 0010 */
((buf[0]&0x20)>>5); /* 0000 0001 */
- dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",code,buf[0]);
+ dprintk("ir hauppauge (em2840): code=0x%02x (rcv=0x%02x)\n",
+ code, buf[0]);
/* return key */
*ir_key = code;
@@ -106,15 +109,14 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
/* poll IR chip */
- if (3 != i2c_master_recv(&ir->c,buf,3)) {
+ if (3 != i2c_master_recv(&ir->c, buf, 3)) {
dprintk("read error\n");
return -EIO;
}
dprintk("key %02x\n", buf[2]&0x3f);
- if (buf[0]!=0x00){
+ if (buf[0] != 0x00)
return 0;
- }
*ir_key = buf[2]&0x3f;
*ir_raw = buf[2]&0x3f;
diff --git a/drivers/media/video/em28xx/em28xx-reg.h b/drivers/media/video/em28xx/em28xx-reg.h
new file mode 100644
index 00000000000..9058bed0795
--- /dev/null
+++ b/drivers/media/video/em28xx/em28xx-reg.h
@@ -0,0 +1,88 @@
+#define EM_GPIO_0 (1 << 0)
+#define EM_GPIO_1 (1 << 1)
+#define EM_GPIO_2 (1 << 2)
+#define EM_GPIO_3 (1 << 3)
+#define EM_GPIO_4 (1 << 4)
+#define EM_GPIO_5 (1 << 5)
+#define EM_GPIO_6 (1 << 6)
+#define EM_GPIO_7 (1 << 7)
+
+#define EM_GPO_0 (1 << 0)
+#define EM_GPO_1 (1 << 1)
+#define EM_GPO_2 (1 << 2)
+#define EM_GPO_3 (1 << 3)
+
+/* em2800 registers */
+#define EM2800_R08_AUDIOSRC 0x08
+
+/* em28xx registers */
+
+ /* GPIO/GPO registers */
+#define EM2880_R04_GPO 0x04 /* em2880-em2883 only */
+#define EM28XX_R08_GPIO 0x08 /* em2820 or upper */
+
+#define EM28XX_R06_I2C_CLK 0x06
+#define EM28XX_R0A_CHIPID 0x0a
+#define EM28XX_R0C_USBSUSP 0x0c /* */
+
+#define EM28XX_R0E_AUDIOSRC 0x0e
+#define EM28XX_R0F_XCLK 0x0f
+
+#define EM28XX_R10_VINMODE 0x10
+#define EM28XX_R11_VINCTRL 0x11
+#define EM28XX_R12_VINENABLE 0x12 /* */
+
+#define EM28XX_R14_GAMMA 0x14
+#define EM28XX_R15_RGAIN 0x15
+#define EM28XX_R16_GGAIN 0x16
+#define EM28XX_R17_BGAIN 0x17
+#define EM28XX_R18_ROFFSET 0x18
+#define EM28XX_R19_GOFFSET 0x19
+#define EM28XX_R1A_BOFFSET 0x1a
+
+#define EM28XX_R1B_OFLOW 0x1b
+#define EM28XX_R1C_HSTART 0x1c
+#define EM28XX_R1D_VSTART 0x1d
+#define EM28XX_R1E_CWIDTH 0x1e
+#define EM28XX_R1F_CHEIGHT 0x1f
+
+#define EM28XX_R20_YGAIN 0x20
+#define EM28XX_R21_YOFFSET 0x21
+#define EM28XX_R22_UVGAIN 0x22
+#define EM28XX_R23_UOFFSET 0x23
+#define EM28XX_R24_VOFFSET 0x24
+#define EM28XX_R25_SHARPNESS 0x25
+
+#define EM28XX_R26_COMPR 0x26
+#define EM28XX_R27_OUTFMT 0x27
+
+#define EM28XX_R28_XMIN 0x28
+#define EM28XX_R29_XMAX 0x29
+#define EM28XX_R2A_YMIN 0x2a
+#define EM28XX_R2B_YMAX 0x2b
+
+#define EM28XX_R30_HSCALELOW 0x30
+#define EM28XX_R31_HSCALEHIGH 0x31
+#define EM28XX_R32_VSCALELOW 0x32
+#define EM28XX_R33_VSCALEHIGH 0x33
+
+#define EM28XX_R40_AC97LSB 0x40
+#define EM28XX_R41_AC97MSB 0x41
+#define EM28XX_R42_AC97ADDR 0x42
+#define EM28XX_R43_AC97BUSY 0x43
+
+/* em202 registers */
+#define EM28XX_R02_MASTER_AC97 0x02
+#define EM28XX_R10_LINE_IN_AC97 0x10
+#define EM28XX_R14_VIDEO_AC97 0x14
+
+/* register settings */
+#define EM2800_AUDIO_SRC_TUNER 0x0d
+#define EM2800_AUDIO_SRC_LINE 0x0c
+#define EM28XX_AUDIO_SRC_TUNER 0xc0
+#define EM28XX_AUDIO_SRC_LINE 0x80
+
+/* FIXME: Need to be populated with the other chip ID's */
+enum em28xx_chip_id {
+ CHIP_ID_EM2883 = 36,
+};
diff --git a/drivers/media/video/em28xx/em28xx-video.c b/drivers/media/video/em28xx/em28xx-video.c
index 4abe6701a77..8996175cc95 100644
--- a/drivers/media/video/em28xx/em28xx-video.c
+++ b/drivers/media/video/em28xx/em28xx-video.c
@@ -1,5 +1,6 @@
/*
- em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB video capture devices
+ em28xx-video.c - driver for Empia EM2800/EM2820/2840 USB
+ video capture devices
Copyright (C) 2005 Ludovico Cavedon <cavedon@sssup.it>
Markus Rechberger <mrechberger@gmail.com>
@@ -52,7 +53,19 @@
#define em28xx_videodbg(fmt, arg...) do {\
if (video_debug) \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __FUNCTION__ , ##arg); } while (0)
+ dev->name, __func__ , ##arg); } while (0)
+
+static unsigned int isoc_debug;
+module_param(isoc_debug, int, 0644);
+MODULE_PARM_DESC(isoc_debug, "enable debug messages [isoc transfers]");
+
+#define em28xx_isocdbg(fmt, arg...) \
+do {\
+ if (isoc_debug) { \
+ printk(KERN_INFO "%s %s :"fmt, \
+ dev->name, __func__ , ##arg); \
+ } \
+ } while (0)
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -74,9 +87,9 @@ 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;
-module_param(video_debug,int,0644);
-MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+static unsigned int video_debug;
+module_param(video_debug, int, 0644);
+MODULE_PARM_DESC(video_debug, "enable debug messages [video]");
/* Bitmask marking allocated devices from 0 to EM28XX_MAXBOARDS */
static unsigned long em28xx_devused;
@@ -93,7 +106,7 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
.step = 0x1,
.default_value = 0x1f,
.flags = 0,
- },{
+ }, {
.id = V4L2_CID_AUDIO_MUTE,
.type = V4L2_CTRL_TYPE_BOOLEAN,
.name = "Mute",
@@ -107,8 +120,391 @@ static struct v4l2_queryctrl em28xx_qctrl[] = {
static struct usb_driver em28xx_usb_driver;
+/* ------------------------------------------------------------------
+ DMA and thread functions
+ ------------------------------------------------------------------*/
+
+/*
+ * Announces that a buffer were filled and request the next
+ */
+static inline void buffer_filled(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf)
+{
+ /* Advice that buffer was filled */
+ em28xx_isocdbg("[%p/%d] wakeup\n", buf, buf->vb.i);
+ buf->vb.state = VIDEOBUF_DONE;
+ buf->vb.field_count++;
+ do_gettimeofday(&buf->vb.ts);
-/********************* v4l2 interface ******************************************/
+ dev->isoc_ctl.buf = NULL;
+
+ list_del(&buf->vb.queue);
+ wake_up(&buf->vb.done);
+}
+
+/*
+ * Identify the buffer header type and properly handles
+ */
+static void em28xx_copy_video(struct em28xx *dev,
+ struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer *buf,
+ unsigned char *p,
+ unsigned char *outp, unsigned long len)
+{
+ void *fieldstart, *startwrite, *startread;
+ int linesdone, currlinedone, offset, lencopy, remain;
+ int bytesperline = dev->width << 1;
+
+ if (dma_q->pos + len > buf->vb.size)
+ len = buf->vb.size - dma_q->pos;
+
+ if (p[0] != 0x88 && p[0] != 0x22) {
+ em28xx_isocdbg("frame is not complete\n");
+ len += 4;
+ } else
+ p += 4;
+
+ startread = p;
+ remain = len;
+
+ /* Interlaces frame */
+ if (buf->top_field)
+ fieldstart = outp;
+ else
+ fieldstart = outp + bytesperline;
+
+ linesdone = dma_q->pos / bytesperline;
+ currlinedone = dma_q->pos % bytesperline;
+ offset = linesdone * bytesperline * 2 + currlinedone;
+ startwrite = fieldstart + offset;
+ lencopy = bytesperline - currlinedone;
+ lencopy = lencopy > remain ? remain : lencopy;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (1)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size - (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ return;
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+
+ while (remain > 0) {
+ startwrite += lencopy + bytesperline;
+ startread += lencopy;
+ if (bytesperline > remain)
+ lencopy = remain;
+ else
+ lencopy = bytesperline;
+
+ if ((char *)startwrite + lencopy > (char *)outp + buf->vb.size) {
+ em28xx_isocdbg("Overflow of %zi bytes past buffer end (2)\n",
+ ((char *)startwrite + lencopy) -
+ ((char *)outp + buf->vb.size));
+ lencopy = remain = (char *)outp + buf->vb.size -
+ (char *)startwrite;
+ }
+ if (lencopy <= 0)
+ break;
+
+ memcpy(startwrite, startread, lencopy);
+
+ remain -= lencopy;
+ }
+
+ dma_q->pos += len;
+}
+
+static inline void print_err_status(struct em28xx *dev,
+ int packet, int status)
+{
+ char *errmsg = "Unknown";
+
+ switch (status) {
+ case -ENOENT:
+ errmsg = "unlinked synchronuously";
+ break;
+ case -ECONNRESET:
+ errmsg = "unlinked asynchronuously";
+ break;
+ case -ENOSR:
+ errmsg = "Buffer error (overrun)";
+ break;
+ case -EPIPE:
+ errmsg = "Stalled (device not responding)";
+ break;
+ case -EOVERFLOW:
+ errmsg = "Babble (bad cable?)";
+ break;
+ case -EPROTO:
+ errmsg = "Bit-stuff error (bad cable?)";
+ break;
+ case -EILSEQ:
+ errmsg = "CRC/Timeout (could be anything)";
+ break;
+ case -ETIME:
+ errmsg = "Device does not respond";
+ break;
+ }
+ if (packet < 0) {
+ em28xx_isocdbg("URB status %d [%s].\n", status, errmsg);
+ } else {
+ em28xx_isocdbg("URB packet %d, status %d [%s].\n",
+ packet, status, errmsg);
+ }
+}
+
+/*
+ * video-buf generic routine to get the next available buffer
+ */
+static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
+ struct em28xx_buffer **buf)
+{
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ char *outp;
+
+ if (list_empty(&dma_q->active)) {
+ em28xx_isocdbg("No active queue to serve\n");
+ dev->isoc_ctl.buf = NULL;
+ *buf = NULL;
+ return;
+ }
+
+ /* Get the next buffer */
+ *buf = list_entry(dma_q->active.next, struct em28xx_buffer, vb.queue);
+
+ /* Cleans up buffer - Usefull for testing for frame/URB loss */
+ outp = videobuf_to_vmalloc(&(*buf)->vb);
+ memset(outp, 0, (*buf)->vb.size);
+
+ dev->isoc_ctl.buf = *buf;
+
+ return;
+}
+
+/*
+ * Controls the isoc copy of each urb packet
+ */
+static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
+{
+ struct em28xx_buffer *buf;
+ struct em28xx_dmaqueue *dma_q = urb->context;
+ unsigned char *outp = NULL;
+ int i, len = 0, rc = 1;
+ unsigned char *p;
+
+ if (!dev)
+ return 0;
+
+ if ((dev->state & DEV_DISCONNECTED) || (dev->state & DEV_MISCONFIGURED))
+ return 0;
+
+ if (urb->status < 0) {
+ print_err_status(dev, -1, urb->status);
+ if (urb->status == -ENOENT)
+ return 0;
+ }
+
+ buf = dev->isoc_ctl.buf;
+ if (buf != NULL)
+ outp = videobuf_to_vmalloc(&buf->vb);
+
+ for (i = 0; i < urb->number_of_packets; i++) {
+ int status = urb->iso_frame_desc[i].status;
+
+ if (status < 0) {
+ print_err_status(dev, i, status);
+ if (urb->iso_frame_desc[i].status != -EPROTO)
+ continue;
+ }
+
+ len = urb->iso_frame_desc[i].actual_length - 4;
+
+ if (urb->iso_frame_desc[i].actual_length <= 0) {
+ /* em28xx_isocdbg("packet %d is empty",i); - spammy */
+ continue;
+ }
+ if (urb->iso_frame_desc[i].actual_length >
+ dev->max_pkt_size) {
+ em28xx_isocdbg("packet bigger than packet size");
+ continue;
+ }
+
+ p = urb->transfer_buffer + urb->iso_frame_desc[i].offset;
+
+ /* FIXME: incomplete buffer checks where removed to make
+ logic simpler. Impacts of those changes should be evaluated
+ */
+ if (p[0] == 0x33 && p[1] == 0x95 && p[2] == 0x00) {
+ em28xx_isocdbg("VBI HEADER!!!\n");
+ /* FIXME: Should add vbi copy */
+ continue;
+ }
+ if (p[0] == 0x22 && p[1] == 0x5a) {
+ em28xx_isocdbg("Video frame %d, length=%i, %s\n", p[2],
+ len, (p[2] & 1)? "odd" : "even");
+
+ if (!(p[2] & 1)) {
+ if (buf != NULL)
+ buffer_filled(dev, dma_q, buf);
+ get_next_buf(dma_q, &buf);
+ if (buf == NULL)
+ outp = NULL;
+ else
+ outp = videobuf_to_vmalloc(&buf->vb);
+ }
+
+ if (buf != NULL) {
+ if (p[2] & 1)
+ buf->top_field = 0;
+ else
+ buf->top_field = 1;
+ }
+
+ dma_q->pos = 0;
+ }
+ if (buf != NULL)
+ em28xx_copy_video(dev, dma_q, buf, p, outp, len);
+ }
+ return rc;
+}
+
+/* ------------------------------------------------------------------
+ Videobuf operations
+ ------------------------------------------------------------------*/
+
+static int
+buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct v4l2_frequency f;
+
+ *size = 16 * fh->dev->width * fh->dev->height >> 3;
+ if (0 == *count)
+ *count = EM28XX_DEF_BUF;
+
+ if (*count < EM28XX_MIN_BUF)
+ *count = EM28XX_MIN_BUF;
+
+ /* Ask tuner to go to analog mode */
+ memset(&f, 0, sizeof(f));
+ f.frequency = dev->ctl_freq;
+
+ em28xx_i2c_call_clients(dev, VIDIOC_S_FREQUENCY, &f);
+
+ return 0;
+}
+
+/* This is called *without* dev->slock held; please keep it that way */
+static void free_buffer(struct videobuf_queue *vq, struct em28xx_buffer *buf)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ unsigned long flags = 0;
+ if (in_interrupt())
+ BUG();
+
+ /* We used to wait for the buffer to finish here, but this didn't work
+ because, as we were keeping the state as VIDEOBUF_QUEUED,
+ videobuf_queue_cancel marked it as finished for us.
+ (Also, it could wedge forever if the hardware was misconfigured.)
+
+ This should be safe; by the time we get here, the buffer isn't
+ queued anymore. If we ever start marking the buffers as
+ VIDEOBUF_ACTIVE, it won't be, though.
+ */
+ spin_lock_irqsave(&dev->slock, flags);
+ if (dev->isoc_ctl.buf == buf)
+ dev->isoc_ctl.buf = NULL;
+ spin_unlock_irqrestore(&dev->slock, flags);
+
+ videobuf_vmalloc_free(&buf->vb);
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int
+buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
+ enum v4l2_field field)
+{
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx *dev = fh->dev;
+ int rc = 0, urb_init = 0;
+
+ /* FIXME: It assumes depth = 16 */
+ /* The only currently supported format is 16 bits/pixel */
+ buf->vb.size = 16 * dev->width * dev->height >> 3;
+
+ if (0 != buf->vb.baddr && buf->vb.bsize < buf->vb.size)
+ return -EINVAL;
+
+ buf->vb.width = dev->width;
+ buf->vb.height = dev->height;
+ buf->vb.field = field;
+
+ if (VIDEOBUF_NEEDS_INIT == buf->vb.state) {
+ rc = videobuf_iolock(vq, &buf->vb, NULL);
+ if (rc < 0)
+ goto fail;
+ }
+
+ if (!dev->isoc_ctl.num_bufs)
+ urb_init = 1;
+
+ if (urb_init) {
+ rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+ EM28XX_NUM_BUFS, dev->max_pkt_size,
+ em28xx_isoc_copy);
+ if (rc < 0)
+ goto fail;
+ }
+
+ buf->vb.state = VIDEOBUF_PREPARED;
+ return 0;
+
+fail:
+ free_buffer(vq, buf);
+ return rc;
+}
+
+static void
+buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = fh->dev;
+ struct em28xx_dmaqueue *vidq = &dev->vidq;
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
+
+}
+
+static void buffer_release(struct videobuf_queue *vq,
+ struct videobuf_buffer *vb)
+{
+ struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
+ struct em28xx_fh *fh = vq->priv_data;
+ struct em28xx *dev = (struct em28xx *)fh->dev;
+
+ em28xx_isocdbg("em28xx: called buffer_release\n");
+
+ free_buffer(vq, buf);
+}
+
+static struct videobuf_queue_ops em28xx_video_qops = {
+ .buf_setup = buffer_setup,
+ .buf_prepare = buffer_prepare,
+ .buf_queue = buffer_queue,
+ .buf_release = buffer_release,
+};
+
+/********************* v4l2 interface **************************************/
/*
* em28xx_config()
@@ -123,9 +519,9 @@ static int em28xx_config(struct em28xx *dev)
/* enable vbi capturing */
-/* em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
-/* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
- em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+/* em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */
+/* em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */
+ em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1);
dev->mute = 1; /* maybe not the right place... */
dev->volume = 0x1f;
@@ -152,23 +548,6 @@ static void em28xx_config_i2c(struct em28xx *dev)
em28xx_i2c_call_clients(dev, VIDIOC_STREAMON, NULL);
}
-/*
- * em28xx_empty_framequeues()
- * prepare queues for incoming and outgoing frames
- */
-static void em28xx_empty_framequeues(struct em28xx *dev)
-{
- u32 i;
-
- INIT_LIST_HEAD(&dev->inqueue);
- INIT_LIST_HEAD(&dev->outqueue);
-
- for (i = 0; i < EM28XX_NUM_FRAMES; i++) {
- dev->frame[i].state = F_UNUSED;
- dev->frame[i].buf.bytesused = 0;
- }
-}
-
static void video_mux(struct em28xx *dev, int index)
{
struct v4l2_routing route;
@@ -181,12 +560,15 @@ static void video_mux(struct em28xx *dev, int index)
em28xx_i2c_call_clients(dev, VIDIOC_INT_S_VIDEO_ROUTING, &route);
if (dev->has_msp34xx) {
- if (dev->i2s_speed)
- em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ, &dev->i2s_speed);
+ if (dev->i2s_speed) {
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_I2S_CLOCK_FREQ,
+ &dev->i2s_speed);
+ }
route.input = dev->ctl_ainput;
route.output = MSP_OUTPUT(MSP_SC_IN_DSP_SCART1);
/* Note: this is msp3400 specific */
- em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING, &route);
+ em28xx_i2c_call_clients(dev, VIDIOC_INT_S_AUDIO_ROUTING,
+ &route);
}
em28xx_audio_analog_set(dev);
@@ -202,15 +584,12 @@ static int res_get(struct em28xx_fh *fh)
if (fh->stream_on)
return rc;
- mutex_lock(&dev->lock);
-
if (dev->stream_on)
- rc = -EINVAL;
- else {
- dev->stream_on = 1;
- fh->stream_on = 1;
- }
+ return -EINVAL;
+ mutex_lock(&dev->lock);
+ dev->stream_on = 1;
+ fh->stream_on = 1;
mutex_unlock(&dev->lock);
return rc;
}
@@ -231,33 +610,6 @@ static void res_free(struct em28xx_fh *fh)
}
/*
- * em28xx_vm_open()
- */
-static void em28xx_vm_open(struct vm_area_struct *vma)
-{
- struct em28xx_frame_t *f = vma->vm_private_data;
- f->vma_use_count++;
-}
-
-/*
- * em28xx_vm_close()
- */
-static void em28xx_vm_close(struct vm_area_struct *vma)
-{
- /* NOTE: buffers are not freed here */
- struct em28xx_frame_t *f = vma->vm_private_data;
-
- if (f->vma_use_count)
- f->vma_use_count--;
-}
-
-static struct vm_operations_struct em28xx_vm_ops = {
- .open = em28xx_vm_open,
- .close = em28xx_vm_close,
-};
-
-
-/*
* em28xx_get_ctrl()
* return the current saturation, brightness or contrast, mute state
*/
@@ -296,34 +648,6 @@ static int em28xx_set_ctrl(struct em28xx *dev, const struct v4l2_control *ctrl)
}
}
-/*
- * em28xx_stream_interrupt()
- * stops streaming
- */
-static int em28xx_stream_interrupt(struct em28xx *dev)
-{
- int rc = 0;
-
- /* stop reading from the device */
-
- dev->stream = STREAM_INTERRUPT;
- rc = wait_event_timeout(dev->wait_stream,
- (dev->stream == STREAM_OFF) ||
- (dev->state & DEV_DISCONNECTED),
- EM28XX_URB_TIMEOUT);
-
- if (rc) {
- dev->state |= DEV_MISCONFIGURED;
- em28xx_videodbg("device is misconfigured; close and "
- "open /dev/video%d again\n",
- dev->vdev->minor-MINOR_VFL_TYPE_GRABBER_MIN);
- return rc;
- }
-
- return 0;
-}
-
-
static int check_dev(struct em28xx *dev)
{
if (dev->state & DEV_DISCONNECTED) {
@@ -370,8 +694,8 @@ static int vidioc_g_fmt_cap(struct file *file, void *priv,
f->fmt.pix.width = dev->width;
f->fmt.pix.height = dev->height;
f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- f->fmt.pix.bytesperline = dev->bytesperline;
- f->fmt.pix.sizeimage = dev->frame_size;
+ f->fmt.pix.bytesperline = dev->width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.bytesperline * dev->height;
f->fmt.pix.colorspace = V4L2_COLORSPACE_SMPTE170M;
/* FIXME: TOP? NONE? BOTTOM? ALTENATE? */
@@ -447,7 +771,7 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- int rc, i;
+ int rc;
rc = check_dev(dev);
if (rc < 0)
@@ -457,49 +781,34 @@ static int vidioc_s_fmt_cap(struct file *file, void *priv,
mutex_lock(&dev->lock);
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].vma_use_count) {
- em28xx_videodbg("VIDIOC_S_FMT failed. "
- "Unmap the buffers first.\n");
- rc = -EINVAL;
- goto err;
- }
-
- /* stop io in case it is already in progress */
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_SET_FMT: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0)
- goto err;
+ if (videobuf_queue_is_busy(&fh->vb_vidq)) {
+ em28xx_errdev("%s queue busy\n", __func__);
+ rc = -EBUSY;
+ goto out;
}
- em28xx_release_buffers(dev);
- dev->io = IO_NONE;
+ if (dev->stream_on && !fh->stream_on) {
+ em28xx_errdev("%s device in use by another fh\n", __func__);
+ rc = -EBUSY;
+ goto out;
+ }
/* set new image size */
dev->width = f->fmt.pix.width;
dev->height = f->fmt.pix.height;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1;
- dev->bytesperline = dev->width * 2;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
- /* FIXME: This is really weird! Why capture is starting with
- this ioctl ???
- */
- em28xx_uninit_isoc(dev);
em28xx_set_alternate(dev);
- em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev);
- em28xx_init_isoc(dev);
+
rc = 0;
-err:
+out:
mutex_unlock(&dev->lock);
return rc;
}
-static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
+static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id * norm)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
@@ -524,9 +833,6 @@ static int vidioc_s_std(struct file *file, void *priv, v4l2_std_id *norm)
/* set new image size */
dev->width = f.fmt.pix.width;
dev->height = f.fmt.pix.height;
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1;
- dev->bytesperline = dev->width * 2;
get_scale(dev, dev->width, dev->height, &dev->hscale, &dev->vscale);
em28xx_resolution_set(dev);
@@ -619,11 +925,11 @@ static int vidioc_g_audio(struct file *file, void *priv, struct v4l2_audio *a)
index = dev->ctl_ainput;
- if (index == 0) {
+ if (index == 0)
strcpy(a->name, "Television");
- } else {
+ else
strcpy(a->name, "Line In");
- }
+
a->capability = V4L2_AUDCAP_STEREO;
a->index = index;
@@ -834,9 +1140,9 @@ static int vidioc_s_frequency(struct file *file, void *priv,
static int em28xx_reg_len(int reg)
{
switch (reg) {
- case AC97LSB_REG:
- case HSCALELOW_REG:
- case VSCALELOW_REG:
+ case EM28XX_R40_AC97LSB:
+ case EM28XX_R30_HSCALELOW:
+ case EM28XX_R32_VSCALELOW:
return 2;
default:
return 1;
@@ -918,23 +1224,11 @@ static int vidioc_streamon(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&dev->inqueue))
- return -EINVAL;
-
- mutex_lock(&dev->lock);
- if (unlikely(res_get(fh) < 0)) {
- mutex_unlock(&dev->lock);
+ if (unlikely(res_get(fh) < 0))
return -EBUSY;
- }
- dev->stream = STREAM_ON; /* FIXME: Start video capture here? */
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_streamon(&fh->vb_vidq));
}
static int vidioc_streamoff(struct file *file, void *priv,
@@ -948,23 +1242,14 @@ static int vidioc_streamoff(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
+ if (fh->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+ if (type != fh->type)
return -EINVAL;
- mutex_lock(&dev->lock);
-
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_STREAMOFF: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0) {
- mutex_unlock(&dev->lock);
- return rc;
- }
- }
-
- em28xx_empty_framequeues(dev);
+ videobuf_streamoff(&fh->vb_vidq);
+ res_free(fh);
- mutex_unlock(&dev->lock);
return 0;
}
@@ -1058,53 +1343,13 @@ static int vidioc_reqbufs(struct file *file, void *priv,
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- u32 i;
int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (rb->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- rb->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
-
- if (dev->io == IO_READ) {
- em28xx_videodbg("method is set to read;"
- " close and open the device again to"
- " choose the mmap I/O method\n");
- return -EINVAL;
- }
-
- for (i = 0; i < dev->num_frames; i++)
- if (dev->frame[i].vma_use_count) {
- em28xx_videodbg("VIDIOC_REQBUFS failed; "
- "previous buffers are still mapped\n");
- return -EINVAL;
- }
-
- mutex_lock(&dev->lock);
-
- if (dev->stream == STREAM_ON) {
- em28xx_videodbg("VIDIOC_REQBUFS: interrupting stream\n");
- rc = em28xx_stream_interrupt(dev);
- if (rc < 0) {
- mutex_unlock(&dev->lock);
- return rc;
- }
- }
-
- em28xx_empty_framequeues(dev);
-
- em28xx_release_buffers(dev);
- if (rb->count)
- rb->count = em28xx_request_buffers(dev, rb->count);
-
- dev->frame_current = NULL;
- dev->io = rb->count ? IO_MMAP : IO_NONE;
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_reqbufs(&fh->vb_vidq, rb));
}
static int vidioc_querybuf(struct file *file, void *priv,
@@ -1118,52 +1363,20 @@ static int vidioc_querybuf(struct file *file, void *priv,
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE ||
- b->index >= dev->num_frames || dev->io != IO_MMAP)
- return -EINVAL;
-
- mutex_lock(&dev->lock);
-
- memcpy(b, &dev->frame[b->index].buf, sizeof(*b));
-
- if (dev->frame[b->index].vma_use_count)
- b->flags |= V4L2_BUF_FLAG_MAPPED;
-
- if (dev->frame[b->index].state == F_DONE)
- b->flags |= V4L2_BUF_FLAG_DONE;
- else if (dev->frame[b->index].state != F_UNUSED)
- b->flags |= V4L2_BUF_FLAG_QUEUED;
-
- mutex_unlock(&dev->lock);
- return 0;
+ return (videobuf_querybuf(&fh->vb_vidq, b));
}
static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *b)
{
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
- unsigned long lock_flags;
int rc;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP ||
- b->index >= dev->num_frames)
- return -EINVAL;
-
- if (dev->frame[b->index].state != F_UNUSED)
- return -EAGAIN;
-
- dev->frame[b->index].state = F_QUEUED;
-
- /* add frame to fifo */
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_add_tail(&dev->frame[b->index].frame, &dev->inqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- return 0;
+ return (videobuf_qbuf(&fh->vb_vidq, b));
}
static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
@@ -1171,46 +1384,24 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *b)
struct em28xx_fh *fh = priv;
struct em28xx *dev = fh->dev;
int rc;
- struct em28xx_frame_t *f;
- unsigned long lock_flags;
rc = check_dev(dev);
if (rc < 0)
return rc;
- if (b->type != V4L2_BUF_TYPE_VIDEO_CAPTURE || dev->io != IO_MMAP)
- return -EINVAL;
-
- if (list_empty(&dev->outqueue)) {
- if (dev->stream == STREAM_OFF)
- return -EINVAL;
-
- if (file->f_flags & O_NONBLOCK)
- return -EAGAIN;
-
- rc = wait_event_interruptible(dev->wait_frame,
- (!list_empty(&dev->outqueue)) ||
- (dev->state & DEV_DISCONNECTED));
- if (rc)
- return rc;
-
- if (dev->state & DEV_DISCONNECTED)
- return -ENODEV;
- }
-
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- f = list_entry(dev->outqueue.next, struct em28xx_frame_t, frame);
- list_del(dev->outqueue.next);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- f->state = F_UNUSED;
- memcpy(b, &f->buf, sizeof(*b));
+ return (videobuf_dqbuf(&fh->vb_vidq, b,
+ file->f_flags & O_NONBLOCK));
+}
- if (f->vma_use_count)
- b->flags |= V4L2_BUF_FLAG_MAPPED;
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+static int vidiocgmbuf(struct file *file, void *priv, struct video_mbuf *mbuf)
+{
+ struct em28xx_fh *fh = priv;
- return 0;
+ return videobuf_cgmbuf(&fh->vb_vidq, mbuf, 8);
}
+#endif
+
/* ----------------------------------------------------------- */
/* RADIO ESPECIFIC IOCTLS */
@@ -1316,17 +1507,18 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
{
int minor = iminor(inode);
int errCode = 0, radio = 0;
- struct em28xx *h,*dev = NULL;
+ struct em28xx *h, *dev = NULL;
struct em28xx_fh *fh;
+ enum v4l2_buf_type fh_type = 0;
list_for_each_entry(h, &em28xx_devlist, devlist) {
if (h->vdev->minor == minor) {
dev = h;
- dev->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ fh_type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
}
if (h->vbi_dev->minor == minor) {
dev = h;
- dev->type = V4L2_BUF_TYPE_VBI_CAPTURE;
+ fh_type = V4L2_BUF_TYPE_VBI_CAPTURE;
}
if (h->radio_dev &&
h->radio_dev->minor == minor) {
@@ -1338,10 +1530,10 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
return -ENODEV;
em28xx_videodbg("open minor=%d type=%s users=%d\n",
- minor,v4l2_type_names[dev->type],dev->users);
+ minor, v4l2_type_names[fh_type], dev->users);
- fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
+ fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
if (!fh) {
em28xx_errdev("em28xx-video.c: Out of memory?!\n");
return -ENOMEM;
@@ -1349,28 +1541,24 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
mutex_lock(&dev->lock);
fh->dev = dev;
fh->radio = radio;
+ fh->type = fh_type;
filp->private_data = fh;
- if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE && dev->users == 0) {
dev->width = norm_maxw(dev);
dev->height = norm_maxh(dev);
- dev->frame_size = dev->width * dev->height * 2;
- dev->field_size = dev->frame_size >> 1; /*both_fileds ? dev->frame_size>>1 : dev->frame_size; */
- dev->bytesperline = dev->width * 2;
dev->hscale = 0;
dev->vscale = 0;
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
em28xx_set_alternate(dev);
- em28xx_capture_start(dev, 1);
em28xx_resolution_set(dev);
+ /* Needed, since GPIO might have disabled power of
+ some i2c device
+ */
+ em28xx_config_i2c(dev);
- /* start the transfer */
- errCode = em28xx_init_isoc(dev);
- if (errCode)
- goto err;
-
- em28xx_empty_framequeues(dev);
}
if (fh->radio) {
em28xx_videodbg("video_open: setting radio device\n");
@@ -1379,8 +1567,12 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->users++;
-err:
+ videobuf_queue_vmalloc_init(&fh->vb_vidq, &em28xx_video_qops,
+ NULL, &dev->slock, fh->type, V4L2_FIELD_INTERLACED,
+ sizeof(struct em28xx_buffer), fh);
+
mutex_unlock(&dev->lock);
+
return errCode;
}
@@ -1423,12 +1615,13 @@ static void em28xx_release_resources(struct em28xx *dev)
usb_put_dev(dev->udev);
/* Mark device as unused */
- em28xx_devused&=~(1<<dev->devno);
+ em28xx_devused &= ~(1<<dev->devno);
}
/*
* em28xx_v4l2_close()
- * stops streaming and deallocates all resources allocated by the v4l2 calls and ioctls
+ * stops streaming and deallocates all resources allocated by the v4l2
+ * calls and ioctls
*/
static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
{
@@ -1445,9 +1638,8 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
mutex_lock(&dev->lock);
if (dev->users == 1) {
- em28xx_uninit_isoc(dev);
- em28xx_release_buffers(dev);
- dev->io = IO_NONE;
+ videobuf_stop(&fh->vb_vidq);
+ videobuf_mmap_free(&fh->vb_vidq);
/* the device is already disconnect,
free the remaining resources */
@@ -1458,6 +1650,10 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
return 0;
}
+ /* do this before setting alternate! */
+ em28xx_uninit_isoc(dev);
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
+
/* set alternate 0 */
dev->alt = 0;
em28xx_videodbg("setting alternate 0\n");
@@ -1479,135 +1675,29 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
* will allocate buffers when called for the first time
*/
static ssize_t
-em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
- loff_t * f_pos)
+em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
+ loff_t *pos)
{
- struct em28xx_frame_t *f, *i;
- unsigned long lock_flags;
- int ret = 0;
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
/* FIXME: read() is not prepared to allow changing the video
resolution while streaming. Seems a bug at em28xx_set_fmt
*/
- if (unlikely(res_get(fh) < 0))
- return -EBUSY;
-
- mutex_lock(&dev->lock);
-
- if (dev->type == V4L2_BUF_TYPE_VIDEO_CAPTURE)
- em28xx_videodbg("V4l2_Buf_type_videocapture is set\n");
+ if (fh->type == V4L2_BUF_TYPE_VIDEO_CAPTURE) {
+ if (unlikely(res_get(fh)))
+ return -EBUSY;
- if (dev->type == V4L2_BUF_TYPE_VBI_CAPTURE) {
- em28xx_videodbg("V4L2_BUF_TYPE_VBI_CAPTURE is set\n");
- em28xx_videodbg("not supported yet! ...\n");
- if (copy_to_user(buf, "", 1)) {
- mutex_unlock(&dev->lock);
- return -EFAULT;
- }
- mutex_unlock(&dev->lock);
- return (1);
- }
- if (dev->type == V4L2_BUF_TYPE_SLICED_VBI_CAPTURE) {
- em28xx_videodbg("V4L2_BUF_TYPE_SLICED_VBI_CAPTURE is set\n");
- em28xx_videodbg("not supported yet! ...\n");
- if (copy_to_user(buf, "", 1)) {
- mutex_unlock(&dev->lock);
- return -EFAULT;
- }
- mutex_unlock(&dev->lock);
- return (1);
+ return videobuf_read_stream(&fh->vb_vidq, buf, count, pos, 0,
+ filp->f_flags & O_NONBLOCK);
}
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("device not present\n");
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
-
- if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg("device misconfigured; close and open it again\n");
- mutex_unlock(&dev->lock);
- return -EIO;
- }
-
- if (dev->io == IO_MMAP) {
- em28xx_videodbg ("IO method is set to mmap; close and open"
- " the device again to choose the read method\n");
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- if (dev->io == IO_NONE) {
- if (!em28xx_request_buffers(dev, EM28XX_NUM_READ_FRAMES)) {
- em28xx_errdev("read failed, not enough memory\n");
- mutex_unlock(&dev->lock);
- return -ENOMEM;
- }
- dev->io = IO_READ;
- dev->stream = STREAM_ON;
- em28xx_queue_unusedframes(dev);
- }
-
- if (!count) {
- mutex_unlock(&dev->lock);
- return 0;
- }
-
- if (list_empty(&dev->outqueue)) {
- if (filp->f_flags & O_NONBLOCK) {
- mutex_unlock(&dev->lock);
- return -EAGAIN;
- }
- ret = wait_event_interruptible
- (dev->wait_frame,
- (!list_empty(&dev->outqueue)) ||
- (dev->state & DEV_DISCONNECTED));
- if (ret) {
- mutex_unlock(&dev->lock);
- return ret;
- }
- if (dev->state & DEV_DISCONNECTED) {
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
- dev->video_bytesread = 0;
- }
-
- f = list_entry(dev->outqueue.prev, struct em28xx_frame_t, frame);
-
- em28xx_queue_unusedframes(dev);
-
- if (count > f->buf.length)
- count = f->buf.length;
-
- if ((dev->video_bytesread + count) > dev->frame_size)
- count = dev->frame_size - dev->video_bytesread;
-
- if (copy_to_user(buf, f->bufmem+dev->video_bytesread, count)) {
- em28xx_err("Error while copying to user\n");
- return -EFAULT;
- }
- dev->video_bytesread += count;
-
- if (dev->video_bytesread == dev->frame_size) {
- spin_lock_irqsave(&dev->queue_lock, lock_flags);
- list_for_each_entry(i, &dev->outqueue, frame)
- i->state = F_UNUSED;
- INIT_LIST_HEAD(&dev->outqueue);
- spin_unlock_irqrestore(&dev->queue_lock, lock_flags);
-
- em28xx_queue_unusedframes(dev);
- dev->video_bytesread = 0;
- }
-
- *f_pos += count;
-
- mutex_unlock(&dev->lock);
-
- return count;
+ return 0;
}
/*
@@ -1616,46 +1706,21 @@ em28xx_v4l2_read(struct file *filp, char __user * buf, size_t count,
*/
static unsigned int em28xx_v4l2_poll(struct file *filp, poll_table * wait)
{
- unsigned int mask = 0;
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
+ int rc;
+
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
if (unlikely(res_get(fh) < 0))
return POLLERR;
- mutex_lock(&dev->lock);
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("device not present\n");
- } else if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg("device is misconfigured; close and open it again\n");
- } else {
- if (dev->io == IO_NONE) {
- if (!em28xx_request_buffers
- (dev, EM28XX_NUM_READ_FRAMES)) {
- em28xx_warn
- ("poll() failed, not enough memory\n");
- } else {
- dev->io = IO_READ;
- dev->stream = STREAM_ON;
- }
- }
-
- if (dev->io == IO_READ) {
- em28xx_queue_unusedframes(dev);
- poll_wait(filp, &dev->wait_frame, wait);
-
- if (!list_empty(&dev->outqueue))
- mask |= POLLIN | POLLRDNORM;
-
- mutex_unlock(&dev->lock);
-
- return mask;
- }
- }
+ if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
+ return POLLERR;
- mutex_unlock(&dev->lock);
- return POLLERR;
+ return videobuf_poll_stream(filp, &fh->vb_vidq, wait);
}
/*
@@ -1665,69 +1730,23 @@ static int em28xx_v4l2_mmap(struct file *filp, struct vm_area_struct *vma)
{
struct em28xx_fh *fh = filp->private_data;
struct em28xx *dev = fh->dev;
- unsigned long size = vma->vm_end - vma->vm_start;
- unsigned long start = vma->vm_start;
- void *pos;
- u32 i;
+ int rc;
if (unlikely(res_get(fh) < 0))
return -EBUSY;
- mutex_lock(&dev->lock);
-
- if (dev->state & DEV_DISCONNECTED) {
- em28xx_videodbg("mmap: device not present\n");
- mutex_unlock(&dev->lock);
- return -ENODEV;
- }
-
- if (dev->state & DEV_MISCONFIGURED) {
- em28xx_videodbg ("mmap: Device is misconfigured; close and "
- "open it again\n");
- mutex_unlock(&dev->lock);
- return -EIO;
- }
-
- if (dev->io != IO_MMAP || !(vma->vm_flags & VM_WRITE)) {
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- if (size > PAGE_ALIGN(dev->frame[0].buf.length))
- size = PAGE_ALIGN(dev->frame[0].buf.length);
-
- for (i = 0; i < dev->num_frames; i++) {
- if ((dev->frame[i].buf.m.offset >> PAGE_SHIFT) == vma->vm_pgoff)
- break;
- }
- if (i == dev->num_frames) {
- em28xx_videodbg("mmap: user supplied mapping address is out of range\n");
- mutex_unlock(&dev->lock);
- return -EINVAL;
- }
-
- /* VM_IO is eventually going to replace PageReserved altogether */
- vma->vm_flags |= VM_IO;
- vma->vm_flags |= VM_RESERVED; /* avoid to swap out this VMA */
+ rc = check_dev(dev);
+ if (rc < 0)
+ return rc;
- pos = dev->frame[i].bufmem;
- while (size > 0) { /* size is page-aligned */
- if (vm_insert_page(vma, start, vmalloc_to_page(pos))) {
- em28xx_videodbg("mmap: vm_insert_page failed\n");
- mutex_unlock(&dev->lock);
- return -EAGAIN;
- }
- start += PAGE_SIZE;
- pos += PAGE_SIZE;
- size -= PAGE_SIZE;
- }
+ rc = videobuf_mmap_mapper(&fh->vb_vidq, vma);
- vma->vm_ops = &em28xx_vm_ops;
- vma->vm_private_data = &dev->frame[i];
+ em28xx_videodbg("vma start=0x%08lx, size=%ld, ret=%d\n",
+ (unsigned long)vma->vm_start,
+ (unsigned long)vma->vm_end-(unsigned long)vma->vm_start,
+ rc);
- em28xx_vm_open(vma);
- mutex_unlock(&dev->lock);
- return 0;
+ return rc;
}
static const struct file_operations em28xx_v4l_fops = {
@@ -1790,6 +1809,9 @@ static const struct video_device em28xx_video_template = {
.vidioc_g_register = vidioc_g_register,
.vidioc_s_register = vidioc_s_register,
#endif
+#ifdef CONFIG_VIDEO_V4L1_COMPAT
+ .vidiocgmbuf = vidiocgmbuf,
+#endif
.tvnorms = V4L2_STD_ALL,
.current_norm = V4L2_STD_PAL,
@@ -1818,7 +1840,7 @@ static struct video_device em28xx_radio_template = {
#endif
};
-/******************************** usb interface *****************************************/
+/******************************** usb interface ******************************/
static LIST_HEAD(em28xx_extension_devlist);
@@ -1875,6 +1897,7 @@ static struct video_device *em28xx_vdev_init(struct em28xx *dev,
vfd->dev = &dev->udev->dev;
vfd->release = video_device_release;
vfd->type = type;
+ vfd->debug = video_debug;
snprintf(vfd->name, sizeof(vfd->name), "%s %s",
dev->name, type_name);
@@ -1898,7 +1921,7 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->udev = udev;
mutex_init(&dev->lock);
- spin_lock_init(&dev->queue_lock);
+ spin_lock_init(&dev->slock);
init_waitqueue_head(&dev->open);
init_waitqueue_head(&dev->wait_frame);
init_waitqueue_head(&dev->wait_stream);
@@ -1910,10 +1933,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->em28xx_read_reg_req = em28xx_read_reg_req;
dev->is_em2800 = em28xx_boards[dev->model].is_em2800;
- errCode = em28xx_read_reg(dev, CHIPID_REG);
- if (errCode >= 0)
- em28xx_info("em28xx chip ID = %d\n", errCode);
-
em28xx_pre_card_setup(dev);
errCode = em28xx_config(dev);
@@ -1946,10 +1965,6 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->width = maxw;
dev->height = maxh;
dev->interlaced = EM28XX_INTERLACED_DEFAULT;
- dev->field_size = dev->width * dev->height;
- dev->frame_size =
- dev->interlaced ? dev->field_size << 1 : dev->field_size;
- dev->bytesperline = dev->width * 2;
dev->hscale = 0;
dev->vscale = 0;
dev->ctl_input = 2;
@@ -2005,6 +2020,10 @@ static int em28xx_init_dev(struct em28xx **devhandle, struct usb_device *udev,
dev->radio_dev->minor & 0x1f);
}
+ /* init video dma queues */
+ INIT_LIST_HEAD(&dev->vidq.active);
+ INIT_LIST_HEAD(&dev->vidq.queued);
+
if (dev->has_msp34xx) {
/* Send a reset to other chips via gpio */
@@ -2048,6 +2067,9 @@ static void request_module_async(struct work_struct *work)
request_module("snd-usb-audio");
else
request_module("em28xx-alsa");
+
+ if (dev->has_dvb)
+ request_module("em28xx-dvb");
}
static void request_modules(struct em28xx *dev)
@@ -2077,22 +2099,24 @@ static int em28xx_usb_probe(struct usb_interface *interface,
ifnum = interface->altsetting[0].desc.bInterfaceNumber;
/* Check to see next free device and mark as used */
- nr=find_first_zero_bit(&em28xx_devused,EM28XX_MAXBOARDS);
- em28xx_devused|=1<<nr;
+ nr = find_first_zero_bit(&em28xx_devused, EM28XX_MAXBOARDS);
+ em28xx_devused |= 1<<nr;
/* Don't register audio interfaces */
if (interface->altsetting[0].desc.bInterfaceClass == USB_CLASS_AUDIO) {
em28xx_err(DRIVER_NAME " audio device (%04x:%04x): interface %i, class %i\n",
- udev->descriptor.idVendor,udev->descriptor.idProduct,
+ udev->descriptor.idVendor,
+ udev->descriptor.idProduct,
ifnum,
interface->altsetting[0].desc.bInterfaceClass);
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
em28xx_err(DRIVER_NAME " new video device (%04x:%04x): interface %i, class %i\n",
- udev->descriptor.idVendor,udev->descriptor.idProduct,
+ udev->descriptor.idVendor,
+ udev->descriptor.idProduct,
ifnum,
interface->altsetting[0].desc.bInterfaceClass);
@@ -2102,18 +2126,19 @@ static int em28xx_usb_probe(struct usb_interface *interface,
if ((endpoint->bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) !=
USB_ENDPOINT_XFER_ISOC) {
em28xx_err(DRIVER_NAME " probing error: endpoint is non-ISO endpoint!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
if ((endpoint->bEndpointAddress & USB_ENDPOINT_DIR_MASK) == USB_DIR_OUT) {
em28xx_err(DRIVER_NAME " probing error: endpoint is ISO OUT endpoint!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENODEV;
}
if (nr >= EM28XX_MAXBOARDS) {
- printk (DRIVER_NAME ": Supports only %i em28xx boards.\n",EM28XX_MAXBOARDS);
- em28xx_devused&=~(1<<nr);
+ printk(DRIVER_NAME ": Supports only %i em28xx boards.\n",
+ EM28XX_MAXBOARDS);
+ em28xx_devused &= ~(1<<nr);
return -ENOMEM;
}
@@ -2121,7 +2146,7 @@ static int em28xx_usb_probe(struct usb_interface *interface,
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
if (dev == NULL) {
em28xx_err(DRIVER_NAME ": out of memory!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
return -ENOMEM;
}
@@ -2145,14 +2170,14 @@ static int em28xx_usb_probe(struct usb_interface *interface,
/* compute alternate max packet sizes */
uif = udev->actconfig->interface[0];
- dev->num_alt=uif->num_altsetting;
- em28xx_info("Alternate settings: %i\n",dev->num_alt);
-// dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)*
- dev->alt_max_pkt_size = kmalloc(32*
- dev->num_alt,GFP_KERNEL);
+ dev->num_alt = uif->num_altsetting;
+ em28xx_info("Alternate settings: %i\n", dev->num_alt);
+/* dev->alt_max_pkt_size = kmalloc(sizeof(*dev->alt_max_pkt_size)* */
+ dev->alt_max_pkt_size = kmalloc(32 * dev->num_alt, GFP_KERNEL);
+
if (dev->alt_max_pkt_size == NULL) {
em28xx_errdev("out of memory!\n");
- em28xx_devused&=~(1<<nr);
+ em28xx_devused &= ~(1<<nr);
kfree(dev);
return -ENOMEM;
}
@@ -2162,11 +2187,11 @@ static int em28xx_usb_probe(struct usb_interface *interface,
wMaxPacketSize);
dev->alt_max_pkt_size[i] =
(tmp & 0x07ff) * (((tmp & 0x1800) >> 11) + 1);
- em28xx_info("Alternate setting %i, max size= %i\n",i,
- dev->alt_max_pkt_size[i]);
+ em28xx_info("Alternate setting %i, max size= %i\n", i,
+ dev->alt_max_pkt_size[i]);
}
- if ((card[nr]>=0)&&(card[nr]<em28xx_bcount))
+ if ((card[nr] >= 0) && (card[nr] < em28xx_bcount))
dev->model = card[nr];
/* allocate device struct */
@@ -2202,7 +2227,8 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
em28xx_info("disconnecting %s\n", dev->vdev->name);
- /* wait until all current v4l2 io is finished then deallocate resources */
+ /* wait until all current v4l2 io is finished then deallocate
+ resources */
mutex_lock(&dev->lock);
wake_up_interruptible_all(&dev->open);
diff --git a/drivers/media/video/em28xx/em28xx.h b/drivers/media/video/em28xx/em28xx.h
index 04e0e48ecab..002f170b211 100644
--- a/drivers/media/video/em28xx/em28xx.h
+++ b/drivers/media/video/em28xx/em28xx.h
@@ -26,11 +26,39 @@
#define _EM28XX_H
#include <linux/videodev2.h>
+#include <media/videobuf-vmalloc.h>
+
#include <linux/i2c.h>
#include <linux/mutex.h>
#include <media/ir-kbd-i2c.h>
-
-#define UNSET -1
+#if defined(CONFIG_VIDEO_EM28XX_DVB) || defined(CONFIG_VIDEO_EM28XX_DVB_MODULE)
+#include <media/videobuf-dvb.h>
+#endif
+#include "tuner-xc2028.h"
+#include "em28xx-reg.h"
+
+/* Boards supported by driver */
+#define EM2800_BOARD_UNKNOWN 0
+#define EM2820_BOARD_UNKNOWN 1
+#define EM2820_BOARD_TERRATEC_CINERGY_250 2
+#define EM2820_BOARD_PINNACLE_USB_2 3
+#define EM2820_BOARD_HAUPPAUGE_WINTV_USB_2 4
+#define EM2820_BOARD_MSI_VOX_USB_2 5
+#define EM2800_BOARD_TERRATEC_CINERGY_200 6
+#define EM2800_BOARD_LEADTEK_WINFAST_USBII 7
+#define EM2800_BOARD_KWORLD_USB2800 8
+#define EM2820_BOARD_PINNACLE_DVC_90 9
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_900 10
+#define EM2880_BOARD_TERRATEC_HYBRID_XS 11
+#define EM2820_BOARD_KWORLD_PVRTV2800RF 12
+#define EM2880_BOARD_TERRATEC_PRODIGY_XS 13
+#define EM2820_BOARD_PROLINK_PLAYTV_USB2 14
+#define EM2800_BOARD_VGEAR_POCKETTV 15
+#define EM2880_BOARD_HAUPPAUGE_WINTV_HVR_950 16
+
+/* Limits minimum and default number of buffers */
+#define EM28XX_MIN_BUF 4
+#define EM28XX_DEF_BUF 8
/* maximum number of em28xx boards */
#define EM28XX_MAXBOARDS 4 /*FIXME: should be bigger */
@@ -81,31 +109,78 @@
/* time in msecs to wait for i2c writes to finish */
#define EM2800_I2C_WRITE_TIMEOUT 20
-/* the various frame states */
-enum em28xx_frame_state {
- F_UNUSED = 0,
- F_QUEUED,
- F_GRABBING,
- F_DONE,
- F_ERROR,
+enum em28xx_mode {
+ EM28XX_MODE_UNDEFINED,
+ EM28XX_ANALOG_MODE,
+ EM28XX_DIGITAL_MODE,
};
-/* stream states */
enum em28xx_stream_state {
STREAM_OFF,
STREAM_INTERRUPT,
STREAM_ON,
};
-/* frames */
-struct em28xx_frame_t {
- void *bufmem;
- struct v4l2_buffer buf;
- enum em28xx_frame_state state;
+struct em28xx;
+
+struct em28xx_usb_isoc_ctl {
+ /* max packet size of isoc transaction */
+ int max_pkt_size;
+
+ /* number of allocated urbs */
+ int num_bufs;
+
+ /* urb for isoc transfers */
+ struct urb **urb;
+
+ /* transfer buffers for isoc transfer */
+ char **transfer_buffer;
+
+ /* Last buffer command and region */
+ u8 cmd;
+ int pos, size, pktsize;
+
+ /* Last field: ODD or EVEN? */
+ int field;
+
+ /* Stores incomplete commands */
+ u32 tmp_buf;
+ int tmp_buf_len;
+
+ /* Stores already requested buffers */
+ struct em28xx_buffer *buf;
+
+ /* Stores the number of received fields */
+ int nfields;
+
+ /* isoc urb callback */
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
+
+};
+
+struct em28xx_fmt {
+ char *name;
+ u32 fourcc; /* v4l2 format id */
+};
+
+/* buffer for one video frame */
+struct em28xx_buffer {
+ /* common v4l buffer stuff -- must be first */
+ struct videobuf_buffer vb;
+
struct list_head frame;
- unsigned long vma_use_count;
int top_field;
- int fieldbytesused;
+ int receiving;
+};
+
+struct em28xx_dmaqueue {
+ struct list_head active;
+ struct list_head queued;
+
+ wait_queue_head_t wq;
+
+ /* Counters to control buffer fill */
+ int pos;
};
/* io methods */
@@ -152,6 +227,12 @@ enum em28xx_decoder {
EM28XX_SAA7114
};
+struct em28xx_reg_seq {
+ int reg;
+ unsigned char val, mask;
+ int sleep;
+};
+
struct em28xx_board {
char *name;
int vchannels;
@@ -165,8 +246,7 @@ struct em28xx_board {
unsigned int mts_firmware:1;
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
-
- unsigned int analog_gpio;
+ unsigned int has_dvb:1;
enum em28xx_decoder decoder;
@@ -199,7 +279,10 @@ enum em28xx_dev_state {
#define EM28XX_NUM_AUDIO_PACKETS 64
#define EM28XX_AUDIO_MAX_PACKET_SIZE 196 /* static value */
#define EM28XX_CAPTURE_STREAM_EN 1
+
+/* em28xx extensions */
#define EM28XX_AUDIO 0x10
+#define EM28XX_DVB 0x20
struct em28xx_audio {
char name[50];
@@ -217,13 +300,24 @@ struct em28xx_audio {
spinlock_t slock;
};
+struct em28xx;
+
+struct em28xx_fh {
+ struct em28xx *dev;
+ unsigned int stream_on:1; /* Locks streams */
+ int radio;
+
+ struct videobuf_queue vb_vidq;
+
+ enum v4l2_buf_type type;
+};
+
/* main device struct */
struct em28xx {
/* generic device properties */
char name[30]; /* name (including minor) of the device */
int model; /* index in the device_data struct */
int devno; /* marks the number of this device */
- unsigned int analog_gpio;
unsigned int is_em2800:1;
unsigned int has_msp34xx:1;
unsigned int has_tda9887:1;
@@ -231,6 +325,16 @@ struct em28xx {
unsigned int has_audio_class:1;
unsigned int has_12mhz_i2s:1;
unsigned int max_range_640_480:1;
+ unsigned int has_dvb:1;
+
+ /* Some older em28xx chips needs a waiting time after writing */
+ unsigned int wait_after_write;
+
+ /* GPIO sequences for analog and digital mode */
+ struct em28xx_reg_seq *analog_gpio, *digital_gpio;
+
+ /* GPIO sequences for tuner callbacks */
+ struct em28xx_reg_seq *tun_analog_gpio, *tun_digital_gpio;
int video_inputs; /* number of video inputs */
struct list_head devlist;
@@ -255,36 +359,28 @@ struct em28xx {
int mute;
int volume;
/* frame properties */
- struct em28xx_frame_t frame[EM28XX_NUM_FRAMES]; /* list of frames */
- int num_frames; /* number of frames currently in use */
- unsigned int frame_count; /* total number of transfered frames */
- struct em28xx_frame_t *frame_current; /* the frame that is being filled */
int width; /* current frame width */
int height; /* current frame height */
- int frame_size; /* current frame size */
- int field_size; /* current field size */
- int bytesperline;
int hscale; /* horizontal scale factor (see datasheet) */
int vscale; /* vertical scale factor (see datasheet) */
int interlaced; /* 1=interlace fileds, 0=just top fileds */
- int type;
unsigned int video_bytesread; /* Number of bytes read */
unsigned long hash; /* eeprom hash - for boards with generic ID */
- unsigned long i2c_hash; /* i2c devicelist hash - for boards with generic ID */
+ unsigned long i2c_hash; /* i2c devicelist hash -
+ for boards with generic ID */
struct em28xx_audio *adev;
/* states */
enum em28xx_dev_state state;
- enum em28xx_stream_state stream;
enum em28xx_io_method io;
struct work_struct request_module_wk;
/* locks */
struct mutex lock;
- spinlock_t queue_lock;
+ /* spinlock_t queue_lock; */
struct list_head inqueue, outqueue;
wait_queue_head_t open, wait_frame, wait_stream;
struct video_device *vbi_dev;
@@ -292,6 +388,11 @@ struct em28xx {
unsigned char eedata[256];
+ /* Isoc control struct */
+ struct em28xx_dmaqueue vidq;
+ struct em28xx_usb_isoc_ctl isoc_ctl;
+ spinlock_t slock;
+
/* usb transfer */
struct usb_device *udev; /* the usb device */
int alt; /* alternate */
@@ -301,20 +402,21 @@ struct em28xx {
struct urb *urb[EM28XX_NUM_BUFS]; /* urb for isoc transfers */
char *transfer_buffer[EM28XX_NUM_BUFS]; /* transfer buffers for isoc transfer */
/* helper funcs that call usb_control_msg */
- int (*em28xx_write_regs) (struct em28xx * dev, u16 reg, char *buf,
- int len);
- int (*em28xx_read_reg) (struct em28xx * dev, u16 reg);
- int (*em28xx_read_reg_req_len) (struct em28xx * dev, u8 req, u16 reg,
+ int (*em28xx_write_regs) (struct em28xx *dev, u16 reg,
char *buf, int len);
- int (*em28xx_write_regs_req) (struct em28xx * dev, u8 req, u16 reg,
+ int (*em28xx_read_reg) (struct em28xx *dev, u16 reg);
+ int (*em28xx_read_reg_req_len) (struct em28xx *dev, u8 req, u16 reg,
+ char *buf, int len);
+ int (*em28xx_write_regs_req) (struct em28xx *dev, u8 req, u16 reg,
char *buf, int len);
- int (*em28xx_read_reg_req) (struct em28xx * dev, u8 req, u16 reg);
-};
+ int (*em28xx_read_reg_req) (struct em28xx *dev, u8 req, u16 reg);
-struct em28xx_fh {
- struct em28xx *dev;
- unsigned int stream_on:1; /* Locks streams */
- int radio;
+ enum em28xx_mode mode;
+
+ /* Caches GPO and GPIO registers */
+ unsigned char reg_gpo, reg_gpio;
+
+ struct em28xx_dvb *dvb;
};
struct em28xx_ops {
@@ -351,22 +453,27 @@ int em28xx_colorlevels_set_default(struct em28xx *dev);
int em28xx_capture_start(struct em28xx *dev, int start);
int em28xx_outfmt_set_yuv422(struct em28xx *dev);
int em28xx_resolution_set(struct em28xx *dev);
-int em28xx_init_isoc(struct em28xx *dev);
-void em28xx_uninit_isoc(struct em28xx *dev);
int em28xx_set_alternate(struct em28xx *dev);
+int em28xx_init_isoc(struct em28xx *dev, int max_packets,
+ int num_bufs, int max_pkt_size,
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb));
+void em28xx_uninit_isoc(struct em28xx *dev);
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode);
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio);
/* Provided by em28xx-video.c */
int em28xx_register_extension(struct em28xx_ops *dev);
void em28xx_unregister_extension(struct em28xx_ops *dev);
/* Provided by em28xx-cards.c */
-extern int em2800_variant_detect(struct usb_device* udev,int model);
+extern int em2800_variant_detect(struct usb_device *udev, int model);
extern void em28xx_pre_card_setup(struct em28xx *dev);
extern void em28xx_card_setup(struct em28xx *dev);
extern struct em28xx_board em28xx_boards[];
extern struct usb_device_id em28xx_id_table[];
extern const unsigned int em28xx_bcount;
void em28xx_set_ir(struct em28xx *dev, struct IR_i2c *ir);
+int em28xx_tuner_callback(void *ptr, int command, int arg);
/* Provided by em28xx-input.c */
/* TODO: Check if the standard get_key handlers on ir-common can be used */
@@ -375,71 +482,6 @@ int em28xx_get_key_em_haup(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw);
int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
u32 *ir_raw);
-/* em2800 registers */
-#define EM2800_AUDIOSRC_REG 0x08
-
-/* em28xx registers */
-#define I2C_CLK_REG 0x06
-#define CHIPID_REG 0x0a
-#define USBSUSP_REG 0x0c /* */
-
-#define AUDIOSRC_REG 0x0e
-#define XCLK_REG 0x0f
-
-#define VINMODE_REG 0x10
-#define VINCTRL_REG 0x11
-#define VINENABLE_REG 0x12 /* */
-
-#define GAMMA_REG 0x14
-#define RGAIN_REG 0x15
-#define GGAIN_REG 0x16
-#define BGAIN_REG 0x17
-#define ROFFSET_REG 0x18
-#define GOFFSET_REG 0x19
-#define BOFFSET_REG 0x1a
-
-#define OFLOW_REG 0x1b
-#define HSTART_REG 0x1c
-#define VSTART_REG 0x1d
-#define CWIDTH_REG 0x1e
-#define CHEIGHT_REG 0x1f
-
-#define YGAIN_REG 0x20
-#define YOFFSET_REG 0x21
-#define UVGAIN_REG 0x22
-#define UOFFSET_REG 0x23
-#define VOFFSET_REG 0x24
-#define SHARPNESS_REG 0x25
-
-#define COMPR_REG 0x26
-#define OUTFMT_REG 0x27
-
-#define XMIN_REG 0x28
-#define XMAX_REG 0x29
-#define YMIN_REG 0x2a
-#define YMAX_REG 0x2b
-
-#define HSCALELOW_REG 0x30
-#define HSCALEHIGH_REG 0x31
-#define VSCALELOW_REG 0x32
-#define VSCALEHIGH_REG 0x33
-
-#define AC97LSB_REG 0x40
-#define AC97MSB_REG 0x41
-#define AC97ADDR_REG 0x42
-#define AC97BUSY_REG 0x43
-
-/* em202 registers */
-#define MASTER_AC97 0x02
-#define LINE_IN_AC97 0x10
-#define VIDEO_AC97 0x14
-
-/* register settings */
-#define EM2800_AUDIO_SRC_TUNER 0x0d
-#define EM2800_AUDIO_SRC_LINE 0x0c
-#define EM28XX_AUDIO_SRC_TUNER 0xc0
-#define EM28XX_AUDIO_SRC_LINE 0x80
-
/* printk macros */
#define em28xx_err(fmt, arg...) do {\
@@ -456,80 +498,80 @@ int em28xx_get_key_pinnacle_usb_grey(struct IR_i2c *ir, u32 *ir_key,
printk(KERN_WARNING "%s: "fmt,\
dev->name , ##arg); } while (0)
-inline static int em28xx_compression_disable(struct em28xx *dev)
+static inline int em28xx_compression_disable(struct em28xx *dev)
{
/* side effect of disabling scaler and mixer */
- return em28xx_write_regs(dev, COMPR_REG, "\x00", 1);
+ return em28xx_write_regs(dev, EM28XX_R26_COMPR, "\x00", 1);
}
-inline static int em28xx_contrast_get(struct em28xx *dev)
+static inline int em28xx_contrast_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, YGAIN_REG) & 0x1f;
+ return em28xx_read_reg(dev, EM28XX_R20_YGAIN) & 0x1f;
}
-inline static int em28xx_brightness_get(struct em28xx *dev)
+static inline int em28xx_brightness_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, YOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R21_YOFFSET);
}
-inline static int em28xx_saturation_get(struct em28xx *dev)
+static inline int em28xx_saturation_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, UVGAIN_REG) & 0x1f;
+ return em28xx_read_reg(dev, EM28XX_R22_UVGAIN) & 0x1f;
}
-inline static int em28xx_u_balance_get(struct em28xx *dev)
+static inline int em28xx_u_balance_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, UOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R23_UOFFSET);
}
-inline static int em28xx_v_balance_get(struct em28xx *dev)
+static inline int em28xx_v_balance_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, VOFFSET_REG);
+ return em28xx_read_reg(dev, EM28XX_R24_VOFFSET);
}
-inline static int em28xx_gamma_get(struct em28xx *dev)
+static inline int em28xx_gamma_get(struct em28xx *dev)
{
- return em28xx_read_reg(dev, GAMMA_REG) & 0x3f;
+ return em28xx_read_reg(dev, EM28XX_R14_GAMMA) & 0x3f;
}
-inline static int em28xx_contrast_set(struct em28xx *dev, s32 val)
+static inline int em28xx_contrast_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, YGAIN_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R20_YGAIN, &tmp, 1);
}
-inline static int em28xx_brightness_set(struct em28xx *dev, s32 val)
+static inline int em28xx_brightness_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, YOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R21_YOFFSET, &tmp, 1);
}
-inline static int em28xx_saturation_set(struct em28xx *dev, s32 val)
+static inline int em28xx_saturation_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, UVGAIN_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R22_UVGAIN, &tmp, 1);
}
-inline static int em28xx_u_balance_set(struct em28xx *dev, s32 val)
+static inline int em28xx_u_balance_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, UOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R23_UOFFSET, &tmp, 1);
}
-inline static int em28xx_v_balance_set(struct em28xx *dev, s32 val)
+static inline int em28xx_v_balance_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, VOFFSET_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R24_VOFFSET, &tmp, 1);
}
-inline static int em28xx_gamma_set(struct em28xx *dev, s32 val)
+static inline int em28xx_gamma_set(struct em28xx *dev, s32 val)
{
u8 tmp = (u8) val;
- return em28xx_write_regs(dev, GAMMA_REG, &tmp, 1);
+ return em28xx_write_regs(dev, EM28XX_R14_GAMMA, &tmp, 1);
}
/*FIXME: maxw should be dependent of alt mode */
-inline static unsigned int norm_maxw(struct em28xx *dev)
+static inline unsigned int norm_maxw(struct em28xx *dev)
{
if (dev->max_range_640_480)
return 640;
@@ -537,7 +579,7 @@ inline static unsigned int norm_maxw(struct em28xx *dev)
return 720;
}
-inline static unsigned int norm_maxh(struct em28xx *dev)
+static inline unsigned int norm_maxh(struct em28xx *dev)
{
if (dev->max_range_640_480)
return 480;
diff --git a/drivers/media/video/et61x251/et61x251.h b/drivers/media/video/et61x251/et61x251.h
index 02c741d8f85..cc77d144df3 100644
--- a/drivers/media/video/et61x251/et61x251.h
+++ b/drivers/media/video/et61x251/et61x251.h
@@ -199,7 +199,7 @@ do { \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
- __FILE__, __FUNCTION__, __LINE__ , ## args); \
+ __FILE__, __func__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -209,7 +209,7 @@ do { \
pr_info("et61x251: " fmt "\n", ## args); \
else if ((level) == 3) \
pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -225,7 +225,7 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
__LINE__ , ## args)
#undef PDBGG
diff --git a/drivers/media/video/et61x251/et61x251_core.c b/drivers/media/video/et61x251/et61x251_core.c
index 06b6a3ae06c..5e749c528a6 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 c7fed340565..352f84d440f 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 137c4736da0..8d3c1482e7e 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 dabafdf71e6..11c5fdedc23 100644
--- a/drivers/media/video/ir-kbd-i2c.c
+++ b/drivers/media/video/ir-kbd-i2c.c
@@ -50,7 +50,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)");
@@ -153,7 +153,7 @@ static int get_key_fusionhdtv(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
}
if(buf[0] !=0 || buf[1] !=0 || buf[2] !=0 || buf[3] != 0)
- dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __FUNCTION__,
+ dprintk(2, "%s: 0x%2x 0x%2x 0x%2x 0x%2x\n", __func__,
buf[0], buf[1], buf[2], buf[3]);
/* no key pressed or signal from other ir remote */
@@ -508,10 +508,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:
@@ -532,23 +532,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/Kconfig b/drivers/media/video/ivtv/Kconfig
index 270906fc314..b6171702c4d 100644
--- a/drivers/media/video/ivtv/Kconfig
+++ b/drivers/media/video/ivtv/Kconfig
@@ -10,6 +10,7 @@ config VIDEO_IVTV
select VIDEO_CX25840
select VIDEO_MSP3400
select VIDEO_SAA711X
+ select VIDEO_SAA717X
select VIDEO_SAA7127
select VIDEO_TVAUDIO
select VIDEO_CS53L32A
diff --git a/drivers/media/video/ivtv/ivtv-cards.c b/drivers/media/video/ivtv/ivtv-cards.c
index f23c6b8d691..e908649ea37 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 191aafdd996..9186fa2ee5f 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 948ca35e7ee..065df53f80f 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;
}
@@ -859,7 +883,9 @@ static void ivtv_load_and_init_modules(struct ivtv *itv)
#ifndef CONFIG_VIDEO_SAA7127
hw = ivtv_request_module(itv, hw, "saa7127", IVTV_HW_SAA7127);
#endif
+#ifndef CONFIG_VIDEO_SAA717X
hw = ivtv_request_module(itv, hw, "saa717x", IVTV_HW_SAA717X);
+#endif
#ifndef CONFIG_VIDEO_UPD64031A
hw = ivtv_request_module(itv, hw, "upd64031a", IVTV_HW_UPD64031A);
#endif
diff --git a/drivers/media/video/ivtv/ivtv-driver.h b/drivers/media/video/ivtv/ivtv-driver.h
index 536140f0c19..ba06e813c58 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 6fb96f19a86..a7640c49f1d 100644
--- a/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/drivers/media/video/ivtv/ivtv-fileops.c
@@ -219,7 +219,9 @@ static struct ivtv_buffer *ivtv_get_buffer(struct ivtv_stream *s, int non_block,
/* Process pending program info updates and pending VBI data */
ivtv_update_pgm_info(itv);
- if (jiffies - itv->dualwatch_jiffies > msecs_to_jiffies(1000)) {
+ if (time_after(jiffies,
+ itv->dualwatch_jiffies +
+ msecs_to_jiffies(1000))) {
itv->dualwatch_jiffies = jiffies;
ivtv_dualwatch(itv);
}
@@ -753,7 +755,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-i2c.c b/drivers/media/video/ivtv/ivtv-i2c.c
index fa5ab1eb180..9824eafee02 100644
--- a/drivers/media/video/ivtv/ivtv-i2c.c
+++ b/drivers/media/video/ivtv/ivtv-i2c.c
@@ -177,10 +177,16 @@ int ivtv_i2c_register(struct ivtv *itv, unsigned idx)
}
if (id != I2C_DRIVERID_TUNER) {
- c = i2c_new_device(&itv->i2c_adap, &info);
- if (c->driver == NULL)
+ if (id == I2C_DRIVERID_UPD64031A ||
+ id == I2C_DRIVERID_UPD64083) {
+ unsigned short addrs[2] = { info.addr, I2C_CLIENT_END };
+
+ c = i2c_new_probed_device(&itv->i2c_adap, &info, addrs);
+ } else
+ c = i2c_new_device(&itv->i2c_adap, &info);
+ if (c && c->driver == NULL)
i2c_unregister_device(c);
- else
+ else if (c)
itv->i2c_clients[i] = c;
return itv->i2c_clients[i] ? 0 : -ENODEV;
}
diff --git a/drivers/media/video/ivtv/ivtv-ioctl.c b/drivers/media/video/ivtv/ivtv-ioctl.c
index edef2a57961..15cac181212 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;
@@ -741,7 +742,8 @@ int ivtv_v4l2_ioctls(struct ivtv *itv, struct file *filp, unsigned int cmd, void
memset(vcap, 0, sizeof(*vcap));
strcpy(vcap->driver, IVTV_DRIVER_NAME); /* driver name */
- strcpy(vcap->card, itv->card_name); /* card type */
+ strncpy(vcap->card, itv->card_name,
+ sizeof(vcap->card)-1); /* card type */
strcpy(vcap->bus_info, pci_name(itv->dev)); /* bus info... */
vcap->version = IVTV_DRIVER_VERSION; /* version */
vcap->capabilities = itv->v4l2_cap; /* capabilities */
@@ -827,8 +829,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 +838,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 +863,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 +874,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 +883,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 +1073,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 +1274,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 +1289,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;
}
@@ -1628,6 +1633,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
+ printk("\n");
}
return ivtv_debug_ioctls(filp, cmd, arg);
@@ -1671,6 +1677,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
+ printk("\n");
}
return ivtv_v4l2_ioctls(itv, filp, cmd, arg);
@@ -1684,6 +1691,7 @@ static int ivtv_v4l2_do_ioctl(struct inode *inode, struct file *filp,
if (ivtv_debug & IVTV_DBGFLG_IOCTL) {
printk(KERN_INFO "ivtv%d ioctl: ", itv->num);
v4l_printk_ioctl(cmd);
+ printk("\n");
}
return ivtv_control_ioctls(itv, cmd, arg);
diff --git a/drivers/media/video/ivtv/ivtv-irq.c b/drivers/media/video/ivtv/ivtv-irq.c
index 65604dde972..a329c4689db 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-mailbox.c b/drivers/media/video/ivtv/ivtv-mailbox.c
index 13a6c374d2d..1b5c0ac09a8 100644
--- a/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/drivers/media/video/ivtv/ivtv-mailbox.c
@@ -177,7 +177,8 @@ static int get_mailbox(struct ivtv *itv, struct ivtv_mailbox_data *mbdata, int f
/* Sleep before a retry, if not atomic */
if (!(flags & API_NO_WAIT_MB)) {
- if (jiffies - then > msecs_to_jiffies(10*retries))
+ if (time_after(jiffies,
+ then + msecs_to_jiffies(10*retries)))
break;
ivtv_msleep_timeout(10, 0);
}
@@ -244,7 +245,9 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
data, then just return 0 as there is no need to issue this command again.
Just an optimization to prevent unnecessary use of mailboxes. */
if (itv->api_cache[cmd].last_jiffies &&
- jiffies - itv->api_cache[cmd].last_jiffies < msecs_to_jiffies(1800000) &&
+ time_before(jiffies,
+ itv->api_cache[cmd].last_jiffies +
+ msecs_to_jiffies(1800000)) &&
!memcmp(data, itv->api_cache[cmd].data, sizeof(itv->api_cache[cmd].data))) {
itv->api_cache[cmd].last_jiffies = jiffies;
return 0;
@@ -299,7 +302,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
}
}
while (!(readl(&mbox->flags) & IVTV_MBOX_FIRMWARE_DONE)) {
- if (jiffies - then > api_timeout) {
+ if (time_after(jiffies, then + api_timeout)) {
IVTV_DEBUG_WARN("Could not get result (%s)\n", api_info[cmd].name);
/* reset the mailbox, but it is likely too late already */
write_sync(0, &mbox->flags);
@@ -311,7 +314,7 @@ static int ivtv_api_call(struct ivtv *itv, int cmd, int args, u32 data[])
else
ivtv_msleep_timeout(1, 0);
}
- if (jiffies - then > msecs_to_jiffies(100))
+ if (time_after(jiffies, then + msecs_to_jiffies(100)))
IVTV_DEBUG_WARN("%s took %u jiffies\n",
api_info[cmd].name,
jiffies_to_msecs(jiffies - then));
diff --git a/drivers/media/video/ivtv/ivtv-queue.c b/drivers/media/video/ivtv/ivtv-queue.c
index 39a21671324..3e1deec67a5 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-streams.c b/drivers/media/video/ivtv/ivtv-streams.c
index 24d98ecf35a..4ab8d36831b 100644
--- a/drivers/media/video/ivtv/ivtv-streams.c
+++ b/drivers/media/video/ivtv/ivtv-streams.c
@@ -768,7 +768,8 @@ int ivtv_stop_v4l2_encode_stream(struct ivtv_stream *s, int gop_end)
/* wait 2s for EOS interrupt */
while (!test_bit(IVTV_F_I_EOS, &itv->i_flags) &&
- jiffies < then + msecs_to_jiffies (2000)) {
+ time_before(jiffies,
+ then + msecs_to_jiffies(2000))) {
schedule_timeout(msecs_to_jiffies(10));
}
diff --git a/drivers/media/video/ivtv/ivtv-yuv.c b/drivers/media/video/ivtv/ivtv-yuv.c
index 85183480a22..393d917cd67 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 3d51fa0a52b..e7ccbc895d7 100644
--- a/drivers/media/video/meye.c
+++ b/drivers/media/video/meye.c
@@ -42,15 +42,10 @@
#include <linux/meye.h>
MODULE_AUTHOR("Stelian Pop <stelian@popies.net>");
-MODULE_DESCRIPTION("v4l/v4l2 driver for the MotionEye camera");
+MODULE_DESCRIPTION("v4l2 driver for the MotionEye camera");
MODULE_LICENSE("GPL");
MODULE_VERSION(MEYE_DRIVER_VERSION);
-/* force usage of V4L1 API */
-static int forcev4l1; /* = 0 */
-module_param(forcev4l1, int, 0644);
-MODULE_PARM_DESC(forcev4l1, "force use of V4L1 instead of V4L2");
-
/* number of grab buffers */
static unsigned int gbuffers = 2;
module_param(gbuffers, int, 0444);
@@ -789,7 +784,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);
@@ -876,795 +871,735 @@ static int meye_release(struct inode *inode, struct file *file)
return 0;
}
-static int meye_do_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, void *arg)
+static int meyeioc_g_params(struct meye_params *p)
{
- switch (cmd) {
+ *p = meye.params;
+ return 0;
+}
- case VIDIOCGCAP: {
- struct video_capability *b = arg;
- strcpy(b->name,meye.video_dev->name);
- b->type = VID_TYPE_CAPTURE;
- b->channels = 1;
- b->audios = 0;
- b->maxwidth = 640;
- b->maxheight = 480;
- b->minwidth = 320;
- b->minheight = 240;
- break;
- }
+static int meyeioc_s_params(struct meye_params *jp)
+{
+ if (jp->subsample > 1)
+ return -EINVAL;
- case VIDIOCGCHAN: {
- struct video_channel *v = arg;
- v->flags = 0;
- v->tuners = 0;
- v->type = VIDEO_TYPE_CAMERA;
- if (v->channel != 0)
- return -EINVAL;
- strcpy(v->name,"Camera");
- break;
- }
+ if (jp->quality > 10)
+ return -EINVAL;
- case VIDIOCSCHAN: {
- struct video_channel *v = arg;
- if (v->channel != 0)
- return -EINVAL;
- break;
- }
+ if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63)
+ return -EINVAL;
- case VIDIOCGPICT: {
- struct video_picture *p = arg;
- *p = meye.picture;
- break;
- }
+ if (jp->framerate > 31)
+ return -EINVAL;
- case VIDIOCSPICT: {
- struct video_picture *p = arg;
- if (p->depth != 16)
- return -EINVAL;
- if (p->palette != VIDEO_PALETTE_YUV422 && p->palette != VIDEO_PALETTE_YUYV)
- return -EINVAL;
- mutex_lock(&meye.lock);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERABRIGHTNESS,
- p->brightness >> 10);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAHUE,
- p->hue >> 10);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACOLOR,
- p->colour >> 10);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERACONTRAST,
- p->contrast >> 10);
- meye.picture = *p;
- mutex_unlock(&meye.lock);
- break;
- }
+ mutex_lock(&meye.lock);
- case VIDIOCSYNC: {
- int *i = arg;
- int unused;
+ if (meye.params.subsample != jp->subsample ||
+ meye.params.quality != jp->quality)
+ mchip_hic_stop(); /* need restart */
+
+ meye.params = *jp;
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
+ meye.params.sharpness);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
+ meye.params.agc);
+ sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
+ meye.params.picture);
+ mutex_unlock(&meye.lock);
- if (*i < 0 || *i >= gbuffers)
- return -EINVAL;
+ return 0;
+}
- mutex_lock(&meye.lock);
+static int meyeioc_qbuf_capt(int *nb)
+{
+ if (!meye.grab_fbuffer)
+ return -EINVAL;
- switch (meye.grab_buffer[*i].state) {
+ if (*nb >= gbuffers)
+ return -EINVAL;
- case MEYE_BUF_UNUSED:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- case MEYE_BUF_USING:
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
- if (wait_event_interruptible(meye.proc_list,
- (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
- mutex_unlock(&meye.lock);
- return -EINTR;
- }
- /* fall through */
- case MEYE_BUF_DONE:
- meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
- kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
- }
- mutex_unlock(&meye.lock);
- break;
+ if (*nb < 0) {
+ /* stop capture */
+ mchip_hic_stop();
+ return 0;
}
- case VIDIOCMCAPTURE: {
- struct video_mmap *vm = arg;
- int restart = 0;
-
- if (vm->frame >= gbuffers || vm->frame < 0)
- return -EINVAL;
- if (vm->format != VIDEO_PALETTE_YUV422 && vm->format != VIDEO_PALETTE_YUYV)
- return -EINVAL;
- if (vm->height * vm->width * 2 > gbufsize)
- return -EINVAL;
- if (!meye.grab_fbuffer)
- return -EINVAL;
- if (meye.grab_buffer[vm->frame].state != MEYE_BUF_UNUSED)
- return -EBUSY;
-
- mutex_lock(&meye.lock);
- if (vm->width == 640 && vm->height == 480) {
- if (meye.params.subsample) {
- meye.params.subsample = 0;
- restart = 1;
- }
- } else if (vm->width == 320 && vm->height == 240) {
- if (!meye.params.subsample) {
- meye.params.subsample = 1;
- restart = 1;
- }
- } else {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
+ if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
+ return -EBUSY;
- if (restart || meye.mchip_mode != MCHIP_HIC_MODE_CONT_OUT)
- mchip_continuous_start();
- meye.grab_buffer[vm->frame].state = MEYE_BUF_USING;
- kfifo_put(meye.grabq, (unsigned char *)&vm->frame, sizeof(int));
- mutex_unlock(&meye.lock);
- break;
- }
+ mutex_lock(&meye.lock);
- case VIDIOCGMBUF: {
- struct video_mbuf *vm = arg;
- int i;
+ if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
+ mchip_cont_compression_start();
- memset(vm, 0 , sizeof(*vm));
- vm->size = gbufsize * gbuffers;
- vm->frames = gbuffers;
- for (i = 0; i < gbuffers; i++)
- vm->offsets[i] = i * gbufsize;
- break;
- }
+ meye.grab_buffer[*nb].state = MEYE_BUF_USING;
+ kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
+ mutex_unlock(&meye.lock);
- case MEYEIOC_G_PARAMS: {
- struct meye_params *p = arg;
- *p = meye.params;
- break;
- }
+ return 0;
+}
- case MEYEIOC_S_PARAMS: {
- struct meye_params *jp = arg;
- if (jp->subsample > 1)
- return -EINVAL;
- if (jp->quality > 10)
- return -EINVAL;
- if (jp->sharpness > 63 || jp->agc > 63 || jp->picture > 63)
- return -EINVAL;
- if (jp->framerate > 31)
- return -EINVAL;
- mutex_lock(&meye.lock);
- if (meye.params.subsample != jp->subsample ||
- meye.params.quality != jp->quality)
- mchip_hic_stop(); /* need restart */
- meye.params = *jp;
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERASHARPNESS,
- meye.params.sharpness);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAAGC,
- meye.params.agc);
- sony_pic_camera_command(SONY_PIC_COMMAND_SETCAMERAPICTURE,
- meye.params.picture);
- mutex_unlock(&meye.lock);
- break;
- }
+static int meyeioc_sync(struct file *file, void *fh, int *i)
+{
+ int unused;
- case MEYEIOC_QBUF_CAPT: {
- int *nb = arg;
-
- if (!meye.grab_fbuffer)
- return -EINVAL;
- if (*nb >= gbuffers)
- return -EINVAL;
- if (*nb < 0) {
- /* stop capture */
- mchip_hic_stop();
- return 0;
- }
- if (meye.grab_buffer[*nb].state != MEYE_BUF_UNUSED)
- return -EBUSY;
- mutex_lock(&meye.lock);
- if (meye.mchip_mode != MCHIP_HIC_MODE_CONT_COMP)
- mchip_cont_compression_start();
- meye.grab_buffer[*nb].state = MEYE_BUF_USING;
- kfifo_put(meye.grabq, (unsigned char *)nb, sizeof(int));
+ if (*i < 0 || *i >= gbuffers)
+ return -EINVAL;
+
+ mutex_lock(&meye.lock);
+ switch (meye.grab_buffer[*i].state) {
+
+ case MEYE_BUF_UNUSED:
mutex_unlock(&meye.lock);
- break;
+ return -EINVAL;
+ case MEYE_BUF_USING:
+ if (file->f_flags & O_NONBLOCK) {
+ mutex_unlock(&meye.lock);
+ return -EAGAIN;
+ }
+ if (wait_event_interruptible(meye.proc_list,
+ (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
+ mutex_unlock(&meye.lock);
+ return -EINTR;
+ }
+ /* fall through */
+ case MEYE_BUF_DONE:
+ meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
+ kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
}
+ *i = meye.grab_buffer[*i].size;
+ mutex_unlock(&meye.lock);
+ return 0;
+}
- case MEYEIOC_SYNC: {
- int *i = arg;
- int unused;
+static int meyeioc_stillcapt(void)
+{
+ if (!meye.grab_fbuffer)
+ return -EINVAL;
- if (*i < 0 || *i >= gbuffers)
- return -EINVAL;
+ if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+ return -EBUSY;
- mutex_lock(&meye.lock);
- switch (meye.grab_buffer[*i].state) {
+ mutex_lock(&meye.lock);
+ meye.grab_buffer[0].state = MEYE_BUF_USING;
+ mchip_take_picture();
- case MEYE_BUF_UNUSED:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- case MEYE_BUF_USING:
- if (file->f_flags & O_NONBLOCK) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
- if (wait_event_interruptible(meye.proc_list,
- (meye.grab_buffer[*i].state != MEYE_BUF_USING))) {
- mutex_unlock(&meye.lock);
- return -EINTR;
- }
- /* fall through */
- case MEYE_BUF_DONE:
- meye.grab_buffer[*i].state = MEYE_BUF_UNUSED;
- kfifo_get(meye.doneq, (unsigned char *)&unused, sizeof(int));
- }
- *i = meye.grab_buffer[*i].size;
- mutex_unlock(&meye.lock);
- break;
- }
+ mchip_get_picture(meye.grab_fbuffer,
+ mchip_hsize() * mchip_vsize() * 2);
- case MEYEIOC_STILLCAPT: {
+ meye.grab_buffer[0].state = MEYE_BUF_DONE;
+ mutex_unlock(&meye.lock);
- if (!meye.grab_fbuffer)
- return -EINVAL;
- if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
- return -EBUSY;
- mutex_lock(&meye.lock);
- meye.grab_buffer[0].state = MEYE_BUF_USING;
+ return 0;
+}
+
+static int meyeioc_stilljcapt(int *len)
+{
+ if (!meye.grab_fbuffer)
+ return -EINVAL;
+
+ if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
+ return -EBUSY;
+
+ mutex_lock(&meye.lock);
+ meye.grab_buffer[0].state = MEYE_BUF_USING;
+ *len = -1;
+
+ while (*len == -1) {
mchip_take_picture();
- mchip_get_picture(
- meye.grab_fbuffer,
- mchip_hsize() * mchip_vsize() * 2);
- meye.grab_buffer[0].state = MEYE_BUF_DONE;
- mutex_unlock(&meye.lock);
- break;
+ *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
}
- case MEYEIOC_STILLJCAPT: {
- int *len = arg;
-
- if (!meye.grab_fbuffer)
- return -EINVAL;
- if (meye.grab_buffer[0].state != MEYE_BUF_UNUSED)
- return -EBUSY;
- mutex_lock(&meye.lock);
- meye.grab_buffer[0].state = MEYE_BUF_USING;
- *len = -1;
- while (*len == -1) {
- mchip_take_picture();
- *len = mchip_compress_frame(meye.grab_fbuffer, gbufsize);
- }
- meye.grab_buffer[0].state = MEYE_BUF_DONE;
- mutex_unlock(&meye.lock);
- break;
- }
+ meye.grab_buffer[0].state = MEYE_BUF_DONE;
+ mutex_unlock(&meye.lock);
+ return 0;
+}
- case VIDIOC_QUERYCAP: {
- struct v4l2_capability *cap = arg;
+static int vidioc_querycap(struct file *file, void *fh,
+ struct v4l2_capability *cap)
+{
+ memset(cap, 0, sizeof(*cap));
+ strcpy(cap->driver, "meye");
+ strcpy(cap->card, "meye");
+ sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
- if (forcev4l1)
- return -EINVAL;
+ cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
+ MEYE_DRIVER_MINORVERSION;
- memset(cap, 0, sizeof(*cap));
- strcpy(cap->driver, "meye");
- strcpy(cap->card, "meye");
- sprintf(cap->bus_info, "PCI:%s", pci_name(meye.mchip_dev));
- cap->version = (MEYE_DRIVER_MAJORVERSION << 8) +
- MEYE_DRIVER_MINORVERSION;
- cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
- V4L2_CAP_STREAMING;
- break;
- }
+ cap->capabilities = V4L2_CAP_VIDEO_CAPTURE |
+ V4L2_CAP_STREAMING;
+
+ return 0;
+}
+
+static int vidioc_enum_input(struct file *file, void *fh, struct v4l2_input *i)
+{
+ if (i->index != 0)
+ return -EINVAL;
- case VIDIOC_ENUMINPUT: {
- struct v4l2_input *i = arg;
+ memset(i, 0, sizeof(*i));
+ i->index = 0;
+ strcpy(i->name, "Camera");
+ i->type = V4L2_INPUT_TYPE_CAMERA;
- if (i->index != 0)
- return -EINVAL;
- memset(i, 0, sizeof(*i));
- i->index = 0;
- strcpy(i->name, "Camera");
- i->type = V4L2_INPUT_TYPE_CAMERA;
+ return 0;
+}
+
+static int vidioc_g_input(struct file *file, void *fh, unsigned int *i)
+{
+ *i = 0;
+ return 0;
+}
+
+static int vidioc_s_input(struct file *file, void *fh, unsigned int i)
+{
+ if (i != 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int vidioc_queryctrl(struct file *file, void *fh,
+ struct v4l2_queryctrl *c)
+{
+ switch (c->id) {
+
+ case V4L2_CID_BRIGHTNESS:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Brightness");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+ c->flags = 0;
+ break;
+ case V4L2_CID_HUE:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Hue");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+ c->flags = 0;
+ break;
+ case V4L2_CID_CONTRAST:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Contrast");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+ c->flags = 0;
+ break;
+ case V4L2_CID_SATURATION:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Saturation");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+ c->flags = 0;
+ break;
+ case V4L2_CID_AGC:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Agc");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ 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");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 32;
+
+ /* 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;
+ strcpy(c->name, "Picture");
+ c->minimum = 0;
+ c->maximum = 63;
+ c->step = 1;
+ c->default_value = 0;
+ c->flags = 0;
+ break;
+ case V4L2_CID_JPEGQUAL:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "JPEG quality");
+ c->minimum = 0;
+ c->maximum = 10;
+ c->step = 1;
+ c->default_value = 8;
+ c->flags = 0;
+ break;
+ case V4L2_CID_FRAMERATE:
+ c->type = V4L2_CTRL_TYPE_INTEGER;
+ strcpy(c->name, "Framerate");
+ c->minimum = 0;
+ c->maximum = 31;
+ c->step = 1;
+ c->default_value = 0;
+ c->flags = 0;
+ break;
+ default:
+ return -EINVAL;
}
- case VIDIOC_G_INPUT: {
- int *i = arg;
+ return 0;
+}
- *i = 0;
+static int vidioc_s_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+ mutex_lock(&meye.lock);
+ switch (c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
+ meye.picture.brightness = c->value << 10;
+ break;
+ case V4L2_CID_HUE:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
+ meye.picture.hue = c->value << 10;
+ break;
+ case V4L2_CID_CONTRAST:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
+ meye.picture.contrast = c->value << 10;
+ break;
+ case V4L2_CID_SATURATION:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
+ meye.picture.colour = c->value << 10;
+ break;
+ case V4L2_CID_AGC:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
+ 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;
+ break;
+ case V4L2_CID_PICTURE:
+ sony_pic_camera_command(
+ SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
+ meye.params.picture = c->value;
+ break;
+ case V4L2_CID_JPEGQUAL:
+ meye.params.quality = c->value;
+ break;
+ case V4L2_CID_FRAMERATE:
+ meye.params.framerate = c->value;
break;
+ default:
+ mutex_unlock(&meye.lock);
+ return -EINVAL;
}
+ mutex_unlock(&meye.lock);
- case VIDIOC_S_INPUT: {
- int *i = arg;
+ return 0;
+}
- if (*i != 0)
- return -EINVAL;
+static int vidioc_g_ctrl(struct file *file, void *fh, struct v4l2_control *c)
+{
+ mutex_lock(&meye.lock);
+ switch (c->id) {
+ case V4L2_CID_BRIGHTNESS:
+ c->value = meye.picture.brightness >> 10;
+ break;
+ case V4L2_CID_HUE:
+ c->value = meye.picture.hue >> 10;
+ break;
+ case V4L2_CID_CONTRAST:
+ c->value = meye.picture.contrast >> 10;
+ break;
+ case V4L2_CID_SATURATION:
+ c->value = meye.picture.colour >> 10;
+ break;
+ case V4L2_CID_AGC:
+ 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:
+ c->value = meye.params.picture;
+ break;
+ case V4L2_CID_JPEGQUAL:
+ c->value = meye.params.quality;
+ break;
+ case V4L2_CID_FRAMERATE:
+ c->value = meye.params.framerate;
+ break;
+ default:
+ mutex_unlock(&meye.lock);
+ return -EINVAL;
}
+ mutex_unlock(&meye.lock);
- case VIDIOC_QUERYCTRL: {
- struct v4l2_queryctrl *c = arg;
+ return 0;
+}
- switch (c->id) {
+static int vidioc_enum_fmt_cap(struct file *file, void *fh,
+ struct v4l2_fmtdesc *f)
+{
+ if (f->index > 1)
+ return -EINVAL;
- case V4L2_CID_BRIGHTNESS:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Brightness");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_HUE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Hue");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_CONTRAST:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Contrast");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_SATURATION:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Saturation");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_AGC:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Agc");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 48;
- c->flags = 0;
- break;
- case V4L2_CID_SHARPNESS:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Sharpness");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 32;
- c->flags = 0;
- break;
- case V4L2_CID_PICTURE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Picture");
- c->minimum = 0;
- c->maximum = 63;
- c->step = 1;
- c->default_value = 0;
- c->flags = 0;
- break;
- case V4L2_CID_JPEGQUAL:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "JPEG quality");
- c->minimum = 0;
- c->maximum = 10;
- c->step = 1;
- c->default_value = 8;
- c->flags = 0;
- break;
- case V4L2_CID_FRAMERATE:
- c->type = V4L2_CTRL_TYPE_INTEGER;
- strcpy(c->name, "Framerate");
- c->minimum = 0;
- c->maximum = 31;
- c->step = 1;
- c->default_value = 0;
- c->flags = 0;
- break;
- default:
- return -EINVAL;
- }
- break;
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (f->index == 0) {
+ /* standard YUV 422 capture */
+ memset(f, 0, sizeof(*f));
+ f->index = 0;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = 0;
+ strcpy(f->description, "YUV422");
+ f->pixelformat = V4L2_PIX_FMT_YUYV;
+ } else {
+ /* compressed MJPEG capture */
+ memset(f, 0, sizeof(*f));
+ f->index = 1;
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ f->flags = V4L2_FMT_FLAG_COMPRESSED;
+ strcpy(f->description, "MJPEG");
+ f->pixelformat = V4L2_PIX_FMT_MJPEG;
}
- case VIDIOC_S_CTRL: {
- struct v4l2_control *c = arg;
+ return 0;
+}
- mutex_lock(&meye.lock);
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERABRIGHTNESS, c->value);
- meye.picture.brightness = c->value << 10;
- break;
- case V4L2_CID_HUE:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAHUE, c->value);
- meye.picture.hue = c->value << 10;
- break;
- case V4L2_CID_CONTRAST:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERACONTRAST, c->value);
- meye.picture.contrast = c->value << 10;
- break;
- case V4L2_CID_SATURATION:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERACOLOR, c->value);
- meye.picture.colour = c->value << 10;
- break;
- case V4L2_CID_AGC:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAAGC, c->value);
- meye.params.agc = c->value;
- break;
- case V4L2_CID_SHARPNESS:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERASHARPNESS, c->value);
- meye.params.sharpness = c->value;
- break;
- case V4L2_CID_PICTURE:
- sony_pic_camera_command(
- SONY_PIC_COMMAND_SETCAMERAPICTURE, c->value);
- meye.params.picture = c->value;
- break;
- case V4L2_CID_JPEGQUAL:
- meye.params.quality = c->value;
- break;
- case V4L2_CID_FRAMERATE:
- meye.params.framerate = c->value;
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- mutex_unlock(&meye.lock);
- break;
+static int vidioc_try_fmt_cap(struct file *file, void *fh,
+ struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+ f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+ return -EINVAL;
+
+ if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+ f->fmt.pix.field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+
+ if (f->fmt.pix.width <= 320) {
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ } else {
+ f->fmt.pix.width = 640;
+ f->fmt.pix.height = 480;
}
- case VIDIOC_G_CTRL: {
- struct v4l2_control *c = arg;
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.priv = 0;
- mutex_lock(&meye.lock);
- switch (c->id) {
- case V4L2_CID_BRIGHTNESS:
- c->value = meye.picture.brightness >> 10;
- break;
- case V4L2_CID_HUE:
- c->value = meye.picture.hue >> 10;
- break;
- case V4L2_CID_CONTRAST:
- c->value = meye.picture.contrast >> 10;
- break;
- case V4L2_CID_SATURATION:
- c->value = meye.picture.colour >> 10;
- break;
- case V4L2_CID_AGC:
- c->value = meye.params.agc;
- break;
- case V4L2_CID_SHARPNESS:
- c->value = meye.params.sharpness;
- break;
- case V4L2_CID_PICTURE:
- c->value = meye.params.picture;
- break;
- case V4L2_CID_JPEGQUAL:
- c->value = meye.params.quality;
- break;
- case V4L2_CID_FRAMERATE:
- c->value = meye.params.framerate;
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- mutex_unlock(&meye.lock);
+ return 0;
+}
+
+static int vidioc_g_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
+ f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+
+ switch (meye.mchip_mode) {
+ case MCHIP_HIC_MODE_CONT_OUT:
+ default:
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
+ break;
+ case MCHIP_HIC_MODE_CONT_COMP:
+ f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
break;
}
- case VIDIOC_ENUM_FMT: {
- struct v4l2_fmtdesc *f = arg;
-
- if (f->index > 1)
- return -EINVAL;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->index == 0) {
- /* standard YUV 422 capture */
- memset(f, 0, sizeof(*f));
- f->index = 0;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->flags = 0;
- strcpy(f->description, "YUV422");
- f->pixelformat = V4L2_PIX_FMT_YUYV;
- } else {
- /* compressed MJPEG capture */
- memset(f, 0, sizeof(*f));
- f->index = 1;
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- f->flags = V4L2_FMT_FLAG_COMPRESSED;
- strcpy(f->description, "MJPEG");
- f->pixelformat = V4L2_PIX_FMT_MJPEG;
- }
- break;
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ f->fmt.pix.width = mchip_hsize();
+ f->fmt.pix.height = mchip_vsize();
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.priv = 0;
+
+ return 0;
+}
+
+static int vidioc_s_fmt_cap(struct file *file, void *fh, struct v4l2_format *f)
+{
+ if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
+ f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
+ return -EINVAL;
+
+ if (f->fmt.pix.field != V4L2_FIELD_ANY &&
+ f->fmt.pix.field != V4L2_FIELD_NONE)
+ return -EINVAL;
+
+ f->fmt.pix.field = V4L2_FIELD_NONE;
+ mutex_lock(&meye.lock);
+
+ if (f->fmt.pix.width <= 320) {
+ f->fmt.pix.width = 320;
+ f->fmt.pix.height = 240;
+ meye.params.subsample = 1;
+ } else {
+ f->fmt.pix.width = 640;
+ f->fmt.pix.height = 480;
+ meye.params.subsample = 0;
}
- case VIDIOC_TRY_FMT: {
- struct v4l2_format *f = arg;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
- f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- if (f->fmt.pix.width <= 320) {
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- } else {
- f->fmt.pix.width = 640;
- f->fmt.pix.height = 480;
- }
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
+ switch (f->fmt.pix.pixelformat) {
+ case V4L2_PIX_FMT_YUYV:
+ meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
+ break;
+ case V4L2_PIX_FMT_MJPEG:
+ meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
break;
}
- case VIDIOC_G_FMT: {
- struct v4l2_format *f = arg;
+ mutex_unlock(&meye.lock);
+ f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
+ f->fmt.pix.sizeimage = f->fmt.pix.height *
+ f->fmt.pix.bytesperline;
+ f->fmt.pix.colorspace = 0;
+ f->fmt.pix.priv = 0;
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- memset(&f->fmt.pix, 0, sizeof(struct v4l2_pix_format));
- f->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- switch (meye.mchip_mode) {
- case MCHIP_HIC_MODE_CONT_OUT:
- default:
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_YUYV;
- break;
- case MCHIP_HIC_MODE_CONT_COMP:
- f->fmt.pix.pixelformat = V4L2_PIX_FMT_MJPEG;
- break;
- }
- f->fmt.pix.field = V4L2_FIELD_NONE;
- f->fmt.pix.width = mchip_hsize();
- f->fmt.pix.height = mchip_vsize();
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
- break;
- }
+ return 0;
+}
- case VIDIOC_S_FMT: {
- struct v4l2_format *f = arg;
-
- if (f->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (f->fmt.pix.pixelformat != V4L2_PIX_FMT_YUYV &&
- f->fmt.pix.pixelformat != V4L2_PIX_FMT_MJPEG)
- return -EINVAL;
- if (f->fmt.pix.field != V4L2_FIELD_ANY &&
- f->fmt.pix.field != V4L2_FIELD_NONE)
- return -EINVAL;
- f->fmt.pix.field = V4L2_FIELD_NONE;
- mutex_lock(&meye.lock);
- if (f->fmt.pix.width <= 320) {
- f->fmt.pix.width = 320;
- f->fmt.pix.height = 240;
- meye.params.subsample = 1;
- } else {
- f->fmt.pix.width = 640;
- f->fmt.pix.height = 480;
- meye.params.subsample = 0;
- }
- switch (f->fmt.pix.pixelformat) {
- case V4L2_PIX_FMT_YUYV:
- meye.mchip_mode = MCHIP_HIC_MODE_CONT_OUT;
- break;
- case V4L2_PIX_FMT_MJPEG:
- meye.mchip_mode = MCHIP_HIC_MODE_CONT_COMP;
- break;
- }
- mutex_unlock(&meye.lock);
- f->fmt.pix.bytesperline = f->fmt.pix.width * 2;
- f->fmt.pix.sizeimage = f->fmt.pix.height *
- f->fmt.pix.bytesperline;
- f->fmt.pix.colorspace = 0;
- f->fmt.pix.priv = 0;
+static int vidioc_reqbufs(struct file *file, void *fh,
+ struct v4l2_requestbuffers *req)
+{
+ int i;
- break;
- }
+ if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
- case VIDIOC_REQBUFS: {
- struct v4l2_requestbuffers *req = arg;
- int i;
+ if (req->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
- if (req->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (req->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- if (meye.grab_fbuffer && req->count == gbuffers) {
- /* already allocated, no modifications */
- break;
- }
- mutex_lock(&meye.lock);
- if (meye.grab_fbuffer) {
- for (i = 0; i < gbuffers; i++)
- if (meye.vma_use_count[i]) {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
- meye.grab_fbuffer = NULL;
- }
- gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
- req->count = gbuffers;
- meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
- if (!meye.grab_fbuffer) {
- printk(KERN_ERR "meye: v4l framebuffer allocation"
- " failed\n");
- mutex_unlock(&meye.lock);
- return -ENOMEM;
- }
- for (i = 0; i < gbuffers; i++)
- meye.vma_use_count[i] = 0;
- mutex_unlock(&meye.lock);
- break;
+ if (meye.grab_fbuffer && req->count == gbuffers) {
+ /* already allocated, no modifications */
+ return 0;
}
- case VIDIOC_QUERYBUF: {
- struct v4l2_buffer *buf = arg;
- int index = buf->index;
-
- if (index < 0 || index >= gbuffers)
- return -EINVAL;
- memset(buf, 0, sizeof(*buf));
- buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
- buf->index = index;
- buf->bytesused = meye.grab_buffer[index].size;
- buf->flags = V4L2_BUF_FLAG_MAPPED;
- if (meye.grab_buffer[index].state == MEYE_BUF_USING)
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
- if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
- buf->flags |= V4L2_BUF_FLAG_DONE;
- buf->field = V4L2_FIELD_NONE;
- buf->timestamp = meye.grab_buffer[index].timestamp;
- buf->sequence = meye.grab_buffer[index].sequence;
- buf->memory = V4L2_MEMORY_MMAP;
- buf->m.offset = index * gbufsize;
- buf->length = gbufsize;
- break;
+ mutex_lock(&meye.lock);
+ if (meye.grab_fbuffer) {
+ for (i = 0; i < gbuffers; i++)
+ if (meye.vma_use_count[i]) {
+ mutex_unlock(&meye.lock);
+ return -EINVAL;
+ }
+ rvfree(meye.grab_fbuffer, gbuffers * gbufsize);
+ meye.grab_fbuffer = NULL;
}
- case VIDIOC_QBUF: {
- struct v4l2_buffer *buf = arg;
-
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
- if (buf->index < 0 || buf->index >= gbuffers)
- return -EINVAL;
- if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
- return -EINVAL;
- mutex_lock(&meye.lock);
- buf->flags |= V4L2_BUF_FLAG_QUEUED;
- buf->flags &= ~V4L2_BUF_FLAG_DONE;
- meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
- kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
+ gbuffers = max(2, min((int)req->count, MEYE_MAX_BUFNBRS));
+ req->count = gbuffers;
+ meye.grab_fbuffer = rvmalloc(gbuffers * gbufsize);
+
+ if (!meye.grab_fbuffer) {
+ printk(KERN_ERR "meye: v4l framebuffer allocation"
+ " failed\n");
mutex_unlock(&meye.lock);
- break;
+ return -ENOMEM;
}
- case VIDIOC_DQBUF: {
- struct v4l2_buffer *buf = arg;
- int reqnr;
+ for (i = 0; i < gbuffers; i++)
+ meye.vma_use_count[i] = 0;
- if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
- return -EINVAL;
- if (buf->memory != V4L2_MEMORY_MMAP)
- return -EINVAL;
+ mutex_unlock(&meye.lock);
- mutex_lock(&meye.lock);
- if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
- mutex_unlock(&meye.lock);
- return -EAGAIN;
- }
- if (wait_event_interruptible(meye.proc_list,
- kfifo_len(meye.doneq) != 0) < 0) {
- mutex_unlock(&meye.lock);
- return -EINTR;
- }
- if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
- sizeof(int))) {
- mutex_unlock(&meye.lock);
- return -EBUSY;
- }
- if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
- buf->index = reqnr;
- buf->bytesused = meye.grab_buffer[reqnr].size;
- buf->flags = V4L2_BUF_FLAG_MAPPED;
- buf->field = V4L2_FIELD_NONE;
- buf->timestamp = meye.grab_buffer[reqnr].timestamp;
- buf->sequence = meye.grab_buffer[reqnr].sequence;
- buf->memory = V4L2_MEMORY_MMAP;
- buf->m.offset = reqnr * gbufsize;
- buf->length = gbufsize;
- meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
+ return 0;
+}
+
+static int vidioc_querybuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ int index = buf->index;
+
+ if (index < 0 || index >= gbuffers)
+ return -EINVAL;
+
+ memset(buf, 0, sizeof(*buf));
+
+ buf->type = V4L2_BUF_TYPE_VIDEO_CAPTURE;
+ buf->index = index;
+ buf->bytesused = meye.grab_buffer[index].size;
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+
+ if (meye.grab_buffer[index].state == MEYE_BUF_USING)
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+
+ if (meye.grab_buffer[index].state == MEYE_BUF_DONE)
+ buf->flags |= V4L2_BUF_FLAG_DONE;
+
+ buf->field = V4L2_FIELD_NONE;
+ buf->timestamp = meye.grab_buffer[index].timestamp;
+ buf->sequence = meye.grab_buffer[index].sequence;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = index * gbufsize;
+ buf->length = gbufsize;
+
+ return 0;
+}
+
+static int vidioc_qbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ if (buf->index < 0 || buf->index >= gbuffers)
+ return -EINVAL;
+
+ if (meye.grab_buffer[buf->index].state != MEYE_BUF_UNUSED)
+ return -EINVAL;
+
+ mutex_lock(&meye.lock);
+ buf->flags |= V4L2_BUF_FLAG_QUEUED;
+ buf->flags &= ~V4L2_BUF_FLAG_DONE;
+ meye.grab_buffer[buf->index].state = MEYE_BUF_USING;
+ kfifo_put(meye.grabq, (unsigned char *)&buf->index, sizeof(int));
+ mutex_unlock(&meye.lock);
+
+ return 0;
+}
+
+static int vidioc_dqbuf(struct file *file, void *fh, struct v4l2_buffer *buf)
+{
+ int reqnr;
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ if (buf->memory != V4L2_MEMORY_MMAP)
+ return -EINVAL;
+
+ mutex_lock(&meye.lock);
+
+ if (kfifo_len(meye.doneq) == 0 && file->f_flags & O_NONBLOCK) {
mutex_unlock(&meye.lock);
- break;
+ return -EAGAIN;
}
- case VIDIOC_STREAMON: {
- mutex_lock(&meye.lock);
- switch (meye.mchip_mode) {
- case MCHIP_HIC_MODE_CONT_OUT:
- mchip_continuous_start();
- break;
- case MCHIP_HIC_MODE_CONT_COMP:
- mchip_cont_compression_start();
- break;
- default:
- mutex_unlock(&meye.lock);
- return -EINVAL;
- }
+ if (wait_event_interruptible(meye.proc_list,
+ kfifo_len(meye.doneq) != 0) < 0) {
mutex_unlock(&meye.lock);
- break;
+ return -EINTR;
}
- case VIDIOC_STREAMOFF: {
- int i;
+ if (!kfifo_get(meye.doneq, (unsigned char *)&reqnr,
+ sizeof(int))) {
+ mutex_unlock(&meye.lock);
+ return -EBUSY;
+ }
- mutex_lock(&meye.lock);
- mchip_hic_stop();
- kfifo_reset(meye.grabq);
- kfifo_reset(meye.doneq);
- for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
- meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+ if (meye.grab_buffer[reqnr].state != MEYE_BUF_DONE) {
mutex_unlock(&meye.lock);
- break;
+ return -EINVAL;
}
- /*
- * XXX what about private snapshot ioctls ?
- * Do they need to be converted to V4L2 ?
- */
+ buf->index = reqnr;
+ buf->bytesused = meye.grab_buffer[reqnr].size;
+ buf->flags = V4L2_BUF_FLAG_MAPPED;
+ buf->field = V4L2_FIELD_NONE;
+ buf->timestamp = meye.grab_buffer[reqnr].timestamp;
+ buf->sequence = meye.grab_buffer[reqnr].sequence;
+ buf->memory = V4L2_MEMORY_MMAP;
+ buf->m.offset = reqnr * gbufsize;
+ buf->length = gbufsize;
+ meye.grab_buffer[reqnr].state = MEYE_BUF_UNUSED;
+ mutex_unlock(&meye.lock);
+
+ return 0;
+}
+static int vidioc_streamon(struct file *file, void *fh, enum v4l2_buf_type i)
+{
+ mutex_lock(&meye.lock);
+
+ switch (meye.mchip_mode) {
+ case MCHIP_HIC_MODE_CONT_OUT:
+ mchip_continuous_start();
+ break;
+ case MCHIP_HIC_MODE_CONT_COMP:
+ mchip_cont_compression_start();
+ break;
default:
- return -ENOIOCTLCMD;
+ mutex_unlock(&meye.lock);
+ return -EINVAL;
}
+ mutex_unlock(&meye.lock);
+
return 0;
}
-static int meye_ioctl(struct inode *inode, struct file *file,
- unsigned int cmd, unsigned long arg)
+static int vidioc_streamoff(struct file *file, void *fh, enum v4l2_buf_type i)
{
- return video_usercopy(inode, file, cmd, arg, meye_do_ioctl);
+ mutex_lock(&meye.lock);
+ mchip_hic_stop();
+ kfifo_reset(meye.grabq);
+ kfifo_reset(meye.doneq);
+
+ for (i = 0; i < MEYE_MAX_BUFNBRS; i++)
+ meye.grab_buffer[i].state = MEYE_BUF_UNUSED;
+
+ mutex_unlock(&meye.lock);
+ return 0;
+}
+
+static int vidioc_default(struct file *file, void *fh, int cmd, void *arg)
+{
+ switch (cmd) {
+ case MEYEIOC_G_PARAMS:
+ return meyeioc_g_params((struct meye_params *) arg);
+
+ case MEYEIOC_S_PARAMS:
+ return meyeioc_s_params((struct meye_params *) arg);
+
+ case MEYEIOC_QBUF_CAPT:
+ return meyeioc_qbuf_capt((int *) arg);
+
+ case MEYEIOC_SYNC:
+ return meyeioc_sync(file, fh, (int *) arg);
+
+ case MEYEIOC_STILLCAPT:
+ return meyeioc_stillcapt();
+
+ case MEYEIOC_STILLJCAPT:
+ return meyeioc_stilljcapt((int *) arg);
+
+ default:
+ return -EINVAL;
+ }
+
}
static unsigned int meye_poll(struct file *file, poll_table *wait)
@@ -1752,8 +1687,10 @@ static const struct file_operations meye_fops = {
.open = meye_open,
.release = meye_release,
.mmap = meye_mmap,
- .ioctl = meye_ioctl,
+ .ioctl = video_ioctl2,
+#ifdef CONFIG_COMPAT
.compat_ioctl = v4l_compat_ioctl32,
+#endif
.poll = meye_poll,
.llseek = no_llseek,
};
@@ -1765,6 +1702,24 @@ static struct video_device meye_template = {
.fops = &meye_fops,
.release = video_device_release,
.minor = -1,
+ .vidioc_querycap = vidioc_querycap,
+ .vidioc_enum_input = vidioc_enum_input,
+ .vidioc_g_input = vidioc_g_input,
+ .vidioc_s_input = vidioc_s_input,
+ .vidioc_queryctrl = vidioc_queryctrl,
+ .vidioc_s_ctrl = vidioc_s_ctrl,
+ .vidioc_g_ctrl = vidioc_g_ctrl,
+ .vidioc_enum_fmt_cap = vidioc_enum_fmt_cap,
+ .vidioc_try_fmt_cap = vidioc_try_fmt_cap,
+ .vidioc_g_fmt_cap = vidioc_g_fmt_cap,
+ .vidioc_s_fmt_cap = vidioc_s_fmt_cap,
+ .vidioc_reqbufs = vidioc_reqbufs,
+ .vidioc_querybuf = vidioc_querybuf,
+ .vidioc_qbuf = vidioc_qbuf,
+ .vidioc_dqbuf = vidioc_dqbuf,
+ .vidioc_streamon = vidioc_streamon,
+ .vidioc_streamoff = vidioc_streamoff,
+ .vidioc_default = vidioc_default,
};
#ifdef CONFIG_PM
diff --git a/drivers/media/video/msp3400-driver.c b/drivers/media/video/msp3400-driver.c
index 7a11f3159e3..b73c740f7fb 100644
--- a/drivers/media/video/msp3400-driver.c
+++ b/drivers/media/video/msp3400-driver.c
@@ -366,7 +366,7 @@ int msp_sleep(struct msp_state *state, int timeout)
}
/* ------------------------------------------------------------------------ */
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
static int msp_mode_v4l2_to_v4l1(int rxsubchans, int audmode)
{
if (rxsubchans == V4L2_TUNER_SUB_MONO)
@@ -514,7 +514,7 @@ static int msp_command(struct i2c_client *client, unsigned int cmd, void *arg)
/* --- v4l ioctls --- */
/* take care: bttv does userspace copying, we'll get a
kernel pointer here... */
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
case VIDIOCGAUDIO:
{
struct video_audio *va = arg;
diff --git a/drivers/media/video/msp3400-kthreads.c b/drivers/media/video/msp3400-kthreads.c
index 61ec794a737..7f556859279 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 74fd6a01d4c..fbcb2823373 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/mt20xx.h b/drivers/media/video/mt20xx.h
index 5e9c825d2e9..aa848e14ce5 100644
--- a/drivers/media/video/mt20xx.h
+++ b/drivers/media/video/mt20xx.h
@@ -29,7 +29,7 @@ static inline struct dvb_frontend *microtune_attach(struct dvb_frontend *fe,
struct i2c_adapter* i2c_adap,
u8 i2c_addr)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
diff --git a/drivers/media/video/mt9m001.c b/drivers/media/video/mt9m001.c
new file mode 100644
index 00000000000..3fb5f63df1e
--- /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", __func__);
+
+ 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 00000000000..d4b9e274434
--- /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 cb5a510f925..f68e91fbe7f 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 6590058e8ff..eafb0c7736e 100644
--- a/drivers/media/video/ov511.c
+++ b/drivers/media/video/ov511.c
@@ -4659,7 +4659,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,
};
@@ -5831,7 +5833,7 @@ ov51x_probe(struct usb_interface *intf, const struct usb_device_id *id)
goto error;
memcpy(ov->vdev, &vdev_template, sizeof(*ov->vdev));
- ov->vdev->dev = &dev->dev;
+ ov->vdev->dev = &intf->dev;
video_set_drvdata(ov->vdev, ov);
for (i = 0; i < OV511_MAX_UNIT_VIDEO; i++) {
diff --git a/drivers/media/video/ov511.h b/drivers/media/video/ov511.h
index 18c64222dd1..1010e51189b 100644
--- a/drivers/media/video/ov511.h
+++ b/drivers/media/video/ov511.h
@@ -12,7 +12,7 @@
#ifdef OV511_DEBUG
#define PDEBUG(level, fmt, args...) \
if (debug >= (level)) info("[%s:%d] " fmt, \
- __FUNCTION__, __LINE__ , ## args)
+ __func__, __LINE__ , ## args)
#else
#define PDEBUG(level, fmt, args...) do {} while(0)
#endif
diff --git a/drivers/media/video/ovcamchip/ovcamchip_priv.h b/drivers/media/video/ovcamchip/ovcamchip_priv.h
index 50c7763d44b..9afa4fe4772 100644
--- a/drivers/media/video/ovcamchip/ovcamchip_priv.h
+++ b/drivers/media/video/ovcamchip/ovcamchip_priv.h
@@ -24,11 +24,11 @@ extern int ovcamchip_debug;
#define PDEBUG(level, fmt, args...) \
if (ovcamchip_debug >= (level)) pr_debug("[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+ __func__, __LINE__ , ## args)
#define DDEBUG(level, dev, fmt, args...) \
if (ovcamchip_debug >= (level)) dev_dbg(dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args)
+ __func__, __LINE__ , ## args)
/* Number of times to retry chip detection. Increase this if you are getting
* "Failed to init camera chip" */
diff --git a/drivers/media/video/pms.c b/drivers/media/video/pms.c
index 6820c2aabd3..51b1461d8fb 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/Kconfig b/drivers/media/video/pvrusb2/Kconfig
index 6fc1b8be1a1..a8da90f69dd 100644
--- a/drivers/media/video/pvrusb2/Kconfig
+++ b/drivers/media/video/pvrusb2/Kconfig
@@ -58,6 +58,30 @@ config VIDEO_PVRUSB2_SYSFS
Note: This feature is experimental and subject to change.
+config VIDEO_PVRUSB2_DVB
+ bool "pvrusb2 DVB support (EXPERIMENTAL)"
+ default n
+ depends on VIDEO_PVRUSB2 && DVB_CORE && EXPERIMENTAL
+ select DVB_LGDT330X if !DVB_FE_CUSTOMISE
+ select DVB_S5H1409 if !DVB_FE_CUSTOMISE
+ select DVB_TDA10048 if !DVB_FE_CUSTOMIZE
+ select DVB_TDA18271 if !DVB_FE_CUSTOMIZE
+ select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select TUNER_TDA8290 if !DVB_FE_CUSTOMIZE
+ ---help---
+
+ This option enables compilation of a DVB interface for the
+ pvrusb2 driver. Currently this is very very experimental.
+ It is also limiting - the DVB interface can only access the
+ digital side of hybrid devices, and there are going to be
+ issues if you attempt to mess with the V4L side at the same
+ time. Don't turn this on unless you know what you are
+ doing.
+
+ If you are in doubt, say N.
+
+ Note: This feature is very experimental and might break
+
config VIDEO_PVRUSB2_DEBUGIFC
bool "pvrusb2 debug interface"
depends on VIDEO_PVRUSB2_SYSFS
diff --git a/drivers/media/video/pvrusb2/Makefile b/drivers/media/video/pvrusb2/Makefile
index 47284e55864..5b3083c89aa 100644
--- a/drivers/media/video/pvrusb2/Makefile
+++ b/drivers/media/video/pvrusb2/Makefile
@@ -1,5 +1,6 @@
obj-pvrusb2-sysfs-$(CONFIG_VIDEO_PVRUSB2_SYSFS) := pvrusb2-sysfs.o
obj-pvrusb2-debugifc-$(CONFIG_VIDEO_PVRUSB2_DEBUGIFC) := pvrusb2-debugifc.o
+obj-pvrusb2-dvb-$(CONFIG_VIDEO_PVRUSB2_DVB) := pvrusb2-dvb.o
pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
pvrusb2-audio.o pvrusb2-i2c-chips-v4l2.o \
@@ -9,6 +10,11 @@ pvrusb2-objs := pvrusb2-i2c-core.o pvrusb2-i2c-cmd-v4l2.o \
pvrusb2-ctrl.o pvrusb2-std.o pvrusb2-devattr.o \
pvrusb2-context.o pvrusb2-io.o pvrusb2-ioread.o \
pvrusb2-cx2584x-v4l.o pvrusb2-wm8775.o \
+ $(obj-pvrusb2-dvb-y) \
$(obj-pvrusb2-sysfs-y) $(obj-pvrusb2-debugifc-y)
obj-$(CONFIG_VIDEO_PVRUSB2) += pvrusb2.o
+
+EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
+EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/drivers/media/video/pvrusb2/pvrusb2-context.c b/drivers/media/video/pvrusb2/pvrusb2-context.c
index 160437b21e6..b5db6a5bab3 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-context.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-context.c
@@ -23,39 +23,193 @@
#include "pvrusb2-ioread.h"
#include "pvrusb2-hdw.h"
#include "pvrusb2-debug.h"
+#include <linux/wait.h>
+#include <linux/kthread.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <linux/slab.h>
+static struct pvr2_context *pvr2_context_exist_first;
+static struct pvr2_context *pvr2_context_exist_last;
+static struct pvr2_context *pvr2_context_notify_first;
+static struct pvr2_context *pvr2_context_notify_last;
+static DEFINE_MUTEX(pvr2_context_mutex);
+static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_sync_data);
+static DECLARE_WAIT_QUEUE_HEAD(pvr2_context_cleanup_data);
+static int pvr2_context_cleanup_flag;
+static int pvr2_context_cleaned_flag;
+static struct task_struct *pvr2_context_thread_ptr;
+
+
+static void pvr2_context_set_notify(struct pvr2_context *mp, int fl)
+{
+ int signal_flag = 0;
+ mutex_lock(&pvr2_context_mutex);
+ if (fl) {
+ if (!mp->notify_flag) {
+ signal_flag = (pvr2_context_notify_first == NULL);
+ mp->notify_prev = pvr2_context_notify_last;
+ mp->notify_next = NULL;
+ pvr2_context_notify_last = mp;
+ if (mp->notify_prev) {
+ mp->notify_prev->notify_next = mp;
+ } else {
+ pvr2_context_notify_first = mp;
+ }
+ mp->notify_flag = !0;
+ }
+ } else {
+ if (mp->notify_flag) {
+ mp->notify_flag = 0;
+ if (mp->notify_next) {
+ mp->notify_next->notify_prev = mp->notify_prev;
+ } else {
+ pvr2_context_notify_last = mp->notify_prev;
+ }
+ if (mp->notify_prev) {
+ mp->notify_prev->notify_next = mp->notify_next;
+ } else {
+ pvr2_context_notify_first = mp->notify_next;
+ }
+ }
+ }
+ mutex_unlock(&pvr2_context_mutex);
+ if (signal_flag) wake_up(&pvr2_context_sync_data);
+}
+
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);
+ pvr2_context_set_notify(mp, 0);
+ mutex_lock(&pvr2_context_mutex);
+ if (mp->exist_next) {
+ mp->exist_next->exist_prev = mp->exist_prev;
+ } else {
+ pvr2_context_exist_last = mp->exist_prev;
+ }
+ if (mp->exist_prev) {
+ mp->exist_prev->exist_next = mp->exist_next;
+ } else {
+ pvr2_context_exist_first = mp->exist_next;
+ }
+ if (!pvr2_context_exist_first) {
+ /* Trigger wakeup on control thread in case it is waiting
+ for an exit condition. */
+ wake_up(&pvr2_context_sync_data);
+ }
+ mutex_unlock(&pvr2_context_mutex);
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;
+ pvr2_context_set_notify(mp,!0);
+}
+
- 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;
+static void pvr2_context_check(struct pvr2_context *mp)
+{
+ struct pvr2_channel *ch1, *ch2;
+ pvr2_trace(PVR2_TRACE_CTXT,
+ "pvr2_context %p (notify)", mp);
+ if (!mp->initialized_flag && !mp->disconnect_flag) {
+ mp->initialized_flag = !0;
+ pvr2_trace(PVR2_TRACE_CTXT,
+ "pvr2_context %p (initialize)", 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 continue 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);
+ for (ch1 = mp->mc_first; ch1; ch1 = ch2) {
+ ch2 = ch1->mc_next;
+ if (ch1->check_func) ch1->check_func(ch1);
+ }
+
+ if (mp->disconnect_flag && !mp->mc_first) {
+ /* Go away... */
+ pvr2_context_destroy(mp);
+ return;
+ }
+}
+
+
+static int pvr2_context_shutok(void)
+{
+ return pvr2_context_cleanup_flag && (pvr2_context_exist_first == NULL);
+}
+
+
+static int pvr2_context_thread_func(void *foo)
+{
+ struct pvr2_context *mp;
+
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread start");
+
+ do {
+ while ((mp = pvr2_context_notify_first) != NULL) {
+ pvr2_context_set_notify(mp, 0);
+ pvr2_context_check(mp);
}
- } while (0); pvr2_context_exit(mp);
- }
+ wait_event_interruptible(
+ pvr2_context_sync_data,
+ ((pvr2_context_notify_first != NULL) ||
+ pvr2_context_shutok()));
+ } while (!pvr2_context_shutok());
+
+ pvr2_context_cleaned_flag = !0;
+ wake_up(&pvr2_context_cleanup_data);
+
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread cleaned up");
+
+ wait_event_interruptible(
+ pvr2_context_sync_data,
+ kthread_should_stop());
+
+ pvr2_trace(PVR2_TRACE_CTXT,"pvr2_context thread end");
+
+ return 0;
+}
+
+
+int pvr2_context_global_init(void)
+{
+ pvr2_context_thread_ptr = kthread_run(pvr2_context_thread_func,
+ 0,
+ "pvrusb2-context");
+ return (pvr2_context_thread_ptr ? 0 : -ENOMEM);
+}
+
+
+void pvr2_context_global_done(void)
+{
+ pvr2_context_cleanup_flag = !0;
+ wake_up(&pvr2_context_sync_data);
+ wait_event_interruptible(
+ pvr2_context_cleanup_data,
+ pvr2_context_cleaned_flag);
+ kthread_stop(pvr2_context_thread_ptr);
+}
struct pvr2_context *pvr2_context_create(
@@ -66,67 +220,75 @@ struct pvr2_context *pvr2_context_create(
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);
mp->setup_func = setup_func;
mutex_init(&mp->mutex);
+ mutex_lock(&pvr2_context_mutex);
+ mp->exist_prev = pvr2_context_exist_last;
+ mp->exist_next = NULL;
+ pvr2_context_exist_last = mp;
+ if (mp->exist_prev) {
+ mp->exist_prev->exist_next = mp;
+ } else {
+ pvr2_context_exist_first = mp;
+ }
+ mutex_unlock(&pvr2_context_mutex);
mp->hdw = pvr2_hdw_create(intf,devid);
if (!mp->hdw) {
pvr2_context_destroy(mp);
mp = NULL;
goto done;
}
- pvr2_hdw_set_state_callback(mp->hdw,
- (void (*)(void *))pvr2_context_state_check,
- mp);
- pvr2_context_state_check(mp);
+ pvr2_context_set_notify(mp, !0);
done:
return mp;
}
-void pvr2_context_enter(struct pvr2_context *mp)
+static void pvr2_context_reset_input_limits(struct pvr2_context *mp)
+{
+ unsigned int tmsk,mmsk;
+ struct pvr2_channel *cp;
+ struct pvr2_hdw *hdw = mp->hdw;
+ mmsk = pvr2_hdw_get_input_available(hdw);
+ tmsk = mmsk;
+ for (cp = mp->mc_first; cp; cp = cp->mc_next) {
+ if (!cp->input_mask) continue;
+ tmsk &= cp->input_mask;
+ }
+ pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk);
+ pvr2_hdw_commit_ctl(hdw);
+}
+
+
+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;
@@ -137,6 +299,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);
}
@@ -152,7 +315,10 @@ 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);
+ cp->input_mask = 0;
pvr2_channel_disclaim_stream(cp);
+ pvr2_context_reset_input_limits(mp);
if (cp->mc_next) {
cp->mc_next->mc_prev = cp->mc_prev;
} else {
@@ -164,6 +330,58 @@ void pvr2_channel_done(struct pvr2_channel *cp)
mp->mc_first = cp->mc_next;
}
cp->hdw = NULL;
+ pvr2_context_exit(mp);
+}
+
+
+int pvr2_channel_limit_inputs(struct pvr2_channel *cp,unsigned int cmsk)
+{
+ unsigned int tmsk,mmsk;
+ int ret = 0;
+ struct pvr2_channel *p2;
+ struct pvr2_hdw *hdw = cp->hdw;
+
+ mmsk = pvr2_hdw_get_input_available(hdw);
+ cmsk &= mmsk;
+ if (cmsk == cp->input_mask) {
+ /* No change; nothing to do */
+ return 0;
+ }
+
+ pvr2_context_enter(cp->mc_head);
+ do {
+ if (!cmsk) {
+ cp->input_mask = 0;
+ pvr2_context_reset_input_limits(cp->mc_head);
+ break;
+ }
+ tmsk = mmsk;
+ for (p2 = cp->mc_head->mc_first; p2; p2 = p2->mc_next) {
+ if (p2 == cp) continue;
+ if (!p2->input_mask) continue;
+ tmsk &= p2->input_mask;
+ }
+ if (!(tmsk & cmsk)) {
+ ret = -EPERM;
+ break;
+ }
+ tmsk &= cmsk;
+ if ((ret = pvr2_hdw_set_input_allowed(hdw,mmsk,tmsk)) != 0) {
+ /* Internal failure changing allowed list; probably
+ should not happen, but react if it does. */
+ break;
+ }
+ cp->input_mask = cmsk;
+ pvr2_hdw_commit_ctl(hdw);
+ } while (0);
+ pvr2_context_exit(cp->mc_head);
+ return ret;
+}
+
+
+unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *cp)
+{
+ return cp->input_mask;
}
@@ -173,7 +391,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 a04187a9322..745e270233c 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 {
@@ -41,11 +40,16 @@ struct pvr2_context_stream {
struct pvr2_context {
struct pvr2_channel *mc_first;
struct pvr2_channel *mc_last;
+ struct pvr2_context *exist_next;
+ struct pvr2_context *exist_prev;
+ struct pvr2_context *notify_next;
+ struct pvr2_context *notify_prev;
struct pvr2_hdw *hdw;
struct pvr2_context_stream video_stream;
struct mutex mutex;
+ int notify_flag;
+ int initialized_flag;
int disconnect_flag;
- int init_flag;
/* Called after pvr2_context initialization is complete */
void (*setup_func)(struct pvr2_context *);
@@ -58,12 +62,10 @@ struct pvr2_channel {
struct pvr2_channel *mc_prev;
struct pvr2_context_stream *stream;
struct pvr2_hdw *hdw;
+ unsigned int input_mask;
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 *));
@@ -71,11 +73,15 @@ void pvr2_context_disconnect(struct pvr2_context *);
void pvr2_channel_init(struct pvr2_channel *,struct pvr2_context *);
void pvr2_channel_done(struct pvr2_channel *);
+int pvr2_channel_limit_inputs(struct pvr2_channel *,unsigned int);
+unsigned int pvr2_channel_get_limited_inputs(struct pvr2_channel *);
int pvr2_channel_claim_stream(struct pvr2_channel *,
struct pvr2_context_stream *);
struct pvr2_ioread *pvr2_channel_create_mpeg_stream(
struct pvr2_context_stream *);
+int pvr2_context_global_init(void);
+void pvr2_context_global_done(void);
#endif /* __PVRUSB2_CONTEXT_H */
/*
diff --git a/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 5a3e8d21a38..91a42f2473a 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-cx2584x-v4l.c b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
index ffdc45c324e..97350b048b8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-cx2584x-v4l.c
@@ -84,7 +84,9 @@ static const struct routing_scheme_item routing_schemegv[] = {
.vid = CX25840_COMPOSITE2,
.aud = CX25840_AUDIO5,
},
- [PVR2_CVAL_INPUT_RADIO] = { /* Treat the same as composite */
+ [PVR2_CVAL_INPUT_RADIO] = {
+ /* line-in is used for radio and composite. A GPIO is
+ used to switch between the two choices. */
.vid = CX25840_COMPOSITE1,
.aud = CX25840_AUDIO_SERIAL,
},
diff --git a/drivers/media/video/pvrusb2/pvrusb2-debug.h b/drivers/media/video/pvrusb2/pvrusb2-debug.h
index fca49d8a931..11537ddf8aa 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-debugifc.c b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
index b0687430fdd..b53121c78ff 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-debugifc.c
@@ -164,6 +164,8 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
int ccnt;
int ret;
u32 gpio_dir,gpio_in,gpio_out;
+ struct pvr2_stream_stats stats;
+ struct pvr2_stream *sp;
ret = pvr2_hdw_is_hsm(hdw);
ccnt = scnprintf(buf,acnt,"USB link speed: %s\n",
@@ -182,6 +184,24 @@ int pvr2_debugifc_print_status(struct pvr2_hdw *hdw,
pvr2_hdw_get_streaming(hdw) ? "on" : "off");
bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+
+ sp = pvr2_hdw_get_video_stream(hdw);
+ if (sp) {
+ pvr2_stream_get_stats(sp, &stats, 0);
+ ccnt = scnprintf(
+ buf,acnt,
+ "Bytes streamed=%u"
+ " URBs: queued=%u idle=%u ready=%u"
+ " processed=%u failed=%u\n",
+ stats.bytes_processed,
+ stats.buffers_in_queue,
+ stats.buffers_in_idle,
+ stats.buffers_in_ready,
+ stats.buffers_processed,
+ stats.buffers_failed);
+ bcnt += ccnt; acnt -= ccnt; buf += ccnt;
+ }
+
return bcnt;
}
@@ -220,6 +240,10 @@ static int pvr2_debugifc_do1cmd(struct pvr2_hdw *hdw,const char *buf,
return pvr2_hdw_cmd_decoder_reset(hdw);
} else if (debugifc_match_keyword(wptr,wlen,"worker")) {
return pvr2_hdw_untrip(hdw);
+ } else if (debugifc_match_keyword(wptr,wlen,"usbstats")) {
+ pvr2_stream_get_stats(pvr2_hdw_get_video_stream(hdw),
+ NULL, !0);
+ return 0;
}
return -EINVAL;
} else if (debugifc_match_keyword(wptr,wlen,"cpufw")) {
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.c b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
index fe9991c10cf..2dd06a90adc 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.c
@@ -32,7 +32,15 @@ pvr2_device_desc structures.
/* This is needed in order to pull in tuner type ids... */
#include <linux/i2c.h>
#include <media/tuner.h>
-
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+#include "pvrusb2-hdw-internal.h"
+#include "lgdt330x.h"
+#include "s5h1409.h"
+#include "tda10048.h"
+#include "tda18271.h"
+#include "tda8290.h"
+#include "tuner-simple.h"
+#endif
/*------------------------------------------------------------------------*/
@@ -49,14 +57,19 @@ static const char *pvr2_fw1_names_29xxx[] = {
};
static const struct pvr2_device_desc pvr2_device_29xxx = {
- .description = "WinTV PVR USB2 Model Category 29xxxx",
+ .description = "WinTV PVR USB2 Model Category 29xxx",
.shortname = "29xxx",
.client_modules.lst = pvr2_client_29xxx,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_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,
};
@@ -75,7 +88,7 @@ static const char *pvr2_fw1_names_24xxx[] = {
};
static const struct pvr2_device_desc pvr2_device_24xxx = {
- .description = "WinTV PVR USB2 Model Category 24xxxx",
+ .description = "WinTV PVR USB2 Model Category 24xxx",
.shortname = "24xxx",
.client_modules.lst = pvr2_client_24xxx,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_24xxx),
@@ -85,7 +98,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 +123,30 @@ 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_fmradio = !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,
};
@@ -114,6 +156,38 @@ static const struct pvr2_device_desc pvr2_device_gotview_2 = {
/*------------------------------------------------------------------------*/
/* OnAir Creator */
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct lgdt330x_config pvr2_lgdt3303_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3303,
+ .clock_polarity_flip = 1,
+};
+
+static int pvr2_lgdt3303_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3303_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_lgh06xf_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x61,
+ TUNER_LG_TDVS_H06XF);
+
+ return 0;
+}
+
+struct pvr2_dvb_props pvr2_onair_creator_fe_props = {
+ .frontend_attach = pvr2_lgdt3303_attach,
+ .tuner_attach = pvr2_lgh06xf_attach,
+};
+#endif
+
static const char *pvr2_client_onair_creator[] = {
"saa7115",
"tuner",
@@ -126,7 +200,16 @@ 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,
+ .flag_digital_requires_cx23416 = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+ .default_std_mask = V4L2_STD_NTSC_M,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_onair_creator_fe_props,
+#endif
};
#endif
@@ -136,6 +219,37 @@ static const struct pvr2_device_desc pvr2_device_onair_creator = {
/*------------------------------------------------------------------------*/
/* OnAir USB 2.0 */
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct lgdt330x_config pvr2_lgdt3302_config = {
+ .demod_address = 0x0e,
+ .demod_chip = LGDT3302,
+};
+
+static int pvr2_lgdt3302_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(lgdt330x_attach, &pvr2_lgdt3302_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_fcv1236d_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(simple_tuner_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x61,
+ TUNER_PHILIPS_FCV1236D);
+
+ return 0;
+}
+
+struct pvr2_dvb_props pvr2_onair_usb2_fe_props = {
+ .frontend_attach = pvr2_lgdt3302_attach,
+ .tuner_attach = pvr2_fcv1236d_attach,
+};
+#endif
+
static const char *pvr2_client_onair_usb2[] = {
"saa7115",
"tuner",
@@ -147,8 +261,17 @@ 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,
+ .flag_digital_requires_cx23416 = !0,
.signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+ .digital_control_scheme = PVR2_DIGITAL_SCHEME_ONAIR,
+ .default_std_mask = V4L2_STD_NTSC_M,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_onair_usb2_fe_props,
+#endif
};
#endif
@@ -157,6 +280,50 @@ static const struct pvr2_device_desc pvr2_device_onair_usb2 = {
/*------------------------------------------------------------------------*/
/* Hauppauge PVR-USB2 Model 73xxx */
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct tda10048_config hauppauge_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_PARALLEL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_50,
+ .inversion = TDA10048_INVERSION_ON,
+};
+
+static struct tda829x_config tda829x_no_probe = {
+ .probe_tuner = TDA829X_DONT_PROBE,
+};
+
+static struct tda18271_config hauppauge_tda18271_dvb_config = {
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static int pvr2_tda10048_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(tda10048_attach, &hauppauge_tda10048_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_73xxx_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(tda829x_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, adap->fe, 0x60,
+ &adap->channel.hdw->i2c_adap,
+ &hauppauge_tda18271_dvb_config);
+
+ return 0;
+}
+
+struct pvr2_dvb_props pvr2_73xxx_dvb_props = {
+ .frontend_attach = pvr2_tda10048_attach,
+ .tuner_attach = pvr2_73xxx_tda18271_8295_attach,
+};
+#endif
+
static const char *pvr2_client_73xxx[] = {
"cx25840",
"tuner",
@@ -167,7 +334,7 @@ static const char *pvr2_fw1_names_73xxx[] = {
};
static const struct pvr2_device_desc pvr2_device_73xxx = {
- .description = "WinTV PVR USB2 Model Category 73xxxx",
+ .description = "WinTV PVR USB2 Model Category 73xxx",
.shortname = "73xxx",
.client_modules.lst = pvr2_client_73xxx,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_73xxx),
@@ -175,15 +342,14 @@ static const struct pvr2_device_desc pvr2_device_73xxx = {
.fx2_firmware.cnt = ARRAY_SIZE(pvr2_fw1_names_73xxx),
.flag_has_cx25840 = !0,
.flag_has_hauppauge_rom = !0,
-#if 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,
.led_scheme = PVR2_LED_SCHEME_HAUPPAUGE,
-#else
- .signal_routing_scheme = PVR2_ROUTING_SCHEME_HAUPPAUGE,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_73xxx_dvb_props,
#endif
};
@@ -192,6 +358,56 @@ static const struct pvr2_device_desc pvr2_device_73xxx = {
/*------------------------------------------------------------------------*/
/* Hauppauge PVR-USB2 Model 75xxx */
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+static struct s5h1409_config pvr2_s5h1409_config = {
+ .demod_address = 0x32 >> 1,
+ .output_mode = S5H1409_PARALLEL_OUTPUT,
+ .gpio = S5H1409_GPIO_OFF,
+ .qam_if = 4000,
+ .inversion = S5H1409_INVERSION_ON,
+ .status_mode = S5H1409_DEMODLOCKING,
+};
+
+static struct tda18271_std_map hauppauge_tda18271_std_map = {
+ .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 = {
+ .std_map = &hauppauge_tda18271_std_map,
+ .gate = TDA18271_GATE_ANALOG,
+};
+
+static int pvr2_s5h1409_attach(struct pvr2_dvb_adapter *adap)
+{
+ adap->fe = dvb_attach(s5h1409_attach, &pvr2_s5h1409_config,
+ &adap->channel.hdw->i2c_adap);
+ if (adap->fe)
+ return 0;
+
+ return -EIO;
+}
+
+static int pvr2_tda18271_8295_attach(struct pvr2_dvb_adapter *adap)
+{
+ dvb_attach(tda829x_attach, adap->fe,
+ &adap->channel.hdw->i2c_adap, 0x42,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, adap->fe, 0x60,
+ &adap->channel.hdw->i2c_adap,
+ &hauppauge_tda18271_config);
+
+ return 0;
+}
+
+struct pvr2_dvb_props pvr2_750xx_dvb_props = {
+ .frontend_attach = pvr2_s5h1409_attach,
+ .tuner_attach = pvr2_tda18271_8295_attach,
+};
+#endif
+
static const char *pvr2_client_75xxx[] = {
"cx25840",
"tuner",
@@ -201,17 +417,43 @@ static const char *pvr2_fw1_names_75xxx[] = {
"v4l-pvrusb2-73xxx-01.fw",
};
-static const struct pvr2_device_desc pvr2_device_75xxx = {
- .description = "WinTV PVR USB2 Model Category 75xxxx",
- .shortname = "75xxx",
+static const struct pvr2_device_desc pvr2_device_750xx = {
+ .description = "WinTV PVR USB2 Model Category 750xx",
+ .shortname = "750xx",
+ .client_modules.lst = pvr2_client_75xxx,
+ .client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
+ .fx2_firmware.lst = pvr2_fw1_names_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,
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ .dvb_props = &pvr2_750xx_dvb_props,
+#endif
+};
+
+static const struct pvr2_device_desc pvr2_device_751xx = {
+ .description = "WinTV PVR USB2 Model Category 751xx",
+ .shortname = "751xx",
.client_modules.lst = pvr2_client_75xxx,
.client_modules.cnt = ARRAY_SIZE(pvr2_client_75xxx),
.fx2_firmware.lst = pvr2_fw1_names_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 +467,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},
@@ -236,9 +480,9 @@ struct usb_device_id pvr2_device_table[] = {
{ USB_DEVICE(0x2040, 0x7300),
.driver_info = (kernel_ulong_t)&pvr2_device_73xxx},
{ USB_DEVICE(0x2040, 0x7500),
- .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
+ .driver_info = (kernel_ulong_t)&pvr2_device_750xx},
{ USB_DEVICE(0x2040, 0x7501),
- .driver_info = (kernel_ulong_t)&pvr2_device_75xxx},
+ .driver_info = (kernel_ulong_t)&pvr2_device_751xx},
{ }
};
diff --git a/drivers/media/video/pvrusb2/pvrusb2-devattr.h b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
index 64b467f0637..c2e2b06fe2e 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-devattr.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-devattr.h
@@ -23,6 +23,9 @@
#include <linux/mod_devicetable.h>
#include <linux/videodev2.h>
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+#include "pvrusb2-dvb.h"
+#endif
/*
@@ -39,6 +42,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 +68,64 @@ struct pvr2_device_desc {
was initialized from internal ROM. */
struct pvr2_string_table fx2_firmware;
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ /* callback functions to handle attachment of digital tuner & demod */
+ struct pvr2_dvb_props *dvb_props;
+
+#endif
+ /* 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;
+
+ /* If set, the encoder must be healthy in order for digital mode to
+ work (otherwise we assume that digital streaming will work even
+ if we fail to locate firmware for the encoder). If the device
+ doesn't support digital streaming then this flag has no
+ effect. */
+ int flag_digital_requires_cx23416: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 +135,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-dvb.c b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
new file mode 100644
index 00000000000..2e64f98d124
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.c
@@ -0,0 +1,425 @@
+/*
+ * pvrusb2-dvb.c - linux-dvb api interface to the pvrusb2 driver.
+ *
+ * Copyright (C) 2007, 2008 Michael Krufky <mkrufky@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ *
+ */
+
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+#include "dvbdev.h"
+#include "pvrusb2-hdw-internal.h"
+#include "pvrusb2-hdw.h"
+#include "pvrusb2-io.h"
+#include "pvrusb2-dvb.h"
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static int pvr2_dvb_feed_func(struct pvr2_dvb_adapter *adap)
+{
+ int ret;
+ unsigned int count;
+ struct pvr2_buffer *bp;
+ struct pvr2_stream *stream;
+
+ printk(KERN_DEBUG "dvb thread started\n");
+ set_freezable();
+
+ stream = adap->channel.stream->stream;
+
+ for (;;) {
+ if (kthread_should_stop()) break;
+
+ /* Not sure about this... */
+ try_to_freeze();
+
+ bp = pvr2_stream_get_ready_buffer(stream);
+ if (bp != NULL) {
+ count = pvr2_buffer_get_count(bp);
+ if (count) {
+ dvb_dmx_swfilter(
+ &adap->demux,
+ adap->buffer_storage[
+ pvr2_buffer_get_id(bp)],
+ count);
+ } else {
+ ret = pvr2_buffer_get_status(bp);
+ if (ret < 0) break;
+ }
+ ret = pvr2_buffer_queue(bp);
+ if (ret < 0) break;
+
+ /* Since we know we did something to a buffer,
+ just go back and try again. No point in
+ blocking unless we really ran out of
+ buffers to process. */
+ continue;
+ }
+
+
+ /* Wait until more buffers become available or we're
+ told not to wait any longer. */
+ ret = wait_event_interruptible(
+ adap->buffer_wait_data,
+ (pvr2_stream_get_ready_count(stream) > 0) ||
+ kthread_should_stop());
+ if (ret < 0) break;
+ }
+
+ /* If we get here and ret is < 0, then an error has occurred.
+ Probably would be a good idea to communicate that to DVB core... */
+
+ printk(KERN_DEBUG "dvb thread stopped\n");
+
+ return 0;
+}
+
+static int pvr2_dvb_feed_thread(void *data)
+{
+ int stat = pvr2_dvb_feed_func(data);
+ /* from videobuf-dvb.c: */
+ while (!kthread_should_stop()) {
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule();
+ }
+ return stat;
+}
+
+static void pvr2_dvb_notify(struct pvr2_dvb_adapter *adap)
+{
+ wake_up(&adap->buffer_wait_data);
+}
+
+static void pvr2_dvb_stream_end(struct pvr2_dvb_adapter *adap)
+{
+ unsigned int idx;
+ struct pvr2_stream *stream;
+
+ if (adap->thread) {
+ kthread_stop(adap->thread);
+ adap->thread = NULL;
+ }
+
+ if (adap->channel.stream) {
+ stream = adap->channel.stream->stream;
+ } else {
+ stream = NULL;
+ }
+ if (stream) {
+ pvr2_hdw_set_streaming(adap->channel.hdw, 0);
+ pvr2_stream_set_callback(stream, NULL, NULL);
+ pvr2_stream_kill(stream);
+ pvr2_stream_set_buffer_count(stream, 0);
+ pvr2_channel_claim_stream(&adap->channel, NULL);
+ }
+
+ if (adap->stream_run) {
+ for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+ if (!(adap->buffer_storage[idx])) continue;
+ kfree(adap->buffer_storage[idx]);
+ adap->buffer_storage[idx] = 0;
+ }
+ adap->stream_run = 0;
+ }
+}
+
+static int pvr2_dvb_stream_do_start(struct pvr2_dvb_adapter *adap)
+{
+ struct pvr2_context *pvr = adap->channel.mc_head;
+ unsigned int idx;
+ int ret;
+ struct pvr2_buffer *bp;
+ struct pvr2_stream *stream = 0;
+
+ if (adap->stream_run) return -EIO;
+
+ ret = pvr2_channel_claim_stream(&adap->channel, &pvr->video_stream);
+ /* somebody else already has the stream */
+ if (ret < 0) return ret;
+
+ stream = adap->channel.stream->stream;
+
+ for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+ adap->buffer_storage[idx] = kmalloc(PVR2_DVB_BUFFER_SIZE,
+ GFP_KERNEL);
+ if (!(adap->buffer_storage[idx])) return -ENOMEM;
+ }
+
+ pvr2_stream_set_callback(pvr->video_stream.stream,
+ (pvr2_stream_callback) pvr2_dvb_notify, adap);
+
+ ret = pvr2_stream_set_buffer_count(stream, PVR2_DVB_BUFFER_COUNT);
+ if (ret < 0) return ret;
+
+ for (idx = 0; idx < PVR2_DVB_BUFFER_COUNT; idx++) {
+ bp = pvr2_stream_get_buffer(stream, idx);
+ pvr2_buffer_set_buffer(bp,
+ adap->buffer_storage[idx],
+ PVR2_DVB_BUFFER_SIZE);
+ }
+
+ ret = pvr2_hdw_set_streaming(adap->channel.hdw, 1);
+ if (ret < 0) return ret;
+
+ while ((bp = pvr2_stream_get_idle_buffer(stream)) != 0) {
+ ret = pvr2_buffer_queue(bp);
+ if (ret < 0) return ret;
+ }
+
+ adap->thread = kthread_run(pvr2_dvb_feed_thread, adap, "pvrusb2-dvb");
+
+ if (IS_ERR(adap->thread)) {
+ ret = PTR_ERR(adap->thread);
+ adap->thread = NULL;
+ return ret;
+ }
+
+ adap->stream_run = !0;
+
+ return 0;
+}
+
+static int pvr2_dvb_stream_start(struct pvr2_dvb_adapter *adap)
+{
+ int ret = pvr2_dvb_stream_do_start(adap);
+ if (ret < 0) pvr2_dvb_stream_end(adap);
+ return ret;
+}
+
+static int pvr2_dvb_ctrl_feed(struct dvb_demux_feed *dvbdmxfeed, int onoff)
+{
+ struct pvr2_dvb_adapter *adap = dvbdmxfeed->demux->priv;
+ int ret = 0;
+
+ if (adap == NULL) return -ENODEV;
+
+ mutex_lock(&adap->lock);
+ do {
+ if (onoff) {
+ if (!adap->feedcount) {
+ printk(KERN_DEBUG "start feeding\n");
+ ret = pvr2_dvb_stream_start(adap);
+ if (ret < 0) break;
+ }
+ (adap->feedcount)++;
+ } else if (adap->feedcount > 0) {
+ (adap->feedcount)--;
+ if (!adap->feedcount) {
+ printk(KERN_DEBUG "stop feeding\n");
+ pvr2_dvb_stream_end(adap);
+ }
+ }
+ } while (0);
+ mutex_unlock(&adap->lock);
+
+ return ret;
+}
+
+static int pvr2_dvb_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ printk(KERN_DEBUG "start pid: 0x%04x, feedtype: %d\n",
+ dvbdmxfeed->pid, dvbdmxfeed->type);
+ return pvr2_dvb_ctrl_feed(dvbdmxfeed, 1);
+}
+
+static int pvr2_dvb_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+ printk(KERN_DEBUG "stop pid: 0x%04x, feedtype: %d\n",
+ dvbdmxfeed->pid, dvbdmxfeed->type);
+ return pvr2_dvb_ctrl_feed(dvbdmxfeed, 0);
+}
+
+static int pvr2_dvb_bus_ctrl(struct dvb_frontend *fe, int acquire)
+{
+ struct pvr2_dvb_adapter *adap = fe->dvb->priv;
+ return pvr2_channel_limit_inputs(
+ &adap->channel,
+ (acquire ? (1 << PVR2_CVAL_INPUT_DTV) : 0));
+}
+
+static int pvr2_dvb_adapter_init(struct pvr2_dvb_adapter *adap)
+{
+ int ret;
+
+ ret = dvb_register_adapter(&adap->dvb_adap, "pvrusb2-dvb",
+ THIS_MODULE/*&hdw->usb_dev->owner*/,
+ &adap->channel.hdw->usb_dev->dev,
+ adapter_nr);
+ if (ret < 0) {
+ err("dvb_register_adapter failed: error %d", ret);
+ goto err;
+ }
+ adap->dvb_adap.priv = adap;
+
+ adap->demux.dmx.capabilities = DMX_TS_FILTERING |
+ DMX_SECTION_FILTERING |
+ DMX_MEMORY_BASED_FILTERING;
+ adap->demux.priv = adap;
+ adap->demux.filternum = 256;
+ adap->demux.feednum = 256;
+ adap->demux.start_feed = pvr2_dvb_start_feed;
+ adap->demux.stop_feed = pvr2_dvb_stop_feed;
+ adap->demux.write_to_decoder = NULL;
+
+ ret = dvb_dmx_init(&adap->demux);
+ if (ret < 0) {
+ err("dvb_dmx_init failed: error %d", ret);
+ goto err_dmx;
+ }
+
+ adap->dmxdev.filternum = adap->demux.filternum;
+ adap->dmxdev.demux = &adap->demux.dmx;
+ adap->dmxdev.capabilities = 0;
+
+ ret = dvb_dmxdev_init(&adap->dmxdev, &adap->dvb_adap);
+ if (ret < 0) {
+ err("dvb_dmxdev_init failed: error %d", ret);
+ goto err_dmx_dev;
+ }
+
+ dvb_net_init(&adap->dvb_adap, &adap->dvb_net, &adap->demux.dmx);
+
+ return 0;
+
+err_dmx_dev:
+ dvb_dmx_release(&adap->demux);
+err_dmx:
+ dvb_unregister_adapter(&adap->dvb_adap);
+err:
+ return ret;
+}
+
+static int pvr2_dvb_adapter_exit(struct pvr2_dvb_adapter *adap)
+{
+ printk(KERN_DEBUG "unregistering DVB devices\n");
+ dvb_net_release(&adap->dvb_net);
+ adap->demux.dmx.close(&adap->demux.dmx);
+ dvb_dmxdev_release(&adap->dmxdev);
+ dvb_dmx_release(&adap->demux);
+ dvb_unregister_adapter(&adap->dvb_adap);
+ return 0;
+}
+
+static int pvr2_dvb_frontend_init(struct pvr2_dvb_adapter *adap)
+{
+ struct pvr2_hdw *hdw = adap->channel.hdw;
+ struct pvr2_dvb_props *dvb_props = hdw->hdw_desc->dvb_props;
+ int ret = 0;
+
+ if (dvb_props == NULL) {
+ err("fe_props not defined!");
+ return -EINVAL;
+ }
+
+ ret = pvr2_channel_limit_inputs(
+ &adap->channel,
+ (1 << PVR2_CVAL_INPUT_DTV));
+ if (ret) {
+ err("failed to grab control of dtv input (code=%d)",
+ ret);
+ return ret;
+ }
+
+ if (dvb_props->frontend_attach == NULL) {
+ err("frontend_attach not defined!");
+ ret = -EINVAL;
+ goto done;
+ }
+
+ if ((dvb_props->frontend_attach(adap) == 0) && (adap->fe)) {
+
+ if (dvb_register_frontend(&adap->dvb_adap, adap->fe)) {
+ err("frontend registration failed!");
+ dvb_frontend_detach(adap->fe);
+ adap->fe = NULL;
+ ret = -ENODEV;
+ goto done;
+ }
+
+ if (dvb_props->tuner_attach)
+ dvb_props->tuner_attach(adap);
+
+ if (adap->fe->ops.analog_ops.standby)
+ adap->fe->ops.analog_ops.standby(adap->fe);
+
+ /* Ensure all frontends negotiate bus access */
+ adap->fe->ops.ts_bus_ctrl = pvr2_dvb_bus_ctrl;
+
+ } else {
+ err("no frontend was attached!");
+ ret = -ENODEV;
+ return ret;
+ }
+
+ done:
+ pvr2_channel_limit_inputs(&adap->channel, 0);
+ return ret;
+}
+
+static int pvr2_dvb_frontend_exit(struct pvr2_dvb_adapter *adap)
+{
+ if (adap->fe != NULL) {
+ dvb_unregister_frontend(adap->fe);
+ dvb_frontend_detach(adap->fe);
+ }
+ return 0;
+}
+
+static void pvr2_dvb_destroy(struct pvr2_dvb_adapter *adap)
+{
+ pvr2_dvb_stream_end(adap);
+ pvr2_dvb_frontend_exit(adap);
+ pvr2_dvb_adapter_exit(adap);
+ pvr2_channel_done(&adap->channel);
+ kfree(adap);
+}
+
+static void pvr2_dvb_internal_check(struct pvr2_channel *chp)
+{
+ struct pvr2_dvb_adapter *adap;
+ adap = container_of(chp, struct pvr2_dvb_adapter, channel);
+ if (!adap->channel.mc_head->disconnect_flag) return;
+ pvr2_dvb_destroy(adap);
+}
+
+struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr)
+{
+ int ret = 0;
+ struct pvr2_dvb_adapter *adap;
+ if (!pvr->hdw->hdw_desc->dvb_props) {
+ /* Device lacks a digital interface so don't set up
+ the DVB side of the driver either. For now. */
+ return NULL;
+ }
+ adap = kzalloc(sizeof(*adap), GFP_KERNEL);
+ if (!adap) return adap;
+ pvr2_channel_init(&adap->channel, pvr);
+ adap->channel.check_func = pvr2_dvb_internal_check;
+ init_waitqueue_head(&adap->buffer_wait_data);
+ mutex_init(&adap->lock);
+ ret = pvr2_dvb_adapter_init(adap);
+ if (ret < 0) goto fail1;
+ ret = pvr2_dvb_frontend_init(adap);
+ if (ret < 0) goto fail2;
+ return adap;
+
+fail2:
+ pvr2_dvb_adapter_exit(adap);
+fail1:
+ pvr2_channel_done(&adap->channel);
+ return NULL;
+}
+
diff --git a/drivers/media/video/pvrusb2/pvrusb2-dvb.h b/drivers/media/video/pvrusb2/pvrusb2-dvb.h
new file mode 100644
index 00000000000..884ff916a35
--- /dev/null
+++ b/drivers/media/video/pvrusb2/pvrusb2-dvb.h
@@ -0,0 +1,41 @@
+#ifndef __PVRUSB2_DVB_H__
+#define __PVRUSB2_DVB_H__
+
+#include "dvb_frontend.h"
+#include "dvb_demux.h"
+#include "dvb_net.h"
+#include "dmxdev.h"
+#include "pvrusb2-context.h"
+
+#define PVR2_DVB_BUFFER_COUNT 32
+#define PVR2_DVB_BUFFER_SIZE PAGE_ALIGN(0x4000)
+
+struct pvr2_dvb_adapter {
+ struct pvr2_channel channel;
+
+ struct dvb_adapter dvb_adap;
+ struct dmxdev dmxdev;
+ struct dvb_demux demux;
+ struct dvb_net dvb_net;
+ struct dvb_frontend *fe;
+
+ int feedcount;
+ int max_feed_count;
+
+ struct task_struct *thread;
+ struct mutex lock;
+
+ unsigned int stream_run:1;
+
+ wait_queue_head_t buffer_wait_data;
+ char *buffer_storage[PVR2_DVB_BUFFER_COUNT];
+};
+
+struct pvr2_dvb_props {
+ int (*frontend_attach) (struct pvr2_dvb_adapter *);
+ int (*tuner_attach) (struct pvr2_dvb_adapter *);
+};
+
+struct pvr2_dvb_adapter *pvr2_dvb_create(struct pvr2_context *pvr);
+
+#endif /* __PVRUSB2_DVB_H__ */
diff --git a/drivers/media/video/pvrusb2/pvrusb2-encoder.c b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
index 64062879981..c46d367f747 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-encoder.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-encoder.c
@@ -278,11 +278,20 @@ static int pvr2_encoder_cmd(void *ctxt,
ret = -EBUSY;
}
if (ret) {
+ del_timer_sync(&hdw->encoder_run_timer);
hdw->state_encoder_ok = 0;
pvr2_trace(PVR2_TRACE_STBITS,
"State bit %s <-- %s",
"state_encoder_ok",
(hdw->state_encoder_ok ? "true" : "false"));
+ if (hdw->state_encoder_runok) {
+ hdw->state_encoder_runok = 0;
+ pvr2_trace(PVR2_TRACE_STBITS,
+ "State bit %s <-- %s",
+ "state_encoder_runok",
+ (hdw->state_encoder_runok ?
+ "true" : "false"));
+ }
pvr2_trace(
PVR2_TRACE_ERROR_LEGS,
"Giving up on command."
@@ -480,10 +489,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 +531,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 ffbc6d09610..abaada31e66 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-fx2-cmd.h
@@ -22,32 +22,41 @@
#ifndef _PVRUSB2_FX2_CMD_H_
#define _PVRUSB2_FX2_CMD_H_
-#define FX2CMD_MEM_WRITE_DWORD 0x01
-#define FX2CMD_MEM_READ_DWORD 0x02
+#define FX2CMD_MEM_WRITE_DWORD 0x01u
+#define FX2CMD_MEM_READ_DWORD 0x02u
-#define FX2CMD_MEM_READ_64BYTES 0x28
+#define FX2CMD_MEM_READ_64BYTES 0x28u
-#define FX2CMD_REG_WRITE 0x04
-#define FX2CMD_REG_READ 0x05
-#define FX2CMD_MEMSEL 0x06
+#define FX2CMD_REG_WRITE 0x04u
+#define FX2CMD_REG_READ 0x05u
+#define FX2CMD_MEMSEL 0x06u
-#define FX2CMD_I2C_WRITE 0x08
-#define FX2CMD_I2C_READ 0x09
+#define FX2CMD_I2C_WRITE 0x08u
+#define FX2CMD_I2C_READ 0x09u
-#define FX2CMD_GET_USB_SPEED 0x0b
+#define FX2CMD_GET_USB_SPEED 0x0bu
-#define FX2CMD_STREAMING_ON 0x36
-#define FX2CMD_STREAMING_OFF 0x37
+#define FX2CMD_STREAMING_ON 0x36u
+#define FX2CMD_STREAMING_OFF 0x37u
-#define FX2CMD_FWPOST1 0x52
+#define FX2CMD_FWPOST1 0x52u
-#define FX2CMD_POWER_OFF 0xdc
-#define FX2CMD_POWER_ON 0xde
+#define FX2CMD_POWER_OFF 0xdcu
+#define FX2CMD_POWER_ON 0xdeu
-#define FX2CMD_DEEP_RESET 0xdd
+#define FX2CMD_DEEP_RESET 0xddu
-#define FX2CMD_GET_EEPROM_ADDR 0xeb
-#define FX2CMD_GET_IR_CODE 0xec
+#define FX2CMD_GET_EEPROM_ADDR 0xebu
+#define FX2CMD_GET_IR_CODE 0xecu
+
+#define FX2CMD_HCW_DEMOD_RESETIN 0xf0u
+#define FX2CMD_HCW_DTV_STREAMING_ON 0xf1u
+#define FX2CMD_HCW_DTV_STREAMING_OFF 0xf2u
+
+#define FX2CMD_ONAIR_DTV_STREAMING_ON 0xa0u
+#define FX2CMD_ONAIR_DTV_STREAMING_OFF 0xa1u
+#define FX2CMD_ONAIR_DTV_POWER_ON 0xa2u
+#define FX2CMD_ONAIR_DTV_POWER_OFF 0xa3u
#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 d7a216b41b7..a3fe251d6fd 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,17 +233,19 @@ 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 */
int state_encoder_waitok; /* Encoder pre-wait done */
+ int state_encoder_runok; /* Encoder has run for >= .25 sec */
int state_decoder_run; /* Decoder is running */
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 +253,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;
@@ -259,6 +268,9 @@ struct pvr2_hdw {
/* Timer for measuring encoder pre-wait time */
struct timer_list encoder_wait_timer;
+ /* Timer for measuring encoder minimum run time */
+ struct timer_list encoder_run_timer;
+
/* Place to block while waiting for state changes */
wait_queue_head_t state_wait_data;
@@ -267,6 +279,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 +336,11 @@ struct pvr2_hdw {
int v4l_minor_number_vbi;
int v4l_minor_number_radio;
+ /* Bit mask of PVR2_CVAL_INPUT choices which are valid for the hardware */
+ unsigned int input_avail_mask;
+ /* Bit mask of PVR2_CVAL_INPUT choices which are currenly allowed */
+ unsigned int input_allowed_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 2404053a4d8..0a868888f38 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -43,13 +43,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");
@@ -182,6 +182,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",
@@ -215,12 +216,45 @@ static const char *pvr2_state_names[] = {
};
+struct pvr2_fx2cmd_descdef {
+ unsigned char id;
+ unsigned char *desc;
+};
+
+static const struct pvr2_fx2cmd_descdef pvr2_fx2cmd_desc[] = {
+ {FX2CMD_MEM_WRITE_DWORD, "write encoder dword"},
+ {FX2CMD_MEM_READ_DWORD, "read encoder dword"},
+ {FX2CMD_MEM_READ_64BYTES, "read encoder 64bytes"},
+ {FX2CMD_REG_WRITE, "write encoder register"},
+ {FX2CMD_REG_READ, "read encoder register"},
+ {FX2CMD_MEMSEL, "encoder memsel"},
+ {FX2CMD_I2C_WRITE, "i2c write"},
+ {FX2CMD_I2C_READ, "i2c read"},
+ {FX2CMD_GET_USB_SPEED, "get USB speed"},
+ {FX2CMD_STREAMING_ON, "stream on"},
+ {FX2CMD_STREAMING_OFF, "stream off"},
+ {FX2CMD_FWPOST1, "fwpost1"},
+ {FX2CMD_POWER_OFF, "power off"},
+ {FX2CMD_POWER_ON, "power on"},
+ {FX2CMD_DEEP_RESET, "deep reset"},
+ {FX2CMD_GET_EEPROM_ADDR, "get rom addr"},
+ {FX2CMD_GET_IR_CODE, "get IR code"},
+ {FX2CMD_HCW_DEMOD_RESETIN, "hcw demod resetin"},
+ {FX2CMD_HCW_DTV_STREAMING_ON, "hcw dtv stream on"},
+ {FX2CMD_HCW_DTV_STREAMING_OFF, "hcw dtv stream off"},
+ {FX2CMD_ONAIR_DTV_STREAMING_ON, "onair dtv stream on"},
+ {FX2CMD_ONAIR_DTV_STREAMING_OFF, "onair dtv stream off"},
+ {FX2CMD_ONAIR_DTV_POWER_ON, "onair dtv power on"},
+ {FX2CMD_ONAIR_DTV_POWER_OFF, "onair dtv power off"},
+};
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v);
static void pvr2_hdw_state_sched(struct pvr2_hdw *);
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 *);
@@ -231,6 +265,8 @@ static void pvr2_hdw_internal_find_stdenum(struct pvr2_hdw *hdw);
static void pvr2_hdw_internal_set_std_avail(struct pvr2_hdw *hdw);
static void pvr2_hdw_quiescent_timeout(unsigned long);
static void pvr2_hdw_encoder_wait_timeout(unsigned long);
+static void pvr2_hdw_encoder_run_timeout(unsigned long);
+static int pvr2_issue_simple_cmd(struct pvr2_hdw *,u32);
static int pvr2_send_request_ex(struct pvr2_hdw *hdw,
unsigned int timeout,int probe_fl,
void *write_data,unsigned int write_len,
@@ -367,26 +403,14 @@ static int ctrl_get_input(struct pvr2_ctrl *cptr,int *vp)
return 0;
}
-static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
+static int ctrl_check_input(struct pvr2_ctrl *cptr,int v)
{
- struct pvr2_hdw *hdw = cptr->hdw;
-
- if (hdw->input_val != v) {
- hdw->input_val = v;
- hdw->input_dirty = !0;
- }
+ return ((1 << v) & cptr->hdw->input_allowed_mask) != 0;
+}
- /* Handle side effects - if we switch to a mode that needs the RF
- tuner, then select the right frequency choice as well and mark
- it dirty. */
- if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
- hdw->freqSelector = 0;
- hdw->freqDirty = !0;
- } else if (hdw->input_val == PVR2_CVAL_INPUT_TV) {
- hdw->freqSelector = 1;
- hdw->freqDirty = !0;
- }
- return 0;
+static int ctrl_set_input(struct pvr2_ctrl *cptr,int m,int v)
+{
+ return pvr2_hdw_set_input(cptr->hdw,v);
}
static int ctrl_isdirty_input(struct pvr2_ctrl *cptr)
@@ -803,6 +827,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),
},{
@@ -982,7 +1007,7 @@ unsigned long pvr2_hdw_get_cur_freq(struct pvr2_hdw *hdw)
/* Set the currently tuned frequency and account for all possible
driver-core side effects of this action. */
-void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
+static void pvr2_hdw_set_cur_freq(struct pvr2_hdw *hdw,unsigned long val)
{
if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
if (hdw->freqSelector) {
@@ -1195,6 +1220,14 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
time we configure the encoder, then we'll fully configure it. */
hdw->enc_cur_valid = 0;
+ /* Encoder is about to be reset so note that as far as we're
+ concerned now, the encoder has never been run. */
+ del_timer_sync(&hdw->encoder_run_timer);
+ if (hdw->state_encoder_runok) {
+ hdw->state_encoder_runok = 0;
+ trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
+ }
+
/* First prepare firmware loading */
ret |= pvr2_write_register(hdw, 0x0048, 0xffffffff); /*interrupt mask*/
ret |= pvr2_hdw_gpio_chg_dir(hdw,0xffffffff,0x00000088); /*gpio dir*/
@@ -1212,19 +1245,14 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
ret |= pvr2_write_register(hdw, 0xaa04, 0x00057810); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa10, 0x00148500); /*unknown*/
ret |= pvr2_write_register(hdw, 0xaa18, 0x00840000); /*unknown*/
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = FX2CMD_FWPOST1;
- ret |= pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
- hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
- hdw->cmd_buffer[1] = 0;
- ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
+ ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_FWPOST1);
+ ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"firmware2 upload prep failed, ret=%d",ret);
release_firmware(fw_entry);
- return ret;
+ goto done;
}
/* Now send firmware */
@@ -1237,7 +1265,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
" must be a multiple of %zu bytes",
fw_files[fwidx],sizeof(u32));
release_firmware(fw_entry);
- return -1;
+ ret = -EINVAL;
+ goto done;
}
fw_ptr = kmalloc(FIRMWARE_CHUNK_SIZE, GFP_KERNEL);
@@ -1245,7 +1274,8 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
release_firmware(fw_entry);
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"failed to allocate memory for firmware2 upload");
- return -ENOMEM;
+ ret = -ENOMEM;
+ goto done;
}
pipe = usb_sndbulkpipe(hdw->usb_dev, PVR2_FIRMWARE_ENDPOINT);
@@ -1276,23 +1306,27 @@ int pvr2_upload_firmware2(struct pvr2_hdw *hdw)
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"firmware2 upload transfer failure");
- return ret;
+ goto done;
}
/* Finish upload */
ret |= pvr2_write_register(hdw, 0x9054, 0xffffffff); /*reset hw blocks*/
ret |= pvr2_write_register(hdw, 0x9058, 0xffffffe8); /*VPU ctrl*/
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] = FX2CMD_MEMSEL;
- hdw->cmd_buffer[1] = 0;
- ret |= pvr2_send_request(hdw,hdw->cmd_buffer,2,NULL,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
+ ret |= pvr2_issue_simple_cmd(hdw,FX2CMD_MEMSEL | (1 << 8) | (0 << 16));
if (ret) {
pvr2_trace(PVR2_TRACE_ERROR_LEGS,
"firmware2 upload post-proc failure");
}
+
+ done:
+ if (hdw->hdw_desc->signal_routing_scheme ==
+ PVR2_ROUTING_SCHEME_GOTVIEW) {
+ /* Ensure that GPIO 11 is set to output for GOTVIEW
+ hardware. */
+ pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+ }
return ret;
}
@@ -1364,11 +1398,6 @@ int pvr2_hdw_untrip(struct pvr2_hdw *hdw)
}
-const char *pvr2_hdw_get_state_name(unsigned int id)
-{
- if (id >= ARRAY_SIZE(pvr2_state_names)) return NULL;
- return pvr2_state_names[id];
-}
int pvr2_hdw_get_streaming(struct pvr2_hdw *hdw)
@@ -1495,7 +1524,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,
@@ -1712,6 +1741,13 @@ static void pvr2_hdw_setup_low(struct pvr2_hdw *hdw)
if (!pvr2_hdw_dev_ok(hdw)) return;
+ if (hdw->hdw_desc->signal_routing_scheme ==
+ PVR2_ROUTING_SCHEME_GOTVIEW) {
+ /* Ensure that GPIO 11 is set to output for GOTVIEW
+ hardware. */
+ pvr2_hdw_gpio_chg_dir(hdw,(1 << 11),~0);
+ }
+
pvr2_hdw_commit_setup(hdw);
hdw->vid_stream = pvr2_stream_create();
@@ -1805,12 +1841,37 @@ 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 {
+ if (hdw->flag_disconnected) {
+ /* Handle a race here: If we're already
+ disconnected by this point, then give up. If we
+ get past this then we'll remain connected for
+ the duration of initialization since the entire
+ initialization sequence is now protected by the
+ big_lock. */
+ break;
+ }
+ hdw->state_data = callback_data;
+ hdw->state_func = callback_func;
+ pvr2_hdw_setup(hdw);
+ } while (0); LOCK_GIVE(hdw->big_lock);
+ 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;
@@ -1834,6 +1895,10 @@ struct pvr2_hdw *pvr2_hdw_create(struct usb_interface *intf,
hdw->encoder_wait_timer.data = (unsigned long)hdw;
hdw->encoder_wait_timer.function = pvr2_hdw_encoder_wait_timeout;
+ init_timer(&hdw->encoder_run_timer);
+ hdw->encoder_run_timer.data = (unsigned long)hdw;
+ hdw->encoder_run_timer.function = pvr2_hdw_encoder_run_timeout;
+
hdw->master_state = PVR2_STATE_DEAD;
init_waitqueue_head(&hdw->state_wait_data);
@@ -1841,6 +1906,26 @@ 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;
+ hdw->input_allowed_mask = hdw->input_avail_mask;
+
+ /* 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,
@@ -1858,6 +1943,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);
@@ -1981,7 +2075,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);
@@ -2003,11 +2096,11 @@ 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) {
del_timer_sync(&hdw->quiescent_timer);
+ del_timer_sync(&hdw->encoder_run_timer);
del_timer_sync(&hdw->encoder_wait_timer);
if (hdw->workqueue) {
flush_workqueue(hdw->workqueue);
@@ -2064,13 +2157,14 @@ 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_run_timer);
+ del_timer_sync(&hdw->encoder_wait_timer);
if (hdw->fw_buffer) {
kfree(hdw->fw_buffer);
hdw->fw_buffer = NULL;
@@ -2352,6 +2446,18 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
}
}
+ if (hdw->input_dirty && hdw->state_pathway_ok &&
+ (((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
@@ -2405,12 +2511,28 @@ static int pvr2_hdw_commit_execute(struct pvr2_hdw *hdw)
hdw->active_stream_type = hdw->desired_stream_type;
}
+ if (hdw->hdw_desc->signal_routing_scheme ==
+ PVR2_ROUTING_SCHEME_GOTVIEW) {
+ u32 b;
+ /* Handle GOTVIEW audio switching */
+ pvr2_hdw_gpio_get_out(hdw,&b);
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ /* Set GPIO 11 */
+ pvr2_hdw_gpio_chg_out(hdw,(1 << 11),~0);
+ } else {
+ /* Clear GPIO 11 */
+ pvr2_hdw_gpio_chg_out(hdw,(1 << 11),0);
+ }
+ }
+
/* 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;
}
@@ -2453,15 +2575,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(
@@ -2471,17 +2584,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)
{
@@ -3050,6 +3152,67 @@ int pvr2_send_request(struct pvr2_hdw *hdw,
read_data,read_len);
}
+
+static int pvr2_issue_simple_cmd(struct pvr2_hdw *hdw,u32 cmdcode)
+{
+ int ret;
+ unsigned int cnt = 1;
+ unsigned int args = 0;
+ LOCK_TAKE(hdw->ctl_lock);
+ hdw->cmd_buffer[0] = cmdcode & 0xffu;
+ args = (cmdcode >> 8) & 0xffu;
+ args = (args > 2) ? 2 : args;
+ if (args) {
+ cnt += args;
+ hdw->cmd_buffer[1] = (cmdcode >> 16) & 0xffu;
+ if (args > 1) {
+ hdw->cmd_buffer[2] = (cmdcode >> 24) & 0xffu;
+ }
+ }
+ if (pvrusb2_debug & PVR2_TRACE_INIT) {
+ unsigned int idx;
+ unsigned int ccnt,bcnt;
+ char tbuf[50];
+ cmdcode &= 0xffu;
+ bcnt = 0;
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ "Sending FX2 command 0x%x",cmdcode);
+ bcnt += ccnt;
+ for (idx = 0; idx < ARRAY_SIZE(pvr2_fx2cmd_desc); idx++) {
+ if (pvr2_fx2cmd_desc[idx].id == cmdcode) {
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ " \"%s\"",
+ pvr2_fx2cmd_desc[idx].desc);
+ bcnt += ccnt;
+ break;
+ }
+ }
+ if (args) {
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ " (%u",hdw->cmd_buffer[1]);
+ bcnt += ccnt;
+ if (args > 1) {
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ ",%u",hdw->cmd_buffer[2]);
+ bcnt += ccnt;
+ }
+ ccnt = scnprintf(tbuf+bcnt,
+ sizeof(tbuf)-bcnt,
+ ")");
+ bcnt += ccnt;
+ }
+ pvr2_trace(PVR2_TRACE_INIT,"%.*s",bcnt,tbuf);
+ }
+ ret = pvr2_send_request(hdw,hdw->cmd_buffer,cnt,NULL,0);
+ LOCK_GIVE(hdw->ctl_lock);
+ return ret;
+}
+
+
int pvr2_write_register(struct pvr2_hdw *hdw, u16 reg, u32 data)
{
int ret;
@@ -3157,25 +3320,19 @@ void pvr2_hdw_cpureset_assert(struct pvr2_hdw *hdw,int val)
int pvr2_hdw_cmd_deep_reset(struct pvr2_hdw *hdw)
{
- int status;
- LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_trace(PVR2_TRACE_INIT,"Requesting uproc hard reset");
- hdw->cmd_buffer[0] = FX2CMD_DEEP_RESET;
- status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
+ return pvr2_issue_simple_cmd(hdw,FX2CMD_DEEP_RESET);
}
int pvr2_hdw_cmd_powerup(struct pvr2_hdw *hdw)
{
- 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);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
+ return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_ON);
+}
+
+
+int pvr2_hdw_cmd_powerdown(struct pvr2_hdw *hdw)
+{
+ return pvr2_issue_simple_cmd(hdw,FX2CMD_POWER_OFF);
}
@@ -3200,16 +3357,173 @@ int pvr2_hdw_cmd_decoder_reset(struct pvr2_hdw *hdw)
}
+static int pvr2_hdw_cmd_hcw_demod_reset(struct pvr2_hdw *hdw, int onoff)
+{
+ hdw->flag_ok = !0;
+ return pvr2_issue_simple_cmd(hdw,
+ FX2CMD_HCW_DEMOD_RESETIN |
+ (1 << 8) |
+ ((onoff ? 1 : 0) << 16));
+}
+
+
+static int pvr2_hdw_cmd_onair_fe_power_ctrl(struct pvr2_hdw *hdw, int onoff)
+{
+ hdw->flag_ok = !0;
+ return pvr2_issue_simple_cmd(hdw,(onoff ?
+ FX2CMD_ONAIR_DTV_POWER_ON :
+ FX2CMD_ONAIR_DTV_POWER_OFF));
+}
+
+
+static int pvr2_hdw_cmd_onair_digital_path_ctrl(struct pvr2_hdw *hdw,
+ int onoff)
+{
+ return pvr2_issue_simple_cmd(hdw,(onoff ?
+ FX2CMD_ONAIR_DTV_STREAMING_ON :
+ FX2CMD_ONAIR_DTV_STREAMING_OFF));
+}
+
+
+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... */
+ pvr2_hdw_cmd_onair_fe_power_ctrl(hdw,digitalFl);
+ 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;
- LOCK_TAKE(hdw->ctl_lock); do {
- hdw->cmd_buffer[0] =
- (runFl ? FX2CMD_STREAMING_ON : FX2CMD_STREAMING_OFF);
- status = pvr2_send_request(hdw,hdw->cmd_buffer,1,NULL,0);
- } while (0); LOCK_GIVE(hdw->ctl_lock);
- return status;
+ int ret;
+
+ /* If we're in analog mode, then just issue the usual analog
+ command. */
+ if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+ return pvr2_issue_simple_cmd(hdw,
+ (runFl ?
+ FX2CMD_STREAMING_ON :
+ FX2CMD_STREAMING_OFF));
+ /*Note: Not reached */
+ }
+
+ if (hdw->pathway_state != PVR2_PATHWAY_DIGITAL) {
+ /* Whoops, we don't know what mode we're in... */
+ return -EINVAL;
+ }
+
+ /* To get here we have to be in digital mode. The mechanism here
+ is unfortunately different for different vendors. So we switch
+ on the device's digital scheme attribute in order to figure out
+ what to do. */
+ switch (hdw->hdw_desc->digital_control_scheme) {
+ case PVR2_DIGITAL_SCHEME_HAUPPAUGE:
+ return pvr2_issue_simple_cmd(hdw,
+ (runFl ?
+ FX2CMD_HCW_DTV_STREAMING_ON :
+ FX2CMD_HCW_DTV_STREAMING_OFF));
+ case PVR2_DIGITAL_SCHEME_ONAIR:
+ ret = pvr2_issue_simple_cmd(hdw,
+ (runFl ?
+ FX2CMD_STREAMING_ON :
+ FX2CMD_STREAMING_OFF));
+ if (ret) return ret;
+ return pvr2_hdw_cmd_onair_digital_path_ctrl(hdw,runFl);
+ default:
+ return -EINVAL;
+ }
+}
+
+
+/* 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;
}
@@ -3222,6 +3536,12 @@ 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_DIGITAL) {
+ if (!hdw->hdw_desc->flag_digital_requires_cx23416) return 0;
+ } else 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);
@@ -3247,7 +3567,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 ||
@@ -3296,20 +3618,116 @@ static int state_eval_encoder_config(struct pvr2_hdw *hdw)
}
+/* Return true if the encoder should not be running. */
+static int state_check_disable_encoder_run(struct pvr2_hdw *hdw)
+{
+ if (!hdw->state_encoder_ok) {
+ /* Encoder isn't healthy at the moment, so stop it. */
+ return !0;
+ }
+ if (!hdw->state_pathway_ok) {
+ /* Mode is not understood at the moment (i.e. it wants to
+ change), so encoder must be stopped. */
+ return !0;
+ }
+
+ switch (hdw->pathway_state) {
+ case PVR2_PATHWAY_ANALOG:
+ if (!hdw->state_decoder_run) {
+ /* We're in analog mode and the decoder is not
+ running; thus the encoder should be stopped as
+ well. */
+ return !0;
+ }
+ break;
+ case PVR2_PATHWAY_DIGITAL:
+ if (hdw->state_encoder_runok) {
+ /* This is a funny case. We're in digital mode so
+ really the encoder should be stopped. However
+ if it really is running, only kill it after
+ runok has been set. This gives a chance for the
+ onair quirk to function (encoder must run
+ briefly first, at least once, before onair
+ digital streaming can work). */
+ return !0;
+ }
+ break;
+ default:
+ /* Unknown mode; so encoder should be stopped. */
+ return !0;
+ }
+
+ /* If we get here, we haven't found a reason to stop the
+ encoder. */
+ return 0;
+}
+
+
+/* Return true if the encoder should be running. */
+static int state_check_enable_encoder_run(struct pvr2_hdw *hdw)
+{
+ if (!hdw->state_encoder_ok) {
+ /* Don't run the encoder if it isn't healthy... */
+ return 0;
+ }
+ if (!hdw->state_pathway_ok) {
+ /* Don't run the encoder if we don't (yet) know what mode
+ we need to be in... */
+ return 0;
+ }
+
+ switch (hdw->pathway_state) {
+ case PVR2_PATHWAY_ANALOG:
+ if (hdw->state_decoder_run) {
+ /* In analog mode, if the decoder is running, then
+ run the encoder. */
+ return !0;
+ }
+ break;
+ case PVR2_PATHWAY_DIGITAL:
+ if ((hdw->hdw_desc->digital_control_scheme ==
+ PVR2_DIGITAL_SCHEME_ONAIR) &&
+ !hdw->state_encoder_runok) {
+ /* This is a quirk. OnAir hardware won't stream
+ digital until the encoder has been run at least
+ once, for a minimal period of time (empiricially
+ measured to be 1/4 second). So if we're on
+ OnAir hardware and the encoder has never been
+ run at all, then start the encoder. Normal
+ state machine logic in the driver will
+ automatically handle the remaining bits. */
+ return !0;
+ }
+ break;
+ default:
+ /* For completeness (unknown mode; encoder won't run ever) */
+ break;
+ }
+ /* If we get here, then we haven't found any reason to run the
+ encoder, so don't run it. */
+ return 0;
+}
+
+
/* Evaluate whether or not state_encoder_run can change */
static int state_eval_encoder_run(struct pvr2_hdw *hdw)
{
if (hdw->state_encoder_run) {
+ if (!state_check_disable_encoder_run(hdw)) return 0;
if (hdw->state_encoder_ok) {
- if (hdw->state_decoder_run) return 0;
+ del_timer_sync(&hdw->encoder_run_timer);
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 (!state_check_enable_encoder_run(hdw)) return 0;
if (pvr2_encoder_start(hdw) < 0) return !0;
hdw->state_encoder_run = !0;
+ if (!hdw->state_encoder_runok) {
+ hdw->encoder_run_timer.expires =
+ jiffies + (HZ*250/1000);
+ add_timer(&hdw->encoder_run_timer);
+ }
}
trace_stbit("state_encoder_run",hdw->state_encoder_run);
return !0;
@@ -3338,13 +3756,27 @@ static void pvr2_hdw_encoder_wait_timeout(unsigned long data)
}
+/* Timeout function for encoder run timer. */
+static void pvr2_hdw_encoder_run_timeout(unsigned long data)
+{
+ struct pvr2_hdw *hdw = (struct pvr2_hdw *)data;
+ if (!hdw->state_encoder_runok) {
+ hdw->state_encoder_runok = !0;
+ trace_stbit("state_encoder_runok",hdw->state_encoder_runok);
+ hdw->state_stale = !0;
+ queue_work(hdw->workqueue,&hdw->workpoll);
+ }
+}
+
+
/* Evaluate whether or not state_decoder_run can change */
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);
@@ -3377,7 +3809,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 ||
@@ -3398,16 +3832,43 @@ 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;
+ int fl = !0;
+ if (hdw->pathway_state == PVR2_PATHWAY_ANALOG) {
+ fl = (hdw->state_encoder_ok &&
+ hdw->state_encoder_run);
+ } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+ (hdw->hdw_desc->flag_digital_requires_cx23416)) {
+ fl = hdw->state_encoder_ok;
+ }
+ if (fl &&
+ 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;
+ } else if ((hdw->pathway_state == PVR2_PATHWAY_DIGITAL) &&
+ (hdw->hdw_desc->flag_digital_requires_cx23416)) {
+ if (!hdw->state_encoder_ok) return 0;
+ if (hdw->state_encoder_run) return 0;
+ if (hdw->hdw_desc->digital_control_scheme ==
+ PVR2_DIGITAL_SCHEME_ONAIR) {
+ /* OnAir digital receivers won't stream
+ unless the analog encoder has run first.
+ Why? I have no idea. But don't even
+ try until we know the analog side is
+ known to have run. */
+ if (!hdw->state_encoder_runok) return 0;
+ }
+ }
if (pvr2_hdw_cmd_usbstream(hdw,!0) < 0) return 0;
hdw->state_usbstream_run = !0;
}
@@ -3453,7 +3914,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,
@@ -3501,6 +3963,34 @@ static int pvr2_hdw_state_update(struct pvr2_hdw *hdw)
}
+static unsigned int print_input_mask(unsigned int msk,
+ char *buf,unsigned int acnt)
+{
+ unsigned int idx,ccnt;
+ unsigned int tcnt = 0;
+ for (idx = 0; idx < ARRAY_SIZE(control_values_input); idx++) {
+ if (!((1 << idx) & msk)) continue;
+ ccnt = scnprintf(buf+tcnt,
+ acnt-tcnt,
+ "%s%s",
+ (tcnt ? ", " : ""),
+ control_values_input[idx]);
+ tcnt += ccnt;
+ }
+ return tcnt;
+}
+
+
+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)
{
@@ -3508,13 +3998,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,
@@ -3527,7 +4019,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 ?
@@ -3537,20 +4029,65 @@ static unsigned int pvr2_hdw_report_unlocked(struct pvr2_hdw *hdw,int which,
(hdw->state_encoder_ok ?
"" : " <encode:init>"),
(hdw->state_encoder_run ?
- " <encode:run>" : " <encode:stop>"),
+ (hdw->state_encoder_runok ?
+ " <encode:run>" :
+ " <encode:firstrun>") :
+ (hdw->state_encoder_runok ?
+ " <encode:stop>" :
+ " <encode:virgin>")),
(hdw->state_encoder_config ?
" <encode:configok>" :
(hdw->state_encoder_waitok ?
- "" : " <encode:wait>")),
+ "" : " <encode:waitok>")),
(hdw->state_usbstream_run ?
- " <usb:run>" : " <usb:stop>"));
- break;
+ " <usb:run>" : " <usb:stop>"),
+ (hdw->state_pathway_ok ?
+ " <pathway:ok>" : ""));
case 3:
return scnprintf(
buf,acnt,
"state: %s",
pvr2_get_state_name(hdw->master_state));
- break;
+ case 4: {
+ unsigned int tcnt = 0;
+ unsigned int ccnt;
+
+ ccnt = scnprintf(buf,
+ acnt,
+ "Hardware supported inputs: ");
+ tcnt += ccnt;
+ tcnt += print_input_mask(hdw->input_avail_mask,
+ buf+tcnt,
+ acnt-tcnt);
+ if (hdw->input_avail_mask != hdw->input_allowed_mask) {
+ ccnt = scnprintf(buf+tcnt,
+ acnt-tcnt,
+ "; allowed inputs: ");
+ tcnt += ccnt;
+ tcnt += print_input_mask(hdw->input_allowed_mask,
+ buf+tcnt,
+ acnt-tcnt);
+ }
+ return tcnt;
+ }
+ case 5: {
+ struct pvr2_stream_stats stats;
+ if (!hdw->vid_stream) break;
+ pvr2_stream_get_stats(hdw->vid_stream,
+ &stats,
+ 0);
+ return scnprintf(
+ buf,acnt,
+ "Bytes streamed=%u"
+ " URBs: queued=%u idle=%u ready=%u"
+ " processed=%u failed=%u",
+ stats.bytes_processed,
+ stats.buffers_in_queue,
+ stats.buffers_in_idle,
+ stats.buffers_in_ready,
+ stats.buffers_processed,
+ stats.buffers_failed);
+ }
default: break;
}
return 0;
@@ -3596,6 +4133,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");
@@ -3606,18 +4144,23 @@ 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->hdw_desc->flag_digital_requires_cx23416) &&
+ !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;
@@ -3627,6 +4170,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;
@@ -3656,47 +4200,6 @@ static void pvr2_hdw_state_sched(struct pvr2_hdw *hdw)
}
-void pvr2_hdw_get_debug_info_unlocked(const struct pvr2_hdw *hdw,
- struct pvr2_hdw_debug_info *ptr)
-{
- ptr->big_lock_held = hdw->big_lock_held;
- ptr->ctl_lock_held = hdw->ctl_lock_held;
- ptr->flag_disconnected = hdw->flag_disconnected;
- ptr->flag_init_ok = hdw->flag_init_ok;
- ptr->flag_ok = hdw->flag_ok;
- ptr->fw1_state = hdw->fw1_state;
- ptr->flag_decoder_missed = hdw->flag_decoder_missed;
- ptr->flag_tripped = hdw->flag_tripped;
- ptr->state_encoder_ok = hdw->state_encoder_ok;
- ptr->state_encoder_run = hdw->state_encoder_run;
- ptr->state_decoder_run = hdw->state_decoder_run;
- ptr->state_usbstream_run = hdw->state_usbstream_run;
- ptr->state_decoder_quiescent = hdw->state_decoder_quiescent;
- ptr->state_pipeline_config = hdw->state_pipeline_config;
- ptr->state_pipeline_req = hdw->state_pipeline_req;
- ptr->state_pipeline_pause = hdw->state_pipeline_pause;
- ptr->state_pipeline_idle = hdw->state_pipeline_idle;
- ptr->cmd_debug_state = hdw->cmd_debug_state;
- ptr->cmd_code = hdw->cmd_debug_code;
- ptr->cmd_debug_write_len = hdw->cmd_debug_write_len;
- ptr->cmd_debug_read_len = hdw->cmd_debug_read_len;
- ptr->cmd_debug_timeout = hdw->ctl_timeout_flag;
- ptr->cmd_debug_write_pend = hdw->ctl_write_pend_flag;
- ptr->cmd_debug_read_pend = hdw->ctl_read_pend_flag;
- ptr->cmd_debug_rstatus = hdw->ctl_read_urb->status;
- ptr->cmd_debug_wstatus = hdw->ctl_read_urb->status;
-}
-
-
-void pvr2_hdw_get_debug_info_locked(struct pvr2_hdw *hdw,
- struct pvr2_hdw_debug_info *ptr)
-{
- LOCK_TAKE(hdw->ctl_lock); do {
- pvr2_hdw_get_debug_info_unlocked(hdw,ptr);
- } while(0); LOCK_GIVE(hdw->ctl_lock);
-}
-
-
int pvr2_hdw_gpio_get_dir(struct pvr2_hdw *hdw,u32 *dp)
{
return pvr2_read_register(hdw,PVR2_GPIO_DIR,dp);
@@ -3756,6 +4259,80 @@ 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;
+}
+
+
+unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *hdw)
+{
+ return hdw->input_allowed_mask;
+}
+
+
+static int pvr2_hdw_set_input(struct pvr2_hdw *hdw,int v)
+{
+ if (hdw->input_val != v) {
+ hdw->input_val = v;
+ hdw->input_dirty = !0;
+ }
+
+ /* Handle side effects - if we switch to a mode that needs the RF
+ tuner, then select the right frequency choice as well and mark
+ it dirty. */
+ if (hdw->input_val == PVR2_CVAL_INPUT_RADIO) {
+ hdw->freqSelector = 0;
+ hdw->freqDirty = !0;
+ } else if ((hdw->input_val == PVR2_CVAL_INPUT_TV) ||
+ (hdw->input_val == PVR2_CVAL_INPUT_DTV)) {
+ hdw->freqSelector = 1;
+ hdw->freqDirty = !0;
+ }
+ return 0;
+}
+
+
+int pvr2_hdw_set_input_allowed(struct pvr2_hdw *hdw,
+ unsigned int change_mask,
+ unsigned int change_val)
+{
+ int ret = 0;
+ unsigned int nv,m,idx;
+ LOCK_TAKE(hdw->big_lock);
+ do {
+ nv = hdw->input_allowed_mask & ~change_mask;
+ nv |= (change_val & change_mask);
+ nv &= hdw->input_avail_mask;
+ if (!nv) {
+ /* No legal modes left; return error instead. */
+ ret = -EPERM;
+ break;
+ }
+ hdw->input_allowed_mask = nv;
+ if ((1 << hdw->input_val) & hdw->input_allowed_mask) {
+ /* Current mode is still in the allowed mask, so
+ we're done. */
+ break;
+ }
+ /* Select and switch to a mode that is still in the allowed
+ mask */
+ if (!hdw->input_allowed_mask) {
+ /* Nothing legal; give up */
+ break;
+ }
+ m = hdw->input_allowed_mask;
+ for (idx = 0; idx < (sizeof(m) << 3); idx++) {
+ if (!((1 << idx) & m)) continue;
+ pvr2_hdw_set_input(hdw,idx);
+ break;
+ }
+ } while (0);
+ LOCK_GIVE(hdw->big_lock);
+ return ret;
+}
+
+
/* 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 3ad7a13d6c3..20295e0c199 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 */
@@ -90,9 +91,6 @@ enum pvr2_v4l_type {
/* Translate configuration enum to a string label */
const char *pvr2_config_get_name(enum pvr2_config);
-/* Translate a master state enum to a string label */
-const char *pvr2_hdw_get_state_name(unsigned int);
-
struct pvr2_hdw;
/* Create and return a structure for interacting with the underlying
@@ -100,14 +98,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 +145,23 @@ 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 a bit mask of allowed input selections for this device. Mask bits
+ * will be according to PVR_CVAL_INPUT_xxxx definitions. */
+unsigned int pvr2_hdw_get_input_allowed(struct pvr2_hdw *);
+
+/* Change the set of allowed input selections for this device. Both
+ change_mask and change_valu are mask bits according to
+ PVR_CVAL_INPUT_xxxx definitions. The change_mask parameter indicate
+ which settings are being changed and the change_val parameter indicates
+ whether corresponding settings are being set or cleared. */
+int pvr2_hdw_set_input_allowed(struct pvr2_hdw *,
+ unsigned int change_mask,
+ unsigned int change_val);
+
/* Return name for this driver instance */
const char *pvr2_hdw_get_driver_name(struct pvr2_hdw *);
@@ -250,6 +266,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 62867fa3517..793c89a8d67 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-io.c b/drivers/media/video/pvrusb2/pvrusb2-io.c
index a9889ff96ec..7aff8b72006 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -80,6 +80,10 @@ struct pvr2_stream {
/* Tracking state for tolerating errors */
unsigned int fail_count;
unsigned int fail_tolerance;
+
+ unsigned int buffers_processed;
+ unsigned int buffers_failed;
+ unsigned int bytes_processed;
};
struct pvr2_buffer {
@@ -446,6 +450,8 @@ static void buffer_complete(struct urb *urb)
(urb->status == -ENOENT) ||
(urb->status == -ECONNRESET) ||
(urb->status == -ESHUTDOWN)) {
+ (sp->buffers_processed)++;
+ sp->bytes_processed += urb->actual_length;
bp->used_count = urb->actual_length;
if (sp->fail_count) {
pvr2_trace(PVR2_TRACE_TOLERANCE,
@@ -457,11 +463,13 @@ static void buffer_complete(struct urb *urb)
// We can tolerate this error, because we're below the
// threshold...
(sp->fail_count)++;
+ (sp->buffers_failed)++;
pvr2_trace(PVR2_TRACE_TOLERANCE,
"stream %p ignoring error %d"
" - fail count increased to %u",
sp,urb->status,sp->fail_count);
} else {
+ (sp->buffers_failed)++;
bp->status = urb->status;
}
spin_unlock_irqrestore(&sp->list_lock,irq_flags);
@@ -515,6 +523,28 @@ void pvr2_stream_set_callback(struct pvr2_stream *sp,
} while(0); mutex_unlock(&sp->mutex);
}
+void pvr2_stream_get_stats(struct pvr2_stream *sp,
+ struct pvr2_stream_stats *stats,
+ int zero_counts)
+{
+ unsigned long irq_flags;
+ spin_lock_irqsave(&sp->list_lock,irq_flags);
+ if (stats) {
+ stats->buffers_in_queue = sp->q_count;
+ stats->buffers_in_idle = sp->i_count;
+ stats->buffers_in_ready = sp->r_count;
+ stats->buffers_processed = sp->buffers_processed;
+ stats->buffers_failed = sp->buffers_failed;
+ stats->bytes_processed = sp->bytes_processed;
+ }
+ if (zero_counts) {
+ sp->buffers_processed = 0;
+ sp->buffers_failed = 0;
+ sp->bytes_processed = 0;
+ }
+ spin_unlock_irqrestore(&sp->list_lock,irq_flags);
+}
+
/* Query / set the nominal buffer count */
int pvr2_stream_get_buffer_count(struct pvr2_stream *sp)
{
diff --git a/drivers/media/video/pvrusb2/pvrusb2-io.h b/drivers/media/video/pvrusb2/pvrusb2-io.h
index 93279cc2a35..42fcf8281a8 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-io.h
+++ b/drivers/media/video/pvrusb2/pvrusb2-io.h
@@ -36,6 +36,15 @@ enum pvr2_buffer_state {
struct pvr2_stream;
struct pvr2_buffer;
+struct pvr2_stream_stats {
+ unsigned int buffers_in_queue;
+ unsigned int buffers_in_idle;
+ unsigned int buffers_in_ready;
+ unsigned int buffers_processed;
+ unsigned int buffers_failed;
+ unsigned int bytes_processed;
+};
+
/* Initialize / tear down stream structure */
struct pvr2_stream *pvr2_stream_create(void);
void pvr2_stream_destroy(struct pvr2_stream *);
@@ -45,6 +54,9 @@ void pvr2_stream_setup(struct pvr2_stream *,
void pvr2_stream_set_callback(struct pvr2_stream *,
pvr2_stream_callback func,
void *data);
+void pvr2_stream_get_stats(struct pvr2_stream *,
+ struct pvr2_stream_stats *,
+ int zero_counts);
/* Query / set the nominal buffer count */
int pvr2_stream_get_buffer_count(struct pvr2_stream *);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-main.c b/drivers/media/video/pvrusb2/pvrusb2-main.c
index b63b2265503..332aced8a5a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-main.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-main.c
@@ -60,6 +60,10 @@ static void pvr_setup_attach(struct pvr2_context *pvr)
{
/* Create association with v4l layer */
pvr2_v4l2_create(pvr);
+#ifdef CONFIG_VIDEO_PVRUSB2_DVB
+ /* Create association with dvb layer */
+ pvr2_dvb_create(pvr);
+#endif
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_create(pvr,class_ptr);
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
@@ -121,6 +125,12 @@ static int __init pvr_init(void)
pvr2_trace(PVR2_TRACE_INIT,"pvr_init");
+ ret = pvr2_context_global_init();
+ if (ret != 0) {
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_init failure code=%d",ret);
+ return ret;
+ }
+
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
class_ptr = pvr2_sysfs_class_create();
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
@@ -132,6 +142,8 @@ static int __init pvr_init(void)
if (pvrusb2_debug) info("Debug mask is %d (0x%x)",
pvrusb2_debug,pvrusb2_debug);
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_init complete");
+
return ret;
}
@@ -144,6 +156,10 @@ static void __exit pvr_exit(void)
#ifdef CONFIG_VIDEO_PVRUSB2_SYSFS
pvr2_sysfs_class_destroy(class_ptr);
#endif /* CONFIG_VIDEO_PVRUSB2_SYSFS */
+
+ pvr2_context_global_done();
+
+ pvr2_trace(PVR2_TRACE_INIT,"pvr_exit complete");
}
module_init(pvr_init);
diff --git a/drivers/media/video/pvrusb2/pvrusb2-std.c b/drivers/media/video/pvrusb2/pvrusb2-std.c
index da309288daa..fdc5a2b49ca 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 07f4eae1843..0ff7a836a8a 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-sysfs.c
@@ -287,6 +287,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;
@@ -298,6 +300,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;
@@ -604,8 +608,9 @@ static void pvr2_sysfs_add_control(struct pvr2_sysfs *sfp,int ctl_id)
ret = sysfs_create_group(&sfp->class_dev->kobj,&cip->grp);
if (ret) {
- printk(KERN_WARNING "%s: sysfs_create_group error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "sysfs_create_group error: %d",
+ ret);
return;
}
cip->created_ok = !0;
@@ -636,15 +641,17 @@ static void pvr2_sysfs_add_debugifc(struct pvr2_sysfs *sfp)
sfp->debugifc = dip;
ret = device_create_file(sfp->class_dev,&dip->attr_debugcmd);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
dip->debugcmd_created_ok = !0;
}
ret = device_create_file(sfp->class_dev,&dip->attr_debuginfo);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
dip->debuginfo_created_ok = !0;
}
@@ -847,8 +854,8 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
class_dev->driver_data = sfp;
ret = device_register(class_dev);
if (ret) {
- printk(KERN_ERR "%s: device_register failed\n",
- __FUNCTION__);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_register failed");
kfree(class_dev);
return;
}
@@ -860,8 +867,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_v4l_minor_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->v4l_minor_number_created_ok = !0;
}
@@ -873,8 +881,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_v4l_radio_minor_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->v4l_radio_minor_number_created_ok = !0;
}
@@ -885,8 +894,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
sfp->attr_unit_number.store = NULL;
ret = device_create_file(sfp->class_dev,&sfp->attr_unit_number);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->unit_number_created_ok = !0;
}
@@ -898,8 +908,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_bus_info);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->bus_info_created_ok = !0;
}
@@ -911,8 +922,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_hdw_name);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->hdw_name_created_ok = !0;
}
@@ -924,8 +936,9 @@ static void class_dev_create(struct pvr2_sysfs *sfp,
ret = device_create_file(sfp->class_dev,
&sfp->attr_hdw_desc);
if (ret < 0) {
- printk(KERN_WARNING "%s: device_create_file error: %d\n",
- __FUNCTION__, ret);
+ pvr2_trace(PVR2_TRACE_ERROR_LEGS,
+ "device_create_file error: %d",
+ ret);
} else {
sfp->hdw_desc_created_ok = !0;
}
diff --git a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
index 8f0587ebd4b..087a1824556 100644
--- a/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
+++ b/drivers/media/video/pvrusb2/pvrusb2-v4l2.c
@@ -57,7 +57,9 @@ struct pvr2_v4l2_fh {
struct pvr2_v4l2_fh *vprev;
wait_queue_head_t wait_data;
int fw_mode_flag;
- int prev_input_val;
+ /* Map contiguous ordinal value to input id */
+ unsigned char *input_map;
+ unsigned int input_cnt;
};
struct pvr2_v4l2 {
@@ -259,14 +261,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 >= fh->input_cnt)) {
+ ret = -EINVAL;
+ break;
+ }
+ val = fh->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 +290,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 +312,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 < fh->input_cnt; idx++) {
+ if (fh->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 >= fh->input_cnt)) {
+ ret = -ERANGE;
+ break;
+ }
ret = pvr2_ctrl_set_value(
pvr2_hdw_get_ctrl_by_id(hdw,PVR2_CID_INPUT),
- vi->index);
+ fh->input_map[vi->index]);
break;
}
@@ -858,7 +878,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 +894,30 @@ 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);
- }
- }
-
- 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);
+ if (fhp->input_map) {
+ kfree(fhp->input_map);
+ fhp->input_map = NULL;
+ }
+ kfree(fhp);
+ if (vp->channel.mc_head->disconnect_flag && !vp->vfirst) {
+ pvr2_v4l2_destroy_no_lock(vp);
+ }
return 0;
}
@@ -921,6 +928,9 @@ static int pvr2_v4l2_open(struct inode *inode, struct file *file)
struct pvr2_v4l2_fh *fhp;
struct pvr2_v4l2 *vp;
struct pvr2_hdw *hdw;
+ unsigned int input_mask = 0;
+ unsigned int input_cnt,idx;
+ int ret = 0;
dip = container_of(video_devdata(file),struct pvr2_v4l2_dev,devbase);
@@ -943,32 +953,62 @@ 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);
+ if (dip->v4l_type == VFL_TYPE_RADIO) {
+ /* Opening device as a radio, legal input selection subset
+ is just the radio. */
+ input_mask = (1 << PVR2_CVAL_INPUT_RADIO);
+ } else {
+ /* Opening the main V4L device, legal input selection
+ subset includes all analog inputs. */
+ input_mask = ((1 << PVR2_CVAL_INPUT_RADIO) |
+ (1 << PVR2_CVAL_INPUT_TV) |
+ (1 << PVR2_CVAL_INPUT_COMPOSITE) |
+ (1 << PVR2_CVAL_INPUT_SVIDEO));
+ }
+ ret = pvr2_channel_limit_inputs(&fhp->channel,input_mask);
+ if (ret) {
+ pvr2_channel_done(&fhp->channel);
+ pvr2_trace(PVR2_TRACE_STRUCT,
+ "Destroying pvr_v4l2_fh id=%p (input mask error)",
+ fhp);
+
+ kfree(fhp);
+ return ret;
+ }
+
+ 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++;
+ }
+ fhp->input_cnt = input_cnt;
+ fhp->input_map = kzalloc(input_cnt,GFP_KERNEL);
+ if (!fhp->input_map) {
+ pvr2_channel_done(&fhp->channel);
+ pvr2_trace(PVR2_TRACE_STRUCT,
+ "Destroying pvr_v4l2_fh id=%p (input map failure)",
+ fhp);
+ kfree(fhp);
+ return -ENOMEM;
+ }
+ input_cnt = 0;
+ for (idx = 0; idx < (sizeof(input_mask) << 3); idx++) {
+ if (!(input_mask & (1 << idx))) continue;
+ fhp->input_map[input_cnt++] = idx;
+ }
+
+ fhp->vnext = NULL;
+ fhp->vprev = vp->vlast;
+ if (vp->vlast) {
+ vp->vlast->vnext = fhp;
+ } else {
+ vp->vfirst = fhp;
+ }
+ vp->vlast = fhp;
+ fhp->vhead = vp;
fhp->file = file;
file->private_data = fhp;
@@ -1201,24 +1241,27 @@ struct pvr2_v4l2 *pvr2_v4l2_create(struct pvr2_context *mnp)
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;
/* 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 (pvr2_hdw_get_input_available(vp->channel.mc_head->hdw) &
+ (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 e0a453a6543..423fa7c2d0c 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 = {
@@ -487,7 +489,7 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
int i;
unsigned long flags;
- PWC_DEBUG_MEMORY(">> %s __enter__\n", __FUNCTION__);
+ PWC_DEBUG_MEMORY(">> %s __enter__\n", __func__);
spin_lock_irqsave(&pdev->ptrlock, flags);
pdev->full_frames = NULL;
@@ -509,7 +511,7 @@ static void pwc_reset_buffers(struct pwc_device *pdev)
pdev->fill_image = 0;
spin_unlock_irqrestore(&pdev->ptrlock, flags);
- PWC_DEBUG_MEMORY("<< %s __leaving__\n", __FUNCTION__);
+ PWC_DEBUG_MEMORY("<< %s __leaving__\n", __func__);
}
@@ -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);
@@ -1426,7 +1428,7 @@ static int pwc_video_mmap(struct file *file, struct vm_area_struct *vma)
unsigned long page, pos = 0;
int index;
- PWC_DEBUG_MEMORY(">> %s\n", __FUNCTION__);
+ PWC_DEBUG_MEMORY(">> %s\n", __func__);
pdev = vdev->priv;
size = vma->vm_end - vma->vm_start;
start = vma->vm_start;
diff --git a/drivers/media/video/pwc/pwc-v4l.c b/drivers/media/video/pwc/pwc-v4l.c
index 32fbe1ae625..1742889874d 100644
--- a/drivers/media/video/pwc/pwc-v4l.c
+++ b/drivers/media/video/pwc/pwc-v4l.c
@@ -351,8 +351,10 @@ int pwc_video_do_ioctl(struct inode *inode, struct file *file,
return -EFAULT;
#ifdef CONFIG_USB_PWC_DEBUG
- if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace)
+ if (PWC_DEBUG_LEVEL_IOCTL & pwc_trace) {
v4l_printk_ioctl(cmd);
+ printk("\n");
+ }
#endif
diff --git a/drivers/media/video/pxa_camera.c b/drivers/media/video/pxa_camera.c
new file mode 100644
index 00000000000..7cc8e9b19fb
--- /dev/null
+++ b/drivers/media/video/pxa_camera.c
@@ -0,0 +1,1206 @@
+/*
+ * 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 CICR1_COLOR_SP_VAL(x) (((x) << 3) & CICR1_COLOR_SP) /* color space */
+#define CICR1_RGB_BPP_VAL(x) (((x) << 7) & CICR1_RGB_BPP) /* bpp for rgb */
+#define CICR1_RGBT_CONV_VAL(x) (((x) << 29) & CICR1_RGBT_CONV) /* rgbt conv */
+
+#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
+ */
+enum pxa_camera_active_dma {
+ DMA_Y = 0x1,
+ DMA_U = 0x2,
+ DMA_V = 0x4,
+};
+
+/* descriptor needed for the PXA DMA engine */
+struct pxa_cam_dma {
+ dma_addr_t sg_dma;
+ struct pxa_dma_desc *sg_cpu;
+ size_t sg_size;
+ int sglen;
+};
+
+/* 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 lists for Y, U and V channels */
+ struct pxa_cam_dma dmas[3];
+
+ int inwork;
+
+ enum pxa_camera_active_dma active_dma;
+};
+
+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;
+
+ int channels;
+ unsigned int dma_chans[3];
+
+ 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;
+ struct pxa_dma_desc *sg_tail[3];
+};
+
+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;
+ struct soc_camera_host *ici =
+ to_soc_camera_host(icd->dev.parent);
+ struct pxa_camera_dev *pcdev = ici->priv;
+
+ dev_dbg(&icd->dev, "count=%d, size=%d\n", *count, *size);
+
+ /* planar capture requires Y, U and V buffers to be page aligned */
+ if (pcdev->channels == 3) {
+ *size = PAGE_ALIGN(icd->width * icd->height); /* Y pages */
+ *size += PAGE_ALIGN(icd->width * icd->height / 2); /* U pages */
+ *size += PAGE_ALIGN(icd->width * icd->height / 2); /* V pages */
+ } else {
+ *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);
+ int i;
+
+ BUG_ON(in_interrupt());
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ &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);
+
+ for (i = 0; i < ARRAY_SIZE(buf->dmas); i++) {
+ if (buf->dmas[i].sg_cpu)
+ dma_free_coherent(pcdev->dev, buf->dmas[i].sg_size,
+ buf->dmas[i].sg_cpu,
+ buf->dmas[i].sg_dma);
+ buf->dmas[i].sg_cpu = NULL;
+ }
+
+ buf->vb.state = VIDEOBUF_NEEDS_INIT;
+}
+
+static int pxa_init_dma_channel(struct pxa_camera_dev *pcdev,
+ struct pxa_buffer *buf,
+ struct videobuf_dmabuf *dma, int channel,
+ int sglen, int sg_start, int cibr,
+ unsigned int size)
+{
+ struct pxa_cam_dma *pxa_dma = &buf->dmas[channel];
+ int i;
+
+ if (pxa_dma->sg_cpu)
+ dma_free_coherent(pcdev->dev, pxa_dma->sg_size,
+ pxa_dma->sg_cpu, pxa_dma->sg_dma);
+
+ pxa_dma->sg_size = (sglen + 1) * sizeof(struct pxa_dma_desc);
+ pxa_dma->sg_cpu = dma_alloc_coherent(pcdev->dev, pxa_dma->sg_size,
+ &pxa_dma->sg_dma, GFP_KERNEL);
+ if (!pxa_dma->sg_cpu)
+ return -ENOMEM;
+
+ pxa_dma->sglen = sglen;
+
+ for (i = 0; i < sglen; i++) {
+ int sg_i = sg_start + i;
+ struct scatterlist *sg = dma->sglist;
+ unsigned int dma_len = sg_dma_len(&sg[sg_i]), xfer_len;
+
+ pxa_dma->sg_cpu[i].dsadr = pcdev->res->start + cibr;
+ pxa_dma->sg_cpu[i].dtadr = sg_dma_address(&sg[sg_i]);
+
+ /* PXA27x Developer's Manual 27.4.4.1: round up to 8 bytes */
+ xfer_len = (min(dma_len, size) + 7) & ~7;
+
+ pxa_dma->sg_cpu[i].dcmd =
+ DCMD_FLOWSRC | DCMD_BURST8 | DCMD_INCTRGADDR | xfer_len;
+ size -= dma_len;
+ pxa_dma->sg_cpu[i].ddadr =
+ pxa_dma->sg_dma + (i + 1) * sizeof(struct pxa_dma_desc);
+ }
+
+ pxa_dma->sg_cpu[sglen - 1].ddadr = DDADR_STOP;
+ pxa_dma->sg_cpu[sglen - 1].dcmd |= DCMD_ENDIRQEN;
+
+ return 0;
+}
+
+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 ret;
+ int sglen_y, sglen_yu = 0, sglen_u = 0, sglen_v = 0;
+ int size_y, size_u = 0, size_v = 0;
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ 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 (pcdev->channels == 3) {
+ /* FIXME the calculations should be more precise */
+ sglen_y = dma->sglen / 2;
+ sglen_u = sglen_v = dma->sglen / 4 + 1;
+ sglen_yu = sglen_y + sglen_u;
+ size_y = size / 2;
+ size_u = size_v = size / 4;
+ } else {
+ sglen_y = dma->sglen;
+ size_y = size;
+ }
+
+ /* init DMA for Y channel */
+ ret = pxa_init_dma_channel(pcdev, buf, dma, 0, sglen_y,
+ 0, 0x28, size_y);
+
+ if (ret) {
+ dev_err(pcdev->dev,
+ "DMA initialization for Y/RGB failed\n");
+ goto fail;
+ }
+
+ if (pcdev->channels == 3) {
+ /* init DMA for U channel */
+ ret = pxa_init_dma_channel(pcdev, buf, dma, 1, sglen_u,
+ sglen_y, 0x30, size_u);
+ if (ret) {
+ dev_err(pcdev->dev,
+ "DMA initialization for U failed\n");
+ goto fail_u;
+ }
+
+ /* init DMA for V channel */
+ ret = pxa_init_dma_channel(pcdev, buf, dma, 2, sglen_v,
+ sglen_yu, 0x38, size_v);
+ if (ret) {
+ dev_err(pcdev->dev,
+ "DMA initialization for V failed\n");
+ goto fail_v;
+ }
+ }
+
+ vb->state = VIDEOBUF_PREPARED;
+ }
+
+ buf->inwork = 0;
+ buf->active_dma = DMA_Y;
+ if (pcdev->channels == 3)
+ buf->active_dma |= DMA_U | DMA_V;
+
+ return 0;
+
+fail_v:
+ dma_free_coherent(pcdev->dev, buf->dmas[1].sg_size,
+ buf->dmas[1].sg_cpu, buf->dmas[1].sg_dma);
+fail_u:
+ dma_free_coherent(pcdev->dev, buf->dmas[0].sg_size,
+ buf->dmas[0].sg_cpu, buf->dmas[0].sg_dma);
+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;
+ unsigned long flags;
+ int i;
+
+ dev_dbg(&icd->dev, "%s (vb=0x%p) 0x%08lx %d\n", __func__,
+ 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;
+
+ for (i = 0; i < pcdev->channels; i++) {
+ DDADR(pcdev->dma_chans[i]) = buf->dmas[i].sg_dma;
+ DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+ pcdev->sg_tail[i] = buf->dmas[i].sg_cpu + buf->dmas[i].sglen - 1;
+ }
+
+ pcdev->active = buf;
+ CICR0 |= CICR0_ENB;
+ } else {
+ struct pxa_cam_dma *buf_dma;
+ struct pxa_cam_dma *act_dma;
+ int nents;
+
+ for (i = 0; i < pcdev->channels; i++) {
+ buf_dma = &buf->dmas[i];
+ act_dma = &active->dmas[i];
+ nents = buf_dma->sglen;
+
+ /* Stop DMA engine */
+ DCSR(pcdev->dma_chans[i]) = 0;
+
+ /* Add the descriptors we just initialized to
+ the currently running chain */
+ pcdev->sg_tail[i]->ddadr = buf_dma->sg_dma;
+ pcdev->sg_tail[i] = buf_dma->sg_cpu + buf_dma->sglen - 1;
+
+ /* Setup a dummy descriptor with the DMA engines current
+ * state
+ */
+ buf_dma->sg_cpu[nents].dsadr =
+ pcdev->res->start + 0x28 + i*8; /* CIBRx */
+ buf_dma->sg_cpu[nents].dtadr =
+ DTADR(pcdev->dma_chans[i]);
+ buf_dma->sg_cpu[nents].dcmd =
+ DCMD(pcdev->dma_chans[i]);
+
+ if (DDADR(pcdev->dma_chans[i]) == DDADR_STOP) {
+ /* The DMA engine is on the last
+ descriptor, set the next descriptors
+ address to the descriptors we just
+ initialized */
+ buf_dma->sg_cpu[nents].ddadr = buf_dma->sg_dma;
+ } else {
+ buf_dma->sg_cpu[nents].ddadr =
+ DDADR(pcdev->dma_chans[i]);
+ }
+
+ /* The next descriptor is the dummy descriptor */
+ DDADR(pcdev->dma_chans[i]) = buf_dma->sg_dma + nents *
+ sizeof(struct pxa_dma_desc);
+
+ DCSR(pcdev->dma_chans[i]) = 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", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ switch (vb->state) {
+ case VIDEOBUF_ACTIVE:
+ dev_dbg(&icd->dev, "%s (active)\n", __func__);
+ break;
+ case VIDEOBUF_QUEUED:
+ dev_dbg(&icd->dev, "%s (queued)\n", __func__);
+ break;
+ case VIDEOBUF_PREPARED:
+ dev_dbg(&icd->dev, "%s (prepared)\n", __func__);
+ break;
+ default:
+ dev_dbg(&icd->dev, "%s (unknown)\n", __func__);
+ break;
+ }
+#endif
+
+ free_buffer(vq, buf);
+}
+
+static void pxa_camera_wakeup(struct pxa_camera_dev *pcdev,
+ struct videobuf_buffer *vb,
+ struct pxa_buffer *buf)
+{
+ /* _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_chans[0]) = 0;
+ DCSR(pcdev->dma_chans[1]) = 0;
+ DCSR(pcdev->dma_chans[2]) = 0;
+ CICR0 &= ~CICR0_ENB;
+ return;
+ }
+
+ pcdev->active = list_entry(pcdev->capture.next,
+ struct pxa_buffer, vb.queue);
+}
+
+static void pxa_camera_dma_irq(int channel, struct pxa_camera_dev *pcdev,
+ enum pxa_camera_active_dma act_dma)
+{
+ struct pxa_buffer *buf;
+ unsigned long flags;
+ u32 status, camera_status, overrun;
+ struct videobuf_buffer *vb;
+
+ spin_lock_irqsave(&pcdev->lock, flags);
+
+ status = DCSR(channel);
+ DCSR(channel) = status | DCSR_ENDINTR;
+
+ 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;
+ }
+
+ camera_status = CISR;
+ overrun = CISR_IFO_0;
+ if (pcdev->channels == 3)
+ overrun |= CISR_IFO_1 | CISR_IFO_2;
+ if (camera_status & overrun) {
+ dev_dbg(pcdev->dev, "FIFO overrun! CISR: %x\n", camera_status);
+ /* Stop the Capture Interface */
+ CICR0 &= ~CICR0_ENB;
+ /* Stop DMA */
+ DCSR(channel) = 0;
+ /* Reset the FIFOs */
+ CIFR |= CIFR_RESET_F;
+ /* Enable End-Of-Frame Interrupt */
+ CICR0 &= ~CICR0_EOFM;
+ /* Restart the Capture Interface */
+ CICR0 |= CICR0_ENB;
+ 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", __func__,
+ vb, vb->baddr, vb->bsize);
+
+ buf->active_dma &= ~act_dma;
+ if (!buf->active_dma)
+ pxa_camera_wakeup(pcdev, vb, buf);
+
+out:
+ spin_unlock_irqrestore(&pcdev->lock, flags);
+}
+
+static void pxa_camera_dma_irq_y(int channel, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(channel, pcdev, DMA_Y);
+}
+
+static void pxa_camera_dma_irq_u(int channel, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(channel, pcdev, DMA_U);
+}
+
+static void pxa_camera_dma_irq_v(int channel, void *data)
+{
+ struct pxa_camera_dev *pcdev = data;
+ pxa_camera_dma_irq(channel, pcdev, DMA_V);
+}
+
+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", __func__);
+ pdata->init(pcdev->dev);
+ }
+
+ if (pdata && pdata->power) {
+ dev_dbg(pcdev->dev, "%s: Power on camera\n", __func__);
+ pdata->power(pcdev->dev, 1);
+ }
+
+ if (pdata && pdata->reset) {
+ dev_dbg(pcdev->dev, "%s: Releasing camera reset\n",
+ __func__);
+ 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",
+ __func__);
+ board->reset(pcdev->dev, 0);
+ }
+
+ if (board && board->power) {
+ dev_dbg(pcdev->dev, "%s: Power off camera\n", __func__);
+ 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);
+
+ if (!status)
+ return IRQ_NONE;
+
+ CISR = status;
+
+ if (status & CISR_EOF) {
+ int i;
+ for (i = 0; i < pcdev->channels; i++) {
+ DDADR(pcdev->dma_chans[i]) =
+ pcdev->active->dmas[i].sg_dma;
+ DCSR(pcdev->dma_chans[i]) = DCSR_RUN;
+ }
+ CICR0 |= CICR0_EOFM;
+ }
+
+ 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_chans[0]) = 0;
+ DCSR(pcdev->dma_chans[1]) = 0;
+ DCSR(pcdev->dma_chans[2]) = 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, cicr1, 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;
+
+ pcdev->channels = 1;
+
+ /* 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;
+
+ switch (pixfmt) {
+ case V4L2_PIX_FMT_YUV422P:
+ pcdev->channels = 3;
+ cicr1 |= CICR1_YCBCR_F;
+ case V4L2_PIX_FMT_YUYV:
+ cicr1 |= CICR1_COLOR_SP_VAL(2);
+ break;
+ case V4L2_PIX_FMT_RGB555:
+ cicr1 |= CICR1_RGB_BPP_VAL(1) | CICR1_RGBT_CONV_VAL(2) |
+ CICR1_TBIT | CICR1_COLOR_SP_VAL(1);
+ break;
+ case V4L2_PIX_FMT_RGB565:
+ cicr1 |= CICR1_COLOR_SP_VAL(1) | CICR1_RGB_BPP_VAL(2);
+ break;
+ }
+
+ CICR1 = cicr1;
+ 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_chans[0] = pxa_request_dma("CI_Y", DMA_PRIO_HIGH,
+ pxa_camera_dma_irq_y, pcdev);
+ if (pcdev->dma_chans[0] < 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_chans[0]);
+
+ pcdev->dma_chans[1] = pxa_request_dma("CI_U", DMA_PRIO_HIGH,
+ pxa_camera_dma_irq_u, pcdev);
+ if (pcdev->dma_chans[1] < 0) {
+ dev_err(pcdev->dev, "Can't request DMA for U\n");
+ err = -ENOMEM;
+ goto exit_free_dma_y;
+ }
+ dev_dbg(pcdev->dev, "got DMA channel (U) %d\n", pcdev->dma_chans[1]);
+
+ pcdev->dma_chans[2] = pxa_request_dma("CI_V", DMA_PRIO_HIGH,
+ pxa_camera_dma_irq_v, pcdev);
+ if (pcdev->dma_chans[0] < 0) {
+ dev_err(pcdev->dev, "Can't request DMA for V\n");
+ err = -ENOMEM;
+ goto exit_free_dma_u;
+ }
+ dev_dbg(pcdev->dev, "got DMA channel (V) %d\n", pcdev->dma_chans[2]);
+
+ DRCMR68 = pcdev->dma_chans[0] | DRCMR_MAPVLD;
+ DRCMR69 = pcdev->dma_chans[1] | DRCMR_MAPVLD;
+ DRCMR70 = pcdev->dma_chans[2] | 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_chans[2]);
+exit_free_dma_u:
+ pxa_free_dma(pcdev->dma_chans[1]);
+exit_free_dma_y:
+ pxa_free_dma(pcdev->dma_chans[0]);
+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_chans[0]);
+ pxa_free_dma(pcdev->dma_chans[1]);
+ pxa_free_dma(pcdev->dma_chans[2]);
+ 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 f55d6e85f20..ec8c65dc840 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 72e344a12c7..716ee7f64df 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 1df2602cd18..4aa82b31070 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 a0772c53bb1..96c3d435772 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 bf91a4faa70..e79075533be 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 41e5e518a47..416d05d4a96 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 80bf9118785..cedb988574b 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 96bc3b1298a..e086f14d566 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 047add8f301..ba3082422a0 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;
}
@@ -954,10 +954,8 @@ static void snd_saa7134_free(struct snd_card * card)
if (chip->dev->dmasound.priv_data == NULL)
return;
- if (chip->irq >= 0) {
- synchronize_irq(chip->irq);
+ if (chip->irq >= 0)
free_irq(chip->irq, &chip->dev->dmasound);
- }
chip->dev->dmasound.priv_data = NULL;
diff --git a/drivers/media/video/saa7134/saa7134-cards.c b/drivers/media/video/saa7134/saa7134-cards.c
index 6f5744286e8..98375955a84 100644
--- a/drivers/media/video/saa7134/saa7134-cards.c
+++ b/drivers/media/video/saa7134/saa7134-cards.c
@@ -22,11 +22,15 @@
#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>
+#include "tea5767.h"
/* commly used strings */
static char name_mute[] = "mute";
@@ -1046,7 +1050,7 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_MANLI_MTV002] = {
/* Ognjen Nastic <ognjen@logosoft.ba> */
- .name = "Manli MuchTV M-TV002/Behold TV 403 FM",
+ .name = "Manli MuchTV M-TV002",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
.radio_type = UNSET,
@@ -1073,7 +1077,7 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_MANLI_MTV001] = {
/* Ognjen Nastic <ognjen@logosoft.ba> UNTESTED */
- .name = "Manli MuchTV M-TV001/Behold TV 401",
+ .name = "Manli MuchTV M-TV001",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_PAL,
.radio_type = UNSET,
@@ -2195,6 +2199,8 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_BEHOLD_409FM] = {
/* <http://tuner.beholder.ru>, Sergey <skiv@orel.ru> */
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 409 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -2202,6 +2208,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -2908,15 +2915,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 +3335,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,
@@ -3575,12 +3580,15 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_BEHOLD_401] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 401",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FQ1216ME,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3601,12 +3609,15 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_403] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 403",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FQ1216ME,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3623,12 +3634,15 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_BEHOLD_403FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 403 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FQ1216ME,
.radio_type = UNSET,
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3649,6 +3663,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_405] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 405",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3656,6 +3672,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3673,6 +3690,8 @@ struct saa7134_board saa7134_boards[] = {
},
[SAA7134_BOARD_BEHOLD_405FM] = {
/* Sergey <skiv@orel.ru> */
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 405 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3680,6 +3699,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3700,6 +3720,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_407] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 407",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3707,7 +3729,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .gpiomask = 0xc0c000,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3727,6 +3749,8 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_BEHOLD_407FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 407 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3734,7 +3758,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
- .gpiomask = 0xc0c000,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_svideo,
.vmux = 8,
@@ -3759,6 +3783,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_409] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 409",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3766,6 +3792,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -3782,6 +3809,8 @@ struct saa7134_board saa7134_boards[] = {
}},
},
[SAA7134_BOARD_BEHOLD_505FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 505 FM/RDS",
.audio_clock = 0x00200000,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3789,6 +3818,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -3813,6 +3843,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_507_9FM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV 507 FM/RDS / BeholdTV 509 FM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_PHILIPS_FM1216ME_MK3,
@@ -3820,6 +3852,7 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x00008000,
.inputs = {{
.name = name_tv,
.vmux = 3,
@@ -3840,6 +3873,8 @@ struct saa7134_board saa7134_boards[] = {
},
},
[SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM] = {
+ /* Beholder Intl. Ltd. 2008 */
+ /*Dmitry Belimov <d.belimov@gmail.com> */
.name = "Beholder BeholdTV Columbus TVFM",
.audio_clock = 0x00187de7,
.tuner_type = TUNER_ALPS_TSBE5_PAL,
@@ -3847,23 +3882,28 @@ struct saa7134_board saa7134_boards[] = {
.tuner_addr = ADDR_UNSET,
.radio_addr = ADDR_UNSET,
.tda9887_conf = TDA9887_PRESENT,
+ .gpiomask = 0x000A8004,
.inputs = {{
.name = name_tv,
.vmux = 3,
.amux = TV,
.tv = 1,
- },{
+ .gpio = 0x000A8004,
+ }, {
.name = name_comp1,
.vmux = 1,
.amux = LINE1,
- },{
+ .gpio = 0x000A8000,
+ }, {
.name = name_svideo,
.vmux = 8,
.amux = LINE1,
- }},
+ .gpio = 0x000A8000,
+ } },
.radio = {
.name = name_radio,
.amux = LINE2,
+ .gpio = 0x000A8000,
},
},
[SAA7134_BOARD_BEHOLD_607_9FM] = {
@@ -3992,6 +4032,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 +4479,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 +5209,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 +5301,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 +5441,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 +5508,29 @@ 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_BEHOLD_COLUMBUS_TVFM:
+ case SAA7134_BOARD_AVERMEDIA_CARDBUS_506:
+ case SAA7134_BOARD_AVERMEDIA_M115:
+ 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_BEHOLD_COLUMBUS_TVFM:
+ /* power-down tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0);
+ msleep(10);
+ /* power-up tuner chip */
+ saa_andorl(SAA7134_GPIO_GPMODE0 >> 2, 0x000A8004, 0x000A8004);
+ saa_andorl(SAA7134_GPIO_GPSTATUS0 >> 2, 0x000A8004, 0x000A8004);
+ msleep(10);
+ /* remote via GPIO */
+ dev->has_remote = SAA7134_REMOTE_GPIO;
break;
case SAA7134_BOARD_RTD_VFG7350:
@@ -5160,7 +5553,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 +5564,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 +5601,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 +5681,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 +5750,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
*/
@@ -5402,13 +5820,46 @@ int saa7134_board_init2(struct saa7134_dev *dev)
break;
}
break;
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ {
+ struct v4l2_priv_tun_config tea5767_cfg;
+ struct tea5767_ctrl ctl;
+
+ dev->i2c_client.addr = 0xC0;
+ /* set TEA5767(analog FM) defines */
+ memset(&ctl, 0, sizeof(ctl));
+ ctl.xtal_freq = TEA5767_HIGH_LO_13MHz;
+ tea5767_cfg.tuner = TUNER_TEA5767;
+ tea5767_cfg.priv = &ctl;
+ saa7134_i2c_call_clients(dev, TUNER_SET_CONFIG, &tea5767_cfg);
+ }
+ 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 58ab163fdbd..eec127864fe 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 ea2be9eceeb..2d16be2259d 100644
--- a/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/drivers/media/video/saa7134/saa7134-dvb.c
@@ -33,33 +33,40 @@
#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).");
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
#define dprintk(fmt, arg...) do { if (debug) \
printk(KERN_DEBUG "%s/dvb: " fmt, dev->name , ## arg); } while(0)
@@ -91,7 +98,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 +118,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 +153,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 +215,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 +467,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 +482,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 +504,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 +538,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 +611,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 +625,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 +638,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 +651,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 +665,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 +678,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 +691,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 +729,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 +742,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 +756,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 +770,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 +784,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 +798,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 +825,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 = {
@@ -842,8 +851,73 @@ static struct tda10086_config flydvbs = {
.demod_address = 0x0e,
.invert = 0,
.diseqc_tone = 0,
+ .xtal_freq = TDA10086_XTAL_16M,
};
+static struct tda10086_config sd1878_4m = {
+ .demod_address = 0x0e,
+ .invert = 0,
+ .diseqc_tone = 0,
+ .xtal_freq = TDA10086_XTAL_4M,
+};
+
+/* ------------------------------------------------------------------
+ * 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 +937,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 +965,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 +997,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 +1022,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 +1063,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 +1126,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 +1137,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 +1153,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,38 +1168,107 @@ 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,
+ &sd1878_4m, &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;
}
/* register everything else */
- ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev);
+ ret = videobuf_dvb_register(&dev->dvb, THIS_MODULE, dev, &dev->pci->dev,
+ adapter_nr);
/* this sequence is necessary to make the tda1004x load its firmware
* and to enter analog mode of hybrid boards
@@ -1106,9 +1299,22 @@ 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);
+ if (dev->dvb.frontend)
+ 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 3d2ec30de22..1314522a813 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");
@@ -402,7 +402,7 @@ static int empress_init(struct saa7134_dev *dev)
{
int err;
- dprintk("%s: %s\n",dev->name,__FUNCTION__);
+ dprintk("%s: %s\n",dev->name,__func__);
dev->empress_dev = video_device_alloc();
if (NULL == dev->empress_dev)
return -ENOMEM;
@@ -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),
@@ -440,7 +440,7 @@ static int empress_init(struct saa7134_dev *dev)
static int empress_fini(struct saa7134_dev *dev)
{
- dprintk("%s: %s\n",dev->name,__FUNCTION__);
+ dprintk("%s: %s\n",dev->name,__func__);
if (NULL == dev->empress_dev)
return 0;
diff --git a/drivers/media/video/saa7134/saa7134-i2c.c b/drivers/media/video/saa7134/saa7134-i2c.c
index d3322c3018f..2ccfaba0c49 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");
@@ -140,6 +140,8 @@ static inline int i2c_is_busy(enum i2c_status status)
{
switch (status) {
case BUSY:
+ case TO_SCL:
+ case TO_ARB:
return true;
default:
return false;
diff --git a/drivers/media/video/saa7134/saa7134-input.c b/drivers/media/video/saa7134/saa7134-input.c
index b4188819782..767ff30832f 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)");
@@ -331,6 +331,11 @@ int saa7134_input_init1(struct saa7134_dev *dev)
break;
case SAA7134_BOARD_MANLI_MTV001:
case SAA7134_BOARD_MANLI_MTV002:
+ ir_codes = ir_codes_manli;
+ mask_keycode = 0x001f00;
+ mask_keyup = 0x004000;
+ polling = 50; /* ms */
+ break;
case SAA7134_BOARD_BEHOLD_409FM:
case SAA7134_BOARD_BEHOLD_401:
case SAA7134_BOARD_BEHOLD_403:
@@ -343,7 +348,13 @@ int saa7134_input_init1(struct saa7134_dev *dev)
case SAA7134_BOARD_BEHOLD_505FM:
case SAA7134_BOARD_BEHOLD_507_9FM:
ir_codes = ir_codes_manli;
- mask_keycode = 0x001f00;
+ mask_keycode = 0x003f00;
+ mask_keyup = 0x004000;
+ polling = 50; /* ms */
+ break;
+ case SAA7134_BOARD_BEHOLD_COLUMBUS_TVFM:
+ ir_codes = ir_codes_behold_columbus;
+ mask_keycode = 0x003f00;
mask_keyup = 0x004000;
polling = 50; // ms
break;
diff --git a/drivers/media/video/saa7134/saa7134-reg.h b/drivers/media/video/saa7134/saa7134-reg.h
index ac6431ba4fc..86f5eefdb0f 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 f1b8fcaeb43..eae72fd60ce 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 4e9810469ae..232af598d94 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 f0d5ed9c2b0..cb0304298a9 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 39c41ad97d0..a0baf2d0ba7 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 f940d025479..924ffd13637 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/saa717x.c b/drivers/media/video/saa717x.c
new file mode 100644
index 00000000000..53c5edbcf7e
--- /dev/null
+++ b/drivers/media/video/saa717x.c
@@ -0,0 +1,1516 @@
+/*
+ * saa717x - Philips SAA717xHL video decoder driver
+ *
+ * Based on the saa7115 driver
+ *
+ * Changes by Ohta Kyuma <alpha292@bremen.or.jp>
+ * - Apply to SAA717x,NEC uPD64031,uPD64083. (1/31/2004)
+ *
+ * Changes by T.Adachi (tadachi@tadachi-net.com)
+ * - support audio, video scaler etc, and checked the initialize sequence.
+ *
+ * Cleaned up by Hans Verkuil <hverkuil@xs4all.nl>
+ *
+ * Note: this is a reversed engineered driver based on captures from
+ * the I2C bus under Windows. This chip is very similar to the saa7134,
+ * though. Unfortunately, this driver is currently only working for NTSC.
+ *
+ * This 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/version.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <linux/videodev.h>
+#include <linux/videodev2.h>
+#include <linux/i2c.h>
+#include <media/v4l2-common.h>
+#include <media/v4l2-i2c-drv.h>
+
+MODULE_DESCRIPTION("Philips SAA717x audio/video decoder driver");
+MODULE_AUTHOR("K. Ohta, T. Adachi, Hans Verkuil");
+MODULE_LICENSE("GPL");
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Debug level (0-1)");
+
+/*
+ * Generic i2c probe
+ * concerning the addresses: i2c wants 7 bit (without the r/w bit), so '>>1'
+ */
+
+struct saa717x_state {
+ v4l2_std_id std;
+ int input;
+ int enable;
+ int radio;
+ int bright;
+ int contrast;
+ int hue;
+ int sat;
+ int playback;
+ int audio;
+ int tuner_audio_mode;
+ int audio_main_mute;
+ int audio_main_vol_r;
+ int audio_main_vol_l;
+ u16 audio_main_bass;
+ u16 audio_main_treble;
+ u16 audio_main_volume;
+ u16 audio_main_balance;
+ int audio_input;
+};
+
+/* ----------------------------------------------------------------------- */
+
+/* for audio mode */
+#define TUNER_AUDIO_MONO 0 /* LL */
+#define TUNER_AUDIO_STEREO 1 /* LR */
+#define TUNER_AUDIO_LANG1 2 /* LL */
+#define TUNER_AUDIO_LANG2 3 /* RR */
+
+#define SAA717X_NTSC_WIDTH (704)
+#define SAA717X_NTSC_HEIGHT (480)
+
+/* ----------------------------------------------------------------------- */
+
+static int saa717x_write(struct i2c_client *client, u32 reg, u32 value)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int fw_addr = reg == 0x454 || (reg >= 0x464 && reg <= 0x478) || reg == 0x480 || reg == 0x488;
+ unsigned char mm1[6];
+ struct i2c_msg msg;
+
+ msg.flags = 0;
+ msg.addr = client->addr;
+ mm1[0] = (reg >> 8) & 0xff;
+ mm1[1] = reg & 0xff;
+
+ if (fw_addr) {
+ mm1[4] = (value >> 16) & 0xff;
+ mm1[3] = (value >> 8) & 0xff;
+ mm1[2] = value & 0xff;
+ } else {
+ mm1[2] = value & 0xff;
+ }
+ msg.len = fw_addr ? 5 : 3; /* Long Registers have *only* three bytes! */
+ msg.buf = mm1;
+ v4l_dbg(2, debug, client, "wrote: reg 0x%03x=%08x\n", reg, value);
+ return i2c_transfer(adap, &msg, 1) == 1;
+}
+
+static void saa717x_write_regs(struct i2c_client *client, u32 *data)
+{
+ while (data[0] || data[1]) {
+ saa717x_write(client, data[0], data[1]);
+ data += 2;
+ }
+}
+
+static u32 saa717x_read(struct i2c_client *client, u32 reg)
+{
+ struct i2c_adapter *adap = client->adapter;
+ int fw_addr = (reg >= 0x404 && reg <= 0x4b8) || reg == 0x528;
+ unsigned char mm1[2];
+ unsigned char mm2[4] = { 0, 0, 0, 0 };
+ struct i2c_msg msgs[2];
+ u32 value;
+
+ msgs[0].flags = 0;
+ msgs[1].flags = I2C_M_RD;
+ msgs[0].addr = msgs[1].addr = client->addr;
+ mm1[0] = (reg >> 8) & 0xff;
+ mm1[1] = reg & 0xff;
+ msgs[0].len = 2;
+ msgs[0].buf = mm1;
+ msgs[1].len = fw_addr ? 3 : 1; /* Multibyte Registers contains *only* 3 bytes */
+ msgs[1].buf = mm2;
+ i2c_transfer(adap, msgs, 2);
+
+ if (fw_addr)
+ value = (mm2[2] & 0xff) | ((mm2[1] & 0xff) >> 8) | ((mm2[0] & 0xff) >> 16);
+ else
+ value = mm2[0] & 0xff;
+
+ v4l_dbg(2, debug, client, "read: reg 0x%03x=0x%08x\n", reg, value);
+ return value;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static u32 reg_init_initialize[] =
+{
+ /* from linux driver */
+ 0x101, 0x008, /* Increment delay */
+
+ 0x103, 0x000, /* Analog input control 2 */
+ 0x104, 0x090, /* Analog input control 3 */
+ 0x105, 0x090, /* Analog input control 4 */
+ 0x106, 0x0eb, /* Horizontal sync start */
+ 0x107, 0x0e0, /* Horizontal sync stop */
+ 0x109, 0x055, /* Luminance control */
+
+ 0x10f, 0x02a, /* Chroma gain control */
+ 0x110, 0x000, /* Chroma control 2 */
+
+ 0x114, 0x045, /* analog/ADC */
+
+ 0x118, 0x040, /* RAW data gain */
+ 0x119, 0x080, /* RAW data offset */
+
+ 0x044, 0x000, /* VBI horizontal input window start (L) TASK A */
+ 0x045, 0x000, /* VBI horizontal input window start (H) TASK A */
+ 0x046, 0x0cf, /* VBI horizontal input window stop (L) TASK A */
+ 0x047, 0x002, /* VBI horizontal input window stop (H) TASK A */
+
+ 0x049, 0x000, /* VBI vertical input window start (H) TASK A */
+
+ 0x04c, 0x0d0, /* VBI horizontal output length (L) TASK A */
+ 0x04d, 0x002, /* VBI horizontal output length (H) TASK A */
+
+ 0x064, 0x080, /* Lumina brightness TASK A */
+ 0x065, 0x040, /* Luminance contrast TASK A */
+ 0x066, 0x040, /* Chroma saturation TASK A */
+ /* 067H: Reserved */
+ 0x068, 0x000, /* VBI horizontal scaling increment (L) TASK A */
+ 0x069, 0x004, /* VBI horizontal scaling increment (H) TASK A */
+ 0x06a, 0x000, /* VBI phase offset TASK A */
+
+ 0x06e, 0x000, /* Horizontal phase offset Luma TASK A */
+ 0x06f, 0x000, /* Horizontal phase offset Chroma TASK A */
+
+ 0x072, 0x000, /* Vertical filter mode TASK A */
+
+ 0x084, 0x000, /* VBI horizontal input window start (L) TAKS B */
+ 0x085, 0x000, /* VBI horizontal input window start (H) TAKS B */
+ 0x086, 0x0cf, /* VBI horizontal input window stop (L) TAKS B */
+ 0x087, 0x002, /* VBI horizontal input window stop (H) TAKS B */
+
+ 0x089, 0x000, /* VBI vertical input window start (H) TAKS B */
+
+ 0x08c, 0x0d0, /* VBI horizontal output length (L) TASK B */
+ 0x08d, 0x002, /* VBI horizontal output length (H) TASK B */
+
+ 0x0a4, 0x080, /* Lumina brightness TASK B */
+ 0x0a5, 0x040, /* Luminance contrast TASK B */
+ 0x0a6, 0x040, /* Chroma saturation TASK B */
+ /* 0A7H reserved */
+ 0x0a8, 0x000, /* VBI horizontal scaling increment (L) TASK B */
+ 0x0a9, 0x004, /* VBI horizontal scaling increment (H) TASK B */
+ 0x0aa, 0x000, /* VBI phase offset TASK B */
+
+ 0x0ae, 0x000, /* Horizontal phase offset Luma TASK B */
+ 0x0af, 0x000, /*Horizontal phase offset Chroma TASK B */
+
+ 0x0b2, 0x000, /* Vertical filter mode TASK B */
+
+ 0x00c, 0x000, /* Start point GREEN path */
+ 0x00d, 0x000, /* Start point BLUE path */
+ 0x00e, 0x000, /* Start point RED path */
+
+ 0x010, 0x010, /* GREEN path gamma curve --- */
+ 0x011, 0x020,
+ 0x012, 0x030,
+ 0x013, 0x040,
+ 0x014, 0x050,
+ 0x015, 0x060,
+ 0x016, 0x070,
+ 0x017, 0x080,
+ 0x018, 0x090,
+ 0x019, 0x0a0,
+ 0x01a, 0x0b0,
+ 0x01b, 0x0c0,
+ 0x01c, 0x0d0,
+ 0x01d, 0x0e0,
+ 0x01e, 0x0f0,
+ 0x01f, 0x0ff, /* --- GREEN path gamma curve */
+
+ 0x020, 0x010, /* BLUE path gamma curve --- */
+ 0x021, 0x020,
+ 0x022, 0x030,
+ 0x023, 0x040,
+ 0x024, 0x050,
+ 0x025, 0x060,
+ 0x026, 0x070,
+ 0x027, 0x080,
+ 0x028, 0x090,
+ 0x029, 0x0a0,
+ 0x02a, 0x0b0,
+ 0x02b, 0x0c0,
+ 0x02c, 0x0d0,
+ 0x02d, 0x0e0,
+ 0x02e, 0x0f0,
+ 0x02f, 0x0ff, /* --- BLUE path gamma curve */
+
+ 0x030, 0x010, /* RED path gamma curve --- */
+ 0x031, 0x020,
+ 0x032, 0x030,
+ 0x033, 0x040,
+ 0x034, 0x050,
+ 0x035, 0x060,
+ 0x036, 0x070,
+ 0x037, 0x080,
+ 0x038, 0x090,
+ 0x039, 0x0a0,
+ 0x03a, 0x0b0,
+ 0x03b, 0x0c0,
+ 0x03c, 0x0d0,
+ 0x03d, 0x0e0,
+ 0x03e, 0x0f0,
+ 0x03f, 0x0ff, /* --- RED path gamma curve */
+
+ 0x109, 0x085, /* Luminance control */
+
+ /**** from app start ****/
+ 0x584, 0x000, /* AGC gain control */
+ 0x585, 0x000, /* Program count */
+ 0x586, 0x003, /* Status reset */
+ 0x588, 0x0ff, /* Number of audio samples (L) */
+ 0x589, 0x00f, /* Number of audio samples (M) */
+ 0x58a, 0x000, /* Number of audio samples (H) */
+ 0x58b, 0x000, /* Audio select */
+ 0x58c, 0x010, /* Audio channel assign1 */
+ 0x58d, 0x032, /* Audio channel assign2 */
+ 0x58e, 0x054, /* Audio channel assign3 */
+ 0x58f, 0x023, /* Audio format */
+ 0x590, 0x000, /* SIF control */
+
+ 0x595, 0x000, /* ?? */
+ 0x596, 0x000, /* ?? */
+ 0x597, 0x000, /* ?? */
+
+ 0x464, 0x00, /* Digital input crossbar1 */
+
+ 0x46c, 0xbbbb10, /* Digital output selection1-3 */
+ 0x470, 0x101010, /* Digital output selection4-6 */
+
+ 0x478, 0x00, /* Sound feature control */
+
+ 0x474, 0x18, /* Softmute control */
+
+ 0x454, 0x0425b9, /* Sound Easy programming(reset) */
+ 0x454, 0x042539, /* Sound Easy programming(reset) */
+
+
+ /**** common setting( of DVD play, including scaler commands) ****/
+ 0x042, 0x003, /* Data path configuration for VBI (TASK A) */
+
+ 0x082, 0x003, /* Data path configuration for VBI (TASK B) */
+
+ 0x108, 0x0f8, /* Sync control */
+ 0x2a9, 0x0fd, /* ??? */
+ 0x102, 0x089, /* select video input "mode 9" */
+ 0x111, 0x000, /* Mode/delay control */
+
+ 0x10e, 0x00a, /* Chroma control 1 */
+
+ 0x594, 0x002, /* SIF, analog I/O select */
+
+ 0x454, 0x0425b9, /* Sound */
+ 0x454, 0x042539,
+
+ 0x111, 0x000,
+ 0x10e, 0x00a,
+ 0x464, 0x000,
+ 0x300, 0x000,
+ 0x301, 0x006,
+ 0x302, 0x000,
+ 0x303, 0x006,
+ 0x308, 0x040,
+ 0x309, 0x000,
+ 0x30a, 0x000,
+ 0x30b, 0x000,
+ 0x000, 0x002,
+ 0x001, 0x000,
+ 0x002, 0x000,
+ 0x003, 0x000,
+ 0x004, 0x033,
+ 0x040, 0x01d,
+ 0x041, 0x001,
+ 0x042, 0x004,
+ 0x043, 0x000,
+ 0x080, 0x01e,
+ 0x081, 0x001,
+ 0x082, 0x004,
+ 0x083, 0x000,
+ 0x190, 0x018,
+ 0x115, 0x000,
+ 0x116, 0x012,
+ 0x117, 0x018,
+ 0x04a, 0x011,
+ 0x08a, 0x011,
+ 0x04b, 0x000,
+ 0x08b, 0x000,
+ 0x048, 0x000,
+ 0x088, 0x000,
+ 0x04e, 0x012,
+ 0x08e, 0x012,
+ 0x058, 0x012,
+ 0x098, 0x012,
+ 0x059, 0x000,
+ 0x099, 0x000,
+ 0x05a, 0x003,
+ 0x09a, 0x003,
+ 0x05b, 0x001,
+ 0x09b, 0x001,
+ 0x054, 0x008,
+ 0x094, 0x008,
+ 0x055, 0x000,
+ 0x095, 0x000,
+ 0x056, 0x0c7,
+ 0x096, 0x0c7,
+ 0x057, 0x002,
+ 0x097, 0x002,
+ 0x0ff, 0x0ff,
+ 0x060, 0x001,
+ 0x0a0, 0x001,
+ 0x061, 0x000,
+ 0x0a1, 0x000,
+ 0x062, 0x000,
+ 0x0a2, 0x000,
+ 0x063, 0x000,
+ 0x0a3, 0x000,
+ 0x070, 0x000,
+ 0x0b0, 0x000,
+ 0x071, 0x004,
+ 0x0b1, 0x004,
+ 0x06c, 0x0e9,
+ 0x0ac, 0x0e9,
+ 0x06d, 0x003,
+ 0x0ad, 0x003,
+ 0x05c, 0x0d0,
+ 0x09c, 0x0d0,
+ 0x05d, 0x002,
+ 0x09d, 0x002,
+ 0x05e, 0x0f2,
+ 0x09e, 0x0f2,
+ 0x05f, 0x000,
+ 0x09f, 0x000,
+ 0x074, 0x000,
+ 0x0b4, 0x000,
+ 0x075, 0x000,
+ 0x0b5, 0x000,
+ 0x076, 0x000,
+ 0x0b6, 0x000,
+ 0x077, 0x000,
+ 0x0b7, 0x000,
+ 0x195, 0x008,
+ 0x0ff, 0x0ff,
+ 0x108, 0x0f8,
+ 0x111, 0x000,
+ 0x10e, 0x00a,
+ 0x2a9, 0x0fd,
+ 0x464, 0x001,
+ 0x454, 0x042135,
+ 0x598, 0x0e7,
+ 0x599, 0x07d,
+ 0x59a, 0x018,
+ 0x59c, 0x066,
+ 0x59d, 0x090,
+ 0x59e, 0x001,
+ 0x584, 0x000,
+ 0x585, 0x000,
+ 0x586, 0x003,
+ 0x588, 0x0ff,
+ 0x589, 0x00f,
+ 0x58a, 0x000,
+ 0x58b, 0x000,
+ 0x58c, 0x010,
+ 0x58d, 0x032,
+ 0x58e, 0x054,
+ 0x58f, 0x023,
+ 0x590, 0x000,
+ 0x595, 0x000,
+ 0x596, 0x000,
+ 0x597, 0x000,
+ 0x464, 0x000,
+ 0x46c, 0xbbbb10,
+ 0x470, 0x101010,
+
+
+ 0x478, 0x000,
+ 0x474, 0x018,
+ 0x454, 0x042135,
+ 0x598, 0x0e7,
+ 0x599, 0x07d,
+ 0x59a, 0x018,
+ 0x59c, 0x066,
+ 0x59d, 0x090,
+ 0x59e, 0x001,
+ 0x584, 0x000,
+ 0x585, 0x000,
+ 0x586, 0x003,
+ 0x588, 0x0ff,
+ 0x589, 0x00f,
+ 0x58a, 0x000,
+ 0x58b, 0x000,
+ 0x58c, 0x010,
+ 0x58d, 0x032,
+ 0x58e, 0x054,
+ 0x58f, 0x023,
+ 0x590, 0x000,
+ 0x595, 0x000,
+ 0x596, 0x000,
+ 0x597, 0x000,
+ 0x464, 0x000,
+ 0x46c, 0xbbbb10,
+ 0x470, 0x101010,
+
+ 0x478, 0x000,
+ 0x474, 0x018,
+ 0x454, 0x042135,
+ 0x598, 0x0e7,
+ 0x599, 0x07d,
+ 0x59a, 0x018,
+ 0x59c, 0x066,
+ 0x59d, 0x090,
+ 0x59e, 0x001,
+ 0x584, 0x000,
+ 0x585, 0x000,
+ 0x586, 0x003,
+ 0x588, 0x0ff,
+ 0x589, 0x00f,
+ 0x58a, 0x000,
+ 0x58b, 0x000,
+ 0x58c, 0x010,
+ 0x58d, 0x032,
+ 0x58e, 0x054,
+ 0x58f, 0x023,
+ 0x590, 0x000,
+ 0x595, 0x000,
+ 0x596, 0x000,
+ 0x597, 0x000,
+ 0x464, 0x000,
+ 0x46c, 0xbbbb10,
+ 0x470, 0x101010,
+ 0x478, 0x000,
+ 0x474, 0x018,
+ 0x454, 0x042135,
+ 0x193, 0x000,
+ 0x300, 0x000,
+ 0x301, 0x006,
+ 0x302, 0x000,
+ 0x303, 0x006,
+ 0x308, 0x040,
+ 0x309, 0x000,
+ 0x30a, 0x000,
+ 0x30b, 0x000,
+ 0x000, 0x002,
+ 0x001, 0x000,
+ 0x002, 0x000,
+ 0x003, 0x000,
+ 0x004, 0x033,
+ 0x040, 0x01d,
+ 0x041, 0x001,
+ 0x042, 0x004,
+ 0x043, 0x000,
+ 0x080, 0x01e,
+ 0x081, 0x001,
+ 0x082, 0x004,
+ 0x083, 0x000,
+ 0x190, 0x018,
+ 0x115, 0x000,
+ 0x116, 0x012,
+ 0x117, 0x018,
+ 0x04a, 0x011,
+ 0x08a, 0x011,
+ 0x04b, 0x000,
+ 0x08b, 0x000,
+ 0x048, 0x000,
+ 0x088, 0x000,
+ 0x04e, 0x012,
+ 0x08e, 0x012,
+ 0x058, 0x012,
+ 0x098, 0x012,
+ 0x059, 0x000,
+ 0x099, 0x000,
+ 0x05a, 0x003,
+ 0x09a, 0x003,
+ 0x05b, 0x001,
+ 0x09b, 0x001,
+ 0x054, 0x008,
+ 0x094, 0x008,
+ 0x055, 0x000,
+ 0x095, 0x000,
+ 0x056, 0x0c7,
+ 0x096, 0x0c7,
+ 0x057, 0x002,
+ 0x097, 0x002,
+ 0x060, 0x001,
+ 0x0a0, 0x001,
+ 0x061, 0x000,
+ 0x0a1, 0x000,
+ 0x062, 0x000,
+ 0x0a2, 0x000,
+ 0x063, 0x000,
+ 0x0a3, 0x000,
+ 0x070, 0x000,
+ 0x0b0, 0x000,
+ 0x071, 0x004,
+ 0x0b1, 0x004,
+ 0x06c, 0x0e9,
+ 0x0ac, 0x0e9,
+ 0x06d, 0x003,
+ 0x0ad, 0x003,
+ 0x05c, 0x0d0,
+ 0x09c, 0x0d0,
+ 0x05d, 0x002,
+ 0x09d, 0x002,
+ 0x05e, 0x0f2,
+ 0x09e, 0x0f2,
+ 0x05f, 0x000,
+ 0x09f, 0x000,
+ 0x074, 0x000,
+ 0x0b4, 0x000,
+ 0x075, 0x000,
+ 0x0b5, 0x000,
+ 0x076, 0x000,
+ 0x0b6, 0x000,
+ 0x077, 0x000,
+ 0x0b7, 0x000,
+ 0x195, 0x008,
+ 0x598, 0x0e7,
+ 0x599, 0x07d,
+ 0x59a, 0x018,
+ 0x59c, 0x066,
+ 0x59d, 0x090,
+ 0x59e, 0x001,
+ 0x584, 0x000,
+ 0x585, 0x000,
+ 0x586, 0x003,
+ 0x588, 0x0ff,
+ 0x589, 0x00f,
+ 0x58a, 0x000,
+ 0x58b, 0x000,
+ 0x58c, 0x010,
+ 0x58d, 0x032,
+ 0x58e, 0x054,
+ 0x58f, 0x023,
+ 0x590, 0x000,
+ 0x595, 0x000,
+ 0x596, 0x000,
+ 0x597, 0x000,
+ 0x464, 0x000,
+ 0x46c, 0xbbbb10,
+ 0x470, 0x101010,
+ 0x478, 0x000,
+ 0x474, 0x018,
+ 0x454, 0x042135,
+ 0x193, 0x0a6,
+ 0x108, 0x0f8,
+ 0x042, 0x003,
+ 0x082, 0x003,
+ 0x454, 0x0425b9,
+ 0x454, 0x042539,
+ 0x193, 0x000,
+ 0x193, 0x0a6,
+ 0x464, 0x000,
+
+ 0, 0
+};
+
+/* Tuner */
+static u32 reg_init_tuner_input[] = {
+ 0x108, 0x0f8, /* Sync control */
+ 0x111, 0x000, /* Mode/delay control */
+ 0x10e, 0x00a, /* Chroma control 1 */
+ 0, 0
+};
+
+/* Composite */
+static u32 reg_init_composite_input[] = {
+ 0x108, 0x0e8, /* Sync control */
+ 0x111, 0x000, /* Mode/delay control */
+ 0x10e, 0x04a, /* Chroma control 1 */
+ 0, 0
+};
+
+/* S-Video */
+static u32 reg_init_svideo_input[] = {
+ 0x108, 0x0e8, /* Sync control */
+ 0x111, 0x000, /* Mode/delay control */
+ 0x10e, 0x04a, /* Chroma control 1 */
+ 0, 0
+};
+
+static u32 reg_set_audio_template[4][2] =
+{
+ { /* for MONO
+ tadachi 6/29 DMA audio output select?
+ Register 0x46c
+ 7-4: DMA2, 3-0: DMA1 ch. DMA4, DMA3 DMA2, DMA1
+ 0: MAIN left, 1: MAIN right
+ 2: AUX1 left, 3: AUX1 right
+ 4: AUX2 left, 5: AUX2 right
+ 6: DPL left, 7: DPL right
+ 8: DPL center, 9: DPL surround
+ A: monitor output, B: digital sense */
+ 0xbbbb00,
+
+ /* tadachi 6/29 DAC and I2S output select?
+ Register 0x470
+ 7-4:DAC right ch. 3-0:DAC left ch.
+ I2S1 right,left I2S2 right,left */
+ 0x00,
+ },
+ { /* for STEREO */
+ 0xbbbb10, 0x101010,
+ },
+ { /* for LANG1 */
+ 0xbbbb00, 0x00,
+ },
+ { /* for LANG2/SAP */
+ 0xbbbb11, 0x111111,
+ }
+};
+
+
+/* Get detected audio flags (from saa7134 driver) */
+static void get_inf_dev_status(struct i2c_client *client,
+ int *dual_flag, int *stereo_flag)
+{
+ u32 reg_data3;
+
+ static char *stdres[0x20] = {
+ [0x00] = "no standard detected",
+ [0x01] = "B/G (in progress)",
+ [0x02] = "D/K (in progress)",
+ [0x03] = "M (in progress)",
+
+ [0x04] = "B/G A2",
+ [0x05] = "B/G NICAM",
+ [0x06] = "D/K A2 (1)",
+ [0x07] = "D/K A2 (2)",
+ [0x08] = "D/K A2 (3)",
+ [0x09] = "D/K NICAM",
+ [0x0a] = "L NICAM",
+ [0x0b] = "I NICAM",
+
+ [0x0c] = "M Korea",
+ [0x0d] = "M BTSC ",
+ [0x0e] = "M EIAJ",
+
+ [0x0f] = "FM radio / IF 10.7 / 50 deemp",
+ [0x10] = "FM radio / IF 10.7 / 75 deemp",
+ [0x11] = "FM radio / IF sel / 50 deemp",
+ [0x12] = "FM radio / IF sel / 75 deemp",
+
+ [0x13 ... 0x1e] = "unknown",
+ [0x1f] = "??? [in progress]",
+ };
+
+
+ *dual_flag = *stereo_flag = 0;
+
+ /* (demdec status: 0x528) */
+
+ /* read current status */
+ reg_data3 = saa717x_read(client, 0x0528);
+
+ v4l_dbg(1, debug, client, "tvaudio thread status: 0x%x [%s%s%s]\n",
+ reg_data3, stdres[reg_data3 & 0x1f],
+ (reg_data3 & 0x000020) ? ",stereo" : "",
+ (reg_data3 & 0x000040) ? ",dual" : "");
+ v4l_dbg(1, debug, client, "detailed status: "
+ "%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s#%s\n",
+ (reg_data3 & 0x000080) ? " A2/EIAJ pilot tone " : "",
+ (reg_data3 & 0x000100) ? " A2/EIAJ dual " : "",
+ (reg_data3 & 0x000200) ? " A2/EIAJ stereo " : "",
+ (reg_data3 & 0x000400) ? " A2/EIAJ noise mute " : "",
+
+ (reg_data3 & 0x000800) ? " BTSC/FM radio pilot " : "",
+ (reg_data3 & 0x001000) ? " SAP carrier " : "",
+ (reg_data3 & 0x002000) ? " BTSC stereo noise mute " : "",
+ (reg_data3 & 0x004000) ? " SAP noise mute " : "",
+ (reg_data3 & 0x008000) ? " VDSP " : "",
+
+ (reg_data3 & 0x010000) ? " NICST " : "",
+ (reg_data3 & 0x020000) ? " NICDU " : "",
+ (reg_data3 & 0x040000) ? " NICAM muted " : "",
+ (reg_data3 & 0x080000) ? " NICAM reserve sound " : "",
+
+ (reg_data3 & 0x100000) ? " init done " : "");
+
+ if (reg_data3 & 0x000220) {
+ v4l_dbg(1, debug, client, "ST!!!\n");
+ *stereo_flag = 1;
+ }
+
+ if (reg_data3 & 0x000140) {
+ v4l_dbg(1, debug, client, "DUAL!!!\n");
+ *dual_flag = 1;
+ }
+}
+
+/* regs write to set audio mode */
+static void set_audio_mode(struct i2c_client *client, int audio_mode)
+{
+ v4l_dbg(1, debug, client, "writing registers to set audio mode by set %d\n",
+ audio_mode);
+
+ saa717x_write(client, 0x46c, reg_set_audio_template[audio_mode][0]);
+ saa717x_write(client, 0x470, reg_set_audio_template[audio_mode][1]);
+}
+
+/* write regs to video output level (bright,contrast,hue,sat) */
+static void set_video_output_level_regs(struct i2c_client *client,
+ struct saa717x_state *decoder)
+{
+ /* brightness ffh (bright) - 80h (ITU level) - 00h (dark) */
+ saa717x_write(client, 0x10a, decoder->bright);
+
+ /* contrast 7fh (max: 1.984) - 44h (ITU) - 40h (1.0) -
+ 0h (luminance off) 40: i2c dump
+ c0h (-1.0 inverse chrominance)
+ 80h (-2.0 inverse chrominance) */
+ saa717x_write(client, 0x10b, decoder->contrast);
+
+ /* saturation? 7fh(max)-40h(ITU)-0h(color off)
+ c0h (-1.0 inverse chrominance)
+ 80h (-2.0 inverse chrominance) */
+ saa717x_write(client, 0x10c, decoder->sat);
+
+ /* color hue (phase) control
+ 7fh (+178.6) - 0h (0 normal) - 80h (-180.0) */
+ saa717x_write(client, 0x10d, decoder->hue);
+}
+
+/* write regs to set audio volume, bass and treble */
+static int set_audio_regs(struct i2c_client *client,
+ struct saa717x_state *decoder)
+{
+ u8 mute = 0xac; /* -84 dB */
+ u32 val;
+ unsigned int work_l, work_r;
+
+ /* set SIF analog I/O select */
+ saa717x_write(client, 0x0594, decoder->audio_input);
+ v4l_dbg(1, debug, client, "set audio input %d\n",
+ decoder->audio_input);
+
+ /* normalize ( 65535 to 0 -> 24 to -40 (not -84)) */
+ work_l = (min(65536 - decoder->audio_main_balance, 32768) * decoder->audio_main_volume) / 32768;
+ work_r = (min(decoder->audio_main_balance, (u16)32768) * decoder->audio_main_volume) / 32768;
+ decoder->audio_main_vol_l = (long)work_l * (24 - (-40)) / 65535 - 40;
+ decoder->audio_main_vol_r = (long)work_r * (24 - (-40)) / 65535 - 40;
+
+ /* set main volume */
+ /* main volume L[7-0],R[7-0],0x00 24=24dB,-83dB, -84(mute) */
+ /* def:0dB->6dB(MPG600GR) */
+ /* if mute is on, set mute */
+ if (decoder->audio_main_mute) {
+ val = mute | (mute << 8);
+ } else {
+ val = (u8)decoder->audio_main_vol_l |
+ ((u8)decoder->audio_main_vol_r << 8);
+ }
+
+ saa717x_write(client, 0x480, val);
+
+ /* bass and treble; go to another function */
+ /* set bass and treble */
+ val = decoder->audio_main_bass | (decoder->audio_main_treble << 8);
+ saa717x_write(client, 0x488, val);
+ return 0;
+}
+
+/********** scaling staff ***********/
+static void set_h_prescale(struct i2c_client *client,
+ int task, int prescale)
+{
+ static const struct {
+ int xpsc;
+ int xacl;
+ int xc2_1;
+ int xdcg;
+ int vpfy;
+ } vals[] = {
+ /* XPSC XACL XC2_1 XDCG VPFY */
+ { 1, 0, 0, 0, 0 },
+ { 2, 2, 1, 2, 2 },
+ { 3, 4, 1, 3, 2 },
+ { 4, 8, 1, 4, 2 },
+ { 5, 8, 1, 4, 2 },
+ { 6, 8, 1, 4, 3 },
+ { 7, 8, 1, 4, 3 },
+ { 8, 15, 0, 4, 3 },
+ { 9, 15, 0, 4, 3 },
+ { 10, 16, 1, 5, 3 },
+ };
+ static const int count = ARRAY_SIZE(vals);
+ int i, task_shift;
+
+ task_shift = task * 0x40;
+ for (i = 0; i < count; i++)
+ if (vals[i].xpsc == prescale)
+ break;
+ if (i == count)
+ return;
+
+ /* horizonal prescaling */
+ saa717x_write(client, 0x60 + task_shift, vals[i].xpsc);
+ /* accumulation length */
+ saa717x_write(client, 0x61 + task_shift, vals[i].xacl);
+ /* level control */
+ saa717x_write(client, 0x62 + task_shift,
+ (vals[i].xc2_1 << 3) | vals[i].xdcg);
+ /*FIR prefilter control */
+ saa717x_write(client, 0x63 + task_shift,
+ (vals[i].vpfy << 2) | vals[i].vpfy);
+}
+
+/********** scaling staff ***********/
+static void set_v_scale(struct i2c_client *client, int task, int yscale)
+{
+ int task_shift;
+
+ task_shift = task * 0x40;
+ /* Vertical scaling ratio (LOW) */
+ saa717x_write(client, 0x70 + task_shift, yscale & 0xff);
+ /* Vertical scaling ratio (HI) */
+ saa717x_write(client, 0x71 + task_shift, yscale >> 8);
+}
+
+static int saa717x_set_audio_clock_freq(struct i2c_client *client, u32 freq)
+{
+ /* not yet implament, so saa717x_cfg_??hz_??_audio is not defined. */
+ return 0;
+}
+
+static int saa717x_set_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct saa717x_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ if (ctrl->value < 0 || ctrl->value > 255) {
+ v4l_err(client, "invalid brightness setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->bright = ctrl->value;
+ v4l_dbg(1, debug, client, "bright:%d\n", state->bright);
+ saa717x_write(client, 0x10a, state->bright);
+ break;
+
+ case V4L2_CID_CONTRAST:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ v4l_err(client, "invalid contrast setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->contrast = ctrl->value;
+ v4l_dbg(1, debug, client, "contrast:%d\n", state->contrast);
+ saa717x_write(client, 0x10b, state->contrast);
+ break;
+
+ case V4L2_CID_SATURATION:
+ if (ctrl->value < 0 || ctrl->value > 127) {
+ v4l_err(client, "invalid saturation setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->sat = ctrl->value;
+ v4l_dbg(1, debug, client, "sat:%d\n", state->sat);
+ saa717x_write(client, 0x10c, state->sat);
+ break;
+
+ case V4L2_CID_HUE:
+ if (ctrl->value < -127 || ctrl->value > 127) {
+ v4l_err(client, "invalid hue setting %d\n", ctrl->value);
+ return -ERANGE;
+ }
+
+ state->hue = ctrl->value;
+ v4l_dbg(1, debug, client, "hue:%d\n", state->hue);
+ saa717x_write(client, 0x10d, state->hue);
+ break;
+
+ case V4L2_CID_AUDIO_MUTE:
+ state->audio_main_mute = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ state->audio_main_volume = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ state->audio_main_balance = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ case V4L2_CID_AUDIO_TREBLE:
+ state->audio_main_treble = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ case V4L2_CID_AUDIO_BASS:
+ state->audio_main_bass = ctrl->value;
+ set_audio_regs(client, state);
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static int saa717x_get_v4lctrl(struct i2c_client *client, struct v4l2_control *ctrl)
+{
+ struct saa717x_state *state = i2c_get_clientdata(client);
+
+ switch (ctrl->id) {
+ case V4L2_CID_BRIGHTNESS:
+ ctrl->value = state->bright;
+ break;
+
+ case V4L2_CID_CONTRAST:
+ ctrl->value = state->contrast;
+ break;
+
+ case V4L2_CID_SATURATION:
+ ctrl->value = state->sat;
+ break;
+
+ case V4L2_CID_HUE:
+ ctrl->value = state->hue;
+ break;
+
+ case V4L2_CID_AUDIO_MUTE:
+ ctrl->value = state->audio_main_mute;
+ break;
+
+ case V4L2_CID_AUDIO_VOLUME:
+ ctrl->value = state->audio_main_volume;
+ break;
+
+ case V4L2_CID_AUDIO_BALANCE:
+ ctrl->value = state->audio_main_balance;
+ break;
+
+ case V4L2_CID_AUDIO_TREBLE:
+ ctrl->value = state->audio_main_treble;
+ break;
+
+ case V4L2_CID_AUDIO_BASS:
+ ctrl->value = state->audio_main_bass;
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+static struct v4l2_queryctrl saa717x_qctrl[] = {
+ {
+ .id = V4L2_CID_BRIGHTNESS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Brightness",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 128,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_CONTRAST,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Contrast",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_SATURATION,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Saturation",
+ .minimum = 0,
+ .maximum = 255,
+ .step = 1,
+ .default_value = 64,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_HUE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Hue",
+ .minimum = -128,
+ .maximum = 127,
+ .step = 1,
+ .default_value = 0,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_VOLUME,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Volume",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 58880,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_BALANCE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Balance",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 32768,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_MUTE,
+ .type = V4L2_CTRL_TYPE_BOOLEAN,
+ .name = "Mute",
+ .minimum = 0,
+ .maximum = 1,
+ .step = 1,
+ .default_value = 1,
+ .flags = 0,
+ }, {
+ .id = V4L2_CID_AUDIO_BASS,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Bass",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 32768,
+ }, {
+ .id = V4L2_CID_AUDIO_TREBLE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "Treble",
+ .minimum = 0,
+ .maximum = 65535,
+ .step = 65535 / 100,
+ .default_value = 32768,
+ },
+};
+
+static int saa717x_set_video_input(struct i2c_client *client, struct saa717x_state *decoder, int inp)
+{
+ int is_tuner = inp & 0x80; /* tuner input flag */
+
+ inp &= 0x7f;
+
+ v4l_dbg(1, debug, client, "decoder set input (%d)\n", inp);
+ /* inputs from 0-9 are available*/
+ /* saa717x have mode0-mode9 but mode5 is reserved. */
+ if (inp < 0 || inp > 9 || inp == 5)
+ return -EINVAL;
+
+ if (decoder->input != inp) {
+ int input_line = inp;
+
+ decoder->input = input_line;
+ v4l_dbg(1, debug, client, "now setting %s input %d\n",
+ input_line >= 6 ? "S-Video" : "Composite",
+ input_line);
+
+ /* select mode */
+ saa717x_write(client, 0x102,
+ (saa717x_read(client, 0x102) & 0xf0) |
+ input_line);
+
+ /* bypass chrominance trap for modes 6..9 */
+ saa717x_write(client, 0x109,
+ (saa717x_read(client, 0x109) & 0x7f) |
+ (input_line < 6 ? 0x0 : 0x80));
+
+ /* change audio_mode */
+ if (is_tuner) {
+ /* tuner */
+ set_audio_mode(client, decoder->tuner_audio_mode);
+ } else {
+ /* Force to STEREO mode if Composite or
+ * S-Video were chosen */
+ set_audio_mode(client, TUNER_AUDIO_STEREO);
+ }
+ /* change initialize procedure (Composite/S-Video) */
+ if (is_tuner)
+ saa717x_write_regs(client, reg_init_tuner_input);
+ else if (input_line >= 6)
+ saa717x_write_regs(client, reg_init_svideo_input);
+ else
+ saa717x_write_regs(client, reg_init_composite_input);
+ }
+
+ return 0;
+}
+
+static int saa717x_command(struct i2c_client *client, unsigned cmd, void *arg)
+{
+ struct saa717x_state *decoder = i2c_get_clientdata(client);
+
+ v4l_dbg(1, debug, client, "IOCTL: %08x\n", cmd);
+
+ switch (cmd) {
+ case VIDIOC_INT_AUDIO_CLOCK_FREQ:
+ return saa717x_set_audio_clock_freq(client, *(u32 *)arg);
+
+ case VIDIOC_G_CTRL:
+ return saa717x_get_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_S_CTRL:
+ return saa717x_set_v4lctrl(client, (struct v4l2_control *)arg);
+
+ case VIDIOC_QUERYCTRL: {
+ struct v4l2_queryctrl *qc = arg;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(saa717x_qctrl); i++)
+ if (qc->id && qc->id == saa717x_qctrl[i].id) {
+ memcpy(qc, &saa717x_qctrl[i], sizeof(*qc));
+ return 0;
+ }
+ return -EINVAL;
+ }
+
+#ifdef CONFIG_VIDEO_ADV_DEBUG
+ case VIDIOC_DBG_G_REGISTER: {
+ struct v4l2_register *reg = arg;
+
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ reg->val = saa717x_read(client, reg->reg);
+ break;
+ }
+
+ case VIDIOC_DBG_S_REGISTER: {
+ struct v4l2_register *reg = arg;
+ u16 addr = reg->reg & 0xffff;
+ u8 val = reg->val & 0xff;
+
+ if (!v4l2_chip_match_i2c_client(client, reg->match_type, reg->match_chip))
+ return -EINVAL;
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+ saa717x_write(client, addr, val);
+ break;
+ }
+#endif
+
+ case VIDIOC_S_FMT: {
+ struct v4l2_format *fmt = (struct v4l2_format *)arg;
+ struct v4l2_pix_format *pix;
+ int prescale, h_scale, v_scale;
+
+ pix = &fmt->fmt.pix;
+ v4l_dbg(1, debug, client, "decoder set size\n");
+
+ /* FIXME need better bounds checking here */
+ if (pix->width < 1 || pix->width > 1440)
+ return -EINVAL;
+ if (pix->height < 1 || pix->height > 960)
+ return -EINVAL;
+
+ /* scaling setting */
+ /* NTSC and interlace only */
+ prescale = SAA717X_NTSC_WIDTH / pix->width;
+ if (prescale == 0)
+ prescale = 1;
+ h_scale = 1024 * SAA717X_NTSC_WIDTH / prescale / pix->width;
+ /* interlace */
+ v_scale = 512 * 2 * SAA717X_NTSC_HEIGHT / pix->height;
+
+ /* Horizontal prescaling etc */
+ set_h_prescale(client, 0, prescale);
+ set_h_prescale(client, 1, prescale);
+
+ /* Horizontal scaling increment */
+ /* TASK A */
+ saa717x_write(client, 0x6C, (u8)(h_scale & 0xFF));
+ saa717x_write(client, 0x6D, (u8)((h_scale >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(client, 0xAC, (u8)(h_scale & 0xFF));
+ saa717x_write(client, 0xAD, (u8)((h_scale >> 8) & 0xFF));
+
+ /* Vertical prescaling etc */
+ set_v_scale(client, 0, v_scale);
+ set_v_scale(client, 1, v_scale);
+
+ /* set video output size */
+ /* video number of pixels at output */
+ /* TASK A */
+ saa717x_write(client, 0x5C, (u8)(pix->width & 0xFF));
+ saa717x_write(client, 0x5D, (u8)((pix->width >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(client, 0x9C, (u8)(pix->width & 0xFF));
+ saa717x_write(client, 0x9D, (u8)((pix->width >> 8) & 0xFF));
+
+ /* video number of lines at output */
+ /* TASK A */
+ saa717x_write(client, 0x5E, (u8)(pix->height & 0xFF));
+ saa717x_write(client, 0x5F, (u8)((pix->height >> 8) & 0xFF));
+ /* TASK B */
+ saa717x_write(client, 0x9E, (u8)(pix->height & 0xFF));
+ saa717x_write(client, 0x9F, (u8)((pix->height >> 8) & 0xFF));
+ break;
+ }
+
+ case AUDC_SET_RADIO:
+ decoder->radio = 1;
+ break;
+
+ case VIDIOC_S_STD: {
+ v4l2_std_id std = *(v4l2_std_id *) arg;
+
+ v4l_dbg(1, debug, client, "decoder set norm ");
+ v4l_dbg(1, debug, client, "(not yet implementd)\n");
+
+ decoder->radio = 0;
+ decoder->std = std;
+ break;
+ }
+
+ case VIDIOC_INT_G_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
+
+ route->input = decoder->audio_input;
+ route->output = 0;
+ break;
+ }
+
+ case VIDIOC_INT_S_AUDIO_ROUTING: {
+ struct v4l2_routing *route = arg;
+
+ if (route->input < 3) { /* FIXME! --tadachi */
+ decoder->audio_input = route->input;
+ v4l_dbg(1, debug, client,
+ "set decoder audio input to %d\n",
+ decoder->audio_input);
+ set_audio_regs(client, decoder);
+ break;
+ }
+ return -ERANGE;
+ }
+
+ case VIDIOC_INT_S_VIDEO_ROUTING: {
+ struct v4l2_routing *route = arg;
+ int inp = route->input;
+
+ return saa717x_set_video_input(client, decoder, inp);
+ }
+
+ case VIDIOC_STREAMON: {
+ v4l_dbg(1, debug, client, "decoder enable output\n");
+ decoder->enable = 1;
+ saa717x_write(client, 0x193, 0xa6);
+ break;
+ }
+
+ case VIDIOC_STREAMOFF: {
+ v4l_dbg(1, debug, client, "decoder disable output\n");
+ decoder->enable = 0;
+ saa717x_write(client, 0x193, 0x26); /* right? FIXME!--tadachi */
+ break;
+ }
+
+ /* change audio mode */
+ case VIDIOC_S_TUNER: {
+ struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+ int audio_mode;
+ char *mes[4] = {
+ "MONO", "STEREO", "LANG1", "LANG2/SAP"
+ };
+
+ audio_mode = V4L2_TUNER_MODE_STEREO;
+
+ switch (vt->audmode) {
+ case V4L2_TUNER_MODE_MONO:
+ audio_mode = TUNER_AUDIO_MONO;
+ break;
+ case V4L2_TUNER_MODE_STEREO:
+ audio_mode = TUNER_AUDIO_STEREO;
+ break;
+ case V4L2_TUNER_MODE_LANG2:
+ audio_mode = TUNER_AUDIO_LANG2;
+ break;
+ case V4L2_TUNER_MODE_LANG1:
+ audio_mode = TUNER_AUDIO_LANG1;
+ break;
+ }
+
+ v4l_dbg(1, debug, client, "change audio mode to %s\n",
+ mes[audio_mode]);
+ decoder->tuner_audio_mode = audio_mode;
+ /* The registers are not changed here. */
+ /* See DECODER_ENABLE_OUTPUT section. */
+ set_audio_mode(client, decoder->tuner_audio_mode);
+ break;
+ }
+
+ case VIDIOC_G_TUNER: {
+ struct v4l2_tuner *vt = (struct v4l2_tuner *)arg;
+ int dual_f, stereo_f;
+
+ if (decoder->radio)
+ break;
+ get_inf_dev_status(client, &dual_f, &stereo_f);
+
+ v4l_dbg(1, debug, client, "DETECT==st:%d dual:%d\n",
+ stereo_f, dual_f);
+
+ /* mono */
+ if ((dual_f == 0) && (stereo_f == 0)) {
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v4l_dbg(1, debug, client, "DETECT==MONO\n");
+ }
+
+ /* stereo */
+ if (stereo_f == 1) {
+ if (vt->audmode == V4L2_TUNER_MODE_STEREO ||
+ vt->audmode == V4L2_TUNER_MODE_LANG1) {
+ vt->rxsubchans = V4L2_TUNER_SUB_STEREO;
+ v4l_dbg(1, debug, client, "DETECT==ST(ST)\n");
+ } else {
+ vt->rxsubchans = V4L2_TUNER_SUB_MONO;
+ v4l_dbg(1, debug, client, "DETECT==ST(MONO)\n");
+ }
+ }
+
+ /* dual */
+ if (dual_f == 1) {
+ if (vt->audmode == V4L2_TUNER_MODE_LANG2) {
+ vt->rxsubchans = V4L2_TUNER_SUB_LANG2 | V4L2_TUNER_SUB_MONO;
+ v4l_dbg(1, debug, client, "DETECT==DUAL1\n");
+ } else {
+ vt->rxsubchans = V4L2_TUNER_SUB_LANG1 | V4L2_TUNER_SUB_MONO;
+ v4l_dbg(1, debug, client, "DETECT==DUAL2\n");
+ }
+ }
+ break;
+ }
+
+ case VIDIOC_LOG_STATUS:
+ /* not yet implemented */
+ break;
+
+ default:
+ return -EINVAL;
+ }
+
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+
+/* i2c implementation */
+
+/* ----------------------------------------------------------------------- */
+static int saa717x_probe(struct i2c_client *client)
+{
+ struct saa717x_state *decoder;
+ u8 id = 0;
+ char *p = "";
+
+ /* Check if the adapter supports the needed features */
+ if (!i2c_check_functionality(client->adapter, I2C_FUNC_SMBUS_BYTE_DATA))
+ return -EIO;
+
+ snprintf(client->name, sizeof(client->name) - 1, "saa717x");
+
+ if (saa717x_write(client, 0x5a4, 0xfe) &&
+ saa717x_write(client, 0x5a5, 0x0f) &&
+ saa717x_write(client, 0x5a6, 0x00) &&
+ saa717x_write(client, 0x5a7, 0x01))
+ id = saa717x_read(client, 0x5a0);
+ if (id != 0xc2 && id != 0x32 && id != 0xf2 && id != 0x6c) {
+ v4l_dbg(1, debug, client, "saa717x not found (id=%02x)\n", id);
+ return -ENODEV;
+ }
+ if (id == 0xc2)
+ p = "saa7173";
+ else if (id == 0x32)
+ p = "saa7174A";
+ else if (id == 0x6c)
+ p = "saa7174HL";
+ else
+ p = "saa7171";
+ v4l_info(client, "%s found @ 0x%x (%s)\n", p,
+ client->addr << 1, client->adapter->name);
+
+ decoder = kzalloc(sizeof(struct saa717x_state), GFP_KERNEL);
+ i2c_set_clientdata(client, decoder);
+
+ if (decoder == NULL)
+ return -ENOMEM;
+ decoder->std = V4L2_STD_NTSC;
+ decoder->input = -1;
+ decoder->enable = 1;
+
+ /* tune these parameters */
+ decoder->bright = 0x80;
+ decoder->contrast = 0x44;
+ decoder->sat = 0x40;
+ decoder->hue = 0x00;
+
+ /* FIXME!! */
+ decoder->playback = 0; /* initially capture mode used */
+ decoder->audio = 1; /* DECODER_AUDIO_48_KHZ */
+
+ decoder->audio_input = 2; /* FIXME!! */
+
+ decoder->tuner_audio_mode = TUNER_AUDIO_STEREO;
+ /* set volume, bass and treble */
+ decoder->audio_main_vol_l = 6;
+ decoder->audio_main_vol_r = 6;
+ decoder->audio_main_bass = 0;
+ decoder->audio_main_treble = 0;
+ decoder->audio_main_mute = 0;
+ decoder->audio_main_balance = 32768;
+ /* normalize (24 to -40 (not -84) -> 65535 to 0) */
+ decoder->audio_main_volume =
+ (decoder->audio_main_vol_r + 41) * 65535 / (24 - (-40));
+
+ v4l_dbg(1, debug, client, "writing init values\n");
+
+ /* FIXME!! */
+ saa717x_write_regs(client, reg_init_initialize);
+ set_video_output_level_regs(client, decoder);
+ /* set bass,treble to 0db 20041101 K.Ohta */
+ decoder->audio_main_bass = 0;
+ decoder->audio_main_treble = 0;
+ set_audio_regs(client, decoder);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ schedule_timeout(2*HZ);
+ return 0;
+}
+
+static int saa717x_remove(struct i2c_client *client)
+{
+ kfree(i2c_get_clientdata(client));
+ return 0;
+}
+
+/* ----------------------------------------------------------------------- */
+
+static struct v4l2_i2c_driver_data v4l2_i2c_data = {
+ .name = "saa717x",
+ .driverid = I2C_DRIVERID_SAA717X,
+ .command = saa717x_command,
+ .probe = saa717x_probe,
+ .remove = saa717x_remove,
+ .legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
+};
diff --git a/drivers/media/video/saa7185.c b/drivers/media/video/saa7185.c
index 41f70440fd3..02fda4eecea 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 d5d7d6cf734..1cd629380f7 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 [] = {
@@ -300,10 +300,10 @@ static void se401_button_irq(struct urb *urb)
case -ENOENT:
case -ESHUTDOWN:
/* this urb is terminated, clean up */
- dbg("%s - urb shutting down with status: %d", __FUNCTION__, urb->status);
+ dbg("%s - urb shutting down with status: %d", __func__, urb->status);
return;
default:
- dbg("%s - nonzero urb status received: %d", __FUNCTION__, urb->status);
+ dbg("%s - nonzero urb status received: %d", __func__, urb->status);
goto exit;
}
@@ -315,7 +315,7 @@ exit:
status = usb_submit_urb (urb, GFP_ATOMIC);
if (status)
err ("%s - usb_submit_urb failed with result %d",
- __FUNCTION__, status);
+ __func__, status);
}
static void se401_video_irq(struct urb *urb)
@@ -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.h b/drivers/media/video/sn9c102/sn9c102.h
index 2e3c3de793a..0c8d87d8d18 100644
--- a/drivers/media/video/sn9c102/sn9c102.h
+++ b/drivers/media/video/sn9c102/sn9c102.h
@@ -176,7 +176,7 @@ do { \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
dev_info(&cam->usbdev->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -191,7 +191,7 @@ do { \
pr_info("sn9c102: " fmt "\n", ## args); \
else if ((level) == 3) \
pr_debug("sn9c102: [%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
} while (0)
#else
@@ -202,7 +202,7 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
__LINE__ , ## args)
#undef PDBGG
diff --git a/drivers/media/video/sn9c102/sn9c102_core.c b/drivers/media/video/sn9c102/sn9c102_core.c
index c40ba3adab2..5748b1e1a12 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 2dc7c686948..4af7382da5c 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);
diff --git a/drivers/media/video/soc_camera.c b/drivers/media/video/soc_camera.c
new file mode 100644
index 00000000000..a1b92446c8b
--- /dev/null
+++ b/drivers/media/video/soc_camera.c
@@ -0,0 +1,1031 @@
+/*
+ * 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", __func__, p->memory);
+
+ ret = videobuf_reqbufs(&icf->vb_vidq, p);
+ if (ret < 0)
+ return ret;
+
+ return ici->ops->reqbufs(icf, p);
+}
+
+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", __func__);
+
+ 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", __func__);
+
+ 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", __func__);
+
+ 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 ceba45ad029..9276ed99738 100644
--- a/drivers/media/video/stk-webcam.c
+++ b/drivers/media/video/stk-webcam.c
@@ -1100,7 +1100,7 @@ static int stk_setup_format(struct stk_camera *dev)
&& i < ARRAY_SIZE(stk_sizes))
i++;
if (i == ARRAY_SIZE(stk_sizes)) {
- STK_ERROR("Something is broken in %s\n", __FUNCTION__);
+ STK_ERROR("Something is broken in %s\n", __func__);
return -EFAULT;
}
/* This registers controls some timings, not sure of what. */
@@ -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 3fb85af5d1f..c109511f21e 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 afc32aa56fd..d7f130bedb5 100644
--- a/drivers/media/video/stv680.c
+++ b/drivers/media/video/stv680.c
@@ -72,15 +72,18 @@
#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 { \
if (debug >= level) \
- info("[%s:%d] " fmt, __FUNCTION__, __LINE__ , ## args); \
+ info("[%s:%d] " fmt, __func__, __LINE__ , ## args); \
} while (0)
@@ -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/tcm825x.c b/drivers/media/video/tcm825x.c
index fb895f6684a..6943b447a1b 100644
--- a/drivers/media/video/tcm825x.c
+++ b/drivers/media/video/tcm825x.c
@@ -906,7 +906,7 @@ static int __init tcm825x_init(void)
rval = i2c_add_driver(&tcm825x_i2c_driver);
if (rval)
printk(KERN_INFO "%s: failed registering " TCM825X_NAME "\n",
- __FUNCTION__);
+ __func__);
return rval;
}
diff --git a/drivers/media/video/tda8290.c b/drivers/media/video/tda8290.c
index 55bc89a6f06..0ebb5b525e5 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);
@@ -365,7 +363,7 @@ static void tda8295_set_params(struct dvb_frontend *fe,
set_audio(fe, params);
- tuner_dbg("%s: freq = %d\n", __FUNCTION__, params->frequency);
+ tuner_dbg("%s: freq = %d\n", __func__, params->frequency);
tda8295_power(fe, 1);
tda8295_agc1_out(fe, 1);
@@ -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);
@@ -616,7 +613,7 @@ static int tda8290_probe(struct tuner_i2c_props *i2c_props)
if (tda8290_id[1] == TDA8290_ID) {
if (debug)
printk(KERN_DEBUG "%s: tda8290 detected @ %d-%04x\n",
- __FUNCTION__, i2c_adapter_id(i2c_props->adap),
+ __func__, i2c_adapter_id(i2c_props->adap),
i2c_props->addr);
return 0;
}
@@ -636,7 +633,7 @@ static int tda8295_probe(struct tuner_i2c_props *i2c_props)
if (tda8295_id[1] == TDA8295_ID) {
if (debug)
printk(KERN_DEBUG "%s: tda8295 detected @ %d-%04x\n",
- __FUNCTION__, i2c_adapter_id(i2c_props->adap),
+ __func__, i2c_adapter_id(i2c_props->adap),
i2c_props->addr);
return 0;
}
@@ -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 dc8ef310b7b..d3bbf276a46 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;
@@ -39,7 +39,7 @@ extern struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
#else
static inline int tda829x_probe(struct i2c_adapter *i2c_adap, u8 i2c_addr)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return -EINVAL;
}
@@ -49,7 +49,7 @@ static inline struct dvb_frontend *tda829x_attach(struct dvb_frontend *fe,
struct tda829x_config *cfg)
{
printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
- __FUNCTION__);
+ __func__);
return NULL;
}
#endif
diff --git a/drivers/media/video/tda9840.c b/drivers/media/video/tda9840.c
index bdca5d27897..0cee0024278 100644
--- a/drivers/media/video/tda9840.c
+++ b/drivers/media/video/tda9840.c
@@ -31,11 +31,11 @@
#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...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
#define SWITCH 0x00
#define LEVEL_ADJUST 0x02
diff --git a/drivers/media/video/tda9887.c b/drivers/media/video/tda9887.c
index 106c93b8203..a0545ba957b 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/tda9887.h b/drivers/media/video/tda9887.h
index 8f873a8e6ed..be49dcbfc70 100644
--- a/drivers/media/video/tda9887.h
+++ b/drivers/media/video/tda9887.h
@@ -30,7 +30,7 @@ static inline struct dvb_frontend *tda9887_attach(struct dvb_frontend *fe,
struct i2c_adapter *i2c_adap,
u8 i2c_addr)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
diff --git a/drivers/media/video/tea5761.c b/drivers/media/video/tea5761.c
index 5326eeceaac..b93cdef9ac7 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);
}
@@ -249,14 +247,19 @@ int tea5761_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
if (16 != (rc = tuner_i2c_xfer_recv(&i2c, buffer, 16))) {
printk(KERN_WARNING "it is not a TEA5761. Received %i chars.\n", rc);
- return EINVAL;
+ return -EINVAL;
}
- if (!((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061))) {
- printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x. It is not a TEA5761\n",buffer[13],buffer[14],buffer[15]);
- return EINVAL;
+ if ((buffer[13] != 0x2b) || (buffer[14] != 0x57) || (buffer[15] != 0x061)) {
+ printk(KERN_WARNING "Manufacturer ID= 0x%02x, Chip ID = %02x%02x."
+ " It is not a TEA5761\n",
+ buffer[13], buffer[14], buffer[15]);
+ return -EINVAL;
}
- printk(KERN_WARNING "TEA5761 detected.\n");
+ printk(KERN_WARNING "tea5761: TEA%02x%02x detected. "
+ "Manufacturer ID= 0x%02x\n",
+ buffer[14], buffer[15], buffer[13]);
+
return 0;
}
@@ -302,6 +305,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/tea5761.h b/drivers/media/video/tea5761.h
index 73a03b42784..8eb62722b98 100644
--- a/drivers/media/video/tea5761.h
+++ b/drivers/media/video/tea5761.h
@@ -31,7 +31,7 @@ static inline int tea5761_autodetection(struct i2c_adapter* i2c_adap,
u8 i2c_addr)
{
printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
- __FUNCTION__);
+ __func__);
return -EINVAL;
}
@@ -39,7 +39,7 @@ static inline struct dvb_frontend *tea5761_attach(struct dvb_frontend *fe,
struct i2c_adapter* i2c_adap,
u8 i2c_addr)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
diff --git a/drivers/media/video/tea5767.c b/drivers/media/video/tea5767.c
index e1b48d87e7b..f6e7d7ad842 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 */
@@ -395,11 +393,6 @@ int tea5767_autodetection(struct i2c_adapter* i2c_adap, u8 i2c_addr)
return EINVAL;
}
- /* It seems that tea5767 returns 0xff after the 5th byte */
- if ((buffer[5] != 0xff) || (buffer[6] != 0xff)) {
- printk(KERN_WARNING "Returned more than 5 bytes. It is not a TEA5767\n");
- return EINVAL;
- }
return 0;
}
@@ -456,6 +449,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/tea5767.h b/drivers/media/video/tea5767.h
index a44451f6114..7b547c092e2 100644
--- a/drivers/media/video/tea5767.h
+++ b/drivers/media/video/tea5767.h
@@ -50,7 +50,7 @@ static inline int tea5767_autodetection(struct i2c_adapter* i2c_adap,
u8 i2c_addr)
{
printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
- __FUNCTION__);
+ __func__);
return -EINVAL;
}
@@ -58,7 +58,7 @@ static inline struct dvb_frontend *tea5767_attach(struct dvb_frontend *fe,
struct i2c_adapter* i2c_adap,
u8 i2c_addr)
{
- printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __FUNCTION__);
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
diff --git a/drivers/media/video/tea6415c.c b/drivers/media/video/tea6415c.c
index df2fad9f391..9513d8611e8 100644
--- a/drivers/media/video/tea6415c.c
+++ b/drivers/media/video/tea6415c.c
@@ -33,11 +33,11 @@
#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...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
#define TEA6415C_NUM_INPUTS 8
#define TEA6415C_NUM_OUTPUTS 6
diff --git a/drivers/media/video/tea6420.c b/drivers/media/video/tea6420.c
index 4ff6c63f723..7fd53367c07 100644
--- a/drivers/media/video/tea6420.c
+++ b/drivers/media/video/tea6420.c
@@ -33,11 +33,11 @@
#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...) \
- do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __FUNCTION__, __LINE__); printk(args); } } while (0)
+ do { if (debug) { printk("%s: %s()[%d]: ", KBUILD_MODNAME, __func__, __LINE__); printk(args); } } while (0)
/* addresses to scan, found only at 0x4c and/or 0x4d (7-Bit) */
static unsigned short normal_i2c[] = { I2C_ADDR_TEA6420_1, I2C_ADDR_TEA6420_2, I2C_CLIENT_END };
diff --git a/drivers/media/video/tuner-core.c b/drivers/media/video/tuner-core.c
index 78a09a2a485..529e00952a8 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;
}
@@ -759,7 +758,7 @@ static int tuner_command(struct i2c_client *client, unsigned int cmd, void *arg)
if (analog_ops->standby)
analog_ops->standby(&t->fe);
break;
-#ifdef CONFIG_VIDEO_V4L1
+#ifdef CONFIG_VIDEO_ALLOW_V4L1
case VIDIOCSAUDIO:
if (check_mode(t, "VIDIOCSAUDIO") == EINVAL)
return 0;
@@ -1112,8 +1111,8 @@ static int tuner_probe(struct i2c_client *client)
if (!no_autodetect) {
switch (client->addr) {
case 0x10:
- if (tea5761_autodetection(t->i2c->adapter, t->i2c->addr)
- != EINVAL) {
+ if (tea5761_autodetection(t->i2c->adapter,
+ t->i2c->addr) >= 0) {
t->type = TUNER_TEA5761;
t->mode_mask = T_RADIO;
t->mode = T_STANDBY;
@@ -1125,7 +1124,7 @@ static int tuner_probe(struct i2c_client *client)
goto register_client;
}
- break;
+ return -ENODEV;
case 0x42:
case 0x43:
case 0x4a:
diff --git a/drivers/media/video/tuner-i2c.h b/drivers/media/video/tuner-i2c.h
index de52e8ffd34..3ad6c8e0b04 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 c1db576696c..be8d903171b 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",
+ __func__, 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 9089939a8c0..e46cf0121e0 100644
--- a/drivers/media/video/tuner-simple.h
+++ b/drivers/media/video/tuner-simple.h
@@ -20,25 +20,18 @@
#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__);
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
#endif
diff --git a/drivers/media/video/tuner-types.c b/drivers/media/video/tuner-types.c
index 883047f9c28..10dddca8b5d 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-types.h b/drivers/media/video/tuner-xc2028-types.h
index d0057fbf0ec..74dc46a71f6 100644
--- a/drivers/media/video/tuner-xc2028-types.h
+++ b/drivers/media/video/tuner-xc2028-types.h
@@ -1,6 +1,9 @@
/* tuner-xc2028_types
*
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * This file includes internal tipes to be used inside tuner-xc2028.
+ * Shouldn't be included outside tuner-xc2028
+ *
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
* This code is placed under the terms of the GNU General Public License v2
*/
@@ -54,11 +57,13 @@
/* LCD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
There are variants both with and without NOGD
+ Those firmwares produce better result with LCD displays
*/
#define LCD (1<<12)
/* NOGD firmwares exist only for MTS STD/MN (PAL or NTSC/M)
and for non-MTS STD/MN (PAL, NTSC/M or NTSC/Kr)
+ The NOGD firmwares don't have group delay compensation filter
*/
#define NOGD (1<<13)
@@ -85,11 +90,19 @@
/* This flag identifies that the scode table has a new format */
#define HAS_IF (1 << 30)
-#define SCODE_TYPES (MTS|DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
- LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \
- DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
+/* There are different scode tables for MTS and non-MTS.
+ The MTS firmwares support mono only
+ */
+#define SCODE_TYPES (SCODE | MTS)
+
-/* Newer types to be moved to videodev2.h */
+/* Newer types not defined on videodev2.h.
+ The original idea were to move all those types to videodev2.h, but
+ it seemed overkill, since, with the exception of SECAM/K3, the other
+ types seem to be autodetected.
+ It is not clear where secam/k3 is used, nor we have a feedback of this
+ working or being autodetected by the standard secam firmware.
+ */
#define V4L2_STD_SECAM_K3 (0x04000000)
diff --git a/drivers/media/video/tuner-xc2028.c b/drivers/media/video/tuner-xc2028.c
index 50cf876f020..cc3db7d79a0 100644
--- a/drivers/media/video/tuner-xc2028.c
+++ b/drivers/media/video/tuner-xc2028.c
@@ -1,6 +1,6 @@
/* tuner-xc2028
*
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
*
* Copyright (c) 2007 Michel Ludwig (michel.ludwig@gmail.com)
* - frontend interface
@@ -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);
@@ -127,12 +130,12 @@ struct xc2028_data {
_rc; \
})
-static unsigned int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
+static int xc2028_get_reg(struct xc2028_data *priv, u16 reg, u16 *val)
{
unsigned char buf[2];
unsigned char ibuf[2];
- tuner_dbg("%s %04x called\n", __FUNCTION__, reg);
+ tuner_dbg("%s %04x called\n", __func__, reg);
buf[0] = reg >> 8;
buf[1] = (unsigned char) reg;
@@ -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 ");
@@ -232,6 +235,7 @@ static v4l2_std_id parse_audio_std_option(void)
static void free_firmware(struct xc2028_data *priv)
{
int i;
+ tuner_dbg("%s called\n", __func__);
if (!priv->firm)
return;
@@ -255,19 +259,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", __func__);
- tuner_dbg("%s called\n", __FUNCTION__);
+ if (!firmware_name[0])
+ fname = priv->ctrl.fname;
+ else
+ fname = firmware_name;
- tuner_dbg("Reading firmware %s\n", priv->ctrl.fname);
- rc = request_firmware(&fw, priv->ctrl.fname,
- &priv->i2c_props.adap->dev);
+ 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 +285,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 +300,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);
@@ -395,9 +404,9 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
{
struct xc2028_data *priv = fe->tuner_priv;
int i, best_i = -1, best_nr_matches = 0;
- unsigned int ign_firm_type_mask = 0;
+ unsigned int type_mask = 0;
- tuner_dbg("%s called, want type=", __FUNCTION__);
+ tuner_dbg("%s called, want type=", __func__);
if (debug) {
dump_firm_type(type);
printk("(%x), id %016llx.\n", type, (unsigned long long)*id);
@@ -412,18 +421,23 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
*id = V4L2_STD_PAL;
if (type & BASE)
- type &= BASE_TYPES;
+ type_mask = BASE_TYPES;
else if (type & SCODE) {
type &= SCODE_TYPES;
- ign_firm_type_mask = HAS_IF;
+ type_mask = SCODE_TYPES & ~HAS_IF;
} else if (type & DTV_TYPES)
- type &= DTV_TYPES;
+ type_mask = DTV_TYPES;
else if (type & STD_SPECIFIC_TYPES)
- type &= STD_SPECIFIC_TYPES;
+ type_mask = STD_SPECIFIC_TYPES;
+
+ type &= type_mask;
+
+ if (!type & SCODE)
+ type_mask = ~0;
/* Seek for exact match */
for (i = 0; i < priv->firm_size; i++) {
- if ((type == (priv->firm[i].type & ~ign_firm_type_mask)) &&
+ if ((type == (priv->firm[i].type & type_mask)) &&
(*id == priv->firm[i].id))
goto found;
}
@@ -433,7 +447,7 @@ static int seek_firmware(struct dvb_frontend *fe, unsigned int type,
v4l2_std_id match_mask;
int nr_matches;
- if (type != (priv->firm[i].type & ~ign_firm_type_mask))
+ if (type != (priv->firm[i].type & type_mask))
continue;
match_mask = *id & priv->firm[i].id;
@@ -483,7 +497,7 @@ static int load_firmware(struct dvb_frontend *fe, unsigned int type,
int pos, rc;
unsigned char *p, *endp, buf[priv->ctrl.max_len];
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
pos = seek_firmware(fe, type, id);
if (pos < 0)
@@ -586,7 +600,7 @@ static int load_scode(struct dvb_frontend *fe, unsigned int type,
int pos, rc;
unsigned char *p;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
if (!int_freq) {
pos = seek_firmware(fe, type, id);
@@ -650,7 +664,7 @@ static int check_firmware(struct dvb_frontend *fe, unsigned int type,
u16 version, hwmodel;
v4l2_std_id std0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
if (!priv->firm) {
if (!priv->ctrl.fname) {
@@ -770,10 +784,10 @@ check_device:
goto fail;
}
- tuner_info("Device is Xceive %d version %d.%d, "
- "firmware version %d.%d\n",
- hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
- (version & 0xf0) >> 4, version & 0xf);
+ tuner_dbg("Device is Xceive %d version %d.%d, "
+ "firmware version %d.%d\n",
+ hwmodel, (version & 0xf000) >> 12, (version & 0xf00) >> 8,
+ (version & 0xf0) >> 4, version & 0xf);
/* Check firmware version against what we downloaded. */
if (priv->firm_version != ((version & 0xf0) << 4 | (version & 0x0f))) {
@@ -824,27 +838,34 @@ static int xc2028_signal(struct dvb_frontend *fe, u16 *strength)
u16 frq_lock, signal = 0;
int rc;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
mutex_lock(&priv->lock);
/* Sync Lock Indicator */
rc = xc2028_get_reg(priv, 0x0002, &frq_lock);
- if (rc < 0 || frq_lock == 0)
+ if (rc < 0)
goto ret;
- /* Frequency is locked. Return signal quality */
+ /* Frequency is locked */
+ if (frq_lock == 1)
+ signal = 32768;
/* Get SNR of the video signal */
rc = xc2028_get_reg(priv, 0x0040, &signal);
if (rc < 0)
- signal = -frq_lock;
+ goto ret;
+
+ /* Use both frq_lock and signal to generate the result */
+ signal = signal || ((signal & 0x07) << 12);
ret:
mutex_unlock(&priv->lock);
*strength = signal;
+ tuner_dbg("signal strength is %d\n", signal);
+
return rc;
}
@@ -861,7 +882,7 @@ static int generic_set_freq(struct dvb_frontend *fe, u32 freq /* in HZ */,
unsigned char buf[4];
u32 div, offset = 0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
mutex_lock(&priv->lock);
@@ -906,9 +927,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);
@@ -942,7 +965,7 @@ static int xc2028_set_analog_freq(struct dvb_frontend *fe,
struct xc2028_data *priv = fe->tuner_priv;
unsigned int type=0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
if (p->mode == V4L2_TUNER_RADIO) {
type |= FM;
@@ -975,7 +998,7 @@ static int xc2028_set_params(struct dvb_frontend *fe,
fe_bandwidth_t bw = BANDWIDTH_8_MHZ;
u16 demod = 0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
if (priv->ctrl.d2633)
type |= D2633;
@@ -1040,33 +1063,12 @@ static int xc2028_set_params(struct dvb_frontend *fe,
T_DIGITAL_TV, type, 0, demod);
}
-static int xc2028_sleep(struct dvb_frontend *fe)
-{
- struct xc2028_data *priv = fe->tuner_priv;
- int rc = 0;
-
- tuner_dbg("%s called\n", __FUNCTION__);
-
- mutex_lock(&priv->lock);
-
- if (priv->firm_version < 0x0202)
- rc = send_seq(priv, {0x00, 0x08, 0x00, 0x00});
- else
- rc = send_seq(priv, {0x80, 0x08, 0x00, 0x00});
-
- priv->cur_fw.type = 0; /* need firmware reload */
-
- mutex_unlock(&priv->lock);
-
- return rc;
-}
-
static int xc2028_dvb_release(struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
mutex_lock(&xc2028_list_mutex);
@@ -1091,7 +1093,7 @@ static int xc2028_get_frequency(struct dvb_frontend *fe, u32 *frequency)
{
struct xc2028_data *priv = fe->tuner_priv;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
*frequency = priv->frequency;
@@ -1104,25 +1106,25 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
struct xc2028_ctrl *p = priv_cfg;
int rc = 0;
- tuner_dbg("%s called\n", __FUNCTION__);
+ tuner_dbg("%s called\n", __func__);
mutex_lock(&priv->lock);
- kfree(priv->ctrl.fname);
- free_firmware(priv);
-
memcpy(&priv->ctrl, p, sizeof(priv->ctrl));
- priv->ctrl.fname = NULL;
+ if (priv->ctrl.max_len < 9)
+ priv->ctrl.max_len = 13;
if (p->fname) {
+ if (priv->ctrl.fname && strcmp(p->fname, priv->ctrl.fname)) {
+ kfree(priv->ctrl.fname);
+ free_firmware(priv);
+ }
+
priv->ctrl.fname = kstrdup(p->fname, GFP_KERNEL);
if (priv->ctrl.fname == NULL)
rc = -ENOMEM;
}
- if (priv->ctrl.max_len < 9)
- priv->ctrl.max_len = 13;
-
mutex_unlock(&priv->lock);
return rc;
@@ -1142,8 +1144,6 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.get_frequency = xc2028_get_frequency,
.get_rf_strength = xc2028_signal,
.set_params = xc2028_set_params,
- .sleep = xc2028_sleep,
-
};
struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
@@ -1153,23 +1153,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 +1189,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 +1203,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/tuner-xc2028.h b/drivers/media/video/tuner-xc2028.h
index 3eb8420379a..fc2f132a554 100644
--- a/drivers/media/video/tuner-xc2028.h
+++ b/drivers/media/video/tuner-xc2028.h
@@ -1,6 +1,6 @@
/* tuner-xc2028
*
- * Copyright (c) 2007 Mauro Carvalho Chehab (mchehab@infradead.org)
+ * Copyright (c) 2007-2008 Mauro Carvalho Chehab (mchehab@infradead.org)
* This code is placed under the terms of the GNU General Public License v2
*/
@@ -12,7 +12,7 @@
#define XC2028_DEFAULT_FIRMWARE "xc3028-v27.fw"
/* Dmoduler IF (kHz) */
-#define XC3028_FE_DEFAULT 0
+#define XC3028_FE_DEFAULT 0 /* Don't load SCODE */
#define XC3028_FE_LG60 6000
#define XC3028_FE_ATI638 6380
#define XC3028_FE_OREN538 5380
@@ -55,7 +55,7 @@ static inline struct dvb_frontend *xc2028_attach(struct dvb_frontend *fe,
struct xc2028_config *cfg)
{
printk(KERN_INFO "%s: not probed - driver disabled by Kconfig\n",
- __FUNCTION__);
+ __func__);
return NULL;
}
#endif
diff --git a/drivers/media/video/tvaudio.c b/drivers/media/video/tvaudio.c
index 01ebcec040c..f29a2cd0f2f 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 dc0da44a5af..3cf8a8e801e 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 b6e24e714a2..6a3af1005f0 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 14db95e10cf..59166b76010 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)");
@@ -802,6 +802,21 @@ static enum ParseState ibmcam_model2_320x240_parse_lines(
return scan_Continue;
}
+/*
+ * ibmcam_model3_parse_lines()
+ *
+ * | Even lines | Odd Lines |
+ * -----------------------------------|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |............|.....................|
+ * |YYY........Y|UYVYUYVY.........UYVY|
+ * |------------+---------------------|
+ *
+ * There is one (U, V) chroma pair for every four luma (Y) values. This
+ * function reads a pair of lines at a time and obtains missing chroma values
+ * from adjacent pixels.
+ */
static enum ParseState ibmcam_model3_parse_lines(
struct uvd *uvd,
struct usbvideo_frame *frame,
@@ -816,6 +831,7 @@ static enum ParseState ibmcam_model3_parse_lines(
const int ccm = 128; /* Color correction median - see below */
int i, u, v, rw, data_w=0, data_h=0, color_corr;
static unsigned char lineBuffer[640*3];
+ int line;
color_corr = (uvd->vpic.colour - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
RESTRICT_TO_RANGE(color_corr, -ccm, ccm+1);
@@ -869,15 +885,15 @@ static enum ParseState ibmcam_model3_parse_lines(
return scan_NextFrame;
}
- /* Make sure there's enough data for the entire line */
- len = 3 * data_w; /* <y-data> <uv-data> */
+ /* Make sure that lineBuffer can store two lines of data */
+ len = 3 * data_w; /* <y-data> <uyvy-data> */
assert(len <= sizeof(lineBuffer));
- /* Make sure there's enough data for the entire line */
+ /* Make sure there's enough data for two lines */
if (RingQueue_GetLength(&uvd->dp) < len)
return scan_Out;
- /* Suck one line out of the ring queue */
+ /* Suck two lines of data out of the ring queue */
RingQueue_Dequeue(&uvd->dp, lineBuffer, len);
data = lineBuffer;
@@ -887,15 +903,23 @@ static enum ParseState ibmcam_model3_parse_lines(
rw = (int)VIDEOSIZE_Y(frame->request) - (int)(frame->curline) - 1;
RESTRICT_TO_RANGE(rw, 0, VIDEOSIZE_Y(frame->request)-1);
- for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
- int y, rv, gv, bv; /* RGB components */
+ /* Iterate over two lines. */
+ for (line = 0; line < 2; line++) {
+ for (i = 0; i < VIDEOSIZE_X(frame->request); i++) {
+ int y;
+ int rv, gv, bv; /* RGB components */
- if (i < data_w) {
- y = data[i]; /* Luminosity is the first line */
+ if (i >= data_w) {
+ RGB24_PUTPIXEL(frame, i, rw, 0, 0, 0);
+ continue;
+ }
+
+ /* first line is YYY...Y; second is UYVY...UYVY */
+ y = data[(line == 0) ? i : (i*2 + 1)];
/* Apply static color correction */
- u = color[i*2] + hue_corr;
- v = color[i*2 + 1] + hue2_corr;
+ u = color[(i/2)*4] + hue_corr;
+ v = color[(i/2)*4 + 2] + hue2_corr;
/* Apply color correction */
if (color_corr != 0) {
@@ -903,13 +927,21 @@ static enum ParseState ibmcam_model3_parse_lines(
u = 128 + ((ccm + color_corr) * (u - 128)) / ccm;
v = 128 + ((ccm + color_corr) * (v - 128)) / ccm;
}
- } else
- y = 0, u = v = 128;
- YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
- RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* Done by deinterlacing now */
+
+ YUV_TO_RGB_BY_THE_BOOK(y, u, v, rv, gv, bv);
+ RGB24_PUTPIXEL(frame, i, rw, rv, gv, bv); /* No deinterlacing */
+ }
+
+ /* Check for the end of requested data */
+ if (rw == 0)
+ break;
+
+ /* Prepare for the second line */
+ rw--;
+ data = lineBuffer + data_w;
}
- frame->deinterlace = Deinterlace_FillEvenLines;
+ frame->deinterlace = Deinterlace_None;
/*
* Account for number of bytes that we wrote into output V4L frame.
diff --git a/drivers/media/video/usbvideo/konicawc.c b/drivers/media/video/usbvideo/konicawc.c
index 719b17ce83f..1c180284ec6 100644
--- a/drivers/media/video/usbvideo/konicawc.c
+++ b/drivers/media/video/usbvideo/konicawc.c
@@ -57,11 +57,11 @@ static struct usbvideo *cams;
static int debug;
#define DEBUG(n, format, arg...) \
if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
}
#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 a2acba0bcc4..32e536edf09 100644
--- a/drivers/media/video/usbvideo/quickcam_messenger.c
+++ b/drivers/media/video/usbvideo/quickcam_messenger.c
@@ -46,11 +46,11 @@
static int debug;
#define DEBUG(n, format, arg...) \
if (n <= debug) { \
- printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __FUNCTION__ , ## arg); \
+ printk(KERN_DEBUG __FILE__ ":%s(): " format "\n", __func__ , ## arg); \
}
#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 95453c108d4..9544e644bf0 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 5d363be7bc7..4128ee20b64 100644
--- a/drivers/media/video/usbvideo/usbvideo.c
+++ b/drivers/media/video/usbvideo/usbvideo.c
@@ -522,14 +522,14 @@ 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__);
+ err("%s: uvd == NULL", __func__);
return;
}
if ((uvd->curframe < 0) || (uvd->curframe >= USBVIDEO_NUMFRAMES)) {
- err("%s: uvd->curframe=%d.", __FUNCTION__, uvd->curframe);
+ err("%s: uvd->curframe=%d.", __func__, uvd->curframe);
return;
}
@@ -630,15 +630,15 @@ EXPORT_SYMBOL(usbvideo_HexDump);
static int usbvideo_ClientIncModCount(struct uvd *uvd)
{
if (uvd == NULL) {
- err("%s: uvd == NULL", __FUNCTION__);
+ err("%s: uvd == NULL", __func__);
return -EINVAL;
}
if (uvd->handle == NULL) {
- err("%s: uvd->handle == NULL", __FUNCTION__);
+ err("%s: uvd->handle == NULL", __func__);
return -EINVAL;
}
if (!try_module_get(uvd->handle->md_module)) {
- err("%s: try_module_get() == 0", __FUNCTION__);
+ err("%s: try_module_get() == 0", __func__);
return -ENODEV;
}
return 0;
@@ -647,15 +647,15 @@ static int usbvideo_ClientIncModCount(struct uvd *uvd)
static void usbvideo_ClientDecModCount(struct uvd *uvd)
{
if (uvd == NULL) {
- err("%s: uvd == NULL", __FUNCTION__);
+ err("%s: uvd == NULL", __func__);
return;
}
if (uvd->handle == NULL) {
- err("%s: uvd->handle == NULL", __FUNCTION__);
+ err("%s: uvd->handle == NULL", __func__);
return;
}
if (uvd->handle->md_module == NULL) {
- err("%s: uvd->handle->md_module == NULL", __FUNCTION__);
+ err("%s: uvd->handle->md_module == NULL", __func__);
return;
}
module_put(uvd->handle->md_module);
@@ -675,13 +675,13 @@ int usbvideo_register(
/* Check parameters for sanity */
if ((num_cams <= 0) || (pCams == NULL) || (cbTbl == NULL)) {
- err("%s: Illegal call", __FUNCTION__);
+ err("%s: Illegal call", __func__);
return -EINVAL;
}
/* Check registration callback - must be set! */
if (cbTbl->probe == NULL) {
- err("%s: probe() is required!", __FUNCTION__);
+ err("%s: probe() is required!", __func__);
return -EINVAL;
}
@@ -692,7 +692,7 @@ int usbvideo_register(
return -ENOMEM;
}
dbg("%s: Allocated $%p (%d. bytes) for %d. cameras",
- __FUNCTION__, cams, base_size, num_cams);
+ __func__, cams, base_size, num_cams);
/* Copy callbacks, apply defaults for those that are not set */
memmove(&cams->cb, cbTbl, sizeof(cams->cb));
@@ -721,7 +721,7 @@ int usbvideo_register(
up->user_data = kmalloc(up->user_size, GFP_KERNEL);
if (up->user_data == NULL) {
err("%s: Failed to allocate user_data (%d. bytes)",
- __FUNCTION__, up->user_size);
+ __func__, up->user_size);
while (i) {
up = &cams->cam[--i];
kfree(up->user_data);
@@ -730,7 +730,7 @@ int usbvideo_register(
return -ENOMEM;
}
dbg("%s: Allocated cams[%d].user_data=$%p (%d. bytes)",
- __FUNCTION__, i, up->user_data, up->user_size);
+ __func__, i, up->user_data, up->user_size);
}
}
@@ -776,19 +776,19 @@ void usbvideo_Deregister(struct usbvideo **pCams)
int i;
if (pCams == NULL) {
- err("%s: pCams == NULL", __FUNCTION__);
+ err("%s: pCams == NULL", __func__);
return;
}
cams = *pCams;
if (cams == NULL) {
- err("%s: cams == NULL", __FUNCTION__);
+ err("%s: cams == NULL", __func__);
return;
}
- dbg("%s: Deregistering %s driver.", __FUNCTION__, cams->drvName);
+ dbg("%s: Deregistering %s driver.", __func__, cams->drvName);
usb_deregister(&cams->usbdrv);
- dbg("%s: Deallocating cams=$%p (%d. cameras)", __FUNCTION__, cams, cams->num_cameras);
+ dbg("%s: Deallocating cams=$%p (%d. cameras)", __func__, cams, cams->num_cameras);
for (i=0; i < cams->num_cameras; i++) {
struct uvd *up = &cams->cam[i];
int warning = 0;
@@ -802,16 +802,16 @@ void usbvideo_Deregister(struct usbvideo **pCams)
}
if (warning) {
err("%s: Warning: user_data=$%p user_size=%d.",
- __FUNCTION__, up->user_data, up->user_size);
+ __func__, up->user_data, up->user_size);
} else {
dbg("%s: Freeing %d. $%p->user_data=$%p",
- __FUNCTION__, i, up, up->user_data);
+ __func__, i, up, up->user_data);
kfree(up->user_data);
}
}
/* Whole array was allocated in one chunk */
dbg("%s: Freed %d uvd structures",
- __FUNCTION__, cams->num_cameras);
+ __func__, cams->num_cameras);
kfree(cams);
*pCams = NULL;
}
@@ -846,7 +846,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
int i;
if (uvd == NULL) {
- err("%s($%p): Illegal call.", __FUNCTION__, intf);
+ err("%s($%p): Illegal call.", __func__, intf);
return;
}
@@ -854,7 +854,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
usbvideo_ClientIncModCount(uvd);
if (uvd->debug > 0)
- info("%s(%p.)", __FUNCTION__, intf);
+ info("%s(%p.)", __func__, intf);
mutex_lock(&uvd->lock);
uvd->remove_pending = 1; /* Now all ISO data will be ignored */
@@ -870,10 +870,10 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
video_unregister_device(&uvd->vdev);
if (uvd->debug > 0)
- info("%s: Video unregistered.", __FUNCTION__);
+ info("%s: Video unregistered.", __func__);
if (uvd->user)
- info("%s: In use, disconnect pending.", __FUNCTION__);
+ info("%s: In use, disconnect pending.", __func__);
else
usbvideo_CameraRelease(uvd);
mutex_unlock(&uvd->lock);
@@ -895,7 +895,7 @@ static void usbvideo_Disconnect(struct usb_interface *intf)
static void usbvideo_CameraRelease(struct uvd *uvd)
{
if (uvd == NULL) {
- err("%s: Illegal call", __FUNCTION__);
+ err("%s: Illegal call", __func__);
return;
}
@@ -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 = {
@@ -1011,18 +1013,18 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
char tmp1[20], tmp2[20]; /* Buffers for printing */
if (uvd == NULL) {
- err("%s: Illegal call.", __FUNCTION__);
+ err("%s: Illegal call.", __func__);
return -EINVAL;
}
if (uvd->video_endp == 0) {
- info("%s: No video endpoint specified; data pump disabled.", __FUNCTION__);
+ info("%s: No video endpoint specified; data pump disabled.", __func__);
}
if (uvd->paletteBits == 0) {
- err("%s: No palettes specified!", __FUNCTION__);
+ err("%s: No palettes specified!", __func__);
return -EINVAL;
}
if (uvd->defaultPalette == 0) {
- info("%s: No default palette!", __FUNCTION__);
+ info("%s: No default palette!", __func__);
}
uvd->max_frame_size = VIDEOSIZE_X(uvd->canvas) *
@@ -1032,19 +1034,19 @@ int usbvideo_RegisterVideoDevice(struct uvd *uvd)
if (uvd->debug > 0) {
info("%s: iface=%d. endpoint=$%02x paletteBits=$%08lx",
- __FUNCTION__, uvd->iface, uvd->video_endp, uvd->paletteBits);
+ __func__, 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__);
+ err("%s: video_register_device failed", __func__);
return -EPIPE;
}
if (uvd->debug > 1) {
- info("%s: video_register_device() successful", __FUNCTION__);
+ info("%s: video_register_device() successful", __func__);
}
info("%s on /dev/video%d: canvas=%s videosize=%s",
@@ -1111,14 +1113,14 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
int i, errCode = 0;
if (uvd->debug > 1)
- info("%s($%p)", __FUNCTION__, dev);
+ info("%s($%p)", __func__, dev);
if (0 < usbvideo_ClientIncModCount(uvd))
return -ENODEV;
mutex_lock(&uvd->lock);
if (uvd->user) {
- err("%s: Someone tried to open an already opened device!", __FUNCTION__);
+ err("%s: Someone tried to open an already opened device!", __func__);
errCode = -EBUSY;
} else {
/* Clear statistics */
@@ -1134,7 +1136,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
RingQueue_Allocate(&uvd->dp, RING_QUEUE_SIZE);
if ((uvd->fbuf == NULL) ||
(!RingQueue_IsAllocated(&uvd->dp))) {
- err("%s: Failed to allocate fbuf or dp", __FUNCTION__);
+ err("%s: Failed to allocate fbuf or dp", __func__);
errCode = -ENOMEM;
} else {
/* Allocate all buffers */
@@ -1178,19 +1180,19 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
if (errCode == 0) {
if (VALID_CALLBACK(uvd, setupOnOpen)) {
if (uvd->debug > 1)
- info("%s: setupOnOpen callback", __FUNCTION__);
+ info("%s: setupOnOpen callback", __func__);
errCode = GET_CALLBACK(uvd, setupOnOpen)(uvd);
if (errCode < 0) {
err("%s: setupOnOpen callback failed (%d.).",
- __FUNCTION__, errCode);
+ __func__, errCode);
} else if (uvd->debug > 1) {
- info("%s: setupOnOpen callback successful", __FUNCTION__);
+ info("%s: setupOnOpen callback successful", __func__);
}
}
if (errCode == 0) {
uvd->settingsAdjusted = 0;
if (uvd->debug > 1)
- info("%s: Open succeeded.", __FUNCTION__);
+ info("%s: Open succeeded.", __func__);
uvd->user++;
file->private_data = uvd;
}
@@ -1200,7 +1202,7 @@ static int usbvideo_v4l_open(struct inode *inode, struct file *file)
if (errCode != 0)
usbvideo_ClientDecModCount(uvd);
if (uvd->debug > 0)
- info("%s: Returning %d.", __FUNCTION__, errCode);
+ info("%s: Returning %d.", __func__, errCode);
return errCode;
}
@@ -1223,7 +1225,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
int i;
if (uvd->debug > 1)
- info("%s($%p)", __FUNCTION__, dev);
+ info("%s($%p)", __func__, dev);
mutex_lock(&uvd->lock);
GET_CALLBACK(uvd, stopDataPump)(uvd);
@@ -1250,7 +1252,7 @@ static int usbvideo_v4l_close(struct inode *inode, struct file *file)
usbvideo_ClientDecModCount(uvd);
if (uvd->debug > 1)
- info("%s: Completed.", __FUNCTION__);
+ info("%s: Completed.", __func__);
file->private_data = NULL;
return 0;
}
@@ -1504,7 +1506,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
return -EFAULT;
if (uvd->debug >= 1)
- info("%s: %Zd. bytes, noblock=%d.", __FUNCTION__, count, noblock);
+ info("%s: %Zd. bytes, noblock=%d.", __func__, count, noblock);
mutex_lock(&uvd->lock);
@@ -1551,7 +1553,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
*/
if (frmx == -1) {
if (uvd->defaultPalette == 0) {
- err("%s: No default palette; don't know what to do!", __FUNCTION__);
+ err("%s: No default palette; don't know what to do!", __func__);
count = -EFAULT;
goto read_done;
}
@@ -1623,7 +1625,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
frame->seqRead_Index += count;
if (uvd->debug >= 1) {
err("%s: {copy} count used=%Zd, new seqRead_Index=%ld",
- __FUNCTION__, count, frame->seqRead_Index);
+ __func__, count, frame->seqRead_Index);
}
/* Finally check if the frame is done with and "release" it */
@@ -1634,7 +1636,7 @@ static ssize_t usbvideo_v4l_read(struct file *file, char __user *buf,
/* Mark it as available to be used again. */
uvd->frame[frmx].frameState = FrameState_Unused;
if (usbvideo_NewFrame(uvd, (frmx + 1) % USBVIDEO_NUMFRAMES)) {
- err("%s: usbvideo_NewFrame failed.", __FUNCTION__);
+ err("%s: usbvideo_NewFrame failed.", __func__);
}
}
read_done:
@@ -1741,10 +1743,10 @@ static int usbvideo_StartDataPump(struct uvd *uvd)
int i, errFlag;
if (uvd->debug > 1)
- info("%s($%p)", __FUNCTION__, uvd);
+ info("%s($%p)", __func__, uvd);
if (!CAMERA_IS_OPERATIONAL(uvd)) {
- err("%s: Camera is not operational", __FUNCTION__);
+ err("%s: Camera is not operational", __func__);
return -EFAULT;
}
uvd->curframe = -1;
@@ -1752,14 +1754,14 @@ static int usbvideo_StartDataPump(struct uvd *uvd)
/* Alternate interface 1 is is the biggest frame size */
i = usb_set_interface(dev, uvd->iface, uvd->ifaceAltActive);
if (i < 0) {
- err("%s: usb_set_interface error", __FUNCTION__);
+ err("%s: usb_set_interface error", __func__);
uvd->last_error = i;
return -EBUSY;
}
if (VALID_CALLBACK(uvd, videoStart))
GET_CALLBACK(uvd, videoStart)(uvd);
else
- err("%s: videoStart not set", __FUNCTION__);
+ err("%s: videoStart not set", __func__);
/* We double buffer the Iso lists */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
@@ -1784,12 +1786,12 @@ static int usbvideo_StartDataPump(struct uvd *uvd)
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
errFlag = usb_submit_urb(uvd->sbuf[i].urb, GFP_KERNEL);
if (errFlag)
- err("%s: usb_submit_isoc(%d) ret %d", __FUNCTION__, i, errFlag);
+ err("%s: usb_submit_isoc(%d) ret %d", __func__, i, errFlag);
}
uvd->streaming = 1;
if (uvd->debug > 1)
- info("%s: streaming=1 video_endp=$%02x", __FUNCTION__, uvd->video_endp);
+ info("%s: streaming=1 video_endp=$%02x", __func__, uvd->video_endp);
return 0;
}
@@ -1811,14 +1813,14 @@ static void usbvideo_StopDataPump(struct uvd *uvd)
return;
if (uvd->debug > 1)
- info("%s($%p)", __FUNCTION__, uvd);
+ info("%s($%p)", __func__, uvd);
/* Unschedule all of the iso td's */
for (i=0; i < USBVIDEO_NUMSBUF; i++) {
usb_kill_urb(uvd->sbuf[i].urb);
}
if (uvd->debug > 1)
- info("%s: streaming=0", __FUNCTION__);
+ info("%s: streaming=0", __func__);
uvd->streaming = 0;
if (!uvd->remove_pending) {
@@ -1826,12 +1828,12 @@ static void usbvideo_StopDataPump(struct uvd *uvd)
if (VALID_CALLBACK(uvd, videoStop))
GET_CALLBACK(uvd, videoStop)(uvd);
else
- err("%s: videoStop not set", __FUNCTION__);
+ err("%s: videoStop not set", __func__);
/* Set packet size to 0 */
j = usb_set_interface(uvd->dev, uvd->iface, uvd->ifaceAltInactive);
if (j < 0) {
- err("%s: usb_set_interface() error %d.", __FUNCTION__, j);
+ err("%s: usb_set_interface() error %d.", __func__, j);
uvd->last_error = j;
}
}
@@ -1955,12 +1957,12 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
struct usbvideo_frame *frame = &uvd->frame[frameNum];
if (uvd->debug >= 2)
- info("%s($%p,%d.)", __FUNCTION__, uvd, frameNum);
+ info("%s($%p,%d.)", __func__, uvd, frameNum);
switch (frame->frameState) {
case FrameState_Unused:
if (uvd->debug >= 2)
- info("%s: FrameState_Unused", __FUNCTION__);
+ info("%s: FrameState_Unused", __func__);
return -EINVAL;
case FrameState_Ready:
case FrameState_Grabbing:
@@ -1970,7 +1972,7 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
redo:
if (!CAMERA_IS_OPERATIONAL(uvd)) {
if (uvd->debug >= 2)
- info("%s: Camera is not operational (1)", __FUNCTION__);
+ info("%s: Camera is not operational (1)", __func__);
return -EIO;
}
ntries = 0;
@@ -1979,24 +1981,24 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
signalPending = signal_pending(current);
if (!CAMERA_IS_OPERATIONAL(uvd)) {
if (uvd->debug >= 2)
- info("%s: Camera is not operational (2)", __FUNCTION__);
+ info("%s: Camera is not operational (2)", __func__);
return -EIO;
}
assert(uvd->fbuf != NULL);
if (signalPending) {
if (uvd->debug >= 2)
- info("%s: Signal=$%08x", __FUNCTION__, signalPending);
+ info("%s: Signal=$%08x", __func__, signalPending);
if (uvd->flags & FLAGS_RETRY_VIDIOCSYNC) {
usbvideo_TestPattern(uvd, 1, 0);
uvd->curframe = -1;
uvd->stats.frame_num++;
if (uvd->debug >= 2)
- info("%s: Forced test pattern screen", __FUNCTION__);
+ info("%s: Forced test pattern screen", __func__);
return 0;
} else {
/* Standard answer: Interrupted! */
if (uvd->debug >= 2)
- info("%s: Interrupted!", __FUNCTION__);
+ info("%s: Interrupted!", __func__);
return -EINTR;
}
} else {
@@ -2006,17 +2008,17 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
else if (VALID_CALLBACK(uvd, processData))
GET_CALLBACK(uvd, processData)(uvd, frame);
else
- err("%s: processData not set", __FUNCTION__);
+ err("%s: processData not set", __func__);
}
} while (frame->frameState == FrameState_Grabbing);
if (uvd->debug >= 2) {
info("%s: Grabbing done; state=%d. (%lu. bytes)",
- __FUNCTION__, frame->frameState, frame->seqRead_Length);
+ __func__, frame->frameState, frame->seqRead_Length);
}
if (frame->frameState == FrameState_Error) {
int ret = usbvideo_NewFrame(uvd, frameNum);
if (ret < 0) {
- err("%s: usbvideo_NewFrame() failed (%d.)", __FUNCTION__, ret);
+ err("%s: usbvideo_NewFrame() failed (%d.)", __func__, ret);
return ret;
}
goto redo;
@@ -2048,7 +2050,7 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
}
frame->frameState = FrameState_Done_Hold;
if (uvd->debug >= 2)
- info("%s: Entered FrameState_Done_Hold state.", __FUNCTION__);
+ info("%s: Entered FrameState_Done_Hold state.", __func__);
return 0;
case FrameState_Done_Hold:
@@ -2059,12 +2061,12 @@ static int usbvideo_GetFrame(struct uvd *uvd, int frameNum)
* it will be released back into the wild to roam freely.
*/
if (uvd->debug >= 2)
- info("%s: FrameState_Done_Hold state.", __FUNCTION__);
+ info("%s: FrameState_Done_Hold state.", __func__);
return 0;
}
/* Catch-all for other cases. We shall not be here. */
- err("%s: Invalid state %d.", __FUNCTION__, frame->frameState);
+ err("%s: Invalid state %d.", __func__, frame->frameState);
frame->frameState = FrameState_Unused;
return 0;
}
@@ -2160,7 +2162,7 @@ static void usbvideo_SoftwareContrastAdjustment(struct uvd *uvd,
const int ccm = 128; /* Color correction median - see below */
if ((uvd == NULL) || (frame == NULL)) {
- err("%s: Illegal call.", __FUNCTION__);
+ err("%s: Illegal call.", __func__);
return;
}
adj = (uvd->vpic.contrast - 0x8000) >> 8; /* -128..+127 = -ccm..+(ccm-1)*/
diff --git a/drivers/media/video/usbvideo/vicam.c b/drivers/media/video/usbvideo/vicam.c
index da1ba021110..64819353276 100644
--- a/drivers/media/video/usbvideo/vicam.c
+++ b/drivers/media/video/usbvideo/vicam.c
@@ -48,7 +48,7 @@
// #define VICAM_DEBUG
#ifdef VICAM_DEBUG
-#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __FUNCTION__, lineno, ##args)
+#define ADBG(lineno,fmt,args...) printk(fmt, jiffies, __func__, lineno, ##args)
#define DBG(fmt,args...) ADBG((__LINE__),KERN_DEBUG __FILE__"(%ld):%s (%d):"fmt,##args)
#else
#define DBG(fmn,args...) do {} while(0)
@@ -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 56775ab8b75..a9c5e5adba3 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 aabc42cae9c..e2274d77ea2 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 df52f8a6021..d97261ab430 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 e3ac5e68607..a0f6c60279e 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,7 +119,7 @@ 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;
}
@@ -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 eab79ffdf56..fc51e4918bb 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,22 @@ 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);
}
+void *videobuf_queue_to_vmalloc (struct videobuf_queue *q,
+ struct videobuf_buffer *buf)
+{
+ return CALL(q, vmalloc, buf);
+}
+EXPORT_SYMBOL_GPL(videobuf_queue_to_vmalloc);
+
/* --------------------------------------------------------------------- */
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,
@@ -144,10 +130,14 @@ void videobuf_queue_core_init(struct videobuf_queue *q,
BUG_ON(!q->ops->buf_queue);
BUG_ON(!q->ops->buf_release);
+ /* Lock is mandatory for queue_cancel to work */
+ BUG_ON(!irqlock);
+
/* Having implementations for abstract methods are mandatory */
BUG_ON(!q->int_ops);
mutex_init(&q->vb_lock);
+ init_waitqueue_head(&q->wait);
INIT_LIST_HEAD(&q->stream);
}
@@ -195,19 +185,22 @@ 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);
+ spin_lock_irqsave(q->irqlock, flags);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
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)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
/* free all buffers + clear queue */
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
@@ -563,14 +556,13 @@ int videobuf_qbuf(struct videobuf_queue *q,
list_add_tail(&buf->stream, &q->stream);
if (q->streaming) {
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
}
dprintk(1, "qbuf: succeded\n");
retval = 0;
+ wake_up_interruptible_sync(&q->wait);
done:
mutex_unlock(&q->vb_lock);
@@ -581,35 +573,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");
@@ -650,14 +695,13 @@ int videobuf_streamon(struct videobuf_queue *q)
if (q->streaming)
goto done;
q->streaming = 1;
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
list_for_each_entry(buf, &q->stream, stream)
if (buf->state == VIDEOBUF_PREPARED)
q->ops->buf_queue(q, buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
+ wake_up_interruptible_sync(&q->wait);
done:
mutex_unlock(&q->vb_lock);
return retval;
@@ -670,7 +714,6 @@ static int __videobuf_streamoff(struct videobuf_queue *q)
return -EINVAL;
videobuf_queue_cancel(q);
- q->streaming = 0;
return 0;
}
@@ -712,11 +755,9 @@ static ssize_t videobuf_read_zerocopy(struct videobuf_queue *q,
goto done;
/* start capture & wait */
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, q->read_buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
retval = videobuf_waiton(q->read_buf, 0, 0);
if (0 == retval) {
CALL(q, sync, q, q->read_buf);
@@ -740,14 +781,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 &&
@@ -778,12 +818,11 @@ ssize_t videobuf_read_one(struct videobuf_queue *q,
q->read_buf = NULL;
goto done;
}
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, q->read_buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
+
q->read_off = 0;
}
@@ -849,12 +888,10 @@ static int __videobuf_read_start(struct videobuf_queue *q)
return err;
list_add_tail(&q->bufs[i]->stream, &q->stream);
}
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
for (i = 0; i < count; i++)
q->ops->buf_queue(q, q->bufs[i]);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
q->reading = 1;
return 0;
}
@@ -863,7 +900,6 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
{
int i;
-
videobuf_queue_cancel(q);
__videobuf_mmap_free(q);
INIT_LIST_HEAD(&q->stream);
@@ -874,7 +910,6 @@ static void __videobuf_read_stop(struct videobuf_queue *q)
q->bufs[i] = NULL;
}
q->read_buf = NULL;
- q->reading = 0;
}
@@ -919,7 +954,7 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
MAGIC_CHECK(q->int_ops->magic, MAGIC_QTYPE_OPS);
- dprintk(2, "%s\n", __FUNCTION__);
+ dprintk(2, "%s\n", __func__);
mutex_lock(&q->vb_lock);
retval = -EBUSY;
if (q->streaming)
@@ -968,11 +1003,9 @@ ssize_t videobuf_read_stream(struct videobuf_queue *q,
if (q->read_off == q->read_buf->size) {
list_add_tail(&q->read_buf->stream,
&q->stream);
- if (q->irqlock)
- spin_lock_irqsave(q->irqlock, flags);
+ spin_lock_irqsave(q->irqlock, flags);
q->ops->buf_queue(q, q->read_buf);
- if (q->irqlock)
- spin_unlock_irqrestore(q->irqlock, flags);
+ spin_unlock_irqrestore(q->irqlock, flags);
q->read_buf = NULL;
}
if (retval < 0)
diff --git a/drivers/media/video/videobuf-dma-sg.c b/drivers/media/video/videobuf-dma-sg.c
index 53fed4b74ce..03a7b946bd5 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;
@@ -157,9 +162,6 @@ static int videobuf_dma_init_user_locked(struct videobuf_dmabuf *dma,
dprintk(1,"init user [0x%lx+0x%lx => %d pages]\n",
data,size,dma->nr_pages);
- dma->varea = (void *) data;
-
-
err = get_user_pages(current,current->mm,
data & PAGE_MASK, dma->nr_pages,
rw == READ, 1, /* force */
@@ -216,10 +218,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,11 +245,11 @@ 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
- "%s: videobuf_map_sg failed\n",__FUNCTION__);
+ "%s: videobuf_map_sg failed\n",__func__);
kfree(dma->sglist);
dma->sglist = NULL;
dma->sglen = 0;
@@ -259,26 +259,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;
@@ -301,33 +297,32 @@ int videobuf_dma_free(struct videobuf_dmabuf *dma)
vfree(dma->vmalloc);
dma->vmalloc = NULL;
- dma->varea = NULL;
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 +342,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 +404,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);
@@ -431,22 +426,32 @@ static void *__videobuf_alloc(size_t size)
videobuf_dma_init(&mem->dma);
dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
- __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+ __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
mem,(long)sizeof(*mem));
return vb;
}
+static void *__videobuf_to_vmalloc (struct videobuf_buffer *buf)
+{
+ struct videobuf_dma_sg_memory *mem = buf->priv;
+ BUG_ON(!mem);
+
+ MAGIC_CHECK(mem->magic, MAGIC_SG_MEM);
+
+ return mem->dma.vmalloc;
+}
+
static int __videobuf_iolock (struct videobuf_queue* q,
struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf)
{
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 +460,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 +478,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 +495,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 +503,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 +513,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 +537,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 +552,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 +604,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 +634,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 +653,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 +677,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,
@@ -668,23 +687,24 @@ static struct videobuf_qtype_ops pci_ops = {
.mmap_mapper = __videobuf_mmap_mapper,
.video_copy_to_user = __videobuf_copy_to_user,
.copy_stream = __videobuf_copy_stream,
+ .vmalloc = __videobuf_to_vmalloc,
};
-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 +712,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 +729,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 b73aba65d21..6e4d73ec685 100644
--- a/drivers/media/video/videobuf-dvb.c
+++ b/drivers/media/video/videobuf-dvb.c
@@ -20,9 +20,10 @@
#include <linux/fs.h>
#include <linux/kthread.h>
#include <linux/file.h>
+
#include <linux/freezer.h>
-#include <media/videobuf-dma-sg.h>
+#include <media/videobuf-core.h>
#include <media/videobuf-dvb.h>
/* ------------------------------------------------------------------ */
@@ -30,7 +31,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");
@@ -45,7 +46,7 @@ static int videobuf_dvb_thread(void *data)
struct videobuf_buffer *buf;
unsigned long flags;
int err;
- struct videobuf_dmabuf *dma;
+ void *outp;
dprintk("dvb thread started\n");
set_freezable();
@@ -66,9 +67,10 @@ static int videobuf_dvb_thread(void *data)
try_to_freeze();
/* feed buffer data to demux */
- dma=videobuf_to_dma(buf);
+ outp = videobuf_queue_to_vmalloc (&dvb->dvbq, buf);
+
if (buf->state == VIDEOBUF_DONE)
- dvb_dmx_swfilter(&dvb->demux, dma->vmalloc,
+ dvb_dmx_swfilter(&dvb->demux, outp,
buf->size);
/* requeue buffer */
@@ -138,14 +140,16 @@ static int videobuf_dvb_stop_feed(struct dvb_demux_feed *feed)
int videobuf_dvb_register(struct videobuf_dvb *dvb,
struct module *module,
void *adapter_priv,
- struct device *device)
+ struct device *device,
+ short *adapter_nr)
{
int result;
mutex_init(&dvb->lock);
/* register adapter */
- result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device);
+ result = dvb_register_adapter(&dvb->adapter, dvb->name, module, device,
+ adapter_nr);
if (result < 0) {
printk(KERN_WARNING "%s: dvb_register_adapter failed (errno = %d)\n",
dvb->name, result);
diff --git a/drivers/media/video/videobuf-vmalloc.c b/drivers/media/video/videobuf-vmalloc.c
index 5266ecc91da..c91e1d8e380 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");
@@ -57,20 +57,26 @@ videobuf_vm_open(struct vm_area_struct *vma)
map->count++;
}
-static void
-videobuf_vm_close(struct vm_area_struct *vma)
+static void videobuf_vm_close(struct vm_area_struct *vma)
{
struct videobuf_mapping *map = vma->vm_private_data;
struct videobuf_queue *q = map->q;
int i;
- dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n",map,
- map->count,vma->vm_start,vma->vm_end);
+ dprintk(2,"vm_close %p [count=%u,vma=%08lx-%08lx]\n", map,
+ map->count, vma->vm_start, vma->vm_end);
map->count--;
if (0 == map->count) {
- dprintk(1,"munmap %p q=%p\n",map,q);
+ struct videobuf_vmalloc_memory *mem;
+
+ dprintk(1, "munmap %p q=%p\n", map, q);
mutex_lock(&q->vb_lock);
+
+ /* We need first to cancel streams, before unmapping */
+ if (q->streaming)
+ videobuf_queue_cancel(q);
+
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (NULL == q->bufs[i])
continue;
@@ -78,14 +84,35 @@ videobuf_vm_close(struct vm_area_struct *vma)
if (q->bufs[i]->map != map)
continue;
- q->ops->buf_release(q,q->bufs[i]);
+ mem = q->bufs[i]->priv;
+ if (mem) {
+ /* This callback is called only if kernel has
+ allocated memory and this memory is mmapped.
+ In this case, memory should be freed,
+ in order to do memory unmap.
+ */
+
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
+
+ /* vfree is not atomic - can't be
+ called with IRQ's disabled
+ */
+ dprintk(1, "%s: buf[%d] freeing (%p)\n",
+ __func__, i, mem->vmalloc);
+
+ vfree(mem->vmalloc);
+ mem->vmalloc = NULL;
+ }
q->bufs[i]->map = NULL;
q->bufs[i]->baddr = 0;
}
- mutex_unlock(&q->vb_lock);
+
kfree(map);
+
+ mutex_unlock(&q->vb_lock);
}
+
return;
}
@@ -102,7 +129,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)
@@ -116,7 +143,7 @@ static void *__videobuf_alloc(size_t size)
mem->magic=MAGIC_VMAL_MEM;
dprintk(1,"%s: allocated at %p(%ld+%ld) & %p(%ld)\n",
- __FUNCTION__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
+ __func__,vb,(long)sizeof(*vb),(long)size-sizeof(*vb),
mem,(long)sizeof(*mem));
return vb;
@@ -126,45 +153,74 @@ static int __videobuf_iolock (struct videobuf_queue* q,
struct videobuf_buffer *vb,
struct v4l2_framebuffer *fbuf)
{
+ struct videobuf_vmalloc_memory *mem = vb->priv;
int pages;
- struct videobuf_vmalloc_memory *mem=vb->priv;
BUG_ON(!mem);
- MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
- pages = PAGE_ALIGN(vb->size) >> PAGE_SHIFT;
+ switch (vb->memory) {
+ case V4L2_MEMORY_MMAP:
+ dprintk(1, "%s memory method MMAP\n", __func__);
- /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
- if ((vb->memory != V4L2_MEMORY_MMAP) &&
- (vb->memory != V4L2_MEMORY_USERPTR) ) {
- printk(KERN_ERR "Method currently unsupported.\n");
- return -EINVAL;
- }
+ /* All handling should be done by __videobuf_mmap_mapper() */
+ if (!mem->vmalloc) {
+ printk(KERN_ERR "memory is not alloced/mmapped.\n");
+ return -EINVAL;
+ }
+ break;
+ case V4L2_MEMORY_USERPTR:
+ pages = PAGE_ALIGN(vb->size);
- /* FIXME: should be tested with kernel mmap mem */
- mem->vmalloc=vmalloc_user (PAGE_ALIGN(vb->size));
- if (NULL == mem->vmalloc) {
- printk(KERN_ERR "vmalloc (%d pages) failed\n",pages);
- return -ENOMEM;
- }
+ dprintk(1, "%s memory method USERPTR\n", __func__);
- dprintk(1,"vmalloc is at addr 0x%08lx, size=%d\n",
- (unsigned long)mem->vmalloc,
- pages << PAGE_SHIFT);
+#if 1
+ if (vb->baddr) {
+ printk(KERN_ERR "USERPTR is currently not supported\n");
+ return -EINVAL;
+ }
+#endif
- /* 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;
+ /* The only USERPTR currently supported is the one needed for
+ read() method.
+ */
+
+ mem->vmalloc = vmalloc_user(pages);
+ if (!mem->vmalloc) {
+ printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
+ return -ENOMEM;
+ }
+ dprintk(1, "vmalloc is at addr %p (%d pages)\n",
+ mem->vmalloc, pages);
+
+#if 0
+ int rc;
+ /* Kernel userptr is used also by read() method. In this case,
+ there's no need to remap, since data will be copied to user
+ */
+ if (!vb->baddr)
+ return 0;
+
+ /* FIXME: to properly support USERPTR, remap should occur.
+ The code bellow won't work, since mem->vma = NULL
+ */
+ /* Try to remap memory */
+ rc = remap_vmalloc_range(mem->vma, (void *)vb->baddr, 0);
+ if (rc < 0) {
+ printk(KERN_ERR "mmap: remap failed with error %d. ", rc);
+ return -ENOMEM;
}
+#endif
+
+ break;
+ case V4L2_MEMORY_OVERLAY:
+ default:
+ dprintk(1, "%s memory method OVERLAY/unknown\n", __func__);
+
+ /* Currently, doesn't support V4L2_MEMORY_OVERLAY */
+ printk(KERN_ERR "Memory method currently unsupported.\n");
+ return -EINVAL;
}
return 0;
@@ -180,6 +236,7 @@ static int __videobuf_mmap_free(struct videobuf_queue *q)
{
unsigned int i;
+ dprintk(1, "%s\n", __func__);
for (i = 0; i < VIDEO_MAX_FRAME; i++) {
if (q->bufs[i]) {
if (q->bufs[i]->map)
@@ -196,10 +253,11 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
struct videobuf_vmalloc_memory *mem;
struct videobuf_mapping *map;
unsigned int first;
- int retval;
+ int retval, pages;
unsigned long offset = vma->vm_pgoff << PAGE_SHIFT;
- if (! (vma->vm_flags & VM_WRITE) || ! (vma->vm_flags & VM_SHARED))
+ dprintk(1, "%s\n", __func__);
+ if (!(vma->vm_flags & VM_WRITE) || !(vma->vm_flags & VM_SHARED))
return -EINVAL;
/* look for first buffer to map */
@@ -219,46 +277,55 @@ static int __videobuf_mmap_mapper(struct videobuf_queue *q,
}
/* create mapping + update buffer list */
- map = q->bufs[first]->map = kzalloc(sizeof(struct videobuf_mapping),GFP_KERNEL);
+ map = kzalloc(sizeof(struct videobuf_mapping), GFP_KERNEL);
if (NULL == map)
return -ENOMEM;
+ q->bufs[first]->map = map;
map->start = vma->vm_start;
map->end = vma->vm_end;
map->q = q;
q->bufs[first]->baddr = vma->vm_start;
- vma->vm_ops = &videobuf_vm_ops;
- vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
- vma->vm_private_data = map;
+ mem = q->bufs[first]->priv;
+ BUG_ON(!mem);
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
- mem=q->bufs[first]->priv;
- BUG_ON (!mem);
- MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+ pages = PAGE_ALIGN(vma->vm_end - vma->vm_start);
+ mem->vmalloc = vmalloc_user(pages);
+ if (!mem->vmalloc) {
+ printk(KERN_ERR "vmalloc (%d pages) failed\n", pages);
+ goto error;
+ }
+ dprintk(1, "vmalloc is at addr %p (%d pages)\n",
+ mem->vmalloc, pages);
/* 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));
+ retval = remap_vmalloc_range(vma, mem->vmalloc, 0);
+ if (retval < 0) {
+ printk(KERN_ERR "mmap: remap failed with error %d. ", retval);
+ vfree(mem->vmalloc);
+ goto error;
}
+ vma->vm_ops = &videobuf_vm_ops;
+ vma->vm_flags |= VM_DONTEXPAND | VM_RESERVED;
+ vma->vm_private_data = map;
+
dprintk(1,"mmap %p: q=%p %08lx-%08lx (%lx) pgoff %08lx buf %d\n",
- map,q,vma->vm_start,vma->vm_end,
+ map, q, vma->vm_start, vma->vm_end,
(long int) q->bufs[first]->bsize,
- vma->vm_pgoff,first);
+ vma->vm_pgoff, first);
videobuf_vm_open(vma);
- return (0);
+ return 0;
+
+error:
+ mem = NULL;
+ kfree(map);
+ return -ENOMEM;
}
static int __videobuf_copy_to_user ( struct videobuf_queue *q,
@@ -320,6 +387,7 @@ static struct videobuf_qtype_ops qops = {
.mmap_mapper = __videobuf_mmap_mapper,
.video_copy_to_user = __videobuf_copy_to_user,
.copy_stream = __videobuf_copy_stream,
+ .vmalloc = videobuf_to_vmalloc,
};
void videobuf_queue_vmalloc_init(struct videobuf_queue* q,
@@ -349,13 +417,24 @@ EXPORT_SYMBOL_GPL(videobuf_to_vmalloc);
void videobuf_vmalloc_free (struct videobuf_buffer *buf)
{
- struct videobuf_vmalloc_memory *mem=buf->priv;
- BUG_ON (!mem);
+ struct videobuf_vmalloc_memory *mem = buf->priv;
- MAGIC_CHECK(mem->magic,MAGIC_VMAL_MEM);
+ /* mmapped memory can't be freed here, otherwise mmapped region
+ would be released, while still needed. In this case, the memory
+ release should happen inside videobuf_vm_close().
+ So, it should free memory only if the memory were allocated for
+ read() operation.
+ */
+ if ((buf->memory != V4L2_MEMORY_USERPTR) || (buf->baddr == 0))
+ return;
+
+ if (!mem)
+ return;
+
+ MAGIC_CHECK(mem->magic, MAGIC_VMAL_MEM);
vfree(mem->vmalloc);
- mem->vmalloc=NULL;
+ mem->vmalloc = NULL;
return;
}
diff --git a/drivers/media/video/videocodec.c b/drivers/media/video/videocodec.c
index 87951ec8254..cf24956f320 100644
--- a/drivers/media/video/videocodec.c
+++ b/drivers/media/video/videocodec.c
@@ -39,12 +39,13 @@
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
#endif
#include "videocodec.h"
-static int debug = 0;
+static int debug;
module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "Debug level (0-4)");
@@ -320,56 +321,22 @@ videocodec_unregister (const struct videocodec *codec)
}
#ifdef CONFIG_PROC_FS
-/* ============ */
-/* procfs stuff */
-/* ============ */
-
-static char *videocodec_buf = NULL;
-static int videocodec_bufsize = 0;
-
-static int
-videocodec_build_table (void)
+static int proc_videocodecs_show(struct seq_file *m, void *v)
{
struct codec_list *h = codeclist_top;
struct attached_list *a;
- int i = 0, size;
-
- // sum up amount of slaves plus their attached masters
- while (h) {
- i += h->attached + 1;
- h = h->next;
- }
-#define LINESIZE 100
- size = LINESIZE * (i + 1);
- dprintk(3, "videocodec_build table: %d entries, %d bytes\n", i,
- size);
-
- kfree(videocodec_buf);
- videocodec_buf = kmalloc(size, GFP_KERNEL);
-
- if (!videocodec_buf)
- return 0;
-
- i = 0;
- i += scnprintf(videocodec_buf + i, size - 1,
- "<S>lave or attached <M>aster name type flags magic ");
- i += scnprintf(videocodec_buf + i, size -i - 1, "(connected as)\n");
+ seq_printf(m, "<S>lave or attached <M>aster name type flags magic ");
+ seq_printf(m, "(connected as)\n");
h = codeclist_top;
while (h) {
- if (i > (size - LINESIZE))
- break; // security check
- i += scnprintf(videocodec_buf + i, size -i -1,
- "S %32s %04x %08lx %08lx (TEMPLATE)\n",
+ seq_printf(m, "S %32s %04x %08lx %08lx (TEMPLATE)\n",
h->codec->name, h->codec->type,
h->codec->flags, h->codec->magic);
a = h->list;
while (a) {
- if (i > (size - LINESIZE))
- break; // security check
- i += scnprintf(videocodec_buf + i, size -i -1,
- "M %32s %04x %08lx %08lx (%s)\n",
+ seq_printf(m, "M %32s %04x %08lx %08lx (%s)\n",
a->codec->master_data->name,
a->codec->master_data->type,
a->codec->master_data->flags,
@@ -380,54 +347,21 @@ videocodec_build_table (void)
h = h->next;
}
- return i;
+ return 0;
}
-//The definition:
-//typedef int (read_proc_t)(char *page, char **start, off_t off,
-// int count, int *eof, void *data);
-
-static int
-videocodec_info (char *buffer,
- char **buffer_location,
- off_t offset,
- int buffer_length,
- int *eof,
- void *data)
+static int proc_videocodecs_open(struct inode *inode, struct file *file)
{
- int size;
-
- dprintk(3, "videocodec_info: offset: %ld, len %d / size %d\n",
- offset, buffer_length, videocodec_bufsize);
-
- if (offset == 0) {
- videocodec_bufsize = videocodec_build_table();
- }
- if ((offset < 0) || (offset >= videocodec_bufsize)) {
- dprintk(4,
- "videocodec_info: call delivers no result, return 0\n");
- *eof = 1;
- return 0;
- }
-
- if (buffer_length < (videocodec_bufsize - offset)) {
- dprintk(4, "videocodec_info: %ld needed, %d got\n",
- videocodec_bufsize - offset, buffer_length);
- size = buffer_length;
- } else {
- dprintk(4, "videocodec_info: last reading of %ld bytes\n",
- videocodec_bufsize - offset);
- size = videocodec_bufsize - offset;
- *eof = 1;
- }
-
- memcpy(buffer, videocodec_buf + offset, size);
- /* doesn't work... */
- /* copy_to_user(buffer, videocodec_buf+offset, size); */
- /* *buffer_location = videocodec_buf+offset; */
-
- return size;
+ return single_open(file, proc_videocodecs_show, NULL);
}
+
+static const struct file_operations videocodecs_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = proc_videocodecs_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif
/* ===================== */
@@ -444,16 +378,8 @@ videocodec_init (void)
VIDEOCODEC_VERSION);
#ifdef CONFIG_PROC_FS
- videocodec_buf = NULL;
- videocodec_bufsize = 0;
-
- videocodec_proc_entry = create_proc_entry("videocodecs", 0, NULL);
- if (videocodec_proc_entry) {
- videocodec_proc_entry->read_proc = videocodec_info;
- videocodec_proc_entry->write_proc = NULL;
- videocodec_proc_entry->data = NULL;
- videocodec_proc_entry->owner = THIS_MODULE;
- } else {
+ videocodec_proc_entry = proc_create("videocodecs", 0, NULL, &videocodecs_proc_fops);
+ if (!videocodec_proc_entry) {
dprintk(1, KERN_ERR "videocodec: can't init procfs.\n");
}
#endif
@@ -465,7 +391,6 @@ videocodec_exit (void)
{
#ifdef CONFIG_PROC_FS
remove_proc_entry("videocodecs", NULL);
- kfree(videocodec_buf);
#endif
}
diff --git a/drivers/media/video/videodev.c b/drivers/media/video/videodev.c
index 0d9b63762a4..31e8af0ba27 100644
--- a/drivers/media/video/videodev.c
+++ b/drivers/media/video/videodev.c
@@ -18,14 +18,14 @@
#define dbgarg(cmd, fmt, arg...) \
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) { \
- printk (KERN_DEBUG "%s: ", vfd->name); \
+ printk(KERN_DEBUG "%s: ", vfd->name); \
v4l_printk_ioctl(cmd); \
- printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg); \
+ printk(" " fmt, ## arg); \
}
#define dbgarg2(fmt, arg...) \
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) \
- printk (KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
+ printk(KERN_DEBUG "%s: " fmt, vfd->name, ## arg);
#include <linux/module.h>
#include <linux/types.h>
@@ -378,38 +378,45 @@ static const char *v4l2_int_ioctls[] = {
external ioctl messages as well as internal V4L ioctl */
void v4l_printk_ioctl(unsigned int cmd)
{
- char *dir;
+ char *dir, *type;
- switch (_IOC_DIR(cmd)) {
- case _IOC_NONE: dir = "--"; break;
- case _IOC_READ: dir = "r-"; break;
- case _IOC_WRITE: dir = "-w"; break;
- case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
- default: dir = "*ERR*"; break;
- }
switch (_IOC_TYPE(cmd)) {
case 'd':
- printk("v4l2_int ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L2_INT_IOCTLS) ?
- v4l2_int_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
+ if (_IOC_NR(cmd) >= V4L2_INT_IOCTLS) {
+ type = "v4l2_int";
+ break;
+ }
+ printk("%s", v4l2_int_ioctls[_IOC_NR(cmd)]);
+ return;
#ifdef CONFIG_VIDEO_V4L1_COMPAT
case 'v':
- printk("v4l1 ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L1_IOCTLS) ?
- v4l1_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
+ if (_IOC_NR(cmd) >= V4L1_IOCTLS) {
+ type = "v4l1";
+ break;
+ }
+ printk("%s", v4l1_ioctls[_IOC_NR(cmd)]);
+ return;
#endif
case 'V':
- printk("v4l2 ioctl %s, dir=%s (0x%08x)\n",
- (_IOC_NR(cmd) < V4L2_IOCTLS) ?
- v4l2_ioctls[_IOC_NR(cmd)] : "UNKNOWN", dir, cmd);
- break;
-
+ if (_IOC_NR(cmd) >= V4L2_IOCTLS) {
+ type = "v4l2";
+ break;
+ }
+ printk("%s", v4l2_ioctls[_IOC_NR(cmd)]);
+ return;
default:
- printk("unknown ioctl '%c', dir=%s, #%d (0x%08x)\n",
- _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
+ type = "unknown";
+ }
+
+ switch (_IOC_DIR(cmd)) {
+ case _IOC_NONE: dir = "--"; break;
+ case _IOC_READ: dir = "r-"; break;
+ case _IOC_WRITE: dir = "-w"; break;
+ case _IOC_READ | _IOC_WRITE: dir = "rw"; break;
+ default: dir = "*ERR*"; break;
}
+ printk("%s ioctl '%c', dir=%s, #%d (0x%08x)",
+ type, _IOC_TYPE(cmd), dir, _IOC_NR(cmd), cmd);
}
EXPORT_SYMBOL(v4l_printk_ioctl);
@@ -774,6 +781,7 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
if ( (vfd->debug & V4L2_DEBUG_IOCTL) &&
!(vfd->debug & V4L2_DEBUG_IOCTL_ARG)) {
v4l_print_ioctl(vfd->name, cmd);
+ printk("\n");
}
#ifdef CONFIG_VIDEO_V4L1_COMPAT
@@ -1853,12 +1861,20 @@ static int __video_do_ioctl(struct inode *inode, struct file *file,
dbgarg (cmd, "chip_ident=%u, revision=0x%x\n", p->ident, p->revision);
break;
}
+ default:
+ {
+ if (!vfd->vidioc_default)
+ break;
+ ret = vfd->vidioc_default(file, fh, cmd, arg);
+ break;
+ }
} /* switch */
if (vfd->debug & V4L2_DEBUG_IOCTL_ARG) {
if (ret<0) {
- printk ("%s: err:\n", vfd->name);
+ printk("%s: err: on ", vfd->name);
v4l_print_ioctl(vfd->name, cmd);
+ printk("\n");
}
}
@@ -2019,7 +2035,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
break;
default:
printk(KERN_ERR "%s called with unknown type: %d\n",
- __FUNCTION__, type);
+ __func__, type);
return -1;
}
@@ -2057,7 +2073,7 @@ int video_register_device(struct video_device *vfd, int type, int nr)
ret = device_register(&vfd->class_dev);
if (ret < 0) {
printk(KERN_ERR "%s: device_register failed\n",
- __FUNCTION__);
+ __func__);
goto fail_minor;
}
diff --git a/drivers/media/video/vino.c b/drivers/media/video/vino.c
index 5bb75294b5a..d545c98dd5e 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 1db067c0281..b1e9592acb9 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,107 +372,71 @@ 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);
+
+ /* Nobody is waiting on this buffer, return */
+ if (!waitqueue_active(&buf->vb.done))
+ goto unlock;
- do_gettimeofday(&buf->vb.ts);
- dprintk(dev, 2, "[%p/%d] wakeup\n", buf, buf->vb. i);
+ list_del(&buf->vb.queue);
- /* Fill buffer */
- vivi_fillbuff(dev, buf);
+ do_gettimeofday(&buf->vb.ts);
- 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);
+ /* 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__,
+ dprintk(dev, 1, "%s dma_q=0x%08lx\n", __func__,
(unsigned long)dma_q);
add_wait_queue(&dma_q->wq, &wait);
if (kthread_should_stop())
goto stop_task;
- 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;
-
- 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);
+ timeout = msecs_to_jiffies(frames_to_ms(1));
- 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__);
+ dprintk(dev, 1, "%s\n", __func__);
- 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");
@@ -519,7 +483,7 @@ static int vivi_start_thread(struct vivi_dmaqueue *dma_q)
/* Wakes thread */
wake_up_interruptible(&dma_q->wq);
- dprintk(dev, 1, "returning from %s\n", __FUNCTION__);
+ dprintk(dev, 1, "returning from %s\n", __func__);
return 0;
}
@@ -527,7 +491,7 @@ static void vivi_stop_thread(struct vivi_dmaqueue *dma_q)
{
struct vivi_dev *dev = container_of(dma_q, struct vivi_dev, vidq);
- dprintk(dev, 1, "%s\n", __FUNCTION__);
+ dprintk(dev, 1, "%s\n", __func__);
/* shutdown control thread */
if (dma_q->kthread) {
kthread_stop(dma_q->kthread);
@@ -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
------------------------------------------------------------------*/
@@ -637,7 +516,7 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
while (*size * *count > vid_limit * 1024 * 1024)
(*count)--;
- dprintk(dev, 1, "%s, count=%d, size=%d\n", __FUNCTION__,
+ dprintk(dev, 1, "%s, count=%d, size=%d\n", __func__,
*count, *size);
return 0;
@@ -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", __func__, buf->vb.state);
if (in_interrupt())
BUG();
- videobuf_waiton(&buf->vb, 0, 0);
videobuf_vmalloc_free(&buf->vb);
+ dprintk(dev, 1, "free_buffer: freed\n");
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);
+ dprintk(dev, 1, "%s, field=%d\n", __func__, 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", __func__);
+
+ buf->vb.state = VIDEOBUF_QUEUED;
+ list_add_tail(&buf->vb.queue, &vidq->active);
}
static void buffer_release(struct videobuf_queue *vq,
@@ -758,11 +601,8 @@ 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);
+ dprintk(dev, 1, "%s\n", __func__);
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", __func__);
+ 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;
}
@@ -1106,7 +974,7 @@ vivi_poll(struct file *file, struct poll_table_struct *wait)
struct vivi_dev *dev = fh->dev;
struct videobuf_queue *q = &fh->vb_vidq;
- dprintk(dev, 1, "%s\n", __FUNCTION__);
+ dprintk(dev, 1, "%s\n", __func__);
if (V4L2_BUF_TYPE_VIDEO_CAPTURE != fh->type)
return POLLERR;
@@ -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 a9133858e91..35293029da0 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 08aaae07c7e..33f702698a5 100644
--- a/drivers/media/video/w9966.c
+++ b/drivers/media/video/w9966.c
@@ -61,10 +61,10 @@
#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)
+#define DPRINTF(x, a...) printk(KERN_DEBUG "W9966: %s(): "x, __func__ , ##a)
#else
#define DPRINTF(x...)
#endif
@@ -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 2ae1430f5f7..840522442d0 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/w9968cf.h b/drivers/media/video/w9968cf.h
index ec7696e8f1f..3c95316bc03 100644
--- a/drivers/media/video/w9968cf.h
+++ b/drivers/media/video/w9968cf.h
@@ -298,7 +298,7 @@ struct w9968cf_device {
dev_warn(&cam->dev, fmt "\n", ## args); \
else if ((level) >= 5) \
dev_info(&cam->dev, "[%s:%d] " fmt "\n", \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
}
/* For generic kernel (not device specific) messages */
@@ -309,7 +309,7 @@ struct w9968cf_device {
if ((level) >= 1 && (level) <= 4) \
pr_info("w9968cf: " fmt "\n", ## args); \
else if ((level) >= 5) \
- pr_debug("w9968cf: [%s:%d] " fmt "\n", __FUNCTION__, \
+ pr_debug("w9968cf: [%s:%d] " fmt "\n", __func__, \
__LINE__ , ## args); \
} \
}
@@ -321,7 +321,7 @@ struct w9968cf_device {
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->dev, "[%s:%d] " fmt "\n", __FUNCTION__, __LINE__ , ## args);
+dev_info(&cam->dev, "[%s:%d] " fmt "\n", __func__, __LINE__ , ## args);
#undef PDBGG
#define PDBGG(fmt, args...) do {;} while(0); /* nothing: it's a placeholder */
diff --git a/drivers/media/video/zc0301/zc0301.h b/drivers/media/video/zc0301/zc0301.h
index a2de50efa31..7bbab541a30 100644
--- a/drivers/media/video/zc0301/zc0301.h
+++ b/drivers/media/video/zc0301/zc0301.h
@@ -160,7 +160,7 @@ do { \
dev_info(&cam->usbdev->dev, fmt "\n", ## args); \
else if ((level) >= 3) \
dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", \
- __FILE__, __FUNCTION__, __LINE__ , ## args); \
+ __FILE__, __func__, __LINE__ , ## args); \
} \
} while (0)
# define KDBG(level, fmt, args...) \
@@ -170,7 +170,7 @@ do { \
pr_info("zc0301: " fmt "\n", ## args); \
else if ((level) == 3) \
pr_debug("sn9c102: [%s:%s:%d] " fmt "\n", __FILE__, \
- __FUNCTION__, __LINE__ , ## args); \
+ __func__, __LINE__ , ## args); \
} \
} while (0)
# define V4LDBG(level, name, cmd) \
@@ -186,7 +186,7 @@ do { \
#undef PDBG
#define PDBG(fmt, args...) \
-dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __FUNCTION__, \
+dev_info(&cam->usbdev->dev, "[%s:%s:%d] " fmt "\n", __FILE__, __func__, \
__LINE__ , ## args)
#undef PDBGG
diff --git a/drivers/media/video/zc0301/zc0301_core.c b/drivers/media/video/zc0301/zc0301_core.c
index 2c5665c8244..363dd2b9475 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.h b/drivers/media/video/zoran.h
index 498a43c1f2b..81cc3b00a07 100644
--- a/drivers/media/video/zoran.h
+++ b/drivers/media/video/zoran.h
@@ -243,10 +243,8 @@ struct zoran_format {
#ifdef CONFIG_VIDEO_V4L1_COMPAT
int palette;
#endif
-#ifdef CONFIG_VIDEO_V4L2
__u32 fourcc;
int colorspace;
-#endif
int depth;
__u32 flags;
__u32 vfespfr;
@@ -271,20 +269,6 @@ struct zoran_v4l_settings {
const struct zoran_format *format; /* capture format */
};
-/* whoops, this one is undeclared if !v4l2 */
-#ifndef CONFIG_VIDEO_V4L2
-struct v4l2_jpegcompression {
- int quality;
- int APPn;
- int APP_len;
- char APP_data[60];
- int COM_len;
- char COM_data[60];
- __u32 jpeg_markers;
- __u8 reserved[116];
-};
-#endif
-
/* jpg-capture/-playback settings */
struct zoran_jpg_settings {
int decimation; /* this bit is used to set everything to default */
diff --git a/drivers/media/video/zoran_card.c b/drivers/media/video/zoran_card.c
index 690281bb59e..006d48847e2 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 8444ca0a5f3..1b5c4171cf9 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 f97c2069205..7b60533efe4 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 fea4946ee71..0134bec1e39 100644
--- a/drivers/media/video/zoran_driver.c
+++ b/drivers/media/video/zoran_driver.c
@@ -85,7 +85,6 @@
#include "zoran_device.h"
#include "zoran_card.h"
-#ifdef CONFIG_VIDEO_V4L2
/* we declare some card type definitions here, they mean
* the same as the v4l1 ZORAN_VID_TYPE above, except it's v4l2 */
#define ZORAN_V4L2_VID_FLAGS ( \
@@ -94,19 +93,15 @@
V4L2_CAP_VIDEO_OUTPUT |\
V4L2_CAP_VIDEO_OVERLAY \
)
-#endif
#include <asm/byteorder.h>
-#if defined(CONFIG_VIDEO_V4L2) && defined(CONFIG_VIDEO_V4L1_COMPAT)
+#if defined(CONFIG_VIDEO_V4L1_COMPAT)
#define ZFMT(pal, fcc, cs) \
.palette = (pal), .fourcc = (fcc), .colorspace = (cs)
-#elif defined(CONFIG_VIDEO_V4L2)
-#define ZFMT(pal, fcc, cs) \
- .fourcc = (fcc), .colorspace = (cs)
#else
#define ZFMT(pal, fcc, cs) \
- .palette = (pal)
+ .fourcc = (fcc), .colorspace = (cs)
#endif
const struct zoran_format zoran_formats[] = {
@@ -205,11 +200,10 @@ 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)");
-#ifdef CONFIG_VIDEO_V4L2
/* small helper function for calculating buffersizes for v4l2
* we calculate the nearest higher power-of-two, which
* will be the recommended buffersize */
@@ -232,7 +226,6 @@ zoran_v4l2_calc_bufsize (struct zoran_jpg_settings *settings)
return 8192;
return result;
}
-#endif
/* forward references */
static void v4l_fbuffer_free(struct file *file);
@@ -1709,7 +1702,6 @@ setup_overlay (struct file *file,
return wait_grab_pending(zr);
}
-#ifdef CONFIG_VIDEO_V4L2
/* get the status of a buffer in the clients buffer queue */
static int
zoran_v4l2_buffer_status (struct file *file,
@@ -1815,7 +1807,6 @@ zoran_v4l2_buffer_status (struct file *file,
return 0;
}
-#endif
static int
zoran_set_norm (struct zoran *zr,
@@ -2624,8 +2615,6 @@ zoran_do_ioctl (struct inode *inode,
}
break;
-#ifdef CONFIG_VIDEO_V4L2
-
/* The new video4linux2 capture interface - much nicer than video4linux1, since
* it allows for integrating the JPEG capturing calls inside standard v4l2
*/
@@ -4197,7 +4186,6 @@ zoran_do_ioctl (struct inode *inode,
return 0;
}
break;
-#endif
default:
dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
@@ -4247,7 +4235,7 @@ zoran_poll (struct file *file,
dprintk(3,
KERN_DEBUG
"%s: %s() raw - active=%c, sync_tail=%lu/%c, pend_tail=%lu, pend_head=%lu\n",
- ZR_DEVNAME(zr), __FUNCTION__,
+ ZR_DEVNAME(zr), __func__,
"FAL"[fh->v4l_buffers.active], zr->v4l_sync_tail,
"UPMD"[zr->v4l_buffers.buffer[frame].state],
zr->v4l_pend_tail, zr->v4l_pend_head);
@@ -4269,7 +4257,7 @@ zoran_poll (struct file *file,
dprintk(3,
KERN_DEBUG
"%s: %s() jpg - active=%c, que_tail=%lu/%c, que_head=%lu, dma=%lu/%lu\n",
- ZR_DEVNAME(zr), __FUNCTION__,
+ ZR_DEVNAME(zr), __func__,
"FAL"[fh->jpg_buffers.active], zr->jpg_que_tail,
"UPMD"[zr->jpg_buffers.buffer[frame].state],
zr->jpg_que_head, zr->jpg_dma_tail, zr->jpg_dma_head);
@@ -4644,7 +4632,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,
@@ -4655,9 +4645,7 @@ static const struct file_operations zoran_fops = {
struct video_device zoran_template __devinitdata = {
.name = ZORAN_NAME,
.type = ZORAN_VID_TYPE,
-#ifdef CONFIG_VIDEO_V4L2
.type2 = ZORAN_V4L2_VID_FLAGS,
-#endif
.fops = &zoran_fops,
.release = &zoran_vdev_release,
.minor = -1
diff --git a/drivers/media/video/zr36016.c b/drivers/media/video/zr36016.c
index dd084555da8..00d132bcd1e 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 faae4ec3ea0..cf8b271a1c8 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 7849b65969d..8e74054d5ef 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 04949c82365..a0e49dc6630 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 */