summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--linux/Documentation/video4linux/CARDLIST.au08284
-rw-r--r--linux/Documentation/video4linux/CARDLIST.cx238852
-rwxr-xr-xlinux/Documentation/video4linux/extract_xc3028.pl46
-rw-r--r--linux/arch/arm/mach-pxa/devices.c32
-rw-r--r--linux/arch/arm/mach-pxa/pcm990-baseboard.c86
-rw-r--r--linux/drivers/media/Kconfig9
-rw-r--r--linux/drivers/media/common/ir-keymaps.c6
-rw-r--r--linux/drivers/media/common/saa7146_core.c13
-rw-r--r--linux/drivers/media/common/saa7146_fops.c2
-rw-r--r--linux/drivers/media/dvb/b2c2/Kconfig2
-rw-r--r--linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c48
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_net.c4
-rw-r--r--linux/drivers/media/dvb/dvb-usb/cxusb.c3
-rw-r--r--linux/drivers/media/dvb/frontends/Kconfig21
-rw-r--r--linux/drivers/media/dvb/frontends/Makefile3
-rw-r--r--linux/drivers/media/dvb/frontends/au8522.c698
-rw-r--r--linux/drivers/media/dvb/frontends/au8522.h56
-rw-r--r--linux/drivers/media/dvb/frontends/itd1000.c408
-rw-r--r--linux/drivers/media/dvb/frontends/itd1000.h42
-rw-r--r--linux/drivers/media/dvb/frontends/itd1000_priv.h88
-rw-r--r--linux/drivers/media/dvb/frontends/mt312.c145
-rw-r--r--linux/drivers/media/dvb/frontends/mt312.h3
-rw-r--r--linux/drivers/media/dvb/frontends/mt312_priv.h5
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1420.c542
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1420.h62
-rw-r--r--linux/drivers/media/dvb/frontends/s5h1420_priv.h380
-rw-r--r--linux/drivers/media/dvb/frontends/tda10048.c710
-rw-r--r--linux/drivers/media/dvb/frontends/tda10048.h63
-rw-r--r--linux/drivers/media/dvb/ttpci/budget.c1
-rw-r--r--linux/drivers/media/radio/radio-si470x.c16
-rw-r--r--linux/drivers/media/radio/radio-typhoon.c40
-rw-r--r--linux/drivers/media/video/Kconfig2
-rw-r--r--linux/drivers/media/video/Makefile2
-rw-r--r--linux/drivers/media/video/adv7170.c2
-rw-r--r--linux/drivers/media/video/adv7175.c2
-rw-r--r--linux/drivers/media/video/au0828/Kconfig13
-rw-r--r--linux/drivers/media/video/au0828/Makefile9
-rw-r--r--linux/drivers/media/video/au0828/au0828-cards.c182
-rw-r--r--linux/drivers/media/video/au0828/au0828-cards.h26
-rw-r--r--linux/drivers/media/video/au0828/au0828-core.c277
-rw-r--r--linux/drivers/media/video/au0828/au0828-dvb.c402
-rw-r--r--linux/drivers/media/video/au0828/au0828-i2c.c388
-rw-r--r--linux/drivers/media/video/au0828/au0828-reg.h38
-rw-r--r--linux/drivers/media/video/au0828/au0828.h137
-rw-r--r--linux/drivers/media/video/bt819.c2
-rw-r--r--linux/drivers/media/video/bt856.c2
-rw-r--r--linux/drivers/media/video/bt8xx/bttv-driver.c3
-rw-r--r--linux/drivers/media/video/c-qcam.c7
-rw-r--r--linux/drivers/media/video/cx23885/Kconfig2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-cards.c66
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-core.c2
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-dvb.c30
-rw-r--r--linux/drivers/media/video/cx23885/cx23885-i2c.c1
-rw-r--r--linux/drivers/media/video/cx23885/cx23885.h2
-rw-r--r--linux/drivers/media/video/cx25840/cx25840-core.c6
-rw-r--r--linux/drivers/media/video/cx88/cx88-cards.c4
-rw-r--r--linux/drivers/media/video/cx88/cx88-dvb.c3
-rw-r--r--linux/drivers/media/video/dpc7146.c2
-rw-r--r--linux/drivers/media/video/em28xx/Kconfig15
-rw-r--r--linux/drivers/media/video/em28xx/Makefile1
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-cards.c205
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-core.c418
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-dvb.c506
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-i2c.c154
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-input.c28
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-reg.h88
-rw-r--r--linux/drivers/media/video/em28xx/em28xx-video.c352
-rw-r--r--linux/drivers/media/video/em28xx/em28xx.h235
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-fileops.c4
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-mailbox.c11
-rw-r--r--linux/drivers/media/video/ivtv/ivtv-streams.c3
-rw-r--r--linux/drivers/media/video/msp3400-driver.c4
-rw-r--r--linux/drivers/media/video/mxb.c5
-rw-r--r--linux/drivers/media/video/ov511.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c4
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c6
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-io.c2
-rw-r--r--linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c2
-rw-r--r--linux/drivers/media/video/pwc/pwc-if.c7
-rw-r--r--linux/drivers/media/video/saa7110.c4
-rw-r--r--linux/drivers/media/video/saa7111.c2
-rw-r--r--linux/drivers/media/video/saa7114.c2
-rw-r--r--linux/drivers/media/video/saa717x.c1
-rw-r--r--linux/drivers/media/video/saa7185.c2
-rw-r--r--linux/drivers/media/video/tda9840.c2
-rw-r--r--linux/drivers/media/video/tea6415c.c2
-rw-r--r--linux/drivers/media/video/tea6420.c2
-rw-r--r--linux/drivers/media/video/tuner-core.c2
-rw-r--r--linux/drivers/media/video/tuner-xc2028-types.h26
-rw-r--r--linux/drivers/media/video/tuner-xc2028.c55
-rw-r--r--linux/drivers/media/video/tuner-xc2028.h4
-rw-r--r--linux/drivers/media/video/tvp5150.c4
-rw-r--r--linux/drivers/media/video/usbvideo/ibmcam.c62
-rw-r--r--linux/drivers/media/video/videocodec.c113
-rw-r--r--linux/drivers/media/video/zoran.h16
-rw-r--r--linux/drivers/media/video/zoran_driver.c20
-rw-r--r--linux/drivers/media/video/zr364xx.c2
-rw-r--r--linux/include/asm-arm/arch-pxa/pxa-regs.h80
-rw-r--r--linux/include/linux/i2c-id.h1
-rwxr-xr-xmailimport5
-rw-r--r--v4l/compat.h40
-rwxr-xr-xv4l/scripts/au0828.pl48
-rwxr-xr-xv4l/scripts/cardlist5
-rwxr-xr-xv4l/scripts/checkpatch.pl750
-rw-r--r--v4l/versions.txt3
105 files changed, 6844 insertions, 1613 deletions
diff --git a/linux/Documentation/video4linux/CARDLIST.au0828 b/linux/Documentation/video4linux/CARDLIST.au0828
new file mode 100644
index 000000000..aaae36031
--- /dev/null
+++ b/linux/Documentation/video4linux/CARDLIST.au0828
@@ -0,0 +1,4 @@
+ 0 -> Unknown board (au0828)
+ 1 -> Hauppauge HVR950Q (au0828) [2040:7200]
+ 2 -> Hauppauge HVR850 (au0828) [2040:7240]
+ 3 -> DViCO FusionHDTV USB (au0828) [0fe9:d620]
diff --git a/linux/Documentation/video4linux/CARDLIST.cx23885 b/linux/Documentation/video4linux/CARDLIST.cx23885
index 0924e6e14..b057a3c9f 100644
--- a/linux/Documentation/video4linux/CARDLIST.cx23885
+++ b/linux/Documentation/video4linux/CARDLIST.cx23885
@@ -5,3 +5,5 @@
4 -> DViCO FusionHDTV5 Express [18ac:d500]
5 -> Hauppauge WinTV-HVR1500Q [0070:7790,0070:7797]
6 -> Hauppauge WinTV-HVR1500 [0070:7710,0070:7717]
+ 7 -> Hauppauge WinTV-HVR1200 [0070:71d1]
+ 8 -> Hauppauge WinTV-HVR1700 [0070:8101]
diff --git a/linux/Documentation/video4linux/extract_xc3028.pl b/linux/Documentation/video4linux/extract_xc3028.pl
index cced8ac5c..2cb816047 100755
--- a/linux/Documentation/video4linux/extract_xc3028.pl
+++ b/linux/Documentation/video4linux/extract_xc3028.pl
@@ -686,11 +686,11 @@ sub main_firmware($$$$)
write_hunk(812664, 192);
#
- # Firmware 58, type: SCODE FW HAS IF (0x60000000), IF = 4.50 MHz id: NTSC/M Jp (0000000000002000), size: 192
+ # Firmware 58, type: SCODE FW MTS LCD NOGD MONO IF HAS IF (0x6002b004), IF = 4.50 MHz id: NTSC PAL/M PAL/N (000000000000b700), size: 192
#
- write_le32(0x60000000); # Type
- write_le64(0x00000000, 0x00002000); # ID
+ write_le32(0x6002b004); # Type
+ write_le64(0x00000000, 0x0000b700); # ID
write_le16(4500); # IF
write_le32(192); # Size
write_hunk(807672, 192);
@@ -706,10 +706,10 @@ sub main_firmware($$$$)
write_hunk(807864, 192);
#
- # Firmware 60, type: SCODE FW DTV78 ZARLINK456 HAS IF (0x62000100), IF = 4.76 MHz id: (0000000000000000), size: 192
+ # Firmware 60, type: SCODE FW DTV6 QAM DTV7 DTV78 DTV8 ZARLINK456 HAS IF (0x620003e0), IF = 4.76 MHz id: (0000000000000000), size: 192
#
- write_le32(0x62000100); # Type
+ write_le32(0x620003e0); # Type
write_le64(0x00000000, 0x00000000); # ID
write_le16(4760); # IF
write_le32(192); # Size
@@ -726,30 +726,30 @@ sub main_firmware($$$$)
write_hunk(811512, 192);
#
- # Firmware 62, type: SCODE FW DTV7 ZARLINK456 HAS IF (0x62000080), IF = 5.26 MHz id: (0000000000000000), size: 192
+ # Firmware 62, type: SCODE FW HAS IF (0x60000000), IF = 5.26 MHz id: (0000000000000000), size: 192
#
- write_le32(0x62000080); # Type
+ write_le32(0x60000000); # Type
write_le64(0x00000000, 0x00000000); # ID
write_le16(5260); # IF
write_le32(192); # Size
write_hunk(810552, 192);
#
- # Firmware 63, type: SCODE FW MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192
+ # Firmware 63, type: SCODE FW MONO HAS IF (0x60008000), IF = 5.32 MHz id: PAL/BG A2 NICAM (0000000f00000007), size: 192
#
write_le32(0x60008000); # Type
- write_le64(0x00000008, 0x00000007); # ID
+ write_le64(0x0000000f, 0x00000007); # ID
write_le16(5320); # IF
write_le32(192); # Size
write_hunk(810744, 192);
#
- # Firmware 64, type: SCODE FW DTV8 CHINA HAS IF (0x64000200), IF = 5.40 MHz id: (0000000000000000), size: 192
+ # Firmware 64, type: SCODE FW DTV7 DTV78 DTV8 DIBCOM52 CHINA HAS IF (0x65000380), IF = 5.40 MHz id: (0000000000000000), size: 192
#
- write_le32(0x64000200); # Type
+ write_le32(0x65000380); # Type
write_le64(0x00000000, 0x00000000); # ID
write_le16(5400); # IF
write_le32(192); # Size
@@ -766,50 +766,50 @@ sub main_firmware($$$$)
write_hunk(809592, 192);
#
- # Firmware 66, type: SCODE FW HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2/B (0000000200000007), size: 192
+ # Firmware 66, type: SCODE FW HAS IF (0x60000000), IF = 5.64 MHz id: PAL/BG A2 (0000000300000007), size: 192
#
write_le32(0x60000000); # Type
- write_le64(0x00000002, 0x00000007); # ID
+ write_le64(0x00000003, 0x00000007); # ID
write_le16(5640); # IF
write_le32(192); # Size
write_hunk(808440, 192);
#
- # Firmware 67, type: SCODE FW HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM/B (0000000800000007), size: 192
+ # Firmware 67, type: SCODE FW HAS IF (0x60000000), IF = 5.74 MHz id: PAL/BG NICAM (0000000c00000007), size: 192
#
write_le32(0x60000000); # Type
- write_le64(0x00000008, 0x00000007); # ID
+ write_le64(0x0000000c, 0x00000007); # ID
write_le16(5740); # IF
write_le32(192); # Size
write_hunk(808632, 192);
#
- # Firmware 68, type: SCODE FW DTV7 DIBCOM52 HAS IF (0x61000080), IF = 5.90 MHz id: (0000000000000000), size: 192
+ # Firmware 68, type: SCODE FW HAS IF (0x60000000), IF = 5.90 MHz id: (0000000000000000), size: 192
#
- write_le32(0x61000080); # Type
+ write_le32(0x60000000); # Type
write_le64(0x00000000, 0x00000000); # ID
write_le16(5900); # IF
write_le32(192); # Size
write_hunk(810360, 192);
#
- # Firmware 69, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/I (0000000000000010), size: 192
+ # Firmware 69, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.00 MHz id: PAL/DK PAL/I SECAM/K3 SECAM/L SECAM/Lc NICAM (0000000c04c000f0), size: 192
#
write_le32(0x60008000); # Type
- write_le64(0x00000000, 0x00000010); # ID
+ write_le64(0x0000000c, 0x04c000f0); # ID
write_le16(6000); # IF
write_le32(192); # Size
write_hunk(808824, 192);
#
- # Firmware 70, type: SCODE FW DTV6 QAM F6MHZ HAS IF (0x68000060), IF = 6.20 MHz id: (0000000000000000), size: 192
+ # Firmware 70, type: SCODE FW DTV6 QAM ATSC LG60 F6MHZ HAS IF (0x68050060), IF = 6.20 MHz id: (0000000000000000), size: 192
#
- write_le32(0x68000060); # Type
+ write_le32(0x68050060); # Type
write_le64(0x00000000, 0x00000000); # ID
write_le16(6200); # IF
write_le32(192); # Size
@@ -846,11 +846,11 @@ sub main_firmware($$$$)
write_hunk(809208, 192);
#
- # Firmware 74, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.50 MHz id: SECAM/K3 (0000000004000000), size: 192
+ # Firmware 74, type: SCODE FW MONO HAS IF (0x60008000), IF = 6.50 MHz id: PAL/DK SECAM/K3 SECAM/L NICAM (0000000c044000e0), size: 192
#
write_le32(0x60008000); # Type
- write_le64(0x00000000, 0x04000000); # ID
+ write_le64(0x0000000c, 0x044000e0); # ID
write_le16(6500); # IF
write_le32(192); # Size
write_hunk(811128, 192);
diff --git a/linux/arch/arm/mach-pxa/devices.c b/linux/arch/arm/mach-pxa/devices.c
index 3838aabdf..bfccb80ac 100644
--- a/linux/arch/arm/mach-pxa/devices.c
+++ b/linux/arch/arm/mach-pxa/devices.c
@@ -11,7 +11,6 @@
#include <asm/arch/irda.h>
#include <asm/arch/i2c.h>
#include <asm/arch/ohci.h>
-#include <asm/arch/camera.h>
#include "devices.h"
@@ -541,37 +540,6 @@ struct platform_device pxa27x_device_ssp3 = {
.resource = pxa27x_resource_ssp3,
.num_resources = ARRAY_SIZE(pxa27x_resource_ssp3),
};
-
-static struct resource pxa27x_resource_camera[] = {
- [0] = {
- .start = 0x50000000,
- .end = 0x50000fff,
- .flags = IORESOURCE_MEM,
- },
- [1] = {
- .start = IRQ_CAMERA,
- .end = IRQ_CAMERA,
- .flags = IORESOURCE_IRQ,
- },
-};
-
-static u64 pxa27x_dma_mask_camera = DMA_BIT_MASK(32);
-
-static struct platform_device pxa27x_device_camera = {
- .name = "pxa27x-camera",
- .id = 0, /* This is used to put cameras on this interface */
- .dev = {
- .dma_mask = &pxa27x_dma_mask_camera,
- .coherent_dma_mask = 0xffffffff,
- },
- .num_resources = ARRAY_SIZE(pxa27x_resource_camera),
- .resource = pxa27x_resource_camera,
-};
-
-void __init pxa_set_camera_info(struct pxacamera_platform_data *info)
-{
- pxa_register_device(&pxa27x_device_camera, info);
-}
#endif /* CONFIG_PXA27x || CONFIG_PXA3xx */
#ifdef CONFIG_PXA3xx
diff --git a/linux/arch/arm/mach-pxa/pcm990-baseboard.c b/linux/arch/arm/mach-pxa/pcm990-baseboard.c
index 07ac050f2..3dda16a20 100644
--- a/linux/arch/arm/mach-pxa/pcm990-baseboard.c
+++ b/linux/arch/arm/mach-pxa/pcm990-baseboard.c
@@ -23,13 +23,6 @@
#include <linux/irq.h>
#include <linux/platform_device.h>
#include <linux/ide.h>
-#include <linux/i2c.h>
-
-#include <media/soc_camera.h>
-
-#include <asm/gpio.h>
-#include <asm/arch/i2c.h>
-#include <asm/arch/camera.h>
#include <asm/mach/map.h>
#include <asm/arch/pxa-regs.h>
#include <asm/arch/mmc.h>
@@ -265,76 +258,6 @@ static struct pxaohci_platform_data pcm990_ohci_platform_data = {
};
/*
- * PXA27x Camera specific stuff
- */
-#if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
-static int pcm990_pxacamera_init(struct device *dev)
-{
- pxa_gpio_mode(GPIO98_CIF_DD0_MD);
- pxa_gpio_mode(GPIO105_CIF_DD1_MD);
- pxa_gpio_mode(GPIO104_CIF_DD2_MD);
- pxa_gpio_mode(GPIO103_CIF_DD3_MD);
- pxa_gpio_mode(GPIO95_CIF_DD4_MD);
- pxa_gpio_mode(GPIO94_CIF_DD5_MD);
- pxa_gpio_mode(GPIO93_CIF_DD6_MD);
- pxa_gpio_mode(GPIO108_CIF_DD7_MD);
- pxa_gpio_mode(GPIO107_CIF_DD8_MD);
- pxa_gpio_mode(GPIO106_CIF_DD9_MD);
- pxa_gpio_mode(GPIO42_CIF_MCLK_MD);
- pxa_gpio_mode(GPIO45_CIF_PCLK_MD);
- pxa_gpio_mode(GPIO43_CIF_FV_MD);
- pxa_gpio_mode(GPIO44_CIF_LV_MD);
-
- return 0;
-}
-
-/*
- * CICR4: PCLK_EN: Pixel clock is supplied by the sensor
- * MCLK_EN: Master clock is generated by PXA
- * PCP: Data sampled on the falling edge of pixel clock
- */
-struct pxacamera_platform_data pcm990_pxacamera_platform_data = {
- .init = pcm990_pxacamera_init,
- .flags = PXA_CAMERA_MASTER | PXA_CAMERA_DATAWIDTH_8 | PXA_CAMERA_DATAWIDTH_10 |
- PXA_CAMERA_PCLK_EN | PXA_CAMERA_MCLK_EN/* | PXA_CAMERA_PCP*/,
- .mclk_10khz = 1000,
-};
-
-#include <linux/i2c/pca953x.h>
-
-static struct pca953x_platform_data pca9536_data = {
- .gpio_base = NR_BUILTIN_GPIO + 1,
-};
-
-static struct soc_camera_link iclink[] = {
- {
- .bus_id = 0, /* Must match with the camera ID above */
- .gpio = NR_BUILTIN_GPIO + 1,
- }, {
- .bus_id = 0, /* Must match with the camera ID above */
- }
-};
-
-/* Board I2C devices. */
-static struct i2c_board_info __initdata pcm990_i2c_devices[] = {
- {
- /* Must initialize before the camera(s) */
- I2C_BOARD_INFO("pca953x", 0x41),
- .type = "pca9536",
- .platform_data = &pca9536_data,
- }, {
- I2C_BOARD_INFO("mt9v022", 0x48),
- .type = "mt9v022",
- .platform_data = &iclink[0], /* With extender */
- }, {
- I2C_BOARD_INFO("mt9m001", 0x5d),
- .type = "mt9m001",
- .platform_data = &iclink[0], /* With extender */
- },
-};
-#endif /* CONFIG_VIDEO_PXA27x ||CONFIG_VIDEO_PXA27x_MODULE */
-
-/*
* AC97 support
* Note: The connected AC97 mixer also reports interrupts at PCM990_AC97_IRQ
*/
@@ -403,14 +326,5 @@ void __init pcm990_baseboard_init(void)
/* USB host */
pxa_set_ohci_info(&pcm990_ohci_platform_data);
- pxa_set_i2c_info(NULL);
-
-#if defined(CONFIG_VIDEO_PXA27x) || defined(CONFIG_VIDEO_PXA27x_MODULE)
- pxa_set_camera_info(&pcm990_pxacamera_platform_data);
-
- i2c_register_board_info(0, pcm990_i2c_devices,
- ARRAY_SIZE(pcm990_i2c_devices));
-#endif
-
printk(KERN_INFO"PCM-990 Evaluation baseboard initialized\n");
}
diff --git a/linux/drivers/media/Kconfig b/linux/drivers/media/Kconfig
index 1f7244cff..128bb9cd5 100644
--- a/linux/drivers/media/Kconfig
+++ b/linux/drivers/media/Kconfig
@@ -30,7 +30,7 @@ config VIDEO_V4L2_COMMON
depends on (I2C || I2C=n) && VIDEO_DEV
default (I2C || I2C=n) && VIDEO_DEV
-config VIDEO_V4L1
+config VIDEO_ALLOW_V4L1
bool "Enable Video For Linux API 1 (DEPRECATED)"
depends on VIDEO_DEV && VIDEO_V4L2_COMMON
default VIDEO_DEV && VIDEO_V4L2_COMMON
@@ -59,10 +59,15 @@ config VIDEO_V4L1_COMPAT
If you are unsure as to whether this is required, answer Y.
config VIDEO_V4L2
- bool
+ tristate
depends on VIDEO_DEV && VIDEO_V4L2_COMMON
default VIDEO_DEV && VIDEO_V4L2_COMMON
+config VIDEO_V4L1
+ tristate
+ depends on VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+ default VIDEO_DEV && VIDEO_V4L2_COMMON && VIDEO_ALLOW_V4L1
+
source "drivers/media/video/Kconfig"
source "drivers/media/radio/Kconfig"
diff --git a/linux/drivers/media/common/ir-keymaps.c b/linux/drivers/media/common/ir-keymaps.c
index 4e5db8cd5..64d3df831 100644
--- a/linux/drivers/media/common/ir-keymaps.c
+++ b/linux/drivers/media/common/ir-keymaps.c
@@ -772,7 +772,11 @@ IR_KEYTAB_TYPE ir_codes_flyvideo[IR_KEYTAB_SIZE] = {
[ 0x12 ] = KEY_CHANNELUP, // Channel +
[ 0x13 ] = KEY_CHANNELDOWN, // Channel -
[ 0x06 ] = KEY_AGAIN, // Recall
- [ 0x10 ] = KEY_ENTER, // Enter
+ [ 0x10 ] = KEY_ENTER, // Enter
+
+ [ 0x19 ] = KEY_BACK, // Rewind ( <<< )
+ [ 0x1f ] = KEY_FORWARD, // Forward ( >>> )
+ [ 0x0a ] = KEY_ANGLE, // (no label, may be used as the PAUSE button)
};
EXPORT_SYMBOL_GPL(ir_codes_flyvideo);
diff --git a/linux/drivers/media/common/saa7146_core.c b/linux/drivers/media/common/saa7146_core.c
index 67b7dbc81..973989dd4 100644
--- a/linux/drivers/media/common/saa7146_core.c
+++ b/linux/drivers/media/common/saa7146_core.c
@@ -310,25 +310,22 @@ static irqreturn_t interrupt_hw(int irq, void *dev_id)
return IRQ_NONE;
}
- if( NULL != (dev->ext)) {
- if( 0 != (dev->ext->irq_mask & isr )) {
- if( NULL != dev->ext->irq_func ) {
+ if (dev->ext) {
+ if (dev->ext->irq_mask & isr) {
+ if (dev->ext->irq_func)
dev->ext->irq_func(dev, &isr);
- }
isr &= ~dev->ext->irq_mask;
}
}
if (0 != (isr & (MASK_27))) {
DEB_INT(("irq: RPS0 (0x%08x).\n",isr));
- if( NULL != dev->vv_data && NULL != dev->vv_callback) {
+ if (dev->vv_data && dev->vv_callback)
dev->vv_callback(dev,isr);
- }
isr &= ~MASK_27;
}
if (0 != (isr & (MASK_28))) {
- if( NULL != dev->vv_data && NULL != dev->vv_callback) {
+ if (dev->vv_data && dev->vv_callback)
dev->vv_callback(dev,isr);
- }
isr &= ~MASK_28;
}
if (0 != (isr & (MASK_16|MASK_17))) {
diff --git a/linux/drivers/media/common/saa7146_fops.c b/linux/drivers/media/common/saa7146_fops.c
index fee81488f..ac035cbcf 100644
--- a/linux/drivers/media/common/saa7146_fops.c
+++ b/linux/drivers/media/common/saa7146_fops.c
@@ -273,7 +273,7 @@ static int fops_open(struct inode *inode, struct file *file)
result = 0;
out:
- if( fh != NULL && result != 0 ) {
+ if (fh && result != 0) {
kfree(fh);
file->private_data = NULL;
}
diff --git a/linux/drivers/media/dvb/b2c2/Kconfig b/linux/drivers/media/dvb/b2c2/Kconfig
index 8193d88d1..6ec5afba1 100644
--- a/linux/drivers/media/dvb/b2c2/Kconfig
+++ b/linux/drivers/media/dvb/b2c2/Kconfig
@@ -10,6 +10,8 @@ config DVB_B2C2_FLEXCOP
select DVB_BCM3510 if !DVB_FE_CUSTOMISE
select DVB_LGDT330X if !DVB_FE_CUSTOMISE
select TUNER_SIMPLE if !DVB_FE_CUSTOMISE
+ select DVB_S5H1420 if !DVB_FE_CUSTOMISE
+ select DVB_TUNER_ITD1000 if !DVB_FE_CUSTOMISE
select DVB_ISL6421 if !DVB_FE_CUSTOMISE
select DVB_CX24123 if !DVB_FE_CUSTOMISE
help
diff --git a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
index 6759c3ad2..04989b7a1 100644
--- a/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
+++ b/linux/drivers/media/dvb/b2c2/flexcop-fe-tuner.c
@@ -19,6 +19,9 @@
#include "dvb-pll.h"
#include "tuner-simple.h"
+#include "s5h1420.h"
+#include "itd1000.h"
+
#include "cx24123.h"
#include "cx24113.h"
@@ -482,6 +485,18 @@ static struct stv0297_config alps_tdee4_stv0297_config = {
};
+/* SkyStar2 rev2.7 (a/u) */
+static struct s5h1420_config skystar2_rev2_7_s5h1420_config = {
+ .demod_address = 0x53,
+ .invert = 1,
+ .repeated_start_workaround = 1,
+};
+
+static struct itd1000_config skystar2_rev2_7_itd1000_config = {
+ .i2c_address = 0x61,
+};
+
+/* SkyStar2 rev2.8 */
static struct cx24123_config skystar2_rev2_8_cx24123_config = {
.demod_address = 0x55,
.dont_use_pll = 1,
@@ -500,6 +515,39 @@ int flexcop_frontend_init(struct flexcop_device *fc)
struct i2c_adapter *i2c = &fc->fc_i2c_adap[0].i2c_adap;
struct i2c_adapter *i2c_tuner;
+ /* enable no_base_addr - no repeated start when reading */
+ fc->fc_i2c_adap[0].no_base_addr = 1;
+ fc->fe = dvb_attach(s5h1420_attach, &skystar2_rev2_7_s5h1420_config, i2c);
+ if (fc->fe != NULL) {
+ flexcop_ibi_value r108;
+ i2c_tuner = s5h1420_get_tuner_i2c_adapter(fc->fe);
+ ops = &fc->fe->ops;
+
+ fc->fe_sleep = ops->sleep;
+ ops->sleep = flexcop_sleep;
+
+ fc->dev_type = FC_SKY_REV27;
+
+ /* enable no_base_addr - no repeated start when reading */
+ fc->fc_i2c_adap[2].no_base_addr = 1;
+ if (dvb_attach(isl6421_attach, fc->fe, &fc->fc_i2c_adap[2].i2c_adap, 0x08, 1, 1) == NULL)
+ err("ISL6421 could NOT be attached");
+ else
+ info("ISL6421 successfully attached");
+
+ /* the ITD1000 requires a lower i2c clock - it slows down the stuff for everyone - but is it a problem ? */
+ r108.raw = 0x00000506;
+ fc->write_ibi_reg(fc, tw_sm_c_108, r108);
+ if (i2c_tuner) {
+ if (dvb_attach(itd1000_attach, fc->fe, i2c_tuner, &skystar2_rev2_7_itd1000_config) == NULL)
+ err("ITD1000 could NOT be attached");
+ else
+ info("ITD1000 successfully attached");
+ }
+ goto fe_found;
+ }
+ fc->fc_i2c_adap[0].no_base_addr = 0; /* for the next devices we need it again */
+
/* try the sky v2.8 (cx24123, isl6421) */
fc->fe = dvb_attach(cx24123_attach,
&skystar2_rev2_8_cx24123_config, i2c);
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.c b/linux/drivers/media/dvb/dvb-core/dvb_net.c
index 86b11c3cc..04c9e00b0 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c
@@ -810,8 +810,8 @@ static int dvb_net_ts_callback(const u8 *buffer1, size_t buffer1_len,
{
struct net_device *dev = feed->priv;
- if (buffer2 != 0)
- printk(KERN_WARNING "buffer2 not 0: %p.\n", buffer2);
+ if (buffer2)
+ printk(KERN_WARNING "buffer2 not NULL: %p.\n", buffer2);
if (buffer1_len > 32768)
printk(KERN_WARNING "length > 32k: %zu.\n", buffer1_len);
/* printk("TS callback: %u bytes, %u TS cells @ %p.\n",
diff --git a/linux/drivers/media/dvb/dvb-usb/cxusb.c b/linux/drivers/media/dvb/dvb-usb/cxusb.c
index 8017f1e8a..ddfa0cff7 100644
--- a/linux/drivers/media/dvb/dvb-usb/cxusb.c
+++ b/linux/drivers/media/dvb/dvb-usb/cxusb.c
@@ -33,7 +33,6 @@
#include "mt352_priv.h"
#include "zl10353.h"
#include "tuner-xc2028.h"
-#include "tuner-xc2028-types.h"
#include "tuner-simple.h"
/* debug */
@@ -521,7 +520,7 @@ static int cxusb_dvico_xc3028_tuner_attach(struct dvb_usb_adapter *adap)
static struct xc2028_ctrl ctl = {
.fname = "xc3028-dvico-au-01.fw",
.max_len = 64,
- .scode_table = ZARLINK456,
+ .scode_table = XC3028_FE_ZARLINK456,
};
fe = dvb_attach(xc2028_attach, adap->fe, &cfg);
diff --git a/linux/drivers/media/dvb/frontends/Kconfig b/linux/drivers/media/dvb/frontends/Kconfig
index 0209644f2..68fab616f 100644
--- a/linux/drivers/media/dvb/frontends/Kconfig
+++ b/linux/drivers/media/dvb/frontends/Kconfig
@@ -188,6 +188,14 @@ config DVB_DIB7000P
A DVB-T tuner module. Designed for mobile usage. Say Y when you want
to support this frontend.
+config DVB_TDA10048
+ tristate "Philips TDA10048HN based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ select FW_LOADER
+ help
+ A DVB-T tuner module. Say Y when you want to support this frontend.
+
comment "DVB-C (cable) frontends"
depends on DVB_CORE
@@ -291,6 +299,14 @@ config DVB_S5H1409
An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
to support this frontend.
+config DVB_AU8522
+ tristate "Auvitek AU8522 based"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+ help
+ An ATSC 8VSB and QAM64/256 tuner module. Say Y when you want
+ to support this frontend.
+
comment "Tuners/PLL support"
depends on DVB_CORE
@@ -369,6 +385,11 @@ config DVB_TUNER_XC5000
This device is only used inside a SiP called togther with a
demodulator for now.
+config DVB_TUNER_ITD1000
+ tristate "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
+ depends on DVB_CORE && I2C
+ default m if DVB_FE_CUSTOMISE
+
comment "Miscellaneous devices"
depends on DVB_CORE
diff --git a/linux/drivers/media/dvb/frontends/Makefile b/linux/drivers/media/dvb/frontends/Makefile
index 23304b377..2f873fc0f 100644
--- a/linux/drivers/media/dvb/frontends/Makefile
+++ b/linux/drivers/media/dvb/frontends/Makefile
@@ -52,3 +52,6 @@ obj-$(CONFIG_DVB_TUA6100) += tua6100.o
obj-$(CONFIG_DVB_TUNER_MT2131) += mt2131.o
obj-$(CONFIG_DVB_S5H1409) += s5h1409.o
obj-$(CONFIG_DVB_TUNER_XC5000) += xc5000.o
+obj-$(CONFIG_DVB_TUNER_ITD1000) += itd1000.o
+obj-$(CONFIG_DVB_AU8522) += au8522.o
+obj-$(CONFIG_DVB_TDA10048) += tda10048.o
diff --git a/linux/drivers/media/dvb/frontends/au8522.c b/linux/drivers/media/dvb/frontends/au8522.c
new file mode 100644
index 000000000..d536454b6
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/au8522.c
@@ -0,0 +1,698 @@
+/*
+ Auvitek AU8522 QAM/8VSB demodulator driver
+
+ 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "dvb-pll.h"
+#include "au8522.h"
+
+struct au8522_state {
+
+ struct i2c_adapter *i2c;
+
+ /* configuration settings */
+ const struct au8522_config *config;
+
+ struct dvb_frontend frontend;
+
+ u32 current_frequency;
+ fe_modulation_t current_modulation;
+
+};
+
+static int debug;
+
+#define dprintk(arg...) do { \
+ if (debug) \
+ printk(arg); \
+ } while (0)
+
+/* 16 bit registers, 8 bit values */
+static int au8522_writereg(struct au8522_state *state, u16 reg, u8 data)
+{
+ int ret;
+ u8 buf [] = { reg >> 8, reg & 0xff, data };
+
+ struct i2c_msg msg = { .addr = state->config->demod_address,
+ .flags = 0, .buf = buf, .len = 3 };
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk("%s: writereg error (reg == 0x%02x, val == 0x%04x, "
+ "ret == %i)\n", __func__, reg, data, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static u8 au8522_readreg(struct au8522_state *state, u16 reg)
+{
+ int ret;
+ u8 b0 [] = { reg >> 8, reg & 0xff };
+ u8 b1 [] = { 0 };
+
+ struct i2c_msg msg [] = {
+ { .addr = state->config->demod_address, .flags = 0,
+ .buf = b0, .len = 2 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD,
+ .buf = b1, .len = 1 } };
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+ __func__, ret);
+ return b1[0];
+}
+
+static int au8522_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+
+ dprintk("%s(%d)\n", __func__, enable);
+
+ if (enable)
+ return au8522_writereg(state, 0x106, 1);
+ else
+ return au8522_writereg(state, 0x106, 0);
+}
+
+struct mse2snr_tab {
+ u16 val;
+ u16 data;
+};
+
+/* VSB SNR lookup table */
+static struct mse2snr_tab vsb_mse2snr_tab[] = {
+ { 0, 270 },
+ { 2, 250 },
+ { 3, 240 },
+ { 5, 230 },
+ { 7, 220 },
+ { 9, 210 },
+ { 12, 200 },
+ { 13, 195 },
+ { 15, 190 },
+ { 17, 185 },
+ { 19, 180 },
+ { 21, 175 },
+ { 24, 170 },
+ { 27, 165 },
+ { 31, 160 },
+ { 32, 158 },
+ { 33, 156 },
+ { 36, 152 },
+ { 37, 150 },
+ { 39, 148 },
+ { 40, 146 },
+ { 41, 144 },
+ { 43, 142 },
+ { 44, 140 },
+ { 48, 135 },
+ { 50, 130 },
+ { 43, 142 },
+ { 53, 125 },
+ { 56, 120 },
+ { 256, 115 },
+};
+
+/* QAM64 SNR lookup table */
+static struct mse2snr_tab qam64_mse2snr_tab[] = {
+ { 15, 0 },
+ { 16, 290 },
+ { 17, 288 },
+ { 18, 286 },
+ { 19, 284 },
+ { 20, 282 },
+ { 21, 281 },
+ { 22, 279 },
+ { 23, 277 },
+ { 24, 275 },
+ { 25, 273 },
+ { 26, 271 },
+ { 27, 269 },
+ { 28, 268 },
+ { 29, 266 },
+ { 30, 264 },
+ { 31, 262 },
+ { 32, 260 },
+ { 33, 259 },
+ { 34, 258 },
+ { 35, 256 },
+ { 36, 255 },
+ { 37, 254 },
+ { 38, 252 },
+ { 39, 251 },
+ { 40, 250 },
+ { 41, 249 },
+ { 42, 248 },
+ { 43, 246 },
+ { 44, 245 },
+ { 45, 244 },
+ { 46, 242 },
+ { 47, 241 },
+ { 48, 240 },
+ { 50, 239 },
+ { 51, 238 },
+ { 53, 237 },
+ { 54, 236 },
+ { 56, 235 },
+ { 57, 234 },
+ { 59, 233 },
+ { 60, 232 },
+ { 62, 231 },
+ { 63, 230 },
+ { 65, 229 },
+ { 67, 228 },
+ { 68, 227 },
+ { 70, 226 },
+ { 71, 225 },
+ { 73, 224 },
+ { 74, 223 },
+ { 76, 222 },
+ { 78, 221 },
+ { 80, 220 },
+ { 82, 219 },
+ { 85, 218 },
+ { 88, 217 },
+ { 90, 216 },
+ { 92, 215 },
+ { 93, 214 },
+ { 94, 212 },
+ { 95, 211 },
+ { 97, 210 },
+ { 99, 209 },
+ { 101, 208 },
+ { 102, 207 },
+ { 104, 206 },
+ { 107, 205 },
+ { 111, 204 },
+ { 114, 203 },
+ { 118, 202 },
+ { 122, 201 },
+ { 125, 200 },
+ { 128, 199 },
+ { 130, 198 },
+ { 132, 197 },
+ { 256, 190 },
+};
+
+/* QAM256 SNR lookup table */
+static struct mse2snr_tab qam256_mse2snr_tab[] = {
+ { 16, 0 },
+ { 17, 400 },
+ { 18, 398 },
+ { 19, 396 },
+ { 20, 394 },
+ { 21, 392 },
+ { 22, 390 },
+ { 23, 388 },
+ { 24, 386 },
+ { 25, 384 },
+ { 26, 382 },
+ { 27, 380 },
+ { 28, 379 },
+ { 29, 378 },
+ { 30, 377 },
+ { 31, 376 },
+ { 32, 375 },
+ { 33, 374 },
+ { 34, 373 },
+ { 35, 372 },
+ { 36, 371 },
+ { 37, 370 },
+ { 38, 362 },
+ { 39, 354 },
+ { 40, 346 },
+ { 41, 338 },
+ { 42, 330 },
+ { 43, 328 },
+ { 44, 326 },
+ { 45, 324 },
+ { 46, 322 },
+ { 47, 320 },
+ { 48, 319 },
+ { 49, 318 },
+ { 50, 317 },
+ { 51, 316 },
+ { 52, 315 },
+ { 53, 314 },
+ { 54, 313 },
+ { 55, 312 },
+ { 56, 311 },
+ { 57, 310 },
+ { 58, 308 },
+ { 59, 306 },
+ { 60, 304 },
+ { 61, 302 },
+ { 62, 300 },
+ { 63, 298 },
+ { 65, 295 },
+ { 68, 294 },
+ { 70, 293 },
+ { 73, 292 },
+ { 76, 291 },
+ { 78, 290 },
+ { 79, 289 },
+ { 81, 288 },
+ { 82, 287 },
+ { 83, 286 },
+ { 84, 285 },
+ { 85, 284 },
+ { 86, 283 },
+ { 88, 282 },
+ { 89, 281 },
+ { 256, 280 },
+};
+
+static int au8522_mse2snr_lookup(struct mse2snr_tab *tab, int sz, int mse,
+ u16 *snr)
+{
+ int i, ret = -EINVAL;
+ dprintk("%s()\n", __func__);
+
+ for (i = 0; i < sz; i++) {
+ if (mse < tab[i].val) {
+ *snr = tab[i].data;
+ ret = 0;
+ break;
+ }
+ }
+ dprintk("%s() snr=%d\n", __func__, *snr);
+ return ret;
+}
+
+/* VSB Modulation table */
+static struct {
+ u16 reg;
+ u16 data;
+} VSB_mod_tab[] = {
+ { 0x8090, 0x84 },
+ { 0x4092, 0x11 },
+ { 0x2005, 0x00 },
+ { 0x8091, 0x80 },
+ { 0x80a3, 0x0c },
+ { 0x80a4, 0xe8 },
+ { 0x8081, 0xc4 },
+ { 0x80a5, 0x40 },
+ { 0x80a7, 0x40 },
+ { 0x80a6, 0x67 },
+ { 0x8262, 0x20 },
+ { 0x821c, 0x30 },
+ { 0x80d8, 0x1a },
+ { 0x8227, 0xa0 },
+ { 0x8121, 0xff },
+ { 0x80a8, 0xf0 },
+ { 0x80a9, 0x05 },
+ { 0x80aa, 0x77 },
+ { 0x80ab, 0xf0 },
+ { 0x80ac, 0x05 },
+ { 0x80ad, 0x77 },
+ { 0x80ae, 0x41 },
+ { 0x80af, 0x66 },
+ { 0x821b, 0xcc },
+ { 0x821d, 0x80 },
+ { 0x80b5, 0xfb },
+ { 0x80b6, 0x8e },
+ { 0x80b7, 0x39 },
+ { 0x80a4, 0xe8 },
+ { 0x8231, 0x13 },
+};
+
+/* QAM Modulation table */
+static struct {
+ u16 reg;
+ u16 data;
+} QAM_mod_tab[] = {
+ { 0x80a3, 0x09 },
+ { 0x80a4, 0x00 },
+ { 0x8081, 0xc4 },
+ { 0x80a5, 0x40 },
+ { 0x80b5, 0xfb },
+ { 0x80b6, 0x8e },
+ { 0x80b7, 0x39 },
+ { 0x80aa, 0x77 },
+ { 0x80ad, 0x77 },
+ { 0x80a6, 0x67 },
+ { 0x8262, 0x20 },
+ { 0x821c, 0x30 },
+ { 0x80b8, 0x3e },
+ { 0x80b9, 0xf0 },
+ { 0x80ba, 0x01 },
+ { 0x80bb, 0x18 },
+ { 0x80bc, 0x50 },
+ { 0x80bd, 0x00 },
+ { 0x80be, 0xea },
+ { 0x80bf, 0xef },
+ { 0x80c0, 0xfc },
+ { 0x80c1, 0xbd },
+ { 0x80c2, 0x1f },
+ { 0x80c3, 0xfc },
+ { 0x80c4, 0xdd },
+ { 0x80c5, 0xaf },
+ { 0x80c6, 0x00 },
+ { 0x80c7, 0x38 },
+ { 0x80c8, 0x30 },
+ { 0x80c9, 0x05 },
+ { 0x80ca, 0x4a },
+ { 0x80cb, 0xd0 },
+ { 0x80cc, 0x01 },
+ { 0x80cd, 0xd9 },
+ { 0x80ce, 0x6f },
+ { 0x80cf, 0xf9 },
+ { 0x80d0, 0x70 },
+ { 0x80d1, 0xdf },
+ { 0x80d2, 0xf7 },
+ { 0x80d3, 0xc2 },
+ { 0x80d4, 0xdf },
+ { 0x80d5, 0x02 },
+ { 0x80d6, 0x9a },
+ { 0x80d7, 0xd0 },
+ { 0x8250, 0x0d },
+ { 0x8251, 0xcd },
+ { 0x8252, 0xe0 },
+ { 0x8253, 0x05 },
+ { 0x8254, 0xa7 },
+ { 0x8255, 0xff },
+ { 0x8256, 0xed },
+ { 0x8257, 0x5b },
+ { 0x8258, 0xae },
+ { 0x8259, 0xe6 },
+ { 0x825a, 0x3d },
+ { 0x825b, 0x0f },
+ { 0x825c, 0x0d },
+ { 0x825d, 0xea },
+ { 0x825e, 0xf2 },
+ { 0x825f, 0x51 },
+ { 0x8260, 0xf5 },
+ { 0x8261, 0x06 },
+ { 0x821a, 0x00 },
+ { 0x8546, 0x40 },
+ { 0x8210, 0x26 },
+ { 0x8211, 0xf6 },
+ { 0x8212, 0x84 },
+ { 0x8213, 0x02 },
+ { 0x8502, 0x01 },
+ { 0x8121, 0x04 },
+ { 0x8122, 0x04 },
+ { 0x852e, 0x10 },
+ { 0x80a4, 0xca },
+ { 0x80a7, 0x40 },
+ { 0x8526, 0x01 },
+};
+
+static int au8522_enable_modulation(struct dvb_frontend *fe,
+ fe_modulation_t m)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ int i;
+
+ dprintk("%s(0x%08x)\n", __func__, m);
+
+ switch (m) {
+ case VSB_8:
+ dprintk("%s() VSB_8\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(VSB_mod_tab); i++)
+ au8522_writereg(state,
+ VSB_mod_tab[i].reg,
+ VSB_mod_tab[i].data);
+ break;
+ case QAM_64:
+ case QAM_256:
+ dprintk("%s() QAM 64/256\n", __func__);
+ for (i = 0; i < ARRAY_SIZE(QAM_mod_tab); i++)
+ au8522_writereg(state,
+ QAM_mod_tab[i].reg,
+ QAM_mod_tab[i].data);
+ break;
+ default:
+ dprintk("%s() Invalid modulation\n", __func__);
+ return -EINVAL;
+ }
+
+ state->current_modulation = m;
+
+ return 0;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+static int au8522_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+
+ dprintk("%s(frequency=%d)\n", __func__, p->frequency);
+
+ state->current_frequency = p->frequency;
+
+ au8522_enable_modulation(fe, p->u.vsb.modulation);
+
+ /* Allow the demod to settle */
+ msleep(100);
+
+ if (fe->ops.tuner_ops.set_params) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+ fe->ops.tuner_ops.set_params(fe, p);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ return 0;
+}
+
+/* Reset the demod hardware and reset all of the configuration registers
+ to a default state. */
+static int au8522_init(struct dvb_frontend *fe)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ dprintk("%s()\n", __func__);
+
+ au8522_writereg(state, 0xa4, 1 << 5);
+
+ au8522_i2c_gate_ctrl(fe, 1);
+
+ return 0;
+}
+
+static int au8522_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ u8 reg;
+ u32 tuner_status = 0;
+
+ *status = 0;
+
+ if (state->current_modulation == VSB_8) {
+ dprintk("%s() Checking VSB_8\n", __func__);
+ reg = au8522_readreg(state, 0x4088);
+ if (reg & 0x01)
+ *status |= FE_HAS_VITERBI;
+ if (reg & 0x02)
+ *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+ } else {
+ dprintk("%s() Checking QAM\n", __func__);
+ reg = au8522_readreg(state, 0x4541);
+ if (reg & 0x80)
+ *status |= FE_HAS_VITERBI;
+ if (reg & 0x20)
+ *status |= FE_HAS_LOCK | FE_HAS_SYNC;
+ }
+
+ switch (state->config->status_mode) {
+ case AU8522_DEMODLOCKING:
+ dprintk("%s() DEMODLOCKING\n", __func__);
+ if (*status & FE_HAS_VITERBI)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ case AU8522_TUNERLOCKING:
+ /* Get the tuner status */
+ dprintk("%s() TUNERLOCKING\n", __func__);
+ if (fe->ops.tuner_ops.get_status) {
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ fe->ops.tuner_ops.get_status(fe, &tuner_status);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+ if (tuner_status)
+ *status |= FE_HAS_CARRIER | FE_HAS_SIGNAL;
+ break;
+ }
+
+ dprintk("%s() status 0x%08x\n", __func__, *status);
+
+ return 0;
+}
+
+static int au8522_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ int ret = -EINVAL;
+
+ dprintk("%s()\n", __func__);
+
+ if (state->current_modulation == QAM_256)
+ ret = au8522_mse2snr_lookup(qam256_mse2snr_tab,
+ ARRAY_SIZE(qam256_mse2snr_tab),
+ au8522_readreg(state, 0x4522),
+ snr);
+ else if (state->current_modulation == QAM_64)
+ ret = au8522_mse2snr_lookup(qam64_mse2snr_tab,
+ ARRAY_SIZE(qam64_mse2snr_tab),
+ au8522_readreg(state, 0x4522),
+ snr);
+ else /* VSB_8 */
+ ret = au8522_mse2snr_lookup(vsb_mse2snr_tab,
+ ARRAY_SIZE(vsb_mse2snr_tab),
+ au8522_readreg(state, 0x4311),
+ snr);
+
+ return ret;
+}
+
+static int au8522_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
+{
+ return au8522_read_snr(fe, signal_strength);
+}
+
+static int au8522_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+
+ if (state->current_modulation == VSB_8)
+ *ucblocks = au8522_readreg(state, 0x4087);
+ else
+ *ucblocks = au8522_readreg(state, 0x4543);
+
+ return 0;
+}
+
+static int au8522_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ return au8522_read_ucblocks(fe, ber);
+}
+
+static int au8522_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+
+ p->frequency = state->current_frequency;
+ p->u.vsb.modulation = state->current_modulation;
+
+ return 0;
+}
+
+static int au8522_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static void au8522_release(struct dvb_frontend *fe)
+{
+ struct au8522_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops au8522_ops;
+
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct au8522_state *state = NULL;
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct au8522_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+#if 0
+ /* check if the demod exists */
+ reg = au8522_readreg(state, 0x04);
+ if ((reg != 0x0066) && (reg != 0x007f))
+ goto error;
+#endif
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &au8522_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ if (au8522_init(&state->frontend) != 0) {
+ printk(KERN_ERR "%s: Failed to initialize correctly\n",
+ __func__);
+ goto error;
+ }
+
+ /* Note: Leaving the I2C gate open here. */
+ au8522_i2c_gate_ctrl(&state->frontend, 1);
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(au8522_attach);
+
+static struct dvb_frontend_ops au8522_ops = {
+
+ .info = {
+ .name = "Auvitek AU8522 QAM/8VSB Frontend",
+ .type = FE_ATSC,
+ .frequency_min = 54000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 62500,
+ .caps = FE_CAN_QAM_64 | FE_CAN_QAM_256 | FE_CAN_8VSB
+ },
+
+ .init = au8522_init,
+ .i2c_gate_ctrl = au8522_i2c_gate_ctrl,
+ .set_frontend = au8522_set_frontend,
+ .get_frontend = au8522_get_frontend,
+ .get_tune_settings = au8522_get_tune_settings,
+ .read_status = au8522_read_status,
+ .read_ber = au8522_read_ber,
+ .read_signal_strength = au8522_read_signal_strength,
+ .read_snr = au8522_read_snr,
+ .read_ucblocks = au8522_read_ucblocks,
+ .release = au8522_release,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("Auvitek AU8522 QAM-B/ATSC Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/frontends/au8522.h b/linux/drivers/media/dvb/frontends/au8522.h
new file mode 100644
index 000000000..d7affa3cd
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/au8522.h
@@ -0,0 +1,56 @@
+/*
+ Auvitek AU8522 QAM/8VSB demodulator driver
+
+ 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.
+
+*/
+
+#ifndef __AU8522_H__
+#define __AU8522_H__
+
+#include <linux/dvb/frontend.h>
+
+struct au8522_config {
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* Return lock status based on tuner lock, or demod lock */
+#define AU8522_TUNERLOCKING 0
+#define AU8522_DEMODLOCKING 1
+ u8 status_mode;
+};
+
+#if defined(CONFIG_DVB_AU8522) || \
+ (defined(CONFIG_DVB_AU8522_MODULE) && defined(MODULE))
+extern struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline
+struct dvb_frontend *au8522_attach(const struct au8522_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_AU8522 */
+
+#endif /* __AU8522_H__ */
+
+/*
+ * Local variables:
+ * c-basic-offset: 8
+ */
diff --git a/linux/drivers/media/dvb/frontends/itd1000.c b/linux/drivers/media/dvb/frontends/itd1000.c
new file mode 100644
index 000000000..abcd0ddae
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/itd1000.c
@@ -0,0 +1,408 @@
+/*
+ * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ * Copyright (c) 2007-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/delay.h>
+#include <linux/dvb/frontend.h>
+#include <linux/i2c.h>
+
+#include "dvb_frontend.h"
+
+#include "itd1000.h"
+#include "itd1000_priv.h"
+
+static int debug;
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Turn on/off debugging (default:off).");
+
+#define deb(args...) do { \
+ if (debug) { \
+ printk(KERN_DEBUG "ITD1000: " args);\
+ printk("\n"); \
+ } \
+} while (0)
+
+#define warn(args...) do { \
+ printk(KERN_WARNING "ITD1000: " args); \
+ printk("\n"); \
+} while (0)
+
+#define info(args...) do { \
+ printk(KERN_INFO "ITD1000: " args); \
+ printk("\n"); \
+} while (0)
+
+/* don't write more than one byte with flexcop behind */
+static int itd1000_write_regs(struct itd1000_state *state, u8 reg, u8 v[], u8 len)
+{
+ u8 buf[1+len];
+ struct i2c_msg msg = {
+ .addr = state->cfg->i2c_address, .flags = 0, .buf = buf, .len = len+1
+ };
+ buf[0] = reg;
+ memcpy(&buf[1], v, len);
+
+ /* deb("wr %02x: %02x", reg, v[0]); */
+
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ printk(KERN_WARNING "itd1000 I2C write failed\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int itd1000_read_reg(struct itd1000_state *state, u8 reg)
+{
+ u8 val;
+ struct i2c_msg msg[2] = {
+ { .addr = state->cfg->i2c_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->cfg->i2c_address, .flags = I2C_M_RD, .buf = &val, .len = 1 },
+ };
+
+ /* ugly flexcop workaround */
+ itd1000_write_regs(state, (reg - 1) & 0xff, &state->shadow[(reg - 1) & 0xff], 1);
+
+ if (i2c_transfer(state->i2c, msg, 2) != 2) {
+ warn("itd1000 I2C read failed");
+ return -EREMOTEIO;
+ }
+ return val;
+}
+
+static inline int itd1000_write_reg(struct itd1000_state *state, u8 r, u8 v)
+{
+ int ret = itd1000_write_regs(state, r, &v, 1);
+ state->shadow[r] = v;
+ return ret;
+}
+
+#if 0
+static void reg_dump(struct itd1000_state *state)
+{
+ int i;
+ for (i = 0x65; i < 0x9c; i++)
+ printk(KERN_DEBUG "ITD: %02x: %02x\n", i, itd1000_read_reg(state, i));
+}
+#endif
+
+static struct {
+ u32 symbol_rate;
+ u8 pgaext : 4; /* PLLFH */
+ u8 bbgvmin : 4; /* BBGVMIN */
+} itd1000_lpf_pga[] = {
+ { 0, 0x8, 0x3 },
+ { 5200000, 0x8, 0x3 },
+ { 12200000, 0x4, 0x3 },
+ { 15400000, 0x2, 0x3 },
+ { 19800000, 0x2, 0x3 },
+ { 21500000, 0x2, 0x3 },
+ { 24500000, 0x2, 0x3 },
+ { 28400000, 0x2, 0x3 },
+ { 33400000, 0x2, 0x3 },
+ { 34400000, 0x1, 0x4 },
+ { 34400000, 0x1, 0x4 },
+ { 38400000, 0x1, 0x4 },
+ { 38400000, 0x1, 0x4 },
+ { 40400000, 0x1, 0x4 },
+ { 45400000, 0x1, 0x4 },
+};
+
+static void itd1000_set_lpf_bw(struct itd1000_state *state, u32 symbol_rate)
+{
+ u8 i;
+ u8 con1 = itd1000_read_reg(state, CON1) & 0xfd;
+ u8 pllfh = itd1000_read_reg(state, PLLFH) & 0x0f;
+ u8 bbgvmin = itd1000_read_reg(state, BBGVMIN) & 0xf0;
+ u8 bw = itd1000_read_reg(state, BW) & 0xf0;
+
+ deb("symbol_rate = %d", symbol_rate);
+
+ /* not sure what is that ? - starting to download the table */
+ itd1000_write_reg(state, CON1, con1 | (1 << 1));
+
+ for (i = 0; i < ARRAY_SIZE(itd1000_lpf_pga); i++)
+ if (symbol_rate < itd1000_lpf_pga[i].symbol_rate) {
+ deb("symrate: index: %d pgaext: %x, bbgvmin: %x", i, itd1000_lpf_pga[i].pgaext, itd1000_lpf_pga[i].bbgvmin);
+ itd1000_write_reg(state, PLLFH, pllfh | (itd1000_lpf_pga[i].pgaext << 4));
+ itd1000_write_reg(state, BBGVMIN, bbgvmin | (itd1000_lpf_pga[i].bbgvmin));
+ itd1000_write_reg(state, BW, bw | (i & 0x0f));
+ break;
+ }
+
+ itd1000_write_reg(state, CON1, con1 | (0 << 1));
+}
+
+static struct {
+ u8 vcorg;
+ u32 fmax_rg;
+} itd1000_vcorg[] = {
+ { 1, 920000 },
+ { 2, 971000 },
+ { 3, 1031000 },
+ { 4, 1091000 },
+ { 5, 1171000 },
+ { 6, 1281000 },
+ { 7, 1381000 },
+ { 8, 500000 }, /* this is intentional. */
+ { 9, 1451000 },
+ { 10, 1531000 },
+ { 11, 1631000 },
+ { 12, 1741000 },
+ { 13, 1891000 },
+ { 14, 2071000 },
+ { 15, 2250000 },
+};
+
+static void itd1000_set_vco(struct itd1000_state *state, u32 freq_khz)
+{
+ u8 i;
+ u8 gvbb_i2c = itd1000_read_reg(state, GVBB_I2C) & 0xbf;
+ u8 vco_chp1_i2c = itd1000_read_reg(state, VCO_CHP1_I2C) & 0x0f;
+ u8 adcout;
+
+ /* reserved bit again (reset ?) */
+ itd1000_write_reg(state, GVBB_I2C, gvbb_i2c | (1 << 6));
+
+ for (i = 0; i < ARRAY_SIZE(itd1000_vcorg); i++) {
+ if (freq_khz < itd1000_vcorg[i].fmax_rg) {
+ itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | (itd1000_vcorg[i].vcorg << 4));
+ msleep(1);
+
+ adcout = itd1000_read_reg(state, PLLLOCK) & 0x0f;
+
+ deb("VCO: %dkHz: %d -> ADCOUT: %d %02x", freq_khz, itd1000_vcorg[i].vcorg, adcout, vco_chp1_i2c);
+
+ if (adcout > 13) {
+ if (!(itd1000_vcorg[i].vcorg == 7 || itd1000_vcorg[i].vcorg == 15))
+ itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg + 1) << 4));
+ } else if (adcout < 2) {
+ if (!(itd1000_vcorg[i].vcorg == 1 || itd1000_vcorg[i].vcorg == 9))
+ itd1000_write_reg(state, VCO_CHP1_I2C, vco_chp1_i2c | ((itd1000_vcorg[i].vcorg - 1) << 4));
+ }
+ break;
+ }
+ }
+}
+
+struct {
+ u32 freq;
+ u8 values[10]; /* RFTR, RFST1 - RFST9 */
+} itd1000_fre_values[] = {
+ { 1075000, { 0x59, 0x1d, 0x1c, 0x17, 0x16, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+ { 1250000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+ { 1450000, { 0x89, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+ { 1650000, { 0x69, 0x1e, 0x1d, 0x17, 0x15, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+ { 1750000, { 0x69, 0x1e, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0c, 0x0b, 0x0a } },
+ { 1850000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } },
+ { 1900000, { 0x69, 0x1d, 0x17, 0x15, 0x14, 0x0f, 0x0e, 0x0d, 0x0b, 0x0a } },
+ { 1950000, { 0x69, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0d, 0x0b, 0x0a } },
+ { 2050000, { 0x69, 0x1e, 0x1d, 0x17, 0x16, 0x14, 0x13, 0x0e, 0x0b, 0x0a } },
+ { 2150000, { 0x69, 0x1d, 0x1c, 0x17, 0x15, 0x14, 0x13, 0x0f, 0x0e, 0x0b } }
+};
+
+
+#define FREF 16
+
+static void itd1000_set_lo(struct itd1000_state *state, u32 freq_khz)
+{
+ int i, j;
+ u32 plln, pllf;
+ u64 tmp;
+
+ plln = (freq_khz * 1000) / 2 / FREF;
+
+ /* Compute the factional part times 1000 */
+ tmp = plln % 1000000;
+ plln /= 1000000;
+
+ tmp *= 1048576;
+ do_div(tmp, 1000000);
+ pllf = (u32) tmp;
+
+ state->frequency = ((plln * 1000) + (pllf * 1000)/1048576) * 2*FREF;
+ deb("frequency: %dkHz (wanted) %dkHz (set), PLLF = %d, PLLN = %d", freq_khz, state->frequency, pllf, plln);
+
+ itd1000_write_reg(state, PLLNH, 0x80); /* PLLNH */;
+ itd1000_write_reg(state, PLLNL, plln & 0xff);
+ itd1000_write_reg(state, PLLFH, (itd1000_read_reg(state, PLLFH) & 0xf0) | ((pllf >> 16) & 0x0f));
+ itd1000_write_reg(state, PLLFM, (pllf >> 8) & 0xff);
+ itd1000_write_reg(state, PLLFL, (pllf >> 0) & 0xff);
+
+ for (i = 0; i < ARRAY_SIZE(itd1000_fre_values); i++) {
+ if (freq_khz <= itd1000_fre_values[i].freq) {
+ deb("fre_values: %d", i);
+ itd1000_write_reg(state, RFTR, itd1000_fre_values[i].values[0]);
+ for (j = 0; j < 9; j++)
+ itd1000_write_reg(state, RFST1+j, itd1000_fre_values[i].values[j+1]);
+ break;
+ }
+ }
+
+ itd1000_set_vco(state, freq_khz);
+}
+
+static int itd1000_set_parameters(struct dvb_frontend *fe, struct dvb_frontend_parameters *p)
+{
+ struct itd1000_state *state = fe->tuner_priv;
+ u8 pllcon1;
+
+ itd1000_set_lo(state, p->frequency);
+ itd1000_set_lpf_bw(state, p->u.qpsk.symbol_rate);
+
+ pllcon1 = itd1000_read_reg(state, PLLCON1) & 0x7f;
+ itd1000_write_reg(state, PLLCON1, pllcon1 | (1 << 7));
+ itd1000_write_reg(state, PLLCON1, pllcon1);
+
+ return 0;
+}
+
+static int itd1000_get_frequency(struct dvb_frontend *fe, u32 *frequency)
+{
+ struct itd1000_state *state = fe->tuner_priv;
+ *frequency = state->frequency;
+ return 0;
+}
+
+static int itd1000_get_bandwidth(struct dvb_frontend *fe, u32 *bandwidth)
+{
+ return 0;
+}
+
+static u8 itd1000_init_tab[][2] = {
+ { PLLCON1, 0x65 }, /* Register does not change */
+ { PLLNH, 0x80 }, /* Bits [7:6] do not change */
+ { RESERVED_0X6D, 0x3b },
+ { VCO_CHP2_I2C, 0x12 },
+ { 0x72, 0xf9 }, /* No such regsister defined */
+ { RESERVED_0X73, 0xff },
+ { RESERVED_0X74, 0xb2 },
+ { RESERVED_0X75, 0xc7 },
+ { EXTGVBBRF, 0xf0 },
+ { DIVAGCCK, 0x80 },
+ { BBTR, 0xa0 },
+ { RESERVED_0X7E, 0x4f },
+ { 0x82, 0x88 }, /* No such regsister defined */
+ { 0x83, 0x80 }, /* No such regsister defined */
+ { 0x84, 0x80 }, /* No such regsister defined */
+ { RESERVED_0X85, 0x74 },
+ { RESERVED_0X86, 0xff },
+ { RESERVED_0X88, 0x02 },
+ { RESERVED_0X89, 0x16 },
+ { RFST0, 0x1f },
+ { RESERVED_0X94, 0x66 },
+ { RESERVED_0X95, 0x66 },
+ { RESERVED_0X96, 0x77 },
+ { RESERVED_0X97, 0x99 },
+ { RESERVED_0X98, 0xff },
+ { RESERVED_0X99, 0xfc },
+ { RESERVED_0X9A, 0xba },
+ { RESERVED_0X9B, 0xaa },
+};
+
+static u8 itd1000_reinit_tab[][2] = {
+ { VCO_CHP1_I2C, 0x8a },
+ { BW, 0x87 },
+ { GVBB_I2C, 0x03 },
+ { BBGVMIN, 0x03 },
+ { CON1, 0x2e },
+};
+
+
+static int itd1000_init(struct dvb_frontend *fe)
+{
+ struct itd1000_state *state = fe->tuner_priv;
+ int i;
+
+ for (i = 0; i < ARRAY_SIZE(itd1000_init_tab); i++)
+ itd1000_write_reg(state, itd1000_init_tab[i][0], itd1000_init_tab[i][1]);
+
+ for (i = 0; i < ARRAY_SIZE(itd1000_reinit_tab); i++)
+ itd1000_write_reg(state, itd1000_reinit_tab[i][0], itd1000_reinit_tab[i][1]);
+
+ return 0;
+}
+
+static int itd1000_sleep(struct dvb_frontend *fe)
+{
+ return 0;
+}
+
+static int itd1000_release(struct dvb_frontend *fe)
+{
+ kfree(fe->tuner_priv);
+ fe->tuner_priv = NULL;
+ return 0;
+}
+
+static const struct dvb_tuner_ops itd1000_tuner_ops = {
+ .info = {
+ .name = "Integrant ITD1000",
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_step = 125, /* kHz for QPSK frontends */
+ },
+
+ .release = itd1000_release,
+
+ .init = itd1000_init,
+ .sleep = itd1000_sleep,
+
+ .set_params = itd1000_set_parameters,
+ .get_frequency = itd1000_get_frequency,
+ .get_bandwidth = itd1000_get_bandwidth
+};
+
+
+struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
+{
+ struct itd1000_state *state = NULL;
+ u8 i = 0;
+
+ state = kzalloc(sizeof(struct itd1000_state), GFP_KERNEL);
+ if (state == NULL)
+ return NULL;
+
+ state->cfg = cfg;
+ state->i2c = i2c;
+
+ i = itd1000_read_reg(state, 0);
+ if (i != 0) {
+ kfree(state);
+ return NULL;
+ }
+ info("successfully identified (ID: %d)", i);
+
+ memset(state->shadow, 0xff, sizeof(state->shadow));
+ for (i = 0x65; i < 0x9c; i++)
+ state->shadow[i] = itd1000_read_reg(state, i);
+
+ memcpy(&fe->ops.tuner_ops, &itd1000_tuner_ops, sizeof(struct dvb_tuner_ops));
+
+ fe->tuner_priv = state;
+
+ return fe;
+}
+EXPORT_SYMBOL(itd1000_attach);
+
+MODULE_AUTHOR("Patrick Boettcher <pb@linuxtv.org>");
+MODULE_DESCRIPTION("Integrant ITD1000 driver");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/frontends/itd1000.h b/linux/drivers/media/dvb/frontends/itd1000.h
new file mode 100644
index 000000000..5e18df071
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/itd1000.h
@@ -0,0 +1,42 @@
+/*
+ * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ * Copyright (c) 2007 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ITD1000_H
+#define ITD1000_H
+
+struct dvb_frontend;
+struct i2c_adapter;
+
+struct itd1000_config {
+ u8 i2c_address;
+};
+
+#if defined(CONFIG_DVB_TUNER_ITD1000) || (defined(CONFIG_DVB_TUNER_ITD1000_MODULE) && defined(MODULE))
+extern struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg);
+#else
+static inline struct dvb_frontend *itd1000_attach(struct dvb_frontend *fe, struct i2c_adapter *i2c, struct itd1000_config *cfg)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif
+
+#endif
diff --git a/linux/drivers/media/dvb/frontends/itd1000_priv.h b/linux/drivers/media/dvb/frontends/itd1000_priv.h
new file mode 100644
index 000000000..8cdc54e57
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/itd1000_priv.h
@@ -0,0 +1,88 @@
+/*
+ * Driver for the Integrant ITD1000 "Zero-IF Tuner IC for Direct Broadcast Satellite"
+ *
+ * Copyright (c) 2007 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.=
+ */
+
+#ifndef ITD1000_PRIV_H
+#define ITD1000_PRIV_H
+
+struct itd1000_state {
+ struct itd1000_config *cfg;
+ struct i2c_adapter *i2c;
+
+ u32 frequency; /* contains the value resulting from the LO-setting */
+
+ /* ugly workaround for flexcop's incapable i2c-controller
+ * FIXME, if possible
+ */
+ u8 shadow[255];
+};
+
+enum itd1000_register {
+ VCO_CHP1 = 0x65,
+ VCO_CHP2,
+ PLLCON1,
+ PLLNH,
+ PLLNL,
+ PLLFH,
+ PLLFM,
+ PLLFL,
+ RESERVED_0X6D,
+ PLLLOCK,
+ VCO_CHP2_I2C,
+ VCO_CHP1_I2C,
+ BW,
+ RESERVED_0X73 = 0x73,
+ RESERVED_0X74,
+ RESERVED_0X75,
+ GVBB,
+ GVRF,
+ GVBB_I2C,
+ EXTGVBBRF,
+ DIVAGCCK,
+ BBTR,
+ RFTR,
+ BBGVMIN,
+ RESERVED_0X7E,
+ RESERVED_0X85 = 0x85,
+ RESERVED_0X86,
+ CON1,
+ RESERVED_0X88,
+ RESERVED_0X89,
+ RFST0,
+ RFST1,
+ RFST2,
+ RFST3,
+ RFST4,
+ RFST5,
+ RFST6,
+ RFST7,
+ RFST8,
+ RFST9,
+ RESERVED_0X94,
+ RESERVED_0X95,
+ RESERVED_0X96,
+ RESERVED_0X97,
+ RESERVED_0X98,
+ RESERVED_0X99,
+ RESERVED_0X9A,
+ RESERVED_0X9B,
+};
+
+#endif
diff --git a/linux/drivers/media/dvb/frontends/mt312.c b/linux/drivers/media/dvb/frontends/mt312.c
index daca855c8..081ca3398 100644
--- a/linux/drivers/media/dvb/frontends/mt312.c
+++ b/linux/drivers/media/dvb/frontends/mt312.c
@@ -1,7 +1,8 @@
/*
- Driver for Zarlink VP310/MT312 Satellite Channel Decoder
+ Driver for Zarlink VP310/MT312/ZL10313 Satellite Channel Decoder
Copyright (C) 2003 Andreas Oberritter <obi@linuxtv.org>
+ Copyright (C) 2008 Matthias Schwarzott <zzam@gentoo.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
@@ -43,7 +44,8 @@ struct mt312_state {
struct dvb_frontend frontend;
u8 id;
- u8 frequency;
+ unsigned long xtal;
+ u8 freq_mult;
};
static int debug;
@@ -53,12 +55,11 @@ static int debug;
printk(KERN_DEBUG "mt312: " args); \
} while (0)
-#define MT312_SYS_CLK 90000000UL /* 90 MHz */
-#define MT312_LPOWER_SYS_CLK 60000000UL /* 60 MHz */
#define MT312_PLL_CLK 10000000UL /* 10 MHz */
+#define MT312_PLL_CLK_10_111 10111000UL /* 10.111 MHz */
static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
- void *buf, const size_t count)
+ u8 *buf, const size_t count)
{
int ret;
struct i2c_msg msg[2];
@@ -84,7 +85,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
int i;
dprintk("R(%d):", reg & 0x7f);
for (i = 0; i < count; i++)
- printk(" %02x", ((const u8 *) buf)[i]);
+ printk(" %02x", buf[i]);
printk("\n");
}
@@ -92,7 +93,7 @@ static int mt312_read(struct mt312_state *state, const enum mt312_reg_addr reg,
}
static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
- const void *src, const size_t count)
+ const u8 *src, const size_t count)
{
int ret;
u8 buf[count + 1];
@@ -102,7 +103,7 @@ static int mt312_write(struct mt312_state *state, const enum mt312_reg_addr reg,
int i;
dprintk("W(%d):", reg & 0x7f);
for (i = 0; i < count; i++)
- printk(" %02x", ((const u8 *) src)[i]);
+ printk(" %02x", src[i]);
printk("\n");
}
@@ -209,7 +210,7 @@ static int mt312_get_symbol_rate(struct mt312_state *state, u32 *sr)
dprintk("sym_rat_op=%d dec_ratio=%d\n",
sym_rat_op, dec_ratio);
dprintk("*sr(manual) = %lu\n",
- (((MT312_PLL_CLK * 8192) / (sym_rat_op + 8192)) *
+ (((state->xtal * 8192) / (sym_rat_op + 8192)) *
2) - dec_ratio);
}
@@ -242,7 +243,7 @@ static int mt312_initfe(struct dvb_frontend *fe)
/* wake up */
ret = mt312_writereg(state, CONFIG,
- (state->frequency == 60 ? 0x88 : 0x8c));
+ (state->freq_mult == 6 ? 0x88 : 0x8c));
if (ret < 0)
return ret;
@@ -265,12 +266,37 @@ static int mt312_initfe(struct dvb_frontend *fe)
return ret;
}
+ switch (state->id) {
+ case ID_ZL10313:
+ /* enable ADC */
+ ret = mt312_writereg(state, GPP_CTRL, 0x80);
+ if (ret < 0)
+ return ret;
+
+ /* configure ZL10313 for optimal ADC performance */
+ buf[0] = 0x80;
+ buf[1] = 0xB0;
+ ret = mt312_write(state, HW_CTRL, buf, 2);
+ if (ret < 0)
+ return ret;
+
+ /* enable MPEG output and ADCs */
+ ret = mt312_writereg(state, HW_CTRL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ ret = mt312_writereg(state, MPEG_CTRL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ break;
+ }
+
/* SYS_CLK */
- buf[0] = mt312_div((state->frequency == 60 ? MT312_LPOWER_SYS_CLK :
- MT312_SYS_CLK) * 2, 1000000);
+ buf[0] = mt312_div(state->xtal * state->freq_mult * 2, 1000000);
/* DISEQC_RATIO */
- buf[1] = mt312_div(MT312_PLL_CLK, 15000 * 4);
+ buf[1] = mt312_div(state->xtal, 22000 * 4);
ret = mt312_write(state, SYS_CLK, buf, sizeof(buf));
if (ret < 0)
@@ -280,7 +306,17 @@ static int mt312_initfe(struct dvb_frontend *fe)
if (ret < 0)
return ret;
- ret = mt312_writereg(state, OP_CTRL, 0x53);
+ /* different MOCLK polarity */
+ switch (state->id) {
+ case ID_ZL10313:
+ buf[0] = 0x33;
+ break;
+ default:
+ buf[0] = 0x53;
+ break;
+ }
+
+ ret = mt312_writereg(state, OP_CTRL, buf[0]);
if (ret < 0)
return ret;
@@ -323,6 +359,9 @@ static int mt312_send_master_cmd(struct dvb_frontend *fe,
if (ret < 0)
return ret;
+ /* is there a better way to wait for message to be transmitted */
+ msleep(100);
+
/* set DISEQC_MODE[2:0] to zero if a return message is expected */
if (c->msg[0] & 0x02) {
ret = mt312_writereg(state, DISEQC_MODE, (diseqc_mode & 0x40));
@@ -383,11 +422,16 @@ static int mt312_set_voltage(struct dvb_frontend *fe, const fe_sec_voltage_t v)
{
struct mt312_state *state = fe->demodulator_priv;
const u8 volt_tab[3] = { 0x00, 0x40, 0x00 };
+ u8 val;
if (v > SEC_VOLTAGE_OFF)
return -EINVAL;
- return mt312_writereg(state, DISEQC_MODE, volt_tab[v]);
+ val = volt_tab[v];
+ if (state->config->voltage_inverted)
+ val ^= 0x40;
+
+ return mt312_writereg(state, DISEQC_MODE, val);
}
static int mt312_read_status(struct dvb_frontend *fe, fe_status_t *s)
@@ -463,7 +507,7 @@ static int mt312_read_snr(struct dvb_frontend *fe, u16 *snr)
int ret;
u8 buf[2];
- ret = mt312_read(state, M_SNR_H, &buf, sizeof(buf));
+ ret = mt312_read(state, M_SNR_H, buf, sizeof(buf));
if (ret < 0)
return ret;
@@ -478,7 +522,7 @@ static int mt312_read_ucblocks(struct dvb_frontend *fe, u32 *ubc)
int ret;
u8 buf[2];
- ret = mt312_read(state, RS_UBC_H, &buf, sizeof(buf));
+ ret = mt312_read(state, RS_UBC_H, buf, sizeof(buf));
if (ret < 0)
return ret;
@@ -532,17 +576,17 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
return ret;
if (p->u.qpsk.symbol_rate >= 30000000) {
/* Note that 30MS/s should use 90MHz */
- if ((config_val & 0x0c) == 0x08) {
+ if (state->freq_mult == 6) {
/* We are running 60MHz */
- state->frequency = 90;
+ state->freq_mult = 9;
ret = mt312_initfe(fe);
if (ret < 0)
return ret;
}
} else {
- if ((config_val & 0x0c) == 0x0C) {
+ if (state->freq_mult == 9) {
/* We are running 90MHz */
- state->frequency = 60;
+ state->freq_mult = 6;
ret = mt312_initfe(fe);
if (ret < 0)
return ret;
@@ -551,6 +595,7 @@ static int mt312_set_frontend(struct dvb_frontend *fe,
break;
case ID_MT312:
+ case ID_ZL10313:
break;
default:
@@ -616,11 +661,29 @@ static int mt312_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
{
struct mt312_state *state = fe->demodulator_priv;
- if (enable) {
- return mt312_writereg(state, GPP_CTRL, 0x40);
- } else {
- return mt312_writereg(state, GPP_CTRL, 0x00);
+ u8 val = 0x00;
+ int ret;
+
+ switch (state->id) {
+ case ID_ZL10313:
+ ret = mt312_readreg(state, GPP_CTRL, &val);
+ if (ret < 0)
+ goto error;
+
+ /* preserve this bit to not accidently shutdown ADC */
+ val &= 0x80;
+ break;
}
+
+ if (enable)
+ val |= 0x40;
+ else
+ val &= ~0x40;
+
+ ret = mt312_writereg(state, GPP_CTRL, val);
+
+error:
+ return ret;
}
static int mt312_sleep(struct dvb_frontend *fe)
@@ -634,6 +697,18 @@ static int mt312_sleep(struct dvb_frontend *fe)
if (ret < 0)
return ret;
+ if (state->id == ID_ZL10313) {
+ /* reset ADC */
+ ret = mt312_writereg(state, GPP_CTRL, 0x00);
+ if (ret < 0)
+ return ret;
+
+ /* full shutdown of ADCs, mpeg bus tristated */
+ ret = mt312_writereg(state, HW_CTRL, 0x0d);
+ if (ret < 0)
+ return ret;
+ }
+
ret = mt312_readreg(state, CONFIG, &config);
if (ret < 0)
return ret;
@@ -661,6 +736,7 @@ static void mt312_release(struct dvb_frontend *fe)
kfree(state);
}
+#define MT312_SYS_CLK 90000000UL /* 90 MHz */
static struct dvb_frontend_ops vp310_mt312_ops = {
.info = {
@@ -668,8 +744,8 @@ static struct dvb_frontend_ops vp310_mt312_ops = {
.type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
- .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128,
- .symbol_rate_min = MT312_SYS_CLK / 128,
+ .frequency_stepsize = (MT312_PLL_CLK / 1000) / 128, /* FIXME: adjust freq to real used xtal */
+ .symbol_rate_min = MT312_SYS_CLK / 128, /* FIXME as above */
.symbol_rate_max = MT312_SYS_CLK / 2,
.caps =
FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 |
@@ -726,14 +802,21 @@ struct dvb_frontend *vp310_mt312_attach(const struct mt312_config *config,
switch (state->id) {
case ID_VP310:
strcpy(state->frontend.ops.info.name, "Zarlink VP310 DVB-S");
- state->frequency = 90;
+ state->xtal = MT312_PLL_CLK;
+ state->freq_mult = 9;
break;
case ID_MT312:
strcpy(state->frontend.ops.info.name, "Zarlink MT312 DVB-S");
- state->frequency = 60;
+ state->xtal = MT312_PLL_CLK;
+ state->freq_mult = 6;
+ break;
+ case ID_ZL10313:
+ strcpy(state->frontend.ops.info.name, "Zarlink ZL10313 DVB-S");
+ state->xtal = MT312_PLL_CLK_10_111;
+ state->freq_mult = 9;
break;
default:
- printk(KERN_WARNING "Only Zarlink VP310/MT312"
+ printk(KERN_WARNING "Only Zarlink VP310/MT312/ZL10313"
" are supported chips.\n");
goto error;
}
@@ -749,7 +832,7 @@ EXPORT_SYMBOL(vp310_mt312_attach);
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Turn on/off frontend debugging (default:off).");
-MODULE_DESCRIPTION("Zarlink VP310/MT312 DVB-S Demodulator driver");
+MODULE_DESCRIPTION("Zarlink VP310/MT312/ZL10313 DVB-S Demodulator driver");
MODULE_AUTHOR("Andreas Oberritter <obi@linuxtv.org>");
MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/frontends/mt312.h b/linux/drivers/media/dvb/frontends/mt312.h
index afe24fd82..96338f0c4 100644
--- a/linux/drivers/media/dvb/frontends/mt312.h
+++ b/linux/drivers/media/dvb/frontends/mt312.h
@@ -31,6 +31,9 @@
struct mt312_config {
/* the demodulator's i2c address */
u8 demod_address;
+
+ /* inverted voltage setting */
+ int voltage_inverted:1;
};
#if defined(CONFIG_DVB_MT312) || (defined(CONFIG_DVB_MT312_MODULE) && defined(MODULE))
diff --git a/linux/drivers/media/dvb/frontends/mt312_priv.h b/linux/drivers/media/dvb/frontends/mt312_priv.h
index 5e0b95b53..a3959f94d 100644
--- a/linux/drivers/media/dvb/frontends/mt312_priv.h
+++ b/linux/drivers/media/dvb/frontends/mt312_priv.h
@@ -110,6 +110,8 @@ enum mt312_reg_addr {
VIT_ERRPER_H = 83,
VIT_ERRPER_M = 84,
VIT_ERRPER_L = 85,
+ HW_CTRL = 84, /* ZL10313 only */
+ MPEG_CTRL = 85, /* ZL10313 only */
VIT_SETUP = 86,
VIT_REF0 = 87,
VIT_REF1 = 88,
@@ -156,7 +158,8 @@ enum mt312_reg_addr {
enum mt312_model_id {
ID_VP310 = 1,
- ID_MT312 = 3
+ ID_MT312 = 3,
+ ID_ZL10313 = 5,
};
#endif /* DVB_FRONTENDS_MT312_PRIV */
diff --git a/linux/drivers/media/dvb/frontends/s5h1420.c b/linux/drivers/media/dvb/frontends/s5h1420.c
index 1e2d602d3..4f4f8f918 100644
--- a/linux/drivers/media/dvb/frontends/s5h1420.c
+++ b/linux/drivers/media/dvb/frontends/s5h1420.c
@@ -1,24 +1,26 @@
/*
-Driver for Samsung S5H1420 QPSK Demodulator
-
-Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.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.
-
-*/
+ * Driver for
+ * Samsung S5H1420 and
+ * PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#include <linux/kernel.h>
#include <linux/module.h>
@@ -29,23 +31,35 @@ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
#include <linux/jiffies.h>
#include <asm/div64.h>
-#include "dvb_frontend.h"
-#include "s5h1420.h"
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "s5h1420.h"
+#include "s5h1420_priv.h"
#define TONE_FREQ 22000
struct s5h1420_state {
struct i2c_adapter* i2c;
const struct s5h1420_config* config;
+
struct dvb_frontend frontend;
+ struct i2c_adapter tuner_i2c_adapter;
+
+ u8 CON_1_val;
u8 postlocked:1;
u32 fclk;
u32 tunedfreq;
fe_code_rate_t fec_inner;
u32 symbol_rate;
+
+ /* FIXME: ugly workaround for flexcop's incapable i2c-controller
+ * it does not support repeated-start, workaround: write addr-1
+ * and then read
+ */
+ u8 shadow[255];
};
static u32 s5h1420_getsymbolrate(struct s5h1420_state* state);
@@ -54,43 +68,65 @@ static int s5h1420_get_tune_settings(struct dvb_frontend* fe,
static int debug;
-#define dprintk if (debug) printk
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "enable debugging");
+
+#define dprintk(x...) do { \
+ if (debug) \
+ printk(KERN_DEBUG "S5H1420: " x); \
+} while (0)
+
+static u8 s5h1420_readreg(struct s5h1420_state *state, u8 reg)
+{
+ int ret;
+ u8 b[2];
+ struct i2c_msg msg[] = {
+ { .addr = state->config->demod_address, .flags = 0, .buf = b, .len = 2 },
+ { .addr = state->config->demod_address, .flags = 0, .buf = &reg, .len = 1 },
+ { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b, .len = 1 },
+ };
+
+ b[0] = (reg - 1) & 0xff;
+ b[1] = state->shadow[(reg - 1) & 0xff];
+
+ if (state->config->repeated_start_workaround) {
+ ret = i2c_transfer(state->i2c, msg, 3);
+ if (ret != 3)
+ return ret;
+ } else {
+ ret = i2c_transfer(state->i2c, &msg[1], 2);
+ if (ret != 2)
+ return ret;
+ }
+
+ /* dprintk("rd(%02x): %02x %02x\n", state->config->demod_address, reg, b[0]); */
+
+ return b[0];
+}
static int s5h1420_writereg (struct s5h1420_state* state, u8 reg, u8 data)
{
- u8 buf [] = { reg, data };
+ u8 buf[] = { reg, data };
struct i2c_msg msg = { .addr = state->config->demod_address, .flags = 0, .buf = buf, .len = 2 };
int err;
- if ((err = i2c_transfer (state->i2c, &msg, 1)) != 1) {
- dprintk ("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
+ /* dprintk("wr(%02x): %02x %02x\n", state->config->demod_address, reg, data); */
+ err = i2c_transfer(state->i2c, &msg, 1);
+ if (err != 1) {
+ dprintk("%s: writereg error (err == %i, reg == 0x%02x, data == 0x%02x)\n", __func__, err, reg, data);
return -EREMOTEIO;
}
+ state->shadow[reg] = data;
return 0;
}
-static u8 s5h1420_readreg (struct s5h1420_state* state, u8 reg)
-{
- int ret;
- u8 b0 [] = { reg };
- u8 b1 [] = { 0 };
- struct i2c_msg msg1 = { .addr = state->config->demod_address, .flags = 0, .buf = b0, .len = 1 };
- struct i2c_msg msg2 = { .addr = state->config->demod_address, .flags = I2C_M_RD, .buf = b1, .len = 1 };
-
- if ((ret = i2c_transfer (state->i2c, &msg1, 1)) != 1)
- return ret;
-
- if ((ret = i2c_transfer (state->i2c, &msg2, 1)) != 1)
- return ret;
-
- return b1[0];
-}
-
static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltage)
{
struct s5h1420_state* state = fe->demodulator_priv;
+ dprintk("enter %s\n", __func__);
+
switch(voltage) {
case SEC_VOLTAGE_13:
s5h1420_writereg(state, 0x3c,
@@ -106,6 +142,7 @@ static int s5h1420_set_voltage (struct dvb_frontend* fe, fe_sec_voltage_t voltag
break;
}
+ dprintk("leave %s\n", __func__);
return 0;
}
@@ -113,6 +150,7 @@ static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
{
struct s5h1420_state* state = fe->demodulator_priv;
+ dprintk("enter %s\n", __func__);
switch(tone) {
case SEC_TONE_ON:
s5h1420_writereg(state, 0x3b,
@@ -124,6 +162,7 @@ static int s5h1420_set_tone (struct dvb_frontend* fe, fe_sec_tone_mode_t tone)
(s5h1420_readreg(state, 0x3b) & 0x74) | 0x01);
break;
}
+ dprintk("leave %s\n", __func__);
return 0;
}
@@ -137,6 +176,7 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe,
unsigned long timeout;
int result = 0;
+ dprintk("enter %s\n", __func__);
if (cmd->msg_len > 8)
return -EINVAL;
@@ -168,6 +208,7 @@ static int s5h1420_send_master_cmd (struct dvb_frontend* fe,
/* restore original settings */
s5h1420_writereg(state, 0x3b, val);
msleep(15);
+ dprintk("leave %s\n", __func__);
return result;
}
@@ -289,6 +330,8 @@ static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
struct s5h1420_state* state = fe->demodulator_priv;
u8 val;
+ dprintk("enter %s\n", __func__);
+
if (status == NULL)
return -EINVAL;
@@ -297,13 +340,13 @@ static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
/* fix for FEC 5/6 inversion issue - if it doesn't quite lock, invert
the inversion, wait a bit and check again */
- if (*status == (FE_HAS_SIGNAL|FE_HAS_CARRIER|FE_HAS_VITERBI)) {
- val = s5h1420_readreg(state, 0x32);
+ if (*status == (FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_VITERBI)) {
+ val = s5h1420_readreg(state, Vit10);
if ((val & 0x07) == 0x03) {
if (val & 0x08)
- s5h1420_writereg(state, 0x31, 0x13);
+ s5h1420_writereg(state, Vit09, 0x13);
else
- s5h1420_writereg(state, 0x31, 0x1b);
+ s5h1420_writereg(state, Vit09, 0x1b);
/* wait a bit then update lock status */
mdelay(200);
@@ -312,68 +355,77 @@ static int s5h1420_read_status(struct dvb_frontend* fe, fe_status_t* status)
}
/* perform post lock setup */
- if ((*status & FE_HAS_LOCK) && (!state->postlocked)) {
+ if ((*status & FE_HAS_LOCK) && !state->postlocked) {
/* calculate the data rate */
u32 tmp = s5h1420_getsymbolrate(state);
- switch(s5h1420_readreg(state, 0x32) & 0x07) {
- case 0:
- tmp = (tmp * 2 * 1) / 2;
- break;
-
- case 1:
- tmp = (tmp * 2 * 2) / 3;
- break;
-
- case 2:
- tmp = (tmp * 2 * 3) / 4;
- break;
-
- case 3:
- tmp = (tmp * 2 * 5) / 6;
- break;
-
- case 4:
- tmp = (tmp * 2 * 6) / 7;
- break;
-
- case 5:
- tmp = (tmp * 2 * 7) / 8;
- break;
+ switch (s5h1420_readreg(state, Vit10) & 0x07) {
+ case 0: tmp = (tmp * 2 * 1) / 2; break;
+ case 1: tmp = (tmp * 2 * 2) / 3; break;
+ case 2: tmp = (tmp * 2 * 3) / 4; break;
+ case 3: tmp = (tmp * 2 * 5) / 6; break;
+ case 4: tmp = (tmp * 2 * 6) / 7; break;
+ case 5: tmp = (tmp * 2 * 7) / 8; break;
}
+
if (tmp == 0) {
- printk("s5h1420: avoided division by 0\n");
+ printk(KERN_ERR "s5h1420: avoided division by 0\n");
tmp = 1;
}
tmp = state->fclk / tmp;
+
/* set the MPEG_CLK_INTL for the calculated data rate */
- if (tmp < 4)
+ if (tmp < 2)
val = 0x00;
- else if (tmp < 8)
+ else if (tmp < 5)
val = 0x01;
- else if (tmp < 12)
+ else if (tmp < 9)
val = 0x02;
- else if (tmp < 16)
+ else if (tmp < 13)
val = 0x03;
- else if (tmp < 24)
+ else if (tmp < 17)
val = 0x04;
- else if (tmp < 32)
+ else if (tmp < 25)
val = 0x05;
- else
+ else if (tmp < 33)
val = 0x06;
- s5h1420_writereg(state, 0x22, val);
-
- /* DC freeze */
- s5h1420_writereg(state, 0x1f, s5h1420_readreg(state, 0x1f) | 0x01);
-
- /* kicker disable + remove DC offset */
- s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) & 0x6f);
+ else
+ val = 0x07;
+ dprintk("for MPEG_CLK_INTL %d %x\n", tmp, val);
+
+ s5h1420_writereg(state, FEC01, 0x18);
+ s5h1420_writereg(state, FEC01, 0x10);
+ s5h1420_writereg(state, FEC01, val);
+
+ /* Enable "MPEG_Out" */
+ val = s5h1420_readreg(state, Mpeg02);
+ s5h1420_writereg(state, Mpeg02, val | (1 << 6));
+
+ /* kicker disable */
+ val = s5h1420_readreg(state, QPSK01) & 0x7f;
+ s5h1420_writereg(state, QPSK01, val);
+
+ /* DC freeze TODO it was never activated by default or it can stay activated */
+#if 0
+ val = s5h1420_readreg(state, 0x1f);
+ s5h1420_writereg(state, 0x1f, val | 0x01);
+#endif
+
+ if (s5h1420_getsymbolrate(state) >= 20000000) {
+ s5h1420_writereg(state, Loop04, 0x8a);
+ s5h1420_writereg(state, Loop05, 0x6a);
+ } else {
+ s5h1420_writereg(state, Loop04, 0x58);
+ s5h1420_writereg(state, Loop05, 0x27);
+ }
/* post-lock processing has been done! */
state->postlocked = 1;
}
+ dprintk("leave %s\n", __func__);
+
return 0;
}
@@ -414,6 +466,7 @@ static int s5h1420_read_ucblocks(struct dvb_frontend* fe, u32* ucblocks)
static void s5h1420_reset(struct s5h1420_state* state)
{
+ dprintk("%s\n", __func__);
s5h1420_writereg (state, 0x01, 0x08);
s5h1420_writereg (state, 0x01, 0x00);
udelay(10);
@@ -422,54 +475,79 @@ static void s5h1420_reset(struct s5h1420_state* state)
static void s5h1420_setsymbolrate(struct s5h1420_state* state,
struct dvb_frontend_parameters *p)
{
+ u8 v;
u64 val;
+ dprintk("enter %s\n", __func__);
+
val = ((u64) p->u.qpsk.symbol_rate / 1000ULL) * (1ULL<<24);
- if (p->u.qpsk.symbol_rate <= 21000000) {
+ if (p->u.qpsk.symbol_rate < 29000000)
val *= 2;
- }
do_div(val, (state->fclk / 1000));
- s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0x7f);
- s5h1420_writereg(state, 0x11, val >> 16);
- s5h1420_writereg(state, 0x12, val >> 8);
- s5h1420_writereg(state, 0x13, val & 0xff);
- s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x80);
+ dprintk("symbol rate register: %06llx\n", val);
+
+ v = s5h1420_readreg(state, Loop01);
+ s5h1420_writereg(state, Loop01, v & 0x7f);
+ s5h1420_writereg(state, Tnco01, val >> 16);
+ s5h1420_writereg(state, Tnco02, val >> 8);
+ s5h1420_writereg(state, Tnco03, val & 0xff);
+ s5h1420_writereg(state, Loop01, v | 0x80);
+ dprintk("leave %s\n", __func__);
}
static u32 s5h1420_getsymbolrate(struct s5h1420_state* state)
{
+#if 0
+ /* TODO getsymbolrate gives strange values - something is wrong with
+ * configuring the read
+ */
+
u64 val = 0;
+ u8 v;
int sampling = 2;
- if (s5h1420_readreg(state, 0x05) & 0x2)
- sampling = 1;
+ v = s5h1420_readreg(state, QPSK02);
+ s5h1420_writereg(state, QPSK02, v | 0x08);
+ val = s5h1420_readreg(state, Tnco01) << 16;
+ val |= s5h1420_readreg(state, Tnco02) << 8;
+ val |= s5h1420_readreg(state, Tnco03);
+ s5h1420_writereg(state, QPSK02, v & 0xf7);
- s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) | 0x08);
- val = s5h1420_readreg(state, 0x11) << 16;
- val |= s5h1420_readreg(state, 0x12) << 8;
- val |= s5h1420_readreg(state, 0x13);
- s5h1420_writereg(state, 0x06, s5h1420_readreg(state, 0x06) & 0xf7);
+ dprintk("get_symbolrate: raw: %x\n", val);
- val *= (state->fclk / 1000ULL);
- do_div(val, ((1<<24) * sampling));
+ val *= (state->fclk / 1000);
+ if (s5h1420_readreg(state, QPSK01) & 0x2)
+ do_div(val, 1 << 24);
+ else
+ do_div(val, 1 << 25);
+ dprintk("get_symbolrate: %d\n", (u32) (val * 1000ULL));
return (u32) (val * 1000ULL);
+#endif
+ return state->symbol_rate;
}
static void s5h1420_setfreqoffset(struct s5h1420_state* state, int freqoffset)
{
int val;
+ u8 v;
+
+ dprintk("enter %s\n", __func__);
/* remember freqoffset is in kHz, but the chip wants the offset in Hz, so
* divide fclk by 1000000 to get the correct value. */
val = -(int) ((freqoffset * (1<<24)) / (state->fclk / 1000000));
- s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) & 0xbf);
- s5h1420_writereg(state, 0x0e, val >> 16);
- s5h1420_writereg(state, 0x0f, val >> 8);
- s5h1420_writereg(state, 0x10, val & 0xff);
- s5h1420_writereg(state, 0x09, s5h1420_readreg(state, 0x09) | 0x40);
+ dprintk("phase rotator/freqoffset: %d %06x\n", freqoffset, val);
+
+ v = s5h1420_readreg(state, Loop01);
+ s5h1420_writereg(state, Loop01, v & 0xbf);
+ s5h1420_writereg(state, Pnco01, val >> 16);
+ s5h1420_writereg(state, Pnco02, val >> 8);
+ s5h1420_writereg(state, Pnco03, val & 0xff);
+ s5h1420_writereg(state, Loop01, v | 0x40);
+ dprintk("leave %s\n", __func__);
}
static int s5h1420_getfreqoffset(struct s5h1420_state* state)
@@ -496,52 +574,53 @@ static void s5h1420_setfec_inversion(struct s5h1420_state* state,
struct dvb_frontend_parameters *p)
{
u8 inversion = 0;
+ u8 vit08, vit09;
+
+ dprintk("enter %s\n", __func__);
- if (p->inversion == INVERSION_OFF) {
+ if (p->inversion == INVERSION_OFF)
inversion = state->config->invert ? 0x08 : 0;
- } else if (p->inversion == INVERSION_ON) {
+ else if (p->inversion == INVERSION_ON)
inversion = state->config->invert ? 0 : 0x08;
- }
if ((p->u.qpsk.fec_inner == FEC_AUTO) || (p->inversion == INVERSION_AUTO)) {
- s5h1420_writereg(state, 0x30, 0x3f);
- s5h1420_writereg(state, 0x31, 0x00 | inversion);
+ vit08 = 0x3f;
+ vit09 = 0;
} else {
switch(p->u.qpsk.fec_inner) {
case FEC_1_2:
- s5h1420_writereg(state, 0x30, 0x01);
- s5h1420_writereg(state, 0x31, 0x10 | inversion);
+ vit08 = 0x01; vit09 = 0x10;
break;
case FEC_2_3:
- s5h1420_writereg(state, 0x30, 0x02);
- s5h1420_writereg(state, 0x31, 0x11 | inversion);
+ vit08 = 0x02; vit09 = 0x11;
break;
case FEC_3_4:
- s5h1420_writereg(state, 0x30, 0x04);
- s5h1420_writereg(state, 0x31, 0x12 | inversion);
+ vit08 = 0x04; vit09 = 0x12;
break;
case FEC_5_6:
- s5h1420_writereg(state, 0x30, 0x08);
- s5h1420_writereg(state, 0x31, 0x13 | inversion);
+ vit08 = 0x08; vit09 = 0x13;
break;
case FEC_6_7:
- s5h1420_writereg(state, 0x30, 0x10);
- s5h1420_writereg(state, 0x31, 0x14 | inversion);
+ vit08 = 0x10; vit09 = 0x14;
break;
case FEC_7_8:
- s5h1420_writereg(state, 0x30, 0x20);
- s5h1420_writereg(state, 0x31, 0x15 | inversion);
+ vit08 = 0x20; vit09 = 0x15;
break;
default:
return;
}
}
+ vit09 |= inversion;
+ dprintk("fec: %02x %02x\n", vit08, vit09);
+ s5h1420_writereg(state, Vit08, vit08);
+ s5h1420_writereg(state, Vit09, vit09);
+ dprintk("leave %s\n", __func__);
}
static fe_code_rate_t s5h1420_getfec(struct s5h1420_state* state)
@@ -583,16 +662,19 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
struct s5h1420_state* state = fe->demodulator_priv;
int frequency_delta;
struct dvb_frontend_tune_settings fesettings;
+ uint8_t clock_settting;
+
+ dprintk("enter %s\n", __func__);
/* check if we should do a fast-tune */
memcpy(&fesettings.parameters, p, sizeof(struct dvb_frontend_parameters));
s5h1420_get_tune_settings(fe, &fesettings);
frequency_delta = p->frequency - state->tunedfreq;
if ((frequency_delta > -fesettings.max_drift) &&
- (frequency_delta < fesettings.max_drift) &&
- (frequency_delta != 0) &&
- (state->fec_inner == p->u.qpsk.fec_inner) &&
- (state->symbol_rate == p->u.qpsk.symbol_rate)) {
+ (frequency_delta < fesettings.max_drift) &&
+ (frequency_delta != 0) &&
+ (state->fec_inner == p->u.qpsk.fec_inner) &&
+ (state->symbol_rate == p->u.qpsk.symbol_rate)) {
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, p);
@@ -606,54 +688,93 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
} else {
s5h1420_setfreqoffset(state, 0);
}
+ dprintk("simple tune\n");
return 0;
}
+ dprintk("tuning demod\n");
/* first of all, software reset */
s5h1420_reset(state);
/* set s5h1420 fclk PLL according to desired symbol rate */
- if (p->u.qpsk.symbol_rate > 28000000) {
- state->fclk = 88000000;
- s5h1420_writereg(state, 0x03, 0x50);
- s5h1420_writereg(state, 0x04, 0x40);
- s5h1420_writereg(state, 0x05, 0xae);
- } else if (p->u.qpsk.symbol_rate > 21000000) {
+ if (p->u.qpsk.symbol_rate > 33000000)
+ state->fclk = 80000000;
+ else if (p->u.qpsk.symbol_rate > 28500000)
state->fclk = 59000000;
- s5h1420_writereg(state, 0x03, 0x33);
- s5h1420_writereg(state, 0x04, 0x40);
- s5h1420_writereg(state, 0x05, 0xae);
- } else {
+ else if (p->u.qpsk.symbol_rate > 25000000)
+ state->fclk = 86000000;
+ else if (p->u.qpsk.symbol_rate > 1900000)
state->fclk = 88000000;
- s5h1420_writereg(state, 0x03, 0x50);
- s5h1420_writereg(state, 0x04, 0x40);
- s5h1420_writereg(state, 0x05, 0xac);
+ else
+ state->fclk = 44000000;
+
+ /* Clock */
+ switch (state->fclk) {
+ default:
+ case 88000000:
+ clock_settting = 80;
+ break;
+ case 86000000:
+ clock_settting = 78;
+ break;
+ case 80000000:
+ clock_settting = 72;
+ break;
+ case 59000000:
+ clock_settting = 51;
+ break;
+ case 44000000:
+ clock_settting = 36;
+ break;
}
+ dprintk("pll01: %d, ToneFreq: %d\n", state->fclk/1000000 - 8, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
+ s5h1420_writereg(state, PLL01, state->fclk/1000000 - 8);
+ s5h1420_writereg(state, PLL02, 0x40);
+ s5h1420_writereg(state, DiS01, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
- /* set misc registers */
- s5h1420_writereg(state, 0x02, 0x00);
- s5h1420_writereg(state, 0x06, 0x00);
- s5h1420_writereg(state, 0x07, 0xb0);
- s5h1420_writereg(state, 0x0a, 0xe7);
- s5h1420_writereg(state, 0x0b, 0x78);
- s5h1420_writereg(state, 0x0c, 0x48);
- s5h1420_writereg(state, 0x0d, 0x6b);
- s5h1420_writereg(state, 0x2e, 0x8e);
- s5h1420_writereg(state, 0x35, 0x33);
- s5h1420_writereg(state, 0x38, 0x01);
- s5h1420_writereg(state, 0x39, 0x7d);
- s5h1420_writereg(state, 0x3a, (state->fclk + (TONE_FREQ * 32) - 1) / (TONE_FREQ * 32));
- s5h1420_writereg(state, 0x3c, 0x00);
- s5h1420_writereg(state, 0x45, 0x61);
- s5h1420_writereg(state, 0x46, 0x1d);
+ /* TODO DC offset removal, config parameter ? */
+ if (p->u.qpsk.symbol_rate > 29000000)
+ s5h1420_writereg(state, QPSK01, 0xae | 0x10);
+ else
+ s5h1420_writereg(state, QPSK01, 0xac | 0x10);
- /* start QPSK */
- s5h1420_writereg(state, 0x05, s5h1420_readreg(state, 0x05) | 1);
+ /* set misc registers */
+ s5h1420_writereg(state, CON_1, 0x00);
+ s5h1420_writereg(state, QPSK02, 0x00);
+ s5h1420_writereg(state, Pre01, 0xb0);
+
+ s5h1420_writereg(state, Loop01, 0xF0);
+ s5h1420_writereg(state, Loop02, 0x2a); /* e7 for s5h1420 */
+ s5h1420_writereg(state, Loop03, 0x79); /* 78 for s5h1420 */
+ if (p->u.qpsk.symbol_rate > 20000000)
+ s5h1420_writereg(state, Loop04, 0x79);
+ else
+ s5h1420_writereg(state, Loop04, 0x58);
+ s5h1420_writereg(state, Loop05, 0x6b);
+
+ if (p->u.qpsk.symbol_rate >= 8000000)
+ s5h1420_writereg(state, Post01, (0 << 6) | 0x10);
+ else if (p->u.qpsk.symbol_rate >= 4000000)
+ s5h1420_writereg(state, Post01, (1 << 6) | 0x10);
+ else
+ s5h1420_writereg(state, Post01, (3 << 6) | 0x10);
+
+ s5h1420_writereg(state, Monitor12, 0x00); /* unfreeze DC compensation */
+
+ s5h1420_writereg(state, Sync01, 0x33);
+ s5h1420_writereg(state, Mpeg01, state->config->cdclk_polarity);
+ s5h1420_writereg(state, Mpeg02, 0x3d); /* Parallel output more, disabled -> enabled later */
+ s5h1420_writereg(state, Err01, 0x03); /* 0x1d for s5h1420 */
+
+ s5h1420_writereg(state, Vit06, 0x6e); /* 0x8e for s5h1420 */
+ s5h1420_writereg(state, DiS03, 0x00);
+ s5h1420_writereg(state, Rf01, 0x61); /* Tuner i2c address - for the gate controller */
/* set tuner PLL */
if (fe->ops.tuner_ops.set_params) {
fe->ops.tuner_ops.set_params(fe, p);
- if (fe->ops.i2c_gate_ctrl) fe->ops.i2c_gate_ctrl(fe, 0);
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
s5h1420_setfreqoffset(state, 0);
}
@@ -661,10 +782,15 @@ static int s5h1420_set_frontend(struct dvb_frontend* fe,
s5h1420_setsymbolrate(state, p);
s5h1420_setfec_inversion(state, p);
+ /* start QPSK */
+ s5h1420_writereg(state, QPSK01, s5h1420_readreg(state, QPSK01) | 1);
+
state->fec_inner = p->u.qpsk.fec_inner;
state->symbol_rate = p->u.qpsk.symbol_rate;
state->postlocked = 0;
state->tunedfreq = p->frequency;
+
+ dprintk("leave %s\n", __func__);
return 0;
}
@@ -717,11 +843,10 @@ static int s5h1420_i2c_gate_ctrl(struct dvb_frontend* fe, int enable)
{
struct s5h1420_state* state = fe->demodulator_priv;
- if (enable) {
- return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) | 1);
- } else {
- return s5h1420_writereg (state, 0x02, s5h1420_readreg(state,0x02) & 0xfe);
- }
+ if (enable)
+ return s5h1420_writereg(state, 0x02, state->CON_1_val | 1);
+ else
+ return s5h1420_writereg(state, 0x02, state->CON_1_val & 0xfe);
}
static int s5h1420_init (struct dvb_frontend* fe)
@@ -729,7 +854,8 @@ static int s5h1420_init (struct dvb_frontend* fe)
struct s5h1420_state* state = fe->demodulator_priv;
/* disable power down and do reset */
- s5h1420_writereg(state, 0x02, 0x10);
+ state->CON_1_val = 0x10;
+ s5h1420_writereg(state, 0x02, state->CON_1_val);
msleep(10);
s5h1420_reset(state);
@@ -739,26 +865,60 @@ static int s5h1420_init (struct dvb_frontend* fe)
static int s5h1420_sleep(struct dvb_frontend* fe)
{
struct s5h1420_state* state = fe->demodulator_priv;
-
- return s5h1420_writereg(state, 0x02, 0x12);
+ state->CON_1_val = 0x12;
+ return s5h1420_writereg(state, 0x02, state->CON_1_val);
}
static void s5h1420_release(struct dvb_frontend* fe)
{
struct s5h1420_state* state = fe->demodulator_priv;
+ i2c_del_adapter(&state->tuner_i2c_adapter);
kfree(state);
}
-static struct dvb_frontend_ops s5h1420_ops;
+static u32 s5h1420_tuner_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+static int s5h1420_tuner_i2c_tuner_xfer(struct i2c_adapter *i2c_adap, struct i2c_msg msg[], int num)
+{
+ struct s5h1420_state *state = i2c_get_adapdata(i2c_adap);
+ struct i2c_msg m[1 + num];
+ u8 tx_open[2] = { CON_1, state->CON_1_val | 1 }; /* repeater stops once there was a stop condition */
+
+ memset(m, 0, sizeof(struct i2c_msg) * (1 + num));
+
+ m[0].addr = state->config->demod_address;
+ m[0].buf = tx_open;
+ m[0].len = 2;
+
+ memcpy(&m[1], msg, sizeof(struct i2c_msg) * num);
-struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
- struct i2c_adapter* i2c)
+ return i2c_transfer(state->i2c, m, 1+num) == 1 + num ? num : -EIO;
+}
+
+static struct i2c_algorithm s5h1420_tuner_i2c_algo = {
+ .master_xfer = s5h1420_tuner_i2c_tuner_xfer,
+ .functionality = s5h1420_tuner_i2c_func,
+};
+
+struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
{
- struct s5h1420_state* state = NULL;
- u8 identity;
+ struct s5h1420_state *state = fe->demodulator_priv;
+ return &state->tuner_i2c_adapter;
+}
+EXPORT_SYMBOL(s5h1420_get_tuner_i2c_adapter);
+
+static struct dvb_frontend_ops s5h1420_ops;
+struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+ struct i2c_adapter *i2c)
+{
/* allocate memory for the internal state */
- state = kmalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
+ struct s5h1420_state *state = kzalloc(sizeof(struct s5h1420_state), GFP_KERNEL);
+ u8 i;
+
if (state == NULL)
goto error;
@@ -772,24 +932,42 @@ struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
state->symbol_rate = 0;
/* check if the demod is there + identify it */
- identity = s5h1420_readreg(state, 0x00);
- if (identity != 0x03)
+ i = s5h1420_readreg(state, ID01);
+ if (i != 0x03)
goto error;
+ memset(state->shadow, 0xff, sizeof(state->shadow));
+
+ for (i = 0; i < 0x50; i++)
+ state->shadow[i] = s5h1420_readreg(state, i);
+
/* create dvb_frontend */
memcpy(&state->frontend.ops, &s5h1420_ops, sizeof(struct dvb_frontend_ops));
state->frontend.demodulator_priv = state;
+
+ /* create tuner i2c adapter */
+ strncpy(state->tuner_i2c_adapter.name, "S5H1420-PN1010 tuner I2C bus", I2C_NAME_SIZE);
+ state->tuner_i2c_adapter.class = I2C_CLASS_TV_DIGITAL,
+ state->tuner_i2c_adapter.algo = &s5h1420_tuner_i2c_algo;
+ state->tuner_i2c_adapter.algo_data = NULL;
+ i2c_set_adapdata(&state->tuner_i2c_adapter, state);
+ if (i2c_add_adapter(&state->tuner_i2c_adapter) < 0) {
+ printk(KERN_ERR "S5H1420/PN1010: tuner i2c bus could not be initialized\n");
+ goto error;
+ }
+
return &state->frontend;
error:
kfree(state);
return NULL;
}
+EXPORT_SYMBOL(s5h1420_attach);
static struct dvb_frontend_ops s5h1420_ops = {
.info = {
- .name = "Samsung S5H1420 DVB-S",
+ .name = "Samsung S5H1420/PnpNetwork PN1010 DVB-S",
.type = FE_QPSK,
.frequency_min = 950000,
.frequency_max = 2150000,
@@ -826,10 +1004,6 @@ static struct dvb_frontend_ops s5h1420_ops = {
.set_voltage = s5h1420_set_voltage,
};
-module_param(debug, int, 0644);
-
-MODULE_DESCRIPTION("Samsung S5H1420 DVB-S Demodulator driver");
-MODULE_AUTHOR("Andrew de Quincey");
+MODULE_DESCRIPTION("Samsung S5H1420/PnpNetwork PN1010 DVB-S Demodulator driver");
+MODULE_AUTHOR("Andrew de Quincey, Patrick Boettcher");
MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(s5h1420_attach);
diff --git a/linux/drivers/media/dvb/frontends/s5h1420.h b/linux/drivers/media/dvb/frontends/s5h1420.h
index 2cc785012..4c913f142 100644
--- a/linux/drivers/media/dvb/frontends/s5h1420.h
+++ b/linux/drivers/media/dvb/frontends/s5h1420.h
@@ -1,25 +1,26 @@
/*
- Driver for S5H1420 QPSK Demodulators
-
- Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.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.
-
-*/
-
+ * Driver for
+ * Samsung S5H1420 and
+ * PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005-8 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
#ifndef S5H1420_H
#define S5H1420_H
@@ -31,19 +32,28 @@ struct s5h1420_config
u8 demod_address;
/* does the inversion require inversion? */
- u8 invert:1;
+ u8 invert : 1;
+
+ u8 repeated_start_workaround : 1;
+ u8 cdclk_polarity : 1; /* 1 == falling edge, 0 == raising edge */
};
#if defined(CONFIG_DVB_S5H1420) || (defined(CONFIG_DVB_S5H1420_MODULE) && defined(MODULE))
-extern struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
- struct i2c_adapter* i2c);
+extern struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+ struct i2c_adapter *i2c);
+extern struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe);
#else
-static inline struct dvb_frontend* s5h1420_attach(const struct s5h1420_config* config,
- struct i2c_adapter* i2c)
+static inline struct dvb_frontend *s5h1420_attach(const struct s5h1420_config *config,
+ struct i2c_adapter *i2c)
{
printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
return NULL;
}
+
+static inline struct i2c_adapter *s5h1420_get_tuner_i2c_adapter(struct dvb_frontend *fe)
+{
+ return NULL;
+}
#endif // CONFIG_DVB_S5H1420
#endif // S5H1420_H
diff --git a/linux/drivers/media/dvb/frontends/s5h1420_priv.h b/linux/drivers/media/dvb/frontends/s5h1420_priv.h
new file mode 100644
index 000000000..7962bbfb6
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/s5h1420_priv.h
@@ -0,0 +1,380 @@
+/*
+ * Driver for
+ * Samsung S5H1420 and
+ * PnpNetwork PN1010 QPSK Demodulator
+ *
+ * Copyright (C) 2005 Andrew de Quincey <adq_dvb@lidskialf.net>
+ * Copyright (C) 2005 Patrick Boettcher <pb@linuxtv.org>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the
+ *
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 675 Mass
+ * Ave, Cambridge, MA 02139, USA.
+ */
+#ifndef S5H1420_PRIV
+#define S5H1420_PRIV
+
+#include <asm/types.h>
+
+enum s5h1420_register {
+ ID01 = 0x00,
+ CON_0 = 0x01,
+ CON_1 = 0x02,
+ PLL01 = 0x03,
+ PLL02 = 0x04,
+ QPSK01 = 0x05,
+ QPSK02 = 0x06,
+ Pre01 = 0x07,
+ Post01 = 0x08,
+ Loop01 = 0x09,
+ Loop02 = 0x0a,
+ Loop03 = 0x0b,
+ Loop04 = 0x0c,
+ Loop05 = 0x0d,
+ Pnco01 = 0x0e,
+ Pnco02 = 0x0f,
+ Pnco03 = 0x10,
+ Tnco01 = 0x11,
+ Tnco02 = 0x12,
+ Tnco03 = 0x13,
+ Monitor01 = 0x14,
+ Monitor02 = 0x15,
+ Monitor03 = 0x16,
+ Monitor04 = 0x17,
+ Monitor05 = 0x18,
+ Monitor06 = 0x19,
+ Monitor07 = 0x1a,
+ Monitor12 = 0x1f,
+
+ FEC01 = 0x22,
+ Soft01 = 0x23,
+ Soft02 = 0x24,
+ Soft03 = 0x25,
+ Soft04 = 0x26,
+ Soft05 = 0x27,
+ Soft06 = 0x28,
+ Vit01 = 0x29,
+ Vit02 = 0x2a,
+ Vit03 = 0x2b,
+ Vit04 = 0x2c,
+ Vit05 = 0x2d,
+ Vit06 = 0x2e,
+ Vit07 = 0x2f,
+ Vit08 = 0x30,
+ Vit09 = 0x31,
+ Vit10 = 0x32,
+ Vit11 = 0x33,
+ Vit12 = 0x34,
+ Sync01 = 0x35,
+ Sync02 = 0x36,
+ Rs01 = 0x37,
+ Mpeg01 = 0x38,
+ Mpeg02 = 0x39,
+ DiS01 = 0x3a,
+ DiS02 = 0x3b,
+ DiS03 = 0x3c,
+ DiS04 = 0x3d,
+ DiS05 = 0x3e,
+ DiS06 = 0x3f,
+ DiS07 = 0x40,
+ DiS08 = 0x41,
+ DiS09 = 0x42,
+ DiS10 = 0x43,
+ DiS11 = 0x44,
+ Rf01 = 0x45,
+ Err01 = 0x46,
+ Err02 = 0x47,
+ Err03 = 0x48,
+ Err04 = 0x49,
+};
+
+#if 0
+
+regsiter mapping follows
+
+/* ID01 */
+#define PN1010_ID 7, 0
+
+/* CON_0 */
+#define QPSK_ONLY 4, 4
+#define SOFT_RST 3, 3 /* System soft reset mode (active high) [1] Enable [0] Disable */
+#define CLK_MODE 2, 2
+#define BPSK_QPSK 1, 1
+#define DSS_DVB 0, 0 /* DSS/DVB mode selection [1] DSS [0] DVB */
+
+/* CON_1 */
+#define ADC_SPD 6, 6
+#define PLL_OEN 5, 5
+#define SER_SEL 4, 4
+#define XTAL_OEN 3, 3
+#define Q_TEST 2, 2
+#define PWR_DN 1, 1 /* Power down mode [1] Power down enable, [0] Power down disable */
+#define I2C_RPT 0, 0 /* I2C repeater control [1] I2C repeater enable, [0] I2C repeater disable.
+ * Note: The master should be set this bit to "1" in order to interface with the tuner.
+ * When the master is not communicated with the tuner, this bit should be set to "0" */
+
+/* PLL programming information
+ * Fout = ((M+8)*Fin)/((P+2)*2^S), Fin = 4 MHz */
+/* PLL01 */
+#define M 7, 0
+
+/* PLL02 */
+#define P 5, 0
+#define S 7, 6
+
+/* QPSK01 */
+#define KICK_EN 7, 7 /* [1] PLL Kicker enable [0] Disable */
+#define ROLL_OFF 6, 6
+#define SCALE_EN 5, 5
+#define DC_EN 4, 4 /* DC offset remove [1] Enable [0] Disable */
+#define VMODE 3, 3
+#define TGL_MSB 2, 2
+#define MODE_QPSK 1, 1 /* QPSK operation mode [1] 1 sampling/1 symbol [0] 2 sampling/1 symbol */
+#define Q_SRESET_N 0, 0 /* QPSK start signal [1] Start [0] Idle */
+
+/* QPSK02 */
+#define DUMP_ACC 3, 3 /* Dump phase loop filter & timing loop filter accumulator [0 and then 1]
+ * The read operation enabled, when user set DUMP_ACC "0" and then "1". */
+#define DC_WIN 2, 0 /* Window position from MSB (0 <= DC_WIN <= 7) */
+
+/* AGC Controls */
+/* Pre01 */
+#define PRE_TH 4, 0 /* PRE-AGC threshold */
+#define INV_PULSE 7, 7 /* PWM signal is reversed [1] PWM signal active low [0] PWM signal active high */
+
+/* Post01 */
+#define RRC_SCALE 7, 6
+#define POST_TH 5, 0 /* POST-AGC threshold */
+
+/* Loop Controls */
+/* Loop01 */
+#define WT_TNCO 7, 7 /* Write TNCO center frequency [0 and then 1] The write operation enabled, when user set WT_TNCO "0" and then "1" */
+#define WT_PNCO 6, 6 /* Write PNCO center frequency [0 and then 1] The write operation enabled, when user set WT_PNCO "0" and then "1" */
+
+/* Loop02 */
+#define LOOP_OUT 7, 7 /* Loop filter monitoring selection [1] Loop filter accumulator + NCO [0] Loop filter accumulator */
+#define KICK_VAL 6, 4 /* The value that gets injected into the accumulator when a "kick" is needed. */
+#define KICK_MUL 3, 0 /* The number of bits KICK_VAL is up-shifted (2^N) before it is injected into the accumulator. */
+
+/* Loop03 */
+#define IGA_PLF 7, 4 /* Phase loop, integral gain (2^IGA_PLF) in the acquisition mode */
+#define PGA_PLF 3, 0 /* Phase loop, proportional gain (2^PGA_PLF) in the acquisition mode (default +8 added) */
+
+/* Loop04 */
+#define IGT_PLF 7, 4 /* Integral gain in the tracking mode */
+#define PGT_PLF 3, 0 /* Phase loop, proportional gain in the tracking mode (default +8 added) */
+
+/* Loop 05 */
+#define IG_TLF 7, 4 /* Timing loop, integral gain */
+#define PG_TLF 3, 0 /* Timing loop, proportional gain (default +8 added) */
+
+/* NCO controls
+ * LOOP_OUT [1] Read PLF accumulator + PNCO, LOOP_OUT [0] Read PLF accumulator */
+/* Pnco01 */
+#define PNCO0 7, 0
+/* Pnco02 */
+#define PNCO1 7, 0
+/* Pnco03 */
+#define PNCO2 7, 0
+
+/* LOOP_OUT [1], Read TLF accumulator + TNCO, LOOP_OUT [0], Read TLF accumulator */
+/* Tnco01 */
+#define TNCO0 7, 0
+/* Tnco02 */
+#define TNCO1 7, 0
+/* Tnco03 */
+#define TNCO2 7, 0
+
+/* Monitor01 */
+#define A_SCL 3, 3
+#define TLOCK 1, 1 /* Timing loop lock (Symbol sync) [1] Timing loop has locked [0] Timing loop has not locked */
+#define PLOCK 0, 0 /* Phase loop lock (Carrier sync) [1] Phase loop has locked [0] Phase loop has not locked */
+
+/* Monitor02 */
+#define PRE_LEVEL 7, 0 /* PRE-AGC gain level */
+
+/* Monitor03 */
+#define POST_LEVEL 7, 0 /* POST-AGC gain level */
+
+/* Monitor04 */
+#define DC_I_LEVEL 7, 0 /* DC offset of I samples */
+
+/* Monitor05 */
+#define DC_Q_LEVEL 7, 0 /* DC offset of Q samples */
+
+/* Monitor06 */
+#define PLOCK_CNT 7, 0
+
+/* Monitor07 */
+#define TLOCK_CNT 7, 0
+
+/* Monitor12 */
+#define QPSK_OUT 6, 1 /* QPSK output monitoring */
+#define DC_FREEZE 0, 0 /* [1] Do not update DC_OFFSET */
+
+/* FEC Block */
+/* FEC01 */
+#define DERAND_BPAS 6, 6
+#define RS_BPAS 5, 5
+#define FEC_SRST_CNTL 4, 4
+#define FEC_SRESET 3, 3
+#define MPEG_CLK_INTL 2, 0
+ /* Tmp=(FMClk/FSR) x (1 / (2xCR)); FMClk: System Clock Frequency, FSR: Symbol Rate, CR: Code Rate
+ * 0: 1 < Tmp <= 2, 4: 13 < Tmp <= 17,
+ * 1: 2 < Tmp <= 5, 5: 17 < Tmp <= 25,
+ * 2: 5 < Tmp <= 9, 6: 25 < Tmp <= 33,
+ * 3: 9 < Tmp <= 13, 7: 33 < Tmp */
+
+/* Soft01 */
+#define ST_VAL_R12 2, 0
+#define STEP_R12 5, 3
+#define STEP_R23 5, 3
+#define STEP_R34 5, 3
+#define STEP_R56 5, 3
+#define STEP_R67 5, 3
+#define STEP_R78 5, 3
+/* Soft02 */
+#define ST_VAL_R23 7, 0
+/* Soft03 */
+#define ST_VAL_R34 7, 0
+/* Soft04 */
+#define ST_VAL_R56 7, 0
+/* Soft05 */
+#define ST_VAL_R67 7, 0
+/* Soft06 */
+#define ST_VAL_R78 7, 0
+
+/* Vit01 */
+#define RENORM_R12 7, 0
+/* Vit02 */
+#define RENORM_R23 7, 0
+/* Vit03 */
+#define RENORM_R34 7, 0
+/* Vit04 */
+#define RENORM_R56 7, 0
+/* Vit05 */
+#define RENORM_R67 7, 0
+/* Vit06 */
+#define RENORM_R78 7, 0
+/* Vit07 */
+#define RENORM_PRD 7, 0
+
+/* Vit08 */
+#define VIT_IN_SR78 7, 7
+#define VIT_IN_SR34 6, 6
+#define VIT_SR78 5, 5
+#define VIT_SR67 4, 4
+#define VIT_SR56 3, 3
+#define VIT_SR34 2, 2
+#define VIT_SR23 1, 1 /* .... */
+#define VIT_SR12 0, 0 /* Include CR 1/2 in search */
+
+/* Vit09 */
+#define PARM_FIX 4, 4 /* Parameter fix mode: [1] Known parameter [0] Unknown parameter */
+#define VIT_INV_SPECPARM_FIX 3, 3 /* Initial spectrum information */
+#define VIT_FR 2, 0 /* Start synchronization search at code rate as follows */
+ #define VIT_CR_12 0x00
+ #define VIT_CR_23 0x01
+ #define VIT_CR_34 0x02
+ #define VIT_CR_56 0x03
+ #define VIT_CR_67 0x04
+ #define VIT_CR_78 0x05
+
+/* Vit10 */
+#define INV_SPEC_STS 3, 3 /* Spectrum information monitoring [1] Inv spectrum [0] Not inv spectrum */
+#define VIT_CR 2, 0 /* Viterbi decoder current code rate [0] R=1/2 [1] R=2/3 [2] R=3/4 [3] R=5/6 [4] R=6/7 [5] R=7/8 */
+
+/* Vit11 */
+#define VIT_CER 7, 0
+
+/* Vit12 */
+#define RENORM_RAT 7, 0
+
+/* Sync01 */
+#define SYNC_MISS_TH 7, 4 /* Sync byte detector?s miss threshold */
+#define SYNC_HIT_TH 3, 0 /* Sync byte detector?s hit threshold This value should be greater than 2 */
+
+/* Sync02 */
+#define BYTE_SYNC 5, 5 /* [1] Acquire byte sync [0] Not acquire byte sync */
+#define SYNC_BYTE_STS 4, 2
+#define VIT_SRCH_STS 1, 1
+#define VIT_SYNC 0, 0 /* [1] Viterbi decoder is in sync [0] Viterbi decoder is out of sync */
+
+/* Rs01 */
+#define RS_ERR 3, 0
+#define PKT_ERR 4, 4
+
+/* Mpeg01 */
+#define ERR_POL 3, 3 /* Packet error polarity [1] Active low [0] Active high */
+#define SYNC_POL 2, 2 /* Sync polarity [1] Active low [0] Active high */
+#define VALID_POL 1, 1 /* Data valid polarity [1] Active low [0] Active high */
+#define CDCLK_POL 0, 0 /* CDCLK polarity [1] Falling edge event [0] Rising edge event */
+
+/* Mpeg02 */
+#define MPEG_OEN 6, 6
+#define DOUT_CONT 5, 5
+#define ERR_CONT 4, 4
+#define CLK_CONT 3, 3 /* Clock continuous mode [1] Continuous clock, [0] Clock is enable during payload data transfer */
+#define ENVELOPE 2, 2
+#define SER_PAR 1, 1 /* Serial / Parallel mode [1] Serial mode, [0] Parallel mode */
+#define DSS_SYNC 0, 0 /* DSS sync mode [1] Output sync, [0] No output sync */
+
+/* DiS01 */
+#define TONE_FREQ 7, 0 /* Tone frequency ratio ftone = fclk / (TONE_FREQ x 32) */
+
+/* DiS02 */
+#define RCV_EN 7, 7 /* DiSEqC receive enable mode [1] Receive enable [0] Receive disable */
+#define DIS_LENGTH 6, 4 /* Message length */
+#define DIS_RDY 3, 3 /* Data Transfer ready / finish [1] Ready [0] Finish */
+#define SWITCH_CON 2, 2 /* Satellite switch in tone burst mode [1] Satellite B [0] Satellite A */
+#define LNB_CON 1, 0 /* LNB control mode, [0] Continuous mode, [1] Tone burst mode, [2] DiSEqC mode, [3] Reserved */
+
+/* DiS03 */
+#define OLF_N 2, 2 /* [1] Disable [0] OLF (active low) */
+#define LNB_DN 1, 1 /* [1] LNB down [0] Disable (active high) */
+#define V18_13V 0, 0 /* 13V/18V select register (0=13V, 1=18V) */
+
+/* DiS04 .. DiS11*/
+#define LNB_MESGE0 7, 0
+#define LNB_MESGE1 7, 0
+#define LNB_MESGE2 7, 0
+#define LNB_MESGE3 7, 0
+#define LNB_MESGE4 7, 0
+#define LNB_MESGE5 7, 0
+#define LNB_MESGE6 7, 0
+#define LNB_MESGE7 7, 0
+
+/* Rf01 */
+#define SLAVE_ADDR 6, 0 /* RF tuner slave Address (SOC VERSION) */
+
+/* Err01 */
+#define ALARM_MODE 4, 4
+#define ERR_CNT_PRD 3, 2
+#define ERR_SRC 1, 0 /* Error monitoring source */
+ #define QPSK_BIT_ERRORS 0x0
+ #define VITERBI_BIT_ERRORS 0x1
+ #define VITERBI_BYTE_ERRORS 0x2
+ #define PACKET_ERRORS 0x3
+
+/* Err02 */
+#define ERR_CNT_L 7, 0 /* Error counter value register (LSB 8 bits) */
+
+/* Err03 */
+#define ERR_CNT_H 7, 0 /* Error counter value register (MSB 8 bits) */
+
+/* Err04 */
+#define PARITY_ERR 7, 0 /* Error flag for DiSEqC receive data */
+
+#endif
+
+#endif
diff --git a/linux/drivers/media/dvb/frontends/tda10048.c b/linux/drivers/media/dvb/frontends/tda10048.c
new file mode 100644
index 000000000..2b9b1d93c
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda10048.c
@@ -0,0 +1,710 @@
+/*
+ NXP TDA10048HN DVB OFDM demodulator driver
+
+ 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/kernel.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include "dvb_frontend.h"
+#include "tda10048.h"
+
+#define TDA10048_DEFAULT_FIRMWARE "dvb-fe-tda10048-1.0.fw"
+#define TDA10048_DEFAULT_FIRMWARE_SIZE 24878
+
+/* Register name definitions */
+#define TDA10048_IDENTITY 0x00
+#define TDA10048_VERSION 0x01
+#define TDA10048_DSP_CODE_CPT 0x0C
+#define TDA10048_DSP_CODE_IN 0x0E
+#define TDA10048_IN_CONF1 0x10
+#define TDA10048_IN_CONF2 0x11
+#define TDA10048_IN_CONF3 0x12
+#define TDA10048_OUT_CONF1 0x14
+#define TDA10048_OUT_CONF2 0x15
+#define TDA10048_OUT_CONF3 0x16
+#define TDA10048_AUTO 0x18
+#define TDA10048_SYNC_STATUS 0x1A
+#define TDA10048_CONF_C4_1 0x1E
+#define TDA10048_CONF_C4_2 0x1F
+#define TDA10048_CODE_IN_RAM 0x20
+#define TDA10048_CHANNEL_INFO_1_R 0x22
+#define TDA10048_CHANNEL_INFO_2_R 0x23
+#define TDA10048_CHANNEL_INFO1 0x24
+#define TDA10048_CHANNEL_INFO2 0x25
+#define TDA10048_TIME_ERROR_R 0x26
+#define TDA10048_TIME_ERROR 0x27
+#define TDA10048_FREQ_ERROR_LSB_R 0x28
+#define TDA10048_FREQ_ERROR_MSB_R 0x29
+#define TDA10048_FREQ_ERROR_LSB 0x2A
+#define TDA10048_FREQ_ERROR_MSB 0x2B
+#define TDA10048_IT_SEL 0x30
+#define TDA10048_IT_STAT 0x32
+#define TDA10048_DSP_AD_LSB 0x3C
+#define TDA10048_DSP_AD_MSB 0x3D
+#define TDA10048_DSP_REF_LSB 0x3E
+#define TDA10048_DSP_REF_MSB 0x3F
+#define TDA10048_CONF_TRISTATE1 0x44
+#define TDA10048_CONF_TRISTATE2 0x45
+#define TDA10048_CONF_POLARITY 0x46
+#define TDA10048_GPIO_SP_DS0 0x48
+#define TDA10048_GPIO_SP_DS1 0x49
+#define TDA10048_GPIO_SP_DS2 0x4A
+#define TDA10048_GPIO_SP_DS3 0x4B
+#define TDA10048_GPIO_OUT_SEL 0x4C
+#define TDA10048_GPIO_SELECT 0x4D
+#define TDA10048_IC_MODE 0x4E
+#define TDA10048_CONF_XO 0x50
+#define TDA10048_CONF_PLL1 0x51
+#define TDA10048_CONF_PLL2 0x52
+#define TDA10048_CONF_PLL3 0x53
+#define TDA10048_CONF_ADC 0x54
+#define TDA10048_CONF_ADC_2 0x55
+#define TDA10048_CONF_C1_1 0x60
+#define TDA10048_CONF_C1_3 0x62
+#define TDA10048_AGC_CONF 0x70
+#define TDA10048_AGC_THRESHOLD_LSB 0x72
+#define TDA10048_AGC_THRESHOLD_MSB 0x73
+#define TDA10048_AGC_RENORM 0x74
+#define TDA10048_AGC_GAINS 0x76
+#define TDA10048_AGC_TUN_MIN 0x78
+#define TDA10048_AGC_TUN_MAX 0x79
+#define TDA10048_AGC_IF_MIN 0x7A
+#define TDA10048_AGC_IF_MAX 0x7B
+#define TDA10048_AGC_TUN_LEVEL 0x7E
+#define TDA10048_AGC_IF_LEVEL 0x7F
+#define TDA10048_DIG_AGC_LEVEL 0x81
+#define TDA10048_FREQ_PHY2_LSB 0x86
+#define TDA10048_FREQ_PHY2_MSB 0x87
+#define TDA10048_TIME_INVWREF_LSB 0x88
+#define TDA10048_TIME_INVWREF_MSB 0x89
+#define TDA10048_TIME_WREF_LSB 0x8A
+#define TDA10048_TIME_WREF_MID1 0x8B
+#define TDA10048_TIME_WREF_MID2 0x8C
+#define TDA10048_TIME_WREF_MSB 0x8D
+#define TDA10048_NP_OUT 0xA2
+#define TDA10048_CELL_ID_LSB 0xA4
+#define TDA10048_CELL_ID_MSB 0xA5
+#define TDA10048_EXTTPS_ODD 0xAA
+#define TDA10048_EXTTPS_EVEN 0xAB
+#define TDA10048_TPS_LENGTH 0xAC
+#define TDA10048_FREE_REG_1 0xB2
+#define TDA10048_FREE_REG_2 0xB3
+#define TDA10048_CONF_C3_1 0xC0
+#define TDA10048_CYBER_CTRL 0xC2
+#define TDA10048_CBER_NMAX_LSB 0xC4
+#define TDA10048_CBER_NMAX_MSB 0xC5
+#define TDA10048_CBER_LSB 0xC6
+#define TDA10048_CBER_MSB 0xC7
+#define TDA10048_VBER_LSB 0xC8
+#define TDA10048_VBER_MID 0xC9
+#define TDA10048_VBER_MSB 0xCA
+#define TDA10048_CYBER_LUT 0xCC
+#define TDA10048_UNCOR_CTRL 0xCD
+#define TDA10048_UNCOR_CPT_LSB 0xCE
+#define TDA10048_UNCOR_CPT_MSB 0xCF
+#define TDA10048_SOFT_IT_C3 0xD6
+#define TDA10048_CONF_TS2 0xE0
+#define TDA10048_CONF_TS1 0xE1
+
+static unsigned int debug;
+
+#define dprintk(level, fmt, arg...)\
+ do { if (debug >= level)\
+ printk(KERN_DEBUG "tda10048: " fmt, ## arg);\
+ } while (0)
+
+struct tda10048_state {
+
+ struct i2c_adapter *i2c;
+
+ /* configuration settings */
+ const struct tda10048_config *config;
+ struct dvb_frontend frontend;
+
+ int fwloaded;
+};
+
+static struct init_tab {
+ u8 reg;
+ u16 data;
+} init_tab[] = {
+ { TDA10048_CONF_PLL1, 0x08 },
+ { TDA10048_CONF_ADC_2, 0x00 },
+ { TDA10048_CONF_C4_1, 0x00 },
+ { TDA10048_CONF_PLL1, 0x0f },
+ { TDA10048_CONF_PLL2, 0x0a },
+ { TDA10048_CONF_PLL3, 0x43 },
+ { TDA10048_FREQ_PHY2_LSB, 0x02 },
+ { TDA10048_FREQ_PHY2_MSB, 0x0a },
+ { TDA10048_TIME_WREF_LSB, 0xbd },
+ { TDA10048_TIME_WREF_MID1, 0xe4 },
+ { TDA10048_TIME_WREF_MID2, 0xa8 },
+ { TDA10048_TIME_WREF_MSB, 0x02 },
+ { TDA10048_TIME_INVWREF_LSB, 0x04 },
+ { TDA10048_TIME_INVWREF_MSB, 0x06 },
+ { TDA10048_CONF_C4_1, 0x00 },
+ { TDA10048_CONF_C1_1, 0xa8 },
+ { TDA10048_AGC_CONF, 0x16 },
+ { TDA10048_CONF_C1_3, 0x0b },
+ { TDA10048_AGC_TUN_MIN, 0x00 },
+ { TDA10048_AGC_TUN_MAX, 0xff },
+ { TDA10048_AGC_IF_MIN, 0x00 },
+ { TDA10048_AGC_IF_MAX, 0xff },
+ { TDA10048_AGC_THRESHOLD_MSB, 0x00 },
+ { TDA10048_AGC_THRESHOLD_LSB, 0x70 },
+ { TDA10048_CYBER_CTRL, 0x38 },
+ { TDA10048_AGC_GAINS, 0x12 },
+ { TDA10048_CONF_XO, 0x00 },
+ { TDA10048_CONF_TS1, 0x07 },
+ { TDA10048_IC_MODE, 0x00 },
+ { TDA10048_CONF_TS2, 0xc0 },
+ { TDA10048_CONF_TRISTATE1, 0x21 },
+ { TDA10048_CONF_TRISTATE2, 0x00 },
+ { TDA10048_CONF_POLARITY, 0x00 },
+ { TDA10048_CONF_C4_2, 0x04 },
+ { TDA10048_CONF_ADC, 0x60 },
+ { TDA10048_CONF_ADC_2, 0x10 },
+ { TDA10048_CONF_ADC, 0x60 },
+ { TDA10048_CONF_ADC_2, 0x00 },
+ { TDA10048_CONF_C1_1, 0xa8 },
+ { TDA10048_UNCOR_CTRL, 0x00 },
+ { TDA10048_CONF_C4_2, 0x04 },
+};
+
+static int tda10048_writereg(struct tda10048_state *state, u8 reg, u8 data)
+{
+ int ret;
+ u8 buf [] = { reg, data };
+ struct i2c_msg msg = {
+ .addr = state->config->demod_address,
+ .flags = 0, .buf = buf, .len = 2 };
+
+ dprintk(2, "%s(reg = 0x%02x, data = 0x%02x)\n", __func__, reg, data);
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+
+ if (ret != 1)
+ printk("%s: writereg error (ret == %i)\n", __func__, ret);
+
+ return (ret != 1) ? -1 : 0;
+}
+
+static u8 tda10048_readreg(struct tda10048_state *state, u8 reg)
+{
+ int ret;
+ u8 b0 [] = { reg };
+ u8 b1 [] = { 0 };
+ struct i2c_msg msg [] = {
+ { .addr = state->config->demod_address,
+ .flags = 0, .buf = b0, .len = 1 },
+ { .addr = state->config->demod_address,
+ .flags = I2C_M_RD, .buf = b1, .len = 1 } };
+
+ dprintk(2, "%s(reg = 0x%02x)\n", __func__, reg);
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+
+ if (ret != 2)
+ printk(KERN_ERR "%s: readreg error (ret == %i)\n",
+ __func__, ret);
+
+ return b1[0];
+}
+
+static int tda10048_writeregbulk(struct tda10048_state *state, u8 reg,
+ u8 *data, u16 len)
+{
+ int ret = -EREMOTEIO;
+ struct i2c_msg msg;
+ u8 *buf;
+
+ dprintk(2, "%s(%d, ?, len = %d)\n", __func__, reg, len);
+
+ buf = kmalloc(len + 1, GFP_KERNEL);
+ if (buf == NULL) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ *buf = reg;
+ memcpy(buf + 1, data, len);
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.buf = buf;
+ msg.len = len + 1;
+
+ dprintk(2, "%s(): write len = %d\n",
+ __func__, msg.len);
+
+ ret = i2c_transfer(state->i2c, &msg, 1);
+ if (ret != 1) {
+ printk(KERN_ERR "%s(): writereg error err %i\n",
+ __func__, ret);
+ ret = -EREMOTEIO;
+ }
+
+error:
+ kfree(buf);
+
+ return ret;
+}
+
+static int tda10048_firmware_upload(struct dvb_frontend *fe)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+ const struct firmware *fw;
+ int ret;
+ int pos = 0;
+ int cnt;
+ u8 wlen = state->config->fwbulkwritelen;
+
+ if ((wlen != TDA10048_BULKWRITE_200) && (wlen != TDA10048_BULKWRITE_50))
+ wlen = TDA10048_BULKWRITE_200;
+
+ /* request the firmware, this will block and timeout */
+ printk(KERN_INFO "%s: waiting for firmware upload (%s)...\n",
+ __func__,
+ TDA10048_DEFAULT_FIRMWARE);
+
+ ret = request_firmware(&fw, TDA10048_DEFAULT_FIRMWARE,
+ &state->i2c->dev);
+ if (ret) {
+ printk(KERN_ERR "%s: Upload failed. (file not found?)\n",
+ __func__);
+ return -EIO;
+ } else {
+ printk(KERN_INFO "%s: firmware read %Zu bytes.\n",
+ __func__,
+ fw->size);
+ ret = 0;
+ }
+
+ if (fw->size != TDA10048_DEFAULT_FIRMWARE_SIZE) {
+ printk(KERN_ERR "%s: firmware incorrect size\n", __func__);
+ return -EIO;
+ } else {
+ printk(KERN_INFO "%s: firmware uploading\n", __func__);
+
+ /* Soft reset */
+ tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
+ tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
+ & 0xfe);
+ tda10048_writereg(state, TDA10048_CONF_TRISTATE1,
+ tda10048_readreg(state, TDA10048_CONF_TRISTATE1)
+ | 0x01);
+
+ /* Put the demod into host download mode */
+ tda10048_writereg(state, TDA10048_CONF_C4_1,
+ tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xf9);
+
+ /* Boot the DSP */
+ tda10048_writereg(state, TDA10048_CONF_C4_1,
+ tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x08);
+
+ /* Prepare for download */
+ tda10048_writereg(state, TDA10048_DSP_CODE_CPT, 0);
+
+ /* Download the firmware payload */
+ while (pos < fw->size) {
+
+ if ((fw->size - pos) > wlen)
+ cnt = wlen;
+ else
+ cnt = fw->size - pos;
+
+ tda10048_writeregbulk(state, TDA10048_DSP_CODE_IN,
+ &fw->data[pos], cnt);
+
+ pos += cnt;
+ }
+
+ ret = -EIO;
+ /* Wait up to 250ms for the DSP to boot */
+ for (cnt = 0; cnt < 250 ; cnt += 10) {
+
+ msleep(10);
+
+ if (tda10048_readreg(state, TDA10048_SYNC_STATUS)
+ & 0x40) {
+ ret = 0;
+ break;
+ }
+ }
+ }
+
+ release_firmware(fw);
+
+ if (ret == 0) {
+ printk(KERN_INFO "%s: firmware uploaded\n", __func__);
+ state->fwloaded = 1;
+ } else
+ printk(KERN_ERR "%s: firmware upload failed\n", __func__);
+
+ return ret;
+}
+
+static int tda10048_set_inversion(struct dvb_frontend *fe, int inversion)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+
+ dprintk(1, "%s(%d)\n", __func__, inversion);
+
+ if (inversion == TDA10048_INVERSION_ON)
+ tda10048_writereg(state, TDA10048_CONF_C1_1,
+ tda10048_readreg(state, TDA10048_CONF_C1_1) | 0x20);
+ else
+ tda10048_writereg(state, TDA10048_CONF_C1_1,
+ tda10048_readreg(state, TDA10048_CONF_C1_1) & 0xdf);
+
+ return 0;
+}
+
+/* Retrieve the demod settings */
+static int tda10048_get_tps(struct tda10048_state *state,
+ struct dvb_ofdm_parameters *p)
+{
+ u8 val;
+
+ /* Make sure the TPS regs are valid */
+ if (!(tda10048_readreg(state, TDA10048_AUTO) & 0x01))
+ return -EAGAIN;
+
+ val = tda10048_readreg(state, TDA10048_OUT_CONF2);
+ switch ((val & 0x60) >> 5) {
+ case 0: p->constellation = QPSK; break;
+ case 1: p->constellation = QAM_16; break;
+ case 2: p->constellation = QAM_64; break;
+ }
+ switch ((val & 0x18) >> 3) {
+ case 0: p->hierarchy_information = HIERARCHY_NONE; break;
+ case 1: p->hierarchy_information = HIERARCHY_1; break;
+ case 2: p->hierarchy_information = HIERARCHY_2; break;
+ case 3: p->hierarchy_information = HIERARCHY_4; break;
+ }
+ switch (val & 0x07) {
+ case 0: p->code_rate_HP = FEC_1_2; break;
+ case 1: p->code_rate_HP = FEC_2_3; break;
+ case 2: p->code_rate_HP = FEC_3_4; break;
+ case 3: p->code_rate_HP = FEC_5_6; break;
+ case 4: p->code_rate_HP = FEC_7_8; break;
+ }
+
+ val = tda10048_readreg(state, TDA10048_OUT_CONF3);
+ switch (val & 0x07) {
+ case 0: p->code_rate_LP = FEC_1_2; break;
+ case 1: p->code_rate_LP = FEC_2_3; break;
+ case 2: p->code_rate_LP = FEC_3_4; break;
+ case 3: p->code_rate_LP = FEC_5_6; break;
+ case 4: p->code_rate_LP = FEC_7_8; break;
+ }
+
+ val = tda10048_readreg(state, TDA10048_OUT_CONF1);
+ switch ((val & 0x0c) >> 2) {
+ case 0: p->guard_interval = GUARD_INTERVAL_1_32; break;
+ case 1: p->guard_interval = GUARD_INTERVAL_1_16; break;
+ case 2: p->guard_interval = GUARD_INTERVAL_1_8; break;
+ case 3: p->guard_interval = GUARD_INTERVAL_1_4; break;
+ }
+ switch (val & 0x02) {
+ case 0: p->transmission_mode = TRANSMISSION_MODE_2K; break;
+ case 1: p->transmission_mode = TRANSMISSION_MODE_8K; break;
+ }
+
+ return 0;
+}
+
+static int tda10048_i2c_gate_ctrl(struct dvb_frontend *fe, int enable)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+ dprintk(1, "%s(%d)\n", __func__, enable);
+
+ if (enable)
+ return tda10048_writereg(state, TDA10048_CONF_C4_1,
+ tda10048_readreg(state, TDA10048_CONF_C4_1) | 0x02);
+ else
+ return tda10048_writereg(state, TDA10048_CONF_C4_1,
+ tda10048_readreg(state, TDA10048_CONF_C4_1) & 0xfd);
+}
+
+static int tda10048_output_mode(struct dvb_frontend *fe, int serial)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+ dprintk(1, "%s(%d)\n", __func__, serial);
+
+ /* Ensure pins are out of tri-state */
+ tda10048_writereg(state, TDA10048_CONF_TRISTATE1, 0x21);
+ tda10048_writereg(state, TDA10048_CONF_TRISTATE2, 0x00);
+
+ if (serial) {
+ tda10048_writereg(state, TDA10048_IC_MODE, 0x80 | 0x20);
+ tda10048_writereg(state, TDA10048_CONF_TS2, 0xc0);
+ } else {
+ tda10048_writereg(state, TDA10048_IC_MODE, 0x00);
+ tda10048_writereg(state, TDA10048_CONF_TS2, 0x01);
+ }
+
+ return 0;
+}
+
+/* Talk to the demod, set the FEC, GUARD, QAM settings etc */
+/* TODO: Support manual tuning with specific params */
+static int tda10048_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+
+ dprintk(1, "%s(frequency=%d)\n", __func__, p->frequency);
+
+ if (fe->ops.tuner_ops.set_params) {
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 1);
+
+ fe->ops.tuner_ops.set_params(fe, p);
+
+ if (fe->ops.i2c_gate_ctrl)
+ fe->ops.i2c_gate_ctrl(fe, 0);
+ }
+
+ /* Enable demod TPS auto detection and begin acquisition */
+ tda10048_writereg(state, TDA10048_AUTO, 0x57);
+
+ return 0;
+}
+
+/* Establish sane defaults and load firmware. */
+static int tda10048_init(struct dvb_frontend *fe)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+ int ret = 0, i;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* Apply register defaults */
+ for (i = 0; i < ARRAY_SIZE(init_tab); i++)
+ tda10048_writereg(state, init_tab[i].reg, init_tab[i].data);
+
+ if (state->fwloaded == 0)
+ ret = tda10048_firmware_upload(fe);
+
+ /* Set either serial or parallel */
+ tda10048_output_mode(fe, state->config->output_mode);
+
+ /* set inversion */
+ tda10048_set_inversion(fe, state->config->inversion);
+
+ /* Ensure we leave the gate closed */
+ tda10048_i2c_gate_ctrl(fe, 0);
+
+ return ret;
+}
+
+static int tda10048_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+ u8 reg;
+
+ *status = 0;
+
+ reg = tda10048_readreg(state, TDA10048_SYNC_STATUS);
+
+ dprintk(1, "%s() status =0x%02x\n", __func__, reg);
+
+ if (reg & 0x02)
+ *status |= FE_HAS_CARRIER;
+
+ if (reg & 0x04)
+ *status |= FE_HAS_SIGNAL;
+
+ if (reg & 0x08) {
+ *status |= FE_HAS_LOCK;
+ *status |= FE_HAS_VITERBI;
+ *status |= FE_HAS_SYNC;
+ }
+
+ return 0;
+}
+
+static int tda10048_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* TODO: A reset may be required here */
+ *ber = tda10048_readreg(state, TDA10048_CBER_MSB) << 8 |
+ tda10048_readreg(state, TDA10048_CBER_LSB);
+
+ return 0;
+}
+
+static int tda10048_read_signal_strength(struct dvb_frontend *fe,
+ u16 *signal_strength)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+ u16 v;
+
+ dprintk(1, "%s()\n", __func__);
+
+ v = tda10048_readreg(state, TDA10048_NP_OUT);
+ if (v == 0)
+ *signal_strength = 100;
+ else {
+ /* TODO: Apply .db math for correct values */
+ *signal_strength = v;
+ }
+
+ return 0;
+}
+
+static int tda10048_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* TODO: This result should be the same as signal strength */
+ *snr = tda10048_readreg(state, TDA10048_NP_OUT);
+
+ return 0;
+}
+
+static int tda10048_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+
+ dprintk(1, "%s()\n", __func__);
+#if 0
+ /* Reset and begin counting */
+ tda10048_writereg(state, TDA10048_UNCOR_CTRL, 0x01);
+ msleep(10);
+#endif
+
+ *ucblocks = tda10048_readreg(state, TDA10048_UNCOR_CPT_MSB) << 8 |
+ tda10048_readreg(state, TDA10048_UNCOR_CPT_LSB);
+
+ return 0;
+}
+
+static int tda10048_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+
+ dprintk(1, "%s()\n", __func__);
+
+ p->inversion = tda10048_readreg(state, TDA10048_CONF_C1_1)
+ & 0x20 ? INVERSION_ON : INVERSION_OFF;
+
+ return tda10048_get_tps(state, &p->u.ofdm);
+}
+
+static int tda10048_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *tune)
+{
+ tune->min_delay_ms = 1000;
+ return 0;
+}
+
+static void tda10048_release(struct dvb_frontend *fe)
+{
+ struct tda10048_state *state = fe->demodulator_priv;
+ dprintk(1, "%s()\n", __func__);
+ kfree(state);
+}
+
+static struct dvb_frontend_ops tda10048_ops;
+
+struct dvb_frontend *tda10048_attach(const struct tda10048_config *config,
+ struct i2c_adapter *i2c)
+{
+ struct tda10048_state *state = NULL;
+
+ dprintk(1, "%s()\n", __func__);
+
+ /* allocate memory for the internal state */
+ state = kmalloc(sizeof(struct tda10048_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->config = config;
+ state->i2c = i2c;
+ state->fwloaded = 0;
+
+ /* check if the demod is present */
+ if (tda10048_readreg(state, TDA10048_IDENTITY) != 0x048)
+ goto error;
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &tda10048_ops,
+ sizeof(struct dvb_frontend_ops));
+ state->frontend.demodulator_priv = state;
+
+ /* Leave the gate closed */
+ tda10048_i2c_gate_ctrl(&state->frontend, 0);
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+EXPORT_SYMBOL(tda10048_attach);
+
+static struct dvb_frontend_ops tda10048_ops = {
+
+ .info = {
+ .name = "NXP TDA10048HN DVB-T",
+ .type = FE_OFDM,
+ .frequency_min = 177000000,
+ .frequency_max = 858000000,
+ .frequency_stepsize = 166666,
+ .caps = FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_5_6 | FE_CAN_FEC_7_8 | FE_CAN_FEC_AUTO |
+ FE_CAN_QPSK | FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_HIERARCHY_AUTO | FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO | FE_CAN_RECOVER
+ },
+
+ .release = tda10048_release,
+ .init = tda10048_init,
+ .i2c_gate_ctrl = tda10048_i2c_gate_ctrl,
+ .set_frontend = tda10048_set_frontend,
+ .get_frontend = tda10048_get_frontend,
+ .get_tune_settings = tda10048_get_tune_settings,
+ .read_status = tda10048_read_status,
+ .read_ber = tda10048_read_ber,
+ .read_signal_strength = tda10048_read_signal_strength,
+ .read_snr = tda10048_read_snr,
+ .read_ucblocks = tda10048_read_ucblocks,
+};
+
+module_param(debug, int, 0644);
+MODULE_PARM_DESC(debug, "Enable verbose debug messages");
+
+MODULE_DESCRIPTION("NXP TDA10048HN DVB-T Demodulator driver");
+MODULE_AUTHOR("Steven Toth");
+MODULE_LICENSE("GPL");
+
diff --git a/linux/drivers/media/dvb/frontends/tda10048.h b/linux/drivers/media/dvb/frontends/tda10048.h
new file mode 100644
index 000000000..2b5c78e62
--- /dev/null
+++ b/linux/drivers/media/dvb/frontends/tda10048.h
@@ -0,0 +1,63 @@
+/*
+ NXP TDA10048HN DVB OFDM demodulator driver
+
+ 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.
+
+*/
+
+#ifndef TDA10048_H
+#define TDA10048_H
+
+#include <linux/dvb/frontend.h>
+#include <linux/firmware.h>
+
+struct tda10048_config {
+
+ /* the demodulator's i2c address */
+ u8 demod_address;
+
+ /* serial/parallel output */
+#define TDA10048_PARALLEL_OUTPUT 0
+#define TDA10048_SERIAL_OUTPUT 1
+ u8 output_mode;
+
+#define TDA10048_BULKWRITE_200 200
+#define TDA10048_BULKWRITE_50 50
+ u8 fwbulkwritelen;
+
+ /* Spectral Inversion */
+#define TDA10048_INVERSION_OFF 0
+#define TDA10048_INVERSION_ON 1
+ u8 inversion;
+};
+
+#if defined(CONFIG_DVB_TDA10048) || \
+ (defined(CONFIG_DVB_TDA10048_MODULE) && defined(MODULE))
+extern struct dvb_frontend *tda10048_attach(
+ const struct tda10048_config *config,
+ struct i2c_adapter *i2c);
+#else
+static inline struct dvb_frontend *tda10048_attach(
+ const struct tda10048_config *config,
+ struct i2c_adapter *i2c)
+{
+ printk(KERN_WARNING "%s: driver disabled by Kconfig\n", __func__);
+ return NULL;
+}
+#endif /* CONFIG_DVB_TDA10048 */
+
+#endif /* TDA10048_H */
diff --git a/linux/drivers/media/dvb/ttpci/budget.c b/linux/drivers/media/dvb/ttpci/budget.c
index 108788bf0..7adfe17b0 100644
--- a/linux/drivers/media/dvb/ttpci/budget.c
+++ b/linux/drivers/media/dvb/ttpci/budget.c
@@ -358,6 +358,7 @@ static int s5h1420_tuner_set_params(struct dvb_frontend* fe, struct dvb_frontend
static struct s5h1420_config s5h1420_config = {
.demod_address = 0x53,
.invert = 1,
+ .cdclk_polarity = 1,
};
static struct tda10086_config tda10086_config = {
diff --git a/linux/drivers/media/radio/radio-si470x.c b/linux/drivers/media/radio/radio-si470x.c
index 83333734e..9f4207edc 100644
--- a/linux/drivers/media/radio/radio-si470x.c
+++ b/linux/drivers/media/radio/radio-si470x.c
@@ -532,8 +532,7 @@ static int si470x_get_register(struct si470x_device *radio, int regnr)
retval = si470x_get_report(radio, (void *) &buf, sizeof(buf));
if (retval >= 0)
- radio->registers[regnr] = be16_to_cpu(get_unaligned(
- (unsigned short *) &buf[1]));
+ radio->registers[regnr] = get_unaligned_be16(&buf[1]);
return (retval < 0) ? -EINVAL : 0;
}
@@ -548,8 +547,7 @@ static int si470x_set_register(struct si470x_device *radio, int regnr)
int retval;
buf[0] = REGISTER_REPORT(regnr);
- put_unaligned(cpu_to_be16(radio->registers[regnr]),
- (unsigned short *) &buf[1]);
+ put_unaligned_be16(radio->registers[regnr], &buf[1]);
retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
@@ -572,9 +570,8 @@ static int si470x_get_all_registers(struct si470x_device *radio)
if (retval >= 0)
for (regnr = 0; regnr < RADIO_REGISTER_NUM; regnr++)
- radio->registers[regnr] = be16_to_cpu(get_unaligned(
- (unsigned short *)
- &buf[regnr * RADIO_REGISTER_SIZE + 1]));
+ radio->registers[regnr] = get_unaligned_be16(
+ &buf[regnr * RADIO_REGISTER_SIZE + 1]);
return (retval < 0) ? -EINVAL : 0;
}
@@ -605,8 +602,7 @@ static int si470x_get_rds_registers(struct si470x_device *radio)
if (retval >= 0)
for (regnr = 0; regnr < RDS_REGISTER_NUM; regnr++)
radio->registers[STATUSRSSI + regnr] =
- be16_to_cpu(get_unaligned((unsigned short *)
- &buf[regnr * RADIO_REGISTER_SIZE + 1]));
+ get_unaligned_be16(&buf[regnr * RADIO_REGISTER_SIZE + 1]);
return (retval < 0) ? -EINVAL : 0;
}
@@ -854,7 +850,7 @@ static void si470x_rds(struct si470x_device *radio)
};
/* Fill the V4L2 RDS buffer */
- put_unaligned(cpu_to_le16(rds), (unsigned short *) &tmpbuf);
+ put_unaligned_le16(rds, &tmpbuf);
tmpbuf[2] = blocknum; /* offset name */
tmpbuf[2] |= blocknum << 3; /* received offset */
if (bler > max_rds_errors)
diff --git a/linux/drivers/media/radio/radio-typhoon.c b/linux/drivers/media/radio/radio-typhoon.c
index 22c999461..5db38526e 100644
--- a/linux/drivers/media/radio/radio-typhoon.c
+++ b/linux/drivers/media/radio/radio-typhoon.c
@@ -35,6 +35,7 @@
#include <linux/init.h> /* Initdata */
#include <linux/ioport.h> /* request_region */
#include <linux/proc_fs.h> /* radio card status report */
+#include <linux/seq_file.h>
#include <asm/io.h> /* outb, outb_p */
#include <asm/uaccess.h> /* copy to/from user */
#include "compat.h"
@@ -98,9 +99,6 @@ static int typhoon_setfreq(struct typhoon_device *dev, unsigned long frequency);
static void typhoon_mute(struct typhoon_device *dev);
static void typhoon_unmute(struct typhoon_device *dev);
static int typhoon_setvol(struct typhoon_device *dev, int vol);
-#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
-static int typhoon_get_info(char *buf, char **start, off_t offset, int len);
-#endif
static void typhoon_setvol_generic(struct typhoon_device *dev, int vol)
{
@@ -373,30 +371,39 @@ static struct video_device typhoon_radio =
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
-static int typhoon_get_info(char *buf, char **start, off_t offset, int len)
+static int typhoon_proc_show(struct seq_file *m, void *v)
{
- char *out = buf;
-
#ifdef MODULE
#define MODULEPROCSTRING "Driver loaded as a module"
#else
#define MODULEPROCSTRING "Driver compiled into kernel"
#endif
- /* output must be kept under PAGE_SIZE */
- out += sprintf(out, BANNER);
- out += sprintf(out, "Load type: " MODULEPROCSTRING "\n\n");
- out += sprintf(out, "frequency = %lu kHz\n",
+ seq_puts(m, BANNER);
+ seq_puts(m, "Load type: " MODULEPROCSTRING "\n\n");
+ seq_printf(m, "frequency = %lu kHz\n",
typhoon_unit.curfreq >> 4);
- out += sprintf(out, "volume = %d\n", typhoon_unit.curvol);
- out += sprintf(out, "mute = %s\n", typhoon_unit.muted ?
+ seq_printf(m, "volume = %d\n", typhoon_unit.curvol);
+ seq_printf(m, "mute = %s\n", typhoon_unit.muted ?
"on" : "off");
- out += sprintf(out, "iobase = 0x%x\n", typhoon_unit.iobase);
- out += sprintf(out, "mute frequency = %lu kHz\n",
+ seq_printf(m, "iobase = 0x%x\n", typhoon_unit.iobase);
+ seq_printf(m, "mute frequency = %lu kHz\n",
typhoon_unit.mutefreq >> 4);
- return out - buf;
+ return 0;
}
+static int typhoon_proc_open(struct inode *inode, struct file *file)
+{
+ return single_open(file, typhoon_proc_show, NULL);
+}
+
+static const struct file_operations typhoon_proc_fops = {
+ .owner = THIS_MODULE,
+ .open = typhoon_proc_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
#endif /* CONFIG_RADIO_TYPHOON_PROC_FS */
MODULE_AUTHOR("Dr. Henrik Seidel");
@@ -457,8 +464,7 @@ static int __init typhoon_init(void)
typhoon_mute(&typhoon_unit);
#ifdef CONFIG_RADIO_TYPHOON_PROC_FS
- if (!create_proc_info_entry("driver/radio-typhoon", 0, NULL,
- typhoon_get_info))
+ if (!proc_create("driver/radio-typhoon", 0, NULL, &typhoon_proc_fops))
printk(KERN_ERR "radio-typhoon: registering /proc/driver/radio-typhoon failed\n");
#endif
diff --git a/linux/drivers/media/video/Kconfig b/linux/drivers/media/video/Kconfig
index 54b9f84e9..fe9a4cc14 100644
--- a/linux/drivers/media/video/Kconfig
+++ b/linux/drivers/media/video/Kconfig
@@ -698,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
diff --git a/linux/drivers/media/video/Makefile b/linux/drivers/media/video/Makefile
index caf9085c2..f190c0702 100644
--- a/linux/drivers/media/video/Makefile
+++ b/linux/drivers/media/video/Makefile
@@ -144,5 +144,7 @@ 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/linux/drivers/media/video/adv7170.c b/linux/drivers/media/video/adv7170.c
index 0d15ce53d..54ef7aa63 100644
--- a/linux/drivers/media/video/adv7170.c
+++ b/linux/drivers/media/video/adv7170.c
@@ -409,7 +409,7 @@ adv7170_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/adv7175.c b/linux/drivers/media/video/adv7175.c
index 86345ba5c..b8618c021 100644
--- a/linux/drivers/media/video/adv7175.c
+++ b/linux/drivers/media/video/adv7175.c
@@ -427,7 +427,7 @@ adv7175_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/au0828/Kconfig b/linux/drivers/media/video/au0828/Kconfig
new file mode 100644
index 000000000..f04c80bc8
--- /dev/null
+++ b/linux/drivers/media/video/au0828/Kconfig
@@ -0,0 +1,13 @@
+
+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/linux/drivers/media/video/au0828/Makefile b/linux/drivers/media/video/au0828/Makefile
new file mode 100644
index 000000000..9f4f572c8
--- /dev/null
+++ b/linux/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/linux/drivers/media/video/au0828/au0828-cards.c b/linux/drivers/media/video/au0828/au0828-cards.c
new file mode 100644
index 000000000..8ca91f814
--- /dev/null
+++ b/linux/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/linux/drivers/media/video/au0828/au0828-cards.h b/linux/drivers/media/video/au0828/au0828-cards.h
new file mode 100644
index 000000000..118629771
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-cards.h
@@ -0,0 +1,26 @@
+/*
+ * 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/linux/drivers/media/video/au0828/au0828-core.c b/linux/drivers/media/video/au0828/au0828-core.c
new file mode 100644
index 000000000..b3a4346b1
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-core.c
@@ -0,0 +1,277 @@
+/*
+ * 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 "compat.h"
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+#include <linux/mutex.h>
+#endif
+
+#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,
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
+ .owner = THIS_MODULE,
+#endif
+};
+
+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/linux/drivers/media/video/au0828/au0828-dvb.c b/linux/drivers/media/video/au0828/au0828-dvb.c
new file mode 100644
index 000000000..f911bbac6
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-dvb.c
@@ -0,0 +1,402 @@
+/*
+ * 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 "compat.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
+};
+
+/*-------------------------------------------------------------------*/
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void urb_completion(struct urb *purb, struct pt_regs *regs)
+#else
+static void urb_completion(struct urb *purb)
+#endif
+{
+ 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;
+ }
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+#else
+ dvb->adapter->priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(dvb->adapter, dvb->frontend);
+#endif
+ 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;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+#else
+ result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
+#endif
+ 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 */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#else
+ dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#endif
+ 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);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_unregister_adapter(&dvb->adapter);
+#else
+ dvb_unregister_adapter(dvb->adapter);
+#endif
+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);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_unregister_adapter(&dvb->adapter);
+#else
+ dvb_unregister_adapter(dvb->adapter);
+#endif
+}
+
+/* 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/linux/drivers/media/video/au0828/au0828-i2c.c b/linux/drivers/media/video/au0828/au0828-i2c.c
new file mode 100644
index 000000000..08d2a6080
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828-i2c.c
@@ -0,0 +1,388 @@
+/*
+ * 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 "compat.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,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 0)
+ .owner = THIS_MODULE,
+#endif
+ .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/linux/drivers/media/video/au0828/au0828-reg.h b/linux/drivers/media/video/au0828/au0828-reg.h
new file mode 100644
index 000000000..398275508
--- /dev/null
+++ b/linux/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/linux/drivers/media/video/au0828/au0828.h b/linux/drivers/media/video/au0828/au0828.h
new file mode 100644
index 000000000..4b0ad1b3e
--- /dev/null
+++ b/linux/drivers/media/video/au0828/au0828.h
@@ -0,0 +1,137 @@
+/*
+ * 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 {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex lock;
+#else
+ struct semaphore lock;
+#endif
+ 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 {
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex mutex;
+#else
+ struct semaphore mutex;
+#endif
+ 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/linux/drivers/media/video/bt819.c b/linux/drivers/media/video/bt819.c
index 9264e2cff..402bccaf7 100644
--- a/linux/drivers/media/video/bt819.c
+++ b/linux/drivers/media/video/bt819.c
@@ -525,7 +525,7 @@ bt819_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/bt856.c b/linux/drivers/media/video/bt856.c
index 7abfad9a4..50ca987ad 100644
--- a/linux/drivers/media/video/bt856.c
+++ b/linux/drivers/media/video/bt856.c
@@ -312,7 +312,7 @@ bt856_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/bt8xx/bttv-driver.c b/linux/drivers/media/video/bt8xx/bttv-driver.c
index c1173a94a..303422115 100644
--- a/linux/drivers/media/video/bt8xx/bttv-driver.c
+++ b/linux/drivers/media/video/bt8xx/bttv-driver.c
@@ -3506,6 +3506,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);
diff --git a/linux/drivers/media/video/c-qcam.c b/linux/drivers/media/video/c-qcam.c
index 479ef617b..a5f5b8a4a 100644
--- a/linux/drivers/media/video/c-qcam.c
+++ b/linux/drivers/media/video/c-qcam.c
@@ -39,6 +39,7 @@
#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
#include <linux/mutex.h>
#endif
+#include <linux/jiffies.h>
#include <asm/uaccess.h>
@@ -102,7 +103,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;
@@ -127,7 +129,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;
diff --git a/linux/drivers/media/video/cx23885/Kconfig b/linux/drivers/media/video/cx23885/Kconfig
index 1fd326fe4..ca5fbce3a 100644
--- a/linux/drivers/media/video/cx23885/Kconfig
+++ b/linux/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/linux/drivers/media/video/cx23885/cx23885-cards.c b/linux/drivers/media/video/cx23885/cx23885-cards.c
index 6f04004b7..0c25b7dd1 100644
--- a/linux/drivers/media/video/cx23885/cx23885-cards.c
+++ b/linux/drivers/media/video/cx23885/cx23885-cards.c
@@ -131,6 +131,14 @@ 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,
+ },
};
const unsigned int cx23885_bcount = ARRAY_SIZE(cx23885_boards);
@@ -182,6 +190,14 @@ 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,
},
};
const unsigned int cx23885_idcount = ARRAY_SIZE(cx23885_subids);
@@ -236,6 +252,9 @@ 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 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);
@@ -315,6 +334,38 @@ 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;
}
}
@@ -325,6 +376,7 @@ 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:
/* FIXME: Implement me */
break;
}
@@ -354,6 +406,8 @@ void cx23885_card_setup(struct cx23885_dev *dev)
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;
@@ -370,12 +424,24 @@ void cx23885_card_setup(struct cx23885_dev *dev)
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:
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/linux/drivers/media/video/cx23885/cx23885-core.c b/linux/drivers/media/video/cx23885/cx23885-core.c
index 309c17586..968b31716 100644
--- a/linux/drivers/media/video/cx23885/cx23885-core.c
+++ b/linux/drivers/media/video/cx23885/cx23885-core.c
@@ -745,8 +745,8 @@ 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) {
diff --git a/linux/drivers/media/video/cx23885/cx23885-dvb.c b/linux/drivers/media/video/cx23885/cx23885-dvb.c
index 689c54541..5923f214e 100644
--- a/linux/drivers/media/video/cx23885/cx23885-dvb.c
+++ b/linux/drivers/media/video/cx23885/cx23885-dvb.c
@@ -37,9 +37,9 @@
#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"
static unsigned int debug;
@@ -108,6 +108,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,
@@ -179,6 +186,10 @@ static struct tda18271_config hauppauge_tda18271_config = {
.gate = TDA18271_GATE_ANALOG,
};
+static struct tda18271_config hauppauge_hvr1200_tuner_config = {
+ .gate = TDA18271_GATE_ANALOG,
+};
+
static int cx23885_hvr1500_xc3028_callback(void *ptr, int command, int arg)
{
struct cx23885_tsport *port = ptr;
@@ -309,7 +320,7 @@ static int dvb_register(struct cx23885_tsport *port)
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,
@@ -318,6 +329,21 @@ static int dvb_register(struct cx23885_tsport *port)
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;
default:
printk("%s: The frontend of your DVB/ATSC card isn't supported yet\n",
dev->name);
diff --git a/linux/drivers/media/video/cx23885/cx23885-i2c.c b/linux/drivers/media/video/cx23885/cx23885-i2c.c
index a06d50396..972c58cc9 100644
--- a/linux/drivers/media/video/cx23885/cx23885-i2c.c
+++ b/linux/drivers/media/video/cx23885/cx23885-i2c.c
@@ -374,6 +374,7 @@ static struct i2c_client cx23885_i2c_client_template = {
};
static char *i2c_devs[128] = {
+ [0x10 >> 1] = "tda10048",
[ 0x1c >> 1 ] = "lgdt3303",
[ 0x86 >> 1 ] = "tda9887",
[ 0x32 >> 1 ] = "cx24227",
diff --git a/linux/drivers/media/video/cx23885/cx23885.h b/linux/drivers/media/video/cx23885/cx23885.h
index d66fe2484..7eaadeab6 100644
--- a/linux/drivers/media/video/cx23885/cx23885.h
+++ b/linux/drivers/media/video/cx23885/cx23885.h
@@ -62,6 +62,8 @@
#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
/* Currently unsupported by the driver: PAL/H, NTSC/Kr, SECAM B/G/H/LC */
#define CX23885_NORMS (\
diff --git a/linux/drivers/media/video/cx25840/cx25840-core.c b/linux/drivers/media/video/cx25840/cx25840-core.c
index 82e7fb267..7e21143e2 100644
--- a/linux/drivers/media/video/cx25840/cx25840-core.c
+++ b/linux/drivers/media/video/cx25840/cx25840-core.c
@@ -1297,6 +1297,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/linux/drivers/media/video/cx88/cx88-cards.c b/linux/drivers/media/video/cx88/cx88-cards.c
index fcecfeed9..0809039a5 100644
--- a/linux/drivers/media/video/cx88/cx88-cards.c
+++ b/linux/drivers/media/video/cx88/cx88-cards.c
@@ -1410,6 +1410,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",
diff --git a/linux/drivers/media/video/cx88/cx88-dvb.c b/linux/drivers/media/video/cx88/cx88-dvb.c
index 8559ef873..7d35590f9 100644
--- a/linux/drivers/media/video/cx88/cx88-dvb.c
+++ b/linux/drivers/media/video/cx88/cx88-dvb.c
@@ -46,7 +46,6 @@
#include "nxt200x.h"
#include "cx24123.h"
#include "isl6421.h"
-#include "tuner-xc2028-types.h"
#include "tuner-simple.h"
#include "tda9887.h"
@@ -820,7 +819,7 @@ static int dvb_register(struct cx8802_dev *dev)
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,
diff --git a/linux/drivers/media/video/dpc7146.c b/linux/drivers/media/video/dpc7146.c
index 258d46407..4bfb3076b 100644
--- a/linux/drivers/media/video/dpc7146.c
+++ b/linux/drivers/media/video/dpc7146.c
@@ -132,7 +132,7 @@ static int dpc_probe(struct saa7146_dev* dev)
device_for_each_child(&dpc->i2c_adapter.dev, dpc, dpc_check_clients);
/* check if all devices are present */
- if( 0 == dpc->saa7111a ) {
+ if (!dpc->saa7111a) {
DEB_D(("dpc_v4l2.o: dpc_attach failed for this device.\n"));
i2c_del_adapter(&dpc->i2c_adapter);
kfree(dpc);
diff --git a/linux/drivers/media/video/em28xx/Kconfig b/linux/drivers/media/video/em28xx/Kconfig
index 0f7a0bd86..3d9082fa6 100644
--- a/linux/drivers/media/video/em28xx/Kconfig
+++ b/linux/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,14 @@ 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/linux/drivers/media/video/em28xx/Makefile b/linux/drivers/media/video/em28xx/Makefile
index 092455099..3d1c3cc33 100644
--- a/linux/drivers/media/video/em28xx/Makefile
+++ b/linux/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/linux/drivers/media/video/em28xx/em28xx-cards.c b/linux/drivers/media/video/em28xx/em28xx-cards.c
index 06a4e4a2b..bdf64cd9c 100644
--- a/linux/drivers/media/video/em28xx/em28xx-cards.c
+++ b/linux/drivers/media/video/em28xx/em28xx-cards.c
@@ -37,7 +37,6 @@
#include <media/v4l2-common.h>
#include "em28xx.h"
-#include "tuner-xc2028.h"
static int tuner = -1;
module_param(tuner, int, 0444);
@@ -53,26 +52,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",
@@ -201,6 +180,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,
@@ -215,9 +195,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",
@@ -454,7 +431,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},
@@ -466,79 +472,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;
@@ -553,11 +593,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;
@@ -655,19 +693,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/linux/drivers/media/video/em28xx/em28xx-core.c b/linux/drivers/media/video/em28xx/em28xx-core.c
index 97635abb9..393425487 100644
--- a/linux/drivers/media/video/em28xx/em28xx-core.c
+++ b/linux/drivers/media/video/em28xx/em28xx-core.c
@@ -53,6 +53,12 @@ static int alt = EM28XX_PINOUT;
module_param(alt, int, 0644);
MODULE_PARM_DESC(alt, "alternate setting to use for video endpoint");
+/* 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()
* reads data from the usb device specifying bRequest
@@ -71,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");
}
@@ -128,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);
@@ -137,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)
@@ -147,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;
}
/*
@@ -167,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);
}
@@ -181,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;
}
@@ -212,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;
}
@@ -238,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);
@@ -246,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;
}
@@ -266,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;
@@ -277,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);
@@ -288,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;
}
@@ -296,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,
@@ -349,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 */
@@ -426,10 +490,246 @@ int em28xx_set_alternate(struct em28xx *dev)
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",
+ em28xx_errdev("cannot change alternate number to %d (error=%i)\n",
dev->alt, errCode);
return errCode;
}
}
return 0;
}
+
+int em28xx_gpio_set(struct em28xx *dev, struct em28xx_reg_seq *gpio)
+{
+ 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 rc;
+}
+
+int em28xx_set_mode(struct em28xx *dev, enum em28xx_mode set_mode)
+{
+ if (dev->mode == set_mode)
+ return 0;
+
+ if (set_mode == EM28XX_MODE_UNDEFINED) {
+ dev->mode = set_mode;
+ return 0;
+ }
+
+#if 0
+ /* Resource is locked */
+ if (dev->mode != EM28XX_MODE_UNDEFINED)
+ return -EINVAL;
+#endif
+ dev->mode = set_mode;
+
+ if (dev->mode == EM28XX_DIGITAL_MODE)
+ return em28xx_gpio_set(dev, dev->digital_gpio);
+ else
+ return em28xx_gpio_set(dev, dev->analog_gpio);
+}
+EXPORT_SYMBOL_GPL(em28xx_set_mode);
+
+/* ------------------------------------------------------------------
+ URB control
+ ------------------------------------------------------------------*/
+
+/*
+ * IRQ callback, called by URB callback
+ */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
+static void em28xx_irq_callback(struct urb *urb, struct pt_regs *regs)
+#else
+static void em28xx_irq_callback(struct urb *urb)
+#endif
+{
+ struct em28xx_dmaqueue *dma_q = urb->context;
+ struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
+ int rc, i;
+
+ /* 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;
+
+ urb->status = usb_submit_urb(urb, GFP_ATOMIC);
+ if (urb->status) {
+ em28xx_isocdbg("urb resubmit failed (error=%i)\n",
+ urb->status);
+ }
+}
+
+/*
+ * Stop and Deallocate URBs
+ */
+void em28xx_uninit_isoc(struct em28xx *dev)
+{
+ struct urb *urb;
+ int 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,
+ urb->transfer_buffer_length,
+ dev->isoc_ctl.transfer_buffer[i],
+ urb->transfer_dma);
+ }
+ usb_free_urb(urb);
+ dev->isoc_ctl.urb[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);
+
+/*
+ * Allocate URBs and start IRQ
+ */
+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))
+{
+ 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->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);
+ return -ENOMEM;
+ }
+ 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;
+ }
+ }
+
+ init_waitqueue_head(&dma_q->wq);
+
+ em28xx_capture_start(dev, 1);
+
+ /* 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/linux/drivers/media/video/em28xx/em28xx-dvb.c b/linux/drivers/media/video/em28xx/em28xx-dvb.c
new file mode 100644
index 000000000..5c9941d92
--- /dev/null
+++ b/linux/drivers/media/video/em28xx/em28xx-dvb.c
@@ -0,0 +1,506 @@
+/*
+ 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 "compat.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 */
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
+ struct mutex lock;
+#else
+ struct semaphore lock;
+#endif
+ int nfeeds;
+
+ /* general boilerplate stuff */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ struct dvb_adapter adapter;
+#else
+ struct dvb_adapter *adapter;
+#endif
+ 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;
+
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb->adapter.priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(&dvb->adapter, dvb->frontend);
+#else
+ dvb->adapter->priv = dev;
+
+ /* register frontend */
+ result = dvb_register_frontend(dvb->adapter, dvb->frontend);
+#endif
+ 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;
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ result = dvb_dmxdev_init(&dvb->dmxdev, &dvb->adapter);
+#else
+ result = dvb_dmxdev_init(&dvb->dmxdev, dvb->adapter);
+#endif
+ 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 */
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_net_init(&dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#else
+ dvb_net_init(dvb->adapter, &dvb->net, &dvb->demux.dmx);
+#endif
+ 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);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_unregister_adapter(&dvb->adapter);
+#else
+ dvb_unregister_adapter(dvb->adapter);
+#endif
+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);
+#if (LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 12))
+ dvb_unregister_adapter(&dvb->adapter);
+#else
+ dvb_unregister_adapter(dvb->adapter);
+#endif
+}
+
+
+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/linux/drivers/media/video/em28xx/em28xx-i2c.c b/linux/drivers/media/video/em28xx/em28xx-i2c.c
index f1e52e5d1..c22e73019 100644
--- a/linux/drivers/media/video/em28xx/em28xx-i2c.c
+++ b/linux/drivers/media/video/em28xx/em28xx-i2c.c
@@ -41,11 +41,21 @@ 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, __func__ , ##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;
}
@@ -441,58 +454,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;
+ 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;
+ default:
+ if (!dev->tuner_addr)
+ dev->tuner_addr = client->addr;
- dprintk1(1,"attach inform: detected I2C address %x\n", client->addr << 1);
+ dprintk1(1, "attach inform: detected I2C address %x\n",
+ client->addr << 1);
}
@@ -522,7 +538,7 @@ static struct i2c_adapter em28xx_adap_template = {
static struct i2c_client em28xx_client_template = {
.name = "em28xx internal",
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
.flags = I2C_CLIENT_ALLOW_USE,
#endif
};
diff --git a/linux/drivers/media/video/em28xx/em28xx-input.c b/linux/drivers/media/video/em28xx/em28xx-input.c
index 5c78eceff..49c40f083 100644
--- a/linux/drivers/media/video/em28xx/em28xx-input.c
+++ b/linux/drivers/media/video/em28xx/em28xx-input.c
@@ -33,10 +33,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); \
+ }
/* ----------------------------------------------------------------------- */
@@ -45,7 +47,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;
}
@@ -75,29 +77,30 @@ 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;
#if 0
/* avoid reapeating keystrokes */
- if (buf[1]==ir->old)
+ if (buf[1] == ir->old)
return 0;
#endif
- 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;
@@ -112,15 +115,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/linux/drivers/media/video/em28xx/em28xx-reg.h b/linux/drivers/media/video/em28xx/em28xx-reg.h
new file mode 100644
index 000000000..9058bed07
--- /dev/null
+++ b/linux/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/linux/drivers/media/video/em28xx/em28xx-video.c b/linux/drivers/media/video/em28xx/em28xx-video.c
index 924f29214..093fef4bb 100644
--- a/linux/drivers/media/video/em28xx/em28xx-video.c
+++ b/linux/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>
@@ -33,7 +34,7 @@
#include <linux/i2c.h>
#include <linux/version.h>
#include <linux/mm.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
#include <linux/mutex.h>
#endif
@@ -41,7 +42,7 @@
#include <media/v4l2-common.h>
#include <media/msp3400.h>
#include <media/tuner.h>
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
#include "i2c-compat.h"
#endif
@@ -63,14 +64,13 @@ 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) \
+#define em28xx_isocdbg(fmt, arg...) \
+do {\
+ if (isoc_debug) { \
printk(KERN_INFO "%s %s :"fmt, \
- dev->name, __func__ , ##arg); } while (0)
-
-/* Limits minimum and default number of buffers */
-#define EM28XX_MIN_BUF 4
-#define EM28XX_DEF_BUF 8
+ dev->name, __func__ , ##arg); \
+ } \
+ } while (0)
MODULE_AUTHOR(DRIVER_AUTHOR);
MODULE_DESCRIPTION(DRIVER_DESC);
@@ -83,13 +83,13 @@ static unsigned int video_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int vbi_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
static unsigned int radio_nr[] = {[0 ... (EM28XX_MAXBOARDS - 1)] = UNSET };
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,5,0)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
MODULE_PARM(card, "1-" __stringify(EM28XX_MAXBOARDS) "i");
MODULE_PARM(video_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
MODULE_PARM(vbi_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
MODULE_PARM(radio_nr, "1-" __stringify(EM28XX_MAXBOARDS) "i");
#else
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,10)
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 10)
static int dummy;
module_param_array(card, int, dummy, 0444);
module_param_array(video_nr, int, dummy, 0444);
@@ -108,8 +108,8 @@ MODULE_PARM_DESC(vbi_nr, "vbi device numbers");
MODULE_PARM_DESC(radio_nr, "radio device numbers");
static unsigned int video_debug;
-module_param(video_debug,int,0644);
-MODULE_PARM_DESC(video_debug,"enable debug messages [video]");
+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;
@@ -126,7 +126,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",
@@ -313,11 +313,10 @@ static inline void get_next_buf(struct em28xx_dmaqueue *dma_q,
/*
* Controls the isoc copy of each urb packet
*/
-static inline int em28xx_isoc_copy(struct urb *urb)
+static inline int em28xx_isoc_copy(struct em28xx *dev, struct urb *urb)
{
struct em28xx_buffer *buf;
struct em28xx_dmaqueue *dma_q = urb->context;
- struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
unsigned char *outp = NULL;
int i, len = 0, rc = 1;
unsigned char *p;
@@ -399,192 +398,6 @@ static inline int em28xx_isoc_copy(struct urb *urb)
}
/* ------------------------------------------------------------------
- URB control
- ------------------------------------------------------------------*/
-
-/*
- * IRQ callback, called by URB callback
- */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 19)
-static void em28xx_irq_callback(struct urb *urb, struct pt_regs *regs)
-#else
-static void em28xx_irq_callback(struct urb *urb)
-#endif
-{
- struct em28xx_dmaqueue *dma_q = urb->context;
- struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
- int rc, i;
-
- /* Copy data from URB */
- spin_lock(&dev->slock);
- rc = em28xx_isoc_copy(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;
-
- urb->status = usb_submit_urb(urb, GFP_ATOMIC);
- if (urb->status) {
- em28xx_err("urb resubmit failed (error=%i)\n",
- urb->status);
- }
-}
-
-/*
- * Stop and Deallocate URBs
- */
-static void em28xx_uninit_isoc(struct em28xx *dev)
-{
- struct urb *urb;
- int 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,
- urb->transfer_buffer_length,
- dev->isoc_ctl.transfer_buffer[i],
- urb->transfer_dma);
- }
- usb_free_urb(urb);
- dev->isoc_ctl.urb[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);
-}
-
-/*
- * Allocate URBs and start IRQ
- */
-static int em28xx_prepare_isoc(struct em28xx *dev, int max_packets,
- int num_bufs)
-{
- struct em28xx_dmaqueue *dma_q = &dev->vidq;
- int i;
- int sb_size, pipe;
- struct urb *urb;
- int j, k;
-
- em28xx_isocdbg("em28xx: called em28xx_prepare_isoc\n");
-
- /* De-allocates all pending stuff */
- em28xx_uninit_isoc(dev);
-
- 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 = dev->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->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);
- return -ENOMEM;
- }
- 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, 0x82);
- 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;
- }
- }
-
- return 0;
-}
-
-static int em28xx_start_thread(struct em28xx_dmaqueue *dma_q)
-{
- struct em28xx *dev = container_of(dma_q, struct em28xx, vidq);
- int i, rc = 0;
-
- em28xx_videodbg("Called em28xx_start_thread\n");
-
- init_waitqueue_head(&dma_q->wq);
-
- em28xx_capture_start(dev, 1);
-
- /* 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;
- }
- }
-
- if (rc < 0)
- return rc;
-
- return 0;
-}
-
-/* ------------------------------------------------------------------
Videobuf operations
------------------------------------------------------------------*/
@@ -592,6 +405,8 @@ 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)
@@ -600,6 +415,12 @@ buffer_setup(struct videobuf_queue *vq, unsigned int *count, unsigned int *size)
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;
}
@@ -637,7 +458,6 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
struct em28xx_fh *fh = vq->priv_data;
struct em28xx_buffer *buf = container_of(vb, struct em28xx_buffer, vb);
struct em28xx *dev = fh->dev;
- struct em28xx_dmaqueue *vidq = &dev->vidq;
int rc = 0, urb_init = 0;
/* FIXME: It assumes depth = 16 */
@@ -661,12 +481,9 @@ buffer_prepare(struct videobuf_queue *vq, struct videobuf_buffer *vb,
urb_init = 1;
if (urb_init) {
- rc = em28xx_prepare_isoc(dev, EM28XX_NUM_PACKETS,
- EM28XX_NUM_BUFS);
- if (rc < 0)
- goto fail;
-
- rc = em28xx_start_thread(vidq);
+ rc = em28xx_init_isoc(dev, EM28XX_NUM_PACKETS,
+ EM28XX_NUM_BUFS, dev->max_pkt_size,
+ em28xx_isoc_copy);
if (rc < 0)
goto fail;
}
@@ -692,7 +509,8 @@ buffer_queue(struct videobuf_queue *vq, struct videobuf_buffer *vb)
}
-static void buffer_release(struct videobuf_queue *vq, struct videobuf_buffer *vb)
+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;
@@ -710,7 +528,7 @@ static struct videobuf_queue_ops em28xx_video_qops = {
.buf_release = buffer_release,
};
-/********************* v4l2 interface ******************************************/
+/********************* v4l2 interface **************************************/
/*
* em28xx_config()
@@ -726,9 +544,9 @@ static int em28xx_config(struct em28xx *dev)
#if 1
/* enable vbi capturing */
-/* em28xx_write_regs_req(dev,0x00,0x0e,"\xC0",1); audio register */
-/* em28xx_write_regs_req(dev,0x00,0x0f,"\x80",1); clk register */
- em28xx_write_regs_req(dev,0x00,0x11,"\x51",1);
+/* em28xx_write_regs_req(dev, 0x00, 0x0e, "\xC0", 1); audio register */
+/* em28xx_write_regs_req(dev, 0x00, 0x0f, "\x80", 1); clk register */
+ em28xx_write_regs_req(dev, 0x00, 0x11, "\x51", 1);
#endif
dev->mute = 1; /* maybe not the right place... */
@@ -768,12 +586,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);
@@ -1013,7 +834,7 @@ out:
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;
@@ -1130,11 +951,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;
@@ -1345,9 +1166,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;
@@ -1749,7 +1570,7 @@ 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;
@@ -1774,8 +1595,15 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
em28xx_videodbg("open minor=%d type=%s users=%d\n",
minor, v4l2_type_names[fh_type], dev->users);
- fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
+#if 0
+ errCode = em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
+ if (errCode < 0) {
+ em28xx_errdev("Device locked on digital mode. Can't open analog\n");
+ return -EBUSY;
+ }
+#endif
+ fh = kzalloc(sizeof(struct em28xx_fh), GFP_KERNEL);
if (!fh) {
em28xx_errdev("em28xx-video.c: Out of memory?!\n");
return -ENOMEM;
@@ -1792,9 +1620,15 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
dev->hscale = 0;
dev->vscale = 0;
+ em28xx_set_mode(dev, EM28XX_ANALOG_MODE);
em28xx_set_alternate(dev);
em28xx_resolution_set(dev);
+ /* Needed, since GPIO might have disabled power of
+ some i2c device
+ */
+ em28xx_config_i2c(dev);
+
#if 0
/* device needs to be initialized before isoc transfer */
video_mux(dev, 0);
@@ -1815,6 +1649,7 @@ static int em28xx_v4l2_open(struct inode *inode, struct file *filp)
sizeof(struct em28xx_buffer), fh);
mutex_unlock(&dev->lock);
+
return errCode;
}
@@ -1857,12 +1692,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)
{
@@ -1893,6 +1729,7 @@ static int em28xx_v4l2_close(struct inode *inode, struct file *filp)
/* do this before setting alternate! */
em28xx_uninit_isoc(dev);
+ em28xx_set_mode(dev, EM28XX_MODE_UNDEFINED);
/* set alternate 0 */
dev->alt = 0;
@@ -1915,7 +1752,7 @@ 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,
+em28xx_v4l2_read(struct file *filp, char __user *buf, size_t count,
loff_t *pos)
{
struct em28xx_fh *fh = filp->private_data;
@@ -2089,7 +1926,7 @@ static struct video_device em28xx_radio_template = {
#endif
};
-/******************************** usb interface *****************************************/
+/******************************** usb interface ******************************/
static LIST_HEAD(em28xx_extension_devlist);
@@ -2184,10 +2021,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);
@@ -2331,6 +2164,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");
}
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
@@ -2369,22 +2205,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);
@@ -2394,18 +2232,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;
}
@@ -2413,7 +2252,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;
}
@@ -2437,14 +2276,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;
}
@@ -2454,11 +2293,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 */
@@ -2494,7 +2333,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);
@@ -2531,7 +2371,7 @@ static void em28xx_usb_disconnect(struct usb_interface *interface)
}
static struct usb_driver em28xx_usb_driver = {
-#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2, 6, 15)
.owner = THIS_MODULE,
#endif
.name = "em28xx",
diff --git a/linux/drivers/media/video/em28xx/em28xx.h b/linux/drivers/media/video/em28xx/em28xx.h
index cf6efe070..d31d11a5e 100644
--- a/linux/drivers/media/video/em28xx/em28xx.h
+++ b/linux/drivers/media/video/em28xx/em28xx.h
@@ -30,10 +30,38 @@
#include <media/videobuf-vmalloc.h>
#include <linux/i2c.h>
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
#include <linux/mutex.h>
#endif
#include <media/ir-kbd-i2c.h>
+#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 */
@@ -84,12 +112,20 @@
/* time in msecs to wait for i2c writes to finish */
#define EM2800_I2C_WRITE_TIMEOUT 20
+enum em28xx_mode {
+ EM28XX_MODE_UNDEFINED,
+ EM28XX_ANALOG_MODE,
+ EM28XX_DIGITAL_MODE,
+};
+
enum em28xx_stream_state {
STREAM_OFF,
STREAM_INTERRUPT,
STREAM_ON,
};
+struct em28xx;
+
struct em28xx_usb_isoc_ctl {
/* max packet size of isoc transaction */
int max_pkt_size;
@@ -119,6 +155,10 @@ struct em28xx_usb_isoc_ctl {
/* Stores the number of received fields */
int nfields;
+
+ /* isoc urb callback */
+ int (*isoc_copy) (struct em28xx *dev, struct urb *urb);
+
};
struct em28xx_fmt {
@@ -190,6 +230,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;
@@ -203,8 +249,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;
@@ -237,7 +282,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];
@@ -263,13 +311,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;
@@ -277,6 +336,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;
@@ -309,7 +378,8 @@ struct em28xx {
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;
@@ -320,7 +390,7 @@ struct em28xx {
struct work_struct request_module_wk;
/* locks */
-#if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,15)
+#if LINUX_VERSION_CODE > KERNEL_VERSION(2, 6, 15)
struct mutex lock;
#else
struct semaphore lock, fileop_lock;
@@ -347,24 +417,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_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,
+ 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;
- struct videobuf_queue vb_vidq;
+ /* Caches GPO and GPIO registers */
+ unsigned char reg_gpo, reg_gpio;
- enum v4l2_buf_type type;
+ struct em28xx_dvb *dvb;
};
struct em28xx_ops {
@@ -402,19 +469,26 @@ 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_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 */
@@ -423,71 +497,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 {\
@@ -504,80 +513,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;
@@ -585,7 +594,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/linux/drivers/media/video/ivtv/ivtv-fileops.c b/linux/drivers/media/video/ivtv/ivtv-fileops.c
index d949a8133..a7640c49f 100644
--- a/linux/drivers/media/video/ivtv/ivtv-fileops.c
+++ b/linux/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);
}
diff --git a/linux/drivers/media/video/ivtv/ivtv-mailbox.c b/linux/drivers/media/video/ivtv/ivtv-mailbox.c
index 13a6c374d..1b5c0ac09 100644
--- a/linux/drivers/media/video/ivtv/ivtv-mailbox.c
+++ b/linux/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/linux/drivers/media/video/ivtv/ivtv-streams.c b/linux/drivers/media/video/ivtv/ivtv-streams.c
index 24d98ecf3..4ab8d3683 100644
--- a/linux/drivers/media/video/ivtv/ivtv-streams.c
+++ b/linux/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/linux/drivers/media/video/msp3400-driver.c b/linux/drivers/media/video/msp3400-driver.c
index ef780ed60..716f30eb5 100644
--- a/linux/drivers/media/video/msp3400-driver.c
+++ b/linux/drivers/media/video/msp3400-driver.c
@@ -410,7 +410,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)
@@ -558,7 +558,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/linux/drivers/media/video/mxb.c b/linux/drivers/media/video/mxb.c
index 97cc92c82..bf2462a58 100644
--- a/linux/drivers/media/video/mxb.c
+++ b/linux/drivers/media/video/mxb.c
@@ -222,9 +222,8 @@ static int mxb_probe(struct saa7146_dev* dev)
device_for_each_child(&mxb->i2c_adapter.dev, mxb, mxb_check_clients);
/* check if all devices are present */
- if( 0 == mxb->tea6420_1 || 0 == mxb->tea6420_2 || 0 == mxb->tea6415c
- || 0 == mxb->tda9840 || 0 == mxb->saa7111a || 0 == mxb->tuner ) {
-
+ if (!mxb->tea6420_1 || !mxb->tea6420_2 || !mxb->tea6415c ||
+ !mxb->tda9840 || !mxb->saa7111a || !mxb->tuner) {
printk("mxb: did not find all i2c devices. aborting\n");
i2c_del_adapter(&mxb->i2c_adapter);
kfree(mxb);
diff --git a/linux/drivers/media/video/ov511.c b/linux/drivers/media/video/ov511.c
index cba851d18..4c8050667 100644
--- a/linux/drivers/media/video/ov511.c
+++ b/linux/drivers/media/video/ov511.c
@@ -5838,7 +5838,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/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
index 32e43e9d1..8b500528d 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ctrl.c
@@ -68,7 +68,7 @@ int pvr2_ctrl_set_mask_value(struct pvr2_ctrl *cptr,int mask,int val)
int ret = 0;
if (!cptr) return -EINVAL;
LOCK_TAKE(cptr->hdw->big_lock); do {
- if (cptr->info->set_value != 0) {
+ 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)||
@@ -269,7 +269,7 @@ unsigned int pvr2_ctrl_get_v4lflags(struct pvr2_ctrl *cptr)
int pvr2_ctrl_is_writable(struct pvr2_ctrl *cptr)
{
if (!cptr) return 0;
- return cptr->info->set_value != 0;
+ return cptr->info->set_value != NULL;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
index 77edc72a2..8356bc0e4 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-hdw.c
@@ -2357,7 +2357,7 @@ static int pvr2_hdw_commit_setup(struct pvr2_hdw *hdw)
for (idx = 0; idx < hdw->control_cnt; idx++) {
cptr = hdw->controls + idx;
- if (cptr->info->is_dirty == 0) continue;
+ if (!cptr->info->is_dirty) continue;
if (!cptr->info->is_dirty(cptr)) continue;
commit_flag = !0;
@@ -2706,7 +2706,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
u16 address;
unsigned int pipe;
LOCK_TAKE(hdw->big_lock); do {
- if ((hdw->fw_buffer == 0) == !enable_flag) break;
+ if ((hdw->fw_buffer == NULL) == !enable_flag) break;
if (!enable_flag) {
pvr2_trace(PVR2_TRACE_FIRMWARE,
@@ -2775,7 +2775,7 @@ void pvr2_hdw_cpufw_set_enabled(struct pvr2_hdw *hdw,
/* Return true if we're in a mode for retrieval CPU firmware */
int pvr2_hdw_cpufw_get_enabled(struct pvr2_hdw *hdw)
{
- return hdw->fw_buffer != 0;
+ return hdw->fw_buffer != NULL;
}
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
index 7b3be67f5..e4aae2c97 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-io.c
@@ -603,7 +603,7 @@ void pvr2_stream_kill(struct pvr2_stream *sp)
struct pvr2_buffer *bp;
mutex_lock(&sp->mutex); do {
pvr2_stream_internal_flush(sp);
- while ((bp = pvr2_stream_get_ready_buffer(sp)) != 0) {
+ while ((bp = pvr2_stream_get_ready_buffer(sp)) != NULL) {
pvr2_buffer_set_idle(bp);
}
if (sp->buffer_total_count != sp->buffer_target_count) {
diff --git a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
index aef12fecb..d7bbbe00f 100644
--- a/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
+++ b/linux/drivers/media/video/pvrusb2/pvrusb2-ioread.c
@@ -174,7 +174,7 @@ static int pvr2_ioread_start(struct pvr2_ioread *cp)
if (!(cp->stream)) return 0;
pvr2_trace(PVR2_TRACE_START_STOP,
"/*---TRACE_READ---*/ pvr2_ioread_start id=%p",cp);
- while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != 0) {
+ while ((bp = pvr2_stream_get_idle_buffer(cp->stream)) != NULL) {
stat = pvr2_buffer_queue(bp);
if (stat < 0) {
pvr2_trace(PVR2_TRACE_DATA_FLOW,
diff --git a/linux/drivers/media/video/pwc/pwc-if.c b/linux/drivers/media/video/pwc/pwc-if.c
index 6a7db17ba..8236b2b2d 100644
--- a/linux/drivers/media/video/pwc/pwc-if.c
+++ b/linux/drivers/media/video/pwc/pwc-if.c
@@ -929,7 +929,7 @@ static void pwc_iso_stop(struct pwc_device *pdev)
struct urb *urb;
urb = pdev->sbuf[i].urb;
- if (urb != 0) {
+ if (urb) {
PWC_DEBUG_MEMORY("Unlinking URB %p\n", urb);
usb_kill_urb(urb);
}
@@ -945,7 +945,7 @@ static void pwc_iso_free(struct pwc_device *pdev)
struct urb *urb;
urb = pdev->sbuf[i].urb;
- if (urb != 0) {
+ if (urb) {
PWC_DEBUG_MEMORY("Freeing URB\n");
usb_free_urb(urb);
pdev->sbuf[i].urb = NULL;
@@ -1784,8 +1784,7 @@ static int usb_pwc_probe(struct usb_interface *intf, const struct usb_device_id
/* Allocate video_device structure */
pdev->vdev = video_device_alloc();
- if (pdev->vdev == 0)
- {
+ if (!pdev->vdev) {
PWC_ERROR("Err, cannot allocate video_device struture. Failing probe.");
kfree(pdev);
return -ENOMEM;
diff --git a/linux/drivers/media/video/saa7110.c b/linux/drivers/media/video/saa7110.c
index eb561ce6c..0692e4bef 100644
--- a/linux/drivers/media/video/saa7110.c
+++ b/linux/drivers/media/video/saa7110.c
@@ -489,7 +489,7 @@ saa7110_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
@@ -497,7 +497,7 @@ saa7110_detect_client (struct i2c_adapter *adapter,
strlcpy(I2C_NAME(client), "saa7110", sizeof(I2C_NAME(client)));
decoder = kzalloc(sizeof(struct saa7110), GFP_KERNEL);
- if (decoder == 0) {
+ if (!decoder) {
kfree(client);
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/saa7111.c b/linux/drivers/media/video/saa7111.c
index df44aed92..917fb2553 100644
--- a/linux/drivers/media/video/saa7111.c
+++ b/linux/drivers/media/video/saa7111.c
@@ -503,7 +503,7 @@ saa7111_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/saa7114.c b/linux/drivers/media/video/saa7114.c
index ebf42cf9e..158bd123c 100644
--- a/linux/drivers/media/video/saa7114.c
+++ b/linux/drivers/media/video/saa7114.c
@@ -842,7 +842,7 @@ saa7114_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/saa717x.c b/linux/drivers/media/video/saa717x.c
index 030d07dd6..bdae62189 100644
--- a/linux/drivers/media/video/saa717x.c
+++ b/linux/drivers/media/video/saa717x.c
@@ -1529,7 +1529,6 @@ static struct v4l2_i2c_driver_data v4l2_i2c_data = {
.legacy_class = I2C_CLASS_TV_ANALOG | I2C_CLASS_TV_DIGITAL,
#endif
};
-
#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 5, 0)
EXPORT_NO_SYMBOLS;
#endif
diff --git a/linux/drivers/media/video/saa7185.c b/linux/drivers/media/video/saa7185.c
index 2ac144d9a..7a6c9c1fb 100644
--- a/linux/drivers/media/video/saa7185.c
+++ b/linux/drivers/media/video/saa7185.c
@@ -404,7 +404,7 @@ saa7185_detect_client (struct i2c_adapter *adapter,
return 0;
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (client == 0)
+ if (!client)
return -ENOMEM;
client->addr = address;
client->adapter = adapter;
diff --git a/linux/drivers/media/video/tda9840.c b/linux/drivers/media/video/tda9840.c
index 72b6f476c..c41e50ba6 100644
--- a/linux/drivers/media/video/tda9840.c
+++ b/linux/drivers/media/video/tda9840.c
@@ -181,7 +181,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind)
/* allocate memory for client structure */
client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (0 == client) {
+ if (!client) {
printk("not enough kernel memory\n");
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/tea6415c.c b/linux/drivers/media/video/tea6415c.c
index 363b5be2c..16f369195 100644
--- a/linux/drivers/media/video/tea6415c.c
+++ b/linux/drivers/media/video/tea6415c.c
@@ -73,7 +73,7 @@ static int detect(struct i2c_adapter *adapter, int address, int kind)
/* allocate memory for client structure */
client = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (0 == client) {
+ if (!client) {
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/tea6420.c b/linux/drivers/media/video/tea6420.c
index 0e3e039f2..7a8fec9cf 100644
--- a/linux/drivers/media/video/tea6420.c
+++ b/linux/drivers/media/video/tea6420.c
@@ -110,7 +110,7 @@ static int tea6420_detect(struct i2c_adapter *adapter, int address, int kind)
/* allocate memory for client structure */
client = kzalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (0 == client) {
+ if (!client) {
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/tuner-core.c b/linux/drivers/media/video/tuner-core.c
index 38a90afb6..fa218e910 100644
--- a/linux/drivers/media/video/tuner-core.c
+++ b/linux/drivers/media/video/tuner-core.c
@@ -802,7 +802,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;
diff --git a/linux/drivers/media/video/tuner-xc2028-types.h b/linux/drivers/media/video/tuner-xc2028-types.h
index d0057fbf0..e38970f1c 100644
--- a/linux/drivers/media/video/tuner-xc2028-types.h
+++ b/linux/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
*/
@@ -85,11 +88,28 @@
/* 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| \
+#if 0
+/* The current seek algorithm doesn'use those flags. Instead, this is
+ currently useful only for debug process, since this is a HINT table
+ associating an alias to an IF table that can be used by that digital
+ video standard (in the case of DTV6/7/78/8, QAM and ATSC), or to a
+ particular demod type
+ */
+#define SCODE_TYPES (DTV6|QAM|DTV7|DTV78|DTV8|LCD|NOGD|MONO|ATSC|IF| \
LG60|ATI638|OREN538|OREN36|TOYOTA388|TOYOTA794| \
DIBCOM52|ZARLINK456|CHINA|F6MHZ|SCODE)
+#else
+#define SCODE_TYPES SCODE
+#endif
-/* 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/linux/drivers/media/video/tuner-xc2028.c b/linux/drivers/media/video/tuner-xc2028.c
index b333b911c..ce066dc97 100644
--- a/linux/drivers/media/video/tuner-xc2028.c
+++ b/linux/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
@@ -145,7 +145,7 @@ 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];
@@ -250,6 +250,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;
@@ -418,7 +419,7 @@ 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=", __func__);
if (debug) {
@@ -435,18 +436,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;
}
@@ -456,7 +462,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;
@@ -793,10 +799,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))) {
@@ -1065,6 +1071,10 @@ static int xc2028_set_params(struct dvb_frontend *fe,
T_DIGITAL_TV, type, 0, demod);
}
+#if 0
+/* This is needed at sleep (S1/S3), but not at fe_standby. Otherwise,
+ firmware will be loaded on every open()
+ */
static int xc2028_sleep(struct dvb_frontend *fe)
{
struct xc2028_data *priv = fe->tuner_priv;
@@ -1085,7 +1095,7 @@ static int xc2028_sleep(struct dvb_frontend *fe)
return rc;
}
-
+#endif
static int xc2028_dvb_release(struct dvb_frontend *fe)
{
@@ -1133,21 +1143,21 @@ static int xc2028_set_config(struct dvb_frontend *fe, void *priv_cfg)
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;
@@ -1167,8 +1177,9 @@ static const struct dvb_tuner_ops xc2028_dvb_tuner_ops = {
.get_frequency = xc2028_get_frequency,
.get_rf_strength = xc2028_signal,
.set_params = xc2028_set_params,
+#if 0
.sleep = xc2028_sleep,
-
+#endif
#if 0
int (*get_bandwidth)(struct dvb_frontend *fe, u32 *bandwidth);
int (*get_status)(struct dvb_frontend *fe, u32 *status);
diff --git a/linux/drivers/media/video/tuner-xc2028.h b/linux/drivers/media/video/tuner-xc2028.h
index 612e49063..fc2f132a5 100644
--- a/linux/drivers/media/video/tuner-xc2028.h
+++ b/linux/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
diff --git a/linux/drivers/media/video/tvp5150.c b/linux/drivers/media/video/tvp5150.c
index e6907db8b..7dc6623cc 100644
--- a/linux/drivers/media/video/tvp5150.c
+++ b/linux/drivers/media/video/tvp5150.c
@@ -1175,12 +1175,12 @@ static int tvp5150_detect_client(struct i2c_adapter *adapter,
return 0;
c = kmalloc(sizeof(struct i2c_client), GFP_KERNEL);
- if (c == 0)
+ if (!c)
return -ENOMEM;
memcpy(c, &client_template, sizeof(struct i2c_client));
core = kzalloc(sizeof(struct tvp5150), GFP_KERNEL);
- if (core == 0) {
+ if (!core) {
kfree(c);
return -ENOMEM;
}
diff --git a/linux/drivers/media/video/usbvideo/ibmcam.c b/linux/drivers/media/video/usbvideo/ibmcam.c
index 1261593cf..1afbcc147 100644
--- a/linux/drivers/media/video/usbvideo/ibmcam.c
+++ b/linux/drivers/media/video/usbvideo/ibmcam.c
@@ -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/linux/drivers/media/video/videocodec.c b/linux/drivers/media/video/videocodec.c
index b30b6b2a9..cf24956f3 100644
--- a/linux/drivers/media/video/videocodec.c
+++ b/linux/drivers/media/video/videocodec.c
@@ -39,6 +39,7 @@
#ifdef CONFIG_PROC_FS
#include <linux/proc_fs.h>
+#include <linux/seq_file.h>
#include <asm/uaccess.h>
#endif
@@ -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;
-
-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/linux/drivers/media/video/zoran.h b/linux/drivers/media/video/zoran.h
index 848dbcf25..5f74688c1 100644
--- a/linux/drivers/media/video/zoran.h
+++ b/linux/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/linux/drivers/media/video/zoran_driver.c b/linux/drivers/media/video/zoran_driver.c
index aede0b584..6b7a7c137 100644
--- a/linux/drivers/media/video/zoran_driver.c
+++ b/linux/drivers/media/video/zoran_driver.c
@@ -88,7 +88,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 ( \
@@ -97,19 +96,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[] = {
@@ -219,7 +214,6 @@ 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 */
@@ -242,7 +236,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);
@@ -353,7 +346,7 @@ v4l_fbuffer_alloc (struct file *file)
/* Use kmalloc */
mem = kmalloc(fh->v4l_buffers.buffer_size, GFP_KERNEL);
- if (mem == 0) {
+ if (!mem) {
dprintk(1,
KERN_ERR
"%s: v4l_fbuffer_alloc() - kmalloc for V4L buf %d failed\n",
@@ -1776,7 +1769,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,
@@ -1882,7 +1874,6 @@ zoran_v4l2_buffer_status (struct file *file,
return 0;
}
-#endif
static int
zoran_set_norm (struct zoran *zr,
@@ -2691,8 +2682,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
*/
@@ -4264,7 +4253,6 @@ zoran_do_ioctl (struct inode *inode,
return 0;
}
break;
-#endif
default:
dprintk(1, KERN_DEBUG "%s: UNKNOWN ioctl cmd: 0x%x\n",
@@ -4724,9 +4712,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/linux/drivers/media/video/zr364xx.c b/linux/drivers/media/video/zr364xx.c
index 0afd1c9c1..c2abb3af9 100644
--- a/linux/drivers/media/video/zr364xx.c
+++ b/linux/drivers/media/video/zr364xx.c
@@ -395,7 +395,7 @@ static int read_frame(struct zr364xx_camera *cam, int framenum)
}
-static ssize_t zr364xx_read(struct file *file, char *buf, size_t cnt,
+static ssize_t zr364xx_read(struct file *file, char __user *buf, size_t cnt,
loff_t * ppos)
{
unsigned long count = cnt;
diff --git a/linux/include/asm-arm/arch-pxa/pxa-regs.h b/linux/include/asm-arm/arch-pxa/pxa-regs.h
index b65a3a789..368b2297c 100644
--- a/linux/include/asm-arm/arch-pxa/pxa-regs.h
+++ b/linux/include/asm-arm/arch-pxa/pxa-regs.h
@@ -1248,26 +1248,19 @@
#define GPIO10_RTCCLK 10 /* real time clock (1 Hz) */
#define GPIO11_3_6MHz 11 /* 3.6 MHz oscillator out */
#define GPIO12_32KHz 12 /* 32 kHz out */
-#define GPIO12_CIF_DD7 12 /* Capture Interface D7 (PXA27x) */
#define GPIO13_MBGNT 13 /* memory controller grant */
#define GPIO14_MBREQ 14 /* alternate bus master request */
#define GPIO15_nCS_1 15 /* chip select 1 */
#define GPIO16_PWM0 16 /* PWM0 output */
#define GPIO17_PWM1 17 /* PWM1 output */
-#define GPIO17_CIF_DD6 17 /* Capture Interface D6 (PXA27x) */
#define GPIO18_RDY 18 /* Ext. Bus Ready */
#define GPIO19_DREQ1 19 /* External DMA Request */
#define GPIO20_DREQ0 20 /* External DMA Request */
#define GPIO23_SCLK 23 /* SSP clock */
-#define GPIO23_CIF_MCLK 23 /* Capture Interface MCLK (PXA27x) */
#define GPIO24_SFRM 24 /* SSP Frame */
-#define GPIO24_CIF_FV 24 /* Capture Interface FV (PXA27x) */
#define GPIO25_STXD 25 /* SSP transmit */
-#define GPIO25_CIF_LV 25 /* Capture Interface LV (PXA27x) */
#define GPIO26_SRXD 26 /* SSP receive */
-#define GPIO26_CIF_PCLK 26 /* Capture Interface PCLK (PXA27x) */
#define GPIO27_SEXTCLK 27 /* SSP ext_clk */
-#define GPIO27_CIF_DD0 27 /* Capture Interface D0 (PXA27x) */
#define GPIO28_BITCLK 28 /* AC97/I2S bit_clk */
#define GPIO29_SDATA_IN 29 /* AC97 Sdata_in0 / I2S Sdata_in */
#define GPIO30_SDATA_OUT 30 /* AC97/I2S Sdata_out */
@@ -1288,40 +1281,28 @@
#define GPIO41_FFRTS 41 /* FFUART request to send */
#define GPIO42_BTRXD 42 /* BTUART receive data */
#define GPIO42_HWRXD 42 /* HWUART receive data */
-#define GPIO42_CIF_MCLK 42 /* Capture interface MCLK (PXA27x) */
#define GPIO43_BTTXD 43 /* BTUART transmit data */
#define GPIO43_HWTXD 43 /* HWUART transmit data */
-#define GPIO43_CIF_FV 43 /* Capture interface FV (PXA27x) */
#define GPIO44_BTCTS 44 /* BTUART clear to send */
#define GPIO44_HWCTS 44 /* HWUART clear to send */
-#define GPIO44_CIF_LV 44 /* Capture interface LV (PXA27x) */
#define GPIO45_BTRTS 45 /* BTUART request to send */
#define GPIO45_HWRTS 45 /* HWUART request to send */
#define GPIO45_AC97_SYSCLK 45 /* AC97 System Clock */
-#define GPIO45_CIF_PCLK 45 /* Capture interface PCLK (PXA27x) */
#define GPIO46_ICPRXD 46 /* ICP receive data */
#define GPIO46_STRXD 46 /* STD_UART receive data */
#define GPIO47_ICPTXD 47 /* ICP transmit data */
#define GPIO47_STTXD 47 /* STD_UART transmit data */
-#define GPIO47_CIF_DD0 47 /* Capture interface D0 (PXA27x) */
#define GPIO48_nPOE 48 /* Output Enable for Card Space */
-#define GPIO48_CIF_DD5 48 /* Capture interface D5 (PXA27x) */
#define GPIO49_nPWE 49 /* Write Enable for Card Space */
#define GPIO50_nPIOR 50 /* I/O Read for Card Space */
-#define GPIO50_CIF_DD3 50 /* Capture interface D3 (PXA27x) */
#define GPIO51_nPIOW 51 /* I/O Write for Card Space */
-#define GPIO51_CIF_DD2 51 /* Capture interface D2 (PXA27x) */
#define GPIO52_nPCE_1 52 /* Card Enable for Card Space */
-#define GPIO52_CIF_DD4 52 /* Capture interface D4 (PXA27x) */
#define GPIO53_nPCE_2 53 /* Card Enable for Card Space */
#define GPIO53_MMCCLK 53 /* MMC Clock */
-#define GPIO53_CIF_MCLK 53 /* Capture interface MCLK (PXA27x) */
#define GPIO54_MMCCLK 54 /* MMC Clock */
#define GPIO54_pSKTSEL 54 /* Socket Select for Card Space */
#define GPIO54_nPCE_2 54 /* Card Enable for Card Space (PXA27x) */
-#define GPIO54_CIF_PCLK 54 /* Capture interface PCLK (PXA27x) */
#define GPIO55_nPREG 55 /* Card Address bit 26 */
-#define GPIO55_CIF_DD1 55 /* Capture interface D1 (PXA27x) */
#define GPIO56_nPWAIT 56 /* Wait signal for Card Space */
#define GPIO57_nIOIS16 57 /* Bus Width select for I/O Card Space */
#define GPIO58_LDD_0 58 /* LCD data pin 0 */
@@ -1356,28 +1337,11 @@
#define GPIO79_nCS_3 79 /* chip select 3 */
#define GPIO80_nCS_4 80 /* chip select 4 */
#define GPIO81_NSCLK 81 /* NSSP clock */
-#define GPIO81_CIF_DD0 81 /* Capture Interface D0 (PXA27x) */
#define GPIO82_NSFRM 82 /* NSSP Frame */
-#define GPIO82_CIF_DD5 82 /* Capture Interface D5 (PXA27x) */
#define GPIO83_NSTXD 83 /* NSSP transmit */
-#define GPIO83_CIF_DD4 83 /* Capture Interface D4 (PXA27x) */
#define GPIO84_NSRXD 84 /* NSSP receive */
-#define GPIO84_CIF_FV 84 /* Capture Interface FV (PXA27x) */
#define GPIO85_nPCE_1 85 /* Card Enable for Card Space (PXA27x) */
-#define GPIO85_CIF_LV 85 /* Capture Interface LV (PXA27x) */
-#define GPIO90_CIF_DD4 90 /* Capture Interface DD4 (PXA27x) */
-#define GPIO91_CIF_DD5 91 /* Capture Interface DD5 (PXA27x) */
#define GPIO92_MMCDAT0 92 /* MMC DAT0 (PXA27x) */
-#define GPIO93_CIF_DD6 93 /* Capture interface D6 (PXA27x) */
-#define GPIO94_CIF_DD5 94 /* Capture interface D5 (PXA27x) */
-#define GPIO95_CIF_DD4 95 /* Capture interface D4 (PXA27x) */
-#define GPIO98_CIF_DD0 98 /* Capture interface D0 (PXA27x) */
-#define GPIO103_CIF_DD3 103 /* Capture interface D3 (PXA27x) */
-#define GPIO104_CIF_DD2 104 /* Capture interface D2 (PXA27x) */
-#define GPIO105_CIF_DD1 105 /* Capture interface D1 (PXA27x) */
-#define GPIO106_CIF_DD9 106 /* Capture interface D9 (PXA27x) */
-#define GPIO107_CIF_DD8 107 /* Capture interface D8 (PXA27x) */
-#define GPIO108_CIF_DD7 108 /* Capture interface D7 (PXA27x) */
#define GPIO102_nPCE_1 102 /* PCMCIA (PXA27x) */
#define GPIO109_MMCDAT1 109 /* MMC DAT1 (PXA27x) */
#define GPIO110_MMCDAT2 110 /* MMC DAT2 (PXA27x) */
@@ -1387,9 +1351,6 @@
#define GPIO112_MMCCMD 112 /* MMC CMD (PXA27x) */
#define GPIO113_I2S_SYSCLK 113 /* I2S System Clock (PXA27x) */
#define GPIO113_AC97_RESET_N 113 /* AC97 NRESET on (PXA27x) */
-#define GPIO114_CIF_DD1 114 /* Capture interface D1 (PXA27x) */
-#define GPIO115_CIF_DD3 115 /* Capture interface D3 (PXA27x) */
-#define GPIO116_CIF_DD2 116 /* Capture interface D2 (PXA27x) */
/* GPIO alternate function mode & direction */
@@ -1415,26 +1376,19 @@
#define GPIO10_RTCCLK_MD (10 | GPIO_ALT_FN_1_OUT)
#define GPIO11_3_6MHz_MD (11 | GPIO_ALT_FN_1_OUT)
#define GPIO12_32KHz_MD (12 | GPIO_ALT_FN_1_OUT)
-#define GPIO12_CIF_DD7_MD (12 | GPIO_ALT_FN_2_IN)
#define GPIO13_MBGNT_MD (13 | GPIO_ALT_FN_2_OUT)
#define GPIO14_MBREQ_MD (14 | GPIO_ALT_FN_1_IN)
#define GPIO15_nCS_1_MD (15 | GPIO_ALT_FN_2_OUT)
#define GPIO16_PWM0_MD (16 | GPIO_ALT_FN_2_OUT)
#define GPIO17_PWM1_MD (17 | GPIO_ALT_FN_2_OUT)
-#define GPIO17_CIF_DD6_MD (17 | GPIO_ALT_FN_2_IN)
#define GPIO18_RDY_MD (18 | GPIO_ALT_FN_1_IN)
#define GPIO19_DREQ1_MD (19 | GPIO_ALT_FN_1_IN)
#define GPIO20_DREQ0_MD (20 | GPIO_ALT_FN_1_IN)
-#define GPIO23_CIF_MCLK_MD (23 | GPIO_ALT_FN_1_OUT)
#define GPIO23_SCLK_MD (23 | GPIO_ALT_FN_2_OUT)
-#define GPIO24_CIF_FV_MD (24 | GPIO_ALT_FN_1_OUT)
#define GPIO24_SFRM_MD (24 | GPIO_ALT_FN_2_OUT)
-#define GPIO25_CIF_LV_MD (25 | GPIO_ALT_FN_1_OUT)
#define GPIO25_STXD_MD (25 | GPIO_ALT_FN_2_OUT)
#define GPIO26_SRXD_MD (26 | GPIO_ALT_FN_1_IN)
-#define GPIO26_CIF_PCLK_MD (26 | GPIO_ALT_FN_2_IN)
#define GPIO27_SEXTCLK_MD (27 | GPIO_ALT_FN_1_IN)
-#define GPIO27_CIF_DD0_MD (27 | GPIO_ALT_FN_3_IN)
#define GPIO28_BITCLK_AC97_MD (28 | GPIO_ALT_FN_1_IN)
#define GPIO28_BITCLK_IN_I2S_MD (28 | GPIO_ALT_FN_2_IN)
#define GPIO28_BITCLK_OUT_I2S_MD (28 | GPIO_ALT_FN_1_OUT)
@@ -1459,46 +1413,34 @@
#define GPIO40_FFDTR_MD (40 | GPIO_ALT_FN_2_OUT)
#define GPIO41_FFRTS_MD (41 | GPIO_ALT_FN_2_OUT)
#define GPIO42_BTRXD_MD (42 | GPIO_ALT_FN_1_IN)
-#define GPIO42_CIF_MCLK_MD (42 | GPIO_ALT_FN_3_OUT)
#define GPIO42_HWRXD_MD (42 | GPIO_ALT_FN_3_IN)
#define GPIO43_BTTXD_MD (43 | GPIO_ALT_FN_2_OUT)
-#define GPIO43_CIF_FV_MD (43 | GPIO_ALT_FN_3_OUT)
#define GPIO43_HWTXD_MD (43 | GPIO_ALT_FN_3_OUT)
#define GPIO44_BTCTS_MD (44 | GPIO_ALT_FN_1_IN)
#define GPIO44_HWCTS_MD (44 | GPIO_ALT_FN_3_IN)
-#define GPIO44_CIF_LV_MD (44 | GPIO_ALT_FN_3_OUT)
#define GPIO45_BTRTS_MD (45 | GPIO_ALT_FN_2_OUT)
#define GPIO45_HWRTS_MD (45 | GPIO_ALT_FN_3_OUT)
#define GPIO45_SYSCLK_AC97_MD (45 | GPIO_ALT_FN_1_OUT)
-#define GPIO45_CIF_PCLK_MD (45 | GPIO_ALT_FN_3_IN)
#define GPIO46_ICPRXD_MD (46 | GPIO_ALT_FN_1_IN)
#define GPIO46_STRXD_MD (46 | GPIO_ALT_FN_2_IN)
#define GPIO47_ICPTXD_MD (47 | GPIO_ALT_FN_2_OUT)
#define GPIO47_STTXD_MD (47 | GPIO_ALT_FN_1_OUT)
-#define GPIO47_CIF_DD0_MD (47 | GPIO_ALT_FN_1_IN)
#define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT)
-#define GPIO48_CIF_DD5_MD (48 | GPIO_ALT_FN_1_IN)
#define GPIO48_HWTXD_MD (48 | GPIO_ALT_FN_1_OUT)
#define GPIO48_nPOE_MD (48 | GPIO_ALT_FN_2_OUT)
#define GPIO49_HWRXD_MD (49 | GPIO_ALT_FN_1_IN)
#define GPIO49_nPWE_MD (49 | GPIO_ALT_FN_2_OUT)
#define GPIO50_nPIOR_MD (50 | GPIO_ALT_FN_2_OUT)
-#define GPIO50_CIF_DD3_MD (50 | GPIO_ALT_FN_1_IN)
#define GPIO50_HWCTS_MD (50 | GPIO_ALT_FN_1_IN)
#define GPIO51_HWRTS_MD (51 | GPIO_ALT_FN_1_OUT)
#define GPIO51_nPIOW_MD (51 | GPIO_ALT_FN_2_OUT)
-#define GPIO51_CIF_DD2_MD (51 | GPIO_ALT_FN_1_IN)
#define GPIO52_nPCE_1_MD (52 | GPIO_ALT_FN_2_OUT)
-#define GPIO52_CIF_DD4_MD (52 | GPIO_ALT_FN_1_IN)
#define GPIO53_nPCE_2_MD (53 | GPIO_ALT_FN_2_OUT)
#define GPIO53_MMCCLK_MD (53 | GPIO_ALT_FN_1_OUT)
-#define GPIO53_CIF_MCLK_MD (53 | GPIO_ALT_FN_2_OUT)
#define GPIO54_MMCCLK_MD (54 | GPIO_ALT_FN_1_OUT)
#define GPIO54_nPCE_2_MD (54 | GPIO_ALT_FN_2_OUT)
#define GPIO54_pSKTSEL_MD (54 | GPIO_ALT_FN_2_OUT)
-#define GPIO54_CIF_PCLK_MD (54 | GPIO_ALT_FN_3_IN)
#define GPIO55_nPREG_MD (55 | GPIO_ALT_FN_2_OUT)
-#define GPIO55_CIF_DD1_MD (55 | GPIO_ALT_FN_1_IN)
#define GPIO56_nPWAIT_MD (56 | GPIO_ALT_FN_1_IN)
#define GPIO57_nIOIS16_MD (57 | GPIO_ALT_FN_1_IN)
#define GPIO58_LDD_0_MD (58 | GPIO_ALT_FN_2_OUT)
@@ -1535,33 +1477,16 @@
#define GPIO80_nCS_4_MD (80 | GPIO_ALT_FN_2_OUT)
#define GPIO81_NSSP_CLK_OUT (81 | GPIO_ALT_FN_1_OUT)
#define GPIO81_NSSP_CLK_IN (81 | GPIO_ALT_FN_1_IN)
-#define GPIO81_CIF_DD0_MD (81 | GPIO_ALT_FN_2_IN)
#define GPIO82_NSSP_FRM_OUT (82 | GPIO_ALT_FN_1_OUT)
#define GPIO82_NSSP_FRM_IN (82 | GPIO_ALT_FN_1_IN)
-#define GPIO82_CIF_DD5_MD (82 | GPIO_ALT_FN_3_IN)
#define GPIO83_NSSP_TX (83 | GPIO_ALT_FN_1_OUT)
#define GPIO83_NSSP_RX (83 | GPIO_ALT_FN_2_IN)
-#define GPIO83_CIF_DD4_MD (83 | GPIO_ALT_FN_3_IN)
#define GPIO84_NSSP_TX (84 | GPIO_ALT_FN_1_OUT)
#define GPIO84_NSSP_RX (84 | GPIO_ALT_FN_2_IN)
-#define GPIO84_CIF_FV_MD (84 | GPIO_ALT_FN_3_OUT)
#define GPIO85_nPCE_1_MD (85 | GPIO_ALT_FN_1_OUT)
-#define GPIO85_CIF_LV_MD (85 | GPIO_ALT_FN_3_OUT)
-#define GPIO90_CIF_DD4_MD (90 | GPIO_ALT_FN_3_IN)
-#define GPIO91_CIF_DD5_MD (91 | GPIO_ALT_FN_3_IN)
#define GPIO92_MMCDAT0_MD (92 | GPIO_ALT_FN_1_OUT)
-#define GPIO93_CIF_DD6_MD (93 | GPIO_ALT_FN_2_IN)
-#define GPIO94_CIF_DD5_MD (94 | GPIO_ALT_FN_2_IN)
-#define GPIO95_CIF_DD4_MD (95 | GPIO_ALT_FN_2_IN)
-#define GPIO98_CIF_DD0_MD (98 | GPIO_ALT_FN_2_IN)
#define GPIO102_nPCE_1_MD (102 | GPIO_ALT_FN_1_OUT)
-#define GPIO103_CIF_DD3_MD (103 | GPIO_ALT_FN_1_IN)
#define GPIO104_pSKTSEL_MD (104 | GPIO_ALT_FN_1_OUT)
-#define GPIO104_CIF_DD2_MD (104 | GPIO_ALT_FN_1_IN)
-#define GPIO105_CIF_DD1_MD (105 | GPIO_ALT_FN_1_IN)
-#define GPIO106_CIF_DD9_MD (106 | GPIO_ALT_FN_1_IN)
-#define GPIO107_CIF_DD8_MD (107 | GPIO_ALT_FN_1_IN)
-#define GPIO108_CIF_DD7_MD (108 | GPIO_ALT_FN_1_IN)
#define GPIO109_MMCDAT1_MD (109 | GPIO_ALT_FN_1_OUT)
#define GPIO110_MMCDAT2_MD (110 | GPIO_ALT_FN_1_OUT)
#define GPIO110_MMCCS0_MD (110 | GPIO_ALT_FN_1_OUT)
@@ -1840,11 +1765,6 @@
/* [1..256 Tpix] */ \
(((Tpix) - 1) << FShft (LCCR1_BLW))
-#if 0
-#define LCCR3_PCD (0xff) /* Pixel clock divisor */
-#define LCCR3_ACB (0xff << 8) /* AC Bias pin frequency */
-#define LCCR3_ACB_S 8
-#endif
#define LCCR2_LPP Fld (10, 0) /* Line Per Panel - 1 */
#define LCCR2_DisHght(Line) /* Display Height [1..1024 lines] */ \
diff --git a/linux/include/linux/i2c-id.h b/linux/include/linux/i2c-id.h
index b979112f7..32eb8bbe4 100644
--- a/linux/include/linux/i2c-id.h
+++ b/linux/include/linux/i2c-id.h
@@ -125,6 +125,7 @@
#define I2C_HW_B_CX2341X 0x010020 /* Conexant CX2341X MPEG encoder cards */
#define I2C_HW_B_INTELFB 0x010021 /* intel framebuffer driver */
#define I2C_HW_B_CX23885 0x010022 /* conexant 23885 based tv cards (bus1) */
+#define I2C_HW_B_AU0828 0x010023 /* auvitek au0828 usb bridge */
/* --- PCF 8584 based algorithms */
#define I2C_HW_P_ELEK 0x020002 /* Elektor ISA Bus inteface card */
diff --git a/mailimport b/mailimport
index 7b233932e..76364aeea 100755
--- a/mailimport
+++ b/mailimport
@@ -112,6 +112,11 @@ apply_patch () {
make whitespace
hg qrefresh
else
+ echo "WILL commit with this comment:"
+ cat $TMP2| grep -v "^#"
+ echo "Press <break> within 3 seconds if this is wrong."
+ sleep 3
+
patch -s -t -p1 -l -N -d $pdir -i $next
if [ "$?" != "0" ]; then
echo "*** ERROR at: patch -s -t -p1 -l -N -d $pdir -i $next"
diff --git a/v4l/compat.h b/v4l/compat.h
index 257143a6b..78d6c1d75 100644
--- a/v4l/compat.h
+++ b/v4l/compat.h
@@ -14,6 +14,13 @@
#include <linux/i2c-dev.h>
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#ifdef CONFIG_PROC_FS
+#include <linux/module.h>
+#include <linux/proc_fs.h>
+#endif
+#endif
+
/* To allow alsa code to work */
#ifdef NEED_SOUND_DRIVER_H
#include <sound/driver.h>
@@ -517,9 +524,32 @@ do { \
.bInterfaceSubClass = (sc), .bInterfaceProtocol = (pr)
#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 26)
+#define get_unaligned_be16(a) \
+ be16_to_cpu(get_unaligned((unsigned short *)(a)))
+#define put_unaligned_be16(r, a) \
+ put_unaligned(cpu_to_be16(r), ((unsigned short *)(a)))
+#define get_unaligned_le16(a) \
+ le16_to_cpu(get_unaligned((unsigned short *)(a)))
+#define put_unaligned_le16(r, a) \
+ put_unaligned(cpu_to_le16(r), ((unsigned short *)(a)))
+#endif
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2, 6, 25)
+#ifdef CONFIG_PROC_FS
+static inline struct proc_dir_entry *proc_create(const char *a,
+ mode_t b, struct proc_dir_entry *c, const struct file_operations *d)
+{
+ struct proc_dir_entry *e;
+
+ e = create_proc_entry(a, b, c);
+ if (e) {
+ e->owner = THIS_MODULE;
+ e->proc_fops = d;
+
+ }
+ return e;
+}
+#endif
+#endif
+
#endif
-/*
- * Local variables:
- * c-basic-offset: 8
- * End:
- */
diff --git a/v4l/scripts/au0828.pl b/v4l/scripts/au0828.pl
new file mode 100755
index 000000000..822a54afb
--- /dev/null
+++ b/v4l/scripts/au0828.pl
@@ -0,0 +1,48 @@
+#!/usr/bin/perl -w
+use strict;
+
+my $new_entry = -1;
+my $nr = 0;
+my ($id,$subvendor,$subdevice);
+my %data;
+
+while (<>) {
+ # defines in header file
+ if (/#define\s+(AU08[\d]._BOARD_\w+)\s+(\d+)/) {
+ $data{$1}->{nr} = $2;
+ next;
+ }
+ # au0828_boards
+ if (/\[(AU0828_BOARD_\w+)\]/) {
+ $id = $1;
+ $data{$id}->{id} = $id;
+ $data{$id}->{type} = "(au0828)";
+# $data{$id}->{nr} = $nr++;
+ };
+
+ next unless defined($id);
+
+ if (/USB_DEVICE.*0x([0-9a-fA-F]*).*0x([0-9a-fA-F]*)/ ) {
+ $subvendor=$1;
+ $subdevice=$2;
+ }
+
+ if (/.*driver_info.*(AU08[\d]._BOARD_\w+)/ ) {
+ push @{$data{$1}->{subid}}, "$subvendor:$subdevice";
+ }
+
+ if (!defined($data{$id}) || !defined($data{$id}->{name})) {
+ $data{$id}->{name} = $1 if (/\.name\s*=\s*\"([^\"]+)\"/);
+ }
+
+ # au0828_USB_tbl
+
+
+}
+
+foreach my $item (sort { $data{$a}->{nr} <=> $data{$b}->{nr} } keys %data) {
+ printf("%3d -> %-40s %-15s", $data{$item}->{nr}, $data{$item}->{name},$data{$item}->{type});
+ printf(" [%s]",join(",",@{$data{$item}->{subid}}))
+ if defined($data{$item}->{subid});
+ print "\n";
+}
diff --git a/v4l/scripts/cardlist b/v4l/scripts/cardlist
index 3e5213975..9fa89db12 100755
--- a/v4l/scripts/cardlist
+++ b/v4l/scripts/cardlist
@@ -6,7 +6,7 @@ scripts/bttv.pl ../linux/drivers/media/video/bt8xx/bttv.h ../linux/drivers/medi
scripts/cx88.pl ../linux/drivers/media/video/cx88/cx88.h ../linux/drivers/media/video/cx88/cx88-cards.c \
| perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.cx88
-scripts/em28xx.pl ../linux/drivers/media/video/em28xx/em28xx-cards.c \
+scripts/em28xx.pl ../linux/drivers/media/video/em28xx/em28xx-cards.c ../linux/drivers/media/video/em28xx/em28xx.h \
| perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.em28xx
scripts/tuner.pl ../linux/include/media/tuner.h ../linux/drivers/media/video/tuner-types.c \
@@ -20,3 +20,6 @@ scripts/usbvision.pl ../linux/drivers/media/video/usbvision/usbvision-cards.h ..
scripts/cx23885.pl ../linux/drivers/media/video/cx23885/cx23885.h ../linux/drivers/media/video/cx23885/cx23885-cards.c \
| perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.cx23885
+
+scripts/au0828.pl ../linux/drivers/media/video/au0828/au0828-cards.h ../linux/drivers/media/video/au0828/au0828-cards.c \
+ | perl -ne 's/[ \t]+$//; print' > ../linux/Documentation/video4linux/CARDLIST.au0828
diff --git a/v4l/scripts/checkpatch.pl b/v4l/scripts/checkpatch.pl
index 12774e762..511935699 100755
--- a/v4l/scripts/checkpatch.pl
+++ b/v4l/scripts/checkpatch.pl
@@ -9,7 +9,7 @@ use strict;
my $P = $0;
$P =~ s@.*/@@g;
-my $V = '0.14';
+my $V = '0.16';
use Getopt::Long qw(:config no_auto_abbrev);
@@ -18,6 +18,7 @@ my $tree = 1;
my $chk_signoff = 1;
my $chk_patch = 1;
my $tst_type = 0;
+my $tst_only;
my $emacs = 0;
my $terse = 0;
my $file = 0;
@@ -44,6 +45,7 @@ GetOptions(
'debug=s' => \%debug,
'test-type!' => \$tst_type,
+ 'test-only=s' => \$tst_only,
) or exit;
my $exit = 0;
@@ -105,8 +107,7 @@ our $Sparse = qr{
__iomem|
__must_check|
__init_refok|
- __kprobes|
- fastcall
+ __kprobes
}x;
our $Attribute = qr{
const|
@@ -158,7 +159,10 @@ sub build_types {
\b
(?:const\s+)?
(?:unsigned\s+)?
- $all
+ (?:
+ $all|
+ (?:typeof|__typeof__)\s*\(\s*\**\s*$Ident\s*\)
+ )
(?:\s+$Sparse|\s+const)*
\b
}x;
@@ -261,17 +265,7 @@ sub expand_tabs {
return $res;
}
sub copy_spacing {
- my ($str) = @_;
-
- my $res = '';
- for my $c (split(//, $str)) {
- if ($c eq "\t") {
- $res .= $c;
- } else {
- $res .= ' ';
- }
- }
-
+ (my $res = shift) =~ tr/\t/ /c;
return $res;
}
@@ -288,53 +282,76 @@ sub line_stats {
return (length($line), length($white));
}
+my $sanitise_quote = '';
+
+sub sanitise_line_reset {
+ my ($in_comment) = @_;
+
+ if ($in_comment) {
+ $sanitise_quote = '*/';
+ } else {
+ $sanitise_quote = '';
+ }
+}
sub sanitise_line {
my ($line) = @_;
my $res = '';
my $l = '';
- my $quote = '';
my $qlen = 0;
+ my $off = 0;
+ my $c;
- foreach my $c (split(//, $line)) {
- # The second backslash of a pair is not a "quote".
- if ($l eq "\\" && $c eq "\\") {
- $c = 'X';
- }
- if ($l ne "\\" && ($c eq "'" || $c eq '"')) {
- if ($quote eq '') {
- $quote = $c;
- $res .= $c;
- $l = $c;
- $qlen = 0;
- next;
- } elsif ($quote eq $c) {
- $quote = '';
- }
+ # Always copy over the diff marker.
+ $res = substr($line, 0, 1);
+
+ for ($off = 1; $off < length($line); $off++) {
+ $c = substr($line, $off, 1);
+
+ # Comments we are wacking completly including the begin
+ # and end, all to $;.
+ if ($sanitise_quote eq '' && substr($line, $off, 2) eq '/*') {
+ $sanitise_quote = '*/';
+
+ substr($res, $off, 2, "$;$;");
+ $off++;
+ next;
}
- if ($quote eq "'" && $qlen > 1) {
- $quote = '';
+ if (substr($line, $off, 2) eq $sanitise_quote) {
+ $sanitise_quote = '';
+ substr($res, $off, 2, "$;$;");
+ $off++;
+ next;
}
- if ($quote && $c ne "\t") {
- $res .= "X";
- $qlen++;
- } else {
- $res .= $c;
+
+ # A \ in a string means ignore the next character.
+ if (($sanitise_quote eq "'" || $sanitise_quote eq '"') &&
+ $c eq "\\") {
+ substr($res, $off, 2, 'XX');
+ $off++;
+ next;
}
+ # Regular quotes.
+ if ($c eq "'" || $c eq '"') {
+ if ($sanitise_quote eq '') {
+ $sanitise_quote = $c;
- $l = $c;
- }
+ substr($res, $off, 1, $c);
+ next;
+ } elsif ($sanitise_quote eq $c) {
+ $sanitise_quote = '';
+ }
+ }
- # Clear out the comments.
- while ($res =~ m@(/\*.*?\*/)@g) {
- substr($res, $-[1], $+[1] - $-[1]) = $; x ($+[1] - $-[1]);
- }
- if ($res =~ m@(/\*.*)@) {
- substr($res, $-[1], $+[1] - $-[1]) = $; x ($+[1] - $-[1]);
- }
- if ($res =~ m@^.(.*\*/)@) {
- substr($res, $-[1], $+[1] - $-[1]) = $; x ($+[1] - $-[1]);
+ #print "SQ:$sanitise_quote\n";
+ if ($off != 0 && $sanitise_quote eq '*/' && $c ne "\t") {
+ substr($res, $off, 1, $;);
+ } elsif ($off != 0 && $sanitise_quote && $c ne "\t") {
+ substr($res, $off, 1, 'X');
+ } else {
+ substr($res, $off, 1, $c);
+ }
}
# The pathname on a #include may be surrounded by '<' and '>'.
@@ -357,17 +374,19 @@ sub ctx_statement_block {
my $blk = '';
my $soff = $off;
my $coff = $off - 1;
+ my $coff_set = 0;
my $loff = 0;
my $type = '';
my $level = 0;
+ my $p;
my $c;
my $len = 0;
my $remainder;
while (1) {
- #warn "CSB: blk<$blk>\n";
+ #warn "CSB: blk<$blk> remain<$remain>\n";
# If we are about to drop off the end, pull in more
# context.
if ($off >= $len) {
@@ -386,10 +405,11 @@ sub ctx_statement_block {
last;
}
}
+ $p = $c;
$c = substr($blk, $off, 1);
$remainder = substr($blk, $off);
- #warn "CSB: c<$c> type<$type> level<$level>\n";
+ #warn "CSB: c<$c> type<$type> level<$level> remainder<$remainder> coff_set<$coff_set>\n";
# Statement ends at the ';' or a close '}' at the
# outermost level.
if ($level == 0 && $c eq ';') {
@@ -397,9 +417,14 @@ sub ctx_statement_block {
}
# An else is really a conditional as long as its not else if
- if ($level == 0 && $remainder =~ /(\s+else)(?:\s|{)/ &&
- $remainder !~ /\s+else\s+if\b/) {
- $coff = $off + length($1);
+ if ($level == 0 && $coff_set == 0 &&
+ (!defined($p) || $p =~ /(?:\s|\}|\+)/) &&
+ $remainder =~ /^(else)(?:\s|{)/ &&
+ $remainder !~ /^else\s+if\b/) {
+ $coff = $off + length($1) - 1;
+ $coff_set = 1;
+ #warn "CSB: mark coff<$coff> soff<$soff> 1<$1>\n";
+ #warn "[" . substr($blk, $soff, $coff - $soff + 1) . "]\n";
}
if (($type eq '' || $type eq '(') && $c eq '(') {
@@ -412,6 +437,8 @@ sub ctx_statement_block {
if ($level == 0 && $coff < $soff) {
$coff = $off;
+ $coff_set = 1;
+ #warn "CSB: mark coff<$coff>\n";
}
}
if (($type eq '' || $type eq '{') && $c eq '{') {
@@ -439,27 +466,79 @@ sub ctx_statement_block {
#warn "STATEMENT<$statement>\n";
#warn "CONDITION<$condition>\n";
- #print "off<$off> loff<$loff>\n";
+ #print "coff<$coff> soff<$off> loff<$loff>\n";
return ($statement, $condition,
$line, $remain + 1, $off - $loff + 1, $level);
}
+sub statement_lines {
+ my ($stmt) = @_;
+
+ # Strip the diff line prefixes and rip blank lines at start and end.
+ $stmt =~ s/(^|\n)./$1/g;
+ $stmt =~ s/^\s*//;
+ $stmt =~ s/\s*$//;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+
+ return $#stmt_lines + 2;
+}
+
+sub statement_rawlines {
+ my ($stmt) = @_;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+
+ return $#stmt_lines + 2;
+}
+
+sub statement_block_size {
+ my ($stmt) = @_;
+
+ $stmt =~ s/(^|\n)./$1/g;
+ $stmt =~ s/^\s*{//;
+ $stmt =~ s/}\s*$//;
+ $stmt =~ s/^\s*//;
+ $stmt =~ s/\s*$//;
+
+ my @stmt_lines = ($stmt =~ /\n/g);
+ my @stmt_statements = ($stmt =~ /;/g);
+
+ my $stmt_lines = $#stmt_lines + 2;
+ my $stmt_statements = $#stmt_statements + 1;
+
+ if ($stmt_lines > $stmt_statements) {
+ return $stmt_lines;
+ } else {
+ return $stmt_statements;
+ }
+}
+
sub ctx_statement_full {
my ($linenr, $remain, $off) = @_;
my ($statement, $condition, $level);
my (@chunks);
+ # Grab the first conditional/block pair.
($statement, $condition, $linenr, $remain, $off, $level) =
ctx_statement_block($linenr, $remain, $off);
- #print "F: c<$condition> s<$statement>\n";
+ #print "F: c<$condition> s<$statement> remain<$remain>\n";
+ push(@chunks, [ $condition, $statement ]);
+ if (!($remain > 0 && $condition =~ /^\s*(?:\n[+-])?\s*(?:if|else|do)\b/s)) {
+ return ($level, $linenr, @chunks);
+ }
+
+ # Pull in the following conditional/block pairs and see if they
+ # could continue the statement.
for (;;) {
- push(@chunks, [ $condition, $statement ]);
- last if (!($remain > 0 && $condition =~ /^.\s*(?:if|else|do)/));
($statement, $condition, $linenr, $remain, $off, $level) =
ctx_statement_block($linenr, $remain, $off);
- #print "C: c<$condition> s<$statement>\n";
+ #print "C: c<$condition> s<$statement> remain<$remain>\n";
+ last if (!($remain > 0 && $condition =~ /^(?:\s*\n[+-])*\s*(?:else|do)\b/s));
+ #print "C: push\n";
+ push(@chunks, [ $condition, $statement ]);
}
return ($level, $linenr, @chunks);
@@ -593,13 +672,13 @@ sub cat_vet {
}
my $av_preprocessor = 0;
-my $av_paren = 0;
+my $av_pending;
my @av_paren_type;
sub annotate_reset {
$av_preprocessor = 0;
- $av_paren = 0;
- @av_paren_type = ();
+ $av_pending = '_';
+ @av_paren_type = ('E');
}
sub annotate_values {
@@ -611,12 +690,14 @@ sub annotate_values {
print "$stream\n" if ($dbg_values > 1);
while (length($cur)) {
- print " <$type> " if ($dbg_values > 1);
+ @av_paren_type = ('E') if ($#av_paren_type < 0);
+ print " <" . join('', @av_paren_type) .
+ "> <$type> " if ($dbg_values > 1);
if ($cur =~ /^(\s+)/o) {
print "WS($1)\n" if ($dbg_values > 1);
if ($1 =~ /\n/ && $av_preprocessor) {
+ $type = pop(@av_paren_type);
$av_preprocessor = 0;
- $type = 'N';
}
} elsif ($cur =~ /^($Type)/) {
@@ -626,11 +707,33 @@ sub annotate_values {
} elsif ($cur =~ /^(#\s*define\s*$Ident)(\(?)/o) {
print "DEFINE($1)\n" if ($dbg_values > 1);
$av_preprocessor = 1;
- $av_paren_type[$av_paren] = 'N';
+ $av_pending = 'N';
- } elsif ($cur =~ /^(#\s*(?:ifdef|ifndef|if|else|elif|endif))/o) {
- print "PRE($1)\n" if ($dbg_values > 1);
+ } elsif ($cur =~ /^(#\s*(?:ifdef|ifndef|if))/o) {
+ print "PRE_START($1)\n" if ($dbg_values > 1);
$av_preprocessor = 1;
+
+ push(@av_paren_type, $type);
+ push(@av_paren_type, $type);
+ $type = 'N';
+
+ } elsif ($cur =~ /^(#\s*(?:else|elif))/o) {
+ print "PRE_RESTART($1)\n" if ($dbg_values > 1);
+ $av_preprocessor = 1;
+
+ push(@av_paren_type, $av_paren_type[$#av_paren_type]);
+
+ $type = 'N';
+
+ } elsif ($cur =~ /^(#\s*(?:endif))/o) {
+ print "PRE_END($1)\n" if ($dbg_values > 1);
+
+ $av_preprocessor = 1;
+
+ # Assume all arms of the conditional end as this
+ # one does, and continue as if the #endif was not here.
+ pop(@av_paren_type);
+ push(@av_paren_type, $type);
$type = 'N';
} elsif ($cur =~ /^(\\\n)/o) {
@@ -639,13 +742,13 @@ sub annotate_values {
} elsif ($cur =~ /^(sizeof)\s*(\()?/o) {
print "SIZEOF($1)\n" if ($dbg_values > 1);
if (defined $2) {
- $av_paren_type[$av_paren] = 'V';
+ $av_pending = 'V';
}
$type = 'N';
} elsif ($cur =~ /^(if|while|typeof|__typeof__|for)\b/o) {
print "COND($1)\n" if ($dbg_values > 1);
- $av_paren_type[$av_paren] = 'N';
+ $av_pending = 'N';
$type = 'N';
} elsif ($cur =~/^(return|case|else)/o) {
@@ -654,14 +757,14 @@ sub annotate_values {
} elsif ($cur =~ /^(\()/o) {
print "PAREN('$1')\n" if ($dbg_values > 1);
- $av_paren++;
+ push(@av_paren_type, $av_pending);
+ $av_pending = '_';
$type = 'N';
} elsif ($cur =~ /^(\))/o) {
- $av_paren-- if ($av_paren > 0);
- if (defined $av_paren_type[$av_paren]) {
- $type = $av_paren_type[$av_paren];
- undef $av_paren_type[$av_paren];
+ my $new_type = pop(@av_paren_type);
+ if ($new_type ne '_') {
+ $type = $new_type;
print "PAREN('$1') -> $type\n"
if ($dbg_values > 1);
} else {
@@ -670,7 +773,7 @@ sub annotate_values {
} elsif ($cur =~ /^($Ident)\(/o) {
print "FUNC($1)\n" if ($dbg_values > 1);
- $av_paren_type[$av_paren] = 'V';
+ $av_pending = 'V';
} elsif ($cur =~ /^($Ident|$Constant)/o) {
print "IDENT($1)\n" if ($dbg_values > 1);
@@ -680,11 +783,11 @@ sub annotate_values {
print "ASSIGN($1)\n" if ($dbg_values > 1);
$type = 'N';
- } elsif ($cur =~/^(;)/) {
+ } elsif ($cur =~/^(;|{|})/) {
print "END($1)\n" if ($dbg_values > 1);
$type = 'E';
- } elsif ($cur =~ /^(;|{|}|\?|:|\[)/o) {
+ } elsif ($cur =~ /^(;|\?|:|\[)/o) {
print "CLOSE($1)\n" if ($dbg_values > 1);
$type = 'N';
@@ -724,28 +827,34 @@ sub possible {
my $prefix = '';
sub report {
+ if (defined $tst_only && $_[0] !~ /\Q$tst_only\E/) {
+ return 0;
+ }
my $line = $prefix . $_[0];
$line = (split('\n', $line))[0] . "\n" if ($terse);
push(our @report, $line);
+
+ return 1;
}
sub report_dump {
our @report;
}
sub ERROR {
- report("ERROR: $_[0]\n");
- our $clean = 0;
- our $cnt_error++;
+ if (report("ERROR: $_[0]\n")) {
+ our $clean = 0;
+ our $cnt_error++;
+ }
}
sub WARN {
- report("WARNING: $_[0]\n");
- our $clean = 0;
- our $cnt_warn++;
+ if (report("WARNING: $_[0]\n")) {
+ our $clean = 0;
+ our $cnt_warn++;
+ }
}
sub CHK {
- if ($check) {
- report("CHECK: $_[0]\n");
+ if ($check && report("CHECK: $_[0]\n")) {
our $clean = 0;
our $cnt_chk++;
}
@@ -787,30 +896,76 @@ sub process {
my $prev_values = 'E';
# suppression flags
- my $suppress_ifbraces = 0;
+ my %suppress_ifbraces;
# Pre-scan the patch sanitizing the lines.
# Pre-scan the patch looking for any __setup documentation.
#
my @setup_docs = ();
my $setup_docs = 0;
+
+ sanitise_line_reset();
my $line;
foreach my $rawline (@rawlines) {
- # Standardise the strings and chars within the input to
- # simplify matching.
- $line = sanitise_line($rawline);
- push(@lines, $line);
-
- ##print "==>$rawline\n";
- ##print "-->$line\n";
+ $linenr++;
+ $line = $rawline;
- if ($line=~/^\+\+\+\s+(\S+)/) {
+ if ($rawline=~/^\+\+\+\s+(\S+)/) {
$setup_docs = 0;
if ($1 =~ m@Documentation/kernel-parameters.txt$@) {
$setup_docs = 1;
}
- next;
+ #next;
+ }
+ if ($rawline=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
+ $realline=$1-1;
+ if (defined $2) {
+ $realcnt=$3+1;
+ } else {
+ $realcnt=1+1;
+ }
+
+ # Guestimate if this is a continuing comment. Run
+ # the context looking for a comment "edge". If this
+ # edge is a close comment then we must be in a comment
+ # at context start.
+ my $edge;
+ for (my $ln = $linenr; $ln < ($linenr + $realcnt); $ln++) {
+ next if ($line =~ /^-/);
+ ($edge) = ($rawlines[$ln - 1] =~ m@(/\*|\*/)@);
+ last if (defined $edge);
+ }
+ if (defined $edge && $edge eq '*/') {
+ $in_comment = 1;
+ }
+
+ # Guestimate if this is a continuing comment. If this
+ # is the start of a diff block and this line starts
+ # ' *' then it is very likely a comment.
+ if (!defined $edge &&
+ $rawlines[$linenr] =~ m@^.\s* \*(?:\s|$)@)
+ {
+ $in_comment = 1;
+ }
+
+ ##print "COMMENT:$in_comment edge<$edge> $rawline\n";
+ sanitise_line_reset($in_comment);
+
+ } elsif ($realcnt) {
+ # Standardise the strings and chars within the input to
+ # simplify matching.
+ $line = sanitise_line($rawline);
}
+ push(@lines, $line);
+
+ if ($realcnt > 1) {
+ $realcnt-- if ($line =~ /^(?:\+| |$)/);
+ } else {
+ $realcnt = 0;
+ }
+
+ #print "==>$rawline\n";
+ #print "-->$line\n";
if ($setup_docs && $line =~ /^\+/) {
push(@setup_docs, $line);
@@ -819,23 +974,17 @@ sub process {
$prefix = '';
+ $realcnt = 0;
+ $linenr = 0;
foreach my $line (@lines) {
$linenr++;
my $rawline = $rawlines[$linenr - 1];
-#extract the filename as it passes
- if ($line=~/^\+\+\+\s+(\S+)/) {
- $realfile=$1;
- $realfile =~ s@^[^/]*/@@;
- $in_comment = 0;
- next;
- }
#extract the line range in the file after the patch is applied
if ($line=~/^\@\@ -\d+(?:,\d+)? \+(\d+)(,(\d+))? \@\@/) {
$is_patch = 1;
$first_line = $linenr + 1;
- $in_comment = 0;
$realline=$1-1;
if (defined $2) {
$realcnt=$3+1;
@@ -845,50 +994,16 @@ sub process {
annotate_reset();
$prev_values = 'E';
- $suppress_ifbraces = $linenr - 1;
+ %suppress_ifbraces = ();
next;
- }
# track the line number as we move through the hunk, note that
# new versions of GNU diff omit the leading space on completely
# blank context lines so we need to count that too.
- if ($line =~ /^( |\+|$)/) {
+ } elsif ($line =~ /^( |\+|$)/) {
$realline++;
$realcnt-- if ($realcnt != 0);
- # Guestimate if this is a continuing comment. Run
- # the context looking for a comment "edge". If this
- # edge is a close comment then we must be in a comment
- # at context start.
- if ($linenr == $first_line) {
- my $edge;
- for (my $ln = $first_line; $ln < ($linenr + $realcnt); $ln++) {
- ($edge) = ($rawlines[$ln - 1] =~ m@(/\*|\*/)@);
- last if (defined $edge);
- }
- if (defined $edge && $edge eq '*/') {
- $in_comment = 1;
- }
- }
-
- # Guestimate if this is a continuing comment. If this
- # is the start of a diff block and this line starts
- # ' *' then it is very likely a comment.
- if ($linenr == $first_line and $rawline =~ m@^.\s* \*(?:\s|$)@) {
- $in_comment = 1;
- }
-
- # Find the last comment edge on _this_ line.
- $comment_edge = 0;
- while (($rawline =~ m@(/\*|\*/)@g)) {
- if ($1 eq '/*') {
- $in_comment = 1;
- } else {
- $in_comment = 0;
- }
- $comment_edge = 1;
- }
-
# Measure the line length and indent.
($length, $indent) = line_stats($rawline);
@@ -897,23 +1012,36 @@ sub process {
($previndent, $stashindent) = ($stashindent, $indent);
($prevrawline, $stashrawline) = ($stashrawline, $rawline);
- #warn "ic<$in_comment> ce<$comment_edge> line<$line>\n";
+ #warn "line<$line>\n";
} elsif ($realcnt == 1) {
$realcnt--;
}
#make up the handle for any error we report on this line
+ $prefix = "$filename:$realline: " if ($emacs && $file);
+ $prefix = "$filename:$linenr: " if ($emacs && !$file);
+
$here = "#$linenr: " if (!$file);
$here = "#$realline: " if ($file);
+
+ # extract the filename as it passes
+ if ($line=~/^\+\+\+\s+(\S+)/) {
+ $realfile = $1;
+ $realfile =~ s@^[^/]*/@@;
+
+ if ($realfile =~ m@include/asm/@) {
+ ERROR("do not modify files in include/asm, change architecture specific files in include/asm-<architecture>\n" . "$here$rawline\n");
+ }
+ next;
+ }
+
$here .= "FILE: $realfile:$realline:" if ($realcnt != 0);
my $hereline = "$here\n$rawline\n";
my $herecurr = "$here\n$rawline\n";
my $hereprev = "$here\n$prevrawline\n$rawline\n";
- $prefix = "$filename:$realline: " if ($emacs && $file);
- $prefix = "$filename:$linenr: " if ($emacs && !$file);
$cnt_lines++ if ($realcnt != 0);
#check the patch for a signoff:
@@ -925,7 +1053,7 @@ sub process {
$herecurr);
}
if ($line =~ /^\s*signed-off-by:\S/i) {
- WARN("need space after Signed-off-by:\n" .
+ WARN("space required after Signed-off-by:\n" .
$herecurr);
}
}
@@ -988,52 +1116,50 @@ sub process {
}
# check for RCS/CVS revision markers
- if ($rawline =~ /\$(Revision|Log|Id)(?:\$|)/) {
+ if ($rawline =~ /^\+.*\$(Revision|Log|Id)(?:\$|)/) {
WARN("CVS style keyword markers, these will _not_ be updated\n". $herecurr);
}
-# The rest of our checks refer specifically to C style
-# only apply those _outside_ comments. Only skip
-# lines in the middle of comments.
- next if (!$comment_edge && $in_comment);
-
# Check for potential 'bare' types
if ($realcnt) {
+ my ($s, $c) = ctx_statement_block($linenr, $realcnt, 0);
+ $s =~ s/\n./ /g;
+ $s =~ s/{.*$//;
+
# Ignore goto labels.
- if ($line =~ /$Ident:\*$/) {
+ if ($s =~ /$Ident:\*$/) {
# Ignore functions being called
- } elsif ($line =~ /^.\s*$Ident\s*\(/) {
+ } elsif ($s =~ /^.\s*$Ident\s*\(/) {
# definitions in global scope can only start with types
- } elsif ($line =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/) {
- possible($1, $line);
+ } elsif ($s =~ /^.(?:$Storage\s+)?(?:$Inline\s+)?(?:const\s+)?($Ident)\b/) {
+ possible($1, $s);
# declarations always start with types
- } elsif ($prev_values eq 'E' && $line =~ /^.\s*(?:$Storage\s+)?(?:const\s+)?($Ident)\b(:?\s+$Sparse)?\s*\**\s*$Ident\s*(?:;|=|,)/) {
- possible($1);
+ } elsif ($prev_values eq 'E' && $s =~ /^.\s*(?:$Storage\s+)?(?:const\s+)?($Ident)\b(:?\s+$Sparse)?\s*\**\s*$Ident\s*(?:;|=|,)/) {
+ possible($1, $s);
}
# any (foo ... *) is a pointer cast, and foo is a type
- while ($line =~ /\(($Ident)(?:\s+$Sparse)*\s*\*+\s*\)/g) {
- possible($1, $line);
+ while ($s =~ /\(($Ident)(?:\s+$Sparse)*\s*\*+\s*\)/g) {
+ possible($1, $s);
}
# Check for any sort of function declaration.
# int foo(something bar, other baz);
# void (*store_gdt)(x86_descr_ptr *);
- if ($prev_values eq 'E' && $line =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/) {
+ if ($prev_values eq 'E' && $s =~ /^(.(?:typedef\s*)?(?:(?:$Storage|$Inline)\s*)*\s*$Type\s*(?:\b$Ident|\(\*\s*$Ident\))\s*)\(/) {
my ($name_len) = length($1);
- my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, $name_len);
- my $ctx = join("\n", @ctx);
- $ctx =~ s/\n.//;
- substr($ctx, 0, $name_len + 1) = '';
+ my $ctx = $s;
+ substr($ctx, 0, $name_len + 1, '');
$ctx =~ s/\)[^\)]*$//;
+
for my $arg (split(/\s*,\s*/, $ctx)) {
if ($arg =~ /^(?:const\s+)?($Ident)(?:\s+$Sparse)*\s*\**\s*(:?\b$Ident)?$/ || $arg =~ /^($Ident)$/) {
- possible($1, $line);
+ possible($1, $s);
}
}
}
@@ -1068,27 +1194,33 @@ sub process {
# if/while/etc brace do not go on next line, unless defining a do while loop,
# or if that brace on the next line is for something else
- if ($line =~ /\b(?:(if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.#/) {
+ if ($line =~ /(.*)\b((?:if|while|for|switch)\s*\(|do\b|else\b)/ && $line !~ /^.#/) {
+ my $pre_ctx = "$1$2";
+
my ($level, @ctx) = ctx_statement_level($linenr, $realcnt, 0);
my $ctx_ln = $linenr + $#ctx + 1;
my $ctx_cnt = $realcnt - $#ctx - 1;
my $ctx = join("\n", @ctx);
+ ##warn "realcnt<$realcnt> ctx_cnt<$ctx_cnt>\n";
+
# Skip over any removed lines in the context following statement.
- while ($ctx_cnt > 0 && $lines[$ctx_ln - 1] =~ /^-/) {
+ while (defined($lines[$ctx_ln - 1]) && $lines[$ctx_ln - 1] =~ /^-/) {
$ctx_ln++;
- $ctx_cnt--;
}
- ##warn "line<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>";
+ ##warn "pre<$pre_ctx>\nline<$line>\nctx<$ctx>\nnext<$lines[$ctx_ln - 1]>\n";
- if ($ctx !~ /{\s*/ && $ctx_cnt > 0 && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
- ERROR("That open brace { should be on the previous line\n" .
+ if ($ctx !~ /{\s*/ && defined($lines[$ctx_ln -1]) && $lines[$ctx_ln - 1] =~ /^\+\s*{/) {
+ ERROR("that open brace { should be on the previous line\n" .
"$here\n$ctx\n$lines[$ctx_ln - 1]");
}
- if ($level == 0 && $ctx =~ /\)\s*\;\s*$/ && defined $lines[$ctx_ln - 1]) {
+ if ($level == 0 && $pre_ctx !~ /}\s*while\s*\($/ &&
+ $ctx =~ /\)\s*\;\s*$/ &&
+ defined $lines[$ctx_ln - 1])
+ {
my ($nlength, $nindent) = line_stats($lines[$ctx_ln - 1]);
if ($nindent > $indent) {
- WARN("Trailing semicolon indicates no statements, indent implies otherwise\n" .
+ WARN("trailing semicolon indicates no statements, indent implies otherwise\n" .
"$here\n$ctx\n$lines[$ctx_ln - 1]");
}
}
@@ -1100,8 +1232,8 @@ sub process {
$curr_values = $prev_values . $curr_values;
if ($dbg_values) {
my $outline = $opline; $outline =~ s/\t/ /g;
- warn "--> .$outline\n";
- warn "--> $curr_values\n";
+ print "$linenr > .$outline\n";
+ print "$linenr > $curr_values\n";
}
$prev_values = substr($curr_values, -1);
@@ -1117,7 +1249,7 @@ sub process {
# check for initialisation to aggregates open brace on the next line
if ($prevline =~ /$Declare\s*$Ident\s*=\s*$/ &&
$line =~ /^.\s*{/) {
- ERROR("That open brace { should be on the previous line\n" . $hereprev);
+ ERROR("that open brace { should be on the previous line\n" . $hereprev);
}
#
@@ -1148,7 +1280,9 @@ sub process {
if (($prevline !~ /^}/) &&
($prevline !~ /^\+}/) &&
($prevline !~ /^ }/) &&
- ($prevline !~ /\b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=)/)) {
+ ($prevline !~ /^.DECLARE_$Ident\(\Q$name\E\)/) &&
+ ($prevline !~ /^.LIST_HEAD\(\Q$name\E\)/) &&
+ ($prevline !~ /\b\Q$name\E(?:\s+$Attribute)?\s*(?:;|=|\[)/)) {
WARN("EXPORT_SYMBOL(foo); should immediately follow its function/variable\n" . $herecurr);
}
}
@@ -1240,22 +1374,31 @@ sub process {
# check for spaces between functions and their parentheses.
while ($line =~ /($Ident)\s+\(/g) {
my $name = $1;
- my $ctx = substr($line, 0, $-[1]);
+ my $ctx_before = substr($line, 0, $-[1]);
+ my $ctx = "$ctx_before$name";
# Ignore those directives where spaces _are_ permitted.
- if ($name =~ /^(?:if|for|while|switch|return|volatile|__volatile__|__attribute__|format|__extension__|Copyright|case|__asm__)$/) {
+ if ($name =~ /^(?:
+ if|for|while|switch|return|case|
+ volatile|__volatile__|
+ __attribute__|format|__extension__|
+ asm|__asm__)$/x)
+ {
# cpp #define statements have non-optional spaces, ie
# if there is a space between the name and the open
# parenthesis it is simply not a parameter group.
- } elsif ($ctx =~ /^.\#\s*define\s*$/) {
+ } elsif ($ctx_before =~ /^.\#\s*define\s*$/) {
+
+ # cpp #elif statement condition may start with a (
+ } elsif ($ctx =~ /^.\#\s*elif\s*$/) {
# If this whole things ends with a type its most
# likely a typedef for a function.
- } elsif ("$ctx$name" =~ /$Type$/) {
+ } elsif ($ctx =~ /$Type$/) {
} else {
- WARN("no space between function name and open parenthesis '('\n" . $herecurr);
+ WARN("space prohibited between function name and open parenthesis '('\n" . $herecurr);
}
}
# Check operator spacing.
@@ -1266,7 +1409,7 @@ sub process {
=>|->|<<|>>|<|>|=|!|~|
&&|\|\||,|\^|\+\+|--|&|\||\+|-|\*|\/|%
}x;
- my @elements = split(/($;+|$ops|;)/, $opline);
+ my @elements = split(/($ops|;)/, $opline);
my $off = 0;
my $blank = copy_spacing($opline);
@@ -1274,12 +1417,21 @@ sub process {
for (my $n = 0; $n < $#elements; $n += 2) {
$off += length($elements[$n]);
+ # Pick up the preceeding and succeeding characters.
+ my $ca = substr($opline, 0, $off);
+ my $cc = '';
+ if (length($opline) >= ($off + length($elements[$n + 1]))) {
+ $cc = substr($opline, $off + length($elements[$n + 1]));
+ }
+ my $cb = "$ca$;$cc";
+
my $a = '';
$a = 'V' if ($elements[$n] ne '');
$a = 'W' if ($elements[$n] =~ /\s$/);
+ $a = 'C' if ($elements[$n] =~ /$;$/);
$a = 'B' if ($elements[$n] =~ /(\[|\()$/);
$a = 'O' if ($elements[$n] eq '');
- $a = 'E' if ($elements[$n] eq '' && $n == 0);
+ $a = 'E' if ($ca =~ /^\s*$/);
my $op = $elements[$n + 1];
@@ -1287,6 +1439,7 @@ sub process {
if (defined $elements[$n + 2]) {
$c = 'V' if ($elements[$n + 2] ne '');
$c = 'W' if ($elements[$n + 2] =~ /^\s/);
+ $c = 'C' if ($elements[$n + 2] =~ /^$;/);
$c = 'B' if ($elements[$n + 2] =~ /^(\)|\]|;)/);
$c = 'O' if ($elements[$n + 2] eq '');
$c = 'E' if ($elements[$n + 2] =~ /\s*\\$/);
@@ -1294,14 +1447,6 @@ sub process {
$c = 'E';
}
- # Pick up the preceeding and succeeding characters.
- my $ca = substr($opline, 0, $off);
- my $cc = '';
- if (length($opline) >= ($off + length($elements[$n + 1]))) {
- $cc = substr($opline, $off + length($elements[$n + 1]));
- }
- my $cb = "$ca$;$cc";
-
my $ctx = "${a}x${c}";
my $at = "(ctx:$ctx)";
@@ -1330,14 +1475,14 @@ sub process {
if ($op_type ne 'V' &&
$ca =~ /\s$/ && $cc =~ /^\s*,/) {
- # Ignore comments
- } elsif ($op =~ /^$;+$/) {
+# # Ignore comments
+# } elsif ($op =~ /^$;+$/) {
# ; should have either the end of line or a space or \ after it
} elsif ($op eq ';') {
- if ($ctx !~ /.x[WEB]/ && $cc !~ /^\\/ &&
- $cc !~ /^;/) {
- ERROR("need space after that '$op' $at\n" . $hereptr);
+ if ($ctx !~ /.x[WEBC]/ &&
+ $cc !~ /^\\/ && $cc !~ /^;/) {
+ ERROR("space required after that '$op' $at\n" . $hereptr);
}
# // is a comment
@@ -1346,13 +1491,13 @@ sub process {
# -> should have no spaces
} elsif ($op eq '->') {
if ($ctx =~ /Wx.|.xW/) {
- ERROR("no spaces around that '$op' $at\n" . $hereptr);
+ ERROR("spaces prohibited around that '$op' $at\n" . $hereptr);
}
# , must have a space on the right.
} elsif ($op eq ',') {
- if ($ctx !~ /.xW|.xE/ && $cc !~ /^}/) {
- ERROR("need space after that '$op' $at\n" . $hereptr);
+ if ($ctx !~ /.x[WEC]/ && $cc !~ /^}/) {
+ ERROR("space required after that '$op' $at\n" . $hereptr);
}
# '*' as part of a type definition -- reported already.
@@ -1364,21 +1509,26 @@ sub process {
# unary operator, or a cast
} elsif ($op eq '!' || $op eq '~' ||
($is_unary && ($op eq '*' || $op eq '-' || $op eq '&'))) {
- if ($ctx !~ /[WEB]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
- ERROR("need space before that '$op' $at\n" . $hereptr);
+ if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
+ ERROR("space required before that '$op' $at\n" . $hereptr);
}
if ($ctx =~ /.xW/) {
- ERROR("no space after that '$op' $at\n" . $hereptr);
+ ERROR("space prohibited after that '$op' $at\n" . $hereptr);
}
# unary ++ and unary -- are allowed no space on one side.
} elsif ($op eq '++' or $op eq '--') {
- if ($ctx !~ /[WOB]x[^W]/ && $ctx !~ /[^W]x[WOBE]/) {
- ERROR("need space one side of that '$op' $at\n" . $hereptr);
+ if ($ctx !~ /[WEOBC]x[^W]/ && $ctx !~ /[^W]x[WOBEC]/) {
+ ERROR("space required one side of that '$op' $at\n" . $hereptr);
}
- if ($ctx =~ /WxB/ || ($ctx =~ /Wx./ && $cc =~ /^;/)) {
- ERROR("no space before that '$op' $at\n" . $hereptr);
+ if ($ctx =~ /Wx[BE]/ ||
+ ($ctx =~ /Wx./ && $cc =~ /^;/)) {
+ ERROR("space prohibited before that '$op' $at\n" . $hereptr);
}
+ if ($ctx =~ /ExW/) {
+ ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+ }
+
# << and >> may either have or not have spaces both sides
} elsif ($op eq '<<' or $op eq '>>' or
@@ -1387,17 +1537,17 @@ sub process {
$op eq '*' or $op eq '/' or
$op eq '%')
{
- if ($ctx !~ /VxV|WxW|VxE|WxE|VxO/) {
+ if ($ctx =~ /Wx[^WCE]|[^WCE]xW/) {
ERROR("need consistent spacing around '$op' $at\n" .
$hereptr);
}
# All the others need spaces both sides.
- } elsif ($ctx !~ /[EW]x[WE]/) {
+ } elsif ($ctx !~ /[EWC]x[CWE]/) {
# Ignore email addresses <foo@bar>
if (!($op eq '<' && $cb =~ /$;\S+\@\S+>/) &&
!($op eq '>' && $cb =~ /<\S+\@\S+$;/)) {
- ERROR("need spaces around that '$op' $at\n" . $hereptr);
+ ERROR("spaces required around that '$op' $at\n" . $hereptr);
}
}
$off += length($elements[$n + 1]);
@@ -1427,31 +1577,31 @@ sub process {
#need space before brace following if, while, etc
if (($line =~ /\(.*\){/ && $line !~ /\($Type\){/) ||
$line =~ /do{/) {
- ERROR("need a space before the open brace '{'\n" . $herecurr);
+ ERROR("space required before the open brace '{'\n" . $herecurr);
}
# closing brace should have a space following it when it has anything
# on the line
if ($line =~ /}(?!(?:,|;|\)))\S/) {
- ERROR("need a space after that close brace '}'\n" . $herecurr);
+ ERROR("space required after that close brace '}'\n" . $herecurr);
}
# check spacing on square brackets
if ($line =~ /\[\s/ && $line !~ /\[\s*$/) {
- ERROR("no space after that open square bracket '['\n" . $herecurr);
+ ERROR("space prohibited after that open square bracket '['\n" . $herecurr);
}
if ($line =~ /\s\]/) {
- ERROR("no space before that close square bracket ']'\n" . $herecurr);
+ ERROR("space prohibited before that close square bracket ']'\n" . $herecurr);
}
# check spacing on paretheses
if ($line =~ /\(\s/ && $line !~ /\(\s*(?:\\)?$/ &&
$line !~ /for\s*\(\s+;/) {
- ERROR("no space after that open parenthesis '('\n" . $herecurr);
+ ERROR("space prohibited after that open parenthesis '('\n" . $herecurr);
}
if ($line =~ /(\s+)\)/ && $line !~ /^.\s*\)/ &&
$line !~ /for\s*\(.*;\s+\)/) {
- ERROR("no space before that close parenthesis ')'\n" . $herecurr);
+ ERROR("space prohibited before that close parenthesis ')'\n" . $herecurr);
}
#goto labels aren't indented, allow a single space however
@@ -1462,7 +1612,7 @@ sub process {
# Need a space before open parenthesis after if, while etc
if ($line=~/\b(if|while|for|switch)\(/) {
- ERROR("need a space before the open parenthesis '('\n" . $herecurr);
+ ERROR("space required before the open parenthesis '('\n" . $herecurr);
}
# Check for illegal assignment in if conditional.
@@ -1475,10 +1625,12 @@ sub process {
# Find out what is on the end of the line after the
# conditional.
- substr($s, 0, length($c)) = '';
+ substr($s, 0, length($c), '');
$s =~ s/\n.*//g;
$s =~ s/$;//g; # Remove any comments
- if (length($c) && $s !~ /^\s*({|;|)\s*\\*\s*$/) {
+ if (length($c) && $s !~ /^\s*({|;|)\s*\\*\s*$/ &&
+ $c !~ /^.\#\s*if/)
+ {
ERROR("trailing statements should be on next line\n" . $herecurr);
}
}
@@ -1520,7 +1672,7 @@ sub process {
# Find out what is on the end of the line after the
# conditional.
- substr($s, 0, length($c)) = '';
+ substr($s, 0, length($c), '');
$s =~ s/\n.*//g;
if ($s =~ /^\s*;/) {
@@ -1544,14 +1696,14 @@ sub process {
if ($tree && $rawline =~ m{^.\#\s*include\s*\<asm\/(.*)\.h\>}) {
my $checkfile = "$root/include/linux/$1.h";
if (-f $checkfile && $1 ne 'irq.h') {
- CHK("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
+ WARN("Use #include <linux/$1.h> instead of <asm/$1.h>\n" .
$herecurr);
}
}
# multi-statement macros should be enclosed in a do while loop, grab the
# first statement and ensure its the whole macro if its not enclosed
-# in a known goot container
+# in a known good container
if ($prevline =~ /\#define.*\\/ &&
$prevline !~/(?:do\s+{|\(\{|\{)/ &&
$line !~ /(?:do\s+{|\(\{|\{)/ &&
@@ -1599,84 +1751,103 @@ sub process {
# check for redundant bracing round if etc
if ($line =~ /(^.*)\bif\b/ && $1 !~ /else\s*$/) {
my ($level, $endln, @chunks) =
- ctx_statement_full($linenr, $realcnt, 0);
+ ctx_statement_full($linenr, $realcnt, 1);
#print "chunks<$#chunks> linenr<$linenr> endln<$endln> level<$level>\n";
- if ($#chunks > 1 && $level == 0) {
+ #print "APW: <<$chunks[1][0]>><<$chunks[1][1]>>\n";
+ if ($#chunks > 0 && $level == 0) {
my $allowed = 0;
my $seen = 0;
+ my $herectx = $here . "\n";
+ my $ln = $linenr - 1;
for my $chunk (@chunks) {
my ($cond, $block) = @{$chunk};
- substr($block, 0, length($cond)) = '';
+ # If the condition carries leading newlines, then count those as offsets.
+ my ($whitespace) = ($cond =~ /^((?:\s*\n[+-])*\s*)/s);
+ my $offset = statement_rawlines($whitespace) - 1;
- $seen++ if ($block =~ /^\s*{/);
+ #print "COND<$cond> whitespace<$whitespace> offset<$offset>\n";
- $block =~ s/(^|\n)./$1/g;
- $block =~ s/^\s*{//;
- $block =~ s/}\s*$//;
- $block =~ s/^\s*//;
- $block =~ s/\s*$//;
+ # We have looked at and allowed this specific line.
+ $suppress_ifbraces{$ln + $offset} = 1;
- my @lines = ($block =~ /\n/g);
- my @statements = ($block =~ /;/g);
+ $herectx .= "$rawlines[$ln + $offset]\n[...]\n";
+ $ln += statement_rawlines($block) - 1;
- #print "cond<$cond> block<$block> lines<" . scalar(@lines) . "> statements<" . scalar(@statements) . "> seen<$seen> allowed<$allowed>\n";
- if (scalar(@lines) != 0) {
+ substr($block, 0, length($cond), '');
+
+ $seen++ if ($block =~ /^\s*{/);
+
+ #print "cond<$cond> block<$block> allowed<$allowed>\n";
+ if (statement_lines($cond) > 1) {
+ #print "APW: ALLOWED: cond<$cond>\n";
$allowed = 1;
}
if ($block =~/\b(?:if|for|while)\b/) {
+ #print "APW: ALLOWED: block<$block>\n";
$allowed = 1;
}
- if (scalar(@statements) > 1) {
+ if (statement_block_size($block) > 1) {
+ #print "APW: ALLOWED: lines block<$block>\n";
$allowed = 1;
}
}
if ($seen && !$allowed) {
- WARN("braces {} are not necessary for any arm of this statement\n" . $herecurr);
- $suppress_ifbraces = $endln;
+ WARN("braces {} are not necessary for any arm of this statement\n" . $herectx);
}
}
}
- if ($linenr > $suppress_ifbraces &&
+ if (!defined $suppress_ifbraces{$linenr - 1} &&
$line =~ /\b(if|while|for|else)\b/) {
- # Locate the end of the opening statement.
- my @control = ctx_statement($linenr, $realcnt, 0);
- my $nr = $linenr + (scalar(@control) - 1);
- my $cnt = $realcnt - (scalar(@control) - 1);
-
- my $off = $realcnt - $cnt;
- #print "$off: line<$line>end<" . $lines[$nr - 1] . ">\n";
-
- # If this is is a braced statement group check it
- if ($lines[$nr - 1] =~ /{\s*$/) {
- my ($lvl, @block) = ctx_block_level($nr, $cnt);
-
- my $stmt = join("\n", @block);
- # Drop the diff line leader.
- $stmt =~ s/\n./\n/g;
- # Drop the code outside the block.
- $stmt =~ s/(^[^{]*){\s*//;
- my $before = $1;
- $stmt =~ s/\s*}([^}]*$)//;
- my $after = $1;
-
- #print "block<" . join(' ', @block) . "><" . scalar(@block) . ">\n";
- #print "before<$before> stmt<$stmt> after<$after>\n\n";
-
- # Count the newlines, if there is only one
- # then the block should not have {}'s.
- my @lines = ($stmt =~ /\n/g);
- my @statements = ($stmt =~ /;/g);
- #print "lines<" . scalar(@lines) . ">\n";
- #print "statements<" . scalar(@statements) . ">\n";
- if ($lvl == 0 && scalar(@lines) == 0 &&
- scalar(@statements) < 2 &&
- $stmt !~ /{/ && $stmt !~ /\bif\b/ &&
- $before !~ /}/ && $after !~ /{/) {
- my $herectx = "$here\n" . join("\n", @control, @block[1 .. $#block]) . "\n";
- shift(@block);
- WARN("braces {} are not necessary for single statement blocks\n" . $herectx);
+ my $allowed = 0;
+
+ # Check the pre-context.
+ if (substr($line, 0, $-[0]) =~ /(\}\s*)$/) {
+ #print "APW: ALLOWED: pre<$1>\n";
+ $allowed = 1;
+ }
+
+ my ($level, $endln, @chunks) =
+ ctx_statement_full($linenr, $realcnt, $-[0]);
+
+ # Check the condition.
+ my ($cond, $block) = @{$chunks[0]};
+ #print "CHECKING<$linenr> cond<$cond> block<$block>\n";
+ if (defined $cond) {
+ substr($block, 0, length($cond), '');
+ }
+ if (statement_lines($cond) > 1) {
+ #print "APW: ALLOWED: cond<$cond>\n";
+ $allowed = 1;
+ }
+ if ($block =~/\b(?:if|for|while)\b/) {
+ #print "APW: ALLOWED: block<$block>\n";
+ $allowed = 1;
+ }
+ if (statement_block_size($block) > 1) {
+ #print "APW: ALLOWED: lines block<$block>\n";
+ $allowed = 1;
+ }
+ # Check the post-context.
+ if (defined $chunks[1]) {
+ my ($cond, $block) = @{$chunks[1]};
+ if (defined $cond) {
+ substr($block, 0, length($cond), '');
}
+ if ($block =~ /^\s*\{/) {
+ #print "APW: ALLOWED: chunk-1 block<$block>\n";
+ $allowed = 1;
+ }
+ }
+ if ($level == 0 && $block =~ /^\s*\{/ && !$allowed) {
+ my $herectx = $here . "\n";;
+ my $end = $linenr + statement_rawlines($block) - 1;
+
+ for (my $ln = $linenr - 1; $ln < $end; $ln++) {
+ $herectx .= $rawlines[$ln] . "\n";;
+ }
+
+ WARN("braces {} are not necessary for single statement blocks\n" . $herectx);
}
}
@@ -1784,6 +1955,28 @@ sub process {
if ($line =~ /__FUNCTION__/) {
WARN("__func__ should be used instead of gcc specific __FUNCTION__\n" . $herecurr);
}
+
+# check for semaphores used as mutexes
+ if ($line =~ /\b(DECLARE_MUTEX|init_MUTEX)\s*\(/) {
+ WARN("mutexes are preferred for single holder semaphores\n" . $herecurr);
+ }
+# check for semaphores used as mutexes
+ if ($line =~ /\binit_MUTEX_LOCKED\s*\(/) {
+ WARN("consider using a completion\n" . $herecurr);
+ }
+# recommend strict_strto* over simple_strto*
+ if ($line =~ /\bsimple_(strto.*?)\s*\(/) {
+ WARN("consider using strict_$1 in preference to simple_$1\n" . $herecurr);
+ }
+
+# use of NR_CPUS is usually wrong
+# ignore definitions of NR_CPUS and usage to define arrays as likely right
+ if ($line =~ /\bNR_CPUS\b/ &&
+ $line !~ /^.#\s*define\s+NR_CPUS\s+/ &&
+ $line !~ /^.\s*$Declare\s.*\[[^\]]*NR_CPUS[^\]]*\]/)
+ {
+ WARN("usage of NR_CPUS is often wrong - consider using cpu_possible(), num_possible_cpus(), for_each_possible_cpu(), etc\n" . $herecurr);
+ }
}
# If we have no input at all, then there is nothing to report on
@@ -1828,15 +2021,6 @@ sub process {
print "are false positives report them to the maintainer, see\n";
print "CHECKPATCH in MAINTAINERS.\n";
}
- print <<EOL if ($file == 1 && $quiet == 0);
-
-WARNING: Using --file mode. Please do not send patches to linux-kernel
-that change whole existing files if you did not significantly change most
-of the the file for other reasons anyways or just wrote the file newly
-from scratch. Pure code style patches have a significant cost in a
-quickly changing code base like Linux because they cause rejects
-with other changes.
-EOL
return $clean;
}
diff --git a/v4l/versions.txt b/v4l/versions.txt
index 221f4f547..9a1dc6698 100644
--- a/v4l/versions.txt
+++ b/v4l/versions.txt
@@ -127,6 +127,7 @@ VIDEO_UPD64031A
VIDEO_UPD64083
VIDEO_IVTV
VIDEO_EM28XX
+VIDEO_AU0828
DVB
DVB_CORE
DVB_AV7110
@@ -201,6 +202,8 @@ DVB_TUNER_MT2060
DVB_TUNER_MT2131
DVB_TDA827X
DVB_TDA18271
+DVB_AU8522
+DVB_TDA10048
VIDEO_SAA7146
VIDEO_SAA7146_VV
VIDEO_TUNER