summaryrefslogtreecommitdiff
path: root/linux
diff options
context:
space:
mode:
authorMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:56:50 -0300
committerMauro Carvalho Chehab <mchehab@redhat.com>2009-09-18 23:56:50 -0300
commit034d0acc1b03bd1d68b729ea719978961628dd2a (patch)
tree37d1972d39ab6a125e483ae293f8f205303c6921 /linux
parent6d20e235949a06a88588f8fcc0bcddce7e3a2924 (diff)
parent7921b528872c180d255e21140cd54502dda70a7a (diff)
downloadmediapointer-dvb-s2-034d0acc1b03bd1d68b729ea719978961628dd2a.tar.gz
mediapointer-dvb-s2-034d0acc1b03bd1d68b729ea719978961628dd2a.tar.bz2
merge: http://www.linuxtv.org/hg/~dougsland/v4l-dvb
From: Mauro Carvalho Chehab <mchehab@redhat.com> Signed-off-by: Mauro Carvalho Chehab <mchehab@redhat.com>
Diffstat (limited to 'linux')
-rw-r--r--linux/Documentation/DocBook/Makefile8
-rw-r--r--linux/Documentation/video4linux/CARDLIST.saa71341
-rw-r--r--linux/arch/arm/mach-mx1/devices.c87
-rw-r--r--linux/arch/arm/mach-mx3/clock.c22
-rw-r--r--linux/arch/arm/plat-mxc/include/mach/memory.h4
-rw-r--r--linux/drivers/media/dvb/Kconfig4
-rw-r--r--linux/drivers/media/dvb/Makefile2
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.c8
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_frontend.h3
-rw-r--r--linux/drivers/media/dvb/dvb-core/dvb_net.c2
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Kconfig6
-rw-r--r--linux/drivers/media/dvb/dvb-usb/Makefile3
-rw-r--r--linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h2
-rw-r--r--linux/drivers/media/dvb/dvb-usb/friio-fe.c483
-rw-r--r--linux/drivers/media/dvb/dvb-usb/friio.c528
-rw-r--r--linux/drivers/media/dvb/dvb-usb/friio.h99
-rw-r--r--linux/drivers/media/dvb/pt1/Kconfig12
-rw-r--r--linux/drivers/media/dvb/pt1/Makefile5
-rw-r--r--linux/drivers/media/dvb/pt1/pt1.c1056
-rw-r--r--linux/drivers/media/dvb/pt1/va1j5jf8007s.c658
-rw-r--r--linux/drivers/media/dvb/pt1/va1j5jf8007s.h40
-rw-r--r--linux/drivers/media/dvb/pt1/va1j5jf8007t.c468
-rw-r--r--linux/drivers/media/dvb/pt1/va1j5jf8007t.h40
-rw-r--r--linux/drivers/media/video/et61x251/et61x251_core.c6
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx.c19
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c151
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h2
-rw-r--r--linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c15
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-cards.c27
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-dvb.c29
-rw-r--r--linux/drivers/media/video/saa7134/saa7134-input.c4
-rw-r--r--linux/drivers/media/video/saa7134/saa7134.h1
-rw-r--r--linux/drivers/media/video/sn9c102/sn9c102_core.c6
-rw-r--r--linux/drivers/media/video/v4l2-device.c2
-rw-r--r--linux/drivers/media/video/zc0301/zc0301_core.c6
-rw-r--r--linux/drivers/staging/cx25821/Makefile1
-rw-r--r--linux/include/linux/dvb/frontend.h4
-rw-r--r--linux/include/linux/mmc/sdio_ids.h6
-rw-r--r--linux/linux/drivers/staging/tm6000/tm6000-alsa.c0
39 files changed, 3661 insertions, 159 deletions
diff --git a/linux/Documentation/DocBook/Makefile b/linux/Documentation/DocBook/Makefile
index ad07875fe..ab8300f67 100644
--- a/linux/Documentation/DocBook/Makefile
+++ b/linux/Documentation/DocBook/Makefile
@@ -32,7 +32,7 @@ PS_METHOD = $(prefer-db2x)
###
# The targets that may be used.
-PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs
+PHONY += xmldocs sgmldocs psdocs pdfdocs htmldocs mandocs installmandocs cleandocs media
BOOKS := $(addprefix $(obj)/,$(DOCBOOKS))
xmldocs: $(BOOKS)
@@ -45,12 +45,16 @@ PDF := $(patsubst %.xml, %.pdf, $(BOOKS))
pdfdocs: $(PDF)
HTML := $(sort $(patsubst %.xml, %.html, $(BOOKS)))
-htmldocs: $(HTML)
+htmldocs: media $(HTML)
$(call build_main_index)
MAN := $(patsubst %.xml, %.9, $(BOOKS))
mandocs: $(MAN)
+media:
+ mkdir -p $(srctree)/Documentation/DocBook/media/
+ cp $(srctree)/Documentation/DocBook/dvb/*.png $(srctree)/Documentation/DocBook/v4l/*.gif $(srctree)/Documentation/DocBook/media/
+
installmandocs: mandocs
mkdir -p /usr/local/man/man9/
install Documentation/DocBook/man/*.9.gz /usr/local/man/man9/
diff --git a/linux/Documentation/video4linux/CARDLIST.saa7134 b/linux/Documentation/video4linux/CARDLIST.saa7134
index 0ac4d2544..2620d6034 100644
--- a/linux/Documentation/video4linux/CARDLIST.saa7134
+++ b/linux/Documentation/video4linux/CARDLIST.saa7134
@@ -171,3 +171,4 @@
170 -> AverMedia AverTV Studio 505 [1461:a115]
171 -> Beholder BeholdTV X7 [5ace:7595]
172 -> RoverMedia TV Link Pro FM [19d1:0138]
+173 -> Zolid Hybrid TV Tuner PCI [1131:2004]
diff --git a/linux/arch/arm/mach-mx1/devices.c b/linux/arch/arm/mach-mx1/devices.c
index 76d1ffb48..b6be29d1c 100644
--- a/linux/arch/arm/mach-mx1/devices.c
+++ b/linux/arch/arm/mach-mx1/devices.c
@@ -29,12 +29,11 @@
#include "devices.h"
static struct resource imx_csi_resources[] = {
- [0] = {
+ {
.start = 0x00224000,
.end = 0x00224010,
.flags = IORESOURCE_MEM,
- },
- [1] = {
+ }, {
.start = CSI_INT,
.end = CSI_INT,
.flags = IORESOURCE_IRQ,
@@ -55,12 +54,11 @@ struct platform_device imx_csi_device = {
};
static struct resource imx_i2c_resources[] = {
- [0] = {
+ {
.start = 0x00217000,
.end = 0x00217010,
.flags = IORESOURCE_MEM,
- },
- [1] = {
+ }, {
.start = I2C_INT,
.end = I2C_INT,
.flags = IORESOURCE_IRQ,
@@ -75,22 +73,19 @@ struct platform_device imx_i2c_device = {
};
static struct resource imx_uart1_resources[] = {
- [0] = {
+ {
.start = UART1_BASE_ADDR,
.end = UART1_BASE_ADDR + 0xD0,
.flags = IORESOURCE_MEM,
- },
- [1] = {
+ }, {
.start = UART1_MINT_RX,
.end = UART1_MINT_RX,
.flags = IORESOURCE_IRQ,
- },
- [2] = {
+ }, {
.start = UART1_MINT_TX,
.end = UART1_MINT_TX,
.flags = IORESOURCE_IRQ,
- },
- [3] = {
+ }, {
.start = UART1_MINT_RTS,
.end = UART1_MINT_RTS,
.flags = IORESOURCE_IRQ,
@@ -105,22 +100,19 @@ struct platform_device imx_uart1_device = {
};
static struct resource imx_uart2_resources[] = {
- [0] = {
+ {
.start = UART2_BASE_ADDR,
.end = UART2_BASE_ADDR + 0xD0,
.flags = IORESOURCE_MEM,
- },
- [1] = {
+ }, {
.start = UART2_MINT_RX,
.end = UART2_MINT_RX,
.flags = IORESOURCE_IRQ,
- },
- [2] = {
+ }, {
.start = UART2_MINT_TX,
.end = UART2_MINT_TX,
.flags = IORESOURCE_IRQ,
- },
- [3] = {
+ }, {
.start = UART2_MINT_RTS,
.end = UART2_MINT_RTS,
.flags = IORESOURCE_IRQ,
@@ -135,17 +127,15 @@ struct platform_device imx_uart2_device = {
};
static struct resource imx_rtc_resources[] = {
- [0] = {
+ {
.start = 0x00204000,
.end = 0x00204024,
.flags = IORESOURCE_MEM,
- },
- [1] = {
+ }, {
.start = RTC_INT,
.end = RTC_INT,
.flags = IORESOURCE_IRQ,
- },
- [2] = {
+ }, {
.start = RTC_SAMINT,
.end = RTC_SAMINT,
.flags = IORESOURCE_IRQ,
@@ -160,12 +150,11 @@ struct platform_device imx_rtc_device = {
};
static struct resource imx_wdt_resources[] = {
- [0] = {
+ {
.start = 0x00201000,
.end = 0x00201008,
.flags = IORESOURCE_MEM,
- },
- [1] = {
+ }, {
.start = WDT_INT,
.end = WDT_INT,
.flags = IORESOURCE_IRQ,
@@ -180,42 +169,35 @@ struct platform_device imx_wdt_device = {
};
static struct resource imx_usb_resources[] = {
- [0] = {
+ {
.start = 0x00212000,
.end = 0x00212148,
.flags = IORESOURCE_MEM,
- },
- [1] = {
+ }, {
.start = USBD_INT0,
.end = USBD_INT0,
.flags = IORESOURCE_IRQ,
- },
- [2] = {
+ }, {
.start = USBD_INT1,
.end = USBD_INT1,
.flags = IORESOURCE_IRQ,
- },
- [3] = {
+ }, {
.start = USBD_INT2,
.end = USBD_INT2,
.flags = IORESOURCE_IRQ,
- },
- [4] = {
+ }, {
.start = USBD_INT3,
.end = USBD_INT3,
.flags = IORESOURCE_IRQ,
- },
- [5] = {
+ }, {
.start = USBD_INT4,
.end = USBD_INT4,
.flags = IORESOURCE_IRQ,
- },
- [6] = {
+ }, {
.start = USBD_INT5,
.end = USBD_INT5,
.flags = IORESOURCE_IRQ,
- },
- [7] = {
+ }, {
.start = USBD_INT6,
.end = USBD_INT6,
.flags = IORESOURCE_IRQ,
@@ -231,29 +213,26 @@ struct platform_device imx_usb_device = {
/* GPIO port description */
static struct mxc_gpio_port imx_gpio_ports[] = {
- [0] = {
+ {
.chip.label = "gpio-0",
.base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR),
.irq = GPIO_INT_PORTA,
- .virtual_irq_start = MXC_GPIO_IRQ_START
- },
- [1] = {
+ .virtual_irq_start = MXC_GPIO_IRQ_START,
+ }, {
.chip.label = "gpio-1",
.base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x100),
.irq = GPIO_INT_PORTB,
- .virtual_irq_start = MXC_GPIO_IRQ_START + 32
- },
- [2] = {
+ .virtual_irq_start = MXC_GPIO_IRQ_START + 32,
+ }, {
.chip.label = "gpio-2",
.base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x200),
.irq = GPIO_INT_PORTC,
- .virtual_irq_start = MXC_GPIO_IRQ_START + 64
- },
- [3] = {
+ .virtual_irq_start = MXC_GPIO_IRQ_START + 64,
+ }, {
.chip.label = "gpio-3",
.base = (void __iomem *)IO_ADDRESS(GPIO_BASE_ADDR + 0x300),
.irq = GPIO_INT_PORTD,
- .virtual_irq_start = MXC_GPIO_IRQ_START + 96
+ .virtual_irq_start = MXC_GPIO_IRQ_START + 96,
}
};
diff --git a/linux/arch/arm/mach-mx3/clock.c b/linux/arch/arm/mach-mx3/clock.c
index 8b1423972..06bd6180b 100644
--- a/linux/arch/arm/mach-mx3/clock.c
+++ b/linux/arch/arm/mach-mx3/clock.c
@@ -29,6 +29,7 @@
#include <mach/clock.h>
#include <mach/hardware.h>
+#include <mach/mx31.h>
#include <mach/common.h>
#include "crm_regs.h"
@@ -402,6 +403,11 @@ static unsigned long clk_ckih_get_rate(struct clk *clk)
return ckih_rate;
}
+static unsigned long clk_ckil_get_rate(struct clk *clk)
+{
+ return CKIL_CLK_FREQ;
+}
+
static struct clk ckih_clk = {
.get_rate = clk_ckih_get_rate,
};
@@ -508,6 +514,7 @@ DEFINE_CLOCK(usb_clk1, 0, NULL, 0, usb_get_rate, NULL, &usb_pll_clk)
DEFINE_CLOCK(nfc_clk, 0, NULL, 0, nfc_get_rate, NULL, &ahb_clk);
DEFINE_CLOCK(scc_clk, 0, NULL, 0, NULL, NULL, &ipg_clk);
DEFINE_CLOCK(ipg_clk, 0, NULL, 0, ipg_get_rate, NULL, &ahb_clk);
+DEFINE_CLOCK(ckil_clk, 0, NULL, 0, clk_ckil_get_rate, NULL, NULL);
#define _REGISTER_CLOCK(d, n, c) \
{ \
@@ -518,9 +525,9 @@ DEFINE_CLOCK(ipg_clk, 0, NULL, 0, ipg_get_rate, NULL, &ahb_clk);
static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, "emi", emi_clk)
- _REGISTER_CLOCK(NULL, "cspi", cspi1_clk)
- _REGISTER_CLOCK(NULL, "cspi", cspi2_clk)
- _REGISTER_CLOCK(NULL, "cspi", cspi3_clk)
+ _REGISTER_CLOCK("spi_imx.0", NULL, cspi1_clk)
+ _REGISTER_CLOCK("spi_imx.1", NULL, cspi2_clk)
+ _REGISTER_CLOCK("spi_imx.2", NULL, cspi3_clk)
_REGISTER_CLOCK(NULL, "gpt", gpt_clk)
_REGISTER_CLOCK(NULL, "pwm", pwm_clk)
_REGISTER_CLOCK(NULL, "wdog", wdog_clk)
@@ -531,6 +538,12 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK("ipu-core", NULL, ipu_clk)
_REGISTER_CLOCK("mx3_sdc_fb", NULL, ipu_clk)
_REGISTER_CLOCK(NULL, "kpp", kpp_clk)
+ _REGISTER_CLOCK("mxc-ehci.0", "usb", usb_clk1)
+ _REGISTER_CLOCK("mxc-ehci.0", "usb_ahb", usb_clk2)
+ _REGISTER_CLOCK("mxc-ehci.1", "usb", usb_clk1)
+ _REGISTER_CLOCK("mxc-ehci.1", "usb_ahb", usb_clk2)
+ _REGISTER_CLOCK("mxc-ehci.2", "usb", usb_clk1)
+ _REGISTER_CLOCK("mxc-ehci.2", "usb_ahb", usb_clk2)
_REGISTER_CLOCK("fsl-usb2-udc", "usb", usb_clk1)
_REGISTER_CLOCK("fsl-usb2-udc", "usb_ahb", usb_clk2)
_REGISTER_CLOCK("mx3-camera.0", NULL, csi_clk)
@@ -559,6 +572,7 @@ static struct clk_lookup lookups[] = {
_REGISTER_CLOCK(NULL, "iim", iim_clk)
_REGISTER_CLOCK(NULL, "mpeg4", mpeg4_clk)
_REGISTER_CLOCK(NULL, "mbx", mbx_clk)
+ _REGISTER_CLOCK("mxc_rtc", NULL, ckil_clk)
};
int __init mx31_clocks_init(unsigned long fref)
@@ -609,7 +623,7 @@ int __init mx31_clocks_init(unsigned long fref)
__raw_writel(reg, MXC_CCM_PMCR1);
}
- mxc_timer_init(&ipg_clk);
+ mxc_timer_init(&ipg_clk, IO_ADDRESS(GPT1_BASE_ADDR), MXC_INT_GPT);
return 0;
}
diff --git a/linux/arch/arm/plat-mxc/include/mach/memory.h b/linux/arch/arm/plat-mxc/include/mach/memory.h
index 6065e0017..d3afafdcc 100644
--- a/linux/arch/arm/plat-mxc/include/mach/memory.h
+++ b/linux/arch/arm/plat-mxc/include/mach/memory.h
@@ -22,6 +22,10 @@
#endif
#elif defined CONFIG_ARCH_MX3
#define PHYS_OFFSET UL(0x80000000)
+#elif defined CONFIG_ARCH_MX25
+#define PHYS_OFFSET UL(0x80000000)
+#elif defined CONFIG_ARCH_MXC91231
+#define PHYS_OFFSET UL(0x90000000)
#endif
#if defined(CONFIG_MX1_VIDEO)
diff --git a/linux/drivers/media/dvb/Kconfig b/linux/drivers/media/dvb/Kconfig
index 1d0e4b1ef..35d081712 100644
--- a/linux/drivers/media/dvb/Kconfig
+++ b/linux/drivers/media/dvb/Kconfig
@@ -68,6 +68,10 @@ comment "Supported FireWire (IEEE 1394) Adapters"
depends on DVB_CORE && IEEE1394
source "drivers/media/dvb/firewire/Kconfig"
+comment "Supported Earthsoft PT1 Adapters"
+ depends on DVB_CORE && PCI && I2C
+source "drivers/media/dvb/pt1/Kconfig"
+
comment "Supported DVB Frontends"
depends on DVB_CORE
source "drivers/media/dvb/frontends/Kconfig"
diff --git a/linux/drivers/media/dvb/Makefile b/linux/drivers/media/dvb/Makefile
index 6092a5bb5..16d262ddb 100644
--- a/linux/drivers/media/dvb/Makefile
+++ b/linux/drivers/media/dvb/Makefile
@@ -2,6 +2,6 @@
# Makefile for the kernel multimedia device drivers.
#
-obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
+obj-y := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/ pt1/
obj-$(CONFIG_DVB_FIREDTV) += firewire/
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
index 2409586d3..b1a481ed3 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.c
@@ -1042,6 +1042,8 @@ static struct dtv_cmds_h dtv_cmds[] = {
_DTV_CMD(DTV_ISDBT_LAYERC_SEGMENT_COUNT, 0, 0),
_DTV_CMD(DTV_ISDBT_LAYERC_TIME_INTERLEAVING, 0, 0),
+ _DTV_CMD(DTV_ISDBS_TS_ID, 1, 0),
+
/* Get */
[DTV_DISEQC_SLAVE_REPLY] = {
.name = "DTV_DISEQC_SLAVE_REPLY",
@@ -1431,6 +1433,9 @@ static int dtv_property_process_get(struct dvb_frontend *fe,
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
tvp->u.data = fe->dtv_property_cache.layer[2].interleaving;
break;
+ case DTV_ISDBS_TS_ID:
+ tvp->u.data = fe->dtv_property_cache.isdbs_ts_id;
+ break;
default:
r = -1;
}
@@ -1582,6 +1587,9 @@ static int dtv_property_process_set(struct dvb_frontend *fe,
case DTV_ISDBT_LAYERC_TIME_INTERLEAVING:
fe->dtv_property_cache.layer[2].interleaving = tvp->u.data;
break;
+ case DTV_ISDBS_TS_ID:
+ fe->dtv_property_cache.isdbs_ts_id = tvp->u.data;
+ break;
default:
r = -1;
}
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
index 9e46f1772..810f07d63 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
+++ b/linux/drivers/media/dvb/dvb-core/dvb_frontend.h
@@ -355,6 +355,9 @@ struct dtv_frontend_properties {
fe_modulation_t modulation;
u8 interleaving;
} layer[3];
+
+ /* ISDB-T specifics */
+ u32 isdbs_ts_id;
};
struct dvb_frontend {
diff --git a/linux/drivers/media/dvb/dvb-core/dvb_net.c b/linux/drivers/media/dvb/dvb-core/dvb_net.c
index 1eede48a9..d2d33cda9 100644
--- a/linux/drivers/media/dvb/dvb-core/dvb_net.c
+++ b/linux/drivers/media/dvb/dvb-core/dvb_net.c
@@ -971,7 +971,7 @@ static int dvb_net_sec_callback(const u8 *buffer1, size_t buffer1_len,
static int dvb_net_tx(struct sk_buff *skb, struct net_device *dev)
{
dev_kfree_skb(skb);
- return 0;
+ return NETDEV_TX_OK;
}
static u8 mask_normal[6]={0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
diff --git a/linux/drivers/media/dvb/dvb-usb/Kconfig b/linux/drivers/media/dvb/dvb-usb/Kconfig
index c5ec9a5f3..0e4b97fba 100644
--- a/linux/drivers/media/dvb/dvb-usb/Kconfig
+++ b/linux/drivers/media/dvb/dvb-usb/Kconfig
@@ -316,3 +316,9 @@ config DVB_USB_CE6230
select MEDIA_TUNER_MXL5005S if !MEDIA_TUNER_CUSTOMISE
help
Say Y here to support the Intel CE6230 DVB-T USB2.0 receiver
+
+config DVB_USB_FRIIO
+ tristate "Friio ISDB-T USB2.0 Receiver support"
+ depends on DVB_USB
+ help
+ Say Y here to support the Japanese DTV receiver Friio.
diff --git a/linux/drivers/media/dvb/dvb-usb/Makefile b/linux/drivers/media/dvb/dvb-usb/Makefile
index f92734ed7..85b83a43d 100644
--- a/linux/drivers/media/dvb/dvb-usb/Makefile
+++ b/linux/drivers/media/dvb/dvb-usb/Makefile
@@ -79,6 +79,9 @@ obj-$(CONFIG_DVB_USB_CINERGY_T2) += dvb-usb-cinergyT2.o
dvb-usb-ce6230-objs = ce6230.o
obj-$(CONFIG_DVB_USB_CE6230) += dvb-usb-ce6230.o
+dvb-usb-friio-objs = friio.o friio-fe.o
+obj-$(CONFIG_DVB_USB_FRIIO) += dvb-usb-friio.o
+
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core/ -Idrivers/media/dvb/frontends/
# due to tuner-xc3028
EXTRA_CFLAGS += -Idrivers/media/common/tuners
diff --git a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
index 2d51e3c28..a548c14c1 100644
--- a/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
+++ b/linux/drivers/media/dvb/dvb-usb/dvb-usb-ids.h
@@ -60,6 +60,7 @@
#define USB_VID_YUAN 0x1164
#define USB_VID_XTENSIONS 0x1ae7
#define USB_VID_HUMAX_COEX 0x10b9
+#define USB_VID_774 0x7a69
/* Product IDs */
#define USB_PID_ADSTECH_USB2_COLD 0xa333
@@ -274,5 +275,6 @@
#define USB_PID_ELGATO_EYETV_DTT_Dlx 0x0020
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_COLD 0x5000
#define USB_PID_DVB_T_USB_STICK_HIGH_SPEED_WARM 0x5001
+#define USB_PID_FRIIO_WHITE 0x0001
#endif
diff --git a/linux/drivers/media/dvb/dvb-usb/friio-fe.c b/linux/drivers/media/dvb/dvb-usb/friio-fe.c
new file mode 100644
index 000000000..c4dfe25cf
--- /dev/null
+++ b/linux/drivers/media/dvb/dvb-usb/friio-fe.c
@@ -0,0 +1,483 @@
+/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
+ *
+ * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
+ *
+ * This module is based off the the gl861 and vp702x modules.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include <linux/init.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+
+#include "friio.h"
+
+struct jdvbt90502_state {
+ struct i2c_adapter *i2c;
+ struct dvb_frontend frontend;
+ struct jdvbt90502_config config;
+};
+
+/* NOTE: TC90502 has 16bit register-address? */
+/* register 0x0100 is used for reading PLL status, so reg is u16 here */
+static int jdvbt90502_reg_read(struct jdvbt90502_state *state,
+ const u16 reg, u8 *buf, const size_t count)
+{
+ int ret;
+ u8 wbuf[3];
+ struct i2c_msg msg[2];
+
+ wbuf[0] = reg & 0xFF;
+ wbuf[1] = 0;
+ wbuf[2] = reg >> 8;
+
+ msg[0].addr = state->config.demod_address;
+ msg[0].flags = 0;
+ msg[0].buf = wbuf;
+ msg[0].len = sizeof(wbuf);
+
+ msg[1].addr = msg[0].addr;
+ msg[1].flags = I2C_M_RD;
+ msg[1].buf = buf;
+ msg[1].len = count;
+
+ ret = i2c_transfer(state->i2c, msg, 2);
+ if (ret != 2) {
+ deb_fe(" reg read failed.\n");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+/* currently 16bit register-address is not used, so reg is u8 here */
+static int jdvbt90502_single_reg_write(struct jdvbt90502_state *state,
+ const u8 reg, const u8 val)
+{
+ struct i2c_msg msg;
+ u8 wbuf[2];
+
+ wbuf[0] = reg;
+ wbuf[1] = val;
+
+ msg.addr = state->config.demod_address;
+ msg.flags = 0;
+ msg.buf = wbuf;
+ msg.len = sizeof(wbuf);
+
+ if (i2c_transfer(state->i2c, &msg, 1) != 1) {
+ deb_fe(" reg write failed.");
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int _jdvbt90502_write(struct dvb_frontend *fe, u8 *buf, int len)
+{
+ struct jdvbt90502_state *state = fe->demodulator_priv;
+ int err, i;
+ for (i = 0; i < len - 1; i++) {
+ err = jdvbt90502_single_reg_write(state,
+ buf[0] + i, buf[i + 1]);
+ if (err)
+ return err;
+ }
+
+ return 0;
+}
+
+/* read pll status byte via the demodulator's I2C register */
+/* note: Win box reads it by 8B block at the I2C addr 0x30 from reg:0x80 */
+static int jdvbt90502_pll_read(struct jdvbt90502_state *state, u8 *result)
+{
+ int ret;
+
+ /* +1 for reading */
+ u8 pll_addr_byte = (state->config.pll_address << 1) + 1;
+
+ *result = 0;
+
+ ret = jdvbt90502_single_reg_write(state, JDVBT90502_2ND_I2C_REG,
+ pll_addr_byte);
+ if (ret)
+ goto error;
+
+ ret = jdvbt90502_reg_read(state, 0x0100, result, 1);
+ if (ret)
+ goto error;
+
+ deb_fe("PLL read val:%02x\n", *result);
+ return 0;
+
+error:
+ deb_fe("%s:ret == %d\n", __func__, ret);
+ return -EREMOTEIO;
+}
+
+
+/* set pll frequency via the demodulator's I2C register */
+static int jdvbt90502_pll_set_freq(struct jdvbt90502_state *state, u32 freq)
+{
+ int ret;
+ int retry;
+ u8 res1;
+ u8 res2[9];
+
+ u8 pll_freq_cmd[PLL_CMD_LEN];
+ u8 pll_agc_cmd[PLL_CMD_LEN];
+ struct i2c_msg msg[2];
+ u32 f;
+
+ deb_fe("%s: freq=%d, step=%d\n", __func__, freq,
+ state->frontend.ops.info.frequency_stepsize);
+ /* freq -> oscilator frequency conversion. */
+ /* freq: 473,000,000 + n*6,000,000 (no 1/7MHz shift to center freq) */
+ /* add 400[1/7 MHZ] = 57.142857MHz. 57MHz for the IF, */
+ /* 1/7MHz for center freq shift */
+ f = freq / state->frontend.ops.info.frequency_stepsize;
+ f += 400;
+ pll_freq_cmd[DEMOD_REDIRECT_REG] = JDVBT90502_2ND_I2C_REG; /* 0xFE */
+ pll_freq_cmd[ADDRESS_BYTE] = state->config.pll_address << 1;
+ pll_freq_cmd[DIVIDER_BYTE1] = (f >> 8) & 0x7F;
+ pll_freq_cmd[DIVIDER_BYTE2] = f & 0xFF;
+ pll_freq_cmd[CONTROL_BYTE] = 0xB2; /* ref.divider:28, 4MHz/28=1/7MHz */
+ pll_freq_cmd[BANDSWITCH_BYTE] = 0x08; /* UHF band */
+
+ msg[0].addr = state->config.demod_address;
+ msg[0].flags = 0;
+ msg[0].buf = pll_freq_cmd;
+ msg[0].len = sizeof(pll_freq_cmd);
+
+ ret = i2c_transfer(state->i2c, &msg[0], 1);
+ if (ret != 1)
+ goto error;
+
+ udelay(50);
+
+ pll_agc_cmd[DEMOD_REDIRECT_REG] = pll_freq_cmd[DEMOD_REDIRECT_REG];
+ pll_agc_cmd[ADDRESS_BYTE] = pll_freq_cmd[ADDRESS_BYTE];
+ pll_agc_cmd[DIVIDER_BYTE1] = pll_freq_cmd[DIVIDER_BYTE1];
+ pll_agc_cmd[DIVIDER_BYTE2] = pll_freq_cmd[DIVIDER_BYTE2];
+ pll_agc_cmd[CONTROL_BYTE] = 0x9A; /* AGC_CTRL instead of BANDSWITCH */
+ pll_agc_cmd[AGC_CTRL_BYTE] = 0x50;
+ /* AGC Time Constant 2s, AGC take-over point:103dBuV(lowest) */
+
+ msg[1].addr = msg[0].addr;
+ msg[1].flags = 0;
+ msg[1].buf = pll_agc_cmd;
+ msg[1].len = sizeof(pll_agc_cmd);
+
+ ret = i2c_transfer(state->i2c, &msg[1], 1);
+ if (ret != 1)
+ goto error;
+
+ /* I don't know what these cmds are for, */
+ /* but the USB log on a windows box contains them */
+ ret = jdvbt90502_single_reg_write(state, 0x01, 0x40);
+ ret |= jdvbt90502_single_reg_write(state, 0x01, 0x00);
+ if (ret)
+ goto error;
+ udelay(100);
+
+ /* wait for the demod to be ready? */
+#define RETRY_COUNT 5
+ for (retry = 0; retry < RETRY_COUNT; retry++) {
+ ret = jdvbt90502_reg_read(state, 0x0096, &res1, 1);
+ if (ret)
+ goto error;
+ /* if (res1 != 0x00) goto error; */
+ ret = jdvbt90502_reg_read(state, 0x00B0, res2, sizeof(res2));
+ if (ret)
+ goto error;
+ if (res2[0] >= 0xA7)
+ break;
+ msleep(100);
+ }
+ if (retry >= RETRY_COUNT) {
+ deb_fe("%s: FE does not get ready after freq setting.\n",
+ __func__);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+error:
+ deb_fe("%s:ret == %d\n", __func__, ret);
+ return -EREMOTEIO;
+}
+
+static int jdvbt90502_read_status(struct dvb_frontend *fe, fe_status_t *state)
+{
+ u8 result;
+ int ret;
+
+ *state = FE_HAS_SIGNAL;
+
+ ret = jdvbt90502_pll_read(fe->demodulator_priv, &result);
+ if (ret) {
+ deb_fe("%s:ret == %d\n", __func__, ret);
+ return -EREMOTEIO;
+ }
+
+ *state = FE_HAS_SIGNAL
+ | FE_HAS_CARRIER
+ | FE_HAS_VITERBI
+ | FE_HAS_SYNC;
+
+ if (result & PLL_STATUS_LOCKED)
+ *state |= FE_HAS_LOCK;
+
+ return 0;
+}
+
+static int jdvbt90502_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+ *ber = 0;
+ return 0;
+}
+
+static int jdvbt90502_read_signal_strength(struct dvb_frontend *fe,
+ u16 *strength)
+{
+ int ret;
+ u8 rbuf[37];
+
+ *strength = 0;
+
+ /* status register (incl. signal strength) : 0x89 */
+ /* TODO: read just the necessary registers [0x8B..0x8D]? */
+ ret = jdvbt90502_reg_read(fe->demodulator_priv, 0x0089,
+ rbuf, sizeof(rbuf));
+
+ if (ret) {
+ deb_fe("%s:ret == %d\n", __func__, ret);
+ return -EREMOTEIO;
+ }
+
+ /* signal_strength: rbuf[2-4] (24bit BE), use lower 16bit for now. */
+ *strength = (rbuf[3] << 8) + rbuf[4];
+ if (rbuf[2])
+ *strength = 0xffff;
+
+ return 0;
+}
+
+static int jdvbt90502_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+ *snr = 0x0101;
+ return 0;
+}
+
+static int jdvbt90502_read_ucblocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+ *ucblocks = 0;
+ return 0;
+}
+
+static int jdvbt90502_get_tune_settings(struct dvb_frontend *fe,
+ struct dvb_frontend_tune_settings *fs)
+{
+ fs->min_delay_ms = 500;
+ fs->step_size = 0;
+ fs->max_drift = 0;
+
+ return 0;
+}
+
+static int jdvbt90502_get_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ p->inversion = INVERSION_AUTO;
+ p->u.ofdm.bandwidth = BANDWIDTH_6_MHZ;
+ p->u.ofdm.code_rate_HP = FEC_AUTO;
+ p->u.ofdm.code_rate_LP = FEC_AUTO;
+ p->u.ofdm.constellation = QAM_64;
+ p->u.ofdm.transmission_mode = TRANSMISSION_MODE_AUTO;
+ p->u.ofdm.guard_interval = GUARD_INTERVAL_AUTO;
+ p->u.ofdm.hierarchy_information = HIERARCHY_AUTO;
+ return 0;
+}
+
+static int jdvbt90502_set_frontend(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *p)
+{
+ /**
+ * NOTE: ignore all the paramters except frequency.
+ * others should be fixed to the proper value for ISDB-T,
+ * but don't check here.
+ */
+
+ struct jdvbt90502_state *state = fe->demodulator_priv;
+ int ret;
+
+ deb_fe("%s: Freq:%d\n", __func__, p->frequency);
+
+ ret = jdvbt90502_pll_set_freq(state, p->frequency);
+ if (ret) {
+ deb_fe("%s:ret == %d\n", __func__, ret);
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+static int jdvbt90502_sleep(struct dvb_frontend *fe)
+{
+ deb_fe("%s called.\n", __func__);
+ return 0;
+}
+
+
+/**
+ * (reg, val) commad list to initialize this module.
+ * captured on a Windows box.
+ */
+static u8 init_code[][2] = {
+ {0x01, 0x40},
+ {0x04, 0x38},
+ {0x05, 0x40},
+ {0x07, 0x40},
+ {0x0F, 0x4F},
+ {0x11, 0x21},
+ {0x12, 0x0B},
+ {0x13, 0x2F},
+ {0x14, 0x31},
+ {0x16, 0x02},
+ {0x21, 0xC4},
+ {0x22, 0x20},
+ {0x2C, 0x79},
+ {0x2D, 0x34},
+ {0x2F, 0x00},
+ {0x30, 0x28},
+ {0x31, 0x31},
+ {0x32, 0xDF},
+ {0x38, 0x01},
+ {0x39, 0x78},
+ {0x3B, 0x33},
+ {0x3C, 0x33},
+ {0x48, 0x90},
+ {0x51, 0x68},
+ {0x5E, 0x38},
+ {0x71, 0x00},
+ {0x72, 0x08},
+ {0x77, 0x00},
+ {0xC0, 0x21},
+ {0xC1, 0x10},
+ {0xE4, 0x1A},
+ {0xEA, 0x1F},
+ {0x77, 0x00},
+ {0x71, 0x00},
+ {0x71, 0x00},
+ {0x76, 0x0C},
+};
+
+const static int init_code_len = sizeof(init_code) / sizeof(u8[2]);
+
+static int jdvbt90502_init(struct dvb_frontend *fe)
+{
+ int i = -1;
+ int ret;
+ struct i2c_msg msg;
+
+ struct jdvbt90502_state *state = fe->demodulator_priv;
+
+ deb_fe("%s called.\n", __func__);
+
+ msg.addr = state->config.demod_address;
+ msg.flags = 0;
+ msg.len = 2;
+ for (i = 0; i < init_code_len; i++) {
+ msg.buf = init_code[i];
+ ret = i2c_transfer(state->i2c, &msg, 1);
+ if (ret != 1)
+ goto error;
+ }
+ msleep(100);
+
+ return 0;
+
+error:
+ deb_fe("%s: init_code[%d] failed. ret==%d\n", __func__, i, ret);
+ return -EREMOTEIO;
+}
+
+
+static void jdvbt90502_release(struct dvb_frontend *fe)
+{
+ struct jdvbt90502_state *state = fe->demodulator_priv;
+ kfree(state);
+}
+
+
+static struct dvb_frontend_ops jdvbt90502_ops;
+
+struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d)
+{
+ struct jdvbt90502_state *state = NULL;
+
+ deb_info("%s called.\n", __func__);
+
+ /* allocate memory for the internal state */
+ state = kzalloc(sizeof(struct jdvbt90502_state), GFP_KERNEL);
+ if (state == NULL)
+ goto error;
+
+ /* setup the state */
+ state->i2c = &d->i2c_adap;
+ memcpy(&state->config, &friio_fe_config, sizeof(friio_fe_config));
+
+ /* create dvb_frontend */
+ memcpy(&state->frontend.ops, &jdvbt90502_ops,
+ sizeof(jdvbt90502_ops));
+ state->frontend.demodulator_priv = state;
+
+ if (jdvbt90502_init(&state->frontend) < 0)
+ goto error;
+
+ return &state->frontend;
+
+error:
+ kfree(state);
+ return NULL;
+}
+
+static struct dvb_frontend_ops jdvbt90502_ops = {
+
+ .info = {
+ .name = "Comtech JDVBT90502 ISDB-T",
+ .type = FE_OFDM,
+ .frequency_min = 473000000, /* UHF 13ch, center */
+ .frequency_max = 767142857, /* UHF 62ch, center */
+ .frequency_stepsize = JDVBT90502_PLL_CLK /
+ JDVBT90502_PLL_DIVIDER,
+ .frequency_tolerance = 0,
+
+ /* NOTE: this driver ignores all parameters but frequency. */
+ .caps = FE_CAN_INVERSION_AUTO |
+ FE_CAN_FEC_1_2 | FE_CAN_FEC_2_3 | FE_CAN_FEC_3_4 |
+ FE_CAN_FEC_4_5 | FE_CAN_FEC_5_6 | FE_CAN_FEC_6_7 |
+ FE_CAN_FEC_7_8 | FE_CAN_FEC_8_9 | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_16 | FE_CAN_QAM_64 | FE_CAN_QAM_AUTO |
+ FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO |
+ FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .release = jdvbt90502_release,
+
+ .init = jdvbt90502_init,
+ .sleep = jdvbt90502_sleep,
+ .write = _jdvbt90502_write,
+
+ .set_frontend = jdvbt90502_set_frontend,
+ .get_frontend = jdvbt90502_get_frontend,
+ .get_tune_settings = jdvbt90502_get_tune_settings,
+
+ .read_status = jdvbt90502_read_status,
+ .read_ber = jdvbt90502_read_ber,
+ .read_signal_strength = jdvbt90502_read_signal_strength,
+ .read_snr = jdvbt90502_read_snr,
+ .read_ucblocks = jdvbt90502_read_ucblocks,
+};
diff --git a/linux/drivers/media/dvb/dvb-usb/friio.c b/linux/drivers/media/dvb/dvb-usb/friio.c
new file mode 100644
index 000000000..7417329e9
--- /dev/null
+++ b/linux/drivers/media/dvb/dvb-usb/friio.c
@@ -0,0 +1,528 @@
+/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
+ *
+ * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
+ *
+ * This module is based off the the gl861 and vp702x modules.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#include "friio.h"
+
+/* debug */
+int dvb_usb_friio_debug;
+module_param_named(debug, dvb_usb_friio_debug, int, 0644);
+MODULE_PARM_DESC(debug,
+ "set debugging level (1=info,2=xfer,4=rc,8=fe (or-able))."
+ DVB_USB_DEBUG_STATUS);
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+/**
+ * Indirect I2C access to the PLL via FE.
+ * whole I2C protocol data to the PLL is sent via the FE's I2C register.
+ * This is done by a control msg to the FE with the I2C data accompanied, and
+ * a specific USB request number is assigned for that purpose.
+ *
+ * this func sends wbuf[1..] to the I2C register wbuf[0] at addr (= at FE).
+ * TODO: refoctored, smarter i2c functions.
+ */
+static int gl861_i2c_ctrlmsg_data(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u16 index = wbuf[0]; /* must be JDVBT90502_2ND_I2C_REG(=0xFE) */
+ u16 value = addr << (8 + 1);
+ int wo = (rbuf == NULL || rlen == 0); /* write only */
+ u8 req, type;
+
+ deb_xfer("write to PLL:0x%02x via FE reg:0x%02x, len:%d\n",
+ wbuf[1], wbuf[0], wlen - 1);
+
+ if (wo && wlen >= 2) {
+ req = GL861_REQ_I2C_DATA_CTRL_WRITE;
+ type = GL861_WRITE;
+ udelay(20);
+ return usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+ req, type, value, index,
+ &wbuf[1], wlen - 1, 2000);
+ }
+
+ deb_xfer("not supported ctrl-msg, aborting.");
+ return -EINVAL;
+}
+
+/* normal I2C access (without extra data arguments).
+ * write to the register wbuf[0] at I2C address addr with the value wbuf[1],
+ * or read from the register wbuf[0].
+ * register address can be 16bit (wbuf[2]<<8 | wbuf[0]) if wlen==3
+ */
+static int gl861_i2c_msg(struct dvb_usb_device *d, u8 addr,
+ u8 *wbuf, u16 wlen, u8 *rbuf, u16 rlen)
+{
+ u16 index;
+ u16 value = addr << (8 + 1);
+ int wo = (rbuf == NULL || rlen == 0); /* write-only */
+ u8 req, type;
+ unsigned int pipe;
+
+ /* special case for the indirect I2C access to the PLL via FE, */
+ if (addr == friio_fe_config.demod_address &&
+ wbuf[0] == JDVBT90502_2ND_I2C_REG)
+ return gl861_i2c_ctrlmsg_data(d, addr, wbuf, wlen, rbuf, rlen);
+
+ if (wo) {
+ req = GL861_REQ_I2C_WRITE;
+ type = GL861_WRITE;
+ pipe = usb_sndctrlpipe(d->udev, 0);
+ } else { /* rw */
+ req = GL861_REQ_I2C_READ;
+ type = GL861_READ;
+ pipe = usb_rcvctrlpipe(d->udev, 0);
+ }
+
+ switch (wlen) {
+ case 1:
+ index = wbuf[0];
+ break;
+ case 2:
+ index = wbuf[0];
+ value = value + wbuf[1];
+ break;
+ case 3:
+ /* special case for 16bit register-address */
+ index = (wbuf[2] << 8) | wbuf[0];
+ value = value + wbuf[1];
+ break;
+ default:
+ deb_xfer("wlen = %x, aborting.", wlen);
+ return -EINVAL;
+ }
+ msleep(1);
+ return usb_control_msg(d->udev, pipe, req, type,
+ value, index, rbuf, rlen, 2000);
+}
+
+/* I2C */
+static int gl861_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msg[],
+ int num)
+{
+ struct dvb_usb_device *d = i2c_get_adapdata(adap);
+ int i;
+
+
+ if (num > 2)
+ return -EINVAL;
+
+ if (mutex_lock_interruptible(&d->i2c_mutex) < 0)
+ return -EAGAIN;
+
+ for (i = 0; i < num; i++) {
+ /* write/read request */
+ if (i + 1 < num && (msg[i + 1].flags & I2C_M_RD)) {
+ if (gl861_i2c_msg(d, msg[i].addr,
+ msg[i].buf, msg[i].len,
+ msg[i + 1].buf, msg[i + 1].len) < 0)
+ break;
+ i++;
+ } else
+ if (gl861_i2c_msg(d, msg[i].addr, msg[i].buf,
+ msg[i].len, NULL, 0) < 0)
+ break;
+ }
+
+ mutex_unlock(&d->i2c_mutex);
+ return i;
+}
+
+static u32 gl861_i2c_func(struct i2c_adapter *adapter)
+{
+ return I2C_FUNC_I2C;
+}
+
+
+static int friio_ext_ctl(struct dvb_usb_adapter *adap,
+ u32 sat_color, int lnb_on)
+{
+ int i;
+ int ret;
+ struct i2c_msg msg;
+ u8 buf[2];
+ u32 mask;
+ u8 lnb = (lnb_on) ? FRIIO_CTL_LNB : 0;
+
+ msg.addr = 0x00;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = buf;
+
+ buf[0] = 0x00;
+
+ /* send 2bit header (&B10) */
+ buf[1] = lnb | FRIIO_CTL_LED | FRIIO_CTL_STROBE;
+ ret = gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+ buf[1] |= FRIIO_CTL_CLK;
+ ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+
+ buf[1] = lnb | FRIIO_CTL_STROBE;
+ ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+ buf[1] |= FRIIO_CTL_CLK;
+ ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+
+ /* send 32bit(satur, R, G, B) data in serial */
+ mask = 1 << 31;
+ for (i = 0; i < 32; i++) {
+ buf[1] = lnb | FRIIO_CTL_STROBE;
+ if (sat_color & mask)
+ buf[1] |= FRIIO_CTL_LED;
+ ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+ buf[1] |= FRIIO_CTL_CLK;
+ ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+ mask >>= 1;
+ }
+
+ /* set the strobe off */
+ buf[1] = lnb;
+ ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+ buf[1] |= FRIIO_CTL_CLK;
+ ret += gl861_i2c_xfer(&adap->dev->i2c_adap, &msg, 1);
+
+ return (ret == 70);
+}
+
+
+static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff);
+
+/* TODO: move these init cmds to the FE's init routine? */
+static u8 streaming_init_cmds[][2] = {
+ {0x33, 0x08},
+ {0x37, 0x40},
+ {0x3A, 0x1F},
+ {0x3B, 0xFF},
+ {0x3C, 0x1F},
+ {0x3D, 0xFF},
+ {0x38, 0x00},
+ {0x35, 0x00},
+ {0x39, 0x00},
+ {0x36, 0x00},
+};
+static int cmdlen = sizeof(streaming_init_cmds) / 2;
+
+/*
+ * Command sequence in this init function is a replay
+ * of the captured USB commands from the Windows proprietary driver.
+ */
+static int friio_initialize(struct dvb_usb_device *d)
+{
+ int ret;
+ int i;
+ int retry = 0;
+ u8 rbuf[2];
+ u8 wbuf[3];
+
+ deb_info("%s called.\n", __func__);
+
+ /* use gl861_i2c_msg instead of gl861_i2c_xfer(), */
+ /* because the i2c device is not set up yet. */
+ wbuf[0] = 0x11;
+ wbuf[1] = 0x02;
+ ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+ if (ret < 0)
+ goto error;
+ msleep(2);
+
+ wbuf[0] = 0x11;
+ wbuf[1] = 0x00;
+ ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+ if (ret < 0)
+ goto error;
+ msleep(1);
+
+ /* following msgs should be in the FE's init code? */
+ /* cmd sequence to identify the device type? (friio black/white) */
+ wbuf[0] = 0x03;
+ wbuf[1] = 0x80;
+ /* can't use gl861_i2c_cmd, as the register-addr is 16bit(0x0100) */
+ ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+ GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
+ 0x1200, 0x0100, wbuf, 2, 2000);
+ if (ret < 0)
+ goto error;
+
+ msleep(2);
+ wbuf[0] = 0x00;
+ wbuf[2] = 0x01; /* reg.0x0100 */
+ wbuf[1] = 0x00;
+ ret = gl861_i2c_msg(d, 0x12 >> 1, wbuf, 3, rbuf, 2);
+ /* my Friio White returns 0xffff. */
+ if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
+ goto error;
+
+ msleep(2);
+ wbuf[0] = 0x03;
+ wbuf[1] = 0x80;
+ ret = usb_control_msg(d->udev, usb_sndctrlpipe(d->udev, 0),
+ GL861_REQ_I2C_DATA_CTRL_WRITE, GL861_WRITE,
+ 0x9000, 0x0100, wbuf, 2, 2000);
+ if (ret < 0)
+ goto error;
+
+ msleep(2);
+ wbuf[0] = 0x00;
+ wbuf[2] = 0x01; /* reg.0x0100 */
+ wbuf[1] = 0x00;
+ ret = gl861_i2c_msg(d, 0x90 >> 1, wbuf, 3, rbuf, 2);
+ /* my Friio White returns 0xffff again. */
+ if (ret < 0 || rbuf[0] != 0xff || rbuf[1] != 0xff)
+ goto error;
+
+ msleep(1);
+
+restart:
+ /* ============ start DEMOD init cmds ================== */
+ /* read PLL status to clear the POR bit */
+ wbuf[0] = JDVBT90502_2ND_I2C_REG;
+ wbuf[1] = (FRIIO_PLL_ADDR << 1) + 1; /* +1 for reading */
+ ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, NULL, 0);
+ if (ret < 0)
+ goto error;
+
+ msleep(5);
+ /* note: DEMODULATOR has 16bit register-address. */
+ wbuf[0] = 0x00;
+ wbuf[2] = 0x01; /* reg addr: 0x0100 */
+ wbuf[1] = 0x00; /* val: not used */
+ ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 3, rbuf, 1);
+ if (ret < 0)
+ goto error;
+/*
+ msleep(1);
+ wbuf[0] = 0x80;
+ wbuf[1] = 0x00;
+ ret = gl861_i2c_msg(d, FRIIO_DEMOD_ADDR, wbuf, 2, rbuf, 1);
+ if (ret < 0)
+ goto error;
+ */
+ if (rbuf[0] & 0x80) { /* still in PowerOnReset state? */
+ if (++retry > 3) {
+ deb_info("failed to get the correct"
+ " FE demod status:0x%02x\n", rbuf[0]);
+ goto error;
+ }
+ msleep(100);
+ goto restart;
+ }
+
+ /* TODO: check return value in rbuf */
+ /* =========== end DEMOD init cmds ===================== */
+ msleep(1);
+
+ wbuf[0] = 0x30;
+ wbuf[1] = 0x04;
+ ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+ if (ret < 0)
+ goto error;
+
+ msleep(2);
+ /* following 2 cmds unnecessary? */
+ wbuf[0] = 0x00;
+ wbuf[1] = 0x01;
+ ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+ if (ret < 0)
+ goto error;
+
+ wbuf[0] = 0x06;
+ wbuf[1] = 0x0F;
+ ret = gl861_i2c_msg(d, 0x00, wbuf, 2, NULL, 0);
+ if (ret < 0)
+ goto error;
+
+ /* some streaming ctl cmds (maybe) */
+ msleep(10);
+ for (i = 0; i < cmdlen; i++) {
+ ret = gl861_i2c_msg(d, 0x00, streaming_init_cmds[i], 2,
+ NULL, 0);
+ if (ret < 0)
+ goto error;
+ msleep(1);
+ }
+ msleep(20);
+
+ /* change the LED color etc. */
+ ret = friio_streaming_ctrl(&d->adapter[0], 0);
+ if (ret < 0)
+ goto error;
+
+ return 0;
+
+error:
+ deb_info("%s:ret == %d\n", __func__, ret);
+ return -EIO;
+}
+
+/* Callbacks for DVB USB */
+
+static int friio_streaming_ctrl(struct dvb_usb_adapter *adap, int onoff)
+{
+ int ret;
+
+ deb_info("%s called.(%d)\n", __func__, onoff);
+
+ /* set the LED color and saturation (and LNB on) */
+ if (onoff)
+ ret = friio_ext_ctl(adap, 0x6400ff64, 1);
+ else
+ ret = friio_ext_ctl(adap, 0x96ff00ff, 1);
+
+ if (ret != 1) {
+ deb_info("%s failed to send cmdx. ret==%d\n", __func__, ret);
+ return -EREMOTEIO;
+ }
+ return 0;
+}
+
+static int friio_frontend_attach(struct dvb_usb_adapter *adap)
+{
+ if (friio_initialize(adap->dev) < 0)
+ return -EIO;
+
+ adap->fe = jdvbt90502_attach(adap->dev);
+ if (adap->fe == NULL)
+ return -EIO;
+
+ return 0;
+}
+
+/* DVB USB Driver stuff */
+static struct dvb_usb_device_properties friio_properties;
+
+static int friio_probe(struct usb_interface *intf,
+ const struct usb_device_id *id)
+{
+ struct dvb_usb_device *d;
+ struct usb_host_interface *alt;
+ int ret;
+
+ if (intf->num_altsetting < GL861_ALTSETTING_COUNT)
+ return -ENODEV;
+
+ alt = usb_altnum_to_altsetting(intf, FRIIO_BULK_ALTSETTING);
+ if (alt == NULL) {
+ deb_rc("not alt found!\n");
+ return -ENODEV;
+ }
+ ret = usb_set_interface(interface_to_usbdev(intf),
+ alt->desc.bInterfaceNumber,
+ alt->desc.bAlternateSetting);
+ if (ret != 0) {
+ deb_rc("failed to set alt-setting!\n");
+ return ret;
+ }
+
+ ret = dvb_usb_device_init(intf, &friio_properties,
+ THIS_MODULE, &d, adapter_nr);
+ if (ret == 0)
+ friio_streaming_ctrl(&d->adapter[0], 1);
+
+ return ret;
+}
+
+
+struct jdvbt90502_config friio_fe_config = {
+ .demod_address = FRIIO_DEMOD_ADDR,
+ .pll_address = FRIIO_PLL_ADDR,
+};
+
+static struct i2c_algorithm gl861_i2c_algo = {
+ .master_xfer = gl861_i2c_xfer,
+ .functionality = gl861_i2c_func,
+#ifdef NEED_ALGO_CONTROL
+ .algo_control = dummy_algo_control,
+#endif
+};
+
+static struct usb_device_id friio_table[] = {
+ { USB_DEVICE(USB_VID_774, USB_PID_FRIIO_WHITE) },
+ { } /* Terminating entry */
+};
+MODULE_DEVICE_TABLE(usb, friio_table);
+
+
+static struct dvb_usb_device_properties friio_properties = {
+ .caps = DVB_USB_IS_AN_I2C_ADAPTER,
+ .usb_ctrl = DEVICE_SPECIFIC,
+
+ .size_of_priv = 0,
+
+ .num_adapters = 1,
+ .adapter = {
+ /* caps:0 => no pid filter, 188B TS packet */
+ /* GL861 has a HW pid filter, but no info available. */
+ {
+ .caps = 0,
+
+ .frontend_attach = friio_frontend_attach,
+ .streaming_ctrl = friio_streaming_ctrl,
+
+ .stream = {
+ .type = USB_BULK,
+ /* count <= MAX_NO_URBS_FOR_DATA_STREAM(10) */
+ .count = 8,
+ .endpoint = 0x01,
+ .u = {
+ /* GL861 has 6KB buf inside */
+ .bulk = {
+ .buffersize = 16384,
+ }
+ }
+ },
+ }
+ },
+ .i2c_algo = &gl861_i2c_algo,
+
+ .num_device_descs = 1,
+ .devices = {
+ {
+ .name = "774 Friio ISDB-T USB2.0",
+ .cold_ids = { NULL },
+ .warm_ids = { &friio_table[0], NULL },
+ },
+ }
+};
+
+static struct usb_driver friio_driver = {
+ .name = "dvb_usb_friio",
+ .probe = friio_probe,
+ .disconnect = dvb_usb_device_exit,
+ .id_table = friio_table,
+};
+
+
+/* module stuff */
+static int __init friio_module_init(void)
+{
+ int ret;
+
+ ret = usb_register(&friio_driver);
+ if (ret)
+ err("usb_register failed. Error number %d", ret);
+
+ return ret;
+}
+
+
+static void __exit friio_module_exit(void)
+{
+ /* deregister this driver from the USB subsystem */
+ usb_deregister(&friio_driver);
+}
+
+module_init(friio_module_init);
+module_exit(friio_module_exit);
+
+MODULE_AUTHOR("Akihiro Tsukada <tskd2@yahoo.co.jp>");
+MODULE_DESCRIPTION("Driver for Friio ISDB-T USB2.0 Receiver");
+MODULE_VERSION("0.2");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/dvb-usb/friio.h b/linux/drivers/media/dvb/dvb-usb/friio.h
new file mode 100644
index 000000000..af8d55e39
--- /dev/null
+++ b/linux/drivers/media/dvb/dvb-usb/friio.h
@@ -0,0 +1,99 @@
+/* DVB USB compliant Linux driver for the Friio USB2.0 ISDB-T receiver.
+ *
+ * Copyright (C) 2009 Akihiro Tsukada <tskd2@yahoo.co.jp>
+ *
+ * This module is based off the the gl861 and vp702x modules.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation, version 2.
+ *
+ * see Documentation/dvb/README.dvb-usb for more information
+ */
+#ifndef _DVB_USB_FRIIO_H_
+#define _DVB_USB_FRIIO_H_
+
+/**
+ * Friio Components
+ * USB hub: AU4254
+ * USB controller(+ TS dmx & streaming): GL861
+ * Frontend: comtech JDVBT-90502
+ * (tuner PLL: tua6034, I2C addr:(0xC0 >> 1))
+ * (OFDM demodulator: TC90502, I2C addr:(0x30 >> 1))
+ * LED x3 (+LNB) controll: PIC 16F676
+ * EEPROM: 24C08
+ *
+ * (USB smart card reader: AU9522)
+ *
+ */
+
+#define DVB_USB_LOG_PREFIX "friio"
+#include "dvb-usb.h"
+
+extern int dvb_usb_friio_debug;
+#define deb_info(args...) dprintk(dvb_usb_friio_debug, 0x01, args)
+#define deb_xfer(args...) dprintk(dvb_usb_friio_debug, 0x02, args)
+#define deb_rc(args...) dprintk(dvb_usb_friio_debug, 0x04, args)
+#define deb_fe(args...) dprintk(dvb_usb_friio_debug, 0x08, args)
+
+/* Vendor requests */
+#define GL861_WRITE 0x40
+#define GL861_READ 0xc0
+
+/* command bytes */
+#define GL861_REQ_I2C_WRITE 0x01
+#define GL861_REQ_I2C_READ 0x02
+/* For control msg with data argument */
+/* Used for accessing the PLL on the secondary I2C bus of FE via GL861 */
+#define GL861_REQ_I2C_DATA_CTRL_WRITE 0x03
+
+#define GL861_ALTSETTING_COUNT 2
+#define FRIIO_BULK_ALTSETTING 0
+#define FRIIO_ISOC_ALTSETTING 1
+
+/* LED & LNB control via PIC. */
+/* basically, it's serial control with clock and strobe. */
+/* write the below 4bit control data to the reg 0x00 at the I2C addr 0x00 */
+/* when controlling the LEDs, 32bit(saturation, R, G, B) is sent on the bit3*/
+#define FRIIO_CTL_LNB (1 << 0)
+#define FRIIO_CTL_STROBE (1 << 1)
+#define FRIIO_CTL_CLK (1 << 2)
+#define FRIIO_CTL_LED (1 << 3)
+
+/* Front End related */
+
+#define FRIIO_DEMOD_ADDR (0x30 >> 1)
+#define FRIIO_PLL_ADDR (0xC0 >> 1)
+
+#define JDVBT90502_PLL_CLK 4000000
+#define JDVBT90502_PLL_DIVIDER 28
+
+#define JDVBT90502_2ND_I2C_REG 0xFE
+
+/* byte index for pll i2c command data structure*/
+/* see datasheet for tua6034 */
+#define DEMOD_REDIRECT_REG 0
+#define ADDRESS_BYTE 1
+#define DIVIDER_BYTE1 2
+#define DIVIDER_BYTE2 3
+#define CONTROL_BYTE 4
+#define BANDSWITCH_BYTE 5
+#define AGC_CTRL_BYTE 5
+#define PLL_CMD_LEN 6
+
+/* bit masks for PLL STATUS response */
+#define PLL_STATUS_POR_MODE 0x80 /* 1: Power on Reset (test) Mode */
+#define PLL_STATUS_LOCKED 0x40 /* 1: locked */
+#define PLL_STATUS_AGC_ACTIVE 0x08 /* 1:active */
+#define PLL_STATUS_TESTMODE 0x07 /* digital output level (5 level) */
+ /* 0.15Vcc step 0x00: < 0.15Vcc, ..., 0x04: >= 0.6Vcc (<= 1Vcc) */
+
+
+struct jdvbt90502_config {
+ u8 demod_address; /* i2c addr for demodulator IC */
+ u8 pll_address; /* PLL addr on the secondary i2c*/
+};
+extern struct jdvbt90502_config friio_fe_config;
+
+extern struct dvb_frontend *jdvbt90502_attach(struct dvb_usb_device *d);
+#endif
diff --git a/linux/drivers/media/dvb/pt1/Kconfig b/linux/drivers/media/dvb/pt1/Kconfig
new file mode 100644
index 000000000..24501d5bf
--- /dev/null
+++ b/linux/drivers/media/dvb/pt1/Kconfig
@@ -0,0 +1,12 @@
+config DVB_PT1
+ tristate "PT1 cards"
+ depends on DVB_CORE && PCI && I2C
+ help
+ Support for Earthsoft PT1 PCI cards.
+
+ Since these cards have no MPEG decoder onboard, they transmit
+ only compressed MPEG data over the PCI bus, so you need
+ an external software decoder to watch TV on your computer.
+
+ Say Y or M if you own such a device and want to use it.
+
diff --git a/linux/drivers/media/dvb/pt1/Makefile b/linux/drivers/media/dvb/pt1/Makefile
new file mode 100644
index 000000000..a66da17bb
--- /dev/null
+++ b/linux/drivers/media/dvb/pt1/Makefile
@@ -0,0 +1,5 @@
+earth-pt1-objs := pt1.o va1j5jf8007s.o va1j5jf8007t.o
+
+obj-$(CONFIG_DVB_PT1) += earth-pt1.o
+
+EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core -Idrivers/media/dvb/frontends
diff --git a/linux/drivers/media/dvb/pt1/pt1.c b/linux/drivers/media/dvb/pt1/pt1.c
new file mode 100644
index 000000000..ef0f7d235
--- /dev/null
+++ b/linux/drivers/media/dvb/pt1/pt1.c
@@ -0,0 +1,1056 @@
+/*
+ * driver for Earthsoft PT1
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * 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>
+#include <linux/pci.h>
+#include <linux/kthread.h>
+#include <linux/freezer.h>
+
+#include "dvbdev.h"
+#include "dvb_demux.h"
+#include "dmxdev.h"
+#include "dvb_net.h"
+#include "dvb_frontend.h"
+
+#include "va1j5jf8007t.h"
+#include "va1j5jf8007s.h"
+
+#define DRIVER_NAME "earth-pt1"
+
+#define PT1_PAGE_SHIFT 12
+#define PT1_PAGE_SIZE (1 << PT1_PAGE_SHIFT)
+#define PT1_NR_UPACKETS 1024
+#define PT1_NR_BUFS 511
+
+struct pt1_buffer_page {
+ __le32 upackets[PT1_NR_UPACKETS];
+};
+
+struct pt1_table_page {
+ __le32 next_pfn;
+ __le32 buf_pfns[PT1_NR_BUFS];
+};
+
+struct pt1_buffer {
+ struct pt1_buffer_page *page;
+ dma_addr_t addr;
+};
+
+struct pt1_table {
+ struct pt1_table_page *page;
+ dma_addr_t addr;
+ struct pt1_buffer bufs[PT1_NR_BUFS];
+};
+
+#define PT1_NR_ADAPS 4
+
+struct pt1_adapter;
+
+struct pt1 {
+ struct pci_dev *pdev;
+ void __iomem *regs;
+ struct i2c_adapter i2c_adap;
+ int i2c_running;
+ struct pt1_adapter *adaps[PT1_NR_ADAPS];
+ struct pt1_table *tables;
+ struct task_struct *kthread;
+};
+
+struct pt1_adapter {
+ struct pt1 *pt1;
+ int index;
+
+ u8 *buf;
+ int upacket_count;
+ int packet_count;
+
+ struct dvb_adapter adap;
+ struct dvb_demux demux;
+ int users;
+ struct dmxdev dmxdev;
+ struct dvb_net net;
+ struct dvb_frontend *fe;
+ int (*orig_set_voltage)(struct dvb_frontend *fe,
+ fe_sec_voltage_t voltage);
+};
+
+#define pt1_printk(level, pt1, format, arg...) \
+ dev_printk(level, &(pt1)->pdev->dev, format, ##arg)
+
+static void pt1_write_reg(struct pt1 *pt1, int reg, u32 data)
+{
+ writel(data, pt1->regs + reg * 4);
+}
+
+static u32 pt1_read_reg(struct pt1 *pt1, int reg)
+{
+ return readl(pt1->regs + reg * 4);
+}
+
+static int pt1_nr_tables = 64;
+module_param_named(nr_tables, pt1_nr_tables, int, 0);
+
+static void pt1_increment_table_count(struct pt1 *pt1)
+{
+ pt1_write_reg(pt1, 0, 0x00000020);
+}
+
+static void pt1_init_table_count(struct pt1 *pt1)
+{
+ pt1_write_reg(pt1, 0, 0x00000010);
+}
+
+static void pt1_register_tables(struct pt1 *pt1, u32 first_pfn)
+{
+ pt1_write_reg(pt1, 5, first_pfn);
+ pt1_write_reg(pt1, 0, 0x0c000040);
+}
+
+static void pt1_unregister_tables(struct pt1 *pt1)
+{
+ pt1_write_reg(pt1, 0, 0x08080000);
+}
+
+static int pt1_sync(struct pt1 *pt1)
+{
+ int i;
+ for (i = 0; i < 57; i++) {
+ if (pt1_read_reg(pt1, 0) & 0x20000000)
+ return 0;
+ pt1_write_reg(pt1, 0, 0x00000008);
+ }
+ pt1_printk(KERN_ERR, pt1, "could not sync\n");
+ return -EIO;
+}
+
+static u64 pt1_identify(struct pt1 *pt1)
+{
+ int i;
+ u64 id;
+ id = 0;
+ for (i = 0; i < 57; i++) {
+ id |= (u64)(pt1_read_reg(pt1, 0) >> 30 & 1) << i;
+ pt1_write_reg(pt1, 0, 0x00000008);
+ }
+ return id;
+}
+
+static int pt1_unlock(struct pt1 *pt1)
+{
+ int i;
+ pt1_write_reg(pt1, 0, 0x00000008);
+ for (i = 0; i < 3; i++) {
+ if (pt1_read_reg(pt1, 0) & 0x80000000)
+ return 0;
+ schedule_timeout_uninterruptible((HZ + 999) / 1000);
+ }
+ pt1_printk(KERN_ERR, pt1, "could not unlock\n");
+ return -EIO;
+}
+
+static int pt1_reset_pci(struct pt1 *pt1)
+{
+ int i;
+ pt1_write_reg(pt1, 0, 0x01010000);
+ pt1_write_reg(pt1, 0, 0x01000000);
+ for (i = 0; i < 10; i++) {
+ if (pt1_read_reg(pt1, 0) & 0x00000001)
+ return 0;
+ schedule_timeout_uninterruptible((HZ + 999) / 1000);
+ }
+ pt1_printk(KERN_ERR, pt1, "could not reset PCI\n");
+ return -EIO;
+}
+
+static int pt1_reset_ram(struct pt1 *pt1)
+{
+ int i;
+ pt1_write_reg(pt1, 0, 0x02020000);
+ pt1_write_reg(pt1, 0, 0x02000000);
+ for (i = 0; i < 10; i++) {
+ if (pt1_read_reg(pt1, 0) & 0x00000002)
+ return 0;
+ schedule_timeout_uninterruptible((HZ + 999) / 1000);
+ }
+ pt1_printk(KERN_ERR, pt1, "could not reset RAM\n");
+ return -EIO;
+}
+
+static int pt1_do_enable_ram(struct pt1 *pt1)
+{
+ int i, j;
+ u32 status;
+ status = pt1_read_reg(pt1, 0) & 0x00000004;
+ pt1_write_reg(pt1, 0, 0x00000002);
+ for (i = 0; i < 10; i++) {
+ for (j = 0; j < 1024; j++) {
+ if ((pt1_read_reg(pt1, 0) & 0x00000004) != status)
+ return 0;
+ }
+ schedule_timeout_uninterruptible((HZ + 999) / 1000);
+ }
+ pt1_printk(KERN_ERR, pt1, "could not enable RAM\n");
+ return -EIO;
+}
+
+static int pt1_enable_ram(struct pt1 *pt1)
+{
+ int i, ret;
+ schedule_timeout_uninterruptible((HZ + 999) / 1000);
+ for (i = 0; i < 10; i++) {
+ ret = pt1_do_enable_ram(pt1);
+ if (ret < 0)
+ return ret;
+ }
+ return 0;
+}
+
+static void pt1_disable_ram(struct pt1 *pt1)
+{
+ pt1_write_reg(pt1, 0, 0x0b0b0000);
+}
+
+static void pt1_set_stream(struct pt1 *pt1, int index, int enabled)
+{
+ pt1_write_reg(pt1, 2, 1 << (index + 8) | enabled << index);
+}
+
+static void pt1_init_streams(struct pt1 *pt1)
+{
+ int i;
+ for (i = 0; i < PT1_NR_ADAPS; i++)
+ pt1_set_stream(pt1, i, 0);
+}
+
+static int pt1_filter(struct pt1 *pt1, struct pt1_buffer_page *page)
+{
+ u32 upacket;
+ int i;
+ int index;
+ struct pt1_adapter *adap;
+ int offset;
+ u8 *buf;
+
+ if (!page->upackets[PT1_NR_UPACKETS - 1])
+ return 0;
+
+ for (i = 0; i < PT1_NR_UPACKETS; i++) {
+ upacket = le32_to_cpu(page->upackets[i]);
+ index = (upacket >> 29) - 1;
+ if (index < 0 || index >= PT1_NR_ADAPS)
+ continue;
+
+ adap = pt1->adaps[index];
+ if (upacket >> 25 & 1)
+ adap->upacket_count = 0;
+ else if (!adap->upacket_count)
+ continue;
+
+ buf = adap->buf;
+ offset = adap->packet_count * 188 + adap->upacket_count * 3;
+ buf[offset] = upacket >> 16;
+ buf[offset + 1] = upacket >> 8;
+ if (adap->upacket_count != 62)
+ buf[offset + 2] = upacket;
+
+ if (++adap->upacket_count >= 63) {
+ adap->upacket_count = 0;
+ if (++adap->packet_count >= 21) {
+ dvb_dmx_swfilter_packets(&adap->demux, buf, 21);
+ adap->packet_count = 0;
+ }
+ }
+ }
+
+ page->upackets[PT1_NR_UPACKETS - 1] = 0;
+ return 1;
+}
+
+static int pt1_thread(void *data)
+{
+ struct pt1 *pt1;
+ int table_index;
+ int buf_index;
+ struct pt1_buffer_page *page;
+
+ pt1 = data;
+ set_freezable();
+
+ table_index = 0;
+ buf_index = 0;
+
+ while (!kthread_should_stop()) {
+ try_to_freeze();
+
+ page = pt1->tables[table_index].bufs[buf_index].page;
+ if (!pt1_filter(pt1, page)) {
+ schedule_timeout_interruptible((HZ + 999) / 1000);
+ continue;
+ }
+
+ if (++buf_index >= PT1_NR_BUFS) {
+ pt1_increment_table_count(pt1);
+ buf_index = 0;
+ if (++table_index >= pt1_nr_tables)
+ table_index = 0;
+ }
+ }
+
+ return 0;
+}
+
+static void pt1_free_page(struct pt1 *pt1, void *page, dma_addr_t addr)
+{
+ dma_free_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, page, addr);
+}
+
+static void *pt1_alloc_page(struct pt1 *pt1, dma_addr_t *addrp, u32 *pfnp)
+{
+ void *page;
+ dma_addr_t addr;
+
+ page = dma_alloc_coherent(&pt1->pdev->dev, PT1_PAGE_SIZE, &addr,
+ GFP_KERNEL);
+ if (page == NULL)
+ return NULL;
+
+ BUG_ON(addr & (PT1_PAGE_SIZE - 1));
+ BUG_ON(addr >> PT1_PAGE_SHIFT >> 31 >> 1);
+
+ *addrp = addr;
+ *pfnp = addr >> PT1_PAGE_SHIFT;
+ return page;
+}
+
+static void pt1_cleanup_buffer(struct pt1 *pt1, struct pt1_buffer *buf)
+{
+ pt1_free_page(pt1, buf->page, buf->addr);
+}
+
+static int
+pt1_init_buffer(struct pt1 *pt1, struct pt1_buffer *buf, u32 *pfnp)
+{
+ struct pt1_buffer_page *page;
+ dma_addr_t addr;
+
+ page = pt1_alloc_page(pt1, &addr, pfnp);
+ if (page == NULL)
+ return -ENOMEM;
+
+ page->upackets[PT1_NR_UPACKETS - 1] = 0;
+
+ buf->page = page;
+ buf->addr = addr;
+ return 0;
+}
+
+static void pt1_cleanup_table(struct pt1 *pt1, struct pt1_table *table)
+{
+ int i;
+
+ for (i = 0; i < PT1_NR_BUFS; i++)
+ pt1_cleanup_buffer(pt1, &table->bufs[i]);
+
+ pt1_free_page(pt1, table->page, table->addr);
+}
+
+static int
+pt1_init_table(struct pt1 *pt1, struct pt1_table *table, u32 *pfnp)
+{
+ struct pt1_table_page *page;
+ dma_addr_t addr;
+ int i, ret;
+ u32 buf_pfn;
+
+ page = pt1_alloc_page(pt1, &addr, pfnp);
+ if (page == NULL)
+ return -ENOMEM;
+
+ for (i = 0; i < PT1_NR_BUFS; i++) {
+ ret = pt1_init_buffer(pt1, &table->bufs[i], &buf_pfn);
+ if (ret < 0)
+ goto err;
+
+ page->buf_pfns[i] = cpu_to_le32(buf_pfn);
+ }
+
+ pt1_increment_table_count(pt1);
+ table->page = page;
+ table->addr = addr;
+ return 0;
+
+err:
+ while (i--)
+ pt1_cleanup_buffer(pt1, &table->bufs[i]);
+
+ pt1_free_page(pt1, page, addr);
+ return ret;
+}
+
+static void pt1_cleanup_tables(struct pt1 *pt1)
+{
+ struct pt1_table *tables;
+ int i;
+
+ tables = pt1->tables;
+ pt1_unregister_tables(pt1);
+
+ for (i = 0; i < pt1_nr_tables; i++)
+ pt1_cleanup_table(pt1, &tables[i]);
+
+ vfree(tables);
+}
+
+static int pt1_init_tables(struct pt1 *pt1)
+{
+ struct pt1_table *tables;
+ int i, ret;
+ u32 first_pfn, pfn;
+
+ tables = vmalloc(sizeof(struct pt1_table) * pt1_nr_tables);
+ if (tables == NULL)
+ return -ENOMEM;
+
+ pt1_init_table_count(pt1);
+
+ i = 0;
+ if (pt1_nr_tables) {
+ ret = pt1_init_table(pt1, &tables[0], &first_pfn);
+ if (ret)
+ goto err;
+ i++;
+ }
+
+ while (i < pt1_nr_tables) {
+ ret = pt1_init_table(pt1, &tables[i], &pfn);
+ if (ret)
+ goto err;
+ tables[i - 1].page->next_pfn = cpu_to_le32(pfn);
+ i++;
+ }
+
+ tables[pt1_nr_tables - 1].page->next_pfn = cpu_to_le32(first_pfn);
+
+ pt1_register_tables(pt1, first_pfn);
+ pt1->tables = tables;
+ return 0;
+
+err:
+ while (i--)
+ pt1_cleanup_table(pt1, &tables[i]);
+
+ vfree(tables);
+ return ret;
+}
+
+static int pt1_start_feed(struct dvb_demux_feed *feed)
+{
+ struct pt1_adapter *adap;
+ adap = container_of(feed->demux, struct pt1_adapter, demux);
+ if (!adap->users++)
+ pt1_set_stream(adap->pt1, adap->index, 1);
+ return 0;
+}
+
+static int pt1_stop_feed(struct dvb_demux_feed *feed)
+{
+ struct pt1_adapter *adap;
+ adap = container_of(feed->demux, struct pt1_adapter, demux);
+ if (!--adap->users)
+ pt1_set_stream(adap->pt1, adap->index, 0);
+ return 0;
+}
+
+static void
+pt1_set_power(struct pt1 *pt1, int power, int lnb, int reset)
+{
+ pt1_write_reg(pt1, 1, power | lnb << 1 | !reset << 3);
+}
+
+static int pt1_set_voltage(struct dvb_frontend *fe, fe_sec_voltage_t voltage)
+{
+ struct pt1_adapter *adap;
+ int lnb;
+
+ adap = container_of(fe->dvb, struct pt1_adapter, adap);
+
+ switch (voltage) {
+ case SEC_VOLTAGE_13: /* actually 11V */
+ lnb = 2;
+ break;
+ case SEC_VOLTAGE_18: /* actually 15V */
+ lnb = 3;
+ break;
+ case SEC_VOLTAGE_OFF:
+ lnb = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+
+ pt1_set_power(adap->pt1, 1, lnb, 0);
+
+ if (adap->orig_set_voltage)
+ return adap->orig_set_voltage(fe, voltage);
+ else
+ return 0;
+}
+
+static void pt1_free_adapter(struct pt1_adapter *adap)
+{
+ dvb_unregister_frontend(adap->fe);
+ dvb_net_release(&adap->net);
+ adap->demux.dmx.close(&adap->demux.dmx);
+ dvb_dmxdev_release(&adap->dmxdev);
+ dvb_dmx_release(&adap->demux);
+ dvb_unregister_adapter(&adap->adap);
+ free_page((unsigned long)adap->buf);
+ kfree(adap);
+}
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+static struct pt1_adapter *
+pt1_alloc_adapter(struct pt1 *pt1, struct dvb_frontend *fe)
+{
+ struct pt1_adapter *adap;
+ void *buf;
+ struct dvb_adapter *dvb_adap;
+ struct dvb_demux *demux;
+ struct dmxdev *dmxdev;
+ int ret;
+
+ adap = kzalloc(sizeof(struct pt1_adapter), GFP_KERNEL);
+ if (!adap) {
+ ret = -ENOMEM;
+ goto err;
+ }
+
+ adap->pt1 = pt1;
+
+ adap->orig_set_voltage = fe->ops.set_voltage;
+ fe->ops.set_voltage = pt1_set_voltage;
+
+ buf = (u8 *)__get_free_page(GFP_KERNEL);
+ if (!buf) {
+ ret = -ENOMEM;
+ goto err_kfree;
+ }
+
+ adap->buf = buf;
+ adap->upacket_count = 0;
+ adap->packet_count = 0;
+
+ dvb_adap = &adap->adap;
+ dvb_adap->priv = adap;
+ ret = dvb_register_adapter(dvb_adap, DRIVER_NAME, THIS_MODULE,
+ &pt1->pdev->dev, adapter_nr);
+ if (ret < 0)
+ goto err_free_page;
+
+ demux = &adap->demux;
+ demux->dmx.capabilities = DMX_TS_FILTERING | DMX_SECTION_FILTERING;
+ demux->priv = adap;
+ demux->feednum = 256;
+ demux->filternum = 256;
+ demux->start_feed = pt1_start_feed;
+ demux->stop_feed = pt1_stop_feed;
+ demux->write_to_decoder = NULL;
+ ret = dvb_dmx_init(demux);
+ if (ret < 0)
+ goto err_unregister_adapter;
+
+ dmxdev = &adap->dmxdev;
+ dmxdev->filternum = 256;
+ dmxdev->demux = &demux->dmx;
+ dmxdev->capabilities = 0;
+ ret = dvb_dmxdev_init(dmxdev, dvb_adap);
+ if (ret < 0)
+ goto err_dmx_release;
+
+ dvb_net_init(dvb_adap, &adap->net, &demux->dmx);
+
+ ret = dvb_register_frontend(dvb_adap, fe);
+ if (ret < 0)
+ goto err_net_release;
+ adap->fe = fe;
+
+ return adap;
+
+err_net_release:
+ dvb_net_release(&adap->net);
+ adap->demux.dmx.close(&adap->demux.dmx);
+ dvb_dmxdev_release(&adap->dmxdev);
+err_dmx_release:
+ dvb_dmx_release(demux);
+err_unregister_adapter:
+ dvb_unregister_adapter(dvb_adap);
+err_free_page:
+ free_page((unsigned long)buf);
+err_kfree:
+ kfree(adap);
+err:
+ return ERR_PTR(ret);
+}
+
+static void pt1_cleanup_adapters(struct pt1 *pt1)
+{
+ int i;
+ for (i = 0; i < PT1_NR_ADAPS; i++)
+ pt1_free_adapter(pt1->adaps[i]);
+}
+
+struct pt1_config {
+ struct va1j5jf8007s_config va1j5jf8007s_config;
+ struct va1j5jf8007t_config va1j5jf8007t_config;
+};
+
+static const struct pt1_config pt1_configs[2] = {
+ {
+ { .demod_address = 0x1b },
+ { .demod_address = 0x1a },
+ }, {
+ { .demod_address = 0x19 },
+ { .demod_address = 0x18 },
+ },
+};
+
+static int pt1_init_adapters(struct pt1 *pt1)
+{
+ int i, j;
+ struct i2c_adapter *i2c_adap;
+ const struct pt1_config *config;
+ struct dvb_frontend *fe[4];
+ struct pt1_adapter *adap;
+ int ret;
+
+ i = 0;
+ j = 0;
+
+ i2c_adap = &pt1->i2c_adap;
+ do {
+ config = &pt1_configs[i / 2];
+
+ fe[i] = va1j5jf8007s_attach(&config->va1j5jf8007s_config,
+ i2c_adap);
+ if (!fe[i]) {
+ ret = -ENODEV; /* This does not sound nice... */
+ goto err;
+ }
+ i++;
+
+ fe[i] = va1j5jf8007t_attach(&config->va1j5jf8007t_config,
+ i2c_adap);
+ if (!fe[i]) {
+ ret = -ENODEV;
+ goto err;
+ }
+ i++;
+
+ ret = va1j5jf8007s_prepare(fe[i - 2]);
+ if (ret < 0)
+ goto err;
+
+ ret = va1j5jf8007t_prepare(fe[i - 1]);
+ if (ret < 0)
+ goto err;
+
+ } while (i < 4);
+
+ do {
+ adap = pt1_alloc_adapter(pt1, fe[j]);
+ if (IS_ERR(adap))
+ goto err;
+ adap->index = j;
+ pt1->adaps[j] = adap;
+ } while (++j < 4);
+
+ return 0;
+
+err:
+ while (i-- > j)
+ fe[i]->ops.release(fe[i]);
+
+ while (j--)
+ pt1_free_adapter(pt1->adaps[j]);
+
+ return ret;
+}
+
+static void pt1_i2c_emit(struct pt1 *pt1, int addr, int busy, int read_enable,
+ int clock, int data, int next_addr)
+{
+ pt1_write_reg(pt1, 4, addr << 18 | busy << 13 | read_enable << 12 |
+ !clock << 11 | !data << 10 | next_addr);
+}
+
+static void pt1_i2c_write_bit(struct pt1 *pt1, int addr, int *addrp, int data)
+{
+ pt1_i2c_emit(pt1, addr, 1, 0, 0, data, addr + 1);
+ pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, data, addr + 2);
+ pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, data, addr + 3);
+ *addrp = addr + 3;
+}
+
+static void pt1_i2c_read_bit(struct pt1 *pt1, int addr, int *addrp)
+{
+ pt1_i2c_emit(pt1, addr, 1, 0, 0, 1, addr + 1);
+ pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 1, addr + 2);
+ pt1_i2c_emit(pt1, addr + 2, 1, 1, 1, 1, addr + 3);
+ pt1_i2c_emit(pt1, addr + 3, 1, 0, 0, 1, addr + 4);
+ *addrp = addr + 4;
+}
+
+static void pt1_i2c_write_byte(struct pt1 *pt1, int addr, int *addrp, int data)
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ pt1_i2c_write_bit(pt1, addr, &addr, data >> (7 - i) & 1);
+ pt1_i2c_write_bit(pt1, addr, &addr, 1);
+ *addrp = addr;
+}
+
+static void pt1_i2c_read_byte(struct pt1 *pt1, int addr, int *addrp, int last)
+{
+ int i;
+ for (i = 0; i < 8; i++)
+ pt1_i2c_read_bit(pt1, addr, &addr);
+ pt1_i2c_write_bit(pt1, addr, &addr, last);
+ *addrp = addr;
+}
+
+static void pt1_i2c_prepare(struct pt1 *pt1, int addr, int *addrp)
+{
+ pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1);
+ pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
+ pt1_i2c_emit(pt1, addr + 2, 1, 0, 0, 0, addr + 3);
+ *addrp = addr + 3;
+}
+
+static void
+pt1_i2c_write_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
+{
+ int i;
+ pt1_i2c_prepare(pt1, addr, &addr);
+ pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1);
+ for (i = 0; i < msg->len; i++)
+ pt1_i2c_write_byte(pt1, addr, &addr, msg->buf[i]);
+ *addrp = addr;
+}
+
+static void
+pt1_i2c_read_msg(struct pt1 *pt1, int addr, int *addrp, struct i2c_msg *msg)
+{
+ int i;
+ pt1_i2c_prepare(pt1, addr, &addr);
+ pt1_i2c_write_byte(pt1, addr, &addr, msg->addr << 1 | 1);
+ for (i = 0; i < msg->len; i++)
+ pt1_i2c_read_byte(pt1, addr, &addr, i == msg->len - 1);
+ *addrp = addr;
+}
+
+static int pt1_i2c_end(struct pt1 *pt1, int addr)
+{
+ pt1_i2c_emit(pt1, addr, 1, 0, 0, 0, addr + 1);
+ pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
+ pt1_i2c_emit(pt1, addr + 2, 1, 0, 1, 1, 0);
+
+ pt1_write_reg(pt1, 0, 0x00000004);
+ do {
+ if (signal_pending(current))
+ return -EINTR;
+ schedule_timeout_interruptible((HZ + 999) / 1000);
+ } while (pt1_read_reg(pt1, 0) & 0x00000080);
+ return 0;
+}
+
+static void pt1_i2c_begin(struct pt1 *pt1, int *addrp)
+{
+ int addr;
+ addr = 0;
+
+ pt1_i2c_emit(pt1, addr, 0, 0, 1, 1, addr /* itself */);
+ addr = addr + 1;
+
+ if (!pt1->i2c_running) {
+ pt1_i2c_emit(pt1, addr, 1, 0, 1, 1, addr + 1);
+ pt1_i2c_emit(pt1, addr + 1, 1, 0, 1, 0, addr + 2);
+ addr = addr + 2;
+ pt1->i2c_running = 1;
+ }
+ *addrp = addr;
+}
+
+static int pt1_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg *msgs, int num)
+{
+ struct pt1 *pt1;
+ int i;
+ struct i2c_msg *msg, *next_msg;
+ int addr, ret;
+ u16 len;
+ u32 word;
+
+ pt1 = i2c_get_adapdata(adap);
+
+ for (i = 0; i < num; i++) {
+ msg = &msgs[i];
+ if (msg->flags & I2C_M_RD)
+ return -ENOTSUPP;
+
+ if (i + 1 < num)
+ next_msg = &msgs[i + 1];
+ else
+ next_msg = NULL;
+
+ if (next_msg && next_msg->flags & I2C_M_RD) {
+ i++;
+
+ len = next_msg->len;
+ if (len > 4)
+ return -ENOTSUPP;
+
+ pt1_i2c_begin(pt1, &addr);
+ pt1_i2c_write_msg(pt1, addr, &addr, msg);
+ pt1_i2c_read_msg(pt1, addr, &addr, next_msg);
+ ret = pt1_i2c_end(pt1, addr);
+ if (ret < 0)
+ return ret;
+
+ word = pt1_read_reg(pt1, 2);
+ while (len--) {
+ next_msg->buf[len] = word;
+ word >>= 8;
+ }
+ } else {
+ pt1_i2c_begin(pt1, &addr);
+ pt1_i2c_write_msg(pt1, addr, &addr, msg);
+ ret = pt1_i2c_end(pt1, addr);
+ if (ret < 0)
+ return ret;
+ }
+ }
+
+ return num;
+}
+
+static u32 pt1_i2c_func(struct i2c_adapter *adap)
+{
+ return I2C_FUNC_I2C;
+}
+
+static const struct i2c_algorithm pt1_i2c_algo = {
+ .master_xfer = pt1_i2c_xfer,
+ .functionality = pt1_i2c_func,
+};
+
+static void pt1_i2c_wait(struct pt1 *pt1)
+{
+ int i;
+ for (i = 0; i < 128; i++)
+ pt1_i2c_emit(pt1, 0, 0, 0, 1, 1, 0);
+}
+
+static void pt1_i2c_init(struct pt1 *pt1)
+{
+ int i;
+ for (i = 0; i < 1024; i++)
+ pt1_i2c_emit(pt1, i, 0, 0, 1, 1, 0);
+}
+
+static void __devexit pt1_remove(struct pci_dev *pdev)
+{
+ struct pt1 *pt1;
+ void __iomem *regs;
+
+ pt1 = pci_get_drvdata(pdev);
+ regs = pt1->regs;
+
+ kthread_stop(pt1->kthread);
+ pt1_cleanup_tables(pt1);
+ pt1_cleanup_adapters(pt1);
+ pt1_disable_ram(pt1);
+ pt1_set_power(pt1, 0, 0, 1);
+ i2c_del_adapter(&pt1->i2c_adap);
+ pci_set_drvdata(pdev, NULL);
+ kfree(pt1);
+ pci_iounmap(pdev, regs);
+ pci_release_regions(pdev);
+ pci_disable_device(pdev);
+}
+
+static int __devinit
+pt1_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int ret;
+ void __iomem *regs;
+ struct pt1 *pt1;
+ struct i2c_adapter *i2c_adap;
+ struct task_struct *kthread;
+
+ ret = pci_enable_device(pdev);
+ if (ret < 0)
+ goto err;
+
+ ret = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+ if (ret < 0)
+ goto err_pci_disable_device;
+
+ pci_set_master(pdev);
+
+ ret = pci_request_regions(pdev, DRIVER_NAME);
+ if (ret < 0)
+ goto err_pci_disable_device;
+
+ regs = pci_iomap(pdev, 0, 0);
+ if (!regs) {
+ ret = -EIO;
+ goto err_pci_release_regions;
+ }
+
+ pt1 = kzalloc(sizeof(struct pt1), GFP_KERNEL);
+ if (!pt1) {
+ ret = -ENOMEM;
+ goto err_pci_iounmap;
+ }
+
+ pt1->pdev = pdev;
+ pt1->regs = regs;
+ pci_set_drvdata(pdev, pt1);
+
+ i2c_adap = &pt1->i2c_adap;
+ i2c_adap->class = I2C_CLASS_TV_DIGITAL;
+ i2c_adap->algo = &pt1_i2c_algo;
+ i2c_adap->algo_data = NULL;
+ i2c_adap->dev.parent = &pdev->dev;
+ i2c_set_adapdata(i2c_adap, pt1);
+ ret = i2c_add_adapter(i2c_adap);
+ if (ret < 0)
+ goto err_kfree;
+
+ pt1_set_power(pt1, 0, 0, 1);
+
+ pt1_i2c_init(pt1);
+ pt1_i2c_wait(pt1);
+
+ ret = pt1_sync(pt1);
+ if (ret < 0)
+ goto err_i2c_del_adapter;
+
+ pt1_identify(pt1);
+
+ ret = pt1_unlock(pt1);
+ if (ret < 0)
+ goto err_i2c_del_adapter;
+
+ ret = pt1_reset_pci(pt1);
+ if (ret < 0)
+ goto err_i2c_del_adapter;
+
+ ret = pt1_reset_ram(pt1);
+ if (ret < 0)
+ goto err_i2c_del_adapter;
+
+ ret = pt1_enable_ram(pt1);
+ if (ret < 0)
+ goto err_i2c_del_adapter;
+
+ pt1_init_streams(pt1);
+
+ pt1_set_power(pt1, 1, 0, 1);
+ schedule_timeout_uninterruptible((HZ + 49) / 50);
+
+ pt1_set_power(pt1, 1, 0, 0);
+ schedule_timeout_uninterruptible((HZ + 999) / 1000);
+
+ ret = pt1_init_adapters(pt1);
+ if (ret < 0)
+ goto err_pt1_disable_ram;
+
+ ret = pt1_init_tables(pt1);
+ if (ret < 0)
+ goto err_pt1_cleanup_adapters;
+
+ kthread = kthread_run(pt1_thread, pt1, "pt1");
+ if (IS_ERR(kthread)) {
+ ret = PTR_ERR(kthread);
+ goto err_pt1_cleanup_tables;
+ }
+
+ pt1->kthread = kthread;
+ return 0;
+
+err_pt1_cleanup_tables:
+ pt1_cleanup_tables(pt1);
+err_pt1_cleanup_adapters:
+ pt1_cleanup_adapters(pt1);
+err_pt1_disable_ram:
+ pt1_disable_ram(pt1);
+ pt1_set_power(pt1, 0, 0, 1);
+err_i2c_del_adapter:
+ i2c_del_adapter(i2c_adap);
+err_kfree:
+ pci_set_drvdata(pdev, NULL);
+ kfree(pt1);
+err_pci_iounmap:
+ pci_iounmap(pdev, regs);
+err_pci_release_regions:
+ pci_release_regions(pdev);
+err_pci_disable_device:
+ pci_disable_device(pdev);
+err:
+ return ret;
+
+}
+
+static struct pci_device_id pt1_id_table[] = {
+ { PCI_DEVICE(0x10ee, 0x211a) },
+ { },
+};
+MODULE_DEVICE_TABLE(pci, pt1_id_table);
+
+static struct pci_driver pt1_driver = {
+ .name = DRIVER_NAME,
+ .probe = pt1_probe,
+ .remove = __devexit_p(pt1_remove),
+ .id_table = pt1_id_table,
+};
+
+
+static int __init pt1_init(void)
+{
+ return pci_register_driver(&pt1_driver);
+}
+
+
+static void __exit pt1_cleanup(void)
+{
+ pci_unregister_driver(&pt1_driver);
+}
+
+module_init(pt1_init);
+module_exit(pt1_cleanup);
+
+MODULE_AUTHOR("Takahito HIRANO <hiranotaka@zng.info>");
+MODULE_DESCRIPTION("Earthsoft PT1 Driver");
+MODULE_LICENSE("GPL");
diff --git a/linux/drivers/media/dvb/pt1/va1j5jf8007s.c b/linux/drivers/media/dvb/pt1/va1j5jf8007s.c
new file mode 100644
index 000000000..2db940f86
--- /dev/null
+++ b/linux/drivers/media/dvb/pt1/va1j5jf8007s.c
@@ -0,0 +1,658 @@
+/*
+ * ISDB-S driver for VA1J5JF8007
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * 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>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "va1j5jf8007s.h"
+
+enum va1j5jf8007s_tune_state {
+ VA1J5JF8007S_IDLE,
+ VA1J5JF8007S_SET_FREQUENCY_1,
+ VA1J5JF8007S_SET_FREQUENCY_2,
+ VA1J5JF8007S_SET_FREQUENCY_3,
+ VA1J5JF8007S_CHECK_FREQUENCY,
+ VA1J5JF8007S_SET_MODULATION,
+ VA1J5JF8007S_CHECK_MODULATION,
+ VA1J5JF8007S_SET_TS_ID,
+ VA1J5JF8007S_CHECK_TS_ID,
+ VA1J5JF8007S_TRACK,
+};
+
+struct va1j5jf8007s_state {
+ const struct va1j5jf8007s_config *config;
+ struct i2c_adapter *adap;
+ struct dvb_frontend fe;
+ enum va1j5jf8007s_tune_state tune_state;
+};
+
+static int va1j5jf8007s_get_frontend_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_HW;
+}
+
+static int
+va1j5jf8007s_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct va1j5jf8007s_state *state;
+
+ state = fe->demodulator_priv;
+
+ switch (state->tune_state) {
+ case VA1J5JF8007S_IDLE:
+ case VA1J5JF8007S_SET_FREQUENCY_1:
+ case VA1J5JF8007S_SET_FREQUENCY_2:
+ case VA1J5JF8007S_SET_FREQUENCY_3:
+ case VA1J5JF8007S_CHECK_FREQUENCY:
+ *status = 0;
+ return 0;
+
+
+ case VA1J5JF8007S_SET_MODULATION:
+ case VA1J5JF8007S_CHECK_MODULATION:
+ *status |= FE_HAS_SIGNAL;
+ return 0;
+
+ case VA1J5JF8007S_SET_TS_ID:
+ case VA1J5JF8007S_CHECK_TS_ID:
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ return 0;
+
+ case VA1J5JF8007S_TRACK:
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+ return 0;
+ }
+
+ BUG();
+}
+
+struct va1j5jf8007s_cb_map {
+ u32 frequency;
+ u8 cb;
+};
+
+static const struct va1j5jf8007s_cb_map va1j5jf8007s_cb_maps[] = {
+ { 986000, 0xb2 },
+ { 1072000, 0xd2 },
+ { 1154000, 0xe2 },
+ { 1291000, 0x20 },
+ { 1447000, 0x40 },
+ { 1615000, 0x60 },
+ { 1791000, 0x80 },
+ { 1972000, 0xa0 },
+};
+
+static u8 va1j5jf8007s_lookup_cb(u32 frequency)
+{
+ int i;
+ const struct va1j5jf8007s_cb_map *map;
+
+ for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_cb_maps); i++) {
+ map = &va1j5jf8007s_cb_maps[i];
+ if (frequency < map->frequency)
+ return map->cb;
+ }
+ return 0xc0;
+}
+
+static int va1j5jf8007s_set_frequency_1(struct va1j5jf8007s_state *state)
+{
+ u32 frequency;
+ u16 word;
+ u8 buf[6];
+ struct i2c_msg msg;
+
+ frequency = state->fe.dtv_property_cache.frequency;
+
+ word = (frequency + 500) / 1000;
+ if (frequency < 1072000)
+ word = (word << 1 & ~0x1f) | (word & 0x0f);
+
+ buf[0] = 0xfe;
+ buf[1] = 0xc0;
+ buf[2] = 0x40 | word >> 8;
+ buf[3] = word;
+ buf[4] = 0xe0;
+ buf[5] = va1j5jf8007s_lookup_cb(frequency);
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int va1j5jf8007s_set_frequency_2(struct va1j5jf8007s_state *state)
+{
+ u8 buf[3];
+ struct i2c_msg msg;
+
+ buf[0] = 0xfe;
+ buf[1] = 0xc0;
+ buf[2] = 0xe4;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int va1j5jf8007s_set_frequency_3(struct va1j5jf8007s_state *state)
+{
+ u32 frequency;
+ u8 buf[4];
+ struct i2c_msg msg;
+
+ frequency = state->fe.dtv_property_cache.frequency;
+
+ buf[0] = 0xfe;
+ buf[1] = 0xc0;
+ buf[2] = 0xf4;
+ buf[3] = va1j5jf8007s_lookup_cb(frequency) | 0x4;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int
+va1j5jf8007s_check_frequency(struct va1j5jf8007s_state *state, int *lock)
+{
+ u8 addr;
+ u8 write_buf[2], read_buf[1];
+ struct i2c_msg msgs[2];
+
+ addr = state->config->demod_address;
+
+ write_buf[0] = 0xfe;
+ write_buf[1] = 0xc1;
+
+ msgs[0].addr = addr;
+ msgs[0].flags = 0;
+ msgs[0].len = sizeof(write_buf);
+ msgs[0].buf = write_buf;
+
+ msgs[1].addr = addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = sizeof(read_buf);
+ msgs[1].buf = read_buf;
+
+ if (i2c_transfer(state->adap, msgs, 2) != 2)
+ return -EREMOTEIO;
+
+ *lock = read_buf[0] & 0x40;
+ return 0;
+}
+
+static int va1j5jf8007s_set_modulation(struct va1j5jf8007s_state *state)
+{
+ u8 buf[2];
+ struct i2c_msg msg;
+
+ buf[0] = 0x03;
+ buf[1] = 0x01;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int
+va1j5jf8007s_check_modulation(struct va1j5jf8007s_state *state, int *lock)
+{
+ u8 addr;
+ u8 write_buf[1], read_buf[1];
+ struct i2c_msg msgs[2];
+
+ addr = state->config->demod_address;
+
+ write_buf[0] = 0xc3;
+
+ msgs[0].addr = addr;
+ msgs[0].flags = 0;
+ msgs[0].len = sizeof(write_buf);
+ msgs[0].buf = write_buf;
+
+ msgs[1].addr = addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = sizeof(read_buf);
+ msgs[1].buf = read_buf;
+
+ if (i2c_transfer(state->adap, msgs, 2) != 2)
+ return -EREMOTEIO;
+
+ *lock = !(read_buf[0] & 0x10);
+ return 0;
+}
+
+static int
+va1j5jf8007s_set_ts_id(struct va1j5jf8007s_state *state)
+{
+ u32 ts_id;
+ u8 buf[3];
+ struct i2c_msg msg;
+
+ ts_id = state->fe.dtv_property_cache.isdbs_ts_id;
+ if (!ts_id)
+ return 0;
+
+ buf[0] = 0x8f;
+ buf[1] = ts_id >> 8;
+ buf[2] = ts_id;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int
+va1j5jf8007s_check_ts_id(struct va1j5jf8007s_state *state, int *lock)
+{
+ u8 addr;
+ u8 write_buf[1], read_buf[2];
+ struct i2c_msg msgs[2];
+ u32 ts_id;
+
+ ts_id = state->fe.dtv_property_cache.isdbs_ts_id;
+ if (!ts_id) {
+ *lock = 1;
+ return 0;
+ }
+
+ addr = state->config->demod_address;
+
+ write_buf[0] = 0xe6;
+
+ msgs[0].addr = addr;
+ msgs[0].flags = 0;
+ msgs[0].len = sizeof(write_buf);
+ msgs[0].buf = write_buf;
+
+ msgs[1].addr = addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = sizeof(read_buf);
+ msgs[1].buf = read_buf;
+
+ if (i2c_transfer(state->adap, msgs, 2) != 2)
+ return -EREMOTEIO;
+
+ *lock = (read_buf[0] << 8 | read_buf[1]) == ts_id;
+ return 0;
+}
+
+static int
+va1j5jf8007s_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ unsigned int mode_flags, unsigned int *delay,
+ fe_status_t *status)
+{
+ struct va1j5jf8007s_state *state;
+ int ret;
+ int lock;
+
+ state = fe->demodulator_priv;
+
+ if (params != NULL)
+ state->tune_state = VA1J5JF8007S_SET_FREQUENCY_1;
+
+ switch (state->tune_state) {
+ case VA1J5JF8007S_IDLE:
+ *delay = 3 * HZ;
+ *status = 0;
+ return 0;
+
+ case VA1J5JF8007S_SET_FREQUENCY_1:
+ ret = va1j5jf8007s_set_frequency_1(state);
+ if (ret < 0)
+ return ret;
+
+ state->tune_state = VA1J5JF8007S_SET_FREQUENCY_2;
+ *delay = 0;
+ *status = 0;
+ return 0;
+
+ case VA1J5JF8007S_SET_FREQUENCY_2:
+ ret = va1j5jf8007s_set_frequency_2(state);
+ if (ret < 0)
+ return ret;
+
+ state->tune_state = VA1J5JF8007S_SET_FREQUENCY_3;
+ *delay = (HZ + 99) / 100;
+ *status = 0;
+ return 0;
+
+ case VA1J5JF8007S_SET_FREQUENCY_3:
+ ret = va1j5jf8007s_set_frequency_3(state);
+ if (ret < 0)
+ return ret;
+
+ state->tune_state = VA1J5JF8007S_CHECK_FREQUENCY;
+ *delay = 0;
+ *status = 0;
+ return 0;
+
+ case VA1J5JF8007S_CHECK_FREQUENCY:
+ ret = va1j5jf8007s_check_frequency(state, &lock);
+ if (ret < 0)
+ return ret;
+
+ if (!lock) {
+ *delay = (HZ + 999) / 1000;
+ *status = 0;
+ return 0;
+ }
+
+ state->tune_state = VA1J5JF8007S_SET_MODULATION;
+ *delay = 0;
+ *status = FE_HAS_SIGNAL;
+ return 0;
+
+ case VA1J5JF8007S_SET_MODULATION:
+ ret = va1j5jf8007s_set_modulation(state);
+ if (ret < 0)
+ return ret;
+
+ state->tune_state = VA1J5JF8007S_CHECK_MODULATION;
+ *delay = 0;
+ *status = FE_HAS_SIGNAL;
+ return 0;
+
+ case VA1J5JF8007S_CHECK_MODULATION:
+ ret = va1j5jf8007s_check_modulation(state, &lock);
+ if (ret < 0)
+ return ret;
+
+ if (!lock) {
+ *delay = (HZ + 49) / 50;
+ *status = FE_HAS_SIGNAL;
+ return 0;
+ }
+
+ state->tune_state = VA1J5JF8007S_SET_TS_ID;
+ *delay = 0;
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ return 0;
+
+ case VA1J5JF8007S_SET_TS_ID:
+ ret = va1j5jf8007s_set_ts_id(state);
+ if (ret < 0)
+ return ret;
+
+ state->tune_state = VA1J5JF8007S_CHECK_TS_ID;
+ return 0;
+
+ case VA1J5JF8007S_CHECK_TS_ID:
+ ret = va1j5jf8007s_check_ts_id(state, &lock);
+ if (ret < 0)
+ return ret;
+
+ if (!lock) {
+ *delay = (HZ + 99) / 100;
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER;
+ return 0;
+ }
+
+ state->tune_state = VA1J5JF8007S_TRACK;
+ /* fall through */
+
+ case VA1J5JF8007S_TRACK:
+ *delay = 3 * HZ;
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+ return 0;
+ }
+
+ BUG();
+}
+
+static int va1j5jf8007s_init_frequency(struct va1j5jf8007s_state *state)
+{
+ u8 buf[4];
+ struct i2c_msg msg;
+
+ buf[0] = 0xfe;
+ buf[1] = 0xc0;
+ buf[2] = 0xf0;
+ buf[3] = 0x04;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int va1j5jf8007s_set_sleep(struct va1j5jf8007s_state *state, int sleep)
+{
+ u8 buf[2];
+ struct i2c_msg msg;
+
+ buf[0] = 0x17;
+ buf[1] = sleep ? 0x01 : 0x00;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int va1j5jf8007s_sleep(struct dvb_frontend *fe)
+{
+ struct va1j5jf8007s_state *state;
+ int ret;
+
+ state = fe->demodulator_priv;
+
+ ret = va1j5jf8007s_init_frequency(state);
+ if (ret < 0)
+ return ret;
+
+ return va1j5jf8007s_set_sleep(state, 1);
+}
+
+static int va1j5jf8007s_init(struct dvb_frontend *fe)
+{
+ struct va1j5jf8007s_state *state;
+
+ state = fe->demodulator_priv;
+ state->tune_state = VA1J5JF8007S_IDLE;
+
+ return va1j5jf8007s_set_sleep(state, 0);
+}
+
+static void va1j5jf8007s_release(struct dvb_frontend *fe)
+{
+ struct va1j5jf8007s_state *state;
+ state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops va1j5jf8007s_ops = {
+ .info = {
+ .name = "VA1J5JF8007 ISDB-S",
+ .type = FE_QPSK,
+ .frequency_min = 950000,
+ .frequency_max = 2150000,
+ .frequency_stepsize = 1000,
+ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .get_frontend_algo = va1j5jf8007s_get_frontend_algo,
+ .read_status = va1j5jf8007s_read_status,
+ .tune = va1j5jf8007s_tune,
+ .sleep = va1j5jf8007s_sleep,
+ .init = va1j5jf8007s_init,
+ .release = va1j5jf8007s_release,
+};
+
+static int va1j5jf8007s_prepare_1(struct va1j5jf8007s_state *state)
+{
+ u8 addr;
+ u8 write_buf[1], read_buf[1];
+ struct i2c_msg msgs[2];
+
+ addr = state->config->demod_address;
+
+ write_buf[0] = 0x07;
+
+ msgs[0].addr = addr;
+ msgs[0].flags = 0;
+ msgs[0].len = sizeof(write_buf);
+ msgs[0].buf = write_buf;
+
+ msgs[1].addr = addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = sizeof(read_buf);
+ msgs[1].buf = read_buf;
+
+ if (i2c_transfer(state->adap, msgs, 2) != 2)
+ return -EREMOTEIO;
+
+ if (read_buf[0] != 0x41)
+ return -EIO;
+
+ return 0;
+}
+
+static const u8 va1j5jf8007s_prepare_bufs[][2] = {
+ {0x04, 0x02}, {0x0d, 0x55}, {0x11, 0x40}, {0x13, 0x80}, {0x17, 0x01},
+ {0x1c, 0x0a}, {0x1d, 0xaa}, {0x1e, 0x20}, {0x1f, 0x88}, {0x51, 0xb0},
+ {0x52, 0x89}, {0x53, 0xb3}, {0x5a, 0x2d}, {0x5b, 0xd3}, {0x85, 0x69},
+ {0x87, 0x04}, {0x8e, 0x02}, {0xa3, 0xf7}, {0xa5, 0xc0},
+};
+
+static int va1j5jf8007s_prepare_2(struct va1j5jf8007s_state *state)
+{
+ u8 addr;
+ u8 buf[2];
+ struct i2c_msg msg;
+ int i;
+
+ addr = state->config->demod_address;
+
+ msg.addr = addr;
+ msg.flags = 0;
+ msg.len = 2;
+ msg.buf = buf;
+ for (i = 0; i < ARRAY_SIZE(va1j5jf8007s_prepare_bufs); i++) {
+ memcpy(buf, va1j5jf8007s_prepare_bufs[i], sizeof(buf));
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+ }
+
+ return 0;
+}
+
+/* must be called after va1j5jf8007t_attach */
+int va1j5jf8007s_prepare(struct dvb_frontend *fe)
+{
+ struct va1j5jf8007s_state *state;
+ int ret;
+
+ state = fe->demodulator_priv;
+
+ ret = va1j5jf8007s_prepare_1(state);
+ if (ret < 0)
+ return ret;
+
+ ret = va1j5jf8007s_prepare_2(state);
+ if (ret < 0)
+ return ret;
+
+ return va1j5jf8007s_init_frequency(state);
+}
+
+struct dvb_frontend *
+va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,
+ struct i2c_adapter *adap)
+{
+ struct va1j5jf8007s_state *state;
+ struct dvb_frontend *fe;
+ u8 buf[2];
+ struct i2c_msg msg;
+
+ state = kzalloc(sizeof(struct va1j5jf8007s_state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ state->config = config;
+ state->adap = adap;
+
+ fe = &state->fe;
+ memcpy(&fe->ops, &va1j5jf8007s_ops, sizeof(struct dvb_frontend_ops));
+ fe->demodulator_priv = state;
+
+ buf[0] = 0x01;
+ buf[1] = 0x80;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1) {
+ kfree(state);
+ return NULL;
+ }
+
+ return fe;
+}
diff --git a/linux/drivers/media/dvb/pt1/va1j5jf8007s.h b/linux/drivers/media/dvb/pt1/va1j5jf8007s.h
new file mode 100644
index 000000000..aa228a816
--- /dev/null
+++ b/linux/drivers/media/dvb/pt1/va1j5jf8007s.h
@@ -0,0 +1,40 @@
+/*
+ * ISDB-S driver for VA1J5JF8007
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * 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 VA1J5JF8007S_H
+#define VA1J5JF8007S_H
+
+struct va1j5jf8007s_config {
+ u8 demod_address;
+};
+
+struct i2c_adapter;
+
+struct dvb_frontend *
+va1j5jf8007s_attach(const struct va1j5jf8007s_config *config,
+ struct i2c_adapter *adap);
+
+/* must be called after va1j5jf8007t_attach */
+int va1j5jf8007s_prepare(struct dvb_frontend *fe);
+
+#endif
diff --git a/linux/drivers/media/dvb/pt1/va1j5jf8007t.c b/linux/drivers/media/dvb/pt1/va1j5jf8007t.c
new file mode 100644
index 000000000..71117f4ca
--- /dev/null
+++ b/linux/drivers/media/dvb/pt1/va1j5jf8007t.c
@@ -0,0 +1,468 @@
+/*
+ * ISDB-T driver for VA1J5JF8007
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * 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>
+#include <linux/slab.h>
+#include <linux/i2c.h>
+#include "dvb_frontend.h"
+#include "dvb_math.h"
+#include "va1j5jf8007t.h"
+
+enum va1j5jf8007t_tune_state {
+ VA1J5JF8007T_IDLE,
+ VA1J5JF8007T_SET_FREQUENCY,
+ VA1J5JF8007T_CHECK_FREQUENCY,
+ VA1J5JF8007T_SET_MODULATION,
+ VA1J5JF8007T_CHECK_MODULATION,
+ VA1J5JF8007T_TRACK,
+ VA1J5JF8007T_ABORT,
+};
+
+struct va1j5jf8007t_state {
+ const struct va1j5jf8007t_config *config;
+ struct i2c_adapter *adap;
+ struct dvb_frontend fe;
+ enum va1j5jf8007t_tune_state tune_state;
+};
+
+static int va1j5jf8007t_get_frontend_algo(struct dvb_frontend *fe)
+{
+ return DVBFE_ALGO_HW;
+}
+
+static int
+va1j5jf8007t_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+ struct va1j5jf8007t_state *state;
+
+ state = fe->demodulator_priv;
+
+ switch (state->tune_state) {
+ case VA1J5JF8007T_IDLE:
+ case VA1J5JF8007T_SET_FREQUENCY:
+ case VA1J5JF8007T_CHECK_FREQUENCY:
+ *status = 0;
+ return 0;
+
+
+ case VA1J5JF8007T_SET_MODULATION:
+ case VA1J5JF8007T_CHECK_MODULATION:
+ case VA1J5JF8007T_ABORT:
+ *status |= FE_HAS_SIGNAL;
+ return 0;
+
+ case VA1J5JF8007T_TRACK:
+ *status |= FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+ return 0;
+ }
+
+ BUG();
+}
+
+struct va1j5jf8007t_cb_map {
+ u32 frequency;
+ u8 cb;
+};
+
+static const struct va1j5jf8007t_cb_map va1j5jf8007t_cb_maps[] = {
+ { 90000000, 0x80 },
+ { 140000000, 0x81 },
+ { 170000000, 0xa1 },
+ { 220000000, 0x62 },
+ { 330000000, 0xa2 },
+ { 402000000, 0xe2 },
+ { 450000000, 0x64 },
+ { 550000000, 0x84 },
+ { 600000000, 0xa4 },
+ { 700000000, 0xc4 },
+};
+
+static u8 va1j5jf8007t_lookup_cb(u32 frequency)
+{
+ int i;
+ const struct va1j5jf8007t_cb_map *map;
+
+ for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_cb_maps); i++) {
+ map = &va1j5jf8007t_cb_maps[i];
+ if (frequency < map->frequency)
+ return map->cb;
+ }
+ return 0xe4;
+}
+
+static int va1j5jf8007t_set_frequency(struct va1j5jf8007t_state *state)
+{
+ u32 frequency;
+ u16 word;
+ u8 buf[6];
+ struct i2c_msg msg;
+
+ frequency = state->fe.dtv_property_cache.frequency;
+
+ word = (frequency + 71428) / 142857 + 399;
+ buf[0] = 0xfe;
+ buf[1] = 0xc2;
+ buf[2] = word >> 8;
+ buf[3] = word;
+ buf[4] = 0x80;
+ buf[5] = va1j5jf8007t_lookup_cb(frequency);
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int
+va1j5jf8007t_check_frequency(struct va1j5jf8007t_state *state, int *lock)
+{
+ u8 addr;
+ u8 write_buf[2], read_buf[1];
+ struct i2c_msg msgs[2];
+
+ addr = state->config->demod_address;
+
+ write_buf[0] = 0xfe;
+ write_buf[1] = 0xc3;
+
+ msgs[0].addr = addr;
+ msgs[0].flags = 0;
+ msgs[0].len = sizeof(write_buf);
+ msgs[0].buf = write_buf;
+
+ msgs[1].addr = addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = sizeof(read_buf);
+ msgs[1].buf = read_buf;
+
+ if (i2c_transfer(state->adap, msgs, 2) != 2)
+ return -EREMOTEIO;
+
+ *lock = read_buf[0] & 0x40;
+ return 0;
+}
+
+static int va1j5jf8007t_set_modulation(struct va1j5jf8007t_state *state)
+{
+ u8 buf[2];
+ struct i2c_msg msg;
+
+ buf[0] = 0x01;
+ buf[1] = 0x40;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int va1j5jf8007t_check_modulation(struct va1j5jf8007t_state *state,
+ int *lock, int *retry)
+{
+ u8 addr;
+ u8 write_buf[1], read_buf[1];
+ struct i2c_msg msgs[2];
+
+ addr = state->config->demod_address;
+
+ write_buf[0] = 0x80;
+
+ msgs[0].addr = addr;
+ msgs[0].flags = 0;
+ msgs[0].len = sizeof(write_buf);
+ msgs[0].buf = write_buf;
+
+ msgs[1].addr = addr;
+ msgs[1].flags = I2C_M_RD;
+ msgs[1].len = sizeof(read_buf);
+ msgs[1].buf = read_buf;
+
+ if (i2c_transfer(state->adap, msgs, 2) != 2)
+ return -EREMOTEIO;
+
+ *lock = !(read_buf[0] & 0x10);
+ *retry = read_buf[0] & 0x80;
+ return 0;
+}
+
+static int
+va1j5jf8007t_tune(struct dvb_frontend *fe,
+ struct dvb_frontend_parameters *params,
+ unsigned int mode_flags, unsigned int *delay,
+ fe_status_t *status)
+{
+ struct va1j5jf8007t_state *state;
+ int ret;
+ int lock, retry;
+
+ state = fe->demodulator_priv;
+
+ if (params != NULL)
+ state->tune_state = VA1J5JF8007T_SET_FREQUENCY;
+
+ switch (state->tune_state) {
+ case VA1J5JF8007T_IDLE:
+ *delay = 3 * HZ;
+ *status = 0;
+ return 0;
+
+ case VA1J5JF8007T_SET_FREQUENCY:
+ ret = va1j5jf8007t_set_frequency(state);
+ if (ret < 0)
+ return ret;
+
+ state->tune_state = VA1J5JF8007T_CHECK_FREQUENCY;
+ *delay = 0;
+ *status = 0;
+ return 0;
+
+ case VA1J5JF8007T_CHECK_FREQUENCY:
+ ret = va1j5jf8007t_check_frequency(state, &lock);
+ if (ret < 0)
+ return ret;
+
+ if (!lock) {
+ *delay = (HZ + 999) / 1000;
+ *status = 0;
+ return 0;
+ }
+
+ state->tune_state = VA1J5JF8007T_SET_MODULATION;
+ *delay = 0;
+ *status = FE_HAS_SIGNAL;
+ return 0;
+
+ case VA1J5JF8007T_SET_MODULATION:
+ ret = va1j5jf8007t_set_modulation(state);
+ if (ret < 0)
+ return ret;
+
+ state->tune_state = VA1J5JF8007T_CHECK_MODULATION;
+ *delay = 0;
+ *status = FE_HAS_SIGNAL;
+ return 0;
+
+ case VA1J5JF8007T_CHECK_MODULATION:
+ ret = va1j5jf8007t_check_modulation(state, &lock, &retry);
+ if (ret < 0)
+ return ret;
+
+ if (!lock) {
+ if (!retry) {
+ state->tune_state = VA1J5JF8007T_ABORT;
+ *delay = 3 * HZ;
+ *status = FE_HAS_SIGNAL;
+ return 0;
+ }
+ *delay = (HZ + 999) / 1000;
+ *status = FE_HAS_SIGNAL;
+ return 0;
+ }
+
+ state->tune_state = VA1J5JF8007T_TRACK;
+ /* fall through */
+
+ case VA1J5JF8007T_TRACK:
+ *delay = 3 * HZ;
+ *status = FE_HAS_SIGNAL | FE_HAS_CARRIER | FE_HAS_LOCK;
+ return 0;
+
+ case VA1J5JF8007T_ABORT:
+ *delay = 3 * HZ;
+ *status = FE_HAS_SIGNAL;
+ return 0;
+ }
+
+ BUG();
+}
+
+static int va1j5jf8007t_init_frequency(struct va1j5jf8007t_state *state)
+{
+ u8 buf[7];
+ struct i2c_msg msg;
+
+ buf[0] = 0xfe;
+ buf[1] = 0xc2;
+ buf[2] = 0x01;
+ buf[3] = 0x8f;
+ buf[4] = 0xc1;
+ buf[5] = 0x80;
+ buf[6] = 0x80;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int va1j5jf8007t_set_sleep(struct va1j5jf8007t_state *state, int sleep)
+{
+ u8 buf[2];
+ struct i2c_msg msg;
+
+ buf[0] = 0x03;
+ buf[1] = sleep ? 0x90 : 0x80;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+
+ return 0;
+}
+
+static int va1j5jf8007t_sleep(struct dvb_frontend *fe)
+{
+ struct va1j5jf8007t_state *state;
+ int ret;
+
+ state = fe->demodulator_priv;
+
+ ret = va1j5jf8007t_init_frequency(state);
+ if (ret < 0)
+ return ret;
+
+ return va1j5jf8007t_set_sleep(state, 1);
+}
+
+static int va1j5jf8007t_init(struct dvb_frontend *fe)
+{
+ struct va1j5jf8007t_state *state;
+
+ state = fe->demodulator_priv;
+ state->tune_state = VA1J5JF8007T_IDLE;
+
+ return va1j5jf8007t_set_sleep(state, 0);
+}
+
+static void va1j5jf8007t_release(struct dvb_frontend *fe)
+{
+ struct va1j5jf8007t_state *state;
+ state = fe->demodulator_priv;
+ kfree(state);
+}
+
+static struct dvb_frontend_ops va1j5jf8007t_ops = {
+ .info = {
+ .name = "VA1J5JF8007 ISDB-T",
+ .type = FE_OFDM,
+ .frequency_min = 90000000,
+ .frequency_max = 770000000,
+ .frequency_stepsize = 142857,
+ .caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
+ FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+ FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+ },
+
+ .get_frontend_algo = va1j5jf8007t_get_frontend_algo,
+ .read_status = va1j5jf8007t_read_status,
+ .tune = va1j5jf8007t_tune,
+ .sleep = va1j5jf8007t_sleep,
+ .init = va1j5jf8007t_init,
+ .release = va1j5jf8007t_release,
+};
+
+static const u8 va1j5jf8007t_prepare_bufs[][2] = {
+ {0x03, 0x90}, {0x14, 0x8f}, {0x1c, 0x2a}, {0x1d, 0xa8}, {0x1e, 0xa2},
+ {0x22, 0x83}, {0x31, 0x0d}, {0x32, 0xe0}, {0x39, 0xd3}, {0x3a, 0x00},
+ {0x5c, 0x40}, {0x5f, 0x80}, {0x75, 0x02}, {0x76, 0x4e}, {0x77, 0x03},
+ {0xef, 0x01}
+};
+
+int va1j5jf8007t_prepare(struct dvb_frontend *fe)
+{
+ struct va1j5jf8007t_state *state;
+ u8 buf[2];
+ struct i2c_msg msg;
+ int i;
+
+ state = fe->demodulator_priv;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ for (i = 0; i < ARRAY_SIZE(va1j5jf8007t_prepare_bufs); i++) {
+ memcpy(buf, va1j5jf8007t_prepare_bufs[i], sizeof(buf));
+ if (i2c_transfer(state->adap, &msg, 1) != 1)
+ return -EREMOTEIO;
+ }
+
+ return va1j5jf8007t_init_frequency(state);
+}
+
+struct dvb_frontend *
+va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
+ struct i2c_adapter *adap)
+{
+ struct va1j5jf8007t_state *state;
+ struct dvb_frontend *fe;
+ u8 buf[2];
+ struct i2c_msg msg;
+
+ state = kzalloc(sizeof(struct va1j5jf8007t_state), GFP_KERNEL);
+ if (!state)
+ return NULL;
+
+ state->config = config;
+ state->adap = adap;
+
+ fe = &state->fe;
+ memcpy(&fe->ops, &va1j5jf8007t_ops, sizeof(struct dvb_frontend_ops));
+ fe->demodulator_priv = state;
+
+ buf[0] = 0x01;
+ buf[1] = 0x80;
+
+ msg.addr = state->config->demod_address;
+ msg.flags = 0;
+ msg.len = sizeof(buf);
+ msg.buf = buf;
+
+ if (i2c_transfer(state->adap, &msg, 1) != 1) {
+ kfree(state);
+ return NULL;
+ }
+
+ return fe;
+}
diff --git a/linux/drivers/media/dvb/pt1/va1j5jf8007t.h b/linux/drivers/media/dvb/pt1/va1j5jf8007t.h
new file mode 100644
index 000000000..ed49906f7
--- /dev/null
+++ b/linux/drivers/media/dvb/pt1/va1j5jf8007t.h
@@ -0,0 +1,40 @@
+/*
+ * ISDB-T driver for VA1J5JF8007
+ *
+ * Copyright (C) 2009 HIRANO Takahito <hiranotaka@zng.info>
+ *
+ * based on pt1dvr - http://pt1dvr.sourceforge.jp/
+ * by Tomoaki Ishikawa <tomy@users.sourceforge.jp>
+ *
+ * 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 VA1J5JF8007T_H
+#define VA1J5JF8007T_H
+
+struct va1j5jf8007t_config {
+ u8 demod_address;
+};
+
+struct i2c_adapter;
+
+struct dvb_frontend *
+va1j5jf8007t_attach(const struct va1j5jf8007t_config *config,
+ struct i2c_adapter *adap);
+
+/* must be called after va1j5jf8007s_attach */
+int va1j5jf8007t_prepare(struct dvb_frontend *fe);
+
+#endif
diff --git a/linux/drivers/media/video/et61x251/et61x251_core.c b/linux/drivers/media/video/et61x251/et61x251_core.c
index bf88a1387..fca273107 100644
--- a/linux/drivers/media/video/et61x251/et61x251_core.c
+++ b/linux/drivers/media/video/et61x251/et61x251_core.c
@@ -1383,8 +1383,10 @@ et61x251_read(struct file* filp, char __user * buf,
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(cam->state & DEV_MISCONFIGURED),
- cam->module_param.frame_timeout *
- 1000 * msecs_to_jiffies(1) );
+ msecs_to_jiffies(
+ cam->module_param.frame_timeout * 1000
+ )
+ );
if (timeout < 0) {
mutex_unlock(&cam->fileop_mutex);
return timeout;
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
index 7af511b5e..65489d6b0 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx.c
@@ -50,7 +50,6 @@ int stv06xx_write_bridge(struct sd *sd, u16 address, u16 i2c_data)
0x04, 0x40, address, 0, buf, len,
STV06XX_URB_MSG_TIMEOUT);
-
PDEBUG(D_CONF, "Written 0x%x to address 0x%x, status: %d",
i2c_data, address, err);
@@ -69,7 +68,7 @@ int stv06xx_read_bridge(struct sd *sd, u16 address, u8 *i2c_data)
*i2c_data = buf[0];
- PDEBUG(D_CONF, "Read 0x%x from address 0x%x, status %d",
+ PDEBUG(D_CONF, "Reading 0x%x from address 0x%x, status %d",
*i2c_data, address, err);
return (err < 0) ? err : 0;
@@ -111,14 +110,14 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
- PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len);
+ PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len);
for (i = 0; i < len;) {
/* Build the command buffer */
memset(buf, 0, I2C_BUFFER_LENGTH);
for (j = 0; j < I2C_MAX_BYTES && i < len; j++, i++) {
buf[j] = data[2*i];
buf[0x10 + j] = data[2*i+1];
- PDEBUG(D_USBO, "I2C: Writing 0x%02x to reg 0x%02x",
+ PDEBUG(D_CONF, "I2C: Writing 0x%02x to reg 0x%02x",
data[2*i+1], data[2*i]);
}
buf[0x20] = sd->sensor->i2c_addr;
@@ -128,8 +127,8 @@ int stv06xx_write_sensor_bytes(struct sd *sd, const u8 *data, u8 len)
0x04, 0x40, 0x0400, 0, buf,
I2C_BUFFER_LENGTH,
STV06XX_URB_MSG_TIMEOUT);
- if (err < 0)
- return err;
+ if (err < 0)
+ return err;
}
return stv06xx_write_sensor_finish(sd);
}
@@ -140,7 +139,7 @@ int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
struct usb_device *udev = sd->gspca_dev.dev;
__u8 *buf = sd->gspca_dev.usb_buf;
- PDEBUG(D_USBO, "I2C: Command buffer contains %d entries", len);
+ PDEBUG(D_CONF, "I2C: Command buffer contains %d entries", len);
for (i = 0; i < len;) {
/* Build the command buffer */
@@ -149,7 +148,7 @@ int stv06xx_write_sensor_words(struct sd *sd, const u16 *data, u8 len)
buf[j] = data[2*i];
buf[0x10 + j * 2] = data[2*i+1];
buf[0x10 + j * 2 + 1] = data[2*i+1] >> 8;
- PDEBUG(D_USBO, "I2C: Writing 0x%04x to reg 0x%02x",
+ PDEBUG(D_CONF, "I2C: Writing 0x%04x to reg 0x%02x",
data[2*i+1], data[2*i]);
}
buf[0x20] = sd->sensor->i2c_addr;
@@ -189,7 +188,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
0x04, 0x40, 0x1400, 0, buf, I2C_BUFFER_LENGTH,
STV06XX_URB_MSG_TIMEOUT);
if (err < 0) {
- PDEBUG(D_ERR, "I2C Read: error writing address: %d", err);
+ PDEBUG(D_ERR, "I2C: Read error writing address: %d", err);
return err;
}
@@ -201,7 +200,7 @@ int stv06xx_read_sensor(struct sd *sd, const u8 address, u16 *value)
else
*value = buf[0];
- PDEBUG(D_USBO, "I2C: Read 0x%x from address 0x%x, status: %d",
+ PDEBUG(D_CONF, "I2C: Read 0x%x from address 0x%x, status: %d",
*value, address, err);
return (err < 0) ? err : 0;
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
index e5024c849..706e08dc5 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.c
@@ -37,7 +37,7 @@ static const struct ctrl hdcs1x00_ctrl[] = {
.type = V4L2_CTRL_TYPE_INTEGER,
.name = "exposure",
.minimum = 0x00,
- .maximum = 0xffff,
+ .maximum = 0xff,
.step = 0x1,
.default_value = HDCS_DEFAULT_EXPOSURE,
.flags = V4L2_CTRL_FLAG_SLIDER
@@ -74,7 +74,35 @@ static struct v4l2_pix_format hdcs1x00_mode[] = {
}
};
-static const struct ctrl hdcs1020_ctrl[] = {};
+static const struct ctrl hdcs1020_ctrl[] = {
+ {
+ {
+ .id = V4L2_CID_EXPOSURE,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "exposure",
+ .minimum = 0x00,
+ .maximum = 0xffff,
+ .step = 0x1,
+ .default_value = HDCS_DEFAULT_EXPOSURE,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = hdcs_set_exposure,
+ .get = hdcs_get_exposure
+ }, {
+ {
+ .id = V4L2_CID_GAIN,
+ .type = V4L2_CTRL_TYPE_INTEGER,
+ .name = "gain",
+ .minimum = 0x00,
+ .maximum = 0xff,
+ .step = 0x1,
+ .default_value = HDCS_DEFAULT_GAIN,
+ .flags = V4L2_CTRL_FLAG_SLIDER
+ },
+ .set = hdcs_set_gain,
+ .get = hdcs_get_gain
+ }
+};
static struct v4l2_pix_format hdcs1020_mode[] = {
{
@@ -120,6 +148,7 @@ struct hdcs {
} exp;
int psmp;
+ u8 exp_cache, gain_cache;
};
static int hdcs_reg_write_seq(struct sd *sd, u8 reg, u8 *vals, u8 len)
@@ -205,34 +234,8 @@ static int hdcs_get_exposure(struct gspca_dev *gspca_dev, __s32 *val)
struct sd *sd = (struct sd *) gspca_dev;
struct hdcs *hdcs = sd->sensor_priv;
- /* Column time period */
- int ct;
- /* Column processing period */
- int cp;
- /* Row processing period */
- int rp;
- int cycles;
- int err;
- int rowexp;
- u16 data[2];
-
- err = stv06xx_read_sensor(sd, HDCS_ROWEXPL, &data[0]);
- if (err < 0)
- return err;
-
- err = stv06xx_read_sensor(sd, HDCS_ROWEXPH, &data[1]);
- if (err < 0)
- return err;
-
- rowexp = (data[1] << 8) | data[0];
-
- ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
- cp = hdcs->exp.cto + (hdcs->w * ct / 2);
- rp = hdcs->exp.rs + cp;
+ *val = hdcs->exp_cache;
- cycles = rp * rowexp;
- *val = cycles / HDCS_CLK_FREQ_MHZ;
- PDEBUG(D_V4L2, "Read exposure %d", *val);
return 0;
}
@@ -252,9 +255,12 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
within the column processing period */
int mnct;
int cycles, err;
- u8 exp[4];
+ u8 exp[14];
- cycles = val * HDCS_CLK_FREQ_MHZ;
+ val &= 0xff;
+ hdcs->exp_cache = val;
+
+ cycles = val * HDCS_CLK_FREQ_MHZ * 257;
ct = hdcs->exp.cto + hdcs->psmp + (HDCS_ADC_START_SIG_DUR + 2);
cp = hdcs->exp.cto + (hdcs->w * ct / 2);
@@ -288,73 +294,79 @@ static int hdcs_set_exposure(struct gspca_dev *gspca_dev, __s32 val)
srowexp = max_srowexp;
if (IS_1020(sd)) {
- exp[0] = rowexp & 0xff;
- exp[1] = rowexp >> 8;
- exp[2] = (srowexp >> 2) & 0xff;
- /* this clears exposure error flag */
- exp[3] = 0x1;
- err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
+ exp[0] = HDCS20_CONTROL;
+ exp[1] = 0x00; /* Stop streaming */
+ exp[2] = HDCS_ROWEXPL;
+ exp[3] = rowexp & 0xff;
+ exp[4] = HDCS_ROWEXPH;
+ exp[5] = rowexp >> 8;
+ exp[6] = HDCS20_SROWEXP;
+ exp[7] = (srowexp >> 2) & 0xff;
+ exp[8] = HDCS20_ERROR;
+ exp[9] = 0x10; /* Clear exposure error flag*/
+ exp[10] = HDCS20_CONTROL;
+ exp[11] = 0x04; /* Restart streaming */
+ err = stv06xx_write_sensor_bytes(sd, exp, 6);
} else {
- exp[0] = rowexp & 0xff;
- exp[1] = rowexp >> 8;
- exp[2] = srowexp & 0xff;
- exp[3] = srowexp >> 8;
- err = hdcs_reg_write_seq(sd, HDCS_ROWEXPL, exp, 4);
+ exp[0] = HDCS00_CONTROL;
+ exp[1] = 0x00; /* Stop streaming */
+ exp[2] = HDCS_ROWEXPL;
+ exp[3] = rowexp & 0xff;
+ exp[4] = HDCS_ROWEXPH;
+ exp[5] = rowexp >> 8;
+ exp[6] = HDCS00_SROWEXPL;
+ exp[7] = srowexp & 0xff;
+ exp[8] = HDCS00_SROWEXPH;
+ exp[9] = srowexp >> 8;
+ exp[10] = HDCS_STATUS;
+ exp[11] = 0x10; /* Clear exposure error flag*/
+ exp[12] = HDCS00_CONTROL;
+ exp[13] = 0x04; /* Restart streaming */
+ err = stv06xx_write_sensor_bytes(sd, exp, 7);
if (err < 0)
return err;
-
- /* clear exposure error flag */
- err = stv06xx_write_sensor(sd,
- HDCS_STATUS, BIT(4));
}
PDEBUG(D_V4L2, "Writing exposure %d, rowexp %d, srowexp %d",
val, rowexp, srowexp);
return err;
}
-static int hdcs_set_gains(struct sd *sd, u8 r, u8 g, u8 b)
+static int hdcs_set_gains(struct sd *sd, u8 g)
{
+ struct hdcs *hdcs = sd->sensor_priv;
+ int err;
u8 gains[4];
+ hdcs->gain_cache = g;
+
/* the voltage gain Av = (1 + 19 * val / 127) * (1 + bit7) */
- if (r > 127)
- r = 0x80 | (r / 2);
if (g > 127)
g = 0x80 | (g / 2);
- if (b > 127)
- b = 0x80 | (b / 2);
gains[0] = g;
- gains[1] = r;
- gains[2] = b;
+ gains[1] = g;
+ gains[2] = g;
gains[3] = g;
- return hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
+ err = hdcs_reg_write_seq(sd, HDCS_ERECPGA, gains, 4);
+ return err;
}
static int hdcs_get_gain(struct gspca_dev *gspca_dev, __s32 *val)
{
struct sd *sd = (struct sd *) gspca_dev;
- int err;
- u16 data;
-
- err = stv06xx_read_sensor(sd, HDCS_ERECPGA, &data);
+ struct hdcs *hdcs = sd->sensor_priv;
- /* Bit 7 doubles the gain */
- if (data & 0x80)
- *val = (data & 0x7f) * 2;
- else
- *val = data;
+ *val = hdcs->gain_cache;
- PDEBUG(D_V4L2, "Read gain %d", *val);
- return err;
+ return 0;
}
static int hdcs_set_gain(struct gspca_dev *gspca_dev, __s32 val)
{
PDEBUG(D_V4L2, "Writing gain %d", val);
return hdcs_set_gains((struct sd *) gspca_dev,
- val & 0xff, val & 0xff, val & 0xff);
+ val & 0xff);
}
static int hdcs_set_size(struct sd *sd,
@@ -572,16 +584,15 @@ static int hdcs_init(struct sd *sd)
if (err < 0)
return err;
- err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN, HDCS_DEFAULT_GAIN,
- HDCS_DEFAULT_GAIN);
+ err = hdcs_set_gains(sd, HDCS_DEFAULT_GAIN);
if (err < 0)
return err;
- err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
+ err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
if (err < 0)
return err;
- err = hdcs_set_size(sd, hdcs->array.width, hdcs->array.height);
+ err = hdcs_set_exposure(&sd->gspca_dev, HDCS_DEFAULT_EXPOSURE);
return err;
}
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
index 412f06cf3..37b31c99d 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_hdcs.h
@@ -124,7 +124,7 @@
#define HDCS_RUN_ENABLE (1 << 2)
#define HDCS_SLEEP_MODE (1 << 1)
-#define HDCS_DEFAULT_EXPOSURE 5000
+#define HDCS_DEFAULT_EXPOSURE 48
#define HDCS_DEFAULT_GAIN 128
static int hdcs_probe_1x00(struct sd *sd);
diff --git a/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c b/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
index 87cb5b9dd..c11f06e4a 100644
--- a/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
+++ b/linux/drivers/media/video/gspca/stv06xx/stv06xx_st6422.c
@@ -166,7 +166,7 @@ static int st6422_init(struct sd *sd)
/* 10 compressed? */
{ 0x1439, 0x00 },
-/* antiflimmer?? 0xa2 ger perfekt bild mot monitor */
+/* anti-noise? 0xa2 gives a perfect image */
{ 0x143b, 0x05 },
{ 0x143c, 0x00 }, /* 0x00-0x01 - ??? */
@@ -197,15 +197,14 @@ static int st6422_init(struct sd *sd)
{ 0x1500, 0x50 }, /* 0x00 - 0xFF 0x80 == compr ? */
{ 0x1501, 0xaf },
-/* high val-> ljus area blir morkare. */
-/* low val -> ljus area blir ljusare. */
+/* high val-> light area gets darker */
+/* low val -> light area gets lighter */
{ 0x1502, 0xc2 },
-/* high val-> ljus area blir morkare. */
-/* low val -> ljus area blir ljusare. */
+/* high val-> light area gets darker */
+/* low val -> light area gets lighter */
{ 0x1503, 0x45 },
-/* high val-> ljus area blir morkare. */
-/* low val -> ljus area blir ljusare. */
-
+/* high val-> light area gets darker */
+/* low val -> light area gets lighter */
{ 0x1505, 0x02 },
/* 2 : 324x248 80352 bytes */
/* 7 : 248x162 40176 bytes */
diff --git a/linux/drivers/media/video/saa7134/saa7134-cards.c b/linux/drivers/media/video/saa7134/saa7134-cards.c
index 896554cac..8116dd9a6 100644
--- a/linux/drivers/media/video/saa7134/saa7134-cards.c
+++ b/linux/drivers/media/video/saa7134/saa7134-cards.c
@@ -5296,6 +5296,27 @@ struct saa7134_board saa7134_boards[] = {
.amux = TV,
},
},
+ [SAA7134_BOARD_ZOLID_HYBRID_PCI] = {
+ .name = "Zolid Hybrid TV Tuner PCI",
+ .audio_clock = 0x00187de7,
+ .tuner_type = TUNER_PHILIPS_TDA8290,
+ .radio_type = UNSET,
+ .tuner_addr = ADDR_UNSET,
+ .radio_addr = ADDR_UNSET,
+ .tuner_config = 0,
+ .mpeg = SAA7134_MPEG_DVB,
+ .ts_type = SAA7134_MPEG_TS_PARALLEL,
+ .inputs = {{
+ .name = name_tv,
+ .vmux = 1,
+ .amux = TV,
+ .tv = 1,
+ } },
+ .radio = { /* untested */
+ .name = name_radio,
+ .amux = TV,
+ },
+ },
};
@@ -6429,6 +6450,12 @@ struct pci_device_id saa7134_pci_tbl[] = {
.subdevice = 0x0138, /* LifeView FlyTV Prime30 OEM */
.driver_data = SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM,
}, {
+ .vendor = PCI_VENDOR_ID_PHILIPS,
+ .device = PCI_DEVICE_ID_PHILIPS_SAA7133,
+ .subvendor = PCI_VENDOR_ID_PHILIPS,
+ .subdevice = 0x2004,
+ .driver_data = SAA7134_BOARD_ZOLID_HYBRID_PCI,
+ }, {
/* --- boards without eeprom + subsystem ID --- */
.vendor = PCI_VENDOR_ID_PHILIPS,
.device = PCI_DEVICE_ID_PHILIPS_SAA7134,
diff --git a/linux/drivers/media/video/saa7134/saa7134-dvb.c b/linux/drivers/media/video/saa7134/saa7134-dvb.c
index dc2428f12..d52b7455c 100644
--- a/linux/drivers/media/video/saa7134/saa7134-dvb.c
+++ b/linux/drivers/media/video/saa7134/saa7134-dvb.c
@@ -1014,6 +1014,22 @@ static struct tda829x_config tda829x_no_probe = {
.probe_tuner = TDA829X_DONT_PROBE,
};
+static struct tda10048_config zolid_tda10048_config = {
+ .demod_address = 0x10 >> 1,
+ .output_mode = TDA10048_PARALLEL_OUTPUT,
+ .fwbulkwritelen = TDA10048_BULKWRITE_200,
+ .inversion = TDA10048_INVERSION_ON,
+ .dtv6_if_freq_khz = TDA10048_IF_3300,
+ .dtv7_if_freq_khz = TDA10048_IF_3500,
+ .dtv8_if_freq_khz = TDA10048_IF_4000,
+ .clk_freq_khz = TDA10048_CLK_16000,
+ .disable_gate_access = 1,
+};
+
+static struct tda18271_config zolid_tda18271_config = {
+ .gate = TDA18271_GATE_ANALOG,
+};
+
/* ==================================================================
* Core code
*/
@@ -1493,6 +1509,19 @@ static int dvb_init(struct saa7134_dev *dev)
__func__);
break;
+ case SAA7134_BOARD_ZOLID_HYBRID_PCI:
+ fe0->dvb.frontend = dvb_attach(tda10048_attach,
+ &zolid_tda10048_config,
+ &dev->i2c_adap);
+ if (fe0->dvb.frontend != NULL) {
+ dvb_attach(tda829x_attach, fe0->dvb.frontend,
+ &dev->i2c_adap, 0x4b,
+ &tda829x_no_probe);
+ dvb_attach(tda18271_attach, fe0->dvb.frontend,
+ 0x60, &dev->i2c_adap,
+ &zolid_tda18271_config);
+ }
+ break;
default:
wprintk("Huh? unknown DVB card?\n");
break;
diff --git a/linux/drivers/media/video/saa7134/saa7134-input.c b/linux/drivers/media/video/saa7134/saa7134-input.c
index 153fb3c5b..5bd1f3b8b 100644
--- a/linux/drivers/media/video/saa7134/saa7134-input.c
+++ b/linux/drivers/media/video/saa7134/saa7134-input.c
@@ -288,6 +288,10 @@ static int get_key_beholdm6xx(struct IR_i2c *ir, u32 *ir_key, u32 *ir_raw)
if (data[10] != 0x6b && data[11] != 0x86 && disable_other_ir)
return 0;
+ /* Wrong data decode fix */
+ if (data[9] != (unsigned char)(~data[8]))
+ return 0;
+
*ir_key = data[9];
*ir_raw = data[9];
diff --git a/linux/drivers/media/video/saa7134/saa7134.h b/linux/drivers/media/video/saa7134/saa7134.h
index 1bf2837b4..ff65f13fd 100644
--- a/linux/drivers/media/video/saa7134/saa7134.h
+++ b/linux/drivers/media/video/saa7134/saa7134.h
@@ -297,6 +297,7 @@ struct saa7134_format {
#define SAA7134_BOARD_AVERMEDIA_STUDIO_505 170
#define SAA7134_BOARD_BEHOLD_X7 171
#define SAA7134_BOARD_ROVERMEDIA_LINK_PRO_FM 172
+#define SAA7134_BOARD_ZOLID_HYBRID_PCI 173
#define SAA7134_MAXBOARDS 32
#define SAA7134_INPUT_MAX 8
diff --git a/linux/drivers/media/video/sn9c102/sn9c102_core.c b/linux/drivers/media/video/sn9c102/sn9c102_core.c
index 63432ccd2..69df0cb75 100644
--- a/linux/drivers/media/video/sn9c102/sn9c102_core.c
+++ b/linux/drivers/media/video/sn9c102/sn9c102_core.c
@@ -1958,8 +1958,10 @@ sn9c102_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(cam->state & DEV_MISCONFIGURED),
- cam->module_param.frame_timeout *
- 1000 * msecs_to_jiffies(1) );
+ msecs_to_jiffies(
+ cam->module_param.frame_timeout * 1000
+ )
+ );
if (timeout < 0) {
mutex_unlock(&cam->fileop_mutex);
return timeout;
diff --git a/linux/drivers/media/video/v4l2-device.c b/linux/drivers/media/video/v4l2-device.c
index 655d19cd6..016c62f6c 100644
--- a/linux/drivers/media/video/v4l2-device.c
+++ b/linux/drivers/media/video/v4l2-device.c
@@ -86,7 +86,7 @@ void v4l2_device_unregister(struct v4l2_device *v4l2_dev)
/* Unregister subdevs */
list_for_each_entry_safe(sd, next, &v4l2_dev->subdevs, list) {
v4l2_device_unregister_subdev(sd);
-#if defined(CONFIG_I2C) || defined(CONFIG_I2C_MODULE)
+#if defined(CONFIG_I2C) || (defined(CONFIG_I2C_MODULE) && defined(MODULE))
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2, 6, 26)
if (sd->flags & V4L2_SUBDEV_FL_IS_I2C) {
struct i2c_client *client = v4l2_get_subdevdata(sd);
diff --git a/linux/drivers/media/video/zc0301/zc0301_core.c b/linux/drivers/media/video/zc0301/zc0301_core.c
index b6a3ac815..996cf0c41 100644
--- a/linux/drivers/media/video/zc0301/zc0301_core.c
+++ b/linux/drivers/media/video/zc0301/zc0301_core.c
@@ -823,8 +823,10 @@ zc0301_read(struct file* filp, char __user * buf, size_t count, loff_t* f_pos)
(!list_empty(&cam->outqueue)) ||
(cam->state & DEV_DISCONNECTED) ||
(cam->state & DEV_MISCONFIGURED),
- cam->module_param.frame_timeout *
- 1000 * msecs_to_jiffies(1) );
+ msecs_to_jiffies(
+ cam->module_param.frame_timeout * 1000
+ )
+ );
if (timeout < 0) {
mutex_unlock(&cam->fileop_mutex);
return timeout;
diff --git a/linux/drivers/staging/cx25821/Makefile b/linux/drivers/staging/cx25821/Makefile
index 2029cd046..10f87f05d 100644
--- a/linux/drivers/staging/cx25821/Makefile
+++ b/linux/drivers/staging/cx25821/Makefile
@@ -9,5 +9,6 @@ obj-$(CONFIG_VIDEO_CX25821) += cx25821.o
obj-$(CONFIG_VIDEO_CX25821_ALSA) += cx25821-alsa.o
EXTRA_CFLAGS += -Idrivers/media/video
+EXTRA_CFLAGS += -Idrivers/media/common/tuners
EXTRA_CFLAGS += -Idrivers/media/dvb/dvb-core
EXTRA_CFLAGS += -Idrivers/media/dvb/frontends
diff --git a/linux/include/linux/dvb/frontend.h b/linux/include/linux/dvb/frontend.h
index 25b01c147..b6cb5425c 100644
--- a/linux/include/linux/dvb/frontend.h
+++ b/linux/include/linux/dvb/frontend.h
@@ -302,7 +302,9 @@ struct dvb_frontend_event {
#define DTV_ISDBT_LAYER_ENABLED 41
-#define DTV_MAX_COMMAND DTV_ISDBT_LAYER_ENABLED
+#define DTV_ISDBS_TS_ID 42
+
+#define DTV_MAX_COMMAND DTV_ISDBS_TS_ID
typedef enum fe_pilot {
PILOT_ON,
diff --git a/linux/include/linux/mmc/sdio_ids.h b/linux/include/linux/mmc/sdio_ids.h
index 39751c8cd..2dbfb5a05 100644
--- a/linux/include/linux/mmc/sdio_ids.h
+++ b/linux/include/linux/mmc/sdio_ids.h
@@ -22,6 +22,12 @@
/*
* Vendors and devices. Sort key: vendor first, device next.
*/
+#define SDIO_VENDOR_ID_INTEL 0x0089
+#define SDIO_DEVICE_ID_INTEL_IWMC3200WIMAX 0x1402
+#define SDIO_DEVICE_ID_INTEL_IWMC3200WIFI 0x1403
+#define SDIO_DEVICE_ID_INTEL_IWMC3200TOP 0x1404
+#define SDIO_DEVICE_ID_INTEL_IWMC3200GPS 0x1405
+#define SDIO_DEVICE_ID_INTEL_IWMC3200BT 0x1406
#define SDIO_VENDOR_ID_MARVELL 0x02df
#define SDIO_DEVICE_ID_MARVELL_LIBERTAS 0x9103
diff --git a/linux/linux/drivers/staging/tm6000/tm6000-alsa.c b/linux/linux/drivers/staging/tm6000/tm6000-alsa.c
deleted file mode 100644
index e69de29bb..000000000
--- a/linux/linux/drivers/staging/tm6000/tm6000-alsa.c
+++ /dev/null